diff --git a/CHANGELOG.md b/CHANGELOG.md
index af602afee7..370fe72000 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -149,6 +149,7 @@
* Move `ThreeDSecureInfo` to `three-d-secure` module
* Add `CardResult` object
* Change `CardTokenizeCallback` parameters
+ * Change `BinType` from String to enum
* SEPA Direct Debit
* Update package name to `com.braintreepayments.api.sepadirectdebit`
* Remove `SEPADirectDebitLifecycleObserver` and `SEPADirectDebitListener`
diff --git a/DataCollector/src/test/java/com/braintreepayments/api/datacollector/DataCollectorUnitTest.kt b/DataCollector/src/test/java/com/braintreepayments/api/datacollector/DataCollectorUnitTest.kt
index 4dea0d4354..64ac6ae4de 100644
--- a/DataCollector/src/test/java/com/braintreepayments/api/datacollector/DataCollectorUnitTest.kt
+++ b/DataCollector/src/test/java/com/braintreepayments/api/datacollector/DataCollectorUnitTest.kt
@@ -12,7 +12,6 @@ import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.slot
import io.mockk.verify
-import org.json.JSONException
import org.json.JSONObject
import org.junit.Assert
import org.junit.Before
@@ -26,7 +25,8 @@ class DataCollectorUnitTest {
@MockK
lateinit var context: Context
- @MockK lateinit var configuration: Configuration
+ @MockK
+ lateinit var configuration: Configuration
@MockK
lateinit var uuidHelper: UUIDHelper
@@ -48,7 +48,6 @@ class DataCollectorUnitTest {
.build()
@Before
- @Throws(JSONException::class)
fun beforeEach() {
MockKAnnotations.init(this, relaxed = true)
diff --git a/DataCollector/src/test/java/com/braintreepayments/api/datacollector/MagnesInternalClientUnitTest.kt b/DataCollector/src/test/java/com/braintreepayments/api/datacollector/MagnesInternalClientUnitTest.kt
index b47524eef3..38803dc868 100644
--- a/DataCollector/src/test/java/com/braintreepayments/api/datacollector/MagnesInternalClientUnitTest.kt
+++ b/DataCollector/src/test/java/com/braintreepayments/api/datacollector/MagnesInternalClientUnitTest.kt
@@ -73,14 +73,14 @@ class MagnesInternalClientUnitTest {
@Test
fun getClientMetaDataId_returnsEmptyStringWhenContextIsNull() {
- val sut = MagnesInternalClient(magnesSDK)
- val result = sut.getClientMetadataId(
- null, sandboxConfiguration,
- dataCollectorInternalRequest
- )
+ val sut = MagnesInternalClient(magnesSDK)
+ val result = sut.getClientMetadataId(
+ null, sandboxConfiguration,
+ dataCollectorInternalRequest
+ )
- Assert.assertEquals("", result)
- }
+ Assert.assertTrue(result.isEmpty())
+ }
@Throws(InvalidInputException::class)
@Test
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.java
deleted file mode 100644
index f258220dca..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-class CreateMandateResult {
-
- private final String approvalUrl;
- private final String ibanLastFour;
- private final String customerId;
- private final String bankReferenceToken;
- private final SEPADirectDebitMandateType mandateType;
-
- CreateMandateResult(String approvalUrl, String ibanLastFour, String customerId,
- String bankReferenceToken, String mandateType) {
- this.approvalUrl = approvalUrl;
- this.ibanLastFour = ibanLastFour;
- this.customerId = customerId;
- this.bankReferenceToken = bankReferenceToken;
- this.mandateType = SEPADirectDebitMandateType.fromString(mandateType);
- }
-
- String getApprovalUrl() {
- return approvalUrl;
- }
-
- String getIbanLastFour() {
- return ibanLastFour;
- }
-
- String getCustomerId() {
- return customerId;
- }
-
- String getBankReferenceToken() {
- return bankReferenceToken;
- }
-
- SEPADirectDebitMandateType getMandateType() {
- return mandateType;
- }
-
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.kt
new file mode 100644
index 0000000000..32b5fab4bc
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/CreateMandateResult.kt
@@ -0,0 +1,9 @@
+package com.braintreepayments.api.sepadirectdebit
+
+data class CreateMandateResult internal constructor(
+ val approvalUrl: String,
+ val ibanLastFour: String,
+ val customerId: String,
+ val bankReferenceToken: String,
+ val mandateType: SEPADirectDebitMandateType
+)
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.java
deleted file mode 100644
index 26fe6e7eab..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import com.braintreepayments.api.core.BraintreeClient;
-import com.braintreepayments.api.sharedutils.HttpResponseCallback;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-class SEPADirectDebitApi {
-
- private final BraintreeClient braintreeClient;
-
- SEPADirectDebitApi(BraintreeClient braintreeClient) {
- this.braintreeClient = braintreeClient;
- }
-
- void createMandate(SEPADirectDebitRequest sepaDirectDebitRequest, String returnUrlScheme,
- final CreateMandateCallback callback) {
- try {
- JSONObject jsonObject =
- buildCreateMandateRequest(sepaDirectDebitRequest, returnUrlScheme);
- String url = "v1/sepa_debit";
- braintreeClient.sendPOST(url, jsonObject.toString(), (responseBody, httpError) -> {
- if (responseBody != null) {
- try {
- CreateMandateResult result = parseCreateMandateResponse(responseBody);
- callback.onResult(result, null);
- } catch (JSONException e) {
- callback.onResult(null, e);
- }
- } else if (httpError != null) {
- callback.onResult(null, httpError);
- }
- });
- } catch (JSONException e) {
- callback.onResult(null, e);
- }
- }
-
- void tokenize(String ibanLastFour, String customerId, String bankReferenceToken,
- String mandateType, final SEPADirectDebitInternalTokenizeCallback callback) {
- try {
- JSONObject jsonObject =
- buildTokenizeRequest(ibanLastFour, customerId, bankReferenceToken, mandateType);
- String url = "v1/payment_methods/sepa_debit_accounts";
- braintreeClient.sendPOST(url, jsonObject.toString(), new HttpResponseCallback() {
-
- @Override
- public void onResult(String responseBody, Exception httpError) {
- if (responseBody != null) {
- try {
- SEPADirectDebitNonce nonce = parseTokenizeResponse(responseBody);
- callback.onResult(nonce, null);
- } catch (JSONException jsonException) {
- callback.onResult(null, jsonException);
- }
- } else if (httpError != null) {
- callback.onResult(null, httpError);
- }
- }
- });
- } catch (JSONException e) {
- callback.onResult(null, e);
- }
- }
-
- private SEPADirectDebitNonce parseTokenizeResponse(String responseBody) throws JSONException {
- JSONObject jsonResponse = new JSONObject(responseBody);
- return SEPADirectDebitNonce.fromJSON(jsonResponse);
- }
-
- private JSONObject buildTokenizeRequest(String ibanLastFour, String customerId,
- String bankReferenceToken, String mandateType)
- throws JSONException {
- JSONObject accountData = new JSONObject()
- .put("last_4", ibanLastFour)
- .put("merchant_or_partner_customer_id", customerId)
- .put("bank_reference_token", bankReferenceToken)
- .put("mandate_type", mandateType);
- JSONObject requestData = new JSONObject()
- .put("sepa_debit_account", accountData);
-
- return requestData;
- }
-
- private CreateMandateResult parseCreateMandateResponse(String responseBody)
- throws JSONException {
- JSONObject json = new JSONObject(responseBody);
- JSONObject sepaDebitAccount = json.getJSONObject("message").getJSONObject("body")
- .getJSONObject("sepaDebitAccount");
- String approvalUrl = sepaDebitAccount.getString("approvalUrl");
- String ibanLastFour = sepaDebitAccount.getString("last4");
- String customerId = sepaDebitAccount.getString("merchantOrPartnerCustomerId");
- String bankReferenceToken = sepaDebitAccount.getString("bankReferenceToken");
- String mandateType = sepaDebitAccount.getString("mandateType");
-
- return new CreateMandateResult(approvalUrl, ibanLastFour, customerId, bankReferenceToken,
- mandateType);
- }
-
- private JSONObject buildCreateMandateRequest(SEPADirectDebitRequest sepaDirectDebitRequest,
- String returnUrlScheme) throws JSONException {
- JSONObject sepaDebitData = new JSONObject()
- .putOpt("account_holder_name", sepaDirectDebitRequest.getAccountHolderName())
- .putOpt("merchant_or_partner_customer_id", sepaDirectDebitRequest.getCustomerId())
- .putOpt("iban", sepaDirectDebitRequest.getIban())
- .putOpt("mandate_type", sepaDirectDebitRequest.getMandateType().toString());
-
- if (sepaDirectDebitRequest.getBillingAddress() != null) {
- JSONObject billingAddress = new JSONObject()
- .putOpt("address_line_1",
- sepaDirectDebitRequest.getBillingAddress().getStreetAddress())
- .putOpt("address_line_2",
- sepaDirectDebitRequest.getBillingAddress().getExtendedAddress())
- .putOpt("admin_area_1",
- sepaDirectDebitRequest.getBillingAddress().getLocality())
- .putOpt("admin_area_2", sepaDirectDebitRequest.getBillingAddress().getRegion())
- .putOpt("postal_code",
- sepaDirectDebitRequest.getBillingAddress().getPostalCode())
- .putOpt("country_code",
- sepaDirectDebitRequest.getBillingAddress().getCountryCodeAlpha2());
-
- sepaDebitData.put("billing_address", billingAddress);
- }
-
- String cancelUrl = String.format("%s://sepa/cancel", returnUrlScheme);
- String successUrl = String.format("%s://sepa/success", returnUrlScheme);
-
- JSONObject requestData = new JSONObject()
- .put("sepa_debit", sepaDebitData)
- .put("cancel_url", cancelUrl)
- .put("return_url", successUrl);
-
- if (sepaDirectDebitRequest.getMerchantAccountId() != null) {
- requestData.putOpt("merchant_account_id",
- sepaDirectDebitRequest.getMerchantAccountId());
- }
-
- if (sepaDirectDebitRequest.getLocale() != null) {
- requestData.putOpt("locale", sepaDirectDebitRequest.getLocale());
- }
-
- return requestData;
- }
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.kt
new file mode 100644
index 0000000000..e7a6c3d6d8
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApi.kt
@@ -0,0 +1,174 @@
+package com.braintreepayments.api.sepadirectdebit
+
+import com.braintreepayments.api.core.BraintreeClient
+import com.braintreepayments.api.sepadirectdebit.SEPADirectDebitNonce.Companion.fromJSON
+import org.json.JSONException
+import org.json.JSONObject
+
+internal class SEPADirectDebitApi(private val braintreeClient: BraintreeClient) {
+
+ fun createMandate(
+ sepaDirectDebitRequest: SEPADirectDebitRequest,
+ returnUrlScheme: String,
+ callback: CreateMandateCallback
+ ) {
+ try {
+ val jsonObject =
+ buildCreateMandateRequest(sepaDirectDebitRequest, returnUrlScheme)
+ val url = "v1/sepa_debit"
+ braintreeClient.sendPOST(
+ url,
+ jsonObject.toString()
+ ) { responseBody, httpError ->
+ if (responseBody != null) {
+ try {
+ val result = parseCreateMandateResponse(responseBody)
+ callback.onResult(result, null)
+ } catch (e: JSONException) {
+ callback.onResult(null, e)
+ }
+ } else if (httpError != null) {
+ callback.onResult(null, httpError)
+ }
+ }
+ } catch (e: JSONException) {
+ callback.onResult(null, e)
+ }
+ }
+
+ fun tokenize(
+ ibanLastFour: String,
+ customerId: String,
+ bankReferenceToken: String,
+ mandateType: String,
+ callback: SEPADirectDebitInternalTokenizeCallback
+ ) {
+ try {
+ val jsonObject =
+ buildTokenizeRequest(ibanLastFour, customerId, bankReferenceToken, mandateType)
+ val url = "v1/payment_methods/sepa_debit_accounts"
+ braintreeClient.sendPOST(
+ url,
+ jsonObject.toString()
+ ) { responseBody, httpError ->
+ if (responseBody != null) {
+ try {
+ val nonce = parseTokenizeResponse(responseBody)
+ callback.onResult(nonce, null)
+ } catch (jsonException: JSONException) {
+ callback.onResult(null, jsonException)
+ }
+ } else if (httpError != null) {
+ callback.onResult(null, httpError)
+ }
+ }
+ } catch (e: JSONException) {
+ callback.onResult(null, e)
+ }
+ }
+
+ @Throws(JSONException::class)
+ private fun parseTokenizeResponse(responseBody: String): SEPADirectDebitNonce {
+ val jsonResponse = JSONObject(responseBody)
+ return fromJSON(jsonResponse)
+ }
+
+ @Throws(JSONException::class)
+ private fun buildTokenizeRequest(
+ ibanLastFour: String, customerId: String,
+ bankReferenceToken: String, mandateType: String
+ ): JSONObject {
+ val accountData = JSONObject()
+ .put("last_4", ibanLastFour)
+ .put("merchant_or_partner_customer_id", customerId)
+ .put("bank_reference_token", bankReferenceToken)
+ .put("mandate_type", mandateType)
+ val requestData = JSONObject()
+ .put("sepa_debit_account", accountData)
+
+ return requestData
+ }
+
+ @Throws(JSONException::class)
+ private fun parseCreateMandateResponse(responseBody: String): CreateMandateResult {
+ val json = JSONObject(responseBody)
+ val sepaDebitAccount = json.getJSONObject("message").getJSONObject("body")
+ .getJSONObject("sepaDebitAccount")
+ val approvalUrl = sepaDebitAccount.getString("approvalUrl")
+ val ibanLastFour = sepaDebitAccount.getString("last4")
+ val customerId = sepaDebitAccount.getString("merchantOrPartnerCustomerId")
+ val bankReferenceToken = sepaDebitAccount.getString("bankReferenceToken")
+ val mandateType = sepaDebitAccount.getString("mandateType")
+
+ return CreateMandateResult(
+ approvalUrl,
+ ibanLastFour,
+ customerId,
+ bankReferenceToken,
+ SEPADirectDebitMandateType.valueOf(mandateType)
+ )
+ }
+
+ @Throws(JSONException::class)
+ private fun buildCreateMandateRequest(
+ sepaDirectDebitRequest: SEPADirectDebitRequest,
+ returnUrlScheme: String
+ ): JSONObject {
+ val sepaDebitData = JSONObject()
+ .putOpt("account_holder_name", sepaDirectDebitRequest.accountHolderName)
+ .putOpt("merchant_or_partner_customer_id", sepaDirectDebitRequest.customerId)
+ .putOpt("iban", sepaDirectDebitRequest.iban)
+ .putOpt("mandate_type", sepaDirectDebitRequest.mandateType.toString())
+
+ val requestBillingAddress = sepaDirectDebitRequest.billingAddress
+ if (requestBillingAddress != null) {
+ val billingAddress = JSONObject()
+ .putOpt(
+ "address_line_1",
+ requestBillingAddress.streetAddress
+ )
+ .putOpt(
+ "address_line_2",
+ requestBillingAddress.extendedAddress
+ )
+ .putOpt(
+ "admin_area_1",
+ requestBillingAddress.locality
+ )
+ .putOpt("admin_area_2",
+ requestBillingAddress.region
+ )
+ .putOpt(
+ "postal_code",
+ requestBillingAddress.postalCode
+ )
+ .putOpt(
+ "country_code",
+ requestBillingAddress.countryCodeAlpha2
+ )
+
+ sepaDebitData.put("billing_address", billingAddress)
+ }
+
+ val cancelUrl = "$returnUrlScheme://sepa/cancel"
+ val successUrl = "$returnUrlScheme://sepa/success"
+
+ val requestData = JSONObject()
+ .put("sepa_debit", sepaDebitData)
+ .put("cancel_url", cancelUrl)
+ .put("return_url", successUrl)
+
+ if (sepaDirectDebitRequest.merchantAccountId != null) {
+ requestData.putOpt(
+ "merchant_account_id",
+ sepaDirectDebitRequest.merchantAccountId
+ )
+ }
+
+ if (sepaDirectDebitRequest.locale != null) {
+ requestData.putOpt("locale", sepaDirectDebitRequest.locale)
+ }
+
+ return requestData
+ }
+}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.java
deleted file mode 100644
index 78ccbab259..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.webkit.URLUtil;
-
-import androidx.activity.ComponentActivity;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import com.braintreepayments.api.BrowserSwitchFinalResult;
-import com.braintreepayments.api.BrowserSwitchOptions;
-import com.braintreepayments.api.core.BraintreeClient;
-import com.braintreepayments.api.core.BraintreeException;
-import com.braintreepayments.api.core.BraintreeRequestCodes;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Used to integrate with SEPA Direct Debit.
- */
-public class SEPADirectDebitClient {
-
- private static final String IBAN_LAST_FOUR_KEY = "ibanLastFour";
- private static final String CUSTOMER_ID_KEY = "customerId";
- private static final String BANK_REFERENCE_TOKEN_KEY = "bankReferenceToken";
- private static final String MANDATE_TYPE_KEY = "mandateType";
-
- private final SEPADirectDebitApi sepaDirectDebitApi;
- private final BraintreeClient braintreeClient;
-
- /**
- * Initializes a new {@link SEPADirectDebitClient} instance
- *
- * @param context an Android Context
- * @param authorization a Tokenization Key or Client Token used to authenticate
- * @param returnUrlScheme a custom return url to use for browser and app switching
- */
- public SEPADirectDebitClient(
- @NonNull Context context,
- @NonNull String authorization,
- @Nullable String returnUrlScheme
- ) {
- this(new BraintreeClient(context, authorization, returnUrlScheme));
- }
-
- @VisibleForTesting
- SEPADirectDebitClient(@NonNull BraintreeClient braintreeClient) {
- this(braintreeClient, new SEPADirectDebitApi(braintreeClient));
- }
-
- @VisibleForTesting
- SEPADirectDebitClient(BraintreeClient braintreeClient, SEPADirectDebitApi sepaDirectDebitApi) {
- this.braintreeClient = braintreeClient;
- this.sepaDirectDebitApi = sepaDirectDebitApi;
- }
-
- /**
- * Starts the SEPA tokenization process by creating a {@link SEPADirectDebitPaymentAuthRequestParams} to be used
- * to launch the SEPA mandate flow in
- * {@link SEPADirectDebitLauncher#launch(ComponentActivity, SEPADirectDebitPaymentAuthRequest.ReadyToLaunch)}
- *
- * @param sepaDirectDebitRequest {@link SEPADirectDebitRequest}
- * @param callback {@link SEPADirectDebitPaymentAuthRequestCallback}
- */
- public void createPaymentAuthRequest(@NonNull final SEPADirectDebitRequest sepaDirectDebitRequest,
- @NonNull final SEPADirectDebitPaymentAuthRequestCallback callback) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_STARTED);
- sepaDirectDebitApi.createMandate(sepaDirectDebitRequest,
- braintreeClient.getReturnUrlScheme(),
- (result, createMandateError) -> {
- if (result != null) {
- if (URLUtil.isValidUrl(result.getApprovalUrl())) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_CHALLENGE_REQUIRED);
- try {
- SEPADirectDebitPaymentAuthRequestParams params =
- new SEPADirectDebitPaymentAuthRequestParams(buildBrowserSwitchOptions(result));
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED);
- callback.onSEPADirectDebitPaymentAuthResult(new SEPADirectDebitPaymentAuthRequest.ReadyToLaunch(params));
- } catch (JSONException exception) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED);
- callbackCreatePaymentAuthFailure(callback, new SEPADirectDebitPaymentAuthRequest.Failure(exception));
- }
- } else if (result.getApprovalUrl().equals("null")) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED);
- // Mandate has already been approved
- sepaDirectDebitApi.tokenize(result.getIbanLastFour(),
- result.getCustomerId(), result.getBankReferenceToken(),
- result.getMandateType().toString(),
- (sepaDirectDebitNonce, tokenizeError) -> {
- if (sepaDirectDebitNonce != null) {
- callbackCreatePaymentAuthChallengeNotRequiredSuccess(callback, new SEPADirectDebitPaymentAuthRequest.LaunchNotRequired(sepaDirectDebitNonce));
- } else if (tokenizeError != null) {
- callbackCreatePaymentAuthFailure(callback, new SEPADirectDebitPaymentAuthRequest.Failure(tokenizeError));
- }
- });
- } else {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED);
- callbackCreatePaymentAuthFailure(callback, new SEPADirectDebitPaymentAuthRequest.Failure(new BraintreeException("An unexpected error occurred.")));
- }
- } else if (createMandateError != null) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED);
- callbackCreatePaymentAuthFailure(callback,
- new SEPADirectDebitPaymentAuthRequest.Failure(createMandateError));
- }
- });
- }
-
- // TODO: - The wording in this docstring is confusing to me. Let's improve & align across all clients.
- /**
- * After receiving a result from the SEPA mandate web flow via
- * {@link SEPADirectDebitLauncher#handleReturnToAppFromBrowser(SEPADirectDebitPendingRequest.Started, Intent)} , pass the
- * {@link SEPADirectDebitPaymentAuthResult.Success} returned to this method to tokenize the SEPA
- * account and receive a {@link SEPADirectDebitNonce} on success.
- *
- * @param paymentAuthResult a {@link SEPADirectDebitPaymentAuthResult.Success} received from
- * {@link SEPADirectDebitLauncher#handleReturnToAppFromBrowser(SEPADirectDebitPendingRequest.Started, Intent)}
- * @param callback {@link SEPADirectDebitInternalTokenizeCallback}
- */
- public void tokenize(@NonNull SEPADirectDebitPaymentAuthResult.Success paymentAuthResult,
- @NonNull final SEPADirectDebitTokenizeCallback callback) {
- BrowserSwitchFinalResult.Success browserSwitchResult =
- paymentAuthResult.getPaymentAuthInfo().getBrowserSwitchSuccess();
-
- Uri deepLinkUri = browserSwitchResult.getReturnUrl();
- if (deepLinkUri != null) {
- if (deepLinkUri.getPath().contains("success") &&
- deepLinkUri.getQueryParameter("success").equals("true")) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_SUCCEEDED);
- JSONObject metadata = browserSwitchResult.getRequestMetadata();
- String ibanLastFour = metadata.optString(IBAN_LAST_FOUR_KEY);
- String customerId = metadata.optString(CUSTOMER_ID_KEY);
- String bankReferenceToken = metadata.optString(BANK_REFERENCE_TOKEN_KEY);
- String mandateType = metadata.optString(MANDATE_TYPE_KEY);
-
- sepaDirectDebitApi.tokenize(ibanLastFour, customerId, bankReferenceToken,
- mandateType,
- (sepaDirectDebitNonce, error) -> {
- if (sepaDirectDebitNonce != null) {
- callbackTokenizeSuccess(callback, new SEPADirectDebitResult.Success(sepaDirectDebitNonce));
- } else if (error != null) {
- callbackTokenizeFailure(callback, new SEPADirectDebitResult.Failure(error));
- }
- });
- } else if (deepLinkUri.getPath().contains("cancel")) {
- callbackTokenizeCancel(callback);
- }
- } else {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_FAILED);
- callbackTokenizeFailure(callback, new SEPADirectDebitResult.Failure(new BraintreeException("Unknown error")));
- }
- }
-
- private void callbackCreatePaymentAuthFailure(SEPADirectDebitPaymentAuthRequestCallback callback, SEPADirectDebitPaymentAuthRequest.Failure result) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
- callback.onSEPADirectDebitPaymentAuthResult(result);
- }
-
- private void callbackCreatePaymentAuthChallengeNotRequiredSuccess(SEPADirectDebitPaymentAuthRequestCallback callback, SEPADirectDebitPaymentAuthRequest.LaunchNotRequired result) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED);
- callback.onSEPADirectDebitPaymentAuthResult(result);
- }
-
- private void callbackTokenizeCancel(SEPADirectDebitTokenizeCallback callback) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_CANCELED);
- callback.onSEPADirectDebitResult(SEPADirectDebitResult.Cancel.INSTANCE);
- }
-
- private void callbackTokenizeFailure(SEPADirectDebitTokenizeCallback callback, SEPADirectDebitResult.Failure result) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
- callback.onSEPADirectDebitResult(result);
- }
-
- private void callbackTokenizeSuccess(SEPADirectDebitTokenizeCallback callback, SEPADirectDebitResult.Success result) {
- braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED);
- callback.onSEPADirectDebitResult(result);
- }
-
- private BrowserSwitchOptions buildBrowserSwitchOptions(CreateMandateResult createMandateResult) throws JSONException {
- JSONObject metadata = new JSONObject()
- .put(IBAN_LAST_FOUR_KEY, createMandateResult.getIbanLastFour())
- .put(CUSTOMER_ID_KEY, createMandateResult.getCustomerId())
- .put(BANK_REFERENCE_TOKEN_KEY, createMandateResult.getBankReferenceToken())
- .put(MANDATE_TYPE_KEY, createMandateResult.getMandateType().toString());
-
- BrowserSwitchOptions browserSwitchOptions = new BrowserSwitchOptions()
- .requestCode(BraintreeRequestCodes.SEPA_DEBIT.getCode())
- .url(Uri.parse(createMandateResult.getApprovalUrl()))
- .metadata(metadata)
- .returnUrlScheme(braintreeClient.getReturnUrlScheme());
-
- return browserSwitchOptions;
- }
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.kt
new file mode 100644
index 0000000000..cbf3c42562
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClient.kt
@@ -0,0 +1,223 @@
+package com.braintreepayments.api.sepadirectdebit
+
+import android.content.Context
+import android.net.Uri
+import android.webkit.URLUtil
+import androidx.annotation.VisibleForTesting
+import com.braintreepayments.api.BrowserSwitchFinalResult
+import com.braintreepayments.api.BrowserSwitchOptions
+import com.braintreepayments.api.core.BraintreeClient
+import com.braintreepayments.api.core.BraintreeException
+import com.braintreepayments.api.core.BraintreeRequestCodes
+import org.json.JSONException
+import org.json.JSONObject
+
+/**
+ * Used to integrate with SEPA Direct Debit.
+ */
+class SEPADirectDebitClient @VisibleForTesting internal constructor(
+ private val braintreeClient: BraintreeClient,
+ private val sepaDirectDebitApi: SEPADirectDebitApi = SEPADirectDebitApi(braintreeClient)
+) {
+ /**
+ * Initializes a new [SEPADirectDebitClient] instance
+ *
+ * @param context an Android Context
+ * @param authorization a Tokenization Key or Client Token used to authenticate
+ * @param returnUrlScheme a custom return url to use for browser and app switching
+ */
+ constructor(
+ context: Context,
+ authorization: String,
+ returnUrlScheme: String?
+ ) : this(BraintreeClient(context, authorization, returnUrlScheme))
+
+ /**
+ * Starts the SEPA tokenization process by creating a [SEPADirectDebitPaymentAuthRequestParams] to be used
+ * to launch the SEPA mandate flow in
+ * [SEPADirectDebitLauncher.launch]
+ *
+ * @param sepaDirectDebitRequest [SEPADirectDebitRequest]
+ * @param callback [SEPADirectDebitPaymentAuthRequestCallback]
+ */
+ fun createPaymentAuthRequest(
+ sepaDirectDebitRequest: SEPADirectDebitRequest,
+ callback: SEPADirectDebitPaymentAuthRequestCallback
+ ) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_STARTED)
+ sepaDirectDebitApi.createMandate(
+ sepaDirectDebitRequest,
+ braintreeClient.getReturnUrlScheme()
+ ) { result, createMandateError ->
+ if (result != null) {
+ if (URLUtil.isValidUrl(result.approvalUrl)) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_CHALLENGE_REQUIRED)
+ try {
+ val params = SEPADirectDebitPaymentAuthRequestParams(buildBrowserSwitchOptions(result))
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED)
+ callback.onSEPADirectDebitPaymentAuthResult(
+ SEPADirectDebitPaymentAuthRequest.ReadyToLaunch(params)
+ )
+ } catch (exception: JSONException) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED)
+ callbackCreatePaymentAuthFailure(
+ callback,
+ SEPADirectDebitPaymentAuthRequest.Failure(exception)
+ )
+ }
+ } else if (result.approvalUrl == "null") {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED)
+ // Mandate has already been approved
+ sepaDirectDebitApi.tokenize(
+ ibanLastFour = result.ibanLastFour,
+ customerId = result.customerId,
+ bankReferenceToken = result.bankReferenceToken,
+ mandateType = result.mandateType.toString()
+ ) { sepaDirectDebitNonce, error ->
+ if (sepaDirectDebitNonce != null) {
+ callbackCreatePaymentAuthChallengeNotRequiredSuccess(
+ callback,
+ SEPADirectDebitPaymentAuthRequest.LaunchNotRequired(sepaDirectDebitNonce)
+ )
+ } else if (error != null) {
+ callbackCreatePaymentAuthFailure(
+ callback,
+ SEPADirectDebitPaymentAuthRequest.Failure(error)
+ )
+ }
+ }
+ } else {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED)
+ callbackCreatePaymentAuthFailure(
+ callback,
+ SEPADirectDebitPaymentAuthRequest.Failure(BraintreeException("An unexpected error occurred."))
+ )
+ }
+ } else if (createMandateError != null) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED)
+ callbackCreatePaymentAuthFailure(
+ callback,
+ SEPADirectDebitPaymentAuthRequest.Failure(createMandateError)
+ )
+ }
+ }
+ }
+
+ // TODO: - The wording in this docstring is confusing to me. Let's improve & align across all clients.
+ /**
+ * After receiving a result from the SEPA mandate web flow via
+ * [SEPADirectDebitLauncher.handleReturnToAppFromBrowser] , pass the
+ * [SEPADirectDebitPaymentAuthResult.Success] returned to this method to tokenize the SEPA
+ * account and receive a [SEPADirectDebitNonce] on success.
+ *
+ * @param paymentAuthResult a [SEPADirectDebitPaymentAuthResult.Success] received from
+ * [SEPADirectDebitLauncher.handleReturnToAppFromBrowser]
+ * @param callback [SEPADirectDebitInternalTokenizeCallback]
+ */
+ fun tokenize(
+ paymentAuthResult: SEPADirectDebitPaymentAuthResult.Success,
+ callback: SEPADirectDebitTokenizeCallback
+ ) {
+ val browserSwitchResult: BrowserSwitchFinalResult.Success =
+ paymentAuthResult.paymentAuthInfo.browserSwitchSuccess
+
+ val deepLinkUri: Uri = browserSwitchResult.returnUrl
+ if (deepLinkUri != null) {
+ if (deepLinkUri.path?.contains("success") == true && deepLinkUri.getQueryParameter("success") == "true") {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_SUCCEEDED)
+ val metadata: JSONObject? = browserSwitchResult.requestMetadata
+ if (metadata != null) {
+ val ibanLastFour = metadata.optString(IBAN_LAST_FOUR_KEY)
+ val customerId = metadata.optString(CUSTOMER_ID_KEY)
+ val bankReferenceToken = metadata.optString(BANK_REFERENCE_TOKEN_KEY)
+ val mandateType = metadata.optString(MANDATE_TYPE_KEY)
+
+ sepaDirectDebitApi.tokenize(
+ ibanLastFour = ibanLastFour,
+ customerId = customerId,
+ bankReferenceToken = bankReferenceToken,
+ mandateType = mandateType
+ ) { sepaDirectDebitNonce, error ->
+ if (sepaDirectDebitNonce != null) {
+ callbackTokenizeSuccess(
+ callback,
+ SEPADirectDebitResult.Success(sepaDirectDebitNonce)
+ )
+ } else if (error != null) {
+ callbackTokenizeFailure(callback, SEPADirectDebitResult.Failure(error))
+ }
+ }
+ }
+ } else if (deepLinkUri.path!!.contains("cancel")) {
+ callbackTokenizeCancel(callback)
+ }
+ } else {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_FAILED)
+ callbackTokenizeFailure(
+ callback,
+ SEPADirectDebitResult.Failure(BraintreeException("Unknown error"))
+ )
+ }
+ }
+
+ private fun callbackCreatePaymentAuthFailure(
+ callback: SEPADirectDebitPaymentAuthRequestCallback,
+ result: SEPADirectDebitPaymentAuthRequest.Failure
+ ) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED)
+ callback.onSEPADirectDebitPaymentAuthResult(result)
+ }
+
+ private fun callbackCreatePaymentAuthChallengeNotRequiredSuccess(
+ callback: SEPADirectDebitPaymentAuthRequestCallback,
+ result: SEPADirectDebitPaymentAuthRequest.LaunchNotRequired
+ ) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED)
+ callback.onSEPADirectDebitPaymentAuthResult(result)
+ }
+
+ private fun callbackTokenizeCancel(callback: SEPADirectDebitTokenizeCallback) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_CANCELED)
+ callback.onSEPADirectDebitResult(SEPADirectDebitResult.Cancel)
+ }
+
+ private fun callbackTokenizeFailure(
+ callback: SEPADirectDebitTokenizeCallback,
+ result: SEPADirectDebitResult.Failure
+ ) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED)
+ callback.onSEPADirectDebitResult(result)
+ }
+
+ private fun callbackTokenizeSuccess(
+ callback: SEPADirectDebitTokenizeCallback,
+ result: SEPADirectDebitResult.Success
+ ) {
+ braintreeClient.sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED)
+ callback.onSEPADirectDebitResult(result)
+ }
+
+ @Throws(JSONException::class)
+ private fun buildBrowserSwitchOptions(createMandateResult: CreateMandateResult): BrowserSwitchOptions {
+ val metadata = JSONObject()
+ .put(IBAN_LAST_FOUR_KEY, createMandateResult.ibanLastFour)
+ .put(CUSTOMER_ID_KEY, createMandateResult.customerId)
+ .put(BANK_REFERENCE_TOKEN_KEY, createMandateResult.bankReferenceToken)
+ .put(MANDATE_TYPE_KEY, createMandateResult.mandateType.toString())
+
+ val browserSwitchOptions = BrowserSwitchOptions()
+ .requestCode(BraintreeRequestCodes.SEPA_DEBIT.code)
+ .url(Uri.parse(createMandateResult.approvalUrl))
+ .metadata(metadata)
+ .returnUrlScheme(braintreeClient.getReturnUrlScheme())
+
+ return browserSwitchOptions
+ }
+
+ companion object {
+ private const val IBAN_LAST_FOUR_KEY = "ibanLastFour"
+ private const val CUSTOMER_ID_KEY = "customerId"
+ private const val BANK_REFERENCE_TOKEN_KEY = "bankReferenceToken"
+ private const val MANDATE_TYPE_KEY = "mandateType"
+ }
+}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitInternalTokenizeCallback.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitInternalTokenizeCallback.kt
index 91272f7241..783e4e2744 100644
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitInternalTokenizeCallback.kt
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitInternalTokenizeCallback.kt
@@ -1,5 +1,5 @@
package com.braintreepayments.api.sepadirectdebit
-internal interface SEPADirectDebitInternalTokenizeCallback {
+internal fun interface SEPADirectDebitInternalTokenizeCallback {
fun onResult(sepaDirectDebitNonce: SEPADirectDebitNonce?, error: Exception?)
}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.java
deleted file mode 100644
index 350aa1fd4f..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import androidx.annotation.NonNull;
-
-/**
- * Mandate type for the SEPA Direct Debit request.
- */
-public enum SEPADirectDebitMandateType {
- RECURRENT("RECURRENT"),
- ONE_OFF("ONE_OFF")
- ;
-
- private final String mandateType;
-
- SEPADirectDebitMandateType(final String mandateType) {
- this.mandateType = mandateType;
- }
-
- static SEPADirectDebitMandateType fromString(String mandateType) {
- switch (mandateType) {
- case "RECURRENT":
- return SEPADirectDebitMandateType.RECURRENT;
- case "ONE_OFF":
- return SEPADirectDebitMandateType.ONE_OFF;
- default:
- return null;
- }
- }
-
- @NonNull
- @Override
- public String toString() {
- return mandateType;
- }
-}
\ No newline at end of file
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.kt
new file mode 100644
index 0000000000..bd0f767829
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitMandateType.kt
@@ -0,0 +1,9 @@
+package com.braintreepayments.api.sepadirectdebit
+
+/**
+ * Mandate type for the SEPA Direct Debit request.
+ */
+enum class SEPADirectDebitMandateType {
+ RECURRENT,
+ ONE_OFF
+}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitNonce.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitNonce.kt
index 30af2064f7..dab826d0a5 100644
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitNonce.kt
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitNonce.kt
@@ -44,7 +44,7 @@ class SEPADirectDebitNonce internal constructor(
if (details != null) {
ibanLastFour = details.optString(IBAN_LAST_FOUR_KEY)
customerId = details.optString(CUSTOMER_ID_KEY)
- mandateType = SEPADirectDebitMandateType.fromString(
+ mandateType = SEPADirectDebitMandateType.valueOf(
details.optString(MANDATE_TYPE_KEY)
)
}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.java
deleted file mode 100644
index 71f2a5cd80..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import androidx.fragment.app.FragmentActivity;
-
-import com.braintreepayments.api.BrowserSwitchOptions;
-
-/**
- * Returned via the {@link SEPADirectDebitPaymentAuthRequestCallback} after calling
- * {@link SEPADirectDebitClient#createPaymentAuthRequest(SEPADirectDebitRequest, SEPADirectDebitPaymentAuthRequestCallback)}.
- *
- * Inspect the {@link SEPADirectDebitNonce} property to determine if tokenization is complete, or
- * if you must continue the SEPA mandate web flow via
- * {@link SEPADirectDebitLauncher#launch(FragmentActivity, SEPADirectDebitPaymentAuthRequest.ReadyToLaunch)}
- */
-public class SEPADirectDebitPaymentAuthRequestParams {
-
- private BrowserSwitchOptions browserSwitchOptions;
-
- SEPADirectDebitPaymentAuthRequestParams(BrowserSwitchOptions browserSwitchOptions) {
- this.browserSwitchOptions = browserSwitchOptions;
- }
-
- BrowserSwitchOptions getBrowserSwitchOptions() {
- return browserSwitchOptions;
- }
-
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.kt
new file mode 100644
index 0000000000..01c0b794ff
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthRequestParams.kt
@@ -0,0 +1,13 @@
+package com.braintreepayments.api.sepadirectdebit
+
+import com.braintreepayments.api.BrowserSwitchOptions
+
+/**
+ * Returned via the [SEPADirectDebitPaymentAuthRequestCallback] after calling
+ * [SEPADirectDebitClient.createPaymentAuthRequest].
+ *
+ * Inspect the [SEPADirectDebitNonce] property to determine if tokenization is complete, or
+ * if you must continue the SEPA mandate web flow via
+ * [SEPADirectDebitLauncher.launch]
+ */
+class SEPADirectDebitPaymentAuthRequestParams internal constructor(val browserSwitchOptions: BrowserSwitchOptions)
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.java
deleted file mode 100644
index 42ace64de4..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import com.braintreepayments.api.BrowserSwitchFinalResult;
-
-/**
- * Details of a {@link SEPADirectDebitPaymentAuthResult.Success}
- */
-public class SEPADirectDebitPaymentAuthResultInfo {
-
- private BrowserSwitchFinalResult.Success browserSwitchSuccess;
-
- SEPADirectDebitPaymentAuthResultInfo(BrowserSwitchFinalResult.Success browserSwitchSuccess) {
- this.browserSwitchSuccess = browserSwitchSuccess;
- }
-
- BrowserSwitchFinalResult.Success getBrowserSwitchSuccess() {
- return browserSwitchSuccess;
- }
-
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.kt
new file mode 100644
index 0000000000..c224b663a3
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitPaymentAuthResultInfo.kt
@@ -0,0 +1,10 @@
+package com.braintreepayments.api.sepadirectdebit
+
+import com.braintreepayments.api.BrowserSwitchFinalResult
+
+/**
+ * Details of a [SEPADirectDebitPaymentAuthResult.Success]
+ */
+data class SEPADirectDebitPaymentAuthResultInfo(
+ val browserSwitchSuccess: BrowserSwitchFinalResult.Success
+)
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.java b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.java
deleted file mode 100644
index ad47800ca6..0000000000
--- a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.braintreepayments.api.sepadirectdebit;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.braintreepayments.api.core.PostalAddress;
-
-/**
- * Parameters for creating a SEPA Direct Debit tokenization request.
- */
-public class SEPADirectDebitRequest {
-
- private String accountHolderName;
- private String iban;
- private String customerId;
- private SEPADirectDebitMandateType mandateType = SEPADirectDebitMandateType.ONE_OFF;
- private PostalAddress billingAddress;
- private String merchantAccountId;
- private String locale;
-
- /**
- * @return The account holder name
- */
- @Nullable
- public String getAccountHolderName() {
- return accountHolderName;
- }
-
- /**
- * Required.
- * @param accountHolderName The account holder name.
- */
- public void setAccountHolderName(@Nullable String accountHolderName) {
- this.accountHolderName = accountHolderName;
- }
-
- /**
- * @return The full IBAN.
- */
- @Nullable
- public String getIban() {
- return iban;
- }
-
- /**
- * Required.
- * @param iban The full IBAN.
- */
- public void setIban(@Nullable String iban) {
- this.iban = iban;
- }
-
- /**
- * @return The customer ID.
- */
- @Nullable
- public String getCustomerId() {
- return customerId;
- }
-
- /**
- * Required.
- * @param customerId The customer ID.
- */
- public void setCustomerId(@Nullable String customerId) {
- this.customerId = customerId;
- }
-
- /**
- * @return The {@link SEPADirectDebitMandateType}.
- */
- @NonNull
- public SEPADirectDebitMandateType getMandateType() {
- return mandateType;
- }
-
- /**
- * Optional. If not set, defaults to ONE_OFF.
- * @param mandateType The {@link SEPADirectDebitMandateType}.
- */
- public void setMandateType(@NonNull SEPADirectDebitMandateType mandateType) {
- this.mandateType = mandateType;
- }
-
- /**
- * @return The user's billing address.
- */
- @Nullable
- public PostalAddress getBillingAddress() {
- return billingAddress;
- }
-
- /**
- * Required.
- * @param billingAddress The user's billing address.
- */
- public void setBillingAddress(@Nullable PostalAddress billingAddress) {
- this.billingAddress = billingAddress;
- }
-
- /**
- * @return A non-default merchant account to use for tokenization.
- */
- @Nullable
- public String getMerchantAccountId() {
- return merchantAccountId;
- }
-
- /**
- * Optional.
- * @param merchantAccountId A non-default merchant account to use for tokenization.
- */
- public void setMerchantAccountId(@Nullable String merchantAccountId) {
- this.merchantAccountId = merchantAccountId;
- }
-
- /**
- * @return A locale code to use for creating a mandate.
- */
- @Nullable
- public String getLocale() {
- return locale;
- }
-
- /**
- * Optional.
- * @param locale A locale code to use for creating a mandate.
- *
- * @see Documentation
- * for possible values. Locale code should be supplied as a BCP-47 formatted locale code.
- */
- public void setLocale(@Nullable String locale) {
- this.locale = locale;
- }
-}
diff --git a/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.kt b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.kt
new file mode 100644
index 0000000000..2a801662f4
--- /dev/null
+++ b/SEPADirectDebit/src/main/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitRequest.kt
@@ -0,0 +1,27 @@
+package com.braintreepayments.api.sepadirectdebit
+
+import com.braintreepayments.api.core.PostalAddress
+
+/**
+ * Parameters for creating a SEPA Direct Debit tokenization request.
+ *
+ * @property accountHolderName The account holder name.
+ * @property iban The full IBAN.
+ * @property customerId The customer ID.
+ * @property mandateType The [SEPADirectDebitMandateType].
+ * @property billingAddress The user's billing address.
+ * @property merchantAccountId A non-default merchant account to use for tokenization.
+ * Optional.
+ * @property locale A locale code to use for creating a mandate.
+ * @see [Documentation](https://developer.paypal.com/reference/locale-codes/)
+ * for possible values. Locale code should be supplied as a BCP-47 formatted locale code.
+ */
+data class SEPADirectDebitRequest internal constructor(
+ var accountHolderName: String? = null,
+ var iban: String? = null,
+ var customerId: String? = null,
+ var mandateType: SEPADirectDebitMandateType = SEPADirectDebitMandateType.ONE_OFF,
+ var billingAddress: PostalAddress? = null,
+ var merchantAccountId: String? = null,
+ var locale: String? = null
+)
diff --git a/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApiUnitTest.java b/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApiUnitTest.java
index ef1a362a6d..798d3e4556 100644
--- a/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApiUnitTest.java
+++ b/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitApiUnitTest.java
@@ -183,8 +183,12 @@ public void createMandate_properlyFormatsPOSTBody() throws JSONException {
sut.createMandate(request, returnUrl, createMandateCallback);
ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
- verify(mockBraintreeClient).sendPOST(eq("v1/sepa_debit"), String.valueOf(captor.capture()),
- any(HttpResponseCallback.class));
+ verify(mockBraintreeClient).sendPOST(
+ eq("v1/sepa_debit"),
+ captor.capture(),
+ any(),
+ any(HttpResponseCallback.class)
+ );
String result = captor.getValue();
JSONObject json = new JSONObject(result);
diff --git a/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClientUnitTest.java b/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClientUnitTest.java
index 8e3cb9a25a..a403dc1149 100644
--- a/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClientUnitTest.java
+++ b/SEPADirectDebit/src/test/java/com/braintreepayments/api/sepadirectdebit/SEPADirectDebitClientUnitTest.java
@@ -46,7 +46,7 @@ public void beforeEach() {
"1234",
"fake-customer-id",
"fake-bank-reference-token",
- "ONE_OFF"
+ SEPADirectDebitMandateType.valueOf("ONE_OFF")
);
sepaDirectDebitRequest = new SEPADirectDebitRequest();
@@ -65,7 +65,7 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_callsBackSEPA
new SEPADirectDebitClient(braintreeClient, sepaDirectDebitApi);
sut.createPaymentAuthRequest(sepaDirectDebitRequest, paymentAuthRequestCallback);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_STARTED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_STARTED), any());
ArgumentCaptor captor =
ArgumentCaptor.forClass(SEPADirectDebitPaymentAuthRequest.class);
@@ -75,8 +75,8 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_callsBackSEPA
assertTrue(paymentAuthRequest instanceof SEPADirectDebitPaymentAuthRequest.ReadyToLaunch);
SEPADirectDebitPaymentAuthRequestParams params = ((SEPADirectDebitPaymentAuthRequest.ReadyToLaunch) paymentAuthRequest).getRequestParams();
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_CHALLENGE_REQUIRED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED), any());
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CREATE_MANDATE_CHALLENGE_REQUIRED), any());
BrowserSwitchOptions browserSwitchOptions = params.getBrowserSwitchOptions();
assertEquals(Uri.parse("http://www.example.com"), browserSwitchOptions.getUrl());
@@ -98,7 +98,7 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenMandateAl
"1234",
"fake-customer-id",
"fake-bank-reference-token",
- "ONE_OFF"
+ SEPADirectDebitMandateType.valueOf("ONE_OFF")
);
SEPADirectDebitNonce nonce = SEPADirectDebitNonce.fromJSON(
@@ -120,7 +120,7 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenMandateAl
SEPADirectDebitPaymentAuthRequest paymentAuthRequest = captor.getValue();
assertTrue(paymentAuthRequest instanceof SEPADirectDebitPaymentAuthRequest.LaunchNotRequired);
assertEquals(((SEPADirectDebitPaymentAuthRequest.LaunchNotRequired) paymentAuthRequest).getNonce(), nonce);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED), any());
}
@Test
@@ -130,7 +130,7 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenApprovalU
"1234",
"fake-customer-id",
"fake-bank-reference-token",
- "ONE_OFF"
+ SEPADirectDebitMandateType.valueOf("ONE_OFF")
);
SEPADirectDebitApi sepaDirectDebitApi = new MockSEPADirectDebitApiBuilder()
@@ -150,8 +150,8 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenApprovalU
Exception error = ((SEPADirectDebitPaymentAuthRequest.Failure) paymentAuthRequest).getError();
assertTrue(error instanceof BraintreeException);
assertEquals("An unexpected error occurred.", error.getMessage());
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED), any());
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_FAILED), any());
}
@Test
@@ -161,7 +161,7 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenApprovalU
"1234",
"fake-customer-id",
"fake-bank-reference-token",
- "ONE_OFF"
+ SEPADirectDebitMandateType.valueOf("ONE_OFF")
);
SEPADirectDebitApi sepaDirectDebitApi = new MockSEPADirectDebitApiBuilder()
@@ -172,8 +172,8 @@ public void createPaymentAuthRequest_onCreateMandateRequestSuccess_whenApprovalU
new SEPADirectDebitClient(braintreeClient, sepaDirectDebitApi);
sut.createPaymentAuthRequest(sepaDirectDebitRequest, paymentAuthRequestCallback);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_STARTED);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_STARTED), any());
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CREATE_MANDATE_SUCCEEDED), any());
verify(sepaDirectDebitApi).tokenize(eq("1234"), eq("fake-customer-id"),
eq("fake-bank-reference-token"), eq("ONE_OFF"),
any(SEPADirectDebitInternalTokenizeCallback.class));
@@ -197,8 +197,8 @@ public void createPaymentAuthRequest_onCreateMandateError_returnsErrorToListener
assertTrue(paymentAuthRequest instanceof SEPADirectDebitPaymentAuthRequest.Failure);
Exception actualError = ((SEPADirectDebitPaymentAuthRequest.Failure) paymentAuthRequest).getError();
assertEquals(error, actualError);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CREATE_MANDATE_FAILED), any());
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_FAILED), any());
}
@@ -232,7 +232,7 @@ public void tokenize_whenDeepLinkContainsSuccess_callsTokenize_andSendsAnalytics
verify(sepaDirectDebitApi).tokenize(eq("1234"), eq("customer-id"),
eq("bank-reference-token"), eq("ONE_OFF"),
any(SEPADirectDebitInternalTokenizeCallback.class));
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_SUCCEEDED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CHALLENGE_SUCCEEDED), any());
}
@Test
@@ -272,7 +272,7 @@ public void tokenize_onTokenizeSuccess_callsBackNonce_andSendsAnalytics()
SEPADirectDebitResult result = captor.getValue();
assertTrue(result instanceof SEPADirectDebitResult.Success);
assertEquals(nonce, ((SEPADirectDebitResult.Success) result).getNonce());
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_SUCCEEDED), any());
}
@Test
@@ -311,7 +311,7 @@ public void tokenize_onTokenizeFailure_callsBackError_andSendsAnalytics()
SEPADirectDebitResult result = captor.getValue();
assertTrue(result instanceof SEPADirectDebitResult.Failure);
assertEquals(exception, ((SEPADirectDebitResult.Failure) result).getError());
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_FAILED), any());
verify(sepaDirectDebitApi).tokenize(eq("1234"), eq("customer-id"),
eq("bank-reference-token"), eq("ONE_OFF"),
any(SEPADirectDebitInternalTokenizeCallback.class));
@@ -380,7 +380,7 @@ public void tokenize_whenDeepLinkContainsCancel_callsBackError_andSendsAnalytics
SEPADirectDebitResult result = captor.getValue();
assertTrue(result instanceof SEPADirectDebitResult.Cancel);
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.CHALLENGE_CANCELED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.CHALLENGE_CANCELED), any());
}
@Test
@@ -409,6 +409,6 @@ public void tokenize_whenDeepLinkURLIsNull_returnsErrorToListener() {
Exception exception = ((SEPADirectDebitResult.Failure) result).getError();
assertTrue(exception instanceof BraintreeException);
assertEquals("Unknown error", exception.getMessage());
- verify(braintreeClient).sendAnalyticsEvent(SEPADirectDebitAnalytics.TOKENIZE_FAILED);
+ verify(braintreeClient).sendAnalyticsEvent(eq(SEPADirectDebitAnalytics.TOKENIZE_FAILED), any());
}
}