Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds preselected shipping to pay session #1167

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Pay/PayAuthorization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ public struct PayAuthorization {
public let billingAddress: PayAddress

/// Shipping address that was selected by the user
public let shippingAddress: PayAddress
public let shippingAddress: PayAddress?

/// Shipping rate that was selected by the user
public let shippingRate: PayShippingRate?

// ----------------------------------
// MARK: - Init -
//
internal init(paymentData: Data, billingAddress: PayAddress, shippingAddress: PayAddress, shippingRate: PayShippingRate?) {
internal init(paymentData: Data, billingAddress: PayAddress, shippingAddress: PayAddress?, shippingRate: PayShippingRate?) {
self.token = String(data: paymentData, encoding: .utf8)!
self.billingAddress = billingAddress
self.shippingAddress = shippingAddress
Expand Down
23 changes: 20 additions & 3 deletions Pay/PayCheckout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
//

import Foundation
import PassKit

/// Encapsulates all fields required for invoking the Apple Pay
/// dialog. It also creates summary items for cart total,
Expand All @@ -43,16 +42,19 @@ public struct PayCheckout {
public let lineItems: [PayLineItem]
public let shippingAddress: PayAddress?
public let shippingRate: PayShippingRate?

public let availableShippingRates: [PayShippingRate]?

public let currencyCode: String
public let totalDuties: Decimal?
public let subtotalPrice: Decimal
public let totalTax: Decimal
public let paymentDue: Decimal
public let total: Decimal

// ----------------------------------
// MARK: - Init -
//
public init(id: String, lineItems: [PayLineItem], giftCards: [PayGiftCard]?, discount: PayDiscount?, shippingDiscount: PayDiscount?, shippingAddress: PayAddress?, shippingRate: PayShippingRate?, currencyCode: String, subtotalPrice: Decimal, needsShipping: Bool, totalTax: Decimal, paymentDue: Decimal) {
public init(id: String, lineItems: [PayLineItem], giftCards: [PayGiftCard]?, discount: PayDiscount?, shippingDiscount: PayDiscount?, shippingAddress: PayAddress?, shippingRate: PayShippingRate?, availableShippingRates: [PayShippingRate]?, currencyCode: String, totalDuties: Decimal?, subtotalPrice: Decimal, needsShipping: Bool, totalTax: Decimal, paymentDue: Decimal, total: Decimal) {

self.id = id
self.lineItems = lineItems
Expand All @@ -62,17 +64,24 @@ public struct PayCheckout {
self.giftCards = giftCards
self.discount = discount
self.shippingDiscount = shippingDiscount
self.availableShippingRates = availableShippingRates

self.currencyCode = currencyCode
self.totalDuties = totalDuties
self.subtotalPrice = subtotalPrice
self.totalTax = totalTax
self.paymentDue = paymentDue

self.hasLineItems = !lineItems.isEmpty
self.needsShipping = needsShipping
self.total = total
}
}

#if canImport(PassKit)

import PassKit

// ----------------------------------
// MARK: - PassKits -
//
Expand Down Expand Up @@ -111,6 +120,12 @@ internal extension PayCheckout {
summaryItems.append(discount.amount.negative.summaryItemNamed(title))
}

// Duties

if let duties = self.totalDuties {
summaryItems.append(duties.summaryItemNamed("DUTIES"))
}

// Taxes

if self.totalTax > 0.0 {
Expand Down Expand Up @@ -140,3 +155,5 @@ internal extension PayCheckout {
return summaryItems
}
}

#endif
27 changes: 24 additions & 3 deletions Pay/PaySession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// THE SOFTWARE.
//

#if canImport(PassKit)

import Foundation
import PassKit

Expand Down Expand Up @@ -129,6 +131,9 @@ public class PaySession: NSObject {

/// Idempotency identifier of this session.
public let identifier: String

/// Shipping Contact can be set on the Pay Session, in order to pass in a pre-populated shipping address.
public var shippingContact: PKContact?

internal var checkout: PayCheckout
internal var shippingRates: [PayShippingRate] = []
Expand Down Expand Up @@ -185,8 +190,22 @@ public class PaySession: NSObject {
request.countryCode = currency.countryCode
request.currencyCode = currency.currencyCode
request.merchantIdentifier = merchantID
request.requiredBillingAddressFields = .all
request.requiredShippingAddressFields = .all
request.shippingContact = shippingContact
request.requiredBillingContactFields = [.phoneNumber, .name, .postalAddress]
request.requiredShippingContactFields = checkout.needsShipping ? [.phoneNumber, .name, .postalAddress, .phoneNumber, .emailAddress] : []
if let shippingRates = checkout.availableShippingRates {
self.shippingRates = shippingRates
}

if checkout.needsShipping {
request.shippingMethods = checkout.availableShippingRates?.compactMap {
let method = PKShippingMethod(label: $0.title, amount: $0.price)
method.identifier = $0.handle
method.detail = ""
return method
}
}

request.supportedNetworks = self.acceptedCardBrands.paymentNetworks
request.merchantCapabilities = [.capability3DS]
request.paymentSummaryItems = checkout.summaryItems(for: self.shopName)
Expand Down Expand Up @@ -229,7 +248,7 @@ extension PaySession: PKPaymentAuthorizationControllerDelegate {
let authorization = PayAuthorization(
paymentData: payment.token.paymentData,
billingAddress: PayAddress(with: payment.billingContact!),
shippingAddress: PayAddress(with: payment.shippingContact!),
shippingAddress: payment.shippingContact != nil ? PayAddress(with: payment.shippingContact!) : nil,
shippingRate: shippingRate
)

Expand Down Expand Up @@ -369,3 +388,5 @@ extension PaySession: PKPaymentAuthorizationControllerDelegate {
self.delegate?.paySessionDidFinish(self)
}
}

#endif
11 changes: 9 additions & 2 deletions PayTests/Models/Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// THE SOFTWARE.
//

#if canImport(PassKit)

import Foundation
import PassKit
import Pay
Expand Down Expand Up @@ -108,7 +110,7 @@ struct Models {
return PayCurrency(currencyCode: "USD", countryCode: "US")
}

static func createCheckout(requiresShipping: Bool = true, giftCards: [PayGiftCard]? = nil, discount: PayDiscount? = nil, shippingDiscount: PayDiscount? = nil, shippingAddress: PayAddress? = nil, shippingRate: PayShippingRate? = nil, empty: Bool = false, hasTax: Bool = true) -> PayCheckout {
static func createCheckout(requiresShipping: Bool = true, giftCards: [PayGiftCard]? = nil, discount: PayDiscount? = nil, shippingDiscount: PayDiscount? = nil, shippingAddress: PayAddress? = nil, shippingRate: PayShippingRate? = nil, emailAddress: String? = nil, duties: Decimal? = nil, empty: Bool = false, hasTax: Bool = true) -> PayCheckout {

let lineItems = [
self.createLineItem1(),
Expand All @@ -123,11 +125,14 @@ struct Models {
shippingDiscount: shippingDiscount,
shippingAddress: shippingAddress,
shippingRate: shippingRate,
availableShippingRates: [shippingRate].compactMap { $0 },
currencyCode: "CAD",
totalDuties: duties,
subtotalPrice: 44.0,
needsShipping: requiresShipping,
totalTax: hasTax ? 6.0 : 0.0,
paymentDue: 50.0
paymentDue: 50.0,
total: 50
)
}

Expand Down Expand Up @@ -188,3 +193,5 @@ struct Models {
return (order, PayShippingRate.DeliveryRange(from: from, to: to))
}
}

#endif
6 changes: 5 additions & 1 deletion PayTests/PayAuthorizationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// THE SOFTWARE.
//

#if canImport(PassKit)

import XCTest
@testable import Pay

Expand All @@ -46,7 +48,9 @@ class PayAuthorizationTests: XCTestCase {

XCTAssertEqual(authorization.token, "123")
XCTAssertEqual(authorization.billingAddress.firstName, address.firstName)
XCTAssertEqual(authorization.shippingAddress.firstName, address.firstName)
XCTAssertEqual(authorization.shippingAddress?.firstName, address.firstName)
XCTAssertEqual(authorization.shippingRate!.handle, rate.handle)
}
}

#endif
38 changes: 37 additions & 1 deletion PayTests/PayCheckoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// THE SOFTWARE.
//

#if canImport(PassKit)

import XCTest
@testable import Pay

Expand Down Expand Up @@ -52,25 +54,31 @@ class PayCheckoutTests: XCTestCase {
shippingDiscount: shipping,
shippingAddress: address,
shippingRate: rate,
availableShippingRates: [rate].compactMap { $0 },
currencyCode: "CAD",
totalDuties: 9.95,
subtotalPrice: 30.0,
needsShipping: true,
totalTax: 15.0,
paymentDue: 35.0
paymentDue: 35.0,
total: 35.0
)

XCTAssertEqual(checkout.id, "123")
XCTAssertEqual(checkout.lineItems.count, 2)
XCTAssertEqual(checkout.shippingAddress!.city, address.city)
XCTAssertEqual(checkout.shippingRate!.handle, rate.handle)
XCTAssertEqual(checkout.availableShippingRates?.count, 1)
XCTAssertEqual(checkout.giftCards!.first!.amount, 5.00)
XCTAssertEqual(checkout.discount!.amount, 20.0)
XCTAssertEqual(checkout.shippingDiscount!.amount, 10.0)
XCTAssertEqual(checkout.currencyCode, "CAD")
XCTAssertEqual(checkout.subtotalPrice, 30.0)
XCTAssertEqual(checkout.totalDuties, 9.95)
XCTAssertEqual(checkout.needsShipping, true)
XCTAssertEqual(checkout.totalTax, 15.0)
XCTAssertEqual(checkout.paymentDue, 35.0)
XCTAssertEqual(checkout.total, 35.0)
}

// ----------------------------------
Expand All @@ -87,6 +95,32 @@ class PayCheckoutTests: XCTestCase {
XCTAssertEqual(summaryItems[3].label, "SHOPIFY")
}

func testSummaryItemsWithDuties() {
let checkout = Models.createCheckout(requiresShipping: false, duties: 24.99)
let summaryItems = checkout.summaryItems(for: self.shopName)

XCTAssertEqual(summaryItems.count, 5)
XCTAssertEqual(summaryItems[0].label, "CART TOTAL")
XCTAssertEqual(summaryItems[1].label, "SUBTOTAL")
XCTAssertEqual(summaryItems[2].label, "DUTIES")
XCTAssertEqual(summaryItems[2].amount as Decimal, 24.99)
XCTAssertEqual(summaryItems[3].label, "TAXES")
XCTAssertEqual(summaryItems[4].label, "SHOPIFY")
}

func testSummaryItemsWithDutiesAmountZero() {
let checkout = Models.createCheckout(requiresShipping: false, duties: 0)
let summaryItems = checkout.summaryItems(for: self.shopName)

XCTAssertEqual(summaryItems.count, 5)
XCTAssertEqual(summaryItems[0].label, "CART TOTAL")
XCTAssertEqual(summaryItems[1].label, "SUBTOTAL")
XCTAssertEqual(summaryItems[2].label, "DUTIES")
XCTAssertEqual(summaryItems[2].amount as Decimal, 0)
XCTAssertEqual(summaryItems[3].label, "TAXES")
XCTAssertEqual(summaryItems[4].label, "SHOPIFY")
}

func testSummaryItemsWithShipping() {
let address = Models.createAddress()
let rate = Models.createShippingRate()
Expand Down Expand Up @@ -220,3 +254,5 @@ class PayCheckoutTests: XCTestCase {
XCTAssertEqual(summaryItems[6].amount as Decimal, giftCards[0].amount.negative)
}
}

#endif
Loading