Skip to content

Commit 4ef0123

Browse files
Accelerated Checkouts: automate Apple Pay supported networks from merchant configuration
1 parent deabed2 commit 4ef0123

File tree

11 files changed

+98
-35
lines changed

11 files changed

+98
-35
lines changed

Samples/ShopifyAcceleratedCheckoutsApp/ShopifyAcceleratedCheckoutsApp/ShopifyAcceleratedCheckoutsApp.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
*/
2323

24-
import PassKit
2524
import ShopifyAcceleratedCheckouts
2625
import SwiftUI
2726

@@ -78,7 +77,6 @@ private func createApplePayConfiguration(
7877

7978
return ShopifyAcceleratedCheckouts.ApplePayConfiguration(
8079
merchantIdentifier: "merchant.com.shopify.example.ShopifyAcceleratedCheckoutsApp",
81-
supportedNetworks: [.amex, .discover, .masterCard, .visa],
8280
contactFields: fields
8381
)
8482
}

Sources/ShopifyAcceleratedCheckouts/Internal/StorefrontAPI/StorefrontAPI+Types.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ extension StorefrontAPI {
3737
typealias Money = StorefrontAPI.MoneyV2
3838
typealias Address = StorefrontAPI.Address
3939
typealias ApplePayPayment = StorefrontAPI.ApplePayPayment
40+
typealias CardBrand = StorefrontAPI.CardBrand
4041
}
4142

