Skip to content

Commit

Permalink
feat(ad-hoc): support apm pay and tokenize in example (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrii-vysotskyi-cko authored Oct 2, 2024
1 parent 92ff6b2 commit 3d65f04
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 25 deletions.
20 changes: 10 additions & 10 deletions Example/Example/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@
}
}
},
"alternative-payments.flow" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Flow"
}
}
}
},
"alternative-payments.gateway" : {
"localizations" : {
"en" : {
Expand Down Expand Up @@ -111,16 +121,6 @@
}
}
},
"alternative-payments.tokenization-preference" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Should Tokenize"
}
}
}
},
"apple-pay.error-message" : {
"localizations" : {
"en" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,17 @@ final class AlternativePaymentsInteractor {
return try await invoicesService.createInvoice(request: request)
}

func authorize(invoice: POInvoice, gatewayConfigurationId: String) async throws {
func authorize(invoice: POInvoice, gatewayConfigurationId: String, saveSource: Bool) async throws {
let request = POAlternativePaymentAuthorizationRequest(
invoiceId: invoice.id, gatewayConfigurationId: gatewayConfigurationId
)
let response = try await alternativePaymentsService.authorize(request: request)
let authorizationRequest = POInvoiceAuthorizationRequest(
invoiceId: invoice.id,
source: response.gatewayToken,
allowFallbackToSale: true
saveSource: saveSource,
allowFallbackToSale: true,
clientSecret: invoice.clientSecret
)
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(request: authorizationRequest, threeDSService: threeDSService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ extension LocalizedStringResource {
/// Native payment preference.
static let nativePreference = LocalizedStringResource("alternative-payments.native-preference")

/// Tokenization preference.
static let tokenizationPreference = LocalizedStringResource("alternative-payments.tokenization-preference")
/// Payment flow.
static let flow = LocalizedStringResource("alternative-payments.flow")

/// Generic error message.
static let errorMessage = LocalizedStringResource("alternative-payments.error-message")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ struct AlternativePaymentsView: View {
Text(.AlternativePayments.gatewayConfiguration)
}
}
Picker(data: $viewModel.state.flow) { flow in
Text(flow.rawValue.capitalized)
} label: {
Text(.AlternativePayments.flow)
}
Toggle(
String(localized: .AlternativePayments.nativePreference),
isOn: $viewModel.state.preferNative
)
Toggle(
String(localized: .AlternativePayments.tokenizationPreference),
isOn: $viewModel.state.shouldTokenize
)
} header: {
Text(.AlternativePayments.gateway)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class AlternativePaymentsViewModel: ObservableObject {
self.interactor = interactor
cancellables = []
observeInteractorStateChanges()
updateStateFlows()
}

// MARK: - AlternativePaymentsViewModel
Expand Down Expand Up @@ -127,6 +128,13 @@ final class AlternativePaymentsViewModel: ObservableObject {
state.message = .init(text: errorMessage, severity: .error)
}

private func updateStateFlows() {
let flows: [AlternativePaymentsViewModelState.Flow] = [
.payment, .tokenization, .combined
]
state.flow = .init(sources: flows, id: \.self, selection: .payment)
}

// MARK: -

private func startPayment() async {
Expand All @@ -142,14 +150,21 @@ final class AlternativePaymentsViewModel: ObservableObject {
try await interactor.invoice(id: state.invoice.id)
}
var authorizationSource = gatewayConfigurationId
if state.shouldTokenize {
switch state.flow.selection {
case .payment where state.preferNative:
try await authorizeNatively(invoice: invoice, gatewayConfigurationId: gatewayConfigurationId)
case .payment:
try await interactor.authorize(
invoice: invoice, gatewayConfigurationId: gatewayConfigurationId, saveSource: false
)
case .tokenization:
let token = try await interactor.tokenize(gatewayConfigurationId: gatewayConfigurationId)
try await interactor.authorize(invoice: invoice, customerToken: token)
authorizationSource = token.id
} else if state.preferNative {
try await authorizeNatively(invoice: invoice, gatewayConfigurationId: gatewayConfigurationId)
} else {
try await interactor.authorize(invoice: invoice, gatewayConfigurationId: gatewayConfigurationId)
case .combined:
try await interactor.authorize(
invoice: invoice, gatewayConfigurationId: gatewayConfigurationId, saveSource: true
)
}
let successMessage = String(
localized: .AlternativePayments.successMessage, replacements: invoice.id, authorizationSource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ import ProcessOutUI

struct AlternativePaymentsViewModelState {

enum Flow: String, Hashable {

/// One time payment.
case payment

/// Payment method should be tokenized.
case tokenization

/// Combined payment and tokenization.
case combined
}

struct GatewayConfiguration: Identifiable {

/// Item identifier.
Expand Down Expand Up @@ -53,8 +65,8 @@ struct AlternativePaymentsViewModelState {
/// Boolean value indicating whether native flow should be preferred if available.
var preferNative = false

/// Boolean value indicating whether payment method should be tokenized before authorizing invoice.
var shouldTokenize = false
/// Payment flow.
var flow: PickerData<Flow, Flow>! // swiftlint:disable:this implicitly_unwrapped_optional

/// Currently presented native alternative payment.
var nativePayment: NativePayment?
Expand Down

0 comments on commit 3d65f04

Please sign in to comment.