Skip to content

Commit d71df5e

Browse files
committed
demo app changes for checkout app switch
1 parent 953908f commit d71df5e

File tree

3 files changed

+80
-72
lines changed

3 files changed

+80
-72
lines changed

Demo/Demo/CardPayments/CardPaymentViewModel/CardPaymentViewModel.swift

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ class CardPaymentViewModel: ObservableObject {
1212

1313
private var cardClient: CardClient?
1414

15+
/// Card supports:
16+
/// - S1: no vault (paymentSource = nil)
17+
/// - S5: vault (paymentSource.card.attributes.vault)
1518
func createOrder(
1619
amount: String,
1720
selectedMerchantIntegration: MerchantIntegration,
@@ -21,37 +24,26 @@ class CardPaymentViewModel: ObservableObject {
2124
) async throws {
2225

2326
let amountRequest = Amount(currencyCode: "USD", value: amount)
24-
// TODO: might need to pass in payee as payee object or as auth header
2527

26-
var vaultCardPaymentSource: VaultCardPaymentSource?
28+
var paymentSource: OrderPaymentSource?
2729
if shouldVault {
28-
var customer: Customer?
29-
if let customerID {
30-
customer = Customer(id: customerID)
31-
}
30+
let customer = customerID.map { Customer(id: $0) }
3231
let attributes = Attributes(vault: Vault(storeInVault: "ON_SUCCESS"), customer: customer)
33-
let card = VaultCard(attributes: attributes)
34-
vaultCardPaymentSource = VaultCardPaymentSource(card: card)
35-
}
36-
37-
var vaultPaymentSource: VaultPaymentSource?
38-
if let vaultCardPaymentSource {
39-
vaultPaymentSource = .card(vaultCardPaymentSource)
32+
let card = CardSource(attributes: attributes)
33+
paymentSource = .card(OrderCardPaymentSource(card: card))
4034
}
4135

42-
let orderRequestParams = CreateOrderParams(
36+
let params = CreateOrderParams(
4337
applicationContext: nil,
4438
intent: intent,
4539
purchaseUnits: [PurchaseUnit(amount: amountRequest)],
46-
paymentSource: vaultPaymentSource
40+
paymentSource: paymentSource
4741
)
4842

4943
do {
50-
DispatchQueue.main.async {
51-
self.state.createdOrderResponse = .loading
52-
}
44+
DispatchQueue.main.async { self.state.createdOrderResponse = .loading }
5345
let order = try await DemoMerchantAPI.sharedService.createOrder(
54-
orderParams: orderRequestParams, selectedMerchantIntegration: selectedMerchantIntegration
46+
orderParams: params, selectedMerchantIntegration: selectedMerchantIntegration
5547
)
5648
DispatchQueue.main.async {
5749
self.state.createdOrderResponse = .loaded(order)

Demo/Demo/Models/CreateOrderParams.swift

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,81 @@
11
struct CreateOrderParams: Encodable {
22

3-
let applicationContext: ApplicationContext?
4-
let intent: String
5-
var purchaseUnits: [PurchaseUnit]?
6-
var paymentSource: VaultPaymentSource?
3+
var applicationContext: ApplicationContext?
4+
var intent: String
5+
var purchaseUnits: [PurchaseUnit]
6+
var paymentSource: OrderPaymentSource?
77
}
88

99
struct ApplicationContext: Codable {
1010

1111
let userAction: String
1212
let shippingPreference: String
13-
14-
enum CodingKeys: String, CodingKey {
15-
case userAction
16-
case shippingPreference
17-
}
1813
}
1914

20-
enum VaultPaymentSource: Encodable {
21-
case card(VaultCardPaymentSource)
22-
case paypal(VaultPayPalPaymentSource)
15+
// MARK: - Payment source (general, for both vault, and non-vault)
16+
17+
enum OrderPaymentSource: Encodable {
18+
19+
case paypal(OrderPayPalPaymentSource)
20+
case card(OrderCardPaymentSource)
2321

2422
func encode(to encoder: Encoder) throws {
2523
var container = encoder.singleValueContainer()
2624
switch self {
27-
case .card(let cardSource):
28-
try container.encode(cardSource)
29-
case .paypal(let paypalSource):
30-
try container.encode(paypalSource)
25+
case .paypal(let source): try container.encode(source)
26+
case .card(let source): try container.encode(source)
3127
}
3228
}
3329
}
3430

35-
struct VaultPayPalPaymentSource: Encodable {
31+
struct OrderPayPalPaymentSource: Encodable {
3632

37-
let paypal: VaultPayPal
33+
let paypal: PayPalSource
3834
}
3935

40-
struct VaultPayPal: Encodable {
36+
struct OrderCardPaymentSource: Encodable {
4137

42-
let attributes: Attributes
43-
let experienceContext: ExperienceContext
38+
let card: CardSource
4439
}
4540

46-
struct ExperienceContext: Encodable {
41+
// Attributes are only for vault now
42+
struct PayPalSource: Encodable {
43+
44+
var attributes: Attributes?
45+
var experienceContext: PayPalExperienceContext?
46+
}
47+
48+
struct CardSource: Encodable {
49+
50+
var attributes: Attributes?
51+
}
52+
53+
// MARK: - PayPal experience context
54+
55+
struct PayPalExperienceContext: Encodable {
4756

48-
// these fields are not encoded for our SDK but are required for create order with PayPal vault option
4957
let returnUrl: String
5058
let cancelUrl: String
59+
var appSwitchContext: AppSwitchContext?
5160
}
5261

53-
struct VaultCardPaymentSource: Encodable {
62+
struct AppSwitchContext: Encodable {
5463

55-
let card: VaultCard
64+
let nativeApp: NativeApp
5665
}
5766

58-
struct VaultCard: Encodable {
67+
struct NativeApp: Encodable {
5968

60-
let attributes: Attributes
69+
let osType: String
70+
let appUrl: String
6171
}
6272

73+
// MARK: - Vault attributes
74+
6375
struct Attributes: Encodable {
6476

6577
let vault: Vault
6678
let customer: Customer?
67-
6879
init(vault: Vault, customer: Customer? = nil) {
6980
self.vault = vault
7081
self.customer = customer
@@ -76,7 +87,6 @@ struct Vault: Encodable {
7687
let storeInVault: String
7788
let usageType: String?
7889
let customerType: String?
79-
8090
init(storeInVault: String, usageType: String? = nil, customerType: String? = nil) {
8191
self.storeInVault = storeInVault
8292
self.usageType = usageType
@@ -132,7 +142,7 @@ struct Amount: Encodable {
132142
let currencyCode: String
133143
let value: String
134144
var breakdown: Breakdown?
135-
145+
136146
struct Breakdown: Encodable {
137147

138148
let shipping: ItemTotal

Demo/Demo/PayPalWebPayments/PayPalWebViewModel/PayPalWebViewModel.swift

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class PayPalWebViewModel: ObservableObject {
1010
@Published var order: Order?
1111
@Published var checkoutResult: PayPalWebCheckoutResult?
1212

13+
let appSwitchURL = "https://ppcp-mobile-demo-sandbox-87bbd7f0a27f.herokuapp.com"
14+
1315
var payPalWebCheckoutClient: PayPalWebCheckoutClient?
1416

1517
var orderID: String? {
@@ -19,42 +21,46 @@ class PayPalWebViewModel: ObservableObject {
1921
let configManager = CoreConfigManager(domain: "PayPalWeb Payments")
2022
private var payPalDataCollector: PayPalDataCollector?
2123

22-
func createOrder(shouldVault: Bool) async throws {
24+
/// S1: No payment source (non app-switch, non vault)
25+
/// S2: PayPal app-switch (no vault) -> experienceContext with appSwitchContext
26+
/// S3: PayPal vault (no app-switch) -> attributes.vault + experienceContext
27+
/// S4: PayPal vault + app-switch -> attributes.vault + experienceContext.appSwitchContext
28+
func createOrder(shouldVault: Bool, appSwitch: Bool = false) async throws {
2329
let amountRequest = Amount(currencyCode: "USD", value: "10.00")
2430

25-
// TODO: might need to pass in payee as payee object or as auth header
26-
var vaultPayPalPaymentSource: VaultPayPalPaymentSource?
27-
if shouldVault {
28-
let attributes = Attributes(vault: Vault(storeInVault: "ON_SUCCESS", usageType: "MERCHANT", customerType: "CONSUMER"))
29-
// The returnURL is not used in our mobile SDK, but a required field for create order with PayPal payment source. DTPPCPSDK-1492 to track this issue
30-
let paypal = VaultPayPal(
31-
attributes: attributes,
32-
experienceContext: ExperienceContext(
33-
returnUrl: "https://example.com/returnUrl",
34-
cancelUrl: "https://example.com/cancelUrl"
35-
)
31+
var paymentSource: OrderPaymentSource?
32+
33+
if appSwitch || shouldVault {
34+
// experienceContext is required for PayPal vault and for app switch
35+
let nativeApp = NativeApp(osType: "IOS", appUrl: appSwitchURL)
36+
let experience = PayPalExperienceContext(
37+
returnUrl: appSwitchURL + "/success",
38+
cancelUrl: appSwitchURL + "/cancel",
39+
appSwitchContext: appSwitch ? AppSwitchContext(nativeApp: nativeApp) : nil
3640
)
37-
vaultPayPalPaymentSource = VaultPayPalPaymentSource(paypal: paypal)
38-
}
3941

40-
var vaultPaymentSource: VaultPaymentSource?
41-
if let vaultPayPalPaymentSource {
42-
vaultPaymentSource = .paypal(vaultPayPalPaymentSource)
42+
let attributes: Attributes? = shouldVault
43+
? Attributes(vault: Vault(
44+
storeInVault: "ON_SUCCESS",
45+
usageType: "MERCHANT",
46+
customerType: "CONSUMER"))
47+
: nil
48+
49+
let paypal = PayPalSource(attributes: attributes, experienceContext: experience)
50+
paymentSource = .paypal(OrderPayPalPaymentSource(paypal: paypal))
4351
}
4452

45-
let orderRequestParams = CreateOrderParams(
53+
let params = CreateOrderParams(
4654
applicationContext: nil,
4755
intent: intent.rawValue,
4856
purchaseUnits: [PurchaseUnit(amount: amountRequest)],
49-
paymentSource: vaultPaymentSource
57+
paymentSource: paymentSource
5058
)
5159

5260
do {
53-
DispatchQueue.main.async {
54-
self.state.createdOrderResponse = .loading
55-
}
61+
DispatchQueue.main.async { self.state.createdOrderResponse = .loading }
5662
let order = try await DemoMerchantAPI.sharedService.createOrder(
57-
orderParams: orderRequestParams,
63+
orderParams: params,
5864
selectedMerchantIntegration: DemoSettings.merchantIntegration
5965
)
6066
DispatchQueue.main.async {

0 commit comments

Comments
 (0)