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
18 changes: 16 additions & 2 deletions checkout_sdk/payments/setups/setups.py
Original file line number Diff line number Diff line change
Expand Up @@ -1303,8 +1303,11 @@ class PaymentMethods:
# The card-present payment method. Not present in the current Payment Setup schema.
# [Optional]
card_present: CardPresent
# The Pay by Bank (Open Banking) payment method's details and configuration. The spec
# names this key paybybank.
# The Pay by Bank (Open Banking) payment method's details and configuration.
# [Optional]
paybybank: PayByBank
# Deprecated: the API does not recognise the pay_by_bank key and ignores it without
# error, so a value set here is never applied. Use paybybank instead.
# [Optional]
pay_by_bank: PayByBank
# The Stablecoin payment method's details and configuration.
Expand All @@ -1315,6 +1318,14 @@ class PaymentMethods:
cashapp: CashApp


# Risk entity
class PaymentSetupRisk:
"""Risk assessment settings for the Payment Setup."""
# Indicates whether a risk assessment should be performed. Defaults to true.
# [Optional]
enabled: bool


# Settings entity
class Settings:
"""Settings for the Payment Setup."""
Expand Down Expand Up @@ -1876,6 +1887,9 @@ class PaymentSetupsRequest:
# Settings for the Payment Setup.
# [Optional]
settings: Settings
# Risk assessment settings for the Payment Setup.
# [Optional]
risk: PaymentSetupRisk
# The customer's details.
# [Optional]
customer: Customer
Expand Down
10 changes: 7 additions & 3 deletions checkout_sdk/payments/setups/setups_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ def create_payment_setup(self, payment_setups_request: PaymentSetupsRequest):
Args:
payment_setups_request: The Payment Setup request body. To offer Cash App Pay, set
payment_methods.cashapp (initialization, customer_profile_sharing) and
customer.device.client.
customer.device.client. To offer Pay by Bank, set payment_methods.paybybank
(the deprecated pay_by_bank attribute is ignored by the API). Set risk.enabled
to control whether a risk assessment is performed (defaults to true).
Returns:
ResponseWrapper with the Payment Setup. For Cash App Pay, the customer is sent to
payment_methods.cashapp.action.redirect_url to authorize the payment.
payment_methods.cashapp.action.redirect_url to authorize the payment. For Pay by
Bank, the banks to choose from are in payment_methods.paybybank.action.banks.
"""
return self._api_client.post(
self.build_path(self.__PAYMENTS_PATH, self.__SETUPS_PATH),
Expand All @@ -39,7 +42,8 @@ def update_payment_setup(self, setup_id: str, payment_setups_request: PaymentSet

Args:
setup_id: The unique identifier of the Payment Setup to update.
payment_setups_request: The Payment Setup request body.
payment_setups_request: The Payment Setup request body. Pay by Bank goes in
payment_methods.paybybank and risk settings in risk.enabled.
Returns:
ResponseWrapper with the updated Payment Setup.
"""
Expand Down
75 changes: 74 additions & 1 deletion tests/payments/setups/payment_setups_serialization_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
MerchantAccount, OrderSubMerchant,
PaymentSetupsRequest, Customer, CustomerEmail, CustomerDevice, CustomerDeviceClient,
PaymentMethodInitialization, CashApp, CashAppAction, CashAppActionType, CashAppAddress,
CashAppCustomerProfile,
CashAppCustomerProfile, PaymentSetupRisk,
)


Expand Down Expand Up @@ -962,3 +962,76 @@ def test_customer_spec_example_reads(self):
assert read.merchant_account.last_transaction_date == '2025-03-28T00:00:00.0000000'
assert read.merchant_account.total_order_count == 6
assert read.merchant_account.last_payment_amount == 55.99


class TestPayByBankKeyAndRiskSerialization:

def _request(self):
request = PaymentSetupsRequest()
request.processing_channel_id = 'pc_aaaaaaaaaaaaaaaaaaaaaaaaaa'
request.amount = 1000
request.currency = Currency.GBP
pay_by_bank = PayByBank()
pay_by_bank.bank_id = 'ob-natwest'
methods = PaymentMethods()
methods.paybybank = pay_by_bank
request.payment_methods = methods
risk = PaymentSetupRisk()
risk.enabled = False
request.risk = risk
return request

def test_request_sends_the_literal_paybybank_key(self):
body = json.dumps(self._request(), cls=JsonSerializer)

assert '"paybybank"' in body
assert 'pay_by_bank' not in body
assert json.loads(body)['payment_methods'] == {'paybybank': {'bank_id': 'ob-natwest'}}

def test_request_sends_risk_enabled_false(self):
assert _serialize(self._request())['risk'] == {'enabled': False}

def test_risk_enabled_true_serializes(self):
risk = PaymentSetupRisk()
risk.enabled = True

assert _serialize(risk) == {'enabled': True}

def test_request_round_trip_keeps_paybybank_and_risk(self):
read = ResponseWrapper(None, _serialize(self._request()))

assert read.payment_methods.paybybank.bank_id == 'ob-natwest'
assert read.risk.enabled is False
assert not hasattr(read.payment_methods, 'pay_by_bank')

def test_response_reads_paybybank_action(self):
response = ResponseWrapper(None, {
'id': 'pset_123',
'risk': {'enabled': True},
'payment_methods': {
'paybybank': {
'status': 'action_required',
'flags': [],
'action': {
'type': 'select_bank',
'banks': [{
'bank_id': 'ob-natwest',
'display_name': 'NatWest',
'logo_url': 'https://example.com/natwest.png',
'available': True,
}],
},
},
},
})

method = response.payment_methods.paybybank
assert method.status == 'action_required'
assert method.flags == []
assert method.action.type == 'select_bank'
bank = method.action.banks[0]
assert bank.bank_id == 'ob-natwest'
assert bank.display_name == 'NatWest'
assert bank.logo_url == 'https://example.com/natwest.png'
assert bank.available is True
assert response.risk.enabled is True
Loading