diff --git a/Braintree.xcodeproj/project.pbxproj b/Braintree.xcodeproj/project.pbxproj index 1ed4e4b4d..a48bfad98 100644 --- a/Braintree.xcodeproj/project.pbxproj +++ b/Braintree.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ 42FC237125CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FC237025CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift */; }; 45227FC52C330FDE00A15018 /* MockURLSessionTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45227FC32C330FDE00A15018 /* MockURLSessionTask.swift */; }; 45227FC72C33104100A15018 /* MockBTHTTPNetworkTiming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45227FC62C33104100A15018 /* MockBTHTTPNetworkTiming.swift */; }; + 454722B02CF0DA34000DCF4E /* LocalPaymentPOSTBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454722AF2CF0DA27000DCF4E /* LocalPaymentPOSTBody.swift */; }; 457D7FC82C29CEC300EF6523 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457D7FC72C29CEC300EF6523 /* RepeatingTimer.swift */; }; 457D7FCA2C2A250E00EF6523 /* RepeatingTimer_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457D7FC92C2A250E00EF6523 /* RepeatingTimer_Tests.swift */; }; 458570782C34A699009CEF7A /* ConfigurationLoader_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458570772C34A699009CEF7A /* ConfigurationLoader_Tests.swift */; }; @@ -722,6 +723,7 @@ 42FC237025CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalCheckoutRequest_Tests.swift; sourceTree = ""; }; 45227FC32C330FDE00A15018 /* MockURLSessionTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLSessionTask.swift; sourceTree = ""; }; 45227FC62C33104100A15018 /* MockBTHTTPNetworkTiming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBTHTTPNetworkTiming.swift; sourceTree = ""; }; + 454722AF2CF0DA27000DCF4E /* LocalPaymentPOSTBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalPaymentPOSTBody.swift; sourceTree = ""; }; 457D7FC72C29CEC300EF6523 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = ""; }; 457D7FC92C2A250E00EF6523 /* RepeatingTimer_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer_Tests.swift; sourceTree = ""; }; 458570772C34A699009CEF7A /* ConfigurationLoader_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationLoader_Tests.swift; sourceTree = ""; }; @@ -1278,6 +1280,7 @@ 80BA64B129D7937E00E15264 /* BTLocalPaymentRequest.swift */, 80BA64B329D795D000E15264 /* BTLocalPaymentRequestDelegate.swift */, 80BA64AB29D788E000E15264 /* BTLocalPaymentResult.swift */, + 454722AE2CF0DA14000DCF4E /* Models */, 3B5A41E82BA2375600921922 /* PrivacyInfo.xcprivacy */, ); path = BraintreeLocalPayment; @@ -1308,6 +1311,14 @@ path = BraintreePayPal; sourceTree = ""; }; + 454722AE2CF0DA14000DCF4E /* Models */ = { + isa = PBXGroup; + children = ( + 454722AF2CF0DA27000DCF4E /* LocalPaymentPOSTBody.swift */, + ); + path = Models; + sourceTree = ""; + }; 570B93AE285397D20041BAFE /* BraintreeCore */ = { isa = PBXGroup; children = ( @@ -3070,6 +3081,7 @@ files = ( 80BA64B429D795D000E15264 /* BTLocalPaymentRequestDelegate.swift in Sources */, 80E2460F29E492DF00945A1D /* BTLocalPaymentClient.swift in Sources */, + 454722B02CF0DA34000DCF4E /* LocalPaymentPOSTBody.swift in Sources */, 80BA64B229D7937E00E15264 /* BTLocalPaymentRequest.swift in Sources */, BE9834A22A041B6200B6C3CC /* BTConfiguration+LocalPayment.swift in Sources */, 80CF988529DB64D400D51979 /* BTLocalPaymentError.swift in Sources */, diff --git a/Sources/BraintreeLocalPayment/BTLocalPaymentClient.swift b/Sources/BraintreeLocalPayment/BTLocalPaymentClient.swift index f9cab5419..70531dafa 100644 --- a/Sources/BraintreeLocalPayment/BTLocalPaymentClient.swift +++ b/Sources/BraintreeLocalPayment/BTLocalPaymentClient.swift @@ -176,8 +176,8 @@ import BraintreeDataCollector // MARK: - Private Methods private func start(request: BTLocalPaymentRequest, configuration: BTConfiguration) { - let requestParameters = buildRequestDictionary(with: request) - apiClient.post("v1/local_payments/create", parameters: requestParameters) { body, _, error in + let localPaymentRequest = LocalPaymentPOSTBody(localPaymentRequest: request) + apiClient.post("v1/local_payments/create", parameters: localPaymentRequest) { body, _, error in if let error { self.notifyFailure(with: error, completion: self.merchantCompletion) return @@ -207,65 +207,7 @@ import BraintreeDataCollector } } } - - private func buildRequestDictionary(with request: BTLocalPaymentRequest) -> [String: Any] { - var requestParameters: [String: Any] = [ - "amount": request.amount, - "funding_source": request.paymentType, - "intent": "sale", - "currency_iso_code": request.currencyCode, - "return_url": "\(BTCoreConstants.callbackURLScheme)://x-callback-url/braintree/local-payment/success", - "cancel_url": "\(BTCoreConstants.callbackURLScheme)://x-callback-url/braintree/local-payment/cancel" - ] - - if let countryCode = request.paymentTypeCountryCode { - requestParameters["payment_type_country_code"] = countryCode - } - - if let address = request.address { - requestParameters["line1"] = address.streetAddress - requestParameters["line2"] = address.extendedAddress - requestParameters["city"] = address.locality - requestParameters["state"] = address.region - requestParameters["postal_code"] = address.postalCode - requestParameters["country_code"] = address.countryCodeAlpha2 - } - - if let givenName = request.givenName { - requestParameters["first_name"] = givenName - } - - if let surname = request.surname { - requestParameters["last_name"] = surname - } - - if let email = request.email { - requestParameters["payer_email"] = email - } - - if let phone = request.phone { - requestParameters["phone"] = phone - } - - if let merchantAccountID = request.merchantAccountID { - requestParameters["merchant_account_id"] = merchantAccountID - } - - if let bic = request.bic { - requestParameters["bic"] = bic - } - - var experienceProfile: [String: Any] = ["no_shipping": !request.isShippingAddressRequired] - - if let displayName = request.displayName { - experienceProfile["brand_name"] = displayName - } - - requestParameters["experience_profile"] = experienceProfile - - return requestParameters - } - + private func onPayment(with url: URL?, error: Error?) { if let error { notifyFailure(with: error, completion: merchantCompletion) diff --git a/Sources/BraintreeLocalPayment/BTLocalPaymentRequest.swift b/Sources/BraintreeLocalPayment/BTLocalPaymentRequest.swift index 8a7400c4b..5dd0f021e 100644 --- a/Sources/BraintreeLocalPayment/BTLocalPaymentRequest.swift +++ b/Sources/BraintreeLocalPayment/BTLocalPaymentRequest.swift @@ -11,6 +11,10 @@ import BraintreeDataCollector /// Used to initialize a local payment flow @objcMembers public class BTLocalPaymentRequest: NSObject { + // MARK: - Public Properties + + public weak var localPaymentFlowDelegate: BTLocalPaymentRequestDelegate? + // MARK: - Internal Properties let paymentType: String @@ -26,8 +30,6 @@ import BraintreeDataCollector let phone: String? let isShippingAddressRequired: Bool let bic: String? - - public weak var localPaymentFlowDelegate: BTLocalPaymentRequestDelegate? var paymentID: String? var correlationID: String? diff --git a/Sources/BraintreeLocalPayment/Models/LocalPaymentPOSTBody.swift b/Sources/BraintreeLocalPayment/Models/LocalPaymentPOSTBody.swift new file mode 100644 index 000000000..d1df89ded --- /dev/null +++ b/Sources/BraintreeLocalPayment/Models/LocalPaymentPOSTBody.swift @@ -0,0 +1,108 @@ +import Foundation + +#if canImport(BraintreeCore) +import BraintreeCore +#endif + +/// The POST body for v1/local_payments/create +struct LocalPaymentPOSTBody: Encodable { + + // MARK: - Private Properties + + private let paymentType: String + private let amount: String + private let currencyCode: String + private let paymentTypeCountryCode: String? + private let merchantAccountID: String? + private let address: BTPostalAddress? + private let email: String? + private let givenName: String? + private let surname: String? + private let phone: String? + private let bic: String? + private let intent: String + private let returnURL: String + private let cancelURL: String + private let experienceProfile: ExperienceProfile + + private var streetAddress: String? + private var extendedAddress: String? + private var locality: String? + private var countryCodeAlpha2: String? + private var postalCode: String? + private var region: String? + + // MARK: - Initializer + + init( + localPaymentRequest: BTLocalPaymentRequest + ) { + self.paymentType = localPaymentRequest.paymentType + self.amount = localPaymentRequest.amount + self.currencyCode = localPaymentRequest.currencyCode + self.paymentTypeCountryCode = localPaymentRequest.paymentTypeCountryCode + self.merchantAccountID = localPaymentRequest.merchantAccountID + self.address = localPaymentRequest.address + self.email = localPaymentRequest.email + self.givenName = localPaymentRequest.givenName + self.surname = localPaymentRequest.surname + self.phone = localPaymentRequest.phone + self.bic = localPaymentRequest.bic + self.experienceProfile = ExperienceProfile( + noShipping: !localPaymentRequest.isShippingAddressRequired, + brandName: localPaymentRequest.displayName + ) + self.intent = "sale" + self.returnURL = BTCoreConstants.callbackURLScheme + "://x-callback-url/braintree/local-payment/success" + self.cancelURL = BTCoreConstants.callbackURLScheme + "://x-callback-url/braintree/local-payment/cancel" + + if let address = localPaymentRequest.address { + self.streetAddress = address.streetAddress + self.extendedAddress = address.extendedAddress + self.locality = address.locality + self.countryCodeAlpha2 = address.countryCodeAlpha2 + self.postalCode = address.postalCode + self.region = address.region + } + } + + enum CodingKeys: String, CodingKey { + case paymentType = "funding_source" + case amount + case currencyCode = "currency_iso_code" + case paymentTypeCountryCode = "payment_type_country_code" + case merchantAccountID = "merchant_account_id" + case email = "payer_email" + case givenName = "first_name" + case surname = "last_name" + case phone + case bic + case intent + case returnURL = "return_url" + case cancelURL = "cancel_url" + case experienceProfile = "experience_profile" + + // Address keys + case streetAddress = "line1" + case extendedAddress = "line2" + case locality = "city" + case countryCodeAlpha2 = "country_code" + case postalCode = "postal_code" + case region = "state" + } +} + +extension LocalPaymentPOSTBody { + + struct ExperienceProfile: Encodable { + + let noShipping: Bool + let brandName: String? + + // swiftlint:disable nesting + enum CodingKeys: String, CodingKey { + case noShipping = "no_shipping" + case brandName = "brand_name" + } + } +}