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

Create encodable for paypal accounts post #1518

Open
wants to merge 25 commits into
base: v7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1c3aeac
Introduce Paypal account encodable
warmkesselj Feb 6, 2025
64ac4ad
update encodable object
warmkesselj Feb 11, 2025
176bc41
Update Encodable object
warmkesselj Feb 11, 2025
635f6cc
Add paypal browser to source. clean up
warmkesselj Feb 12, 2025
532fb10
Merge branch 'v7' of https://github.com/braintree/braintree_ios into …
warmkesselj Feb 12, 2025
9a68e22
Refactor
warmkesselj Feb 12, 2025
3844f89
Single line for guard
warmkesselj Feb 12, 2025
82b5a4c
update unit tests
warmkesselj Feb 12, 2025
d3dd64a
Update unit tests
warmkesselj Feb 14, 2025
940d9a8
PR comments
warmkesselj Feb 14, 2025
8ef4fe3
PR comments
warmkesselj Feb 14, 2025
f0839eb
Swiftlint fix
warmkesselj Feb 20, 2025
f7ebcdf
PR comments
warmkesselj Feb 25, 2025
81e2835
Updates for meta
warmkesselj Feb 25, 2025
b58452b
apiClient metadata included
warmkesselj Feb 25, 2025
31ed09a
PayPalBrowser is hardcoded
warmkesselj Feb 25, 2025
3599deb
Merge branch 'v7' of https://github.com/braintree/braintree_ios into …
warmkesselj Feb 26, 2025
742f229
Update project file
warmkesselj Feb 26, 2025
ec402b2
PR comments
warmkesselj Mar 3, 2025
c3bc6a1
Add new test and update error handling
warmkesselj Mar 3, 2025
c1e8c73
Update unit tests
warmkesselj Mar 4, 2025
eddb580
Update Sources/BraintreePayPal/BTPayPalClient.swift
warmkesselj Mar 4, 2025
cc489ac
Move uit test
warmkesselj Mar 4, 2025
4c9b7dd
Merge branch 'create-encodable-paypal-accounts-post' of https://githu…
warmkesselj Mar 4, 2025
8073b07
Update name
warmkesselj Mar 4, 2025
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
4 changes: 4 additions & 0 deletions Braintree.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
A9E80A9F24FEF40C00196BD3 /* BraintreeTestShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A903E1A624F9D34000C314E1 /* BraintreeTestShared.framework */; };
A9E80AA324FEF4D800196BD3 /* MockLocalPaymentRequestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E80AA224FEF4D800196BD3 /* MockLocalPaymentRequestDelegate.swift */; };
B8BA342E2D4811560030423C /* BTContactInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BA342D2D4811560030423C /* BTContactInformation.swift */; };
B8FB48082D553B4F00084A27 /* PayPalAccountPostEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8FB48072D553B3800084A27 /* PayPalAccountPostEncodable.swift */; };
BC17F9B428D23C5C004B18CC /* BTGraphQLMultiErrorNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC17F9B328D23C5C004B18CC /* BTGraphQLMultiErrorNode.swift */; };
BC17F9BC28D24C9E004B18CC /* BTGraphQLErrorTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC17F9BB28D24C9E004B18CC /* BTGraphQLErrorTree.swift */; };
BC17F9BE28D25054004B18CC /* BTGraphQLErrorNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC17F9BD28D25054004B18CC /* BTGraphQLErrorNode.swift */; };
Expand Down Expand Up @@ -898,6 +899,7 @@
A9E5C22824FD6D0800EE691F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A9E80AA224FEF4D800196BD3 /* MockLocalPaymentRequestDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLocalPaymentRequestDelegate.swift; sourceTree = "<group>"; };
B8BA342D2D4811560030423C /* BTContactInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTContactInformation.swift; sourceTree = "<group>"; };
B8FB48072D553B3800084A27 /* PayPalAccountPostEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalAccountPostEncodable.swift; sourceTree = "<group>"; };
BC17F9B328D23C5C004B18CC /* BTGraphQLMultiErrorNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTGraphQLMultiErrorNode.swift; sourceTree = "<group>"; };
BC17F9BB28D24C9E004B18CC /* BTGraphQLErrorTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTGraphQLErrorTree.swift; sourceTree = "<group>"; };
BC17F9BD28D25054004B18CC /* BTGraphQLErrorNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTGraphQLErrorNode.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1305,6 +1307,7 @@
8014221B2BAE935B009F9999 /* BTPayPalApprovalURLParser.swift */,
BE8E5CEE294B6937001BF017 /* BTPayPalCheckoutRequest.swift */,
57544F5929524E4D00DEB7B0 /* BTPayPalClient.swift */,
B8FB48072D553B3800084A27 /* PayPalAccountPostEncodable.swift */,
5754481F294A2EBE00DEB7B0 /* BTPayPalCreditFinancing.swift */,
5754481D294A2A1D00DEB7B0 /* BTPayPalCreditFinancingAmount.swift */,
57544F5D295258AC00DEB7B0 /* BTPayPalError.swift */,
Expand Down Expand Up @@ -3156,6 +3159,7 @@
BE349111294B77E100D2CF68 /* BTPayPalVaultRequest.swift in Sources */,
62B811882CC002470024A688 /* BTPayPalPhoneNumber.swift in Sources */,
807D22F52C29ADE2009FFEA4 /* BTPayPalRecurringBillingPlanType.swift in Sources */,
B8FB48082D553B4F00084A27 /* PayPalAccountPostEncodable.swift in Sources */,
B8BA342E2D4811560030423C /* BTContactInformation.swift in Sources */,
57544820294A2EBE00DEB7B0 /* BTPayPalCreditFinancing.swift in Sources */,
807D22EE2C29A918009FFEA4 /* BTPayPalRecurringBillingDetails.swift in Sources */,
Expand Down
9 changes: 9 additions & 0 deletions IntegrationTests/BraintreePayPal_IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class BraintreePayPal_IntegrationTests: XCTestCase {
}

