From 273e8a97c70b786a6b1b14eec9b3a7a68d964f40 Mon Sep 17 00:00:00 2001 From: warmkesselj <150195168+warmkesselj@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:24:11 -0800 Subject: [PATCH 1/6] Update heroku server endpoints (#1449) * update the environmentURL to point to the new heroku app servers * trigger 3DS UI test * Trigger CI --- Demo/Application/Base/Settings/BraintreeDemoSettings.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Demo/Application/Base/Settings/BraintreeDemoSettings.swift b/Demo/Application/Base/Settings/BraintreeDemoSettings.swift index 6b2546b06..008ecb30e 100644 --- a/Demo/Application/Base/Settings/BraintreeDemoSettings.swift +++ b/Demo/Application/Base/Settings/BraintreeDemoSettings.swift @@ -45,9 +45,9 @@ class BraintreeDemoSettings: NSObject { static var currentEnvironmentURLString: String { switch currentEnvironment { case .sandbox, .custom: - return "https://braintree-sample-merchant.herokuapp.com" + return "https://braintree-demo-merchant-63b7a2204f6e.herokuapp.com/" case .production: - return "https://executive-sample-merchant.herokuapp.com" + return "https://braintree-production-merchant-455d21469113.herokuapp.com/" } } From 5ecb18dc594019e5bf9292fd67871b8f15812fd1 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 5 Nov 2024 08:47:00 -0600 Subject: [PATCH 2/6] remove SDK_ERROR_CODES.md (#1455) --- SDK_ERROR_CODES.md | 139 --------------------------------------------- 1 file changed, 139 deletions(-) delete mode 100644 SDK_ERROR_CODES.md diff --git a/SDK_ERROR_CODES.md b/SDK_ERROR_CODES.md deleted file mode 100644 index 4a59bf9ba..000000000 --- a/SDK_ERROR_CODES.md +++ /dev/null @@ -1,139 +0,0 @@ -# Braintree iOS SDK Error Codes - -See below for a comprehensive list of error types and codes thrown by each feature module: - -* BraintreeAmericanExpress - | Error Type | Error Code | - |------------|------------| - | BTAmericanExpressError.unknown | 0 | - | BTAmericanExpressError.noRewardsData | 1 | - | BTAmericanExpressError.deallocated | 2 | -* BraintreeApplePay - | Error Type | Error Code | - |------------|------------| - | BTApplePayError.unknown | 0 | - | BTApplePayError.unsupported | 1 | - | BTApplePayError.noApplePayCardsReturned | 2 | - | BTApplePayError.failedToCreateNonce | 3 | -* BraintreeCard - | Error Type | Error Code | - |------------|------------| - | BTCardError.unknown | 0 | - | BTCardError.integration | 1 | - | BTCardError.customerInputInvalid | 2 | - | BTCardError.cardAlreadyExists | 3 | - | BTCardError.fetchConfigurationFailed | 4 | -* BraintreeCore - | Error Type | Error Code | - |------------|------------| - | BTAPIClientError.configurationUnavailable | 0 | - | BTAPIClientError.notAuthorized | 1 | - | BTAPIClientError.deallocated | 2 | - | BTClientTokenError.invalidAuthorizationFingerprint | 0 | - | BTClientTokenError.invalidConfigURL | 1 | - | BTClientTokenError.invalidFormat | 2 | - | BTClientTokenError.unsupportedVersion | 3 | - | BTClientTokenError.failedDecoding | 4 | - | BTHTTPError.unknown | 0 | - | BTHTTPError.responseContentTypeNotAcceptable | 1 | - | BTHTTPError.clientError | 2 | - | BTHTTPError.serverError | 3 | - | BTHTTPError.missingBaseURL | 4 | - | BTHTTPError.rateLimitError | 5 | - | BTHTTPError.dataNotFound | 6 | - | BTHTTPError.httpResponseInvalid | 7 | - | BTHTTPError.urlStringInvalid | 8 | - | BTHTTPError.clientApiURLInvalid | 9 | - | BTHTTPError.invalidAuthorizationFingerprint | 10 | - | BTHTTPError.serializationError | 11 | - | BTHTTPError.deallocated | 12 | - | BTJSONError.jsonSerializationFailure | 0 | - | BTJSONError.indexInvalid | 1 | - | BTJSONError.keyInvalid | 2 | -* BraintreeDataCollector - | Error Type | Error Code | - |------------|------------| - | BTDataCollectorError.unknown | 0 | - | BTDataCollectorError.jsonSerializationFailure | 1 | - | BTDataCollectorError.encodingFailure | 2 | -* BraintreeLocalPayment - | Error Type | Error Code | - |------------|------------| - | BTLocalPaymentError.unknown | 0 | - | BTLocalPaymentError.disabled | 1 | - | BTLocalPaymentError.appSwitchFailed | 2 | - | BTLocalPaymentError.integration | 3 | - | BTLocalPaymentError.noAccountData | 4 | - | BTLocalPaymentError.canceled | 5 | - | BTLocalPaymentError.failedToCreateNonce | 6 | - | BTLocalPaymentError.fetchConfigurationFailed | 7 | - | BTLocalPaymentError.missingRedirectURL | 8 | - | BTLocalPaymentError.missingReturnURL | 9 | - | BTLocalPaymentError.webSessionError | 10 | -* BraintreePayPal - | Error Type | Error Code | - |------------|------------| - | BTPayPalError.disabled | 0 | - | BTPayPalError.canceled | 1 | - | BTPayPalError.fetchConfigurationFailed | 2 | - | BTPayPalError.httpPostRequestError | 3 | - | BTPayPalError.invalidURL | 4 | - | BTPayPalError.asWebAuthenticationSessionURLInvalid | 5 | - | BTPayPalError.invalidURLAction | 6 | - | BTPayPalError.failedToCreateNonce | 7 | - | BTPayPalError.webSessionError | 8 | - | BTPayPalError.deallocated | 9 | -* BraintreePayPalNativeCheckout - | Error Type | Error Code | - |------------|------------| - | BTPayPalNativeCheckoutError.invalidRequest | 0 | - | BTPayPalNativeCheckoutError.fetchConfigurationFailed | 1 | - | BTPayPalNativeCheckoutError.payPalNotEnabled | 2 | - | BTPayPalNativeCheckoutError.payPalClientIDNotFound | 3 | - | BTPayPalNativeCheckoutError.invalidEnvironment | 4 | - | BTPayPalNativeCheckoutError.orderCreationFailed | 5 | - | BTPayPalNativeCheckoutError.canceled | 6 | - | BTPayPalNativeCheckoutError.checkoutSDKFailed | 7 | - | BTPayPalNativeCheckoutError.tokenizationFailed | 8 | - | BTPayPalNativeCheckoutError.parsingTokenizationResultFailed | 9 | - | BTPayPalNativeCheckoutError.invalidJSONResponse | 10 | - | BTPayPalNativeCheckoutError.deallocated | 11 | -* BraintreeSEPADirectDebit - | Error Type | Error Code | - |------------|------------| - | BTSEPADirectDebitError.unknown | 0 | - | BTSEPADirectDebitError.webFlowCanceled | 1 | - | BTSEPADirectDebitError.resultURLInvalid | 2 | - | BTSEPADirectDebitError.resultReturnedNil | 3 | - | BTSEPADirectDebitError.approvalURLInvalid | 4 | - | BTSEPADirectDebitError.authenticationResultNil | 5 | - | BTSEPADirectDebitError.noBodyReturned | 6 | - | BTSEPADirectDebitError.failedToCreateNonce | 7 | - | BTSEPADirectDebitError.deallocated | 8 | -* BraintreeThreeDSecure - | Error Type | Error Code | - |------------|------------| - | BTThreeDSecureError.unknown | 0 | - | BTThreeDSecureError.failedLookup | 1 | - | BTThreeDSecureError.failedAuthentication | 2 | - | BTThreeDSecureError.configuration | 3 | - | BTThreeDSecureError.noBodyReturned | 4 | - | BTThreeDSecureError.canceled | 5 | - | BTThreeDSecureError.invalidAPIClient | 6 | - | BTThreeDSecureError.jsonSerializationFailure | 7 | - | BTThreeDSecureError.deallocated | 8 | -* BraintreeVenmo - | Error Type | Error Code | - |------------|------------| - | BTVenmoAppSwitchError.returnURLError | 0 | - | BTVenmoError.unknown | 0 | - | BTVenmoError.disabled | 1 | - | BTVenmoError.appNotAvailable | 2 | - | BTVenmoError.bundleDisplayNameMissing | 3 | - | BTVenmoError.appSwitchFailed | 4 | - | BTVenmoError.invalidReturnURL | 5 | - | BTVenmoError.invalidBodyReturned | 6 | - | BTVenmoError.invalidRedirectURL | 7 | - | BTVenmoError.fetchConfigurationFailed | 8 | - | BTVenmoError.enrichedCustomerDataDisabled | 9 | - | BTVenmoError.canceled | 10 | \ No newline at end of file From cd41610afa9e531a229d0bd973620f0a0e938c37 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Fri, 8 Nov 2024 08:23:07 -0600 Subject: [PATCH 3/6] Bump GraphQL API Version (#1457) * bump graphQLVersion to todays date * update unit test * update CHANGELOG --- CHANGELOG.md | 13 +++++++------ Sources/BraintreeCore/BTCoreConstants.swift | 2 +- .../BraintreeCoreTests/BTGraphQLHTTP_Tests.swift | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 860f79999..3b57308ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,15 @@ ## unreleased (v7) * Breaking Changes * Bump minimum supported deployment target to iOS 16+ + * `countryCodeAlpha2` now returns a 2 character country code instead of a 3 character country code * BraintreePayPalNativeCheckout * Remove entire PayPal Native Checkout module -* BraintreeVenmo - * Update `BTVenmoRequest` to make all properties accessible on the initializer only vs via the dot syntax. -* BraintreeSEPADirectDebit - * Update `BTSEPADirectDebitRequest` to make all properties accessible on the initializer only vs via the dot syntax. -* BraintreeLocalPayment - * Update `BTLocalPaymentRequest` to make all properties accessible on the initializer only vs via the dot syntax. + * BraintreeVenmo + * Update `BTVenmoRequest` to make all properties accessible on the initializer only vs via the dot syntax. + * BraintreeSEPADirectDebit + * Update `BTSEPADirectDebitRequest` to make all properties accessible on the initializer only vs via the dot syntax. + * BraintreeLocalPayment + * Update `BTLocalPaymentRequest` to make all properties accessible on the initializer only vs via the dot syntax. ## unreleased * BraintreePayPal diff --git a/Sources/BraintreeCore/BTCoreConstants.swift b/Sources/BraintreeCore/BTCoreConstants.swift index aaa8eb3a2..97fb160d6 100644 --- a/Sources/BraintreeCore/BTCoreConstants.swift +++ b/Sources/BraintreeCore/BTCoreConstants.swift @@ -18,7 +18,7 @@ import Foundation static let apiVersion: String = "2016-10-07" - static let graphQLVersion: String = "2018-03-06" + static let graphQLVersion: String = "2024-11-05" // swiftlint:disable force_unwrapping static let payPalProductionURL = URL(string: "https://api.paypal.com")! diff --git a/UnitTests/BraintreeCoreTests/BTGraphQLHTTP_Tests.swift b/UnitTests/BraintreeCoreTests/BTGraphQLHTTP_Tests.swift index 288b7c843..06f330602 100644 --- a/UnitTests/BraintreeCoreTests/BTGraphQLHTTP_Tests.swift +++ b/UnitTests/BraintreeCoreTests/BTGraphQLHTTP_Tests.swift @@ -175,7 +175,7 @@ final class BTGraphQLHTTP_Tests: XCTestCase { http?.post("", configuration: fakeConfiguration, parameters: nil) { body, _, _ in let httpRequest = BTHTTPTestProtocol.parseRequestFromTestResponseBody(body!) let requestHeaders = httpRequest.allHTTPHeaderFields - XCTAssertEqual(requestHeaders!["Braintree-Version"], "2018-03-06") + XCTAssertEqual(requestHeaders!["Braintree-Version"], "2024-11-05") expectation.fulfill() } From 7334e5bc969189e2c85fd0108c1682689c15fd72 Mon Sep 17 00:00:00 2001 From: Rich Herrera Date: Fri, 8 Nov 2024 09:22:20 -0600 Subject: [PATCH 4/6] Remove MXO testable reference (#1460) --- .../xcshareddata/xcschemes/Demo.xcscheme | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme index 2f905023b..334010021 100644 --- a/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme +++ b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme @@ -230,17 +230,6 @@ ReferencedContainer = "container:../Braintree.xcodeproj"> - - - - From 3fba4f1697b1c504fa7b4678eeb14d1821e488f3 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 12 Nov 2024 15:49:37 -0600 Subject: [PATCH 5/6] [v7] Remove `BTPayPalVaultBaseRequest` (#1462) * remove BTPayPalVaultBaseRequest * cleanup BTPayPalVaultRequest to subclass BTPayPalRequest --- Braintree.xcodeproj/project.pbxproj | 28 ---------- .../BTPayPalVaultBaseRequest.swift | 56 ------------------- .../BTPayPalVaultRequest.swift | 38 ++++++++++--- 3 files changed, 31 insertions(+), 91 deletions(-) delete mode 100644 Sources/BraintreePayPal/BTPayPalVaultBaseRequest.swift diff --git a/Braintree.xcodeproj/project.pbxproj b/Braintree.xcodeproj/project.pbxproj index 46d51f5f8..bc7ee97d0 100644 --- a/Braintree.xcodeproj/project.pbxproj +++ b/Braintree.xcodeproj/project.pbxproj @@ -226,7 +226,6 @@ BE349113294B798300D2CF68 /* BTPayPalRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE349112294B798300D2CF68 /* BTPayPalRequest.swift */; }; BE48CE4829D5DDA600F0825C /* BTThreeDSecureV2TextBoxCustomization.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE82E74029C4A1330059FE97 /* BTThreeDSecureV2TextBoxCustomization.swift */; }; BE549F112BF5445F00B6F441 /* BTPayPalReturnURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6BC22D2BA9CFFC00C3E321 /* BTPayPalReturnURL.swift */; }; - BE549F122BF5449E00B6F441 /* BTPayPalVaultBaseRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6BC22B2BA9C67600C3E321 /* BTPayPalVaultBaseRequest.swift */; }; BE549F142BF6576300B6F441 /* BTAnalyticsEventsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE549F132BF6576300B6F441 /* BTAnalyticsEventsStorage.swift */; }; BE54C0332912B68E009C6CEE /* BTHTTP_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE54C0322912B68E009C6CEE /* BTHTTP_Tests.swift */; }; BE54C0352912B6BC009C6CEE /* BTHTTPTestProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE54C0342912B6BC009C6CEE /* BTHTTPTestProtocol.swift */; }; @@ -937,7 +936,6 @@ BE698EA328AD2C10001D9B10 /* BTCoreConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTCoreConstants.swift; sourceTree = ""; }; BE698EA528B3CDAD001D9B10 /* ConfigurationCache_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationCache_Tests.swift; sourceTree = ""; }; BE698EAA28B50F41001D9B10 /* BTClientToken_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTClientToken_Tests.swift; sourceTree = ""; }; - BE6BC22B2BA9C67600C3E321 /* BTPayPalVaultBaseRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalVaultBaseRequest.swift; sourceTree = ""; }; BE6BC22D2BA9CFFC00C3E321 /* BTPayPalReturnURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalReturnURL.swift; sourceTree = ""; }; BE70A962284FA3F000F6D3F7 /* BTDataCollectorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTDataCollectorError.swift; sourceTree = ""; }; BE70A964284FA9DE00F6D3F7 /* MockBTDataCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBTDataCollector.swift; sourceTree = ""; }; @@ -1086,13 +1084,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9CE51798282D54030013C740 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; A76D7BFC1BB1CAB00000FA6A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1309,7 +1300,6 @@ 57D9436D2968A8080079EAB1 /* BTPayPalLocaleCode.swift */, BE349112294B798300D2CF68 /* BTPayPalRequest.swift */, BE6BC22D2BA9CFFC00C3E321 /* BTPayPalReturnURL.swift */, - BE6BC22B2BA9C67600C3E321 /* BTPayPalVaultBaseRequest.swift */, BE349110294B77E100D2CF68 /* BTPayPalVaultRequest.swift */, 62A659A32B98CB23008DFD67 /* PrivacyInfo.xcprivacy */, 807D22F32C29ADA8009FFEA4 /* RecurringBillingMetadata */, @@ -2659,9 +2649,6 @@ 8046983D2B27C5530090878E = { CreatedOnToolsVersion = 15.0.1; }; - 9CE5179A282D54030013C740 = { - CreatedOnToolsVersion = 13.2.1; - }; A76D7BFF1BB1CAB00000FA6A = { CreatedOnToolsVersion = 7.0; LastSwiftMigration = 1340; @@ -2821,13 +2808,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9CE51799282D54030013C740 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; A76D7BFE1BB1CAB00000FA6A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -3120,7 +3100,6 @@ BE349113294B798300D2CF68 /* BTPayPalRequest.swift in Sources */, BE549F112BF5445F00B6F441 /* BTPayPalReturnURL.swift in Sources */, 57544F5C295254A500DEB7B0 /* BTJSON+PayPal.swift in Sources */, - BE549F122BF5449E00B6F441 /* BTPayPalVaultBaseRequest.swift in Sources */, 3B7A261129C0CAA40087059D /* BTPayPalAnalytics.swift in Sources */, BE8E5CEF294B6937001BF017 /* BTPayPalCheckoutRequest.swift in Sources */, 807D22F02C29A93A009FFEA4 /* BTPayPalBillingCycle.swift in Sources */, @@ -3221,13 +3200,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9CE51797282D54030013C740 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; A76D7BFB1BB1CAB00000FA6A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; diff --git a/Sources/BraintreePayPal/BTPayPalVaultBaseRequest.swift b/Sources/BraintreePayPal/BTPayPalVaultBaseRequest.swift deleted file mode 100644 index 99c31e82c..000000000 --- a/Sources/BraintreePayPal/BTPayPalVaultBaseRequest.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Foundation - -#if canImport(BraintreeCore) -import BraintreeCore -#endif - -/// Options for the PayPal Vault flow. -@objcMembers open class BTPayPalVaultBaseRequest: BTPayPalRequest { - - // MARK: - Public Properties - - /// Optional: Offers PayPal Credit if the customer qualifies. Defaults to `false`. - public var offerCredit: Bool - - // MARK: - Initializer - - /// Initializes a PayPal Native Vault request - /// - Parameters: - /// - offerCredit: Optional: Offers PayPal Credit if the customer qualifies. Defaults to `false`. - public init(offerCredit: Bool = false) { - self.offerCredit = offerCredit - - super.init(hermesPath: "v1/paypal_hermes/setup_billing_agreement", paymentType: .vault) - } - - // MARK: Internal Methods - - override func parameters( - with configuration: BTConfiguration, - universalLink: URL? = nil, - isPayPalAppInstalled: Bool = false - ) -> [String: Any] { - let baseParameters = super.parameters(with: configuration) - var vaultParameters: [String: Any] = ["offer_paypal_credit": offerCredit] - - if let billingAgreementDescription { - vaultParameters["description"] = billingAgreementDescription - } - - if let shippingAddressOverride { - let shippingAddressParameters: [String: String?] = [ - "line1": shippingAddressOverride.streetAddress, - "line2": shippingAddressOverride.extendedAddress, - "city": shippingAddressOverride.locality, - "state": shippingAddressOverride.region, - "postal_code": shippingAddressOverride.postalCode, - "country_code": shippingAddressOverride.countryCodeAlpha2, - "recipient_name": shippingAddressOverride.recipientName - ] - - vaultParameters["shipping_address"] = shippingAddressParameters - } - - return baseParameters.merging(vaultParameters) { $1 } - } -} diff --git a/Sources/BraintreePayPal/BTPayPalVaultRequest.swift b/Sources/BraintreePayPal/BTPayPalVaultRequest.swift index a39cee1cd..ca33fe35a 100644 --- a/Sources/BraintreePayPal/BTPayPalVaultRequest.swift +++ b/Sources/BraintreePayPal/BTPayPalVaultRequest.swift @@ -5,13 +5,16 @@ import BraintreeCore #endif /// Options for the PayPal Vault flow. -@objcMembers public class BTPayPalVaultRequest: BTPayPalVaultBaseRequest { +@objcMembers public class BTPayPalVaultRequest: BTPayPalRequest { // MARK: - Public Properties /// Optional: User email to initiate a quicker authentication flow in cases where the user has a PayPal Account with the same email. public var userAuthenticationEmail: String? + /// Optional: Offers PayPal Credit if the customer qualifies. Defaults to `false`. + public var offerCredit: Bool + // MARK: - Internal Properties /// Optional: Used to determine if the customer will use the PayPal app switch flow. @@ -55,10 +58,11 @@ import BraintreeCore recurringBillingPlanType: BTPayPalRecurringBillingPlanType? = nil, userAuthenticationEmail: String? = nil ) { + self.offerCredit = offerCredit self.recurringBillingDetails = recurringBillingDetails self.recurringBillingPlanType = recurringBillingPlanType self.userAuthenticationEmail = userAuthenticationEmail - super.init(offerCredit: offerCredit) + super.init(hermesPath: "v1/paypal_hermes/setup_billing_agreement", paymentType: .vault) } public override func parameters( @@ -68,7 +72,7 @@ import BraintreeCore ) -> [String: Any] { var baseParameters = super.parameters(with: configuration) - if let userAuthenticationEmail { + if let userAuthenticationEmail, !userAuthenticationEmail.isEmpty { baseParameters["payer_email"] = userAuthenticationEmail } @@ -79,18 +83,38 @@ import BraintreeCore "os_type": UIDevice.current.systemName, "merchant_app_return_url": universalLink.absoluteString ] - + return baseParameters.merging(appSwitchParameters) { $1 } } - + if let recurringBillingPlanType { baseParameters["plan_type"] = recurringBillingPlanType.rawValue } - + if let recurringBillingDetails { baseParameters["plan_metadata"] = recurringBillingDetails.parameters() } - return baseParameters + var vaultParameters: [String: Any] = ["offer_paypal_credit": offerCredit] + + if let billingAgreementDescription { + vaultParameters["description"] = billingAgreementDescription + } + + if let shippingAddressOverride { + let shippingAddressParameters: [String: String?] = [ + "line1": shippingAddressOverride.streetAddress, + "line2": shippingAddressOverride.extendedAddress, + "city": shippingAddressOverride.locality, + "state": shippingAddressOverride.region, + "postal_code": shippingAddressOverride.postalCode, + "country_code": shippingAddressOverride.countryCodeAlpha2, + "recipient_name": shippingAddressOverride.recipientName + ] + + vaultParameters["shipping_address"] = shippingAddressParameters + } + + return baseParameters.merging(vaultParameters) { $1 } } } From 38672686086503c0ff47d1ff3b44ee91ea368f0d Mon Sep 17 00:00:00 2001 From: Stephanie <127455800+stechiu@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:03:53 -0800 Subject: [PATCH 6/6] Removed Venmo `fallbacktoWeb` (#1434) * Removed Venmo `fallbacktoWeb` * Addressed PR comment * Updated CHANGELOG * Removed `LinkType` and `urlSchemeURL()` * Added link type back to PayPal * Fixed `linkType` error * Removed Venmo UI tests. Updated docstrings * Updated CHANGELOG * Revert "Merge branch 'v7' of https://github.com/braintree/braintree_ios into v7-venmo-universal-link" This reverts commit 438dfc7af31d42a040bd55957f3e95ce1840f79e, reversing changes made to 1a24560d78b449a4bcde006d0f4d26cbd17cfb25. * Revert "Revert "Merge branch 'v7' of https://github.com/braintree/braintree_ios into v7-venmo-universal-link"" This reverts commit 2d0d7e015565c0c7f7fe46cc36b819794a09cc5b. * Reset v7 files * Removed duplicate LinkType file * Removed unused `return` * Reverted cocoapods version * Updated migration guide. Added `TODO` --- Braintree.xcodeproj/project.pbxproj | 8 +-- CHANGELOG.md | 1 + .../Features/VenmoViewController.swift | 7 +- .../Venmo UI Tests/Venmo_UITests.swift | 44 +----------- .../BraintreeCore/Analytics/LinkType.swift | 2 +- Sources/BraintreePayPal/BTPayPalClient.swift | 2 +- .../BTVenmoAppSwitchRedirectURL.swift | 7 -- Sources/BraintreeVenmo/BTVenmoClient.swift | 51 +++---------- Sources/BraintreeVenmo/BTVenmoRequest.swift | 8 +-- .../BTVenmoAppSwitchRedirectURL_Tests.swift | 22 ------ .../BTVenmoClient_Tests.swift | 72 ++----------------- .../BTVenmoRequest_Tests.swift | 5 -- V7_MIGRATION.md | 4 +- 13 files changed, 30 insertions(+), 203 deletions(-) diff --git a/Braintree.xcodeproj/project.pbxproj b/Braintree.xcodeproj/project.pbxproj index bc7ee97d0..bfc0a7c5a 100644 --- a/Braintree.xcodeproj/project.pbxproj +++ b/Braintree.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 04ECD8A02CC9CB1E000329EC /* LinkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ECD89F2CC9CB1A000329EC /* LinkType.swift */; }; 0917F6E42A27BDC700ACED2E /* BTVenmoLineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C6B2529CCDCEB00912863 /* BTVenmoLineItem.swift */; }; 09357DCB2A2FBEC10096D449 /* BTVenmoLineItem_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09357DCA2A2FBEC10096D449 /* BTVenmoLineItem_Tests.swift */; }; 1FEB89E614CB6BF0B9858EE4 /* Pods_Tests_IntegrationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 85BD589D380436A0C9D1DEC1 /* Pods_Tests_IntegrationTests.framework */; }; @@ -313,7 +314,6 @@ BED00CAE28A5419900D74AEC /* BTBinData.swift in Sources */ = {isa = PBXBuildFile; fileRef = BED00CAD28A5419900D74AEC /* BTBinData.swift */; }; BED00CB028A579D700D74AEC /* BTClientToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = BED00CAF28A579D700D74AEC /* BTClientToken.swift */; }; BED00CB228A57AD400D74AEC /* BTClientTokenError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BED00CB128A57AD400D74AEC /* BTClientTokenError.swift */; }; - BED3A2C62C5D74B20034D9A6 /* LinkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BED3A2C52C5D74AC0034D9A6 /* LinkType.swift */; }; BED7493628579BAC0074C818 /* BTURLUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BED7493528579BAC0074C818 /* BTURLUtils.swift */; }; BEDA91A028EDDE64007441D9 /* FakeAnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEDA919F28EDDE64007441D9 /* FakeAnalyticsService.swift */; }; BEDB820229B109EE00075AF3 /* BTApplePayAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEDB820129B109EE00075AF3 /* BTApplePayAnalytics.swift */; }; @@ -677,6 +677,7 @@ 035A59D91EA5DE97002960C8 /* BTLocalPaymentClient_UnitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BTLocalPaymentClient_UnitTests.swift; sourceTree = ""; }; 039A8BD91F9E993500D607E7 /* BTAmericanExpressRewardsBalance_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTAmericanExpressRewardsBalance_Tests.swift; sourceTree = ""; }; 03F921C1200EBB200076CD80 /* BTThreeDSecurePostalAddress_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecurePostalAddress_Tests.swift; sourceTree = ""; }; + 04ECD89F2CC9CB1A000329EC /* LinkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkType.swift; sourceTree = ""; }; 09357DCA2A2FBEC10096D449 /* BTVenmoLineItem_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoLineItem_Tests.swift; sourceTree = ""; }; 096C6B2529CCDCEB00912863 /* BTVenmoLineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoLineItem.swift; sourceTree = ""; }; 162174E1192D9220008DC35D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -996,7 +997,6 @@ BED00CAD28A5419900D74AEC /* BTBinData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTBinData.swift; sourceTree = ""; }; BED00CAF28A579D700D74AEC /* BTClientToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTClientToken.swift; sourceTree = ""; }; BED00CB128A57AD400D74AEC /* BTClientTokenError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTClientTokenError.swift; sourceTree = ""; }; - BED3A2C52C5D74AC0034D9A6 /* LinkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkType.swift; sourceTree = ""; }; BED7493528579BAC0074C818 /* BTURLUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTURLUtils.swift; sourceTree = ""; }; BEDA919F28EDDE64007441D9 /* FakeAnalyticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeAnalyticsService.swift; sourceTree = ""; }; BEDB820129B109EE00075AF3 /* BTApplePayAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTApplePayAnalytics.swift; sourceTree = ""; }; @@ -1554,13 +1554,13 @@ 80F4F4D529F8A628003EACB1 /* Analytics */ = { isa = PBXGroup; children = ( + 04ECD89F2CC9CB1A000329EC /* LinkType.swift */, 808E4A152C581CD40006A737 /* AnalyticsSendable.swift */, BE549F132BF6576300B6F441 /* BTAnalyticsEventsStorage.swift */, BEE2E4E329007FF100C03FDD /* BTAnalyticsService.swift */, BEE2E4E5290080BD00C03FDD /* BTAnalyticsServiceError.swift */, BEF388C02BE52CD2000965C8 /* BTCoreAnalytics.swift */, 800E78C329E0DD5300D1B0FC /* FPTIBatchData.swift */, - BED3A2C52C5D74AC0034D9A6 /* LinkType.swift */, 457D7FC72C29CEC300EF6523 /* RepeatingTimer.swift */, ); path = Analytics; @@ -3123,6 +3123,7 @@ files = ( BE9FB82D28984ADE00D6FE2F /* BTPaymentMethodNonceParser.swift in Sources */, BED00CAE28A5419900D74AEC /* BTBinData.swift in Sources */, + 04ECD8A02CC9CB1E000329EC /* LinkType.swift in Sources */, BE549F142BF6576300B6F441 /* BTAnalyticsEventsStorage.swift in Sources */, BC17F9BE28D25054004B18CC /* BTGraphQLErrorNode.swift in Sources */, 800E78C429E0DD5300D1B0FC /* FPTIBatchData.swift in Sources */, @@ -3159,7 +3160,6 @@ BE63A3A7288F3026001936DA /* BTPostalAddress.swift in Sources */, BE2F98D028A2BCCD008EF189 /* BTConfiguration.swift in Sources */, 804DC45D2B2D08FF00F17A15 /* BTConfigurationRequest.swift in Sources */, - BED3A2C62C5D74B20034D9A6 /* LinkType.swift in Sources */, BED00CB228A57AD400D74AEC /* BTClientTokenError.swift in Sources */, BE24C67328E73E810067B11A /* BTAPIClientHTTPType.swift in Sources */, 457D7FC82C29CEC300EF6523 /* RepeatingTimer.swift in Sources */, diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b57308ef..3fffdbca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Remove entire PayPal Native Checkout module * BraintreeVenmo * Update `BTVenmoRequest` to make all properties accessible on the initializer only vs via the dot syntax. + * Remove `fallbacktoWeb` property from `BTVenmoRequest`. All Venmo flows will now use universal links to switch to the Venmo app or fallback to the web flow if the Venmo app is not installed * BraintreeSEPADirectDebit * Update `BTSEPADirectDebitRequest` to make all properties accessible on the initializer only vs via the dot syntax. * BraintreeLocalPayment diff --git a/Demo/Application/Features/VenmoViewController.swift b/Demo/Application/Features/VenmoViewController.swift index aab95cb0b..24b6494a0 100644 --- a/Demo/Application/Features/VenmoViewController.swift +++ b/Demo/Application/Features/VenmoViewController.swift @@ -6,7 +6,6 @@ class VenmoViewController: PaymentButtonBaseViewController { // swiftlint:disable:next implicitly_unwrapped_optional var venmoClient: BTVenmoClient! - let webFallbackToggle = Toggle(title: "Enable Web Fallback") let vaultToggle = Toggle(title: "Vault") override func viewDidLoad() { @@ -18,7 +17,7 @@ class VenmoViewController: PaymentButtonBaseViewController { override func createPaymentButton() -> UIView { let venmoButton = createButton(title: "Venmo", action: #selector(tappedVenmo)) - let stackView = UIStackView(arrangedSubviews: [webFallbackToggle, vaultToggle, venmoButton]) + let stackView = UIStackView(arrangedSubviews: [vaultToggle, venmoButton]) stackView.axis = .vertical stackView.spacing = 15 stackView.alignment = .fill @@ -31,12 +30,10 @@ class VenmoViewController: PaymentButtonBaseViewController { @objc func tappedVenmo() { self.progressBlock("Tapped Venmo - initiating Venmo auth") - let isWebFallbackEnabled = webFallbackToggle.isOn let isVaultingEnabled = vaultToggle.isOn let venmoRequest = BTVenmoRequest( paymentMethodUsage: .multiUse, - vault: isVaultingEnabled, - fallbackToWeb: isWebFallbackEnabled + vault: isVaultingEnabled ) Task { diff --git a/Demo/UI Tests/Venmo UI Tests/Venmo_UITests.swift b/Demo/UI Tests/Venmo UI Tests/Venmo_UITests.swift index 265e3cef3..74e5a4614 100644 --- a/Demo/UI Tests/Venmo UI Tests/Venmo_UITests.swift +++ b/Demo/UI Tests/Venmo UI Tests/Venmo_UITests.swift @@ -4,60 +4,18 @@ class Venmo_UITests: XCTestCase { // swiftlint:disable implicitly_unwrapped_optional var demoApp: XCUIApplication! - var mockVenmo: XCUIApplication! // swiftlint:enable implicitly_unwrapped_optional override func setUp() { super.setUp() continueAfterFailure = false - mockVenmo = XCUIApplication(bundleIdentifier: "com.braintreepayments.MockVenmo") - mockVenmo.activate() - demoApp = XCUIApplication(bundleIdentifier: "com.braintreepayments.Demo") demoApp.launchArguments.append("-EnvironmentSandbox") demoApp.launchArguments.append("-ClientToken") demoApp.launchArguments.append("-Integration:VenmoViewController") demoApp.launch() } - - func testTokenizeVenmo_whenSignInSuccessfulWithPaymentContext_returnsNonce() { - waitForElementToBeHittable(demoApp.buttons["Venmo"]) - demoApp.buttons["Venmo"].tap() - - waitForElementToBeHittable(mockVenmo.buttons["SUCCESS WITH PAYMENT CONTEXT"]) - mockVenmo.buttons["SUCCESS WITH PAYMENT CONTEXT"].tap() - - XCTAssertTrue(demoApp.buttons["Got a nonce. Tap to make a transaction."].waitForExistence(timeout: 30)) - } - - func testTokenizeVenmo_whenSignInSuccessfulWithoutPaymentContext_returnsNonce() { - waitForElementToBeHittable(demoApp.buttons["Venmo"]) - demoApp.buttons["Venmo"].tap() - - waitForElementToBeHittable(mockVenmo.buttons["SUCCESS WITHOUT PAYMENT CONTEXT"]) - mockVenmo.buttons["SUCCESS WITHOUT PAYMENT CONTEXT"].tap() - - XCTAssertTrue(demoApp.buttons["Got a nonce. Tap to make a transaction."].waitForExistence(timeout: 30)) - } - func testTokenizeVenmo_whenErrorOccurs_returnsError() { - waitForElementToBeHittable(demoApp.buttons["Venmo"]) - demoApp.buttons["Venmo"].tap() - - waitForElementToBeHittable(mockVenmo.buttons["ERROR"]) - mockVenmo.buttons["ERROR"].tap() - - XCTAssertTrue(demoApp.buttons["An error occurred during the Venmo flow"].waitForExistence(timeout: 30)) - } - - func testTokenizeVenmo_whenUserCancels_returnsCancel() { - waitForElementToBeHittable(demoApp.buttons["Venmo"]) - demoApp.buttons["Venmo"].tap() - - waitForElementToBeHittable(mockVenmo.buttons["Cancel"]) - mockVenmo.buttons["Cancel"].tap() - - XCTAssertTrue(demoApp.buttons["Canceled 🔰"].waitForExistence(timeout: 30)) - } + // TODO: Add UI test } diff --git a/Sources/BraintreeCore/Analytics/LinkType.swift b/Sources/BraintreeCore/Analytics/LinkType.swift index 0fb70292c..f49426236 100644 --- a/Sources/BraintreeCore/Analytics/LinkType.swift +++ b/Sources/BraintreeCore/Analytics/LinkType.swift @@ -1,4 +1,4 @@ -/// Used to describe the link type for analytics +/// Used to describe the type of link that directs users to a specific URL for analytics /// :nodoc: This class is exposed for internal Braintree use only. Do not use. It is not covered by Semantic Versioning and may change or be removed at any time. @_documentation(visibility: private) public enum LinkType: String { diff --git a/Sources/BraintreePayPal/BTPayPalClient.swift b/Sources/BraintreePayPal/BTPayPalClient.swift index 0362ed159..629c54240 100644 --- a/Sources/BraintreePayPal/BTPayPalClient.swift +++ b/Sources/BraintreePayPal/BTPayPalClient.swift @@ -62,7 +62,7 @@ import BraintreeDataCollector /// Used for analytics purposes, to determine if brower-presentation event is associated with a locally cached, or remotely fetched `BTConfiguration` private var isConfigFromCache: Bool? - /// Used for sending the type of flow, universal vs deeplink to FPTI + /// Used for indicating the type of URL link, universal link or deep link, that directs users to a specific URL to FPTI private var linkType: LinkType? // MARK: - Initializer diff --git a/Sources/BraintreeVenmo/BTVenmoAppSwitchRedirectURL.swift b/Sources/BraintreeVenmo/BTVenmoAppSwitchRedirectURL.swift index b9d561e06..c02ad1e2a 100644 --- a/Sources/BraintreeVenmo/BTVenmoAppSwitchRedirectURL.swift +++ b/Sources/BraintreeVenmo/BTVenmoAppSwitchRedirectURL.swift @@ -75,13 +75,6 @@ struct BTVenmoAppSwitchRedirectURL { return urlComponent.url } - func urlSchemeURL() -> URL? { - var components = BTVenmoAppSwitchRedirectURL.appSwitchBaseURLComponents() - components.percentEncodedQuery = BTURLUtils.queryString(from: queryParameters as NSDictionary) - - return components.url - } - // MARK: - Private Helper Methods private func constructRedirectURL(with scheme: String, result: String) -> URL? { diff --git a/Sources/BraintreeVenmo/BTVenmoClient.swift b/Sources/BraintreeVenmo/BTVenmoClient.swift index 50f677676..873db989f 100644 --- a/Sources/BraintreeVenmo/BTVenmoClient.swift +++ b/Sources/BraintreeVenmo/BTVenmoClient.swift @@ -67,8 +67,7 @@ import BraintreeCore @objc(tokenizeWithVenmoRequest:completion:) // swiftlint:disable:next function_body_length cyclomatic_complexity public func tokenize(_ request: BTVenmoRequest, completion: @escaping (BTVenmoAccountNonce?, Error?) -> Void) { - linkType = request.fallbackToWeb ? .universal : .deeplink - apiClient.sendAnalyticsEvent(BTVenmoAnalytics.tokenizeStarted, isVaultRequest: shouldVault, linkType: linkType) + apiClient.sendAnalyticsEvent(BTVenmoAnalytics.tokenizeStarted, isVaultRequest: shouldVault) let returnURLScheme = BTAppContextSwitcher.sharedInstance.returnURLScheme if returnURLScheme.isEmpty { @@ -100,7 +99,7 @@ import BraintreeCore } do { - _ = try self.verifyAppSwitch(with: configuration, fallbackToWeb: request.fallbackToWeb) + _ = try self.verifyAppSwitch(with: configuration) } catch { self.notifyFailure(with: error, completion: completion) return @@ -160,24 +159,15 @@ import BraintreeCore environment: configuration.venmoEnvironment ) - if request.fallbackToWeb { - guard let universalLinksURL = appSwitchURL.universalLinksURL() else { - self.notifyFailure( - with: BTVenmoError.invalidReturnURL("Universal links URL cannot be nil"), - completion: completion - ) - return - } - - self.startVenmoFlow(with: universalLinksURL, shouldVault: request.vault, completion: completion) - } else { - guard let urlSchemeURL = appSwitchURL.urlSchemeURL() else { - self.notifyFailure(with: BTVenmoError.invalidReturnURL("App switch URL cannot be nil"), completion: completion) - return - } - - self.startVenmoFlow(with: urlSchemeURL, shouldVault: request.vault, completion: completion) + guard let universalLinksURL = appSwitchURL.universalLinksURL() else { + self.notifyFailure( + with: BTVenmoError.invalidReturnURL("Universal links URL cannot be nil"), + completion: completion + ) + return } + + self.startVenmoFlow(with: universalLinksURL, shouldVault: request.vault, completion: completion) } catch { self.notifyFailure(with: error, completion: completion) return @@ -202,15 +192,6 @@ import BraintreeCore } } - /// Returns true if the proper Venmo app is installed and configured correctly, returns false otherwise. - @objc public func isVenmoAppInstalled() -> Bool { - guard let appSwitchURL = BTVenmoAppSwitchRedirectURL.baseAppSwitchURL else { - return false - } - - return application.canOpenURL(appSwitchURL) - } - /// Switches to the App Store to download the Venmo application. @objc public func openVenmoAppPageInAppStore() { application.open(appStoreURL, completionHandler: nil) @@ -291,7 +272,6 @@ import BraintreeCore apiClient.sendAnalyticsEvent( BTVenmoAnalytics.handleReturnStarted, isVaultRequest: shouldVault, - linkType: linkType, payPalContextID: payPalContextID ) guard let cleanedURL = URL(string: url.absoluteString.replacingOccurrences(of: "#", with: "?")) else { @@ -394,7 +374,6 @@ import BraintreeCore apiClient.sendAnalyticsEvent( BTVenmoAnalytics.appSwitchSucceeded, isVaultRequest: shouldVault, - linkType: linkType, payPalContextID: payPalContextID, appSwitchURL: appSwitchURL ) @@ -443,16 +422,11 @@ import BraintreeCore // MARK: - App Switch Methods - func verifyAppSwitch(with configuration: BTConfiguration, fallbackToWeb: Bool) throws -> Bool { + func verifyAppSwitch(with configuration: BTConfiguration) throws -> Bool { if !configuration.isVenmoEnabled { throw BTVenmoError.disabled } - - if !fallbackToWeb && !isVenmoAppInstalled() { - throw BTVenmoError.appNotAvailable - } - guard bundle.object(forInfoDictionaryKey: "CFBundleDisplayName") != nil else { throw BTVenmoError.bundleDisplayNameMissing } @@ -469,7 +443,6 @@ import BraintreeCore apiClient.sendAnalyticsEvent( BTVenmoAnalytics.tokenizeSucceeded, isVaultRequest: shouldVault, - linkType: linkType, payPalContextID: payPalContextID ) completion(result, nil) @@ -480,7 +453,6 @@ import BraintreeCore BTVenmoAnalytics.tokenizeFailed, errorDescription: error.localizedDescription, isVaultRequest: shouldVault, - linkType: linkType, payPalContextID: payPalContextID ) completion(nil, error) @@ -490,7 +462,6 @@ import BraintreeCore apiClient.sendAnalyticsEvent( BTVenmoAnalytics.appSwitchCanceled, isVaultRequest: shouldVault, - linkType: linkType, payPalContextID: payPalContextID ) completion(nil, BTVenmoError.canceled) diff --git a/Sources/BraintreeVenmo/BTVenmoRequest.swift b/Sources/BraintreeVenmo/BTVenmoRequest.swift index b95daca2a..a974cb31f 100644 --- a/Sources/BraintreeVenmo/BTVenmoRequest.swift +++ b/Sources/BraintreeVenmo/BTVenmoRequest.swift @@ -37,7 +37,6 @@ import Foundation var shippingAmount: String? var totalAmount: String? var lineItems: [BTVenmoLineItem]? - var fallbackToWeb: Bool = false // MARK: - Initializer @@ -57,9 +56,8 @@ import Foundation /// - shippingAmount: The shipping amount for the transaction to be displayed on the paysheet. If this value is set, `totalAmount` must also be set. /// - totalAmount: The grand total amount on the transaction that should be displayed on the paysheet. /// - lineItems: The line items for this transaction. It can include up to 249 line items. If this value is set, `totalAmount` must also be set. - /// - fallbackToWeb: Used to determine if the customer should fallback to the web flow if Venmo app is not installed. Defaults to `false` @objc(initWithPaymentMethodUsage:profileID:vault:displayName:collectCustomerBillingAddress:collectCustomerShippingAddress: - isFinalAmount:subTotalAmount:discountAmount:taxAmount:shippingAmount:totalAmount:lineItems:fallbackToWeb:) + isFinalAmount:subTotalAmount:discountAmount:taxAmount:shippingAmount:totalAmount:lineItems:) public init( paymentMethodUsage: BTVenmoPaymentMethodUsage, profileID: String? = nil, @@ -73,8 +71,7 @@ import Foundation taxAmount: String? = nil, shippingAmount: String? = nil, totalAmount: String? = nil, - lineItems: [BTVenmoLineItem]? = [], - fallbackToWeb: Bool = false + lineItems: [BTVenmoLineItem]? = [] ) { self.paymentMethodUsage = paymentMethodUsage self.profileID = profileID @@ -89,6 +86,5 @@ import Foundation self.shippingAmount = shippingAmount self.totalAmount = totalAmount self.lineItems = lineItems - self.fallbackToWeb = fallbackToWeb } } diff --git a/UnitTests/BraintreeVenmoTests/BTVenmoAppSwitchRedirectURL_Tests.swift b/UnitTests/BraintreeVenmoTests/BTVenmoAppSwitchRedirectURL_Tests.swift index da92e9bc0..98b2cdf2e 100644 --- a/UnitTests/BraintreeVenmoTests/BTVenmoAppSwitchRedirectURL_Tests.swift +++ b/UnitTests/BraintreeVenmoTests/BTVenmoAppSwitchRedirectURL_Tests.swift @@ -4,28 +4,6 @@ import XCTest class BTVenmoAppSwitchRedirectURL_Tests: XCTestCase { - func testUrlSchemeURL_whenAllValuesAreInitialized_returnsURLWithPaymentContextID() { - do { - let requestURL = try BTVenmoAppSwitchRedirectURL( - returnURLScheme: "url-scheme", - paymentContextID: "12345", - metadata: BTClientMetadata(), - forMerchantID: "merchant-id", - accessToken: "access-token", - bundleDisplayName: "display-name", - environment: "sandbox" - ) - - XCTAssertTrue(requestURL.urlSchemeURL()!.absoluteString.contains("com.venmo.touch.v2://x-callback-url/vzero/auth")) - - let components = URLComponents(string: requestURL.urlSchemeURL()!.absoluteString) - guard let queryItems = components?.queryItems else { XCTFail(); return } - XCTAssertTrue(queryItems.contains(URLQueryItem(name: "resource_id", value: "12345"))) - } catch { - XCTFail("This request URL should be constructed successfully") - } - } - func testAppSwitchURL_whenMerchantIDNil_throwsError() { do { _ = try BTVenmoAppSwitchRedirectURL( diff --git a/UnitTests/BraintreeVenmoTests/BTVenmoClient_Tests.swift b/UnitTests/BraintreeVenmoTests/BTVenmoClient_Tests.swift index e9101a438..2d8a8183a 100644 --- a/UnitTests/BraintreeVenmoTests/BTVenmoClient_Tests.swift +++ b/UnitTests/BraintreeVenmoTests/BTVenmoClient_Tests.swift @@ -275,7 +275,7 @@ class BTVenmoClient_Tests: XCTestCase { return } - XCTAssertEqual(urlComponents.scheme, "com.venmo.touch.v2") + XCTAssertEqual(urlComponents.scheme, "https") XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_merchant_id", value: "venmo_merchant_id"))) XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_access_token", value: "venmo-access-token"))) XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_environment", value: "sandbox"))) @@ -344,7 +344,7 @@ class BTVenmoClient_Tests: XCTestCase { return } - XCTAssertEqual(urlComponents.scheme, "com.venmo.touch.v2") + XCTAssertEqual(urlComponents.scheme, "https") XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_merchant_id", value: "venmo_merchant_id"))) XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_access_token", value: "venmo-access-token"))) XCTAssertTrue(queryItems.contains(URLQueryItem(name: "braintree_environment", value: "sandbox"))) @@ -584,48 +584,6 @@ class BTVenmoClient_Tests: XCTestCase { XCTAssertEqual(mockAPIClient.postedAnalyticsEvents.last!, BTVenmoAnalytics.tokenizeSucceeded) XCTAssertEqual(mockAPIClient.postedPayPalContextID, "some-resource-id") - XCTAssertEqual(mockAPIClient.postedLinkType, .deeplink) - } - - func testTokenizeVenmoAccount_fallbackToWebTrue_sendsSuccessAnalyticsEvent() { - mockAPIClient.authorization = try! BTClientToken(clientToken: TestClientTokenFactory.validClientToken) - - let venmoClient = BTVenmoClient(apiClient: mockAPIClient) - venmoClient.application = FakeApplication() - venmoClient.bundle = FakeBundle() - BTAppContextSwitcher.sharedInstance.returnURLScheme = "scheme" - - let expectation = expectation(description: "Callback invoked") - - venmoRequest.fallbackToWeb = true - - venmoClient.tokenize(venmoRequest) { venmoAccount, error in - XCTAssertNil(error) - XCTAssertEqual(venmoAccount?.username, "venmojoe") - XCTAssertEqual(venmoAccount?.nonce, "abcd-venmo-nonce") - expectation.fulfill() - } - - mockAPIClient.cannedResponseBody = BTJSON(value: [ - "venmoAccounts": [[ - "type": "VenmoAccount", - "nonce": "abcd-venmo-nonce", - "description": "VenmoAccount", - "consumed": false, - "default": true, - "details": [ - "cardType": "Discover", - "username": "venmojoe" - ] - ] as [String: Any]] - ]) - - BTVenmoClient.handleReturnURL(URL(string: "scheme://x-callback-url/vzero/auth/venmo/success?paymentMethodNonce=abcd-venmo-nonce&username=venmojoe")!) - waitForExpectations(timeout: 2) - - XCTAssertEqual(mockAPIClient.postedAnalyticsEvents.last!, BTVenmoAnalytics.tokenizeSucceeded) - XCTAssertEqual(mockAPIClient.postedPayPalContextID, "some-resource-id") - XCTAssertEqual(mockAPIClient.postedLinkType, .universal) } func testTokenizeVenmoAccount_vaultTrue_sendsFailureAnalyticsEvent() { @@ -651,7 +609,6 @@ class BTVenmoClient_Tests: XCTestCase { XCTAssertEqual(mockAPIClient.postedAnalyticsEvents.last!, BTVenmoAnalytics.tokenizeFailed) XCTAssertEqual(mockAPIClient.postedPayPalContextID, "some-resource-id") - XCTAssertEqual(mockAPIClient.postedLinkType, .deeplink) } func testTokenizeVenmoAccount_whenAppSwitchCanceled_callsBackWithCancelError() { @@ -686,7 +643,7 @@ class BTVenmoClient_Tests: XCTestCase { venmoClient.tokenize(venmoRequest) { _, _ in } XCTAssertTrue(fakeApplication.openURLWasCalled) - XCTAssertEqual(fakeApplication.lastOpenURL!.scheme, "com.venmo.touch.v2") + XCTAssertEqual(fakeApplication.lastOpenURL!.scheme, "https") XCTAssertNotNil(fakeApplication.lastOpenURL!.absoluteString.range(of: "venmo_merchant_id")); XCTAssertNotNil(fakeApplication.lastOpenURL!.absoluteString.range(of: "venmo-access-token")); } @@ -703,7 +660,7 @@ class BTVenmoClient_Tests: XCTestCase { venmoClient.tokenize(venmoRequest) { _, _ in } XCTAssertTrue(fakeApplication.openURLWasCalled) - XCTAssertEqual(fakeApplication.lastOpenURL!.scheme, "com.venmo.touch.v2") + XCTAssertEqual(fakeApplication.lastOpenURL!.scheme, "https") XCTAssertNotNil(fakeApplication.lastOpenURL!.absoluteString.range(of: "second_venmo_merchant_id")); XCTAssertNotNil(fakeApplication.lastOpenURL!.absoluteString.range(of: "venmo-access-token")); } @@ -821,27 +778,6 @@ class BTVenmoClient_Tests: XCTestCase { // MARK: - BTAppContextSwitchClient - func testIsiOSAppSwitchAvailable_whenApplicationCanOpenVenmoURL_returnsTrue() { - let venmoClient = BTVenmoClient(apiClient: mockAPIClient) - BTAppContextSwitcher.sharedInstance.returnURLScheme = "scheme" - let fakeApplication = FakeApplication() - fakeApplication.cannedCanOpenURL = false - fakeApplication.canOpenURLWhitelist.append(URL(string: "com.venmo.touch.v2://x-callback-url/path")!) - venmoClient.application = fakeApplication - - XCTAssertTrue(venmoClient.isVenmoAppInstalled()) - } - - func testIsiOSAppSwitchAvailable_whenApplicationCantOpenVenmoURL_returnsFalse() { - let venmoClient = BTVenmoClient(apiClient: mockAPIClient) - BTAppContextSwitcher.sharedInstance.returnURLScheme = "scheme" - let fakeApplication = FakeApplication() - fakeApplication.cannedCanOpenURL = false - venmoClient.application = fakeApplication - - XCTAssertFalse(venmoClient.isVenmoAppInstalled()) - } - func testCanHandleReturnURL_withValidHost_andValidPath_returnsTrue() { let host = "x-callback-url" let path = "/vzero/auth/venmo/" diff --git a/UnitTests/BraintreeVenmoTests/BTVenmoRequest_Tests.swift b/UnitTests/BraintreeVenmoTests/BTVenmoRequest_Tests.swift index 1685de690..00f215e4b 100644 --- a/UnitTests/BraintreeVenmoTests/BTVenmoRequest_Tests.swift +++ b/UnitTests/BraintreeVenmoTests/BTVenmoRequest_Tests.swift @@ -23,9 +23,4 @@ class BTVenmoRequest_Tests: XCTestCase { let request = BTVenmoRequest(paymentMethodUsage: .singleUse) XCTAssertEqual(request.isFinalAmount, false) } - - func testFallbackToWeb_whenNotPassed_defaultsValueAsFalse() { - let request = BTVenmoRequest(paymentMethodUsage: .singleUse) - XCTAssertEqual(request.fallbackToWeb, false) - } } diff --git a/V7_MIGRATION.md b/V7_MIGRATION.md index 8d0c509ae..5e57c5e12 100644 --- a/V7_MIGRATION.md +++ b/V7_MIGRATION.md @@ -19,8 +19,10 @@ v7 bumps to a minimum deployment target of iOS 16+. ## Venmo All properties within `BTVenmoRequest` can only be accessed on the initializer vs via the dot syntax. +Remove the `fallbackToWeb` boolean parameter from `BTVenmoRequest`. If a Buyer has the Venmo app installed and taps on "Pay with Venmo", they will automatically be switched to the Venmo app. If the Venmo app isn't installed, the Buyer will fallback to their default web brower to checkout. + ``` -let venmoRequest = BTVenmoRequest(paymentMethodUsage: .multiUse, vault: true, fallbackToWeb: true) +let venmoRequest = BTVenmoRequest(paymentMethodUsage: .multiUse, vault: true) ``` ## SEPA Direct Debit