diff --git a/OSPaymentsLib.xcodeproj/project.pbxproj b/OSPaymentsLib.xcodeproj/project.pbxproj index 323ffa2..8a98295 100644 --- a/OSPaymentsLib.xcodeproj/project.pbxproj +++ b/OSPaymentsLib.xcodeproj/project.pbxproj @@ -38,7 +38,7 @@ 75EC4D1A2894156E00CF50E2 /* OSPMTError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D192894156E00CF50E2 /* OSPMTError.swift */; }; 75EC4D1C2894160400CF50E2 /* OSPMTActionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D1B2894160400CF50E2 /* OSPMTActionDelegate.swift */; }; 75EC4D1E289416B600CF50E2 /* OSPMTApplePayHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D1D289416B600CF50E2 /* OSPMTApplePayHandler.swift */; }; - 75EC4D2228942C3800CF50E2 /* OSPMTConfigurationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationDelegate.swift */; }; + 75EC4D2228942C3800CF50E2 /* OSPMTConfigurationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationModel.swift */; }; 75EC4D242894449700CF50E2 /* OSPMTApplePayHandlerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D232894449700CF50E2 /* OSPMTApplePayHandlerSpec.swift */; }; 75EC4D262894478200CF50E2 /* OSPMTTestConfigurations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC4D252894478200CF50E2 /* OSPMTTestConfigurations.swift */; }; 7E9C30CBBF9DFE5A747787FF /* Pods_OSPaymentsLib_OSPaymentsLibTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6BD4033DE465D38CA50CA9E /* Pods_OSPaymentsLib_OSPaymentsLibTests.framework */; }; @@ -91,7 +91,7 @@ 75EC4D192894156E00CF50E2 /* OSPMTError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTError.swift; sourceTree = ""; }; 75EC4D1B2894160400CF50E2 /* OSPMTActionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTActionDelegate.swift; sourceTree = ""; }; 75EC4D1D289416B600CF50E2 /* OSPMTApplePayHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTApplePayHandler.swift; sourceTree = ""; }; - 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTConfigurationDelegate.swift; sourceTree = ""; }; + 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTConfigurationModel.swift; sourceTree = ""; }; 75EC4D232894449700CF50E2 /* OSPMTApplePayHandlerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTApplePayHandlerSpec.swift; sourceTree = ""; }; 75EC4D252894478200CF50E2 /* OSPMTTestConfigurations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSPMTTestConfigurations.swift; sourceTree = ""; }; 8CDB829B99BC8A28609750EF /* Pods-OSPaymentsLib-OSPaymentsLibTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OSPaymentsLib-OSPaymentsLibTests.debug.xcconfig"; path = "Target Support Files/Pods-OSPaymentsLib-OSPaymentsLibTests/Pods-OSPaymentsLib-OSPaymentsLibTests.debug.xcconfig"; sourceTree = ""; }; @@ -196,6 +196,7 @@ isa = PBXGroup; children = ( 755A8061289BD56300426EAA /* OSPMTAddressModel.swift */, + 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationModel.swift */, 755A8063289BD58900426EAA /* OSPMTContactInfoModel.swift */, 755A805F289BD54E00426EAA /* OSPMTDataModel.swift */, 755A8053289BC8EE00426EAA /* OSPMTDetailsModel.swift */, @@ -223,7 +224,6 @@ 75EC4D1B2894160400CF50E2 /* OSPMTActionDelegate.swift */, 7509DC7C28995A07005BA0D4 /* OSPMTAvailabilityDelegate.swift */, 75EC4D142894143A00CF50E2 /* OSPMTCallbackDelegate.swift */, - 75EC4D2128942C3800CF50E2 /* OSPMTConfigurationDelegate.swift */, 75EC4D162894150F00CF50E2 /* OSPMTHandlerDelegate.swift */, 755A8057289BC90A00426EAA /* OSPMTRequestDelegate.swift */, ); @@ -449,7 +449,7 @@ 755A8055289BC8EE00426EAA /* OSPMTDetailsModel.swift in Sources */, 755A804B289BB96900426EAA /* PKPassLibrary+Adapter.swift in Sources */, 75760F83289C1F99001BDCEC /* PKPayment+Adapter.swift in Sources */, - 75EC4D2228942C3800CF50E2 /* OSPMTConfigurationDelegate.swift in Sources */, + 75EC4D2228942C3800CF50E2 /* OSPMTConfigurationModel.swift in Sources */, 75EC4D172894150F00CF50E2 /* OSPMTHandlerDelegate.swift in Sources */, 755A8058289BC90A00426EAA /* OSPMTRequestDelegate.swift in Sources */, 755A8062289BD56300426EAA /* OSPMTAddressModel.swift in Sources */, diff --git a/OSPaymentsLib/Error/OSPMTError.swift b/OSPaymentsLib/Error/OSPMTError.swift index 780c639..be763b9 100644 --- a/OSPaymentsLib/Error/OSPMTError.swift +++ b/OSPaymentsLib/Error/OSPMTError.swift @@ -1,33 +1,33 @@ /// All plugin errors that can be thrown enum OSPMTError: Int, CustomNSError, LocalizedError { case invalidConfiguration = 1 - case walletNotAvailable = 2 - case paymentNotAvailable = 3 - case setupPaymentNotAvailable = 4 - case invalidDecodeDetails = 6 - case paymentTriggerPresentationFailed = 7 - case paymentTriggerNotCompleted = 8 + case walletNotAvailable = 3 + case paymentNotAvailable = 5 + case setupPaymentNotAvailable = 6 + case invalidDecodeDetails = 8 case invalidEncodeScope = 9 + case paymentTriggerPresentationFailed = 10 + case paymentCancelled = 11 /// Textual description var errorDescription: String? { switch self { case .invalidConfiguration: - return "An invalid configuration was provided to the plugin." + return "Couldn't obtain the payment's informations from the configurations file." case .walletNotAvailable: - return "Wallet is not available on this device." + return "The Apple Pay is not available in the device." case .paymentNotAvailable: - return "Payment is not available on this device." + return "There is no payment method configured." case .setupPaymentNotAvailable: - return "Payment through the configured networks and capabilities is not available on this device." + return "There are no valid payment cards for the supported networks and/or capabilities." case .invalidDecodeDetails: - return "Couldn't decode payment details." + return "Couldn't decode the payment details." + case .invalidEncodeScope: + return "Couldn't encode the payment scope." case .paymentTriggerPresentationFailed: return "Couldn't present the Apple Pay screen." - case .paymentTriggerNotCompleted: - return "Couldn't complete the payment trigger process." - case .invalidEncodeScope: - return "Couldn't encode payment scope." + case .paymentCancelled: + return "Payment was cancelled by the user." } } } diff --git a/OSPaymentsLib/Extensions/PKPayment+Adapter.swift b/OSPaymentsLib/Extensions/PKPayment+Adapter.swift index 338406c..bd54e9c 100644 --- a/OSPaymentsLib/Extensions/PKPayment+Adapter.swift +++ b/OSPaymentsLib/Extensions/PKPayment+Adapter.swift @@ -18,7 +18,7 @@ extension PKPayment { /// Converts a `PKPayment` object into a dictionary that relates to an `OSPMTDataModel` object. /// - Returns: The corresponding `OSPMTDataModel` dictionary object. - func createTokenDataData() -> [String: Any] { + private func createTokenDataData() -> [String: Any] { var result: [String: Any] = [ OSPMTDataModel.CodingKeys.tokenData.rawValue: self.createTokenData(for: self.token.paymentData) ] @@ -39,7 +39,7 @@ extension PKPayment { /// Takes the passed payment data object and converts it into a dictionary that relates to an `OSPMTTokenInfoModel` object. /// - Parameter paymentData: `Data` type object that contains information related to a payment token. /// - Returns: The corresponding `OSPMTTokenInfoModel` dictionary object. - func createTokenData(for paymentData: Data) -> [String: String] { + private func createTokenData(for paymentData: Data) -> [String: String] { // TODO: The type passed here will probably be changed into the Payment Service Provider's name when this is implemented. var result = [OSPMTTokenInfoModel.CodingKeys.type.rawValue: "Apple Pay"] @@ -53,7 +53,7 @@ extension PKPayment { /// Takes the passed contact object and converts it into a dictionary that relates to an `OSPMTContactInfoModel` object. /// - Parameter contact: `PKContact` type object that contains information related to the filled Billing or Shipping Information /// - Returns: The corresponding `OSPMTContactInfoModel` dictionary object. - func createContactInfoData(for contact: PKContact) -> [String: Any]? { + private func createContactInfoData(for contact: PKContact) -> [String: Any]? { var result = [String: Any]() if let address = contact.postalAddress { result[OSPMTContactInfoModel.CodingKeys.address.rawValue] = self.createAddressData(for: address) @@ -74,7 +74,7 @@ extension PKPayment { /// Takes the passed address object and converts it into a dictionary that relates to an `OSPMTAddressModel` object. /// - Parameter postalAddress: `CNPostalAddress` type object that contains an address related to the filled Billing or Shipping Information. /// - Returns: The corresponding `OSPMTAddressModel` dictionary object. - func createAddressData(for postalAddress: CNPostalAddress) -> [String: String] { + private func createAddressData(for postalAddress: CNPostalAddress) -> [String: String] { var result = [ OSPMTAddressModel.CodingKeys.postalCode.rawValue: postalAddress.postalCode, OSPMTAddressModel.CodingKeys.fullAddress.rawValue: postalAddress.street, diff --git a/OSPaymentsLib/Extensions/PKPaymentAuthorizationController+Adapter.swift b/OSPaymentsLib/Extensions/PKPaymentAuthorizationController+Adapter.swift index 1055d26..a449e0c 100644 --- a/OSPaymentsLib/Extensions/PKPaymentAuthorizationController+Adapter.swift +++ b/OSPaymentsLib/Extensions/PKPaymentAuthorizationController+Adapter.swift @@ -47,10 +47,14 @@ extension PKPaymentAuthorizationController: OSPMTApplePayRequestTriggerDelegate paymentRequest.merchantCapabilities = merchantCapabilities paymentRequest.paymentSummaryItems = paymentSummaryItems paymentRequest.requiredBillingContactFields = delegate.getContactFields( - for: detailsModel.billingContactArray ?? delegate.configuration.billingSupportedContacts + for: detailsModel.billingContact.isCustom + ? detailsModel.billingContact.contactArray + : delegate.configuration.billingSupportedContacts ) paymentRequest.requiredShippingContactFields = delegate.getContactFields( - for: detailsModel.shippingContactArray ?? delegate.configuration.shippingSupportedContacts + for: detailsModel.shippingContact.isCustom + ? detailsModel.shippingContact.contactArray + : delegate.configuration.shippingSupportedContacts ) paymentRequest.supportedCountries = delegate.configuration.supportedCountries paymentRequest.supportedNetworks = supportedNetworks diff --git a/OSPaymentsLib/Models/OSPMTConfigurationModel.swift b/OSPaymentsLib/Models/OSPMTConfigurationModel.swift new file mode 100644 index 0000000..565b10e --- /dev/null +++ b/OSPaymentsLib/Models/OSPMTConfigurationModel.swift @@ -0,0 +1,198 @@ +import PassKit + +/// Protocol that contains all properties needed to configure a payment service. +class OSPMTConfigurationModel: Encodable { + // MARK: Merchant Information + var merchantID: String? + var merchantName: String? + var merchantCountryCode: String? + + // MARK: Payment Information + var paymentAllowedNetworks: [String]? + var paymentSupportedCapabilities: [String]? + var paymentSupportedCardCountries: [String]? + + // MARK: Shipping Information + var shippingSupportedContacts: [String]? + + // MARK: Billing Information + var billingSupportedContacts: [String]? + + /// Keys used to encode and decode the model. + enum CodingKeys: String, CodingKey { + case merchantID + case merchantName + case merchantCountryCode + case paymentAllowedNetworks + case paymentSupportedCapabilities + case paymentSupportedCardCountries + case shippingSupportedContacts + case billingSupportedContacts + } + + /// Constructor method. + /// - Parameters: + /// - merchantID: Merchant ID configured + /// - merchantName: Merchant Name configured + /// - merchantCountryCode: Merchant Country Code configured + /// - paymentAllowedNetworks: Payment Allowed Networks configured + /// - paymentSupportedCapabilities: Payment Supported Capabilities configured + /// - paymentSupportedCardCountries: Payment Support Card Countries configured + /// - shippingSupportedContacts: Shipping Supported Contacts configured + /// - billingSupportedContacts: Billing Supported Contacts configured + init(merchantID: String?, merchantName: String?, merchantCountryCode: String?, paymentAllowedNetworks: [String]?, paymentSupportedCapabilities: [String]?, paymentSupportedCardCountries: [String]?, shippingSupportedContacts: [String]?, billingSupportedContacts: [String]?) { + self.merchantID = merchantID + self.merchantName = merchantName + self.merchantCountryCode = merchantCountryCode + self.paymentAllowedNetworks = paymentAllowedNetworks + self.paymentSupportedCapabilities = paymentSupportedCapabilities + self.paymentSupportedCardCountries = paymentSupportedCardCountries + self.shippingSupportedContacts = shippingSupportedContacts + self.billingSupportedContacts = billingSupportedContacts + } + + /// Encodes this value into the given encoder. + /// + /// If the value fails to encode anything, `encoder` will encode an empty + /// keyed container in its place. + /// + /// This function throws an error if any values are invalid for the given + /// encoder's format. + /// + /// - Parameter encoder: The encoder to write data to. + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + // MARK: Merchant Information + try container.encodeIfPresent(merchantID, forKey: .merchantID) + try container.encodeIfPresent(merchantName, forKey: .merchantName) + try container.encodeIfPresent(merchantCountryCode, forKey: .merchantCountryCode) + + // MARK: Payment Information + try container.encodeIfPresent(paymentAllowedNetworks, forKey: .paymentAllowedNetworks) + try container.encodeIfPresent(paymentSupportedCapabilities, forKey: .paymentSupportedCapabilities) + try container.encodeIfPresent(paymentSupportedCardCountries, forKey: .paymentSupportedCardCountries) + + // MARK: Shipping Information + try container.encodeIfPresent(shippingSupportedContacts, forKey: .shippingSupportedContacts) + + // MARK: Billing Information + try container.encodeIfPresent(billingSupportedContacts, forKey: .billingSupportedContacts) + } +} + +typealias OSPMTConfiguration = [String: Any] + +/// Manages all configuration properties required to enable Apple Pay in the plugin. +class OSPMTApplePayConfiguration: OSPMTConfigurationModel { + struct ConfigurationKeys { + static let merchantID = "ApplePayMerchantID" + static let merchantName = "ApplePayMerchantName" + static let merchantCountryCode = "ApplePayMerchantCountryCode" + + static let paymentAllowedNetworks = "ApplePayPaymentAllowedNetworks" + static let paymentSupportedCapabilities = "ApplePayPaymentSupportedCapabilities" + static let paymentSupportedCardCountries = "ApplePayPaymentSupportedCardCountries" + + static let shippingSupportedContacts = "ApplePayShippingSupportedContacts" + + static let billingSupportedContacts = "ApplePayBillingSupportedContacts" + } + + /// Constructor method. + /// - Parameter source: Source class contaning the configuration. + convenience init(source: OSPMTConfiguration) { + // MARK: Merchant Information + let merchantID = Self.getRequiredProperty( + ofType: String.self, forSource: source, andKey: ConfigurationKeys.merchantID + ) + let merchantName = Self.getRequiredProperty( + ofType: String.self, forSource: source, andKey: ConfigurationKeys.merchantName + ) + let merchantCountryCode = Self.getRequiredProperty( + ofType: String.self, forSource: source, andKey: ConfigurationKeys.merchantCountryCode + ) + + // MARK: Payment Information + let paymentAllowedNetworks = Self.getRequiredProperty( + ofType: [String].self, forSource: source, andKey: ConfigurationKeys.paymentAllowedNetworks + ) + let paymentSupportedCapabilities = Self.getRequiredProperty( + ofType: [String].self, forSource: source, andKey: ConfigurationKeys.paymentSupportedCapabilities + ) + let paymentSupportedCardCountries = Self.getProperty( + ofType: [String].self, forSource: source, andKey: ConfigurationKeys.paymentSupportedCardCountries + ) + + // MARK: Shipping Information + let shippingSupportedContacts = Self.getProperty( + ofType: [String].self, forSource: source, andKey: ConfigurationKeys.shippingSupportedContacts + ) + + // MARK: Billing Information + let billingSupportedContacts = Self.getProperty( + ofType: [String].self, forSource: source, andKey: ConfigurationKeys.billingSupportedContacts + ) + + self.init( + merchantID: merchantID, + merchantName: merchantName, + merchantCountryCode: merchantCountryCode, + paymentAllowedNetworks: paymentAllowedNetworks, + paymentSupportedCapabilities: paymentSupportedCapabilities, + paymentSupportedCardCountries: paymentSupportedCardCountries, + shippingSupportedContacts: shippingSupportedContacts, + billingSupportedContacts: billingSupportedContacts + ) + } +} + +private extension OSPMTApplePayConfiguration { + /// Fetches the parameter property, if it exists. + /// - Parameters: + /// - type: Type of variable to return. + /// - key: Property key to search from. + /// - isRequired: Indicates if the property is mandatory or not. + /// - Returns: The configuration property, if it exists. + static func getProperty(ofType type: T.Type, forSource source: OSPMTConfiguration, andKey key: String, isRequired: Bool = false) -> T? { + let result = source[key] as? T + return !isRequired || result?.isEmpty == false ? result : nil + } + + /// An acelerator for `getProperty(ofType:forKey:isRequired:)`, that should be used for mandatory properties. + /// - Parameters: + /// - type: Type of variable to return. + /// - key: Property key to search from. + /// - Returns: The configuration property, if it exists. + static func getRequiredProperty(ofType type: T.Type, forSource source: OSPMTConfiguration, andKey key: String) -> T? { + self.getProperty(ofType: type, forSource: source, andKey: key, isRequired: true) + } +} + +extension OSPMTApplePayConfiguration { + var supportedNetworks: [PKPaymentNetwork]? { + guard let paymentAllowedNetworks = self.paymentAllowedNetworks else { return nil } + let result = paymentAllowedNetworks.compactMap(PKPaymentNetwork.convert(from:)) + + return !result.isEmpty ? result : nil + } + + var merchantCapabilities: PKMerchantCapability? { + guard let paymentSupportedCapabilities = self.paymentSupportedCapabilities else { return nil } + + var result: PKMerchantCapability = [] + result = paymentSupportedCapabilities.reduce(into: result) { partialResult, capability in + let merchantCapability = PKMerchantCapability.convert(from: capability) + if let merchantCapability = merchantCapability { + partialResult.insert(merchantCapability) + } + } + + return !result.isEmpty ? result : nil + } + + var supportedCountries: Set? { + guard let paymentSupportedCardCountries = self.paymentSupportedCardCountries, !paymentSupportedCardCountries.isEmpty else { return nil } + return Set(paymentSupportedCardCountries) + } +} diff --git a/OSPaymentsLib/Models/OSPMTDetailsModel.swift b/OSPaymentsLib/Models/OSPMTDetailsModel.swift index 5ea769a..a991c3b 100644 --- a/OSPaymentsLib/Models/OSPMTDetailsModel.swift +++ b/OSPaymentsLib/Models/OSPMTDetailsModel.swift @@ -6,21 +6,55 @@ enum OSPMTStatus: String, Codable { case pending } +/// Structure of the shipping/billing information +struct OSPMTContact: Decodable { + let isCustom: Bool + let contactArray: [String]? + + /// Keys used to encode and decode the model. + enum CodingKeys: String, CodingKey { + case isCustom + case contactArray = "contactInfo" + } + + /// Constructor method + /// - Parameters: + /// - isCustom: Indicates if the custom contact information should be used when trigger a payment request. + /// - contactArray: Shipping/Billing properties required for filling. + init(isCustom: Bool, contactArray: [String]?) { + self.isCustom = isCustom + self.contactArray = contactArray + } + + /// Creates a new instance by decoding from the given decoder. + /// + /// This initializer throws an error if reading from the decoder fails, or + /// if the data read is corrupted or otherwise invalid. + /// + /// - Parameter decoder: The decoder to read data from. + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let isCustom = try container.decode(Bool.self, forKey: .isCustom) + let contactArray = isCustom ? try container.decodeIfPresent([String].self, forKey: .contactArray) : nil + self.init(isCustom: isCustom, contactArray: contactArray) + } +} + /// Payment Details to be processed. struct OSPMTDetailsModel: Decodable { let amount: Decimal let currency: String let status: OSPMTStatus - let shippingContactArray: [String]? - let billingContactArray: [String]? + let shippingContact: OSPMTContact + let billingContact: OSPMTContact /// Keys used to encode and decode the model. enum CodingKeys: String, CodingKey { case amount case currency case status - case shippingContactArray = "shippingContacts" - case billingContactArray = "billingContacts" + case shippingContact = "shippingContacts" + case billingContact = "billingContacts" } /// Constructor method. @@ -28,14 +62,14 @@ struct OSPMTDetailsModel: Decodable { /// - amount: Amount to be charged. /// - currency: The three-letter ISO 4217 currency code. /// - status: Final value status. - /// - shippingContactArray: Shipping properties required for filling. - /// - billingContactArray: Billiing properties required for filling. - init(amount: Decimal, currency: String, status: OSPMTStatus, shippingContactArray: [String]? = nil, billingContactArray: [String]? = nil) { + /// - shippingContact: Shipping properties required for filling. + /// - billingContact: Billiing properties required for filling. + init(amount: Decimal, currency: String, status: OSPMTStatus, shippingContact: OSPMTContact, billingContact: OSPMTContact) { self.amount = amount self.currency = currency self.status = status - self.shippingContactArray = shippingContactArray - self.billingContactArray = billingContactArray + self.shippingContact = shippingContact + self.billingContact = billingContact } /// Creates a new instance by decoding from the given decoder. @@ -49,10 +83,10 @@ struct OSPMTDetailsModel: Decodable { let amount = try container.decode(Decimal.self, forKey: .amount) let currency = try container.decode(String.self, forKey: .currency) let status = try container.decode(OSPMTStatus.self, forKey: .status) - let shippingContactArray = try container.decodeIfPresent([String].self, forKey: .shippingContactArray) - let billingContactArray = try container.decodeIfPresent([String].self, forKey: .billingContactArray) + let shippingContact = try container.decode(OSPMTContact.self, forKey: .shippingContact) + let billingContact = try container.decode(OSPMTContact.self, forKey: .billingContact) self.init( - amount: amount, currency: currency, status: status, shippingContactArray: shippingContactArray, billingContactArray: billingContactArray + amount: amount, currency: currency, status: status, shippingContact: shippingContact, billingContact: billingContact ) } } diff --git a/OSPaymentsLib/OSPMTApplePayHandler.swift b/OSPaymentsLib/OSPMTApplePayHandler.swift index 5e5ce12..b60ae67 100644 --- a/OSPaymentsLib/OSPMTApplePayHandler.swift +++ b/OSPaymentsLib/OSPMTApplePayHandler.swift @@ -1,6 +1,6 @@ /// Class resopnsible to manage the Apple Pay payment service requests. It delegates every operation type to its manager. class OSPMTApplePayHandler: NSObject { - let configuration: OSPMTConfigurationDelegate + let configuration: OSPMTConfigurationModel let availabilityBehaviour: OSPMTAvailabilityDelegate let requestBehaviour: OSPMTRequestDelegate @@ -9,7 +9,7 @@ class OSPMTApplePayHandler: NSObject { /// - configuration: Configuration manager. /// - availabilityBehaviour: Availability manager. /// - requestBehaviour: Request trigger manager. - init(configuration: OSPMTConfigurationDelegate, availabilityBehaviour: OSPMTAvailabilityDelegate, requestBehaviour: OSPMTRequestDelegate) { + init(configuration: OSPMTConfigurationModel, availabilityBehaviour: OSPMTAvailabilityDelegate, requestBehaviour: OSPMTRequestDelegate) { self.configuration = configuration self.availabilityBehaviour = availabilityBehaviour self.requestBehaviour = requestBehaviour @@ -33,7 +33,11 @@ extension OSPMTApplePayHandler: OSPMTHandlerDelegate { /// Allows the configuration of the payment service. /// - Returns: Returns a JSON mapping if successful or an error if anything failed. func setupConfiguration() -> Result { - !self.configuration.description.isEmpty ? .success(self.configuration.description) : .failure(.invalidConfiguration) + guard + let configurationData = try? JSONEncoder().encode(self.configuration), + let configurationText = String(data: configurationData, encoding: .utf8) + else { return .failure(.invalidConfiguration) } + return .success(configurationText) } /// Checks for the Wallet and Payment availability. diff --git a/OSPaymentsLib/OSPMTPayments.swift b/OSPaymentsLib/OSPMTPayments.swift index 1e11995..9a429c1 100644 --- a/OSPaymentsLib/OSPMTPayments.swift +++ b/OSPaymentsLib/OSPMTPayments.swift @@ -1,6 +1,6 @@ /// Class that provides the bridge between the library and 3rd party consumers. class OSPMTPayments: NSObject { - private let delegate: OSPMTCallbackDelegate + private weak var delegate: OSPMTCallbackDelegate? private let handler: OSPMTHandlerDelegate /// Constructor method. @@ -30,18 +30,18 @@ extension OSPMTPayments: OSPMTActionDelegate { switch result { case .success(let message): - self.delegate.callback(result: message) + self.delegate?.callback(result: message) case .failure(let error): - self.delegate.callback(error: error) + self.delegate?.callback(error: error) } } /// Verifies the device is ready to process a payment, considering the configuration provided before. func checkWalletSetup() { if let error = self.handler.checkWalletAvailability() { - self.delegate.callback(error: error) + self.delegate?.callback(error: error) } else { - self.delegate.callbackSuccess() + self.delegate?.callbackSuccess() } } @@ -58,16 +58,16 @@ extension OSPMTPayments: OSPMTActionDelegate { let scopeResult = self.encode(scopeModel) switch scopeResult { case .success(let scopeText): - self.delegate.callback(result: scopeText) + self.delegate?.callback(result: scopeText) case .failure(let error): - self.delegate.callback(error: error) + self.delegate?.callback(error: error) } case .failure(let error): - self.delegate.callback(error: error) + self.delegate?.callback(error: error) } } case .failure(let error): - self.delegate.callback(error: error) + self.delegate?.callback(error: error) } } } diff --git a/OSPaymentsLib/Protocols/OSPMTConfigurationDelegate.swift b/OSPaymentsLib/Protocols/OSPMTConfigurationDelegate.swift deleted file mode 100644 index 6f2d6ac..0000000 --- a/OSPaymentsLib/Protocols/OSPMTConfigurationDelegate.swift +++ /dev/null @@ -1,167 +0,0 @@ -import PassKit - -typealias OSPMTConfiguration = [String: Any] - -/// Protocol that contains all properties needed to configure a payment service. -protocol OSPMTConfigurationDelegate: AnyObject, CustomStringConvertible { - var source: OSPMTConfiguration { get set } - - // MARK: Merchant Information - var merchantID: String? { get } - var merchantName: String? { get } - var merchantCountryCode: String? { get } - - // MARK: Payment Information - var paymentAllowedNetworks: [String]? { get } - var paymentSupportedCapabilities: [String]? { get } - var paymentSupportedCardCountries: [String]? { get } - - // MARK: Shipping Information - var shippingSupportedContacts: [String]? { get } - - // MARK: Billing Information - var billingSupportedContacts: [String]? { get } -} - -/// Manages all configuration properties required to enable Apple Pay in the plugin. -class OSPMTApplePayConfiguration: OSPMTConfigurationDelegate { - /// Structures with all configuration property identifiers. - struct ConfigurationKeys { - static let merchantID = "ApplePayMerchantID" - static let merchantName = "ApplePayMerchantName" - static let merchantCountryCode = "ApplePayMerchantCountryCode" - - static let paymentAllowedNetworks = "ApplePayPaymentAllowedNetworks" - static let paymentSupportedCapabilities = "ApplePayPaymentSupportedCapabilities" - static let paymentSupportedCardCountries = "ApplePayPaymentSupportedCardCountries" - - static let shippingSupportedContacts = "ApplePayShippingSupportedContacts" - - static let billingSupportedContacts = "ApplePayBillingSupportedContacts" - } - - var source: OSPMTConfiguration - - /// Constructor method. - /// - Parameter source: The source to fetch the configuration for (e.g. main bundle). - init(source: OSPMTConfiguration) { - self.source = source - } - - // MARK: Merchant Information - var merchantID: String? { - self.getRequiredProperty(ofType: String.self, forKey: ConfigurationKeys.merchantID) - } - var merchantName: String? { - self.getRequiredProperty(ofType: String.self, forKey: ConfigurationKeys.merchantName) - } - var merchantCountryCode: String? { - self.getRequiredProperty(ofType: String.self, forKey: ConfigurationKeys.merchantCountryCode) - } - - // MARK: Payment Information - var paymentAllowedNetworks: [String]? { - self.getRequiredProperty(ofType: [String].self, forKey: ConfigurationKeys.paymentAllowedNetworks) - } - var paymentSupportedCapabilities: [String]? { - self.getRequiredProperty(ofType: [String].self, forKey: ConfigurationKeys.paymentSupportedCapabilities) - } - var paymentSupportedCardCountries: [String]? { - self.getProperty(ofType: [String].self, forKey: ConfigurationKeys.paymentSupportedCardCountries) - } - - // MARK: Shipping Information - var shippingSupportedContacts: [String]? { - self.getProperty(ofType: [String].self, forKey: ConfigurationKeys.shippingSupportedContacts) - } - - // MARK: Billing Information - var billingSupportedContacts: [String]? { - self.getProperty(ofType: [String].self, forKey: ConfigurationKeys.billingSupportedContacts) - } - - // MARK: CustomStringConvertible Property - lazy var description: String = { - guard let merchantID = self.merchantID, - let merchantName = self.merchantName, - let merchantCountryCode = self.merchantCountryCode, - let paymentAllowedNetworks = self.paymentAllowedNetworks, - let paymentSupportedCapabilities = self.paymentSupportedCapabilities, - let shippingSupportedContacts = self.shippingSupportedContacts, - let billingSupportedContacts = self.billingSupportedContacts - else { return "" } - - var configurationDict: [String: Any] = [ - ConfigurationKeys.merchantID: merchantID, - ConfigurationKeys.merchantName: merchantName, - ConfigurationKeys.merchantCountryCode: merchantCountryCode, - - ConfigurationKeys.paymentAllowedNetworks: paymentAllowedNetworks, - ConfigurationKeys.paymentSupportedCapabilities: paymentSupportedCapabilities - ] - - if let shippingSupportedContacts = self.shippingSupportedContacts { - configurationDict[ConfigurationKeys.shippingSupportedContacts] = shippingSupportedContacts - } - if let billingSupportedContacts = self.billingSupportedContacts { - configurationDict[ConfigurationKeys.billingSupportedContacts] = billingSupportedContacts - } - if let paymentSupportedCardCountries = self.paymentSupportedCardCountries { - configurationDict[ConfigurationKeys.paymentSupportedCardCountries] = paymentSupportedCardCountries - } - - guard let data = try? JSONSerialization.data(withJSONObject: configurationDict), let result = String(data: data, encoding: .utf8) - else { return "" } - return result - }() -} - -private extension OSPMTApplePayConfiguration { - /// Fetches the parameter property, if it exists. - /// - Parameters: - /// - type: Type of variable to return. - /// - key: Property key to search from. - /// - isRequired: Indicates if the property is mandatory or not. - /// - Returns: The configuration property, if it exists. - func getProperty(ofType type: T.Type, forKey key: String, isRequired: Bool = false) -> T? { - let result = self.source[key] as? T - return !isRequired || result?.isEmpty == false ? result : nil - } - - /// An acelerator for `getProperty(ofType:forKey:isRequired:)`, that should be used for mandatory properties. - /// - Parameters: - /// - type: Type of variable to return. - /// - key: Property key to search from. - /// - Returns: The configuration property, if it exists. - func getRequiredProperty(ofType type: T.Type, forKey key: String) -> T? { - self.getProperty(ofType: type, forKey: key, isRequired: true) - } -} - -extension OSPMTApplePayConfiguration { - var supportedNetworks: [PKPaymentNetwork]? { - guard let paymentAllowedNetworks = self.paymentAllowedNetworks else { return nil } - let result = paymentAllowedNetworks.compactMap(PKPaymentNetwork.convert(from:)) - - return !result.isEmpty ? result : nil - } - - var merchantCapabilities: PKMerchantCapability? { - guard let paymentSupportedCapabilities = self.paymentSupportedCapabilities else { return nil } - - var result: PKMerchantCapability = [] - result = paymentSupportedCapabilities.reduce(into: result) { partialResult, capability in - let merchantCapability = PKMerchantCapability.convert(from: capability) - if let merchantCapability = merchantCapability { - partialResult.insert(merchantCapability) - } - } - - return !result.isEmpty ? result : nil - } - - var supportedCountries: Set? { - guard let paymentSupportedCardCountries = self.paymentSupportedCardCountries, !paymentSupportedCardCountries.isEmpty else { return nil } - return Set(paymentSupportedCardCountries) - } -} diff --git a/OSPaymentsLib/Protocols/OSPMTRequestDelegate.swift b/OSPaymentsLib/Protocols/OSPMTRequestDelegate.swift index 303fd46..2a5e2c3 100644 --- a/OSPaymentsLib/Protocols/OSPMTRequestDelegate.swift +++ b/OSPaymentsLib/Protocols/OSPMTRequestDelegate.swift @@ -99,7 +99,7 @@ extension OSPMTApplePayRequestBehaviour: PKPaymentAuthorizationControllerDelegat if self.paymentStatus == .success, let paymentScope = self.paymentScope { self.completionHandler(.success(paymentScope)) } else { - self.completionHandler(.failure(.paymentTriggerNotCompleted)) + self.completionHandler(.failure(.paymentCancelled)) } } } @@ -114,6 +114,7 @@ extension OSPMTApplePayRequestBehaviour: PKPaymentAuthorizationControllerDelegat self.paymentScope = scopeModel self.paymentStatus = .success } else { + self.paymentScope = nil self.paymentStatus = .failure } diff --git a/OSPaymentsLibTests/OSPMTApplePayHandlerSpec.swift b/OSPaymentsLibTests/OSPMTApplePayHandlerSpec.swift index bc22a18..c02d4c7 100644 --- a/OSPaymentsLibTests/OSPMTApplePayHandlerSpec.swift +++ b/OSPaymentsLibTests/OSPMTApplePayHandlerSpec.swift @@ -62,7 +62,6 @@ class OSPMTApplePayHandlerSpec: QuickSpec { if case let .success(text) = result { OSPMTTestConfigurations.fullConfig.forEach { item in - expect(text).to(contain(item.key)) expect(text).toNot(beEmpty()) if let value = item.value as? [String] { expect(value).toNot(beEmpty()) @@ -76,152 +75,6 @@ class OSPMTApplePayHandlerSpec: QuickSpec { } } - describe("Given an incomplete configuration") { - describe("without Merchant ID configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noMerchantIDConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Merchant Name configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noMerchantNameConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Merchant Country Code configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noMerchantCountryCodeConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Payment Allowed Networks configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noPaymentAllowedNetworksConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Payment Supported Capabilities configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noPaymentSupportedCapabilitiesConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Payment Supported Card Countries configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noPaymentSupportedCardCountriesConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a successful configuration string") { - let result = applePayHandler.setupConfiguration() - - if case let .success(text) = result { - expect(text).toNot(beEmpty()) - } else { - fail() - } - } - } - } - - describe("without Shipping Supported Contacts configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noShippingSupportedContactsConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - - describe("without Billing Supported Contacts configured") { - beforeEach { - applePayHandler = OSPMTApplePayHandler(configurationSource: OSPMTTestConfigurations.noBillingSupportedContactsConfig) - } - - context("When Apple Pay Handler is initialized") { - it("should return a InvalidConfiguration error") { - let result = applePayHandler.setupConfiguration() - - if case let .failure(error) = result { - expect(error).to(equal(.invalidConfiguration)) - } else { - fail() - } - } - } - } - } - describe("Given an AvailabilityBehaviour") { var applePayConfiguration: OSPMTApplePayConfiguration! diff --git a/OSPaymentsLibTests/OSPMTPaymentsSpec.swift b/OSPaymentsLibTests/OSPMTPaymentsSpec.swift index 7f1818c..4770295 100644 --- a/OSPaymentsLibTests/OSPMTPaymentsSpec.swift +++ b/OSPaymentsLibTests/OSPMTPaymentsSpec.swift @@ -96,6 +96,40 @@ class OSPMTPaymentsSpec: QuickSpec { } } } + + context("When the OSPMTPayments object is initialized") { + context(""" + And payment details is set so that it should use the billing information + from the configuration and custom shipping information + """) { + beforeEach { + mockHandler = OSPMTMockHandler( + successText: OSPMTTestConfigurations.dummyString, + scopeModel: OSPMTTestConfigurations.useConfigurationBillingScopeModel + ) + payments = OSPMTPayments(delegate: mockDelegate, handler: mockHandler) + } + + it("Should return the values as expected") { + if let detailsData = try? JSONSerialization.data( + withJSONObject: OSPMTTestConfigurations.useConfigBillingContactDetailModel + ), + let detailsString = String(data: detailsData, encoding: .utf8) { + payments.set(detailsString) + + expect(mockDelegate.error).to(beNil()) + let result = payments.encode(OSPMTTestConfigurations.useConfigurationBillingScopeModel) + if case let .success(scopeText) = result { + expect(mockDelegate.successText).to(equal(scopeText)) + } else { + fail() + } + } else { + fail() + } + } + } + } } describe("and a handler configured with an error") { diff --git a/OSPaymentsLibTests/OSPMTTestConfigurations.swift b/OSPaymentsLibTests/OSPMTTestConfigurations.swift index 80905e7..63de031 100644 --- a/OSPaymentsLibTests/OSPMTTestConfigurations.swift +++ b/OSPaymentsLibTests/OSPMTTestConfigurations.swift @@ -17,16 +17,6 @@ struct OSPMTTestConfigurations { OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] ] - static let noMerchantIDConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - static let noMerchantNameConfig: OSPMTConfiguration = [ OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, @@ -37,66 +27,6 @@ struct OSPMTTestConfigurations { OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] ] - static let noMerchantCountryCodeConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - - static let noPaymentAllowedNetworksConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - - static let noPaymentSupportedCapabilitiesConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - - static let noPaymentSupportedCardCountriesConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - - static let noShippingSupportedContactsConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.billingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - - static let noBillingSupportedContactsConfig: OSPMTConfiguration = [ - OSPMTApplePayConfiguration.ConfigurationKeys.merchantID: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantName: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.merchantCountryCode: Self.dummyString, - OSPMTApplePayConfiguration.ConfigurationKeys.paymentAllowedNetworks: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCapabilities: [Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.paymentSupportedCardCountries: [Self.dummyString, Self.dummyString], - OSPMTApplePayConfiguration.ConfigurationKeys.shippingSupportedContacts: [Self.dummyString, Self.dummyString] - ] - // MARK: - OSPMTApplePayConfigurationSpec Configurations static let networkVisa = "VISA" static let networkMasterCard = "MasterCard" @@ -128,7 +58,10 @@ struct OSPMTTestConfigurations { static let nilNetworkCapabilityConfig: OSPMTConfiguration = [:] // MARK: - OSPMTApplePayRequestBehaviourSpec Configurations - static let dummyDetailsModel = OSPMTDetailsModel(amount: 1, currency: Self.dummyString, status: .final) + static let dummyContact = OSPMTContact(isCustom: true, contactArray: [Self.dummyString]) + static let dummyDetailsModel = OSPMTDetailsModel( + amount: 1, currency: Self.dummyString, status: .final, shippingContact: dummyContact, billingContact: dummyContact + ) static let dummyAddressModel = OSPMTAddressModel( postalCode: Self.dummyString, fullAddress: Self.dummyString, countryCode: Self.dummyString, city: Self.dummyString ) @@ -149,18 +82,48 @@ struct OSPMTTestConfigurations { OSPMTDetailsModel.CodingKeys.amount.rawValue: 1, OSPMTDetailsModel.CodingKeys.currency.rawValue: Self.dummyString, OSPMTDetailsModel.CodingKeys.status.rawValue: OSPMTStatus.final.rawValue, - OSPMTDetailsModel.CodingKeys.billingContactArray.rawValue: [Self.dummyString], - OSPMTDetailsModel.CodingKeys.shippingContactArray.rawValue: [Self.dummyString] + OSPMTDetailsModel.CodingKeys.billingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: true, + OSPMTContact.CodingKeys.contactArray.rawValue: [Self.dummyString] + ], + OSPMTDetailsModel.CodingKeys.shippingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: true, + OSPMTContact.CodingKeys.contactArray.rawValue: [Self.dummyString] + ] ] static let invalidStatusDetailModel: [String: Any] = [ OSPMTDetailsModel.CodingKeys.amount.rawValue: 1, OSPMTDetailsModel.CodingKeys.currency.rawValue: Self.dummyString, OSPMTDetailsModel.CodingKeys.status.rawValue: Self.dummyString, - OSPMTDetailsModel.CodingKeys.billingContactArray.rawValue: [Self.dummyString], - OSPMTDetailsModel.CodingKeys.shippingContactArray.rawValue: [Self.dummyString] + OSPMTDetailsModel.CodingKeys.billingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: true, + OSPMTContact.CodingKeys.contactArray.rawValue: [Self.dummyString] + ], + OSPMTDetailsModel.CodingKeys.shippingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: true, + OSPMTContact.CodingKeys.contactArray.rawValue: [Self.dummyString] + ] + ] + + static let useConfigBillingContactDetailModel: [String: Any] = [ + OSPMTDetailsModel.CodingKeys.amount.rawValue: 1, + OSPMTDetailsModel.CodingKeys.currency.rawValue: Self.dummyString, + OSPMTDetailsModel.CodingKeys.status.rawValue: OSPMTStatus.final.rawValue, + OSPMTDetailsModel.CodingKeys.billingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: false + ], + OSPMTDetailsModel.CodingKeys.shippingContact.rawValue: [ + OSPMTContact.CodingKeys.isCustom.rawValue: true, + OSPMTContact.CodingKeys.contactArray.rawValue: [Self.dummyString] + ] ] + static let useConfigurationBillingContactInfoModel = OSPMTContactInfoModel(name: Self.dummyString) + static let useConfigurationBillingScopeModel = OSPMTScopeModel( + paymentData: Self.dummyDataModel, shippingInfo: Self.useConfigurationBillingContactInfoModel + ) + // MARK: - ModelSpec Methods static func decode(for type: T.Type, _ dictionary: [String: Any]) -> T? { guard