4243
/// Represents a cart in the Storefront API
@@ -353,10 +354,20 @@ extension StorefrontAPI {
353354
/// Shop payment settings
354355
struct ShopPaymentSettings: Codable {
355356
let supportedDigitalWallets: [String]
356-
let acceptedCardBrands: [String]
357+
let acceptedCardBrands: [CardBrand]
357358
let countryCode: String
358359
}
359360

361+
/// Card brands supported by Shopify's payment system
362+
enum CardBrand: String, Codable, CaseIterable {
363+
case americanExpress = "AMERICAN_EXPRESS"
364+
case dinersClub = "DINERS_CLUB"
365+
case discover = "DISCOVER"
366+
case jcb = "JCB"
367+
case mastercard = "MASTERCARD"
368+
case visa = "VISA"
369+
}
370+
360371
// MARK: - Delivery Groups
361372

362373
/// Connection type for delivery groups
@@ -1010,7 +1021,8 @@ extension StorefrontAPI.Address {
10101021
shop.paymentSettings.countryCode
10111022

10121023
let paymentSettings = PaymentSettings(
1013-
countryCode: countryCode
1024+
countryCode: countryCode,
1025+
acceptedCardBrands: shop.paymentSettings.acceptedCardBrands
10141026
)
10151027

10161028
// Extract primary domain
@@ -1028,16 +1040,22 @@ extension StorefrontAPI.Address {
10281040
}
10291041

10301042
/// Payment settings for the shop
1043+
@available(iOS 17.0, *)
10311044
class PaymentSettings {
10321045
/// The shop's country code (e.g., "US", "CA")
10331046
let countryCode: String
10341047

1035-
init(countryCode: String) {
1048+
/// Card brands accepted by the merchant
1049+
let acceptedCardBrands: [StorefrontAPI.CardBrand]
1050+
1051+
init(countryCode: String, acceptedCardBrands: [StorefrontAPI.CardBrand] = []) {
10361052
self.countryCode = countryCode
1053+
self.acceptedCardBrands = acceptedCardBrands
10371054
}
10381055
}
10391056

10401057
/// Domain information for the shop
1058+
@available(iOS 17.0, *)
10411059
class Domain {
10421060
/// The host name of the domain (e.g., "example.myshopify.com")
10431061
let host: String

Sources/ShopifyAcceleratedCheckouts/Wallets/ApplePay/ApplePayConfiguration.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ extension ShopifyAcceleratedCheckouts {
3434
/// Configuration options for Apple Pay integration within Shopify Accelerated Checkouts.
3535
///
3636
/// This class encapsulates all necessary settings for enabling Apple Pay as a payment method,
37-
/// including merchant identification, supported payment networks, and required contact information.
37+
/// including merchant identification and required contact information. Supported payment networks
38+
/// are automatically determined based on the merchant's Shopify configuration.
3839
@Observable public class ApplePayConfiguration {
3940
/// The merchant identifier for Apple Pay transactions.
4041
///
@@ -44,12 +45,6 @@ extension ShopifyAcceleratedCheckouts {
4445
/// - See: [Apple Developer Documentation - merchantIdentifier](https://developer.apple.com/documentation/passkit_apple_pay_and_wallet/pkpaymentrequest/1619305-merchantidentifier)
4546
public let merchantIdentifier: String
4647

47-
/// Payment card networks supported for Apple Pay transactions.
48-
///
49-
/// Only card types included in this array will be displayed as available payment
50-
/// options in the Apple Pay payment sheet.
51-
public let supportedNetworks: [PKPaymentNetwork]
52-
5348
/// Contact information fields required during the Apple Pay payment flow.
5449
///
5550
/// Fields specified in this array will be marked as required in the payment sheet.
@@ -65,15 +60,14 @@ extension ShopifyAcceleratedCheckouts {
6560
///
6661
/// - Parameters:
6762
/// - merchantIdentifier: The merchant identifier registered with Apple.
68-
/// - supportedNetworks: Array of payment card networks to accept.
6963
/// - contactFields: Contact information fields to require from the customer.
64+
/// - Note: Supported payment networks are automatically determined based on the
65+
/// merchant's accepted card brands configuration in Shopify.
7066
public init(
7167
merchantIdentifier: String,
72-
supportedNetworks: [PKPaymentNetwork],
7368
contactFields: [RequiredContactFields]
7469
) {
7570
self.merchantIdentifier = merchantIdentifier
76-
self.supportedNetworks = supportedNetworks
7771
self.contactFields = contactFields
7872
}
7973
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
MIT License
3+
4+
Copyright 2023 - Present, Shopify Inc.
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
import PassKit
25+
26+
@available(iOS 17.0, *)
27+
enum CardBrandMapper {
28+
/// Maps Shopify's CardBrand enum values to Apple Pay's PKPaymentNetwork values
29+
/// - Parameter shopifyCardBrand: The card brand from Shopify's acceptedCardBrands
30+
/// - Returns: The corresponding PKPaymentNetwork, or nil if the brand is not supported by Apple Pay
31+
static func mapToPKPaymentNetwork(_ shopifyCardBrand: StorefrontAPI.CardBrand) -> PKPaymentNetwork? {
32+
switch shopifyCardBrand {
33+
case .americanExpress:
34+
return .amex
35+
case .discover:
36+
return .discover
37+
case .jcb:
38+
return .JCB
39+
case .mastercard:
40+
return .masterCard
41+
case .visa:
42+
return .visa
43+
case .dinersClub:
44+
// Diners Club is not supported by Apple Pay
45+
return nil
46+
}
47+
}
48+
49+
/// Maps an array of Shopify card brands to PKPaymentNetwork values
50+
/// - Parameter shopifyCardBrands: Array of card brands from Shopify
51+
/// - Returns: Array of PKPaymentNetwork values, filtering out any unsupported brands
52+
static func mapToPKPaymentNetworks(_ shopifyCardBrands: [StorefrontAPI.CardBrand]) -> [PKPaymentNetwork] {
53+
shopifyCardBrands.compactMap { mapToPKPaymentNetwork($0) }
54+
}
55+
}

Sources/ShopifyAcceleratedCheckouts/Wallets/ApplePay/Data/PKDecoder.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ class PKDecoder {
4949
let currencyCode = cart.cost.totalAmount.currencyCode
5050

5151
paymentRequest.merchantIdentifier = configuration.applePay.merchantIdentifier
52-
paymentRequest.supportedNetworks = configuration.applePay.supportedNetworks
52+
53+
// Map accepted card brands from Shopify to PKPaymentNetwork
54+
let acceptedCardBrands = configuration.shopSettings.paymentSettings.acceptedCardBrands
55+
paymentRequest.supportedNetworks = CardBrandMapper.mapToPKPaymentNetworks(acceptedCardBrands)
56+
5357
paymentRequest.countryCode = configuration.shopSettings.paymentSettings.countryCode
5458
paymentRequest.currencyCode = currencyCode
5559
initialCurrencyCode = currencyCode

Tests/ShopifyAcceleratedCheckoutsTests/Internal/StorefrontAPI/ShopSettingsTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class ShopSettingsTests: XCTestCase {
107107
shipsToCountries: ["US", "CA"],
108108
paymentSettings: StorefrontAPI.ShopPaymentSettings(
109109
supportedDigitalWallets: ["APPLE_PAY", "SHOP_PAY"],
110-
acceptedCardBrands: ["VISA", "MASTERCARD"],
110+
acceptedCardBrands: [.visa, .mastercard],
111111
countryCode: countryCode
112112
),
113113
moneyFormat: "${{amount}}"

Tests/ShopifyAcceleratedCheckoutsTests/TestHelpers.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
*/
2323

24-
import PassKit
2524
@testable import ShopifyAcceleratedCheckouts
2625

2726
// MARK: - Configuration Helpers
@@ -70,7 +69,8 @@ extension ShopSettings {
7069
url: "https://test-shop.myshopify.com"
7170
),
7271
paymentSettings: PaymentSettings(
73-
countryCode: "US"
72+
countryCode: "US",
73+
acceptedCardBrands: [.visa, .mastercard, .americanExpress, .discover]
7474
)
7575
)
7676
}
@@ -82,7 +82,8 @@ extension ShopSettings {
8282
url: "https://test-shop.myshopify.com"
8383
),
8484
paymentSettings: PaymentSettings = PaymentSettings(
85-
countryCode: "US"
85+
countryCode: "US",
86+
acceptedCardBrands: [.visa, .mastercard, .americanExpress, .discover]
8687
)
8788
) -> ShopSettings {
8889
return ShopSettings(
@@ -98,18 +99,15 @@ extension ShopifyAcceleratedCheckouts.ApplePayConfiguration {
9899
static var testConfiguration: ShopifyAcceleratedCheckouts.ApplePayConfiguration {
99100
return ShopifyAcceleratedCheckouts.ApplePayConfiguration(
100101
merchantIdentifier: "merchant.test.id",
101-
supportedNetworks: [.visa],
102102
contactFields: [.email, .phone]
103103
)
104104
}
105105

106106
static func testConfiguration(
107-
merchantIdentifier: String = "merchant.test.id",
108-
supportedNetworks: [PKPaymentNetwork] = [.visa]
107+
merchantIdentifier: String = "merchant.test.id"
109108
) -> ShopifyAcceleratedCheckouts.ApplePayConfiguration {
110109
return ShopifyAcceleratedCheckouts.ApplePayConfiguration(
111110
merchantIdentifier: merchantIdentifier,
112-
supportedNetworks: supportedNetworks,
113111
contactFields: [.email, .phone]
114112
)
115113
}

Tests/ShopifyAcceleratedCheckoutsTests/Wallets/ApplePay/ApplePayCallbackTests.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
*/
2323

24-
import PassKit
2524
@testable import ShopifyAcceleratedCheckouts
2625
@testable import ShopifyCheckoutSheetKit
2726
import XCTest
@@ -50,7 +49,6 @@ final class ApplePayCallbackTests: XCTestCase {
5049

5150
let applePayConfig = ShopifyAcceleratedCheckouts.ApplePayConfiguration(
5251
merchantIdentifier: "test.merchant.id",
53-
supportedNetworks: [.visa, .masterCard],
5452
contactFields: []
5553
)
5654

@@ -60,7 +58,7 @@ final class ApplePayCallbackTests: XCTestCase {
6058
host: "test-shop.myshopify.com",
6159
url: "https://test-shop.myshopify.com"
6260
),
63-
paymentSettings: PaymentSettings(countryCode: "US")
61+
paymentSettings: PaymentSettings(countryCode: "US", acceptedCardBrands: [.visa, .mastercard])
6462
)
6563

6664
mockConfiguration = ApplePayConfigurationWrapper(

Tests/ShopifyAcceleratedCheckoutsTests/Wallets/ApplePay/ApplePayIntegrationTests.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
*/
2323

24-
import PassKit
2524
@testable import ShopifyAcceleratedCheckouts
2625
import ShopifyCheckoutSheetKit
2726
import SwiftUI
@@ -48,7 +47,6 @@ final class ApplePayIntegrationTests: XCTestCase {
4847

4948
mockApplePayConfiguration = ShopifyAcceleratedCheckouts.ApplePayConfiguration(
5049
merchantIdentifier: "test.merchant.id",
51-
supportedNetworks: [.visa, .masterCard, .amex],
5250
contactFields: []
5351
)
5452

@@ -58,7 +56,10 @@ final class ApplePayIntegrationTests: XCTestCase {
5856
host: "test-shop.myshopify.com",
5957
url: "https://test-shop.myshopify.com"
6058
),
61-
paymentSettings: PaymentSettings(countryCode: "US")
59+
paymentSettings: PaymentSettings(
60+
countryCode: "US",
61+
acceptedCardBrands: [.visa, .mastercard, .americanExpress]
62+
)
6263
)
6364

6465
mockConfiguration = ApplePayConfigurationWrapper(

Tests/ShopifyAcceleratedCheckoutsTests/Wallets/ApplePay/ApplePayViewControllerTests.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
*/
2323

24-
import PassKit
2524
@testable import ShopifyAcceleratedCheckouts
2625
import ShopifyCheckoutSheetKit
2726
import UIKit
@@ -36,7 +35,7 @@ class ApplePayViewControllerTests: XCTestCase {
3635
super.setUp()
3736

3837
// Create mock shop settings
39-
let paymentSettings = PaymentSettings(countryCode: "US")
38+
let paymentSettings = PaymentSettings(countryCode: "US", acceptedCardBrands: [.visa, .mastercard])
4039
let primaryDomain = Domain(host: "test-shop.myshopify.com", url: "https://test-shop.myshopify.com")
4140
let shopSettings = ShopSettings(
4241
name: "Test Shop",
@@ -53,7 +52,6 @@ class ApplePayViewControllerTests: XCTestCase {
5352
// Create Apple Pay configuration
5453
let applePayConfig = ShopifyAcceleratedCheckouts.ApplePayConfiguration(
5554
merchantIdentifier: "test.merchant",
56-
supportedNetworks: [.visa, .masterCard],
5755
contactFields: []
5856
)
5957

0 commit comments

Comments
 (0)