diff --git a/core/src/main/java/com/hyperwallet/android/Hyperwallet.java b/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
index d0eecf36..0dac0141 100644
--- a/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
+++ b/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
@@ -307,6 +307,34 @@ public void updateBankCard(@NonNull final HyperwalletBankCard bankCard,
performRestTransaction(builder, listener);
}
+ /**
+ * Updates the {@link PayPalAccount} for the User associated with the authentication token returned from
+ * {@link HyperwalletAuthenticationTokenProvider#retrieveAuthenticationToken(HyperwalletAuthenticationTokenListener)}.
+ *
+ *
To identify the {@code PayPalAccount} that is going to be updated, the transfer method token must be
+ * set as part of the {@code PayPalAccount} object passed in.
+ *
+ * The {@link HyperwalletListener} that is passed in to this method invocation will receive the responses from
+ * processing the request.
+ *
+ * This function will requests a new authentication token via {@link HyperwalletAuthenticationTokenProvider}
+ * if the current one is expired or about to expire.
+ *
+ * @param payPalAccount the {@code PayPalAccount} to be created; must not be null
+ * @param listener the callback handler of responses from the Hyperwallet platform; must not be null
+ */
+ public void updatePayPalAccount(@NonNull final PayPalAccount payPalAccount,
+ @NonNull final HyperwalletListener listener) {
+ PathFormatter pathFormatter = new PathFormatter("users/{0}/paypal-accounts/{1}",
+ payPalAccount.getField(HyperwalletTransferMethod.TransferMethodFields.TOKEN));
+
+ RestTransaction.Builder builder = new RestTransaction.Builder<>(PUT, pathFormatter,
+ new TypeReference() {
+ }, listener).jsonModel(payPalAccount);
+
+ performRestTransaction(builder, listener);
+ }
+
/**
* Deactivates the {@link HyperwalletBankAccount} linked to the transfer method token specified. The
* {@code HyperwalletBankAccount} being deactivated must belong to the User that is associated with the
diff --git a/core/src/main/java/com/hyperwallet/android/model/PayPalAccount.java b/core/src/main/java/com/hyperwallet/android/model/PayPalAccount.java
index c658316c..59c84d5a 100644
--- a/core/src/main/java/com/hyperwallet/android/model/PayPalAccount.java
+++ b/core/src/main/java/com/hyperwallet/android/model/PayPalAccount.java
@@ -42,7 +42,7 @@
public class PayPalAccount extends HyperwalletTransferMethod {
/**
- * Constructor to build bank card, based on json object
+ * Constructor to build PayPal Account, based on json object
*/
public PayPalAccount(@NonNull JSONObject jsonObject) throws JSONException {
super(jsonObject);
diff --git a/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java b/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
index 27b1182e..efd821d2 100644
--- a/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
+++ b/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
@@ -13,6 +13,7 @@
import com.hyperwallet.android.transfermethod.HyperwalletRetrieveTransferMethodConfigurationKeysTest;
import com.hyperwallet.android.transfermethod.HyperwalletUpdateBankAccountTest;
import com.hyperwallet.android.transfermethod.HyperwalletUpdateBankCardTest;
+import com.hyperwallet.android.transfermethod.HyperwalletUpdatePayPalAccountTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -27,6 +28,7 @@
HyperwalletGetBankCardTest.class,
HyperwalletUpdateBankAccountTest.class,
HyperwalletUpdateBankCardTest.class,
+ HyperwalletUpdatePayPalAccountTest.class,
HyperwalletDeactivateBankAccountTest.class,
HyperwalletDeactivateBankCardTest.class,
HyperwalletListTransferMethodsTest.class,
diff --git a/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletUpdatePayPalAccountTest.java b/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletUpdatePayPalAccountTest.java
new file mode 100644
index 00000000..004331e2
--- /dev/null
+++ b/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletUpdatePayPalAccountTest.java
@@ -0,0 +1,147 @@
+package com.hyperwallet.android.transfermethod;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.CREATED_ON;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.EMAIL;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.STATUS;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TOKEN;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT;
+
+import com.hyperwallet.android.Hyperwallet;
+import com.hyperwallet.android.exception.HyperwalletException;
+import com.hyperwallet.android.exception.HyperwalletRestException;
+import com.hyperwallet.android.listener.HyperwalletListener;
+import com.hyperwallet.android.model.HyperwalletError;
+import com.hyperwallet.android.model.HyperwalletErrors;
+import com.hyperwallet.android.model.PayPalAccount;
+import com.hyperwallet.android.rule.HyperwalletExternalResourceManager;
+import com.hyperwallet.android.rule.HyperwalletMockWebServer;
+import com.hyperwallet.android.rule.HyperwalletSdkMock;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.net.HttpURLConnection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.mockwebserver.RecordedRequest;
+
+@RunWith(RobolectricTestRunner.class)
+public class HyperwalletUpdatePayPalAccountTest {
+ @Rule
+ public HyperwalletMockWebServer mServer = new HyperwalletMockWebServer();
+ @Rule
+ public HyperwalletSdkMock mSdkMock = new HyperwalletSdkMock(mServer);
+ @Rule
+ public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager();
+ @Rule
+ public MockitoRule mMockito = MockitoJUnit.rule();
+
+ @Mock
+ private HyperwalletListener mListener;
+
+ @Captor
+ private ArgumentCaptor mPayPalAccountCaptor;
+ @Captor
+ private ArgumentCaptor mExceptionCaptor;
+
+ private final CountDownLatch mAwait = new CountDownLatch(1);
+
+ @Test
+ public void testUpdatePayPalAccount_withSuccess() throws InterruptedException {
+ String responseBody = mExternalResourceManager.getResourceContent("paypal_account_update_response.json");
+ mServer.mockResponse().withHttpResponseCode(HttpURLConnection.HTTP_OK).withBody(responseBody).mock();
+
+ final PayPalAccount payPalAccount = new PayPalAccount
+ .Builder()
+ .email("jsmith2@paypal.com")
+ .token("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b")
+ .build();
+
+ assertThat(payPalAccount.getField(EMAIL), is("jsmith2@paypal.com"));
+ assertThat(payPalAccount.getField(TOKEN), is("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b"));
+
+ Hyperwallet.getDefault().updatePayPalAccount(payPalAccount, mListener);
+ mAwait.await(50, TimeUnit.MILLISECONDS);
+
+ RecordedRequest recordedRequest = mServer.getRequest();
+ verify(mListener).onSuccess(mPayPalAccountCaptor.capture());
+ verify(mListener, never()).onFailure(any(HyperwalletException.class));
+
+ PayPalAccount payPalAccountResponse = mPayPalAccountCaptor.getValue();
+ assertThat(payPalAccountResponse, is(notNullValue()));
+
+ assertThat(recordedRequest.getPath(),
+ is("/rest/v3/users/usr-fbfd5848-60d0-43c5-8462-099c959b49c7/paypal-accounts/trm-ac5727ac-8fe7-42fb"
+ + "-b69d-977ebdd7b48b"));
+
+ assertThat(payPalAccountResponse.getField(TOKEN), is("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b"));
+ assertThat(payPalAccountResponse.getField(STATUS), is("ACTIVATED"));
+ assertThat(payPalAccountResponse.getField(TYPE), is(PAYPAL_ACCOUNT));
+ assertThat(payPalAccountResponse.getField(EMAIL), is("jsmith2@paypal.com"));
+ assertThat(payPalAccountResponse.getField(TRANSFER_METHOD_CURRENCY), is("USD"));
+ assertThat(payPalAccountResponse.getField(TRANSFER_METHOD_COUNTRY), is("US"));
+ assertThat(payPalAccountResponse.getField(CREATED_ON), is("2019-01-09T22:50:14"));
+ }
+
+ @Test
+ public void testUpdatePayPalAccount_withValidationError() throws InterruptedException {
+
+ String responseBody = mExternalResourceManager.getResourceContentError(
+ "paypal_account_update_error_response.json");
+ mServer.mockResponse().withHttpResponseCode(HttpURLConnection.HTTP_BAD_REQUEST).withBody(responseBody).mock();
+
+ final PayPalAccount payPalAccount = new PayPalAccount
+ .Builder()
+ .email("00G0G1ema.com")
+ .token("trm-56b976c5-26b2-42fa-87cf-14b3366673c6")
+ .build();
+
+ assertThat(payPalAccount.getField(EMAIL), is("00G0G1ema.com"));
+ assertThat(payPalAccount.getField(TOKEN),
+ is("trm-56b976c5-26b2-42fa-87cf-14b3366673c6"));
+
+ Hyperwallet.getDefault().updatePayPalAccount(payPalAccount, mListener);
+ mAwait.await(50, TimeUnit.MILLISECONDS);
+
+ RecordedRequest recordedRequest = mServer.getRequest();
+ verify(mListener, never()).onSuccess(any(PayPalAccount.class));
+ verify(mListener).onFailure(mExceptionCaptor.capture());
+
+ HyperwalletException hyperwalletException = mExceptionCaptor.getValue();
+ assertThat(hyperwalletException, is(notNullValue()));
+ assertThat(((HyperwalletRestException) hyperwalletException).getHttpCode(),
+ is(HttpURLConnection.HTTP_BAD_REQUEST));
+
+ assertThat(recordedRequest.getPath(),
+ is("/rest/v3/users/usr-fbfd5848-60d0-43c5-8462-099c959b49c7/paypal-accounts/trm-56b976c5-26b2-42fa-87cf"
+ + "-14b3366673c6"));
+
+ HyperwalletErrors hyperwalletErrors = hyperwalletException.getHyperwalletErrors();
+ assertThat(hyperwalletErrors, is(notNullValue()));
+ assertThat(hyperwalletErrors.getErrors(), hasSize(1));
+
+ HyperwalletError hyperwalletError1 = hyperwalletErrors.getErrors().get(0);
+ assertThat(hyperwalletError1.getCode(), is("CONSTRAINT_VIOLATIONS"));
+ assertThat(hyperwalletError1.getFieldName(), is("email"));
+ assertThat(hyperwalletError1.getMessage(), is("Invalid Email"));
+ }
+}
diff --git a/core/src/test/resources/errors/paypal_account_update_error_response.json b/core/src/test/resources/errors/paypal_account_update_error_response.json
new file mode 100644
index 00000000..408baab1
--- /dev/null
+++ b/core/src/test/resources/errors/paypal_account_update_error_response.json
@@ -0,0 +1,9 @@
+{
+ "errors": [
+ {
+ "message": "Invalid Email",
+ "fieldName": "email",
+ "code": "CONSTRAINT_VIOLATIONS"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/src/test/resources/paypal_account_update_response.json b/core/src/test/resources/paypal_account_update_response.json
new file mode 100644
index 00000000..a157c0a0
--- /dev/null
+++ b/core/src/test/resources/paypal_account_update_response.json
@@ -0,0 +1,17 @@
+{
+ "token": "trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b",
+ "type": "PAYPAL_ACCOUNT",
+ "status": "ACTIVATED",
+ "createdOn": "2019-01-09T22:50:14",
+ "transferMethodCountry": "US",
+ "transferMethodCurrency": "USD",
+ "email": "jsmith2@paypal.com",
+ "links": [
+ {
+ "params": {
+ "rel": "self"
+ },
+ "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-c4292f1a-866f-4310-a289-b916853939de/paypal-accounts/trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b"
+ }
+ ]
+}
\ No newline at end of file