Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions buckaroo/builders/payments/in3_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ def get_allowed_service_parameters(self, action: str = "Pay") -> Dict[str, Any]:
"description": "Shipping customer information",
},
"article": {"type": list, "required": True, "description": "IN3 articles"},
"route": {
"type": str,
"required": False,
"description": (
"In3 acquirer route, e.g. 'abn_b2b' for ABN-AMRO Achteraf Betalen"
),
},
}

return {}
97 changes: 97 additions & 0 deletions examples/abn_amro_achteraf_betalen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Demo of ABN-AMRO Achteraf Betalen via the In3 payment method.

Same underlying service as In3 V3 — setting the optional ``Route`` service
parameter to ``abn_b2b`` selects ABN-AMRO Achteraf Betalen instead of the
default In3 acquirer. NL/B2B only. Gated on ``BUCKAROO_STORE_KEY`` /
``BUCKAROO_SECRET_KEY`` env vars.
"""

import os
import sys

# Add parent directory to Python path so the demo can import the SDK in-place.
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from buckaroo.app import Buckaroo


def _have_credentials() -> bool:
if not os.getenv("BUCKAROO_STORE_KEY") or not os.getenv("BUCKAROO_SECRET_KEY"):
print("⚠️ Set BUCKAROO_STORE_KEY and BUCKAROO_SECRET_KEY to run this demo")
return False
return True


def demo_abn_amro_achteraf_betalen() -> None:
"""Pay via In3 with the ABN-AMRO Achteraf Betalen route."""
print("\nABN-AMRO Achteraf Betalen (In3, Route=abn_b2b)")
print("-" * 40)
if not _have_credentials():
return

try:
app = Buckaroo.from_env()

# create_payment(method, params) dispatches through the PaymentMethodFactory
# and returns a ready-to-execute In3Builder.
builder = app.payments.create_payment(
"in3",
{
"currency": "EUR",
"amount": 121.00,
"description": "ABN-AMRO Achteraf Betalen demo",
"invoice": "ABN-B2B-DEMO-001",
"return_url": "https://www.buckaroo.nl",
"return_url_cancel": "https://www.buckaroo.nl/cancel",
"return_url_error": "https://www.buckaroo.nl/error",
"return_url_reject": "https://www.buckaroo.nl/reject",
"service_parameters": {
"billingCustomer": [
{
"firstName": "John",
"lastName": "Doe",
"chamberOfCommerce": "12345678",
"companyName": "Acme B.V.",
}
],
"shippingCustomer": [
{
"firstName": "John",
"lastName": "Doe",
"chamberOfCommerce": "12345678",
"companyName": "Acme B.V.",
}
],
"article": [
{"description": "Widget", "quantity": "1", "price": "100.00"},
],
},
},
)

# Route is optional and NL/B2B only - selects ABN-AMRO Achteraf Betalen
# instead of the default In3 acquirer.
builder.add_parameter("route", "abn_b2b")

response = builder.pay()

print(f" status.code={response.status.code.code} key={response.key}")
except Exception as e:
print(f" ❌ {e}")


def main() -> None:
print("BUCKAROO SDK — ABN-AMRO ACHTERAF BETALEN DEMO")
print("=" * 60)
print("Env vars read:")
print(" BUCKAROO_STORE_KEY, BUCKAROO_SECRET_KEY, BUCKAROO_MODE")

demo_abn_amro_achteraf_betalen()

print("\n" + "=" * 60)
print("done.")


if __name__ == "__main__":
main()
43 changes: 43 additions & 0 deletions tests/unit/builders/payments/test_in3_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,21 @@ def test_get_allowed_service_parameters_pay_snapshot(client):
"required": True,
"description": "IN3 articles",
},
"route": {
"type": str,
"required": False,
"description": ("In3 acquirer route, e.g. 'abn_b2b' for ABN-AMRO Achteraf Betalen"),
},
}


def test_get_allowed_service_parameters_pay_allows_optional_route(client):
allowed = In3Builder(client).get_allowed_service_parameters("Pay")

assert "route" in allowed
assert allowed["route"]["required"] is False


def test_get_allowed_service_parameters_pay_is_case_insensitive(client):
builder = In3Builder(client)

Expand All @@ -59,6 +71,37 @@ def test_get_allowed_service_parameters_non_pay_returns_empty(client, action):
assert In3Builder(client).get_allowed_service_parameters(action) == {}


def test_build_pay_with_route_keeps_route_parameter(client):
request = (
populate_required_fields(In3Builder(client), amount=99.95)
.add_parameter("billingCustomer", [{"Name": "John"}])
.add_parameter("shippingCustomer", [{"Name": "John"}])
.add_parameter("article", [{"Description": "Widget", "Quantity": 1}])
.add_parameter("route", "abn_b2b")
.build("Pay")
)

service = request.services.services[0]
route_params = [p for p in service.parameters if p.name == "Route"]

assert len(route_params) == 1
assert route_params[0].value == "abn_b2b"


def test_build_pay_without_route_is_unchanged(client):
request = (
populate_required_fields(In3Builder(client), amount=99.95)
.add_parameter("billingCustomer", [{"Name": "John"}])
.add_parameter("shippingCustomer", [{"Name": "John"}])
.add_parameter("article", [{"Description": "Widget", "Quantity": 1}])
.build("Pay")
)

service = request.services.services[0]

assert all(p.name != "Route" for p in service.parameters)


def test_pay_posts_transaction_and_parses_response(client, mock_strategy):
mock_strategy.queue(
BuckarooMockRequest.json(
Expand Down
Loading