Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* Update `BTPayPalLineItem` to make all properties accessible on the initializer only vs via the dot syntax.
* BraintreeVenmo
* Update `BTVenmoLineItem` to make all properties accessible on the initializer only vs via the dot syntax.
* BraintreeCore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we care about alphabetical order here?
BraintreeCore before BraintreePayPal?

* Update`BTPostalAddress` to make all properties accessible on the initializer only vs via the dot syntax.

## 6.39.0 (2025-10-01)
* BraintreeCore
Expand Down
11 changes: 6 additions & 5 deletions Demo/Application/Features/IdealViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ class IdealViewController: PaymentButtonBaseViewController {
private func startPaymentWithBank() {
localPaymentClient = BTLocalPaymentClient(authorization: "sandbox_f252zhq7_hh4cpc39zq4rgjcg")

let postalAddress = BTPostalAddress()
postalAddress.countryCodeAlpha2 = "NL"
postalAddress.postalCode = "2585 GJ"
postalAddress.streetAddress = "836486 of 22321 Park Lake"
postalAddress.locality = "Den Haag"
let postalAddress = BTPostalAddress(
streetAddress: "836486 of 22321 Park Lake",
locality: "Den Haag",
countryCodeAlpha2: "NL",
postalCode: "2585 GJ"
)

let request = BTLocalPaymentRequest(
paymentType: "ideal",
Expand Down
15 changes: 8 additions & 7 deletions Demo/Application/Features/SEPADirectDebitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ class SEPADirectDebitViewController: PaymentButtonBaseViewController {
@objc func sepaDirectDebitButtonTapped() {
self.progressBlock("Tapped SEPA Direct Debit")

let billingAddress = BTPostalAddress()
billingAddress.streetAddress = "Kantstraße 70"
billingAddress.extendedAddress = "#170"
billingAddress.locality = "Freistaat Sachsen"
billingAddress.region = "Annaberg-buchholz"
billingAddress.postalCode = "09456"
billingAddress.countryCodeAlpha2 = "FR"
let billingAddress = BTPostalAddress(
streetAddress: "Kantstraße 70",
extendedAddress: "#170",
locality: "Freistaat Sachsen",
countryCodeAlpha2: "FR",
postalCode: "09456",
region: "Annaberg-buchholz"
)

let sepaDirectDebitRequest = BTSEPADirectDebitRequest(
accountHolderName: "John Doe",
Expand Down
26 changes: 17 additions & 9 deletions Sources/BraintreeCore/BTJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,22 @@ public class BTJSON: NSObject {
public func asAddress() -> BTPostalAddress? {
guard self.isObject else { return nil }

let address = BTPostalAddress()
address.recipientName = self["recipientName"].asString() ?? self["fullName"].asString() // Likely to be nil
address.streetAddress = self["street1"].asString() ?? self["line1"].asString() ?? self["addressLine1"].asString()
address.extendedAddress = self["street2"].asString() ?? self["line2"].asString() ?? self["addressLine2"].asString()
address.locality = self["city"].asString() ?? self["adminArea2"].asString()
address.region = self["state"].asString() ?? self["adminArea1"].asString()
address.postalCode = self["postalCode"].asString()
address.countryCodeAlpha2 = self["country"].asString() ?? self["countryCode"].asString()
return address
let recipientName = self["recipientName"].asString() ?? self["fullName"].asString()
let streetAddress = self["street1"].asString() ?? self["line1"].asString() ?? self["addressLine1"].asString()
let extendedAddress = self["street2"].asString() ?? self["line2"].asString() ?? self["addressLine2"].asString()
let locality = self["city"].asString() ?? self["adminArea2"].asString()
let region = self["state"].asString() ?? self["adminArea1"].asString()
let postalCode = self["postalCode"].asString()
let countryCodeAlpha2 = self["country"].asString() ?? self["countryCode"].asString()

return BTPostalAddress(
recipientName: recipientName,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a blocker, very much a take it or leave it. For these instead of making them all stored properties we could also just this inline:

Suggested change
recipientName: recipientName,
recipientName: self["recipientName"].asString() ?? self["fullName"].asString(),

streetAddress: streetAddress,
extendedAddress: extendedAddress,
locality: locality,
countryCodeAlpha2: countryCodeAlpha2,
postalCode: postalCode,
region: region
)
}
}
89 changes: 67 additions & 22 deletions Sources/BraintreeCore/BTPostalAddress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,46 @@ import Foundation
/// Generic postal address
@objcMembers public class BTPostalAddress: NSObject, Encodable {

// MARK: - Internal Properties

// Property names follow the `Braintree_Address` convention as documented at:
// https://developer.paypal.com/braintree/docs/reference/request/address/create

/// Optional. Recipient name for shipping address.
public var recipientName: String?

/// Line 1 of the Address (eg. number, street, etc).
public var streetAddress: String?

/// Optional line 2 of the Address (eg. suite, apt #, etc.).
public var extendedAddress: String?

/// City name
public var locality: String?

/// 2 letter country code.
public var countryCodeAlpha2: String?

/// Zip code or equivalent is usually required for countries that have them.
/// For a list of countries that do not have postal codes please refer to http://en.wikipedia.org/wiki/Postal_code.
public var postalCode: String?

/// Either a two-letter state code (for the US), or an ISO-3166-2 country subdivision code of up to three letters.
public var region: String?
let recipientName: String?
let streetAddress: String?
let extendedAddress: String?
let locality: String?
let countryCodeAlpha2: String?
let postalCode: String?
let region: String?

// MARK: - Initializer

/// Creats a postal address with all components
/// - Parameters:
/// - recipientName: Optional. Recipient name for shipping address.
/// - streetAddress: Optional. Line 1 of the Address (eg. number, street, etc).
/// - extendedAddress: Optional. Line 2 of the Address (eg. suite, apt #, etc.).
/// - locality: Optional. City name
/// - countryCodeAlpha2: Optional. 2 letter country code.
/// - postalCode: Optional. Zip code or equivalent is usually required for countries that have them. For a list of countries that do not have postal codes please refer to http://en.wikipedia.org/wiki/Postal_code.
/// - region: Optional. Either a two-letter state code (for the US), or an ISO-3166-2 country subdivision code of up to three letters.
public init(
recipientName: String? = nil,
streetAddress: String? = nil,
extendedAddress: String? = nil,
locality: String? = nil,
countryCodeAlpha2: String? = nil,
postalCode: String? = nil,
region: String? = nil
) {
self.recipientName = recipientName
self.streetAddress = streetAddress
self.extendedAddress = extendedAddress
self.locality = locality
self.countryCodeAlpha2 = countryCodeAlpha2
self.postalCode = postalCode
self.region = region
}

enum CodingKeys: String, CodingKey {
case countryCodeAlpha2 = "country_code"
Expand All @@ -37,4 +53,33 @@ import Foundation
case recipientName = "recipient_name"
case streetAddress = "line1"
}

// MARK: - Helper Method

/// Returns address components as a dictionary for accessing internal properties across modules
public func addressComponents() -> [String: String] {
var components: [String: String] = [:]
if let recipientName = recipientName {
components["recipientName"] = recipientName
}
if let streetAddress = streetAddress {
components["streetAddress"] = streetAddress
}
if let extendedAddress = extendedAddress {
components["extendedAddress"] = extendedAddress
}
if let locality = locality {
components["locality"] = locality
}
if let countryCodeAlpha2 = countryCodeAlpha2 {
components["countryCodeAlpha2"] = countryCodeAlpha2
}
if let postalCode = postalCode {
components["postalCode"] = postalCode
}
if let region = region {
components["region"] = region
}
return components
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ struct LocalPaymentPOSTBody: Encodable {
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
let addressComponents = address.addressComponents()
self.streetAddress = addressComponents["streetAddress"]
self.extendedAddress = addressComponents["extendedAddress"]
self.locality = addressComponents["locality"]
self.countryCodeAlpha2 = addressComponents["countryCodeAlpha2"]
self.postalCode = addressComponents["postalCode"]
self.region = addressComponents["region"]
}
}

Expand Down
15 changes: 8 additions & 7 deletions Sources/BraintreePayPal/Models/PayPalCheckoutPOSTBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ struct PayPalCheckoutPOSTBody: Encodable {
}

if let shippingAddressOverride = payPalRequest.shippingAddressOverride {
self.streetAddress = shippingAddressOverride.streetAddress
self.extendedAddress = shippingAddressOverride.extendedAddress
self.locality = shippingAddressOverride.locality
self.countryCodeAlpha2 = shippingAddressOverride.countryCodeAlpha2
self.postalCode = shippingAddressOverride.postalCode
self.region = shippingAddressOverride.region
self.recipientName = shippingAddressOverride.recipientName
let addressComponents = shippingAddressOverride.addressComponents()
self.recipientName = addressComponents["recipientName"]
self.streetAddress = addressComponents["streetAddress"]
self.extendedAddress = addressComponents["extendedAddress"]
self.locality = addressComponents["locality"]
self.countryCodeAlpha2 = addressComponents["countryCodeAlpha2"]
self.postalCode = addressComponents["postalCode"]
self.region = addressComponents["region"]
}

if let merchantAccountID = payPalRequest.merchantAccountID {
Expand Down
20 changes: 12 additions & 8 deletions Sources/BraintreeSEPADirectDebit/Models/SEPADebitRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ struct SEPADebitRequest: Encodable {
self.mandateType = sepaDirectDebitRequest.mandateType?.description
self.accountHolderName = sepaDirectDebitRequest.accountHolderName
self.iban = sepaDirectDebitRequest.iban
self.billingAddress = BillingAddress(
streetAddress: sepaDirectDebitRequest.billingAddress?.streetAddress,
extendedAddress: sepaDirectDebitRequest.billingAddress?.extendedAddress,
locality: sepaDirectDebitRequest.billingAddress?.locality,
region: sepaDirectDebitRequest.billingAddress?.region,
postalCode: sepaDirectDebitRequest.billingAddress?.postalCode,
countryCodeAlpha2: sepaDirectDebitRequest.billingAddress?.countryCodeAlpha2
)

self.billingAddress = sepaDirectDebitRequest.billingAddress.map { postalAddress in
let components = postalAddress.addressComponents()
return BillingAddress(
streetAddress: components["streetAddress"],
extendedAddress: components["extendedAddress"],
locality: components["locality"],
region: components["region"],
postalCode: components["postalCode"],
countryCodeAlpha2: components["countryCodeAlpha2"]
)
}
}
}

Expand Down
35 changes: 19 additions & 16 deletions UnitTests/BraintreeCoreTests/BTPostalAddress_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@ import BraintreeCore

class BTPostalAddress_Tests: XCTestCase {

func testAsParameters_setsAllProperties() {
let postalAddress = BTPostalAddress()
postalAddress.recipientName = "Jane Smith"
postalAddress.streetAddress = "555 Smith St."
postalAddress.extendedAddress = "#5"
postalAddress.locality = "Oakland"
postalAddress.region = "CA"
postalAddress.countryCodeAlpha2 = "US"
postalAddress.postalCode = "54321"
func testInitializer_setsAllProperties() {
let postalAddress = BTPostalAddress(
recipientName: "Jane Smith",
streetAddress: "555 Smith St.",
extendedAddress: "#5",
locality: "Oakland",
countryCodeAlpha2: "US",
postalCode: "54321",
region: "CA"
)

let addressComponents = postalAddress.addressComponents()

XCTAssertEqual(postalAddress.recipientName, "Jane Smith")
XCTAssertEqual(postalAddress.streetAddress, "555 Smith St.")
XCTAssertEqual(postalAddress.extendedAddress, "#5")
XCTAssertEqual(postalAddress.locality, "Oakland")
XCTAssertEqual(postalAddress.region, "CA")
XCTAssertEqual(postalAddress.countryCodeAlpha2, "US")
XCTAssertEqual(postalAddress.postalCode, "54321")
XCTAssertEqual(addressComponents["recipientName"], "Jane Smith")
XCTAssertEqual(addressComponents["streetAddress"], "555 Smith St.")
XCTAssertEqual(addressComponents["extendedAddress"], "#5")
XCTAssertEqual(addressComponents["locality"], "Oakland")
XCTAssertEqual(addressComponents["region"], "CA")
XCTAssertEqual(addressComponents["countryCodeAlpha2"], "US")
XCTAssertEqual(addressComponents["postalCode"], "54321")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,14 @@ class BTLocalPaymentClient_UnitTests: XCTestCase {
]
)

let postalAddress = BTPostalAddress()
postalAddress.countryCodeAlpha2 = "NL"
postalAddress.region = "CA"
postalAddress.postalCode = "2585 GJ"
postalAddress.streetAddress = "836486 of 22321 Park Lake"
postalAddress.extendedAddress = "#102"
postalAddress.locality = "Den Haag"
let postalAddress = BTPostalAddress(
streetAddress: "836486 of 22321 Park Lake",
extendedAddress: "#102",
locality: "Den Haag",
countryCodeAlpha2: "NL",
postalCode: "2585 GJ",
region: "CA"
)

let paymentRequest = BTLocalPaymentRequest(
paymentType: "ideal",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,15 @@ class BTPayPalCheckoutRequest_Tests: XCTestCase {
request.userAuthenticationEmail = "[email protected]"
request.userPhoneNumber = BTPayPalPhoneNumber(countryCode: "1", nationalNumber: "4087463271")

let shippingAddress = BTPostalAddress()
shippingAddress.streetAddress = "123 Main"
shippingAddress.extendedAddress = "Unit 1"
shippingAddress.locality = "Chicago"
shippingAddress.region = "IL"
shippingAddress.postalCode = "11111"
shippingAddress.countryCodeAlpha2 = "US"
shippingAddress.recipientName = "Recipient"
let shippingAddress = BTPostalAddress(
recipientName: "Recipient",
streetAddress: "123 Main",
extendedAddress: "Unit 1",
locality: "Chicago",
countryCodeAlpha2: "US",
postalCode: "11111",
region: "IL"
)
request.shippingAddressOverride = shippingAddress
request.isShippingAddressEditable = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,15 @@ class BTPayPalVaultRequest_Tests: XCTestCase {
let request = BTPayPalVaultRequest()
request.billingAgreementDescription = "desc"

let shippingAddress = BTPostalAddress()
shippingAddress.streetAddress = "123 Main"
shippingAddress.extendedAddress = "Unit 1"
shippingAddress.locality = "Chicago"
shippingAddress.region = "IL"
shippingAddress.postalCode = "11111"
shippingAddress.countryCodeAlpha2 = "US"
shippingAddress.recipientName = "Recipient"
let shippingAddress = BTPostalAddress(
recipientName: "Recipient",
streetAddress: "123 Main",
extendedAddress: "Unit 1",
locality: "Chicago",
countryCodeAlpha2: "US",
postalCode: "11111",
region: "IL"
)
request.shippingAddressOverride = shippingAddress
request.isShippingAddressEditable = true
request.offerCredit = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import AuthenticationServices

class BTSEPADirectDebitClient_Tests: XCTestCase {

var billingAddress = BTPostalAddress()
var billingAddress: BTPostalAddress!
var sepaDirectDebitRequest: BTSEPADirectDebitRequest!

var mockAPIClient : MockAPIClient = MockAPIClient(authorization: "development_client_key")
let authorization: String = "sandbox_9dbg82cq_dcpspy2brwdjr3qn"

override func setUp() {
mockAPIClient = MockAPIClient(authorization: authorization)

billingAddress.streetAddress = "Kantstraße 70"
billingAddress.extendedAddress = "#170"
billingAddress.locality = "Freistaat Sachsen"
billingAddress.region = "Annaberg-buchholz"
billingAddress.postalCode = "09456"
billingAddress.countryCodeAlpha2 = "FR"
billingAddress = BTPostalAddress(
streetAddress: "Kantstraße 70",
extendedAddress: "#170",
locality: "Freistaat Sachsen",
countryCodeAlpha2: "FR",
postalCode: "09456",
region: "Annaberg-buchholz"
)

sepaDirectDebitRequest = BTSEPADirectDebitRequest(
accountHolderName: "John Doe",
Expand Down
Loading
Loading