Skip to content

Release 4.1.0 - BACS Direct Debit notifications + refactor - #233

Merged
david-ruiz-cko merged 1 commit into
mainfrom
release/4.1.0
Sep 7, 2026
Merged

Release 4.1.0 - BACS Direct Debit notifications + refactor#233
david-ruiz-cko merged 1 commit into
mainfrom
release/4.1.0

Conversation

@david-ruiz-cko

Copy link
Copy Markdown
Contributor

Breaking changes (check at the end image)

This release adds comprehensive support for Bacs Direct Debit to the SDK, including new models, client methods, and tests. It introduces the ability to send Bacs pre-notification requests, updates enums and instrument data structures to support Bacs, and adds serialization and integration tests to ensure correctness. The changes also clarify and expand SEPA and ACH instrument handling for consistency.

Bacs Direct Debit Support

  • Added BacsNotificationRequest and BacsNotificationType models for Bacs pre-notification requests, with full property validation and documentation.
  • Introduced BacsClient with a send_notification method to POST Bacs notifications, and exposed it via the main API client. [1] [2] [3]
  • Added RequestBacsSource for payment requests using Bacs instruments.

Enums and Instrument Data Model Updates

  • Extended PaymentSourceType and InstrumentType enums to include Bacs. Added specific enums for Bacs and SEPA payment types, and clarified account holder types. [1] [2] [3]
  • Refactored instrument data structures to add dedicated classes for Bacs, SEPA, and ACH, including billing address and account holder models, and created request/response classes for creating and updating these instruments. [1] [2] [3] [4] [5]

Testing and Serialization

  • Added unit, integration, and serialization tests for Bacs notification requests, covering all properties, optional fields, and enum values. [1] [2] [3]
  • Ensured the Bacs client is only exposed on the current platform API, not the legacy one.

SEPA and ACH Improvements

  • Clarified the difference between legacy and current SEPA source classes, and improved documentation. [1] [2]
  • Refined the handling and updating of SEPA and ACH instrument data and requests for consistency with Bacs. [1] [2] [3]

Minor Fixes and Cleanups

  • Corrected and clarified enum values for payment networks and account holder types.

These changes collectively enable robust Bacs Direct Debit support, align SEPA/ACH handling, and ensure the SDK is well-tested for these new capabilities.

Breaking changes imageimageimage

The instruments models were reshaped so that each scheme (SEPA, Bacs, ACH) and each operation has its
own type. Previously a single InstrumentData served both SEPA and ACH, with comments marking
which attributes belonged to which scheme, and the shared AccountHolder was reused on schemas that
declare a fraction of its 15 attributes.

Removed classes

Removed Replacement
checkout_sdk.instruments.instruments.InstrumentData SepaInstrumentData (SEPA) / AchInstrumentData (ACH)

The removed class carried nine attributes across two schemes: account_number, country,
currency, payment_type, mandate_id, date_of_signature, type (SEPA) and account_type,
bank_code (ACH). All are present on the replacements.

Removed attributes

Class Attribute Why
CreateSepaInstrumentRequest token Not declared by StoreSepaInstrumentRequest.
CreateBankAccountInstrumentRequest bank_details The schema declares this object as bank. The class already had a correct bank attribute, so bank_details serialized under a key the API does not declare. Use bank.
UpdateBankAccountInstrumentRequest bank_details Same, but this class had only bank_details, so the bank details could not be sent at all. Renamed to bank.

Retyped attributes

Class Attribute Before After
CreateSepaInstrumentRequest instrument_data InstrumentData SepaInstrumentData
CreateSepaInstrumentRequest account_holder AccountHolder (15 attrs) SepaAccountHolder (5 attrs)
CreateAchInstrumentRequest instrument_data InstrumentData AchInstrumentData
CreateAchInstrumentRequest account_holder AccountHolder (15 attrs) AchAccountHolder (4 attrs, no billing address)
SepaInstrumentData date_of_signature datetime (on the old class) str

Changed enum values

PaymentNetwork — four wire values corrected to the lowercase forms the
payment-network query parameter declares. The member names are unchanged, so this is source
compatible:

Member Before After
PaymentNetwork.FPS 'Fps' 'fps'
PaymentNetwork.ACH 'Ach' 'ach'
PaymentNetwork.FEDWIRE 'Fedwire' 'fedwire'
PaymentNetwork.SWIFT 'Swift' 'swift'

Mitigating fact: the four old values were rejected by the API, so no working integration can have
depended on them. Filtering bank-account fields by FPS, ACH, Fedwire or SWIFT was silently broken
before this change.

Why this is worth a major

