Skip to content

Commit

Permalink
Merge branch 'main' into shipping-callback-feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jaxdesmarais authored Jan 21, 2025
2 parents ee491b4 + 402d25a commit 7a3b5c9
Show file tree
Hide file tree
Showing 19 changed files with 382 additions and 332 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import androidx.annotation.RestrictTo
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class AnalyticsEventParams @JvmOverloads constructor(
var payPalContextId: String? = null,
var linkType: String? = null,
var isVaultRequest: Boolean = false,
var startTime: Long? = null,
var endTime: Long? = null,
var endpoint: String? = null,
val payPalContextId: String? = null,
val linkType: String? = null,
val isVaultRequest: Boolean = false,
val startTime: Long? = null,
val endTime: Long? = null,
val endpoint: String? = null,
val experiment: String? = null,
val paymentMethodsDisplayed: List<String> = emptyList(),
val appSwitchUrl: String? = null
Expand Down
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# Braintree Android SDK Release Notes

## unreleased

* PayPal
* Fix bug to ensure that `PayPalVaultRequest.userAuthenticationEmail` is not sent as an empty string
* Add `shippingCallbackUrl` to `PayPalCheckoutRequest`

* ThreeDSecure
* Return error if no `dfReferenceId` is returned in the 3D Secure flow

## 5.3.0 (2024-12-11)

* PayPal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public static PayPalVaultRequest createPayPalVaultRequest(
postalAddress.setStreetAddress("123 Fake Street");
postalAddress.setExtendedAddress("Floor A");
postalAddress.setLocality("San Francisco");
postalAddress.setPostalCode("12345");
postalAddress.setRegion("CA");
postalAddress.setCountryCodeAlpha2("US");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ class ShopperInsightsFragment : BaseFragment() {

venmoClient = VenmoClient(requireContext(), super.getAuthStringArg(), null)
payPalClient = PayPalClient(
requireContext(), super.getAuthStringArg(),
Uri.parse("https://mobile-sdk-demo-site-838cead5d3ab.herokuapp.com/")
requireContext(),
super.getAuthStringArg(),
Uri.parse("https://mobile-sdk-demo-site-838cead5d3ab.herokuapp.com/braintree-payments"),
)

return inflater.inflate(R.layout.fragment_shopping_insights, container, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ class LocalPaymentClient internal constructor(
}

private fun sendAnalyticsEvent(eventName: String) {
val eventParameters = AnalyticsEventParams()
eventParameters.payPalContextId = payPalContextId
val eventParameters = AnalyticsEventParams(
payPalContextId = payPalContextId
)
braintreeClient.sendAnalyticsEvent(eventName, eventParameters)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,9 @@ public void createPaymentAuthRequest_success_withPaymentId_sendsAnalyticsEvents(
sut.createPaymentAuthRequest(getIdealLocalPaymentRequest(), localPaymentAuthCallback);

verify(braintreeClient).sendAnalyticsEvent(LocalPaymentAnalytics.PAYMENT_STARTED, new AnalyticsEventParams());
AnalyticsEventParams params = new AnalyticsEventParams();
params.setPayPalContextId("some-paypal-context-id");
AnalyticsEventParams params = new AnalyticsEventParams(
"some-paypal-context-id"
);
verify(braintreeClient).sendAnalyticsEvent(LocalPaymentAnalytics.BROWSER_SWITCH_SUCCEEDED, params);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import com.braintreepayments.api.BrowserSwitchException
import com.braintreepayments.api.BrowserSwitchFinalResult
import com.braintreepayments.api.BrowserSwitchStartResult
import com.braintreepayments.api.core.AnalyticsClient
import com.braintreepayments.api.core.AnalyticsEventParams
import com.braintreepayments.api.core.BraintreeException
import com.braintreepayments.api.core.GetReturnLinkUseCase
import com.braintreepayments.api.core.MerchantRepository

/**
* Responsible for launching PayPal user authentication in a web browser
*/
class PayPalLauncher internal constructor(
private val browserSwitchClient: BrowserSwitchClient,
private val merchantRepository: MerchantRepository = MerchantRepository.instance,
private val getReturnLinkUseCase: GetReturnLinkUseCase = GetReturnLinkUseCase(merchantRepository),
lazyAnalyticsClient: Lazy<AnalyticsClient>
) {
/**
Expand Down Expand Up @@ -82,7 +87,20 @@ class PayPalLauncher internal constructor(
pendingRequest: PayPalPendingRequest.Started,
intent: Intent
): PayPalPaymentAuthResult {
analyticsClient.sendEvent(PayPalAnalytics.HANDLE_RETURN_STARTED)
analyticsClient.sendEvent(
PayPalAnalytics.HANDLE_RETURN_STARTED,
AnalyticsEventParams(
appSwitchUrl = when (val returnLinkResult = getReturnLinkUseCase()) {
is GetReturnLinkUseCase.ReturnLinkResult.AppLink -> {
returnLinkResult.appLinkReturnUri.toString()
}
is GetReturnLinkUseCase.ReturnLinkResult.DeepLink -> {
returnLinkResult.deepLinkFallbackUrlScheme
}
else -> null
}
)
)
return when (val browserSwitchResult =
browserSwitchClient.completeRequest(intent, pendingRequest.pendingRequestString)) {
is BrowserSwitchFinalResult.Success -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class PayPalVaultRequest
) {

@Throws(JSONException::class)
@Suppress("LongMethod")
@Suppress("LongMethod", "CyclomaticComplexMethod")
override fun createRequestBody(
configuration: Configuration?,
authorization: Authorization?,
Expand All @@ -90,7 +90,9 @@ class PayPalVaultRequest
parameters.put(DESCRIPTION_KEY, billingAgreementDescription)
}

parameters.putOpt(PAYER_EMAIL_KEY, userAuthenticationEmail)
if (!userAuthenticationEmail.isNullOrEmpty()) {
parameters.put(PAYER_EMAIL_KEY, userAuthenticationEmail)
}

userPhoneNumber?.let { parameters.put(PHONE_NUMBER_KEY, it.toJson()) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,11 @@ public void createPaymentAuthRequest_whenPayPalNotEnabled_returnsError() {
"for more information.",
((PayPalPaymentAuthRequest.Failure) request).getError().getMessage());

AnalyticsEventParams params = new AnalyticsEventParams();
params.setVaultRequest(false);
AnalyticsEventParams params = new AnalyticsEventParams(
null,
null,
false
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params);
}

Expand All @@ -309,8 +312,11 @@ public void createPaymentAuthRequest_whenCheckoutRequest_whenConfigError_forward
assertTrue(request instanceof PayPalPaymentAuthRequest.Failure);
assertEquals(authError, ((PayPalPaymentAuthRequest.Failure) request).getError());

AnalyticsEventParams params = new AnalyticsEventParams();
params.setVaultRequest(false);
AnalyticsEventParams params = new AnalyticsEventParams(
null,
null,
false
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params);
}

Expand All @@ -334,8 +340,11 @@ public void requestBillingAgreement_whenConfigError_forwardsErrorToListener() {
assertTrue(request instanceof PayPalPaymentAuthRequest.Failure);
assertEquals(authError, ((PayPalPaymentAuthRequest.Failure) request).getError());

AnalyticsEventParams params = new AnalyticsEventParams();
params.setVaultRequest(true);
AnalyticsEventParams params = new AnalyticsEventParams(
null,
null,
true
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params);
}

Expand Down Expand Up @@ -414,9 +423,11 @@ public void createPaymentAuthRequest_whenVaultRequest_sendsAppSwitchStartedEvent
assertFalse(browserSwitchOptions.isLaunchAsNewTask());


AnalyticsEventParams params = new AnalyticsEventParams();
params.setVaultRequest(true);
params.setLinkType("universal");
AnalyticsEventParams params = new AnalyticsEventParams(
null,
"universal",
true
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.APP_SWITCH_STARTED, params);
}

Expand Down Expand Up @@ -541,8 +552,11 @@ public void tokenize_whenCancelUriReceived_notifiesCancellationAndSendsAnalytics
PayPalResult result = captor.getValue();
assertTrue(result instanceof PayPalResult.Cancel);

AnalyticsEventParams params = new AnalyticsEventParams();
params.setVaultRequest(false);
AnalyticsEventParams params = new AnalyticsEventParams(
null,
null,
false
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.BROWSER_LOGIN_CANCELED, params);
}

Expand Down Expand Up @@ -582,9 +596,11 @@ public void tokenize_whenPayPalInternalClientTokenizeResult_callsBackResult()
assertTrue(result instanceof PayPalResult.Success);
assertEquals(payPalAccountNonce, ((PayPalResult.Success) result).getNonce());

AnalyticsEventParams params = new AnalyticsEventParams();
params.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");
params.setVaultRequest(false);
AnalyticsEventParams params = new AnalyticsEventParams(
"EC-HERMES-SANDBOX-EC-TOKEN",
null,
false
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_SUCCEEDED, params);
}

Expand Down Expand Up @@ -624,19 +640,20 @@ public void tokenize_whenPayPalInternalClientTokenizeResult_sendsAppSwitchSuccee
assertTrue(result instanceof PayPalResult.Success);
assertEquals(payPalAccountNonce, ((PayPalResult.Success) result).getNonce());

AnalyticsEventParams params = new AnalyticsEventParams();
params.setPayPalContextId("EC-HERMES-SANDBOX-EC-TOKEN");
AnalyticsEventParams params = new AnalyticsEventParams(
"EC-HERMES-SANDBOX-EC-TOKEN"
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_SUCCEEDED, params);
AnalyticsEventParams appSwitchParams = new AnalyticsEventParams(
"EC-HERMES-SANDBOX-EC-TOKEN",
null,
false,
null,
null,
null,
null,
emptyList(),
"sample-scheme://onetouch/v1/success?PayerID=HERMES-SANDBOX-PAYER-ID&paymentId=HERMES-SANDBOX-PAYMENT-ID&token=EC-HERMES-SANDBOX-EC-TOKEN&switch_initiated_time=17166111926211"
"EC-HERMES-SANDBOX-EC-TOKEN",
null,
false,
null,
null,
null,
null,
emptyList(),
"sample-scheme://onetouch/v1/success?PayerID=HERMES-SANDBOX-PAYER-ID&paymentId=HERMES-SANDBOX-PAYMENT-ID&token=EC-HERMES-SANDBOX-EC-TOKEN&switch_initiated_time=17166111926211"
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.APP_SWITCH_SUCCEEDED, appSwitchParams);
}
Expand Down Expand Up @@ -666,19 +683,20 @@ public void tokenize_whenPayPalNotEnabled_sendsAppSwitchFailedEvents() throws JS

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

AnalyticsEventParams params = new AnalyticsEventParams();
params.setPayPalContextId("SOME-BA");
AnalyticsEventParams params = new AnalyticsEventParams(
"SOME-BA"
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params);
AnalyticsEventParams appSwitchParams = new AnalyticsEventParams(
"SOME-BA",
null,
false,
null,
null,
null,
null,
emptyList(),
"https://some-scheme/onetouch/v1/cancel?token=SOME-BA&switch_initiated_time=17166111926211"
"SOME-BA",
null,
false,
null,
null,
null,
null,
emptyList(),
"https://some-scheme/onetouch/v1/cancel?token=SOME-BA&switch_initiated_time=17166111926211"
);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.APP_SWITCH_FAILED, appSwitchParams);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.braintreepayments.api.paypal

import android.content.Intent
import android.net.Uri
import androidx.activity.ComponentActivity
import com.braintreepayments.api.BrowserSwitchClient
import com.braintreepayments.api.BrowserSwitchException
import com.braintreepayments.api.BrowserSwitchFinalResult
import com.braintreepayments.api.BrowserSwitchOptions
import com.braintreepayments.api.BrowserSwitchStartResult
import com.braintreepayments.api.core.AnalyticsClient
import com.braintreepayments.api.core.AnalyticsEventParams
import com.braintreepayments.api.core.GetReturnLinkUseCase
import com.braintreepayments.api.core.MerchantRepository
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
Expand All @@ -29,13 +33,26 @@ class PayPalLauncherUnitTest {
private val options: BrowserSwitchOptions = mockk(relaxed = true)
private val pendingRequestString = "pending_request_string"
private val analyticsClient: AnalyticsClient = mockk(relaxed = true)
private val merchantRepository = mockk<MerchantRepository>(relaxed = true)
private val getReturnLinkUseCase = mockk<GetReturnLinkUseCase>()
private val returnUrl = "https://return.url"
private val deepLinkScheme = "deepLinkScheme"

private lateinit var sut: PayPalLauncher

@Before
fun setup() {
every { paymentAuthRequestParams.browserSwitchOptions } returns options
sut = PayPalLauncher(browserSwitchClient, lazy { analyticsClient })

val appSwitchReturnUrl = Uri.parse(returnUrl)
every { getReturnLinkUseCase() } returns GetReturnLinkUseCase.ReturnLinkResult.AppLink(
appSwitchReturnUrl
)
sut = PayPalLauncher(
browserSwitchClient,
merchantRepository,
getReturnLinkUseCase,
lazy { analyticsClient })
}

@Test
Expand Down Expand Up @@ -100,7 +117,48 @@ class PayPalLauncherUnitTest {
PayPalPendingRequest.Started(pendingRequestString),
intent
)
verify { analyticsClient.sendEvent(PayPalAnalytics.HANDLE_RETURN_STARTED) }
verify {
analyticsClient.sendEvent(
PayPalAnalytics.HANDLE_RETURN_STARTED,
AnalyticsEventParams(appSwitchUrl = returnUrl)
)
}
}

@Test
@Throws(JSONException::class)
fun `handleReturnToApp with deeplinkScheme sends handle started event with deeplink scheme`() {
every { getReturnLinkUseCase() } returns GetReturnLinkUseCase.ReturnLinkResult.DeepLink(
deepLinkScheme
)
sut.handleReturnToApp(
PayPalPendingRequest.Started(pendingRequestString),
intent
)
verify {
analyticsClient.sendEvent(
PayPalAnalytics.HANDLE_RETURN_STARTED,
AnalyticsEventParams(appSwitchUrl = deepLinkScheme)
)
}
}

@Test
@Throws(JSONException::class)
fun `handleReturnToApp with ReturnLinkResult Failure sends handle started event with null appSwitchUrl`() {
every { getReturnLinkUseCase() } returns GetReturnLinkUseCase.ReturnLinkResult.Failure(
Exception("handle return start failed")
)
sut.handleReturnToApp(
PayPalPendingRequest.Started(pendingRequestString),
intent
)
verify {
analyticsClient.sendEvent(
PayPalAnalytics.HANDLE_RETURN_STARTED,
AnalyticsEventParams()
)
}
}

@Test
Expand Down
Loading

0 comments on commit 7a3b5c9

Please sign in to comment.