Skip to content

feat: Add domain foundation + test data factory#1633

Open
bthebladeprimer wants to merge 2 commits into
bn/feature/cc-03-sdk-refactorsfrom
bn/feature/cc-04-domain-foundation
Open

feat: Add domain foundation + test data factory#1633
bthebladeprimer wants to merge 2 commits into
bn/feature/cc-03-sdk-refactorsfrom
bn/feature/cc-04-domain-foundation

Conversation

@bthebladeprimer
Copy link
Copy Markdown
Contributor

Summary

  • Adds domain models: InternalPaymentMethod, PaymentResult for internal payment state management
  • Adds repository protocols for all payment methods (ACH, Apple Pay, Card, Klarna, PayPal, QR Code, Web Redirect, Form Redirect)
  • Adds domain interactors for payment processing, card network detection, and input validation
  • Adds PaymentMethodMapper for converting between API and domain models
  • Adds comprehensive TestData factory with extensions for addresses, cards, config, contacts, errors, payment methods, and validation

Context

PR 4 of 15 in the CheckoutComponents feature split. Establishes the domain layer foundation that all subsequent PRs depend on. Depends on PR 3 (#1632).

Tracker: https://www.notion.so/32fca65dc30e81dabf66f33e2b58c3a1

Test plan

  • Verify domain model tests pass (InternalPaymentMethodTests, PaymentMethodMapperTests)
  • Verify ProcessPayPalPaymentInteractorTests passes
  • Confirm TestData factory compiles and provides valid test fixtures
  • Run: xcodebuild -workspace PrimerSDK.xcworkspace -scheme PrimerSDKTests -destination "platform=iOS Simulator,name=iPhone 16" test

@bthebladeprimer bthebladeprimer requested a review from a team as a code owner March 26, 2026 15:38
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 26, 2026

Warnings
⚠️ > Pull Request size seems relatively large. If this Pull Request contains multiple changes, please split each into separate PR will helps faster, easier review.

Generated by 🚫 Danger Swift against 0e73d61

@bthebladeprimer bthebladeprimer self-assigned this Mar 26, 2026
@bthebladeprimer bthebladeprimer marked this pull request as draft March 26, 2026 16:31
@bthebladeprimer bthebladeprimer force-pushed the bn/feature/cc-04-domain-foundation branch from 8e4c043 to a9450d7 Compare March 31, 2026 14:06
@bthebladeprimer bthebladeprimer marked this pull request as ready for review April 3, 2026 18:09

return PaymentResult(
paymentId: paymentResponse.paymentId,
status: .success,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paymentResponse.status?

paymentId: paymentResponse.paymentId,
status: .success,
token: token,
amount: nil,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be nil?


import Foundation

public struct PaymentResult {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is public and is a much larger exposure than we currently offer today in Auto Flow, is this a conscious choice?

self.cornerRadius = cornerRadius
}

static func == (lhs: InternalPaymentMethod, rhs: InternalPaymentMethod) -> Bool {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on not comparing every attribute - is this an intentional choice?

}

func execute() async throws -> PaymentResult {
let intent = PrimerInternal.shared.intent
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one example (there are others,ill only comment once) of accessing a singleton without being in a @mainactor. Is this a potential issue? Perhaps @MainActor or MainActor.run {} ?

)

return PaymentResult(
paymentId: paymentResponse.id ?? "",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This string fallback stands out - is it required? What is the background if yes?


import Foundation

protocol HeadlessRepository {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other repositories include @available(iOS 15.0, *) - should we have it here for consistency?

@available(iOS 15.0, *)
struct ApplePayRequestBuilder {

static func build() throws -> ApplePayRequest {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We access 4 singletons here which makes this hard to test. Perhaps we can inject them

}

@available(iOS 15.0, *)
struct AchStripeData {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where this can or cannot be printed around the codebase, but for sensitive types like this I would like to see a CustomStringConvertible which redacts stripeClientSecret and decodedJwtToken

case requires3DS
case requiresAction

init(from apiStatus: Response.Body.Payment.Status) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 8 statuses, but can only be initialised from 3 - conscious choice?

Primer.shared.delegate?.primerDidResumeWith?(resumeToken) { decision in
continuation.resume(returning: decision)
}
} else if PrimerInternal.shared.sdkIntegrationType == .checkoutComponents {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice we bypass the delegate here - expected with the new integration method - curious how we surface these events to the merchant now?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And critically allow them to interject/halt in the flow as they do today

@bthebladeprimer bthebladeprimer force-pushed the bn/feature/cc-03-sdk-refactors branch from 2e87ec4 to 9c8d8ab Compare April 15, 2026 12:59
@bthebladeprimer bthebladeprimer requested a review from a team as a code owner April 15, 2026 12:59
@bthebladeprimer bthebladeprimer force-pushed the bn/feature/cc-04-domain-foundation branch from 708e244 to 0e73d61 Compare April 15, 2026 13:01
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