Three of these were live defects, not tidying:

  1. payment_type sent a value the API rejects. InstrumentData.payment_type was typed
    checkout_sdk.payments.payments.PaymentType, whose values are capitalised ('Recurring',
    'Regular'). The specification declares the SEPA field lowercase. Anyone following the annotation
    was sending a rejected value. Split into SepaPaymentType (lowercase) and BacsPaymentType
    (capitalised, which is what Bacs Direct Debit genuinely uses), with a regression test pinning both
    so they cannot be unified again.
  2. PaymentNetwork — as above.
  3. bank_details never reached the API, and on the update request there was no way to send the
    bank details at all.

Migration

# Before
from checkout_sdk.instruments.instruments import CreateSepaInstrumentRequest, InstrumentData
from checkout_sdk.payments.payments import PaymentType
from checkout_sdk.common.common import AccountHolder

data = InstrumentData()
data.account_number = 'FR7630006000011234567890189'
data.country = Country.FR
data.currency = Currency.EUR
data.payment_type = PaymentType.RECURRING        # sent 'Recurring' - rejected

holder = AccountHolder()
holder.first_name = 'John'
holder.last_name = 'Smith'
holder.phone = phone                             # not in the SEPA schema
holder.billing_address = address

request = CreateSepaInstrumentRequest()
request.instrument_data = data
request.account_holder = holder

# After
from checkout_sdk.common.enums import SepaMandateType, SepaPaymentType
from checkout_sdk.instruments.instruments import (
    CreateSepaInstrumentRequest, SepaAccountHolder, SepaBillingAddress, SepaInstrumentData,
)

data = SepaInstrumentData()
data.type = SepaMandateType.CORE                 # new: was on the old class but undocumented
data.account_number = 'FR7630006000011234567890189'
data.country = Country.FR
data.currency = Currency.EUR
data.payment_type = SepaPaymentType.RECURRING    # sends 'recurring'
data.date_of_signature = '2020-01-01'            # str, not datetime - see below

billing_address = SepaBillingAddress()
billing_address.address_line1 = 'Evergreen Terrace'
billing_address.address_line2 = '742'
billing_address.city = 'Paris'
billing_address.zip = '75000'
billing_address.country = Country.FR

holder = SepaAccountHolder()
holder.first_name = 'John'
holder.last_name = 'Smith'
holder.billing_address = billing_address

request = CreateSepaInstrumentRequest()
request.instrument_data = data
request.account_holder = holder
Two things to watch when upgrading

@david-ruiz-cko
david-ruiz-cko requested a review from a team September 4, 2026 09:55
@agent-wall-e

agent-wall-e Bot commented Sep 4, 2026

Copy link
Copy Markdown

🟡 Risk Classification: MINOR

Approval route: AI Review + Human Approval
Rollback controls: Staged rollout + rollback

Classification reasons

  • no_low_class_matched
  • prod_source_modified

Operational gates

  • ✅ jira_ticket
  • ✅ independent_review

Files analysed: 1


wall-e 2026.06.19-02 · policy 376219bc71e6…

@agent-wall-e

agent-wall-e Bot commented Sep 4, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
no_low_class_matched informational §2.2 (fall-through) None of the deterministic Low classes (§2.2.3, §2.2.4, §2.2.7, docs-only) applied; classifier fell through to LLM evaluation.
prod_source_modified informational §2.1 M7 (informational) At least one file is non-doc, non-test, non-IaC — i.e. application source code was modified.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@agent-wall-e

agent-wall-e Bot commented Sep 4, 2026

Copy link
Copy Markdown

🔵 Advisory review: Sound, but needs your judgement

This PR needs a human approval. The code itself reads as correct; whether it should land depends on context I don't have.

The visible diff only bumps the version string from 4.0.0 to 4.1.0; all the substantive changes described (BacsClient, new models, instrument refactors, breaking changes to InstrumentData) are not present in the provided diff and cannot be reviewed.

For you to decide

  • The diff is partial — only properties.py is shown, so correctness of the Bacs models, client, enum changes, instrument data refactor, and tests cannot be assessed from this diff alone.
  • The PR description documents several breaking changes (removed InstrumentData, removed bank_details attribute, removed token from CreateSepaInstrumentRequest); a human reviewer must confirm these are intentional and communicated to consumers before approving a version bump.
  • A semver minor bump (4.0.0 → 4.1.0) is inconsistent with the described breaking changes — the PR itself labels these as breaking, which would typically warrant a major version bump; a human must decide if this versioning is intentional.

This is not an approval. wall-e cannot auto-approve this PR — it is an opinion to help whoever does. Advisory review · us.anthropic.claude-sonnet-4-6 · wall-e 2026.06.19-02

@sonarqubecloud

sonarqubecloud Bot commented Sep 4, 2026

Copy link
Copy Markdown

@david-ruiz-cko
david-ruiz-cko merged commit 3c84dd0 into main Sep 7, 2026
5 of 6 checks passed
@david-ruiz-cko
david-ruiz-cko deleted the release/4.1.0 branch September 7, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants