Skip to content

fix(ad-hoc): improve native alternative payment state handling - #552

Draft
andrii-vysotskyi-cko wants to merge 9 commits into
masterfrom
feat/napm-improvements
Draft

andrii-vysotskyi-cko wants to merge 9 commits into
masterfrom
feat/napm-improvements

Conversation

@andrii-vysotskyi-cko

Copy link
Copy Markdown
Collaborator

Description

Native alternative payment improvements that don't depend on payment finalization, ported from #539.

Solution

  • Poll only while payment is PENDING; new steps are now accepted while awaiting completion.
  • Ignore redirect-result-unexpected and redirect-result-unexpected-for-step when resolving return deep links; polling picks up the actual state.
  • setState(with:) reports its own failures with the response's payment state; callers only handle request errors.
  • Store payment state in interactor states and report it in didFail.
  • cancel() always fails the payment, unless it is already completed. Check cancellation before state changes and before starting a redirect.
  • In submit(), separate request errors (recoverable) from response handling errors.
  • Add Task.poCheckCancellation() and metadata to POInvoiceCreationRequest.
  • Clarify enableHeadlessMode: it only skips the first redirect's confirmation, has no effect when redirectButton is nil, and with deep links start() usually returns while payment is pending.

Notes

  • Unknown or failed states returned while polling now fail right away instead of after the timeout.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Automatic redirects retain the awaiting-completion state, causing valid pending → redirect → pending flows to fail with a generic error instead of resuming polling.

1 open issue
What changed in this PR

This PR improves native alternative payment handling across polling, redirects, cancellation, and failure reporting.

Changes:

  • Poll only while payment is pending, allowing new steps and terminal states to be handled immediately.
  • Preserve payment-state context in failures, strengthen cancellation handling, and ignore obsolete redirect-result errors.
  • Add invoice metadata support and clarify headless-mode documentation.
File Description
Sources/​ProcessOutUI/​Sources/​Modules/​NativeAlternativePayment/​Interactor/​NativeAlternativePaymentInteractorState.swift Stores payment state for failure reporting.
Sources/​ProcessOutUI/​Sources/​Modules/​NativeAlternativePayment/​Interactor/​NativeAlternativePaymentDefaultInteractor.swift Updates transitions, cancellation, submission errors, and deep-link handling.
Sources/​ProcessOutUI/​Sources/​Modules/​NativeAlternativePayment/​Interactor/​Adapter/​DefaultNativeAlternativePaymentServiceAdapter.swift Limits polling to pending payments.
Sources/​ProcessOutUI/​Sources/​Modules/​NativeAlternativePayment/​Configuration/​PONativeAlternativePaymentConfiguration.swift Clarifies headless redirect behavior in documentation.
Sources/​ProcessOut/​Sources/​Repositories/​Shared/​Responses/​Failure/​POFailureCode.swift Adds unexpected redirect-result failure codes.
Sources/​ProcessOut/​Sources/​Repositories/​Invoices/​Requests/​POInvoiceCreationRequest.swift Adds optional invoice metadata.
Sources/​ProcessOut/​Sources/​Core/​Utils/​Task+Cancellation.swift Adds a cancellation check that throws POFailure.

Review effort: Balanced

switch result {
case let .success(response):
return response.state != .success
return response.state == .pending // Any other state is handled by caller

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

A critical polling flaw can repeatedly reset the configured timeout, and cancellation during the redirect delegate callback can still allow an external redirect to launch.

2 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Recheck cancellation after willStartRedirect before opening the deep link

Sources/​ProcessOutUI/​Sources/​Modules/​NativeAlternativePayment/​Interactor/​NativeAlternativePaymentDefaultInteractor.swift:415

If the synchronous willStartRedirect delegate callback calls the component's cancel(), the payment enters failure after this cancellation check, but a deep-link redirect still reaches UIApplication.open. Recheck cancellation and terminal state after notifying the delegate so cancelling at this boundary does not launch the external redirect.

Review effort: Balanced

)
let response = try await serviceAdapter.expectPaymentCompletion(with: request)
try await setState(with: response)
await setState(with: response)

This branch has not been deployed

No deployments
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