From 506daa9917a2e44904a210f27f5a9cbe069a35ef Mon Sep 17 00:00:00 2001 From: Rich Herrera Date: Fri, 11 Oct 2024 11:01:19 -0600 Subject: [PATCH 1/3] Add Shipping Callback URL to PayPalRequest (#1185) * Add shipping callback uri * Override checkout shipping callback property * Override vault shipping callback property * Use let to assign shipping callback value * Add CheckoutRequest tests * Add VaultRequest tests * Update CHANGELOG --- CHANGELOG.md | 5 ++ .../api/paypal/PayPalCheckoutRequest.kt | 9 ++- .../api/paypal/PayPalRequest.kt | 8 ++- .../api/paypal/PayPalVaultRequest.kt | 9 ++- .../paypal/PayPalCheckoutRequestUnitTest.java | 57 ++++++++++++++++++- .../paypal/PayPalVaultRequestUnitTest.java | 55 ++++++++++++++++++ 6 files changed, 139 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7081ccce..6734e82a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Braintree Android SDK Release Notes +## unreleased + +* PayPal + * Add `shippingCallbackURL` to `PayPalRequest` + ## 5.0.0 (2024-09-30) * PayPal diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt index f3b888abda..7004f35f2f 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt @@ -1,5 +1,6 @@ package com.braintreepayments.api.paypal +import android.net.Uri import android.text.TextUtils import com.braintreepayments.api.core.Authorization import com.braintreepayments.api.core.ClientToken @@ -75,6 +76,7 @@ class PayPalCheckoutRequest @JvmOverloads constructor( override var riskCorrelationId: String? = null, override var userAuthenticationEmail: String? = null, override var lineItems: List = emptyList(), + override var shippingCallbackUrl: Uri? = null, ) : PayPalRequest( hasUserLocationConsent = hasUserLocationConsent, localeCode = localeCode, @@ -87,7 +89,8 @@ class PayPalCheckoutRequest @JvmOverloads constructor( merchantAccountId = merchantAccountId, riskCorrelationId = riskCorrelationId, userAuthenticationEmail = userAuthenticationEmail, - lineItems = lineItems + lineItems = lineItems, + shippingCallbackUrl = shippingCallbackUrl, ) { @Throws(JSONException::class) @@ -104,6 +107,10 @@ class PayPalCheckoutRequest @JvmOverloads constructor( .put(CANCEL_URL_KEY, cancelUrl) .put(OFFER_PAY_LATER_KEY, shouldOfferPayLater) + shippingCallbackUrl?.let { + if (it.toString().isNotEmpty()) parameters.put(SHIPPING_CALLBACK_URL_KEY, it) + } + if (authorization is ClientToken) { parameters.put(AUTHORIZATION_FINGERPRINT_KEY, authorization.bearer) } else { diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt index 72e3f2d991..fc68d35a5b 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt @@ -1,5 +1,6 @@ package com.braintreepayments.api.paypal +import android.net.Uri import android.os.Parcelable import androidx.annotation.RestrictTo import com.braintreepayments.api.core.Authorization @@ -71,6 +72,9 @@ import org.json.JSONException * @property userAuthenticationEmail User email to initiate a quicker authentication flow in cases * where the user has a PayPal Account with the same email. * @property lineItems The line items for this transaction. It can include up to 249 line items. + * @property shippingCallbackUrl Server side shipping callback URL to be notified when a customer + * updates their shipping address or options. A callback request will be sent to the merchant server + * at this URL. */ abstract class PayPalRequest internal constructor( open val hasUserLocationConsent: Boolean, @@ -84,7 +88,8 @@ abstract class PayPalRequest internal constructor( open var merchantAccountId: String? = null, open var riskCorrelationId: String? = null, open var userAuthenticationEmail: String? = null, - open var lineItems: List = emptyList() + open var lineItems: List = emptyList(), + open var shippingCallbackUrl: Uri? = null, ) : Parcelable { @Throws(JSONException::class) @@ -126,5 +131,6 @@ abstract class PayPalRequest internal constructor( internal const val OS_VERSION_KEY: String = "os_version" internal const val OS_TYPE_KEY: String = "os_type" internal const val MERCHANT_APP_RETURN_URL_KEY: String = "merchant_app_return_url" + internal const val SHIPPING_CALLBACK_URL_KEY: String = "shipping_callback_url" } } diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt index 140a31dd43..37b873b8f4 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt @@ -1,5 +1,6 @@ package com.braintreepayments.api.paypal +import android.net.Uri import android.os.Build import android.text.TextUtils import com.braintreepayments.api.core.Authorization @@ -45,6 +46,7 @@ class PayPalVaultRequest override var riskCorrelationId: String? = null, override var userAuthenticationEmail: String? = null, override var lineItems: List = emptyList(), + override var shippingCallbackUrl: Uri? = null, ) : PayPalRequest( hasUserLocationConsent = hasUserLocationConsent, localeCode = localeCode, @@ -57,7 +59,8 @@ class PayPalVaultRequest merchantAccountId = merchantAccountId, riskCorrelationId = riskCorrelationId, userAuthenticationEmail = userAuthenticationEmail, - lineItems = lineItems + lineItems = lineItems, + shippingCallbackUrl = shippingCallbackUrl, ) { @Throws(JSONException::class) @@ -74,6 +77,10 @@ class PayPalVaultRequest .put(CANCEL_URL_KEY, cancelUrl) .put(OFFER_CREDIT_KEY, shouldOfferCredit) + shippingCallbackUrl?.let { + if (it.toString().isNotEmpty()) parameters.put(SHIPPING_CALLBACK_URL_KEY, it) + } + if (authorization is ClientToken) { parameters.put(AUTHORIZATION_FINGERPRINT_KEY, authorization.bearer) } else { diff --git a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestUnitTest.java b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestUnitTest.java index fe0def7af7..c4358ae6b0 100644 --- a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestUnitTest.java +++ b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestUnitTest.java @@ -1,5 +1,6 @@ package com.braintreepayments.api.paypal; +import android.net.Uri; import android.os.Parcel; import com.braintreepayments.api.core.Authorization; @@ -7,6 +8,7 @@ import com.braintreepayments.api.core.PostalAddress; import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -155,4 +157,57 @@ public void createRequestBody_does_not_set_userAuthenticationEmail_when_email_is assertFalse(requestBody.contains("\"payer_email\":" + "\"" + payerEmail + "\"")); } -} \ No newline at end of file + + @Test + public void createRequestBody_sets_shippingCallbackUri_when_not_null() throws JSONException { + String urlString = "https://www.example.com/path"; + Uri uri = Uri.parse(urlString); + + PayPalCheckoutRequest request = new PayPalCheckoutRequest("1.00", true); + request.setShippingCallbackUrl(uri); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertEquals(urlString, jsonObject.getString("shipping_callback_url")); + } + + @Test + public void createRequestBody_does_not_set_shippingCallbackUri_when_null() throws JSONException { + PayPalCheckoutRequest request = new PayPalCheckoutRequest("1.00", true); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertFalse(jsonObject.has("shipping_callback_url")); + } + + @Test + public void createRequestBody_does_not_set_shippingCallbackUri_when_empty() throws JSONException { + PayPalCheckoutRequest request = new PayPalCheckoutRequest("1.00", true); + request.setShippingCallbackUrl(Uri.parse("")); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertFalse(jsonObject.has("shipping_callback_url")); + } +} diff --git a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java index 04a0cd475f..79dc0d83fe 100644 --- a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java +++ b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java @@ -1,5 +1,6 @@ package com.braintreepayments.api.paypal; +import android.net.Uri; import android.os.Build; import android.os.Parcel; @@ -8,6 +9,7 @@ import com.braintreepayments.api.core.PostalAddress; import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -142,4 +144,57 @@ public void createRequestBody_sets_enablePayPalSwitch_and_userAuthenticationEmai assertTrue(requestBody.contains("\"os_version\":" + "\"" + versionSDK + "\"")); assertTrue(requestBody.contains("\"merchant_app_return_url\":" + "\"universal_url\"")); } + + @Test + public void createRequestBody_sets_shippingCallbackUri_when_not_null() throws JSONException { + String urlString = "https://www.example.com/path"; + Uri uri = Uri.parse(urlString); + + PayPalVaultRequest request = new PayPalVaultRequest(true); + request.setShippingCallbackUrl(uri); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertEquals(urlString, jsonObject.getString("shipping_callback_url")); + } + + @Test + public void createRequestBody_does_not_set_shippingCallbackUri_when_null() throws JSONException { + PayPalVaultRequest request = new PayPalVaultRequest(true); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertFalse(jsonObject.has("shipping_callback_url")); + } + + @Test + public void createRequestBody_does_not_set_shippingCallbackUri_when_empty() throws JSONException { + PayPalVaultRequest request = new PayPalVaultRequest(true); + request.setShippingCallbackUrl(Uri.parse("")); + + String requestBody = request.createRequestBody( + mock(Configuration.class), + mock(Authorization.class), + "success_url", + "cancel_url", + null + ); + + JSONObject jsonObject = new JSONObject(requestBody); + assertFalse(jsonObject.has("shipping_callback_url")); + } } From 182f599b5256749c096fd7db967fc3d241b3f3e1 Mon Sep 17 00:00:00 2001 From: Rich Herrera Date: Fri, 1 Nov 2024 13:13:27 -0600 Subject: [PATCH 2/3] Move Shipping Callback URL to `PayPalCheckoutRequest` (#1200) * Remove unnecessary Vault UTs * Update CHANGELOG * Remove shippingCallbackUrl from PayPalRequest interface * Remove shippingCallbackUri from PayPalVaultRequest class * Remove unnecessary docstring from interface * Make shippingCallbackUrl a property of PayPalCheckoutRequest --- CHANGELOG.md | 2 +- .../api/paypal/PayPalCheckoutRequest.kt | 10 ++-- .../api/paypal/PayPalRequest.kt | 7 +-- .../api/paypal/PayPalVaultRequest.kt | 9 +-- .../paypal/PayPalVaultRequestUnitTest.java | 55 ------------------- 5 files changed, 9 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7076960019..ce8ad66e41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## unreleased * PayPal - * Add `shippingCallbackURL` to `PayPalRequest` + * Add `shippingCallbackURL` to `PayPalCheckoutRequest` ## 5.2.0 (2024-10-30) diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt index 54537ccd9c..c6b4888832 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt @@ -55,6 +55,9 @@ import org.json.JSONObject * * @property shouldOfferPayLater Offers PayPal Pay Later if the customer qualifies. Defaults to * false. + * @property shippingCallbackUrl Server side shipping callback URL to be notified when a customer + * updates their shipping address or options. A callback request will be sent to the merchant server + * at this URL. */ @Parcelize class PayPalCheckoutRequest @JvmOverloads constructor( @@ -65,6 +68,7 @@ class PayPalCheckoutRequest @JvmOverloads constructor( var currencyCode: String? = null, var shouldRequestBillingAgreement: Boolean = false, var shouldOfferPayLater: Boolean = false, + var shippingCallbackUrl: Uri? = null, override var localeCode: String? = null, override var billingAgreementDescription: String? = null, override var isShippingAddressRequired: Boolean = false, @@ -76,8 +80,7 @@ class PayPalCheckoutRequest @JvmOverloads constructor( override var riskCorrelationId: String? = null, override var userAuthenticationEmail: String? = null, override var userPhoneNumber: PayPalPhoneNumber? = null, - override var lineItems: List = emptyList(), - override var shippingCallbackUrl: Uri? = null, + override var lineItems: List = emptyList() ) : PayPalRequest( hasUserLocationConsent = hasUserLocationConsent, localeCode = localeCode, @@ -90,8 +93,7 @@ class PayPalCheckoutRequest @JvmOverloads constructor( merchantAccountId = merchantAccountId, riskCorrelationId = riskCorrelationId, userAuthenticationEmail = userAuthenticationEmail, - lineItems = lineItems, - shippingCallbackUrl = shippingCallbackUrl, + lineItems = lineItems ) { @Throws(JSONException::class) diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt index 852cdd3133..eb44dd5faa 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt @@ -1,6 +1,5 @@ package com.braintreepayments.api.paypal -import android.net.Uri import android.os.Parcelable import androidx.annotation.RestrictTo import com.braintreepayments.api.core.Authorization @@ -74,9 +73,6 @@ import org.json.JSONException * @property userPhoneNumber User phone number used to initiate a quicker authentication flow in * cases where the user has a PayPal Account with the phone number. * @property lineItems The line items for this transaction. It can include up to 249 line items. - * @property shippingCallbackUrl Server side shipping callback URL to be notified when a customer - * updates their shipping address or options. A callback request will be sent to the merchant server - * at this URL. */ abstract class PayPalRequest internal constructor( open val hasUserLocationConsent: Boolean, @@ -91,8 +87,7 @@ abstract class PayPalRequest internal constructor( open var riskCorrelationId: String? = null, open var userAuthenticationEmail: String? = null, open var userPhoneNumber: PayPalPhoneNumber? = null, - open var lineItems: List = emptyList(), - open var shippingCallbackUrl: Uri? = null + open var lineItems: List = emptyList() ) : Parcelable { @Throws(JSONException::class) diff --git a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt index 7f8d762d4c..609d911141 100644 --- a/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt +++ b/PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt @@ -1,6 +1,5 @@ package com.braintreepayments.api.paypal -import android.net.Uri import android.os.Build import android.text.TextUtils import com.braintreepayments.api.core.Authorization @@ -50,8 +49,7 @@ class PayPalVaultRequest override var riskCorrelationId: String? = null, override var userAuthenticationEmail: String? = null, override var userPhoneNumber: PayPalPhoneNumber? = null, - override var lineItems: List = emptyList(), - override var shippingCallbackUrl: Uri? = null, + override var lineItems: List = emptyList() ) : PayPalRequest( hasUserLocationConsent = hasUserLocationConsent, localeCode = localeCode, @@ -65,7 +63,6 @@ class PayPalVaultRequest riskCorrelationId = riskCorrelationId, userAuthenticationEmail = userAuthenticationEmail, lineItems = lineItems, - shippingCallbackUrl = shippingCallbackUrl, ) { @Throws(JSONException::class) @@ -82,10 +79,6 @@ class PayPalVaultRequest .put(CANCEL_URL_KEY, cancelUrl) .put(OFFER_CREDIT_KEY, shouldOfferCredit) - shippingCallbackUrl?.let { - if (it.toString().isNotEmpty()) parameters.put(SHIPPING_CALLBACK_URL_KEY, it) - } - if (authorization is ClientToken) { parameters.put(AUTHORIZATION_FINGERPRINT_KEY, authorization.bearer) } else { diff --git a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java index 940d3dfcc3..350e1c9ad5 100644 --- a/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java +++ b/PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; -import android.net.Uri; import android.os.Build; import android.os.Parcel; @@ -17,7 +16,6 @@ import com.braintreepayments.api.testutils.Fixtures; import org.json.JSONException; -import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -301,57 +299,4 @@ public void createRequestBody_sets_userPhoneNumber_when_not_null() throws JSONEx assertTrue(requestBody.contains("\"phone_number\":{\"country_code\":\"1\",\"national_number\":\"1231231234\"}")); } - - @Test - public void createRequestBody_sets_shippingCallbackUri_when_not_null() throws JSONException { - String urlString = "https://www.example.com/path"; - Uri uri = Uri.parse(urlString); - - PayPalVaultRequest request = new PayPalVaultRequest(true); - request.setShippingCallbackUrl(uri); - - String requestBody = request.createRequestBody( - mock(Configuration.class), - mock(Authorization.class), - "success_url", - "cancel_url", - null - ); - - JSONObject jsonObject = new JSONObject(requestBody); - assertEquals(urlString, jsonObject.getString("shipping_callback_url")); - } - - @Test - public void createRequestBody_does_not_set_shippingCallbackUri_when_null() throws JSONException { - PayPalVaultRequest request = new PayPalVaultRequest(true); - - String requestBody = request.createRequestBody( - mock(Configuration.class), - mock(Authorization.class), - "success_url", - "cancel_url", - null - ); - - JSONObject jsonObject = new JSONObject(requestBody); - assertFalse(jsonObject.has("shipping_callback_url")); - } - - @Test - public void createRequestBody_does_not_set_shippingCallbackUri_when_empty() throws JSONException { - PayPalVaultRequest request = new PayPalVaultRequest(true); - request.setShippingCallbackUrl(Uri.parse("")); - - String requestBody = request.createRequestBody( - mock(Configuration.class), - mock(Authorization.class), - "success_url", - "cancel_url", - null - ); - - JSONObject jsonObject = new JSONObject(requestBody); - assertFalse(jsonObject.has("shipping_callback_url")); - } } From ee491b4093a02b0acea479d45d4eb2297d2a1cc4 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Fri, 10 Jan 2025 08:39:32 -0600 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d50bf437bb..d36cb5e813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## unreleased * PayPal - * Add `shippingCallbackURL` to `PayPalCheckoutRequest` + * Add `shippingCallbackUrl` to `PayPalCheckoutRequest` ## 5.3.0 (2024-12-11)