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 credit cards post #1488

Open
wants to merge 64 commits into
base: v7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1bf3167
Add new codable struct
warmkesselj Nov 7, 2024
048e1bb
Model encodable object
warmkesselj Nov 8, 2024
b75543c
Update BTCreditCardBody
warmkesselj Nov 18, 2024
ab0b715
Add BTCreditCardGraphQLBody
warmkesselj Nov 19, 2024
c0872bd
Update to use new encodable objects
warmkesselj Nov 19, 2024
8fc4325
Move auth insight property
warmkesselj Nov 19, 2024
63512a7
Update BTCreditCardGraphQLBody
warmkesselj Nov 19, 2024
4630b44
Update the encodable objects. Remove dynamic keys and use the enum co…
warmkesselj Nov 19, 2024
36d3bf8
Clean up
warmkesselj Nov 19, 2024
f271a67
Identify failing tests for updating
warmkesselj Nov 19, 2024
b1b46af
Updates to Encodable body
warmkesselj Nov 19, 2024
8a72b11
Conform encodable objects to NSObject
warmkesselj Nov 20, 2024
9062d97
Fix unit tests
warmkesselj Dec 2, 2024
d1e9d9b
Merge branch 'main' into create-encodable-for-credit-cards-post
warmkesselj Dec 16, 2024
f0f72e7
Remove commented out code
warmkesselj Dec 16, 2024
69c963a
Refactor for linting
warmkesselj Dec 17, 2024
9d525fa
Linting
warmkesselj Dec 17, 2024
22340e2
Disable lint in Encodable files
warmkesselj Dec 17, 2024
c57f551
Unit tests update
warmkesselj Jan 13, 2025
6152ee9
Check if not equal to nil and sets the billing address properties
warmkesselj Jan 13, 2025
ba01e6d
Update unit tests BTCard_tests
warmkesselj Jan 14, 2025
6197b1d
Updates to unit tests
warmkesselj Jan 14, 2025
f963037
Updating naming, and use structs
warmkesselj Jan 15, 2025
15f3ccd
Update names
warmkesselj Jan 15, 2025
8d8c768
Move card post body init to BTCard parameters method, move instantiat…
richherrera Jan 15, 2025
fcaa1e7
Encapsulate logic to build CreditCardGraphQLBody
warmkesselj Jan 22, 2025
2607562
Use let over var
warmkesselj Jan 22, 2025
2b204b6
Clean up
warmkesselj Jan 22, 2025
4a2dad5
Refactor name
warmkesselj Jan 22, 2025
931392e
Merge branch 'v7' of https://github.com/braintree/braintree_ios into …
warmkesselj Jan 27, 2025
03090c3
Update project file
warmkesselj Jan 27, 2025
88b9b01
BTCard from V7
warmkesselj Jan 28, 2025
03b8d66
Use Mark public
warmkesselj Jan 28, 2025
9473497
Undo internal change
warmkesselj Jan 28, 2025
db601a3
Remove extra line
warmkesselj Jan 28, 2025
a08a167
Update to include billing address
warmkesselj Jan 28, 2025
85dfe83
Fix unit test merge conflict
warmkesselj Jan 28, 2025
76f51e0
Update CreditCardGraphQLBody
warmkesselj Jan 29, 2025
dabd1d1
Undo change on BTCard
warmkesselj Jan 29, 2025
d2d1c28
Further refactoring
warmkesselj Jan 29, 2025
c56dd73
Update unit tests
warmkesselj Jan 30, 2025
4f2dc63
BillingAddress only if name
warmkesselj Jan 30, 2025
e38acfd
Unit tests
warmkesselj Jan 30, 2025
38be363
Unit tests
warmkesselj Feb 3, 2025
651ce42
Update CreditCardGraphQLBody
warmkesselj Feb 3, 2025
730cfb0
Re-add lastPOSTParameters
warmkesselj Feb 3, 2025
4d0addd
Update unit tests
warmkesselj Feb 3, 2025
c568526
Changed Id to ID
warmkesselj Feb 3, 2025
c4e9b8c
Pass the entire metadata field into CreditCardPOSTBody
warmkesselj Feb 3, 2025
3fe7c4c
Update to use ID instead of Id syntax
warmkesselj Feb 3, 2025
7a6d3ea
disable swiftlint cyclomatic_complexity on PayPalCheckoutPOSTBody
warmkesselj Feb 4, 2025
2c62305
Update to merchantAccountID in unit tests.
warmkesselj Feb 4, 2025
2015365
Add compiler directive to check if BraintreeCore can be imported
warmkesselj Feb 4, 2025
95f1b03
PR comments
warmkesselj Feb 5, 2025
fc06112
PR comments
warmkesselj Feb 5, 2025
7b2c1a8
Update unit tests
warmkesselj Feb 5, 2025
09d3ab1
PR comments and swift lint
warmkesselj Feb 6, 2025
e4d2019
Update swiftlint rule to disable nesting
warmkesselj Feb 6, 2025
7528172
Merge branch 'v7' of https://github.com/braintree/braintree_ios into …
warmkesselj Feb 6, 2025
3cc172b
Swiftlint issues
warmkesselj Feb 6, 2025
0076cb6
Remove uneeded guard for authenticationInsightRequested
warmkesselj Feb 6, 2025
71c807b
Remove uneeded guard
warmkesselj Feb 6, 2025
f4829c4
Omitting checks for each of the properties
warmkesselj Feb 7, 2025
b11ef64
Update unit test due to change in contract
warmkesselj Feb 7, 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
8 changes: 8 additions & 0 deletions Braintree.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@
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 */; };
B8F870152D48435D000FCE3C /* CreditCardPOSTBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F870142D48435D000FCE3C /* CreditCardPOSTBody.swift */; };
B8F870162D48435D000FCE3C /* CreditCardGraphQLBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F870132D48435D000FCE3C /* CreditCardGraphQLBody.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 @@ -896,6 +898,8 @@
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>"; };
B8F870132D48435D000FCE3C /* CreditCardGraphQLBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCardGraphQLBody.swift; sourceTree = "<group>"; };
B8F870142D48435D000FCE3C /* CreditCardPOSTBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCardPOSTBody.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 @@ -1746,6 +1750,8 @@
BEFE9A3C29C8ECAA00BF69AB /* BTCardError.swift */,
BE80C00A29C66F4800793A6C /* BTCardNonce.swift */,
BE80C00629C5516E00793A6C /* BTThreeDSecureInfo.swift */,
B8F870132D48435D000FCE3C /* CreditCardGraphQLBody.swift */,
B8F870142D48435D000FCE3C /* CreditCardPOSTBody.swift */,
806C85622B90EBED00A2754C /* PrivacyInfo.xcprivacy */,
);
path = BraintreeCard;
Expand Down Expand Up @@ -3300,6 +3306,8 @@
BE80C00B29C66F4800793A6C /* BTCardNonce.swift in Sources */,
BE80C00D29C8B4B900793A6C /* BTCard.swift in Sources */,
BE80C00529C54F2000793A6C /* BTAuthenticationInsight.swift in Sources */,
B8F870152D48435D000FCE3C /* CreditCardPOSTBody.swift in Sources */,
B8F870162D48435D000FCE3C /* CreditCardGraphQLBody.swift in Sources */,
BE80C00729C5516E00793A6C /* BTThreeDSecureInfo.swift in Sources */,
BEFE9A3D29C8ECAA00BF69AB /* BTCardError.swift in Sources */,
BEFE9A3B29C8EC6B00BF69AB /* BTCardClient.swift in Sources */,
Expand Down
187 changes: 12 additions & 175 deletions Sources/BraintreeCard/BTCard.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import Foundation