let payPalClient = BTPayPalClient(apiClient: apiClient)

payPalClient.payPalRequest = BTPayPalVaultRequest()

let tokenizationExpectation = expectation(description: "Tokenize one-time payment")
let returnURL = URL(string: oneTouchCoreAppSwitchSuccessURLFixture)

Expand All @@ -39,6 +42,8 @@ class BraintreePayPal_IntegrationTests: XCTestCase {
}

let payPalClient = BTPayPalClient(apiClient: apiClient)
payPalClient.payPalRequest = BTPayPalVaultRequest()

let tokenizationExpectation = expectation(description: "Tokenize one-time payment")
let returnURL = URL(string: oneTouchCoreAppSwitchSuccessURLFixture)

Expand All @@ -65,6 +70,8 @@ class BraintreePayPal_IntegrationTests: XCTestCase {
}

let payPalClient = BTPayPalClient(apiClient: apiClient)
payPalClient.payPalRequest = BTPayPalVaultRequest()

let tokenizationExpectation = expectation(description: "Tokenize billing agreement payment")
let returnURL = URL(string: oneTouchCoreAppSwitchSuccessURLFixture)

Expand All @@ -89,6 +96,8 @@ class BraintreePayPal_IntegrationTests: XCTestCase {
}

let payPalClient = BTPayPalClient(apiClient: apiClient)
payPalClient.payPalRequest = BTPayPalVaultRequest()

let tokenizationExpectation = expectation(description: "Tokenize billing agreement payment")
let returnURL = URL(string: oneTouchCoreAppSwitchSuccessURLFixture)

Expand Down
50 changes: 10 additions & 40 deletions Sources/BraintreePayPal/BTPayPalClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,48 +208,18 @@ import BraintreeDataCollector
notifyCancel(completion: completion)
return
}

let clientDictionary: [String: String] = [
"platform": "iOS",
"product_name": "PayPal",
"paypal_sdk_version": "version"
]

let responseDictionary: [String: String] = ["webURL": url.absoluteString]

var account: [String: Any] = [
"client": clientDictionary,
"response": responseDictionary,
"response_type": "web"
]

if paymentType == .checkout {
account["options"] = ["validate": false]
if let request = payPalRequest as? BTPayPalCheckoutRequest {
account["intent"] = request.intent.stringValue
}
}

if let clientMetadataID {
account["correlation_id"] = clientMetadataID
}

var parameters: [String: Any] = ["paypal_account": account]

if let payPalRequest, let merchantAccountID = payPalRequest.merchantAccountID {
parameters["merchant_account_id"] = merchantAccountID
}

let metadata = apiClient.metadata
metadata.source = .payPalBrowser

parameters["_meta"] = [
"source": metadata.source.stringValue,
"integration": metadata.integration.stringValue,
"sessionId": metadata.sessionID
]
guard let request = payPalRequest else { return }

let encodableParams = PayPalAccountPostEncodable(
request: request,
client: apiClient,
paymentType: paymentType,
url: url,
correlationID: clientMetadataID
)

