diff --git a/src/main/java/com/adyen/model/recurring/StoreTokenRequest.java b/src/main/java/com/adyen/model/recurring/StoreTokenRequest.java new file mode 100644 index 000000000..a68f7fd29 --- /dev/null +++ b/src/main/java/com/adyen/model/recurring/StoreTokenRequest.java @@ -0,0 +1,262 @@ +/** + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############ ##### ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2017 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ +package com.adyen.model.recurring; + +import com.adyen.model.Card; +import com.adyen.model.recurring.Recurring; +import com.google.gson.annotations.SerializedName; + +/** + * StoreTokenRequest - This type contains data that should be passed in either prepareStoreToken or storeToken calls. + */ +public class StoreTokenRequest { + + @SerializedName("card") + private Card card; + + @SerializedName("merchantAccount") + private String merchantAccount; + + @SerializedName("pspEchoData") + private String pspEchoData; + + @SerializedName("recurring") + private Recurring recurring; + + @SerializedName("selectedBrand") + private String selectedBrand; + + @SerializedName("shopperEmail") + private String shopperEmail; + + @SerializedName("shopperIP") + private String shopperIP; + + @SerializedName("shopperReference") + private String shopperReference; + + @SerializedName("shopperStatement") + private String shopperStatement; + + /** + * A container for card data. + * + * @return card + */ + public Card getCard() { + return card; + } + + public void setCard(Card card) { + this.card = card; + } + + public StoreTokenRequest card(Card card) { + this.card = card; + return this; + } + + /** + * The merchant account identifier you want to process the (transaction) request with. + * + * @return merchantAccount + */ + public String getMerchantAccount() { + return merchantAccount; + } + + public void setMerchantAccount(String merchantAccount) { + this.merchantAccount = merchantAccount; + } + + public StoreTokenRequest merchantAccount(String merchantAccount) { + this.merchantAccount = merchantAccount; + return this; + } + + /** + * The pspEchoData value received in the prepareStoreToken response. + * + * @return pspEchoData + */ + public String getPspEchoData() { + return pspEchoData; + } + + public void setPspEchoData(String pspEchoData) { + this.pspEchoData = pspEchoData; + } + + public StoreTokenRequest pspEchoData(String pspEchoData) { + this.pspEchoData = pspEchoData; + return this; + } + + /** + * A container for the type of recurring contract to be retrieved. The recurring.contract must be set to "RECURRING". + * + * @return recurring + */ + public Recurring getRecurring() { + return recurring; + } + + public void setRecurring(Recurring recurring) { + this.recurring = recurring; + } + + public StoreTokenRequest recurring(Recurring recurring) { + this.recurring = recurring; + return this; + } + + /** + * Some payment methods require defining a value for this field to specify how to process the transaction. + * + * @return selectedBrand + */ + public String getSelectedBrand() { + return selectedBrand; + } + + public void setSelectedBrand(String selectedBrand) { + this.selectedBrand = selectedBrand; + } + + public StoreTokenRequest selectedBrand(String selectedBrand) { + this.selectedBrand = selectedBrand; + return this; + } + + /** + * The shopper's email address. + * + * @return shopperEmail + */ + public String getShopperEmail() { + return shopperEmail; + } + + public void setShopperEmail(String shopperEmail) { + this.shopperEmail = shopperEmail; + } + + public StoreTokenRequest shopperEmail(String shopperEmail) { + this.shopperEmail = shopperEmail; + return this; + } + + /** + * The shopper's IP address. + * + * @return shopperIP + */ + public String getShopperIP() { + return shopperIP; + } + + public void setShopperIP(String shopperIP) { + this.shopperIP = shopperIP; + } + + public StoreTokenRequest shopperIP(String shopperIP) { + this.shopperIP = shopperIP; + return this; + } + + /** + * The shopper's reference for the payment transaction. + * + * @return shopperReference + */ + public String getShopperReference() { + return shopperReference; + } + + public void setShopperReference(String shopperReference) { + this.shopperReference = shopperReference; + } + + public StoreTokenRequest shopperReference(String shopperReference) { + this.shopperReference = shopperReference; + return this; + } + + /** + * The text to appear on a shopper's statement. + * + * @return shopperStatement + */ + public String getShopperStatement() { + return shopperStatement; + } + + public void setShopperStatement(String shopperStatement) { + this.shopperStatement = shopperStatement; + } + + public StoreTokenRequest shopperStatement(String shopperStatement) { + this.shopperStatement = shopperStatement; + return this; + } + + public StoreTokenRequest setCardData(String cardNumber, String cardHolder, String expiryMonth, String expiryYear, String cvc) { + Card card = new Card(); + card.setExpiryMonth(expiryMonth); + card.setExpiryYear(expiryYear); + card.setHolderName(cardHolder); + card.setNumber(cardNumber); + card.setCvc(cvc); + + this.setCard(card); + return this; + } + + public StoreTokenRequest setContractToRecurring() { + setRecurring(new Recurring().contract(Recurring.ContractEnum.RECURRING)); + return this; + } + + public StoreTokenRequest setContractToOneClick() { + setRecurring(new Recurring().contract(Recurring.ContractEnum.ONECLICK)); + return this; + } + + public StoreTokenRequest setContractToOneClickRecurring() { + setRecurring(new Recurring().contract(Recurring.ContractEnum.ONECLICK_RECURRING)); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getSimpleName()); + sb.append("[merchantAccount=").append(merchantAccount); + sb.append(", shopperReference=").append(shopperReference); + sb.append(", shopperEmail=").append(shopperEmail); + sb.append(", hasCard=").append(card != null); + sb.append(", selectedBrand=").append(selectedBrand); + sb.append(", shopperStatement=").append(shopperStatement); + sb.append("]"); + return sb.toString(); + } + +} diff --git a/src/main/java/com/adyen/model/recurring/StoreTokenResult.java b/src/main/java/com/adyen/model/recurring/StoreTokenResult.java new file mode 100644 index 000000000..b1b395d7f --- /dev/null +++ b/src/main/java/com/adyen/model/recurring/StoreTokenResult.java @@ -0,0 +1,203 @@ +/** + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############ ##### ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2017 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ +package com.adyen.model.recurring; + +import com.google.gson.annotations.SerializedName; + +/** + * StoreTokenResult - This type contains data that can be returned in response to either prepareStoreToken or storeToken calls. + */ +public class StoreTokenResult { + + @SerializedName("alias") + private String alias; + + @SerializedName("aliasType") + private String aliasType; + + @SerializedName("pspEchoData") + private String pspEchoData; + + @SerializedName("pspReference") + private String pspReference; + + @SerializedName("recurringDetailReference") + private String recurringDetailReference; + + @SerializedName("redirectType") + private String redirectType; + + @SerializedName("redirectUrl") + private String redirectUrl; + + @SerializedName("result") + private String result; + + /** + * The alias of the credit card number. It is a unique alphanumeric identifier for the card. + * + * @return alias + */ + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public StoreTokenResult alias(String alias) { + this.alias = alias; + return this; + } + + /** + * The alias type of the credit card number. Allowed values: Default and BinLetterRandomLastFour. The alias type depends on your account configuration. + * + * @return aliasType + */ + public String getAliasType() { + return aliasType; + } + + public void setAliasType(String aliasType) { + this.aliasType = aliasType; + } + + public StoreTokenResult aliasType(String aliasType) { + this.aliasType = aliasType; + return this; + } + + /** + * A data blob that must be submitted in the storeToken request. + * + * @return pspEchoData + */ + public String getPspEchoData() { + return pspEchoData; + } + + public void setPspEchoData(String pspEchoData) { + this.pspEchoData = pspEchoData; + } + + public StoreTokenResult pspEchoData(String pspEchoData) { + this.pspEchoData = pspEchoData; + return this; + } + + /** + * A reference to uniquely identify the request. + * + * @return pspReference + */ + public String getPspReference() { + return pspReference; + } + + public void setPspReference(String pspReference) { + this.pspReference = pspReference; + } + + public StoreTokenResult pspReference(String pspReference) { + this.pspReference = pspReference; + return this; + } + + /** + * The reference that uniquely identifies the recurring detail. + * + * @return recurringDetailReference + */ + public String getRecurringDetailReference() { + return recurringDetailReference; + } + + public void setRecurringDetailReference(String recurringDetailReference) { + this.recurringDetailReference = recurringDetailReference; + } + + public StoreTokenResult recurringDetailReference(String recurringDetailReference) { + this.recurringDetailReference = recurringDetailReference; + return this; + } + + public String getRedirectType() { + return redirectType; + } + + public void setRedirectType(String redirectType) { + this.redirectType = redirectType; + } + + public StoreTokenResult redirectType(String redirectType) { + this.redirectType = redirectType; + return this; + } + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + + public StoreTokenResult redirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + return this; + } + + /** + * + * @return result + */ + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public StoreTokenResult result(String result) { + this.result = result; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getSimpleName()); + sb.append("["); + sb.append("pspReference=").append(pspReference); + sb.append(", recurringDetailReference=").append(recurringDetailReference); + sb.append(", result=").append(result); + sb.append(", alias=").append(alias); + sb.append(", aliasType=").append(aliasType); + sb.append(", redirectUrl=").append(redirectUrl); + sb.append(", redirectType=").append(redirectType); + sb.append("]"); + return sb.toString(); + } + +} diff --git a/src/main/java/com/adyen/service/Recurring.java b/src/main/java/com/adyen/service/Recurring.java index 8cb82324f..cb658322d 100644 --- a/src/main/java/com/adyen/service/Recurring.java +++ b/src/main/java/com/adyen/service/Recurring.java @@ -21,26 +21,32 @@ package com.adyen.service; import java.io.IOException; + import com.adyen.Client; import com.adyen.Service; import com.adyen.model.recurring.DisableRequest; import com.adyen.model.recurring.DisableResult; import com.adyen.model.recurring.RecurringDetailsRequest; import com.adyen.model.recurring.RecurringDetailsResult; +import com.adyen.model.recurring.StoreTokenRequest; +import com.adyen.model.recurring.StoreTokenResult; import com.adyen.service.exception.ApiException; import com.adyen.service.resource.recurring.Disable; import com.adyen.service.resource.recurring.ListRecurringDetails; +import com.adyen.service.resource.recurring.StoreToken; import com.google.gson.reflect.TypeToken; public class Recurring extends Service { private ListRecurringDetails listRecurringDetails; private Disable disable; + private StoreToken storeToken; public Recurring(Client client) { super(client); listRecurringDetails = new ListRecurringDetails(this); disable = new Disable(this); + storeToken = new StoreToken(this); } /** @@ -77,4 +83,23 @@ public DisableResult disable(DisableRequest request) throws IOException, ApiExce }.getType()); return result; } + + /** + * Issues a storeToken API call + * + * @param request + * @return + * @throws IOException + * @throws ApiException + */ + public StoreTokenResult storeToken(StoreTokenRequest request) throws IOException, ApiException { + String jsonRequest = GSON.toJson(request); + + String jsonResult = storeToken.request(jsonRequest); + + StoreTokenResult result = GSON.fromJson(jsonResult, new TypeToken() { + }.getType()); + return result; + } + } diff --git a/src/main/java/com/adyen/service/resource/recurring/StoreToken.java b/src/main/java/com/adyen/service/resource/recurring/StoreToken.java new file mode 100644 index 000000000..32c456b72 --- /dev/null +++ b/src/main/java/com/adyen/service/resource/recurring/StoreToken.java @@ -0,0 +1,37 @@ +/* + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############ ##### ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2017 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ + +package com.adyen.service.resource.recurring; + +import java.util.Arrays; + +import com.adyen.Client; +import com.adyen.Service; +import com.adyen.service.Resource; + +public class StoreToken extends Resource { + + public StoreToken(Service service) { + super(service, service.getClient().getConfig().getEndpoint() + "/pal/servlet/Recurring/" + Client.RECURRING_API_VERSION + "/storeToken", + Arrays.asList("merchantAccount", "recurring.contract", "shopperReference")); + } + +} diff --git a/src/test/java/com/adyen/RecurringTest.java b/src/test/java/com/adyen/RecurringTest.java index 809202677..88cbdc000 100644 --- a/src/test/java/com/adyen/RecurringTest.java +++ b/src/test/java/com/adyen/RecurringTest.java @@ -27,10 +27,13 @@ import com.adyen.model.recurring.RecurringDetail; import com.adyen.model.recurring.RecurringDetailsRequest; import com.adyen.model.recurring.RecurringDetailsResult; +import com.adyen.model.recurring.StoreTokenRequest; +import com.adyen.model.recurring.StoreTokenResult; import com.adyen.service.Recurring; import com.adyen.service.exception.ApiException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; public class RecurringTest extends BaseTest { @@ -52,6 +55,19 @@ private DisableRequest createDisableRequest() { return request; } + private StoreTokenRequest createStoreTokenRequest() { + StoreTokenRequest request = new StoreTokenRequest() + .shopperReference("test-123") + .merchantAccount("MerchantAccount") + .shopperEmail("johndoe@merchant.com") + .shopperStatement("this is your statement") + .shopperIP("192.168.1.1") + .setContractToOneClick() + .setCardData("5136333333333335", "John Doe", "08", "2018", "737"); + + return request; + } + @Test public void testListRecurringDetails() throws Exception { Client client = createMockClientFromFile("mocks/recurring/listRecurringDetails-success.json"); @@ -99,4 +115,38 @@ public void testDisable803() throws IOException { assertEquals("803", e.getError().getErrorCode()); } } + + @Test + public void testStoreToken() throws Exception { + Client client = createMockClientFromFile("mocks/recurring/storeToken-success.json"); + Recurring recurring = new Recurring(client); + + StoreTokenRequest request = createStoreTokenRequest(); + + StoreTokenResult result = recurring.storeToken(request); + assertNotNull(result); + assertEquals("Success", result.getResult()); + assertEquals("Default", result.getAliasType()); + assertEquals("8815398995557524", result.getPspReference()); + assertEquals("8315398995429067", result.getRecurringDetailReference()); + } + + @Test + public void testStoreToken101() throws IOException { + Client client = createMockClientForErrors(422, "mocks/recurring/storeToken-error-101.json"); + Recurring recurring = new Recurring(client); + + StoreTokenRequest request = createStoreTokenRequest(); + + @SuppressWarnings("unused") + StoreTokenResult result = null; + try { + result = recurring.storeToken(request); + fail("Exception expected!"); + } catch (ApiException e) { + assertNotEquals(200, e.getStatusCode()); + assertEquals("101", e.getError().getErrorCode()); + } + } + } diff --git a/src/test/resources/mocks/recurring/storeToken-error-101.json b/src/test/resources/mocks/recurring/storeToken-error-101.json new file mode 100644 index 000000000..848c68cc6 --- /dev/null +++ b/src/test/resources/mocks/recurring/storeToken-error-101.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "101", + "message": "Invalid card number", + "errorType": "validation" +} diff --git a/src/test/resources/mocks/recurring/storeToken-success.json b/src/test/resources/mocks/recurring/storeToken-success.json new file mode 100644 index 000000000..03457d7b6 --- /dev/null +++ b/src/test/resources/mocks/recurring/storeToken-success.json @@ -0,0 +1,7 @@ +{ + "alias": "P931324991331404", + "aliasType": "Default", + "pspReference": "8815398995557524", + "recurringDetailReference": "8315398995429067", + "result": "Success" +}