#if canImport(BraintreeCore)
import BraintreeCore
#endif

/// The card tokenization request represents raw credit or debit card data provided by the customer.
/// Its main purpose is to serve as the input for tokenization.
@objcMembers public class BTCard: NSObject {
Expand Down Expand Up @@ -116,181 +120,14 @@ import Foundation

// MARK: - Internal Methods

func parameters() -> [String: Any] {
var cardDictionary: [String: Any] = buildCardDictionary(isGraphQL: false)
let billingAddressDictionary: [String: String] = buildBillingAddressDictionary(isGraphQL: false)

if !billingAddressDictionary.isEmpty {
cardDictionary["billing_address"] = billingAddressDictionary
}

let options: [String: Bool] = ["validate": shouldValidate]
cardDictionary["options"] = options
return cardDictionary
}

func graphQLParameters() -> [String: Any] {
var cardDictionary: [String: Any] = buildCardDictionary(isGraphQL: true)
let billingAddressDictionary: [String: String] = buildBillingAddressDictionary(isGraphQL: true)

if !billingAddressDictionary.isEmpty {
cardDictionary["billingAddress"] = billingAddressDictionary
}

let options: [String: Bool] = ["validate": shouldValidate]
let inputDictionary: [String: Any] = ["creditCard": cardDictionary, "options": options]
var variables: [String: Any] = ["input": inputDictionary]

if authenticationInsightRequested {
if let merchantAccountID {
variables["authenticationInsightInput"] = ["merchantAccountId": merchantAccountID]
} else {
variables["authenticationInsightInput"] = [:]
}
}

return [
"operationName": "TokenizeCreditCard",
"query": cardTokenizationGraphQLMutation(),
"variables": variables
]
}

// MARK: - Private Methods

private func buildCardDictionary(isGraphQL: Bool) -> [String: Any] {
var cardDictionary: [String: Any] = [:]

if !number.isEmpty {
cardDictionary["number"] = number
}

if !expirationMonth.isEmpty {
cardDictionary[isGraphQL ? "expirationMonth" : "expiration_month"] = expirationMonth
}

if !expirationYear.isEmpty {
cardDictionary[isGraphQL ? "expirationYear" : "expiration_year"] = expirationYear
}

cardDictionary["cvv"] = cvv

if let cardholderName {
cardDictionary[isGraphQL ? "cardholderName" : "cardholder_name"] = cardholderName
}

return cardDictionary
}

// swiftlint:disable cyclomatic_complexity
private func buildBillingAddressDictionary(isGraphQL: Bool) -> [String: String] {
var billingAddressDictionary: [String: String] = [:]

if let firstName {
billingAddressDictionary[isGraphQL ? "firstName" : "first_name"] = firstName
}

if let lastName {
billingAddressDictionary[isGraphQL ? "lastName" : "last_name"] = lastName
}

if let company {
billingAddressDictionary["company"] = company
}

if let postalCode {
billingAddressDictionary[isGraphQL ? "postalCode" : "postal_code"] = postalCode
}

if let streetAddress {
billingAddressDictionary[isGraphQL ? "streetAddress" : "street_address"] = streetAddress
}

if let extendedAddress {
billingAddressDictionary[isGraphQL ? "extendedAddress" : "extended_address"] = extendedAddress
}

if let locality {
billingAddressDictionary["locality"] = locality
}

if let region {
billingAddressDictionary["region"] = region
}

if let countryName {
billingAddressDictionary[isGraphQL ? "countryName" : "country_name"] = countryName
}

if let countryCodeAlpha2 {
billingAddressDictionary[isGraphQL ? "countryCodeAlpha2" : "country_code_alpha2"] = countryCodeAlpha2
}

if let countryCodeAlpha3 {
billingAddressDictionary[isGraphQL ? "countryCode" : "country_code_alpha3"] = countryCodeAlpha3
}

if let countryCodeNumeric {
billingAddressDictionary[isGraphQL ? "countryCodeNumeric" : "country_code_numeric"] = countryCodeNumeric
}

return billingAddressDictionary
}
// swiftlint:enable cyclomatic_complexity

private func cardTokenizationGraphQLMutation() -> String {
var mutation = "mutation TokenizeCreditCard($input: TokenizeCreditCardInput!"

if authenticationInsightRequested {
mutation.append(", $authenticationInsightInput: AuthenticationInsightInput!")
}

// swiftlint:disable indentation_width
mutation.append(
"""
) {
tokenizeCreditCard(input: $input) {
token
creditCard {
brand
expirationMonth
expirationYear
cardholderName
last4
bin
binData {
prepaid
healthcare
debit
durbinRegulated
commercial
payroll
issuingBank
countryOfIssuance
productId
}
}
"""
func graphQLParameters(apiClient: BTAPIClient) -> CreditCardPOSTBody {
CreditCardPOSTBody(
card: self,
metadata: apiClient.metadata
)

if authenticationInsightRequested {
mutation.append(
"""
authenticationInsight(input: $authenticationInsightInput) {
customerAuthenticationRegulationEnvironment
}
"""
)
}

mutation.append(
"""
}
}
"""
)
// swiftlint:enable indentation_width

return mutation.replacingOccurrences(of: "\n", with: "")
}

func parameters() -> CreditCardGraphQLBody {
warmkesselj marked this conversation as resolved.
Show resolved Hide resolved
CreditCardGraphQLBody(card: self)
}
}
24 changes: 2 additions & 22 deletions Sources/BraintreeCard/BTCardClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import BraintreeCore
return
}

let parameters = card.graphQLParameters()
let parameters = card.parameters()

self.apiClient.post("", parameters: parameters, httpType: .graphQLAPI) { body, _, error in
if let error = error as NSError? {
Expand Down Expand Up @@ -79,7 +79,7 @@ import BraintreeCore
return
}
} else {
let parameters = self.clientAPIParameters(for: card)
let parameters = card.graphQLParameters(apiClient: self.apiClient)

self.apiClient.post("v1/payment_methods/credit_cards", parameters: parameters) {body, _, error in
if let error = error as NSError? {
Expand Down Expand Up @@ -136,26 +136,6 @@ import BraintreeCore
return false
}

private func clientAPIParameters(for card: BTCard) -> [String: Any] {
var parameters: [String: Any] = [:]
parameters["credit_card"] = card.parameters()

let metadata: [String: String] = [
"source": apiClient.metadata.source.stringValue,
"integration": apiClient.metadata.integration.stringValue,
"sessionId": apiClient.metadata.sessionID
]

parameters["_meta"] = metadata

if card.authenticationInsightRequested {
parameters["authenticationInsight"] = true
parameters["merchantAccountId"] = card.merchantAccountID
}

return parameters
}

// MARK: - Error Construction Methods

/// Convenience helper method for creating friendlier, more human-readable userInfo dictionaries for 422 HTTP errors
Expand Down
Loading
Loading