apiClient.post("/v1/payment_methods/paypal_accounts", parameters: parameters) { body, _, error in
apiClient.post("/v1/payment_methods/paypal_accounts", parameters: encodableParams) { body, _, error in
if let error {
self.notifyFailure(with: error, completion: completion)
return
Expand Down
113 changes: 113 additions & 0 deletions Sources/BraintreePayPal/PayPalAccountPostEncodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import Foundation

#if canImport(BraintreeCore)
import BraintreeCore
#endif

/// The POST body for /v1/payment_methods/paypal_accounts
struct PayPalAccountPostEncodable: Encodable {

let paypalAccount: PayPalAccount
let meta: Meta
let merchantAccountID: String?

init(
request: BTPayPalRequest,
client: BTAPIClient,
paymentType: BTPayPalPaymentType,
url: URL?,
correlationID: String?
) {
self.paypalAccount = PayPalAccount(
request: request,
client: client,
paymentType: paymentType,
url: url,
correlationID: correlationID
)

self.meta = Meta(meta: client.metadata)

self.merchantAccountID = request.merchantAccountID
}

enum CodingKeys: String, CodingKey {
case paypalAccount = "paypal_account"
case meta = "_meta"
case merchantAccountID = "merchant_account_id"
}
}

struct PayPalAccount: Encodable {

let responseType: String
let intent: String?
let correlationId: String?
let options: Options?
let client: Client
let response: PayPalResponse

init(request: BTPayPalRequest, client: BTAPIClient, paymentType: BTPayPalPaymentType, url: URL?, correlationID: String?) {
responseType = "web"
correlationId = correlationID

options = paymentType == .checkout ? Options(validate: false) : nil
intent = paymentType == .checkout
? (request as? BTPayPalCheckoutRequest)?.intent.stringValue
: nil

self.client = Client()
self.response = PayPalResponse(webURL: url?.absoluteString ?? "")
}

enum CodingKeys: String, CodingKey {
case responseType = "response_type"
case intent
case correlationId = "correlation_id"
case options
case client
case response
}
}

struct Options: Encodable {

let validate: Bool
}

struct Client: Encodable {

let platform = "iOS"
let productName = "PayPal"
let paypalSdkVersion = "version"

enum CodingKeys: String, CodingKey {
case platform
case productName = "product_name"
case paypalSdkVersion = "paypal_sdk_version"
}
}

struct PayPalResponse: Encodable {

let webURL: String

enum CodingKeys: String, CodingKey {
case webURL
}
}

struct Meta: Encodable {

let integration: String
let source: String
let sessionId: String

init(meta: BTClientMetadata) {
meta.source = .payPalBrowser

self.integration = meta.integration.stringValue
self.source = meta.source.stringValue
self.sessionId = meta.sessionID
}
}
20 changes: 19 additions & 1 deletion UnitTests/BraintreePayPalTests/BTPayPalClient_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,10 @@ class BTPayPalClient_Tests: XCTestCase {

func testHandleBrowserSwitchReturn_whenBrowserSwitchSucceeds_tokenizesPayPalCheckout() {
let returnURL = URL(string: "bar://onetouch/v1/success?token=hermes_token")!

let payPalRequest = BTPayPalVaultRequest()
payPalClient.payPalRequest = payPalRequest

payPalClient.handleReturn(returnURL, paymentType: .checkout) { _, _ in }

XCTAssertEqual(mockAPIClient.lastPOSTPath, "/v1/payment_methods/paypal_accounts")
Expand Down Expand Up @@ -430,6 +434,8 @@ class BTPayPalClient_Tests: XCTestCase {
func testHandleBrowserSwitchReturn_whenBrowserSwitchSucceeds_intentShouldBeNilForVaultRequests() {
let payPalRequest = BTPayPalVaultRequest()
let returnURL = URL(string: "bar://onetouch/v1/success?ec-token=ec_token")!

payPalClient.payPalRequest = payPalRequest
payPalClient.handleReturn(returnURL, paymentType: payPalRequest.paymentType) { _, _ in }

XCTAssertEqual(mockAPIClient.lastPOSTPath, "/v1/payment_methods/paypal_accounts")
Expand All @@ -441,8 +447,12 @@ class BTPayPalClient_Tests: XCTestCase {

func testHandleBrowserSwitchReturn_whenBrowserSwitchSucceeds_merchantAccountIdIsSet() {
let merchantAccountID = "alternate-merchant-account-id"

let payPalRequest = BTPayPalVaultRequest()
payPalClient.payPalRequest = payPalRequest

payPalClient.payPalRequest = BTPayPalCheckoutRequest(amount: "1.34", merchantAccountID: merchantAccountID)

let returnURL = URL(string: "bar://onetouch/v1/success?token=hermes_token")!
payPalClient.handleReturn(returnURL, paymentType: .checkout) { _, _ in }

Expand Down Expand Up @@ -520,6 +530,10 @@ class BTPayPalClient_Tests: XCTestCase {

func testHandleBrowserSwitchReturn_whenBrowserSwitchSucceeds_sendsCorrectParametersForTokenization() {
let returnURL = URL(string: "bar://onetouch/v1/success?token=hermes_token")!

let payPalRequest = BTPayPalVaultRequest()
payPalClient.payPalRequest = payPalRequest

payPalClient.handleReturn(returnURL, paymentType: .vault) { _, _ in }

XCTAssertEqual(mockAPIClient.lastPOSTPath, "/v1/payment_methods/paypal_accounts")
Expand Down Expand Up @@ -696,6 +710,10 @@ class BTPayPalClient_Tests: XCTestCase {

func testMetadata_whenCheckoutBrowserSwitchIsSuccessful_isPOSTedToServer() {
let returnURL = URL(string: "bar://onetouch/v1/success?token=hermes_token")!

let payPalRequest = BTPayPalVaultRequest()
payPalClient.payPalRequest = payPalRequest

payPalClient.handleReturn(returnURL, paymentType: .checkout) { _, _ in }

XCTAssertEqual(mockAPIClient.lastPOSTPath, "/v1/payment_methods/paypal_accounts")
Expand Down
Loading