Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Shopper Session ID param #1241

Merged
merged 7 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class AnalyticsClient internal constructor(
endpoint = analyticsEventParams.endpoint,
experiment = analyticsEventParams.experiment,
paymentMethodsDisplayed = analyticsEventParams.paymentMethodsDisplayed,
appSwitchUrl = analyticsEventParams.appSwitchUrl
appSwitchUrl = analyticsEventParams.appSwitchUrl,
shopperSessionId = analyticsEventParams.shopperSessionId
)
configurationLoader.loadConfiguration { result ->
if (result is ConfigurationLoaderResult.Success) {
Expand Down Expand Up @@ -242,6 +243,7 @@ class AnalyticsClient internal constructor(
.putOpt(FPTI_KEY_MERCHANT_PAYMENT_METHODS_DISPLAYED,
event.paymentMethodsDisplayed.ifEmpty { null })
.putOpt(FPTI_KEY_URL, event.appSwitchUrl)
.putOpt(FPTI_KEY_SHOPPER_SESSION_ID, event.shopperSessionId)
return json.toString()
}

Expand Down Expand Up @@ -295,6 +297,7 @@ class AnalyticsClient internal constructor(
private const val FPTI_KEY_MERCHANT_EXPERIMENT = "experiment"
private const val FPTI_KEY_MERCHANT_PAYMENT_METHODS_DISPLAYED = "payment_methods_displayed"
private const val FPTI_KEY_URL = "url"
private const val FPTI_KEY_SHOPPER_SESSION_ID = "shopper_session_id"

private const val FPTI_BATCH_KEY_VENMO_INSTALLED = "venmo_installed"
private const val FPTI_BATCH_KEY_PAYPAL_INSTALLED = "paypal_installed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ internal data class AnalyticsEvent(
val endpoint: String? = null,
val experiment: String? = null,
val paymentMethodsDisplayed: List<String> = emptyList(),
val appSwitchUrl: String? = null
val appSwitchUrl: String? = null,
val shopperSessionId: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.annotation.RestrictTo
* the experiment, as a JSON string, that the merchant sent to the us.
* @property paymentMethodsDisplayed A ShopperInsights module specific event that indicates the
* order of payment methods displayed to the shopper by the merchant.
* @property shopperSessionId The Shopper Insights customer session ID created by a merchant's server SDK or graphQL integration.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class AnalyticsEventParams @JvmOverloads constructor(
Expand All @@ -28,5 +29,6 @@ data class AnalyticsEventParams @JvmOverloads constructor(
var endpoint: String? = null,
val experiment: String? = null,
val paymentMethodsDisplayed: List<String> = emptyList(),
val appSwitchUrl: String? = null
val appSwitchUrl: String? = null,
val shopperSessionId: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ class AnalyticsParamRepository(
_sessionId = uuidHelper.formattedUUID
}

fun setSessionId(sessionId: String) {
_sessionId = sessionId
}

companion object {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,4 @@ class AnalyticsParamRepositoryUnitTest {

assertEquals(newUuid, sut.sessionId)
}

@Test
fun `setSessionId sets the session ID with input value`() {
sut.setSessionId("override-session-id")
assertEquals("override-session-id", sut.sessionId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.net.Uri
import android.text.TextUtils
import com.braintreepayments.api.BrowserSwitchOptions
import com.braintreepayments.api.core.AnalyticsEventParams
import com.braintreepayments.api.core.AnalyticsParamRepository
import com.braintreepayments.api.core.BraintreeClient
import com.braintreepayments.api.core.BraintreeException
import com.braintreepayments.api.core.BraintreeRequestCodes
Expand All @@ -25,8 +24,7 @@ import org.json.JSONObject
class PayPalClient internal constructor(
private val braintreeClient: BraintreeClient,
private val internalPayPalClient: PayPalInternalClient = PayPalInternalClient(braintreeClient),
private val merchantRepository: MerchantRepository = MerchantRepository.instance,
private val analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance
private val merchantRepository: MerchantRepository = MerchantRepository.instance
) {
/**
* Used for linking events from the client to server side request
Expand All @@ -44,6 +42,11 @@ class PayPalClient internal constructor(
*/
private var isVaultRequest = false

/**
* Used for sending Shopper Insights session ID provided by merchant to FPTI
*/
private var shopperSessionId: String? = null
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we save this in a repository singleton outside of the Client class? Maybe a PayPalRepository that holds all PayPal specific values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered adding it to the AnalyticsParamRepository but since it is passed in by the merchant at each step there didn't seem much value there and it seemed a little confusing that we don't do that for any other general analytics event params. Open to a new param repository or adding it to the existing one if folks think that would be more helpful!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah gotcha. That makes sense 👍


/**
* Initializes a new [PayPalClient] instance
*
Expand Down Expand Up @@ -74,11 +77,7 @@ class PayPalClient internal constructor(
payPalRequest: PayPalRequest,
callback: PayPalPaymentAuthCallback
) {
// The shopper insights server SDK integration
payPalRequest.shopperSessionId?.let {
analyticsParamRepository.setSessionId(it)
}

shopperSessionId = payPalRequest.shopperSessionId
isVaultRequest = payPalRequest is PayPalVaultRequest

braintreeClient.sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_STARTED, analyticsParams)
Expand Down Expand Up @@ -337,7 +336,8 @@ class PayPalClient internal constructor(
return AnalyticsEventParams(
payPalContextId = payPalContextId,
linkType = linkType?.stringValue,
isVaultRequest = isVaultRequest
isVaultRequest = isVaultRequest,
shopperSessionId = shopperSessionId
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.robolectric.RobolectricTestRunner;
import org.skyscreamer.jsonassert.JSONAssert;

import java.util.Collections;

@RunWith(RobolectricTestRunner.class)
public class PayPalClientUnitTest {

Expand All @@ -44,11 +46,9 @@ public class PayPalClientUnitTest {
private PayPalPaymentAuthCallback paymentAuthCallback;

private MerchantRepository merchantRepository;
private AnalyticsParamRepository analyticsParamRepository;

@Before
public void beforeEach() throws JSONException {
analyticsParamRepository = mock(AnalyticsParamRepository.class);
activity = mock(FragmentActivity.class);
merchantRepository = mock(MerchantRepository.class);
payPalEnabledConfig = Configuration.fromJson(Fixtures.CONFIGURATION_WITH_LIVE_PAYPAL);
Expand All @@ -64,6 +64,7 @@ public void beforeEach() throws JSONException {
public void createPaymentAuthRequest_callsBackPayPalResponse_sendsStartedAnalytics() throws JSONException {
PayPalVaultRequest payPalVaultRequest = new PayPalVaultRequest(true);
payPalVaultRequest.setMerchantAccountId("sample-merchant-account-id");
payPalVaultRequest.setShopperSessionId("test-shopper-session-id");

PayPalPaymentAuthRequestParams paymentAuthRequest = new PayPalPaymentAuthRequestParams(
payPalVaultRequest,
Expand All @@ -80,7 +81,7 @@ public void createPaymentAuthRequest_callsBackPayPalResponse_sendsStartedAnalyti
BraintreeClient braintreeClient =
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalVaultRequest, paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand Down Expand Up @@ -108,7 +109,7 @@ public void createPaymentAuthRequest_callsBackPayPalResponse_sendsStartedAnalyti

verify(braintreeClient).sendAnalyticsEvent(
PayPalAnalytics.TOKENIZATION_STARTED,
new AnalyticsEventParams(null, null, true, null, null, null)
new AnalyticsEventParams(null, null, true, null, null, null, null, Collections.emptyList(), null, "test-shopper-session-id")
);
}

Expand All @@ -134,7 +135,7 @@ public void createPaymentAuthRequest_whenLaunchesBrowserSwitchAsNewTaskEnabled_s
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig)
.launchesBrowserSwitchAsNewTask(true).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalVaultRequest, paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand Down Expand Up @@ -169,7 +170,7 @@ public void createPaymentAuthRequest_setsAppLinkReturnUrl() {
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().configuration(payPalEnabledConfig)
.build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalVaultRequest, paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand All @@ -189,7 +190,7 @@ public void createPaymentAuthRequest_whenPayPalNotEnabled_returnsError() {
BraintreeClient braintreeClient =
new MockBraintreeClientBuilder().configuration(payPalDisabledConfig).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, new PayPalCheckoutRequest("1.00", true),
paymentAuthCallback);

Expand Down Expand Up @@ -218,7 +219,7 @@ public void createPaymentAuthRequest_whenCheckoutRequest_whenConfigError_forward
.configurationError(authError)
.build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, new PayPalCheckoutRequest("1.00", true), paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand All @@ -243,7 +244,7 @@ public void requestBillingAgreement_whenConfigError_forwardsErrorToListener() {
.configurationError(authError)
.build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, new PayPalVaultRequest(true), paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand All @@ -269,7 +270,7 @@ public void createPaymentAuthRequest_whenVaultRequest_sendsPayPalRequestViaInter

PayPalVaultRequest payPalRequest = new PayPalVaultRequest(true);

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalRequest, paymentAuthCallback);

verify(payPalInternalClient).sendRequest(same(activity), same(payPalRequest),
Expand All @@ -285,7 +286,7 @@ public void createPaymentAuthRequest_whenCheckoutRequest_sendsPayPalRequestViaIn

PayPalCheckoutRequest payPalRequest = new PayPalCheckoutRequest("1.00", true);

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalRequest, paymentAuthCallback);

verify(payPalInternalClient).sendRequest(same(activity), same(payPalRequest),
Expand Down Expand Up @@ -317,7 +318,7 @@ public void createPaymentAuthRequest_whenVaultRequest_sendsAppSwitchStartedEvent
BraintreeClient braintreeClient =
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);
sut.createPaymentAuthRequest(activity, payPalVaultRequest, paymentAuthCallback);

ArgumentCaptor<PayPalPaymentAuthRequest> captor =
Expand Down Expand Up @@ -362,7 +363,7 @@ public void tokenize_withBillingAgreement_tokenizesResponseOnSuccess() throws JS
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -406,7 +407,7 @@ public void tokenize_withOneTimePayment_tokenizesResponseOnSuccess() throws JSON
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -451,7 +452,7 @@ public void tokenize_whenCancelUriReceived_notifiesCancellationAndSendsAnalytics
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -491,7 +492,7 @@ public void tokenize_whenPayPalInternalClientTokenizeResult_callsBackResult()
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -533,7 +534,7 @@ public void tokenize_whenPayPalInternalClientTokenizeResult_sendsAppSwitchSuccee
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -572,7 +573,7 @@ public void tokenize_whenPayPalNotEnabled_sendsAppSwitchFailedEvents() throws JS
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand Down Expand Up @@ -604,7 +605,7 @@ public void tokenize_whenCancelUriReceived_sendsAppSwitchCanceledEvents()
PayPalPaymentAuthResult.Success payPalPaymentAuthResult = new PayPalPaymentAuthResult.Success(
browserSwitchResult);
BraintreeClient braintreeClient = new MockBraintreeClientBuilder().build();
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository);

sut.tokenize(payPalPaymentAuthResult, payPalTokenizeCallback);

Expand All @@ -618,60 +619,4 @@ public void tokenize_whenCancelUriReceived_sendsAppSwitchCanceledEvents()
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.BROWSER_LOGIN_CANCELED, params);
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.APP_SWITCH_CANCELED, params);
}

@Test
public void test_vaultRequest_shopperSessionId_sets_repository() throws JSONException {
PayPalVaultRequest payPalVaultRequest = new PayPalVaultRequest(true);

payPalVaultRequest.setShopperSessionId("test-shopper-id");

PayPalPaymentAuthRequestParams paymentAuthRequest = new PayPalPaymentAuthRequestParams(
payPalVaultRequest,
null,
"https://example.com/approval/url",
"sample-client-metadata-id",
null,
"https://example.com/success/url"
);

PayPalInternalClient payPalInternalClient =
new MockPayPalInternalClientBuilder().sendRequestSuccess(paymentAuthRequest)
.build();

BraintreeClient braintreeClient =
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
sut.createPaymentAuthRequest(activity, payPalVaultRequest, paymentAuthCallback);

verify(analyticsParamRepository).setSessionId("test-shopper-id");
}

@Test
public void test_checkoutRequest_shopperSessionId_sets_repository() throws JSONException {
PayPalCheckoutRequest request = new PayPalCheckoutRequest("2.00", true);

request.setShopperSessionId("test-shopper-id");

PayPalPaymentAuthRequestParams paymentAuthRequest = new PayPalPaymentAuthRequestParams(
request,
null,
"https://example.com/approval/url",
"sample-client-metadata-id",
null,
"https://example.com/success/url"
);

PayPalInternalClient payPalInternalClient =
new MockPayPalInternalClientBuilder().sendRequestSuccess(paymentAuthRequest)
.build();

BraintreeClient braintreeClient =
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig).build();

PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, analyticsParamRepository);
sut.createPaymentAuthRequest(activity, request, paymentAuthCallback);

verify(analyticsParamRepository).setSessionId("test-shopper-id");
}
}
Loading
Loading