/** * Starts the Billing Agreement flow for PayPal. This will launch the PayPal app if installed or * fall back to a browser switch. * * @param fragment A {@link BraintreeFragment} used to process the request. * @param request A {@link PayPalRequest} used to customize the request. */ public static void requestBillingAgreement(BraintreeFragment fragment, PayPalRequest request) { requestBillingAgreement(fragment, request, null); }
public void launchBillingAgreement(View v) { setProgressBarIndeterminateVisibility(true); PayPal.requestBillingAgreement(mBraintreeFragment, getPayPalRequest(null)); }
@Test public void requestBillingAgreement_postsExceptionWhenAmountIsIncluded() { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest("1")); ArgumentCaptor<Exception> captor = ArgumentCaptor.forClass(Exception.class); verify(fragment).postCallback(captor.capture()); assertTrue(captor.getValue() instanceof BraintreeException); assertEquals("There must be no amount specified for the Billing Agreement flow", captor.getValue().getMessage()); }
@Test public void requestBillingAgreement_whenMerchantAccountIdNotPresent_postsDoNotIncludeMerchantAccountId() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPalRequest request = new PayPalRequest(); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); assertFalse(json.has("merchant_account_id")); }
@Test public void requestBillingAgreement_whenMerchantAccountIdPresent_postsParamsIncludeMerchantAccountId() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPalRequest request = new PayPalRequest() .merchantAccountId("merchant_account_id"); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); String merchantAccountId = json.getString("merchant_account_id"); assertEquals("merchant_account_id", merchantAccountId); }
@Test public void requestBillingAgreement_containsOfferPayPalCreditParam() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest().offerCredit(true)); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(contains("/paypal_hermes/setup_billing_agreement"), dataCaptor.capture(), any(HttpResponseCallback.class)); JSONObject json = new JSONObject(dataCaptor.getValue()); assertTrue(json.getBoolean("offer_paypal_credit")); }
@Test public void requestBillingAgreement_defaultPostParamsIncludeCorrectValues() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(contains("/paypal_hermes/setup_billing_agreement"), dataCaptor.capture(), any(HttpResponseCallback.class)); JSONObject expected = new JSONObject() .put("client_key", "authorization") .put("return_url", "com.braintreepayments.api.braintree://onetouch/v1/success") .put("cancel_url", "com.braintreepayments.api.braintree://onetouch/v1/cancel") .put("experience_profile", new JSONObject() .put("address_override", false) .put("brand_name", "displayName") .put("no_shipping", true)) .put("offer_paypal_credit", false); JSONObject actual = new JSONObject(dataCaptor.getValue()); JSONAssert.assertEquals(expected, actual, true); }
@Test public void requestBillingAgreement_startsBrowser() throws InvalidArgumentException { BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_billing_agreement_response.json")) .build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(fragment).browserSwitch(eq(BraintreeRequestCodes.PAYPAL), captor.capture()); Intent intent = captor.getValue(); assertEquals(Intent.ACTION_VIEW, intent.getAction()); assertEquals("checkout.paypal.com", intent.getData().getHost()); assertEquals("/one-touch-login-sandbox/index.html", intent.getData().getPath()); assertEquals("create_payment_resource", intent.getData().getQueryParameter("action")); assertEquals("63cc461306c35080ce674a3372bffe1580b4130c7fd33d33968aa76bb93cdd06|created_at=2015-10-13T18:49:48.371382792+0000&merchant_id=dcpspy2brwdjr3qn&public_key=9wwrzqk3vr3t4nc8", intent.getData().getQueryParameter("authorization_fingerprint")); assertFalse(intent.getData().getQueryParameterNames().contains("amount")); assertFalse(intent.getData().getQueryParameterNames().contains("currency_iso_code")); assertEquals("false", intent.getData().getQueryParameter("experience_profile[address_override]")); assertEquals("false", intent.getData().getQueryParameter("experience_profile[no_shipping]")); assertEquals("dcpspy2brwdjr3qn", intent.getData().getQueryParameter("merchant_id")); assertEquals("com.braintreepayments.api.test.braintree://onetouch/v1/success", intent.getData().getQueryParameter("return_url")); assertEquals("com.braintreepayments.api.test.braintree://onetouch/v1/cancel", intent.getData().getQueryParameter("cancel_url")); }
@Test public void requestBillingAgreement_startsBrowserWithPayPalCredit() { BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_billing_agreement_response.json")) .build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest().offerCredit(true)); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(fragment).browserSwitch(eq(BraintreeRequestCodes.PAYPAL), captor.capture()); Intent intent = captor.getValue(); assertEquals(Intent.ACTION_VIEW, intent.getAction()); assertEquals("checkout.paypal.com", intent.getData().getHost()); assertEquals("/one-touch-login-sandbox/index.html", intent.getData().getPath()); assertEquals("create_payment_resource", intent.getData().getQueryParameter("action")); assertEquals("63cc461306c35080ce674a3372bffe1580b4130c7fd33d33968aa76bb93cdd06|created_at=2015-10-13T18:49:48.371382792+0000&merchant_id=dcpspy2brwdjr3qn&public_key=9wwrzqk3vr3t4nc8", intent.getData().getQueryParameter("authorization_fingerprint")); assertFalse(intent.getData().getQueryParameterNames().contains("amount")); assertEquals("true", intent.getData().getQueryParameter("offer_paypal_credit")); assertFalse(intent.getData().getQueryParameterNames().contains("currency_iso_code")); assertEquals("false", intent.getData().getQueryParameter("experience_profile[address_override]")); assertEquals("false", intent.getData().getQueryParameter("experience_profile[no_shipping]")); assertEquals("dcpspy2brwdjr3qn", intent.getData().getQueryParameter("merchant_id")); assertEquals("com.braintreepayments.api.test.braintree://onetouch/v1/success", intent.getData().getQueryParameter("return_url")); assertEquals("com.braintreepayments.api.test.braintree://onetouch/v1/cancel", intent.getData().getQueryParameter("cancel_url")); }
@Test public void requestBillingAgreement_whenShippingRequiredFalse_postsNoShippingFalse() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PostalAddress address = new PostalAddress() .streetAddress("123 Fake St.") .extendedAddress("Apt. v.0") .locality("Oakland") .region("CA") .postalCode("12345") .countryCodeAlpha2("US"); PayPalRequest request = new PayPalRequest(); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); JSONObject experienceProfile = json.getJSONObject("experience_profile"); assertEquals(true, experienceProfile.get("no_shipping")); }
@Test public void requestBillingAgreement_postParamsIncludeAddress() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PostalAddress address = new PostalAddress() .streetAddress("123 Fake St.") .extendedAddress("Apt. v.0") .locality("Oakland") .region("CA") .postalCode("12345") .countryCodeAlpha2("US"); PayPalRequest request = new PayPalRequest() .shippingAddressRequired(true) .shippingAddressOverride(address); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); JSONObject shippingAddress = json.getJSONObject("shipping_address"); assertEquals("123 Fake St.", shippingAddress.get("line1")); assertEquals("Apt. v.0", shippingAddress.get("line2")); assertEquals("Oakland", shippingAddress.get("city")); assertEquals("CA", shippingAddress.get("state")); assertEquals("12345", shippingAddress.get("postal_code")); assertEquals("US", shippingAddress.get("country_code")); } @Test
@Test public void requestBillingAgreement_whenEditableFalse_postsAddressOverrideTrue() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PostalAddress address = new PostalAddress() .streetAddress("123 Fake St.") .extendedAddress("Apt. v.0") .locality("Oakland") .region("CA") .postalCode("12345") .countryCodeAlpha2("US"); PayPalRequest request = new PayPalRequest() .shippingAddressOverride(address); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); JSONObject shippingAddress = json.getJSONObject("shipping_address"); JSONObject experienceProfile = json.getJSONObject("experience_profile"); assertTrue(shippingAddress.length() > 0); assertEquals(true, experienceProfile.get("address_override")); }
@Test public void requestBillingAgreement_whenEditable_postsAddressOverrideFalse() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PostalAddress address = new PostalAddress() .streetAddress("123 Fake St.") .extendedAddress("Apt. v.0") .locality("Oakland") .region("CA") .postalCode("12345") .countryCodeAlpha2("US"); PayPalRequest request = new PayPalRequest() .shippingAddressEditable(true) .shippingAddressOverride(address); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); JSONObject shippingAddress = json.getJSONObject("shipping_address"); JSONObject experienceProfile = json.getJSONObject("experience_profile"); assertTrue(shippingAddress.length() > 0); assertEquals(false, experienceProfile.get("address_override")); }
@Test public void requestBillingAgreement_whenShippingRequired_postsNoShippingTrue() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PostalAddress address = new PostalAddress() .streetAddress("123 Fake St.") .extendedAddress("Apt. v.0") .locality("Oakland") .region("CA") .postalCode("12345") .countryCodeAlpha2("US"); PayPalRequest request = new PayPalRequest() .shippingAddressRequired(true); PayPal.requestBillingAgreement(fragment, request); ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); verify(fragment.getHttpClient()).post(pathCaptor.capture(), dataCaptor.capture(), any(HttpResponseCallback.class)); assertTrue(pathCaptor.getValue().contains("/paypal_hermes/setup_billing_agreement")); JSONObject json = new JSONObject(dataCaptor.getValue()); JSONObject experienceProfile = json.getJSONObject("experience_profile"); assertEquals(false, experienceProfile.get("no_shipping")); }
@Test public void requestBillingAgreement_sendsPayPalCreditOfferedAnalyticsEvent() throws JSONException { BraintreeFragment fragment = mMockFragmentBuilder.build(); PayPal.requestBillingAgreement(fragment, new PayPalRequest().offerCredit(true)); verify(fragment).sendAnalyticsEvent("paypal.billing-agreement.credit.offered"); }
@Test public void requestBillingAgreement_cancelUrlTriggersCancelListener() { final BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_response.json")) .build(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Intent intent = new Intent() .setData(Uri.parse("com.braintreepayments.api.test.braintree://onetouch/v1/cancel")); PayPal.onActivityResult(fragment, Activity.RESULT_OK, intent); return null; } }).when(fragment).browserSwitch(eq(BraintreeRequestCodes.PAYPAL), any(Intent.class)); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); verify(fragment).postCancelCallback(BraintreeRequestCodes.PAYPAL); }
@Test public void requestBillingAgreement_doesNotCallCancelListenerWhenSuccessful() { final BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_response.json")) .build(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Intent intent = new Intent() .setData(Uri.parse("com.braintreepayments.api.test.braintree://onetouch/v1/success?PayerID=HERMES-SANDBOX-PAYER-ID&paymentId=HERMES-SANDBOX-PAYMENT-ID&ba_token=EC-HERMES-SANDBOX-EC-TOKEN")); PayPal.onActivityResult(fragment, Activity.RESULT_OK, intent); return null; } }).when(fragment).startActivity(any(Intent.class)); mockStatic(TokenizationClient.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { ((PaymentMethodNonceCallback) invocation.getArguments()[2]).success(new PayPalAccountNonce()); return null; } }).when(TokenizationClient.class); TokenizationClient.tokenize(any(BraintreeFragment.class), any(PaymentMethodBuilder.class), any(PaymentMethodNonceCallback.class)); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); verify(fragment, never()).postCancelCallback(anyInt()); }
@Test public void requestBillingAgreement_isSuccessful() { final BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_billing_agreement_response.json")) .build(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Intent intent = new Intent() .setData(Uri.parse("com.braintreepayments.api.test.braintree://onetouch/v1/success?PayerID=HERMES-SANDBOX-PAYER-ID&paymentId=HERMES-SANDBOX-PAYMENT-ID&ba_token=EC-HERMES-SANDBOX-EC-TOKEN")); PayPal.onActivityResult(fragment, Activity.RESULT_OK, intent); return null; } }).when(fragment).browserSwitch(eq(BraintreeRequestCodes.PAYPAL), any(Intent.class)); mockStatic(TokenizationClient.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { ((PaymentMethodNonceCallback) invocation.getArguments()[2]).success(new PayPalAccountNonce()); return null; } }).when(TokenizationClient.class); TokenizationClient.tokenize(any(BraintreeFragment.class), any(PaymentMethodBuilder.class), any(PaymentMethodNonceCallback.class)); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); verify(fragment).postCallback(any(PayPalAccountNonce.class)); }
@Test public void requestBillingAgreement_whenSuccessful_sendsAnalyticsEvents() { final BraintreeFragment fragment = mMockFragmentBuilder .successResponse(stringFromFixture("paypal_hermes_billing_agreement_response.json")) .build(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Intent intent = new Intent() .setData(Uri.parse("com.braintreepayments.api.test.braintree://onetouch/v1/success?PayerID=HERMES-SANDBOX-PAYER-ID&paymentId=HERMES-SANDBOX-PAYMENT-ID&ba_token=EC-HERMES-SANDBOX-EC-TOKEN")); PayPal.onActivityResult(fragment, Activity.RESULT_OK, intent); return null; } }).when(fragment).browserSwitch(eq(BraintreeRequestCodes.PAYPAL), any(Intent.class)); mockStatic(TokenizationClient.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { ((PaymentMethodNonceCallback) invocation.getArguments()[2]).success(new PayPalAccountNonce()); return null; } }).when(TokenizationClient.class); TokenizationClient.tokenize(any(BraintreeFragment.class), any(PaymentMethodBuilder.class), any(PaymentMethodNonceCallback.class)); PayPal.requestBillingAgreement(fragment, new PayPalRequest()); verify(fragment).sendAnalyticsEvent("paypal.billing-agreement.selected"); verify(fragment).sendAnalyticsEvent("paypal-billing-agreement.webswitch.started"); verify(fragment).sendAnalyticsEvent("paypal-billing-agreement.webswitch.succeeded"); }
@Override public void onConfigurationFetched(Configuration configuration) { if (!configuration.isPayPalEnabled()) { fragment.postCallback(new BraintreeException("PayPal is not enabled")); return; } if (!isManifestValid(fragment)) { fragment.sendAnalyticsEvent("paypal.invalid-manifest"); fragment.postCallback(new BraintreeException("BraintreeBrowserSwitchActivity missing, " + "incorrectly configured in AndroidManifest.xml or another app defines the same browser " + "switch url as this app. See " + "https://developers.braintreepayments.com/guides/client-sdk/android/v2#browser-switch " + "for the correct configuration")); return; } if (configuration.getPayPal().shouldUseBillingAgreement() && !sFuturePaymentsOverride) { requestBillingAgreement(fragment, new PayPalRequest()); return; } fragment.sendAnalyticsEvent("paypal.future-payments.selected"); AuthorizationRequest request = getAuthorizationRequest(fragment); if (additionalScopes != null) { for (String scope : additionalScopes) { request.withScopeValue(scope); } } startPayPal(fragment, request, null); } });