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
33 changes: 33 additions & 0 deletions checkout_sdk/apm/bacs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from __future__ import absolute_import

from enum import Enum

from checkout_sdk.common.enums import Currency


# The type of pre-notification being sent to the payer.
class BacsNotificationType(str, Enum):
ADVANCE_NOTICE = 'advance_notice'


class BacsNotificationRequest:
r"""Bacs Direct Debit notification request.

collection_date is a yyyy-MM-dd string. Do not pass a datetime: the serializer emits a full ISO
timestamp for it, which this field rejects, and a date object raises inside the serializer.

source_id matches the pattern ^(src)_(\w{26})$. amount is in the currency's minor unit with a
minimum of 1. currency is min 3 max 3 characters. reference is max 50 and billing_descriptor
max 25 characters. customer_email and support_email are email addresses, and support_phone is in
E.164 format. reference and support_phone are the only optional properties.
"""
source_id: str
notification_type: BacsNotificationType
collection_date: str
amount: int
currency: Currency
reference: str
customer_email: str
billing_descriptor: str
support_email: str
support_phone: str
33 changes: 33 additions & 0 deletions checkout_sdk/apm/bacs_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from __future__ import absolute_import

from checkout_sdk.api_client import ApiClient
from checkout_sdk.apm.bacs import BacsNotificationRequest
from checkout_sdk.authorization_type import AuthorizationType
from checkout_sdk.checkout_configuration import CheckoutConfiguration
from checkout_sdk.client import Client


class BacsClient(Client):
__APMS_PATH = 'apms'
__BACS_PATH = 'bacs'
__NOTIFICATIONS_PATH = 'notifications'

def __init__(self, api_client: ApiClient, configuration: CheckoutConfiguration):
super().__init__(api_client=api_client,
configuration=configuration,
authorization_type=AuthorizationType.SECRET_KEY)

def send_notification(self, bacs_notification_request: BacsNotificationRequest):
"""Sends a Bacs Direct Debit pre-notification (advance notice) to a payer ahead of collecting
funds from their account.

Args:
bacs_notification_request: The pre-notification details.

Returns:
The notification event, carrying event_id.
"""
return self._api_client.post(
self.build_path(self.__APMS_PATH, self.__BACS_PATH, self.__NOTIFICATIONS_PATH),
self._sdk_authorization(),
bacs_notification_request)
2 changes: 2 additions & 0 deletions checkout_sdk/checkout_apm_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import absolute_import

from checkout_sdk.api_client import ApiClient
from checkout_sdk.apm.bacs_client import BacsClient
from checkout_sdk.apm.ideal_client import IdealClient
from checkout_sdk.checkout_configuration import CheckoutConfiguration

Expand All @@ -9,3 +10,4 @@ class CheckoutApmApi:

def __init__(self, api_client: ApiClient, configuration: CheckoutConfiguration):
self.ideal = IdealClient(api_client=api_client, configuration=configuration)
self.bacs = BacsClient(api_client=api_client, configuration=configuration)
66 changes: 61 additions & 5 deletions checkout_sdk/common/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ class PaymentSourceType(str, Enum):
TWINT = 'twint'
VIPPS = 'vipps'
BLIK = 'blik'
BACS = 'bacs'


class ChallengeIndicator(str, Enum):
Expand Down Expand Up @@ -510,6 +511,8 @@ class InstrumentType(str, Enum):
CARD = 'card'
SEPA = 'sepa'
ACH = 'ach'
BACS = 'bacs'
# Previous API (ABC) only - the current API's instrument type does not declare this value.
CARD_TOKEN = 'card_token'


Expand All @@ -519,11 +522,29 @@ class AccountType(str, Enum):
CASH = 'cash'


# ACH-specific account type. Distinct from AccountType because the ACH endpoint's
# accepted values are a different set (`savings`, `checking`) — sharing the
# AccountType enum here would let callers pass `current` or `cash` which the
# ACH API rejects.
class AchAccountType(str, Enum):
class AchSourceAccountType(str, Enum):
"""The type of Direct Debit account on an ACH payment source.

PaymentRequestAchSource is the only position declaring this set. AccountType is
savings / current / cash and serves the bank-account positions, so it cannot express
checking. AchInstrumentAccountType is savings / checking and serves the stored ACH
instrument positions, so it does not declare cash.
"""
SAVINGS = 'savings'
CHECKING = 'checking'
CASH = 'cash'


class AchInstrumentAccountType(str, Enum):
"""The type of Direct Debit account on a stored ACH instrument.

Serves the five stored ACH instrument positions, which declare savings and checking only.
Named for its position so it cannot be confused with the two neighbours that declare
different value sets: AchSourceAccountType is savings / checking / cash and serves
PaymentRequestAchSource, and payments.setups.setups.AchAccountType is
savings / current / cash and serves the PaymentSetups Ach schema. Passing the wrong one
sends a value the target schema rejects.
"""
SAVINGS = 'savings'
CHECKING = 'checking'

Expand All @@ -535,9 +556,44 @@ class SepaMandateType(str, Enum):
B2B = 'B2B'


# The type of payment for a SEPA instrument. The wire values are lowercase.
# The equivalent Bacs Direct Debit field is capitalised, so do not share one enum between the two.
# Do not use checkout_sdk.payments.payments.PaymentType either: it serializes capitalised values and
# also carries MOTO, Installment, PayLater and Unscheduled, which SEPA does not allow.
class SepaPaymentType(str, Enum):
RECURRING = 'recurring'
REGULAR = 'regular'


# The type of payment for a Bacs Direct Debit instrument. The wire values are capitalised.
# The equivalent SEPA field is lowercase, so do not share one enum between the two.
class BacsPaymentType(str, Enum):
RECURRING = 'Recurring'
REGULAR = 'Regular'


# The type of account holder on a stored instrument. The instrument schemas declare individual and
# corporate only, unlike AccountHolderType which also carries government.
class InstrumentAccountHolderType(str, Enum):
INDIVIDUAL = 'individual'
CORPORATE = 'corporate'


# Every position this enum serves declares individual, corporate and government:
# - common.common.AccountHolder.type (AccountHolder schema)
# - accounts.accounts.AccountsAccountHolder.type
# - instruments.instruments.BankAccountFieldQuery.account_holder_type
# (the account-holder-type query parameter of
# GET /validation/bank-accounts/{country}/{currency})
class AccountHolderType(str, Enum):
INDIVIDUAL = 'individual'
CORPORATE = 'corporate'
GOVERNMENT = 'government'

# Possibly obsolete - do not use.
#
# Retained rather than removed because removal is breaking and needs confirmation from the API
# owners that no undocumented position accepts it. Nothing in this SDK references it.
INSTRUMENT = 'instrument'


Expand Down
Loading
Loading