From f416aaef3c0969e2bfd5d8e849d10684dbeffe47 Mon Sep 17 00:00:00 2001 From: abhilash Date: Wed, 2 Jun 2021 14:58:35 +0200 Subject: [PATCH 01/14] Fixed NPE in validateHMAC --- .../java/com/adyen/util/HMACValidator.java | 28 +++++++++++++++--- .../com/adyen/util/HMACValidatorTest.java | 29 +++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/adyen/util/HMACValidator.java b/src/main/java/com/adyen/util/HMACValidator.java index c775debe9..4b1a7ad8b 100644 --- a/src/main/java/com/adyen/util/HMACValidator.java +++ b/src/main/java/com/adyen/util/HMACValidator.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import java.util.SortedMap; +import java.util.stream.Collectors; import static com.adyen.constants.ApiConstants.AdditionalData.HMAC_SIGNATURE; @@ -65,7 +66,7 @@ public String calculateHMAC(String data, String key) throws java.security.Signat } // To calculate the HMAC SHA-256 - public String calculateHMAC(NotificationRequestItem notificationRequestItem, String key) throws SignatureException { + public String calculateHMAC(NotificationRequestItem notificationRequestItem, String key) throws IllegalArgumentException, SignatureException { return calculateHMAC(getDataToSign(notificationRequestItem), key); } @@ -79,7 +80,11 @@ public boolean validateHMAC(NotificationRequestItem notificationRequestItem, Str return MessageDigest.isEqual(merchantSign, expectedSign); } - public String getDataToSign(NotificationRequestItem notificationRequestItem) { + public String getDataToSign(NotificationRequestItem notificationRequestItem) throws IllegalArgumentException { + if(notificationRequestItem == null) { + throw new IllegalArgumentException("Missing NotificationRequestItem."); + } + List signedDataList = new ArrayList<>(8); signedDataList.add(notificationRequestItem.getPspReference()); signedDataList.add(notificationRequestItem.getOriginalReference()); @@ -87,8 +92,23 @@ public String getDataToSign(NotificationRequestItem notificationRequestItem) { signedDataList.add(notificationRequestItem.getMerchantReference()); Amount amount = notificationRequestItem.getAmount(); - signedDataList.add(amount.getValue().toString()); - signedDataList.add(amount.getCurrency()); + + //If the amount and value are not null, append them to the payload. + if(amount != null && amount.getValue() != null) { + signedDataList.add(amount.getValue().toString()); + } else { + //Else append a null. Will appear as a empty string in the final payload. + signedDataList.add(null); + } + + //If the amount and currency are not null, append them to the payload. + if(amount != null && amount.getCurrency() != null) { + signedDataList.add(amount.getCurrency()); + } else { + //Else append a null. Will appear as a empty string in the final payload. + signedDataList.add(null); + } + signedDataList.add(notificationRequestItem.getEventCode()); signedDataList.add(String.valueOf(notificationRequestItem.isSuccess())); diff --git a/src/test/java/com/adyen/util/HMACValidatorTest.java b/src/test/java/com/adyen/util/HMACValidatorTest.java index 3c3c99799..a398ab2e2 100644 --- a/src/test/java/com/adyen/util/HMACValidatorTest.java +++ b/src/test/java/com/adyen/util/HMACValidatorTest.java @@ -27,6 +27,7 @@ import java.security.SignatureException; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class HMACValidatorTest { @@ -56,4 +57,32 @@ public void testValidateHMAC() throws SignatureException { boolean result = new HMACValidator().validateHMAC(notificationRequest, HMAC_KEY); assertTrue(result); } + + @Test + public void testValidateHMACMissingOptionalField() throws SignatureException { + String notificationJson = "{\n" + + " \"additionalData\": {\n" + + " \"hmacSignature\": \"NuEkADFmlCC6VgX+wcoPAegIWxVPNBPCuKlM4Hzo5qc=\"\n" + + " },\n" + + " \"eventCode\": \"REPORT_AVAILABLE\",\n" + + " \"eventDate\": \"2019-11-20T14:35:36+01:00\",\n" + + " \"merchantAccountCode\": \"Magento2Rik\",\n" + + " \"merchantReference\": \"testMerchantRef1\",\n" + + " \"pspReference\": \"test_REPORT_AVAILABLE\",\n" + + " \"reason\": \"will contain the url to the report\",\n" + + " \"success\": \"true\"\n" + + "}"; + NotificationRequestItem notificationRequest = new Gson().fromJson(notificationJson, NotificationRequestItem.class); + String payload = new HMACValidator().getDataToSign(notificationRequest); + assertEquals("test_REPORT_AVAILABLE::Magento2Rik:testMerchantRef1:::REPORT_AVAILABLE:true", payload); + } + + @Test + public void testValidateHMACEmptyNotificationRequest() { + try { + new HMACValidator().getDataToSign((NotificationRequestItem) null); + } catch (IllegalArgumentException e) { + assertEquals("Missing NotificationRequestItem.", e.getMessage()); + } + } } From 84f4f9eca42b11f8be87a9aeeb5d6c25cd55296b Mon Sep 17 00:00:00 2001 From: abhilash Date: Wed, 2 Jun 2021 15:06:04 +0200 Subject: [PATCH 02/14] Fixed checkstyle issues. --- src/main/java/com/adyen/util/HMACValidator.java | 7 +++---- src/test/java/com/adyen/util/HMACValidatorTest.java | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/adyen/util/HMACValidator.java b/src/main/java/com/adyen/util/HMACValidator.java index 4b1a7ad8b..b07732924 100644 --- a/src/main/java/com/adyen/util/HMACValidator.java +++ b/src/main/java/com/adyen/util/HMACValidator.java @@ -33,7 +33,6 @@ import java.util.ArrayList; import java.util.List; import java.util.SortedMap; -import java.util.stream.Collectors; import static com.adyen.constants.ApiConstants.AdditionalData.HMAC_SIGNATURE; @@ -81,7 +80,7 @@ public boolean validateHMAC(NotificationRequestItem notificationRequestItem, Str } public String getDataToSign(NotificationRequestItem notificationRequestItem) throws IllegalArgumentException { - if(notificationRequestItem == null) { + if (notificationRequestItem == null) { throw new IllegalArgumentException("Missing NotificationRequestItem."); } @@ -94,7 +93,7 @@ public String getDataToSign(NotificationRequestItem notificationRequestItem) thr Amount amount = notificationRequestItem.getAmount(); //If the amount and value are not null, append them to the payload. - if(amount != null && amount.getValue() != null) { + if (amount != null && amount.getValue() != null) { signedDataList.add(amount.getValue().toString()); } else { //Else append a null. Will appear as a empty string in the final payload. @@ -102,7 +101,7 @@ public String getDataToSign(NotificationRequestItem notificationRequestItem) thr } //If the amount and currency are not null, append them to the payload. - if(amount != null && amount.getCurrency() != null) { + if (amount != null && amount.getCurrency() != null) { signedDataList.add(amount.getCurrency()); } else { //Else append a null. Will appear as a empty string in the final payload. diff --git a/src/test/java/com/adyen/util/HMACValidatorTest.java b/src/test/java/com/adyen/util/HMACValidatorTest.java index a398ab2e2..b8d753979 100644 --- a/src/test/java/com/adyen/util/HMACValidatorTest.java +++ b/src/test/java/com/adyen/util/HMACValidatorTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class HMACValidatorTest { From 4c80b757dbdeb2148da7280e8bbc72a974954e58 Mon Sep 17 00:00:00 2001 From: abhilash Date: Fri, 4 Jun 2021 12:08:10 +0200 Subject: [PATCH 03/14] Removed unused import. --- src/test/java/com/adyen/util/HMACValidatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/adyen/util/HMACValidatorTest.java b/src/test/java/com/adyen/util/HMACValidatorTest.java index b8d753979..a398ab2e2 100644 --- a/src/test/java/com/adyen/util/HMACValidatorTest.java +++ b/src/test/java/com/adyen/util/HMACValidatorTest.java @@ -29,7 +29,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; public class HMACValidatorTest { From 3bb85f983e58aaaa22649f4c27605801d27ec1cd Mon Sep 17 00:00:00 2001 From: amortJ <24584216+amortJ@users.noreply.github.com> Date: Mon, 7 Jun 2021 18:13:06 +0200 Subject: [PATCH 04/14] HTTP Client wrong encoding The Apache Http client uses the ISO-8859-1 encoding for request bodies. This is not compatible with the rest endpoint and the encoding declared in the header of the request (UTF-8). #565 --- .../com/adyen/httpclient/AdyenHttpClient.java | 55 ++++++------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java index 89f2f8796..a0452e963 100644 --- a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java +++ b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java @@ -29,12 +29,7 @@ import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPatch; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; @@ -42,13 +37,8 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.*; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URI; @@ -59,12 +49,7 @@ import java.util.Map; import static com.adyen.constants.ApiConstants.HttpMethod.POST; -import static com.adyen.constants.ApiConstants.RequestProperty.ACCEPT_CHARSET; -import static com.adyen.constants.ApiConstants.RequestProperty.API_KEY; -import static com.adyen.constants.ApiConstants.RequestProperty.APPLICATION_JSON_TYPE; -import static com.adyen.constants.ApiConstants.RequestProperty.CONTENT_TYPE; -import static com.adyen.constants.ApiConstants.RequestProperty.IDEMPOTENCY_KEY; -import static com.adyen.constants.ApiConstants.RequestProperty.USER_AGENT; +import static com.adyen.constants.ApiConstants.RequestProperty.*; public class AdyenHttpClient implements ClientInterface { @@ -150,25 +135,21 @@ private void setHeaders(Config config, RequestOptions requestOptions, HttpReques } } - private HttpRequestBase createHttpRequestBase(URI endpoint, String requestBody, ApiConstants.HttpMethod httpMethod) throws HTTPClientException { - try { - switch (httpMethod) { - case GET: - return new HttpGet(endpoint); - case PATCH: - HttpPatch httpPatch = new HttpPatch(endpoint); - httpPatch.setEntity(new StringEntity(requestBody)); - return httpPatch; - case DELETE: - new HttpDelete(endpoint); - default: - // Default to POST if httpMethod is not provided - HttpPost httpPost = new HttpPost(endpoint); - httpPost.setEntity(new StringEntity(requestBody)); - return httpPost; - } - } catch (UnsupportedEncodingException e) { - throw new HTTPClientException("Unsupported encoding", e); + private HttpRequestBase createHttpRequestBase(URI endpoint, String requestBody, ApiConstants.HttpMethod httpMethod) { + switch (httpMethod) { + case GET: + return new HttpGet(endpoint); + case PATCH: + HttpPatch httpPatch = new HttpPatch(endpoint); + httpPatch.setEntity(new StringEntity(requestBody, CHARSET)); + return httpPatch; + case DELETE: + return new HttpDelete(endpoint); + default: + // Default to POST if httpMethod is not provided + HttpPost httpPost = new HttpPost(endpoint); + httpPost.setEntity(new StringEntity(requestBody, CHARSET)); + return httpPost; } } From 317d3da64407ae4c47e0925ab9175f7f6e15a7db Mon Sep 17 00:00:00 2001 From: amortJ <24584216+amortJ@users.noreply.github.com> Date: Mon, 7 Jun 2021 18:20:55 +0200 Subject: [PATCH 05/14] HTTP Client wrong encoding The Apache Http client uses the ISO-8859-1 encoding for request bodies. This is not compatible with the rest endpoint and the encoding declared in the header of the request (UTF-8). #565 --- .../com/adyen/httpclient/AdyenHttpClient.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java index a0452e963..b42d97186 100644 --- a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java +++ b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java @@ -29,7 +29,12 @@ import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPatch; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; @@ -37,7 +42,11 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; -import javax.net.ssl.*; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; @@ -49,7 +58,12 @@ import java.util.Map; import static com.adyen.constants.ApiConstants.HttpMethod.POST; -import static com.adyen.constants.ApiConstants.RequestProperty.*; +import static com.adyen.constants.ApiConstants.RequestProperty.ACCEPT_CHARSET; +import static com.adyen.constants.ApiConstants.RequestProperty.API_KEY; +import static com.adyen.constants.ApiConstants.RequestProperty.APPLICATION_JSON_TYPE; +import static com.adyen.constants.ApiConstants.RequestProperty.CONTENT_TYPE; +import static com.adyen.constants.ApiConstants.RequestProperty.IDEMPOTENCY_KEY; +import static com.adyen.constants.ApiConstants.RequestProperty.USER_AGENT; public class AdyenHttpClient implements ClientInterface { From 7a18bed9b5d8fc6714151a34f1b29889eb5faeeb Mon Sep 17 00:00:00 2001 From: abhilash Date: Tue, 8 Jun 2021 09:48:23 +0200 Subject: [PATCH 06/14] Added possible NPE null check --- src/main/java/com/adyen/util/HMACValidator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/adyen/util/HMACValidator.java b/src/main/java/com/adyen/util/HMACValidator.java index b07732924..a99604820 100644 --- a/src/main/java/com/adyen/util/HMACValidator.java +++ b/src/main/java/com/adyen/util/HMACValidator.java @@ -70,6 +70,10 @@ public String calculateHMAC(NotificationRequestItem notificationRequestItem, Str } public boolean validateHMAC(NotificationRequestItem notificationRequestItem, String key) throws IllegalArgumentException, SignatureException { + if (notificationRequestItem == null) { + throw new IllegalArgumentException("Missing NotificationRequestItem."); + } + if (notificationRequestItem.getAdditionalData() == null || notificationRequestItem.getAdditionalData().get(HMAC_SIGNATURE).isEmpty()) { throw new IllegalArgumentException("Missing " + HMAC_SIGNATURE); } From 521ff631296970e009daaddf344f91d81b98e125 Mon Sep 17 00:00:00 2001 From: ibartj Date: Tue, 8 Jun 2021 16:45:26 +0200 Subject: [PATCH 07/14] Use KeyStore.getDefaultType() Please keep using KeyStore.getDefaultType(). Android throws `java.security.KeyStoreException: JKS not found` as it (Dalvik virtual machine) does not provide JKS key store type. See KeyStore description at https://developer.android.com/reference/java/security/KeyStore --- src/main/java/com/adyen/httpclient/AdyenHttpClient.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java index 89f2f8796..f82eecfb7 100644 --- a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java +++ b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java @@ -70,7 +70,6 @@ public class AdyenHttpClient implements ClientInterface { private static final String CHARSET = "UTF-8"; private static final String TERMINAL_CERTIFICATE_ALIAS = "TerminalCertificate"; - private static final String JAVA_KEYSTORE = "JKS"; private static final String SSL = "SSL"; private Proxy proxy; @@ -193,7 +192,7 @@ private CloseableHttpClient createCloseableHttpClient(Config config) throws HTTP HttpClientBuilder httpClientBuilder = HttpClients.custom(); // Create new KeyStore for the terminal certificate try { - KeyStore keyStore = KeyStore.getInstance(JAVA_KEYSTORE); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry(TERMINAL_CERTIFICATE_ALIAS, config.getTerminalCertificate()); @@ -275,4 +274,4 @@ private void setBasicAuthentication(HttpUriRequest httpUriRequest, String userna httpUriRequest.addHeader("Authorization", "Basic " + authStringEnc); } -} \ No newline at end of file +} From 43eb1ff553ec4270e739915de56d88173857043d Mon Sep 17 00:00:00 2001 From: abhilash Date: Thu, 10 Jun 2021 09:41:59 +0200 Subject: [PATCH 08/14] Added NPE check for payload/key. --- .../java/com/adyen/util/HMACValidator.java | 9 ++++++-- .../com/adyen/util/HMACValidatorTest.java | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/adyen/util/HMACValidator.java b/src/main/java/com/adyen/util/HMACValidator.java index a99604820..34d4169a4 100644 --- a/src/main/java/com/adyen/util/HMACValidator.java +++ b/src/main/java/com/adyen/util/HMACValidator.java @@ -41,8 +41,12 @@ public class HMACValidator { public static final String DATA_SEPARATOR = ":"; // To calculate the HMAC SHA-256 - public String calculateHMAC(String data, String key) throws java.security.SignatureException { + public String calculateHMAC(String data, String key) throws IllegalArgumentException, SignatureException { try { + if (data == null || key == null) { + throw new IllegalArgumentException(); + } + byte[] rawKey = Hex.decodeHex(key.toCharArray()); // Create an hmac_sha256 key from the raw key bytes SecretKeySpec signingKey = new SecretKeySpec(rawKey, HMAC_SHA256_ALGORITHM); @@ -58,7 +62,8 @@ public String calculateHMAC(String data, String key) throws java.security.Signat // Base64-encode the hmac return new String(Base64.encodeBase64(rawHmac)); - + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Missing data or key."); } catch (Exception e) { throw new SignatureException("Failed to generate HMAC : " + e.getMessage()); } diff --git a/src/test/java/com/adyen/util/HMACValidatorTest.java b/src/test/java/com/adyen/util/HMACValidatorTest.java index a398ab2e2..50fde0945 100644 --- a/src/test/java/com/adyen/util/HMACValidatorTest.java +++ b/src/test/java/com/adyen/util/HMACValidatorTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class HMACValidatorTest { @@ -85,4 +86,26 @@ public void testValidateHMACEmptyNotificationRequest() { assertEquals("Missing NotificationRequestItem.", e.getMessage()); } } + + @Test + public void testCalculateHMACNullPayload() { + try { + new HMACValidator().calculateHMAC((String)null, HMAC_KEY); + } catch (IllegalArgumentException e) { + assertEquals("Missing data or key.", e.getMessage()); + } catch (SignatureException e) { + fail(); + } + } + + @Test + public void testCalculateHMACNullKey() { + try { + new HMACValidator().calculateHMAC("TestPayload", null); + } catch (IllegalArgumentException e) { + assertEquals("Missing data or key.", e.getMessage()); + } catch (SignatureException e) { + fail(); + } + } } From d80b0f71223deb45461b332282222b306a4565c8 Mon Sep 17 00:00:00 2001 From: Alessio Zampatti Date: Thu, 10 Jun 2021 10:56:26 +0200 Subject: [PATCH 09/14] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5026f4684..fdee26b77 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @rkewlani @martinsrenato @Aleffio @abhilash-adyen @saquibsayyad @AlexandrosMor +* @rkewlani @martinsrenato @Aleffio @abhilash-adyen @saquibsayyad From 1b0588a6a85cde4fea61dcc8be2f9227a35a5e16 Mon Sep 17 00:00:00 2001 From: saquib Date: Mon, 14 Jun 2021 16:12:36 +0200 Subject: [PATCH 10/14] PW-4930 Add requiredShopperFields field to CreatePaymentLinkRequest --- .../checkout/CreatePaymentLinkRequest.java | 240 ++++++++++++------ .../model/checkout/InstallmentOption.java | 213 ++++++++++++++++ .../com/adyen/service/PaymentLinksTest.java | 4 +- 3 files changed, 379 insertions(+), 78 deletions(-) create mode 100644 src/main/java/com/adyen/model/checkout/InstallmentOption.java diff --git a/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java b/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java index 87b9b38e3..90877267d 100755 --- a/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java +++ b/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java @@ -20,6 +20,9 @@ */ package com.adyen.model.checkout; +import java.util.Date; +import java.util.Objects; + import com.adyen.model.Address; import com.adyen.model.Amount; import com.adyen.model.Name; @@ -32,17 +35,11 @@ import com.google.gson.annotations.SerializedName; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; - import java.io.IOException; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; - -import static com.adyen.util.Util.toIndentedString; - /** * CreatePaymentLinkRequest */ @@ -79,6 +76,9 @@ public class CreatePaymentLinkRequest { @SerializedName("expiresAt") private String expiresAt = null; + @SerializedName("installmentOptions") + private Map installmentOptions = null; + @SerializedName("lineItems") private List lineItems = null; @@ -92,7 +92,7 @@ public class CreatePaymentLinkRequest { private Map metadata = null; /** - * Defines a recurring payment type. Allowed values: * `Subscription` – A transaction for a fixed or variable amount, which follows a fixed schedule. * `CardOnFile` – With a card-on-file (CoF) transaction, card details are stored to enable one-click or omnichannel journeys, or simply to streamline the checkout process. Any subscription not following a fixed schedule is also considered a card-on-file transaction. * `UnscheduledCardOnFile` – An unscheduled card-on-file (UCoF) transaction is a transaction that occurs on a non-fixed schedule and/or has variable amounts. For example, automatic top-ups when a cardholder's balance drops below a certain amount. + * Defines a recurring payment type. Possible values: * **Subscription** – A transaction for a fixed or variable amount, which follows a fixed schedule. * **CardOnFile** – With a card-on-file (CoF) transaction, card details are stored to enable one-click or omnichannel journeys, or simply to streamline the checkout process. Any subscription not following a fixed schedule is also considered a card-on-file transaction. * **UnscheduledCardOnFile** – An unscheduled card-on-file (UCoF) transaction is a transaction that occurs on a non-fixed schedule and/or has variable amounts. For example, automatic top-ups when a cardholder's balance drops below a certain amount. */ @JsonAdapter(RecurringProcessingModelEnum.Adapter.class) public enum RecurringProcessingModelEnum { @@ -106,7 +106,6 @@ public enum RecurringProcessingModelEnum { RecurringProcessingModelEnum(String value) { this.value = value; } - public String getValue() { return value; } @@ -115,7 +114,6 @@ public String getValue() { public String toString() { return String.valueOf(value); } - public static RecurringProcessingModelEnum fromValue(String text) { for (RecurringProcessingModelEnum b : RecurringProcessingModelEnum.values()) { if (String.valueOf(b.value).equals(text)) { @@ -124,7 +122,6 @@ public static RecurringProcessingModelEnum fromValue(String text) { } return null; } - public static class Adapter extends TypeAdapter { @Override public void write(final JsonWriter jsonWriter, final RecurringProcessingModelEnum enumeration) throws IOException { @@ -133,7 +130,7 @@ public void write(final JsonWriter jsonWriter, final RecurringProcessingModelEnu @Override public RecurringProcessingModelEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); + Object value = jsonReader.nextString(); return RecurringProcessingModelEnum.fromValue(String.valueOf(value)); } } @@ -145,6 +142,56 @@ public RecurringProcessingModelEnum read(final JsonReader jsonReader) throws IOE @SerializedName("reference") private String reference = null; + /** + * Gets or Sets requiredShopperFields + */ + @JsonAdapter(RequiredShopperFieldsEnum.Adapter.class) + public enum RequiredShopperFieldsEnum { + BILLINGADDRESS("billingAddress"), + DELIVERYADDRESS("deliveryAddress"), + SHOPPEREMAIL("shopperEmail"), + SHOPPERNAME("shopperName"), + TELEPHONENUMBER("telephoneNumber"); + + @JsonValue + private String value; + + RequiredShopperFieldsEnum(String value) { + this.value = value; + } + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + public static RequiredShopperFieldsEnum fromValue(String text) { + for (RequiredShopperFieldsEnum b : RequiredShopperFieldsEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final RequiredShopperFieldsEnum enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public RequiredShopperFieldsEnum read(final JsonReader jsonReader) throws IOException { + Object value = jsonReader.nextString(); + return RequiredShopperFieldsEnum.fromValue(String.valueOf(value)); + } + } + } + + @SerializedName("requiredShopperFields") + private List requiredShopperFields = null; + @SerializedName("returnUrl") private String returnUrl = null; @@ -189,8 +236,7 @@ public CreatePaymentLinkRequest addAllowedPaymentMethodsItem(String allowedPayme } /** - * List of payments methods to be presented to the shopper. To refer to payment methods, use their `paymentMethod.type` from [Payment methods overview](https://docs.adyen.com/payment-methods). Example: `\"allowedPaymentMethods\":[\"ideal\",\"giropay\"]` - * + * List of payment methods to be presented to the shopper. To refer to payment methods, use their `paymentMethod.type` from [Payment methods overview](https://docs.adyen.com/payment-methods). Example: `\"allowedPaymentMethods\":[\"ideal\",\"giropay\"]` * @return allowedPaymentMethods **/ public List getAllowedPaymentMethods() { @@ -208,7 +254,6 @@ public CreatePaymentLinkRequest amount(Amount amount) { /** * Get amount - * * @return amount **/ public Amount getAmount() { @@ -226,7 +271,6 @@ public CreatePaymentLinkRequest applicationInfo(ApplicationInfo applicationInfo) /** * Get applicationInfo - * * @return applicationInfo **/ public ApplicationInfo getApplicationInfo() { @@ -244,7 +288,6 @@ public CreatePaymentLinkRequest billingAddress(Address billingAddress) { /** * Get billingAddress - * * @return billingAddress **/ public Address getBillingAddress() { @@ -269,8 +312,7 @@ public CreatePaymentLinkRequest addBlockedPaymentMethodsItem(String blockedPayme } /** - * List of payments methods to be hidden from the shopper. To refer to payment methods, use their `paymentMethod.type` from [Payment methods overview](https://docs.adyen.com/payment-methods). Example: `\"blockedPaymentMethods\":[\"ideal\",\"giropay\"]` - * + * List of payment methods to be hidden from the shopper. To refer to payment methods, use their `paymentMethod.type` from [Payment methods overview](https://docs.adyen.com/payment-methods). Example: `\"blockedPaymentMethods\":[\"ideal\",\"giropay\"]` * @return blockedPaymentMethods **/ public List getBlockedPaymentMethods() { @@ -288,7 +330,6 @@ public CreatePaymentLinkRequest countryCode(String countryCode) { /** * The shopper's two-letter country code. - * * @return countryCode **/ public String getCountryCode() { @@ -306,7 +347,6 @@ public CreatePaymentLinkRequest deliverAt(Date deliverAt) { /** * The date and time the purchased goods should be delivered. - * * @return deliverAt **/ public Date getDeliverAt() { @@ -324,7 +364,6 @@ public CreatePaymentLinkRequest deliveryAddress(Address deliveryAddress) { /** * Get deliveryAddress - * * @return deliveryAddress **/ public Address getDeliveryAddress() { @@ -342,7 +381,6 @@ public CreatePaymentLinkRequest description(String description) { /** * A short description visible on the payment page. Maximum length: 280 characters. - * * @return description **/ public String getDescription() { @@ -359,8 +397,7 @@ public CreatePaymentLinkRequest expiresAt(String expiresAt) { } /** - * The date that the payment link expires, in ISO 8601 format. For example `2019-11-23T12:25:28Z`, or `2020-05-27T20:25:28+08:00`. Maximum expiry date should be 30 days from when the payment link is created. If not provided, the default expiry is set to 24 hours after the payment link is created. - * + * The date that the payment link expires, in ISO 8601 format. For example `2019-11-23T12:25:28Z`, or `2020-05-27T20:25:28+08:00`. Maximum expiry date should be 70 days from when the payment link is created. If not provided, the default expiry is set to 24 hours after the payment link is created. * @return expiresAt **/ public String getExpiresAt() { @@ -371,6 +408,31 @@ public void setExpiresAt(String expiresAt) { this.expiresAt = expiresAt; } + public CreatePaymentLinkRequest installmentOptions(Map installmentOptions) { + this.installmentOptions = installmentOptions; + return this; + } + + public CreatePaymentLinkRequest putInstallmentOptionsItem(String key, InstallmentOption installmentOptionsItem) { + if (this.installmentOptions == null) { + this.installmentOptions = new HashMap<>(); + } + this.installmentOptions.put(key, installmentOptionsItem); + return this; + } + + /** + * A set of key-value pairs that specifies the installment options available per payment method. The key must be a payment method name in lowercase. For example, **card** to specify installment options for all cards, or **visa** or **mc**. The value must be an object containing the installment options. + * @return installmentOptions + **/ + public Map getInstallmentOptions() { + return installmentOptions; + } + + public void setInstallmentOptions(Map installmentOptions) { + this.installmentOptions = installmentOptions; + } + public CreatePaymentLinkRequest lineItems(List lineItems) { this.lineItems = lineItems; return this; @@ -386,7 +448,6 @@ public CreatePaymentLinkRequest addLineItemsItem(LineItem lineItemsItem) { /** * Price and product information about the purchased items, to be included on the invoice sent to the shopper. This parameter is required for open invoice (_buy now, pay later_) payment methods such AfterPay, Klarna, RatePay, and Zip. - * * @return lineItems **/ public List getLineItems() { @@ -404,7 +465,6 @@ public CreatePaymentLinkRequest merchantAccount(String merchantAccount) { /** * The merchant account identifier for which the payment link is created. - * * @return merchantAccount **/ public String getMerchantAccount() { @@ -422,7 +482,6 @@ public CreatePaymentLinkRequest merchantOrderReference(String merchantOrderRefer /** * This reference allows linking multiple transactions to each other for reporting purposes (for example, order auth-rate). The reference should be unique per billing cycle. - * * @return merchantOrderReference **/ public String getMerchantOrderReference() { @@ -447,8 +506,7 @@ public CreatePaymentLinkRequest putMetadataItem(String key, String metadataItem) } /** - * Metadata consists of entries, each of which includes a key and a value. Limitations: * Maximum 20 key-value pairs per request. When exceeding, the \"177\" error occurs: \"Metadata size exceeds limit\" * Maximum 20 characters per key. When exceeding, the \"178\" error occurs: \"Metadata key size exceeds limit\" * A key cannot have the name `checkout.linkId`. Whatever value is present under that key is going to be replaced by the real link id - * + * Metadata consists of entries, each of which includes a key and a value. Limitations: * Maximum 20 key-value pairs per request. Otherwise, error \"177\" occurs: \"Metadata size exceeds limit\" * Maximum 20 characters per key. Otherwise, error \"178\" occurs: \"Metadata key size exceeds limit\" * A key cannot have the name `checkout.linkId`. Any value that you provide with this key is going to be replaced by the real payment link ID. * @return metadata **/ public Map getMetadata() { @@ -465,8 +523,7 @@ public CreatePaymentLinkRequest recurringProcessingModel(RecurringProcessingMode } /** - * Defines a recurring payment type. Allowed values: * `Subscription` – A transaction for a fixed or variable amount, which follows a fixed schedule. * `CardOnFile` – With a card-on-file (CoF) transaction, card details are stored to enable one-click or omnichannel journeys, or simply to streamline the checkout process. Any subscription not following a fixed schedule is also considered a card-on-file transaction. * `UnscheduledCardOnFile` – An unscheduled card-on-file (UCoF) transaction is a transaction that occurs on a non-fixed schedule and/or has variable amounts. For example, automatic top-ups when a cardholder's balance drops below a certain amount. - * + * Defines a recurring payment type. Possible values: * **Subscription** – A transaction for a fixed or variable amount, which follows a fixed schedule. * **CardOnFile** – With a card-on-file (CoF) transaction, card details are stored to enable one-click or omnichannel journeys, or simply to streamline the checkout process. Any subscription not following a fixed schedule is also considered a card-on-file transaction. * **UnscheduledCardOnFile** – An unscheduled card-on-file (UCoF) transaction is a transaction that occurs on a non-fixed schedule and/or has variable amounts. For example, automatic top-ups when a cardholder's balance drops below a certain amount. * @return recurringProcessingModel **/ public RecurringProcessingModelEnum getRecurringProcessingModel() { @@ -484,7 +541,6 @@ public CreatePaymentLinkRequest reference(String reference) { /** * A reference that is used to uniquely identify the payment in future communications about the payment status. - * * @return reference **/ public String getReference() { @@ -495,6 +551,31 @@ public void setReference(String reference) { this.reference = reference; } + public CreatePaymentLinkRequest requiredShopperFields(List requiredShopperFields) { + this.requiredShopperFields = requiredShopperFields; + return this; + } + + public CreatePaymentLinkRequest addRequiredShopperFieldsItem(RequiredShopperFieldsEnum requiredShopperFieldsItem) { + if (this.requiredShopperFields == null) { + this.requiredShopperFields = new ArrayList<>(); + } + this.requiredShopperFields.add(requiredShopperFieldsItem); + return this; + } + + /** + * List of fields that the shopper has to provide on the payment page before completing the payment. For more information, refer to [Provide shopper information](https://docs.adyen.com/online-payments/pay-by-link/api#shopper-information). Possible values: * **billingAddress** – The address where to send the invoice. * **deliveryAddress** – The address where the purchased goods should be delivered. * **shopperEmail** – The shopper's email address. * **shopperName** – The shopper's full name. * **telephoneNumber** – The shopper's phone number. + * @return requiredShopperFields + **/ + public List getRequiredShopperFields() { + return requiredShopperFields; + } + + public void setRequiredShopperFields(List requiredShopperFields) { + this.requiredShopperFields = requiredShopperFields; + } + public CreatePaymentLinkRequest returnUrl(String returnUrl) { this.returnUrl = returnUrl; return this; @@ -502,7 +583,6 @@ public CreatePaymentLinkRequest returnUrl(String returnUrl) { /** * Website URL used for redirection after payment is completed. If provided, a **Continue** button will be shown on the payment page. If shoppers select the button, they are redirected to the specified URL. - * * @return returnUrl **/ public String getReturnUrl() { @@ -520,7 +600,6 @@ public CreatePaymentLinkRequest reusable(Boolean reusable) { /** * Indicates whether the payment link can be reused for multiple payments. If not provided, this defaults to **false** which means the link can be used for one successful payment only. - * * @return reusable **/ public Boolean isReusable() { @@ -538,7 +617,6 @@ public CreatePaymentLinkRequest riskData(RiskData riskData) { /** * Get riskData - * * @return riskData **/ public RiskData getRiskData() { @@ -556,7 +634,6 @@ public CreatePaymentLinkRequest shopperEmail(String shopperEmail) { /** * The shopper's email address. - * * @return shopperEmail **/ public String getShopperEmail() { @@ -573,8 +650,7 @@ public CreatePaymentLinkRequest shopperLocale(String shopperLocale) { } /** - * The language to be used in the payment page, specified by a combination of a language and country code. For example, `en-US`. For a list of shopper locales that Pay by Link supports, refer to [Language and localization](https://docs.adyen.com/checkout/pay-by-link#language-and-localization). - * + * The language to be used in the payment page, specified by a combination of a language and country code. For example, `en-US`. For a list of shopper locales that Pay by Link supports, refer to [Language and localization](https://docs.adyen.com/online-payments/pay-by-link#language-and-localization). * @return shopperLocale **/ public String getShopperLocale() { @@ -592,7 +668,6 @@ public CreatePaymentLinkRequest shopperName(Name shopperName) { /** * Get shopperName - * * @return shopperName **/ public Name getShopperName() { @@ -609,8 +684,7 @@ public CreatePaymentLinkRequest shopperReference(String shopperReference) { } /** - * A unique identifier for the shopper (for example, user ID or account ID). - * + * Your reference to uniquely identify this shopper (for example, user ID or account ID). Minimum length: 3 characters. * @return shopperReference **/ public String getShopperReference() { @@ -635,8 +709,7 @@ public CreatePaymentLinkRequest addSplitsItem(Split splitsItem) { } /** - * Information on how the payment should be split between accounts when using [Adyen for Platforms](https://docs.adyen.com/platforms/processing-payments#providing-split-information). - * + * An array of objects specifying how the payment should be split between accounts when using Adyen for Platforms. For details, refer to [Providing split information](https://docs.adyen.com/platforms/processing-payments#providing-split-information). * @return splits **/ public List getSplits() { @@ -654,7 +727,6 @@ public CreatePaymentLinkRequest store(String store) { /** * The physical store, for which this payment is processed. - * * @return store **/ public String getStore() { @@ -672,7 +744,6 @@ public CreatePaymentLinkRequest storePaymentMethod(Boolean storePaymentMethod) { /** * When this is set to **true** and the `shopperReference` is provided, the payment details will be stored. - * * @return storePaymentMethod **/ public Boolean isStorePaymentMethod() { @@ -683,6 +754,7 @@ public void setStorePaymentMethod(Boolean storePaymentMethod) { this.storePaymentMethod = storePaymentMethod; } + @Override public boolean equals(java.lang.Object o) { if (this == o) { @@ -702,12 +774,14 @@ public boolean equals(java.lang.Object o) { Objects.equals(this.deliveryAddress, createPaymentLinkRequest.deliveryAddress) && Objects.equals(this.description, createPaymentLinkRequest.description) && Objects.equals(this.expiresAt, createPaymentLinkRequest.expiresAt) && + Objects.equals(this.installmentOptions, createPaymentLinkRequest.installmentOptions) && Objects.equals(this.lineItems, createPaymentLinkRequest.lineItems) && Objects.equals(this.merchantAccount, createPaymentLinkRequest.merchantAccount) && Objects.equals(this.merchantOrderReference, createPaymentLinkRequest.merchantOrderReference) && Objects.equals(this.metadata, createPaymentLinkRequest.metadata) && Objects.equals(this.recurringProcessingModel, createPaymentLinkRequest.recurringProcessingModel) && Objects.equals(this.reference, createPaymentLinkRequest.reference) && + Objects.equals(this.requiredShopperFields, createPaymentLinkRequest.requiredShopperFields) && Objects.equals(this.returnUrl, createPaymentLinkRequest.returnUrl) && Objects.equals(this.reusable, createPaymentLinkRequest.reusable) && Objects.equals(this.riskData, createPaymentLinkRequest.riskData) && @@ -722,42 +796,54 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(allowedPaymentMethods, amount, applicationInfo, billingAddress, blockedPaymentMethods, countryCode, deliverAt, deliveryAddress, description, expiresAt, lineItems, merchantAccount, merchantOrderReference, metadata, recurringProcessingModel, reference, returnUrl, reusable, riskData, shopperEmail, shopperLocale, shopperName, shopperReference, splits, store, storePaymentMethod); + return Objects.hash(allowedPaymentMethods, amount, applicationInfo, billingAddress, blockedPaymentMethods, countryCode, deliverAt, deliveryAddress, description, expiresAt, installmentOptions, lineItems, merchantAccount, merchantOrderReference, metadata, recurringProcessingModel, reference, requiredShopperFields, returnUrl, reusable, riskData, shopperEmail, shopperLocale, shopperName, shopperReference, splits, store, storePaymentMethod); } + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class CreatePaymentLinkRequest {\n"); - - sb.append(" allowedPaymentMethods: ").append(toIndentedString(allowedPaymentMethods)).append("\n"); - sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); - sb.append(" applicationInfo: ").append(toIndentedString(applicationInfo)).append("\n"); - sb.append(" billingAddress: ").append(toIndentedString(billingAddress)).append("\n"); - sb.append(" blockedPaymentMethods: ").append(toIndentedString(blockedPaymentMethods)).append("\n"); - sb.append(" countryCode: ").append(toIndentedString(countryCode)).append("\n"); - sb.append(" deliverAt: ").append(toIndentedString(deliverAt)).append("\n"); - sb.append(" deliveryAddress: ").append(toIndentedString(deliveryAddress)).append("\n"); - sb.append(" description: ").append(toIndentedString(description)).append("\n"); - sb.append(" expiresAt: ").append(toIndentedString(expiresAt)).append("\n"); - sb.append(" lineItems: ").append(toIndentedString(lineItems)).append("\n"); - sb.append(" merchantAccount: ").append(toIndentedString(merchantAccount)).append("\n"); - sb.append(" merchantOrderReference: ").append(toIndentedString(merchantOrderReference)).append("\n"); - sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); - sb.append(" recurringProcessingModel: ").append(toIndentedString(recurringProcessingModel)).append("\n"); - sb.append(" reference: ").append(toIndentedString(reference)).append("\n"); - sb.append(" returnUrl: ").append(toIndentedString(returnUrl)).append("\n"); - sb.append(" reusable: ").append(toIndentedString(reusable)).append("\n"); - sb.append(" riskData: ").append(toIndentedString(riskData)).append("\n"); - sb.append(" shopperEmail: ").append(toIndentedString(shopperEmail)).append("\n"); - sb.append(" shopperLocale: ").append(toIndentedString(shopperLocale)).append("\n"); - sb.append(" shopperName: ").append(toIndentedString(shopperName)).append("\n"); - sb.append(" shopperReference: ").append(toIndentedString(shopperReference)).append("\n"); - sb.append(" splits: ").append(toIndentedString(splits)).append("\n"); - sb.append(" store: ").append(toIndentedString(store)).append("\n"); - sb.append(" storePaymentMethod: ").append(toIndentedString(storePaymentMethod)).append("\n"); - sb.append("}"); - return sb.toString(); + + return "class CreatePaymentLinkRequest {\n" + + " allowedPaymentMethods: " + toIndentedString(allowedPaymentMethods) + "\n" + + " amount: " + toIndentedString(amount) + "\n" + + " applicationInfo: " + toIndentedString(applicationInfo) + "\n" + + " billingAddress: " + toIndentedString(billingAddress) + "\n" + + " blockedPaymentMethods: " + toIndentedString(blockedPaymentMethods) + "\n" + + " countryCode: " + toIndentedString(countryCode) + "\n" + + " deliverAt: " + toIndentedString(deliverAt) + "\n" + + " deliveryAddress: " + toIndentedString(deliveryAddress) + "\n" + + " description: " + toIndentedString(description) + "\n" + + " expiresAt: " + toIndentedString(expiresAt) + "\n" + + " installmentOptions: " + toIndentedString(installmentOptions) + "\n" + + " lineItems: " + toIndentedString(lineItems) + "\n" + + " merchantAccount: " + toIndentedString(merchantAccount) + "\n" + + " merchantOrderReference: " + toIndentedString(merchantOrderReference) + "\n" + + " metadata: " + toIndentedString(metadata) + "\n" + + " recurringProcessingModel: " + toIndentedString(recurringProcessingModel) + "\n" + + " reference: " + toIndentedString(reference) + "\n" + + " requiredShopperFields: " + toIndentedString(requiredShopperFields) + "\n" + + " returnUrl: " + toIndentedString(returnUrl) + "\n" + + " reusable: " + toIndentedString(reusable) + "\n" + + " riskData: " + toIndentedString(riskData) + "\n" + + " shopperEmail: " + toIndentedString(shopperEmail) + "\n" + + " shopperLocale: " + toIndentedString(shopperLocale) + "\n" + + " shopperName: " + toIndentedString(shopperName) + "\n" + + " shopperReference: " + toIndentedString(shopperReference) + "\n" + + " splits: " + toIndentedString(splits) + "\n" + + " store: " + toIndentedString(store) + "\n" + + " storePaymentMethod: " + toIndentedString(storePaymentMethod) + "\n" + + "}"; + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } } diff --git a/src/main/java/com/adyen/model/checkout/InstallmentOption.java b/src/main/java/com/adyen/model/checkout/InstallmentOption.java new file mode 100644 index 000000000..16b560495 --- /dev/null +++ b/src/main/java/com/adyen/model/checkout/InstallmentOption.java @@ -0,0 +1,213 @@ +/* + * Adyen Checkout API + * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/online-payments). ## Authentication Each request to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/development-resources/api-credentials#generate-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v67/payments ``` + * + * OpenAPI spec version: 67 + * Contact: developer-experience@adyen.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +package com.adyen.model.checkout; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +/** + * InstallmentOption + */ + +public class InstallmentOption { + @SerializedName("maxValue") + private Integer maxValue = null; + + /** + * Gets or Sets plans + */ + @JsonAdapter(PlansEnum.Adapter.class) + public enum PlansEnum { + REGULAR("regular"), + REVOLVING("revolving"); + + @JsonValue + private String value; + + PlansEnum(String value) { + this.value = value; + } + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + public static PlansEnum fromValue(String text) { + for (PlansEnum b : PlansEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final PlansEnum enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public PlansEnum read(final JsonReader jsonReader) throws IOException { + Object value = jsonReader.nextString(); + return PlansEnum.fromValue(String.valueOf(value)); + } + } + } @SerializedName("plans") + private List plans = null; + + @SerializedName("preselectedValue") + private Integer preselectedValue = null; + + @SerializedName("values") + private List values = null; + + public InstallmentOption maxValue(Integer maxValue) { + this.maxValue = maxValue; + return this; + } + + /** + * The maximum number of installments offered for this payment method. + * @return maxValue + **/ + public Integer getMaxValue() { + return maxValue; + } + + public void setMaxValue(Integer maxValue) { + this.maxValue = maxValue; + } + + public InstallmentOption plans(List plans) { + this.plans = plans; + return this; + } + + public InstallmentOption addPlansItem(PlansEnum plansItem) { + if (this.plans == null) { + this.plans = new ArrayList<>(); + } + this.plans.add(plansItem); + return this; + } + + /** + * Defines the type of installment plan. If not set, defaults to **regular**. Possible values: * **regular** * **revolving** + * @return plans + **/ + public List getPlans() { + return plans; + } + + public void setPlans(List plans) { + this.plans = plans; + } + + public InstallmentOption preselectedValue(Integer preselectedValue) { + this.preselectedValue = preselectedValue; + return this; + } + + /** + * Preselected number of installments offered for this payment method. + * @return preselectedValue + **/ + public Integer getPreselectedValue() { + return preselectedValue; + } + + public void setPreselectedValue(Integer preselectedValue) { + this.preselectedValue = preselectedValue; + } + + public InstallmentOption values(List values) { + this.values = values; + return this; + } + + public InstallmentOption addValuesItem(Integer valuesItem) { + if (this.values == null) { + this.values = new ArrayList<>(); + } + this.values.add(valuesItem); + return this; + } + + /** + * An array of the number of installments that the shopper can choose from. For example, **[2,3,5]**. This cannot be specified simultaneously with `maxValue`. + * @return values + **/ + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InstallmentOption installmentOption = (InstallmentOption) o; + return Objects.equals(this.maxValue, installmentOption.maxValue) && + Objects.equals(this.plans, installmentOption.plans) && + Objects.equals(this.preselectedValue, installmentOption.preselectedValue) && + Objects.equals(this.values, installmentOption.values); + } + + @Override + public int hashCode() { + return Objects.hash(maxValue, plans, preselectedValue, values); + } + + + @Override + public String toString() { + + return "class InstallmentOption {\n" + + " maxValue: " + toIndentedString(maxValue) + "\n" + + " plans: " + toIndentedString(plans) + "\n" + + " preselectedValue: " + toIndentedString(preselectedValue) + "\n" + + " values: " + toIndentedString(values) + "\n" + + "}"; + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} diff --git a/src/test/java/com/adyen/service/PaymentLinksTest.java b/src/test/java/com/adyen/service/PaymentLinksTest.java index ee760132c..5655cf545 100644 --- a/src/test/java/com/adyen/service/PaymentLinksTest.java +++ b/src/test/java/com/adyen/service/PaymentLinksTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import java.io.IOException; +import java.util.Collections; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -40,7 +41,7 @@ public class PaymentLinksTest extends BaseTest { @Test public void TestCreatePaymentLinksSuccess() throws Exception { - Client client = createMockClientFromFile("mocks/paymentlinks/get-payment-link-success.json"); + Client client = createMockClientFromFile("mocks/paymentlinks/create-payment-links-success.json"); PaymentLinks paymentLinks = new PaymentLinks(client); CreatePaymentLinkRequest createPaymentLinkRequest = createPaymentLinkRequest(); PaymentLinkResource paymentLink = paymentLinks.create(createPaymentLinkRequest); @@ -138,6 +139,7 @@ private CreatePaymentLinkRequest createPaymentLinkRequest() { createPaymentLinkRequest.setShopperEmail("test@email.com"); createPaymentLinkRequest.setShopperLocale("pt_BR"); createPaymentLinkRequest.setExpiresAt("2019-12-17T10:05:29Z"); + createPaymentLinkRequest.setRequiredShopperFields(Collections.singletonList(CreatePaymentLinkRequest.RequiredShopperFieldsEnum.DELIVERYADDRESS)); Address address = new Address(); address.setStreet("Street"); address.setPostalCode("59000060"); From f2fc43ae6d091f95d324f677ec8213ab0d81284e Mon Sep 17 00:00:00 2001 From: saquib Date: Tue, 15 Jun 2021 13:30:14 +0200 Subject: [PATCH 11/14] PW-4930 Added copyright and change type --- .../checkout/CreatePaymentLinkRequest.java | 4 ++-- .../model/checkout/InstallmentOption.java | 23 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java b/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java index 90877267d..e98fc6ee0 100755 --- a/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java +++ b/src/main/java/com/adyen/model/checkout/CreatePaymentLinkRequest.java @@ -14,7 +14,7 @@ * * Adyen Java API Library * - * Copyright (c) 2020 Adyen B.V. + * Copyright (c) 2021 Adyen B.V. * This file is open source and available under the MIT license. * See the LICENSE file for more info. */ @@ -130,7 +130,7 @@ public void write(final JsonWriter jsonWriter, final RecurringProcessingModelEnu @Override public RecurringProcessingModelEnum read(final JsonReader jsonReader) throws IOException { - Object value = jsonReader.nextString(); + String value = jsonReader.nextString(); return RecurringProcessingModelEnum.fromValue(String.valueOf(value)); } } diff --git a/src/main/java/com/adyen/model/checkout/InstallmentOption.java b/src/main/java/com/adyen/model/checkout/InstallmentOption.java index 16b560495..2a048637c 100644 --- a/src/main/java/com/adyen/model/checkout/InstallmentOption.java +++ b/src/main/java/com/adyen/model/checkout/InstallmentOption.java @@ -1,13 +1,22 @@ /* - * Adyen Checkout API - * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/online-payments). ## Authentication Each request to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/development-resources/api-credentials#generate-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v67/payments ``` + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############ ##### ###### + * ###### + * ############# + * ############ * - * OpenAPI spec version: 67 - * Contact: developer-experience@adyen.com + * Adyen Java API Library * - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen.git - * Do not edit the class manually. + * Copyright (c) 2021 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.checkout; From 3972f612693a1763724b2a017a8a5a49535ca682 Mon Sep 17 00:00:00 2001 From: amin Date: Tue, 15 Jun 2021 14:48:16 +0200 Subject: [PATCH 12/14] PW-4719 Handle null for requestBody - hpp passes null as requestBody for 'directoryLookup' --- src/main/java/com/adyen/httpclient/AdyenHttpClient.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java index 146c7b4de..6bee0df8d 100644 --- a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java +++ b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java @@ -149,19 +149,24 @@ private void setHeaders(Config config, RequestOptions requestOptions, HttpReques } private HttpRequestBase createHttpRequestBase(URI endpoint, String requestBody, ApiConstants.HttpMethod httpMethod) { + StringEntity requestEntity = null; + if (requestBody != null && !requestBody.isEmpty()) { + requestEntity = new StringEntity(requestBody, CHARSET); + } + switch (httpMethod) { case GET: return new HttpGet(endpoint); case PATCH: HttpPatch httpPatch = new HttpPatch(endpoint); - httpPatch.setEntity(new StringEntity(requestBody, CHARSET)); + httpPatch.setEntity(requestEntity); return httpPatch; case DELETE: return new HttpDelete(endpoint); default: // Default to POST if httpMethod is not provided HttpPost httpPost = new HttpPost(endpoint); - httpPost.setEntity(new StringEntity(requestBody, CHARSET)); + httpPost.setEntity(requestEntity); return httpPost; } } From 0f41ffbd5339c39a0e7ef32b45aa0f5526c977a8 Mon Sep 17 00:00:00 2001 From: alessio Date: Fri, 18 Jun 2021 10:19:52 +0200 Subject: [PATCH 13/14] Version bump 15.0.2 --- README.md | 2 +- pom.xml | 2 +- src/main/java/com/adyen/Client.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4406d0812..75f497dea 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ You can use Maven and add this dependency to your project's POM: com.adyen adyen-java-api-library - 15.0.1 + 15.0.2 ``` diff --git a/pom.xml b/pom.xml index 5dafb27e7..3d21bf269 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.adyen adyen-java-api-library jar - 15.0.1 + 15.0.2 Adyen Java API Library Adyen API Client Library for Java https://github.com/adyen/adyen-java-api-library diff --git a/src/main/java/com/adyen/Client.java b/src/main/java/com/adyen/Client.java index 03225bd54..fbe8d69f9 100644 --- a/src/main/java/com/adyen/Client.java +++ b/src/main/java/com/adyen/Client.java @@ -45,7 +45,7 @@ public class Client { public static final String MARKETPAY_NOTIFICATION_API_VERSION = "v6"; public static final String MARKETPAY_HOP_API_VERSION = "v6"; public static final String LIB_NAME = "adyen-java-api-library"; - public static final String LIB_VERSION = "15.0.1"; + public static final String LIB_VERSION = "15.0.2"; public static final String CHECKOUT_ENDPOINT_TEST = "https://checkout-test.adyen.com/checkout"; public static final String CHECKOUT_ENDPOINT_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout"; public static final String CHECKOUT_API_VERSION = "v67"; From 1d1e0e5ab4bc1c52f9b805f70ec62cd824fbf06d Mon Sep 17 00:00:00 2001 From: alessio Date: Fri, 18 Jun 2021 10:25:07 +0200 Subject: [PATCH 14/14] Autoformat InstallmentOption.java --- .../model/checkout/InstallmentOption.java | 352 +++++++++--------- 1 file changed, 181 insertions(+), 171 deletions(-) diff --git a/src/main/java/com/adyen/model/checkout/InstallmentOption.java b/src/main/java/com/adyen/model/checkout/InstallmentOption.java index 2a048637c..01d2bcd39 100644 --- a/src/main/java/com/adyen/model/checkout/InstallmentOption.java +++ b/src/main/java/com/adyen/model/checkout/InstallmentOption.java @@ -32,191 +32,201 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; + /** * InstallmentOption */ public class InstallmentOption { - @SerializedName("maxValue") - private Integer maxValue = null; + @SerializedName("maxValue") + private Integer maxValue = null; + + /** + * Gets or Sets plans + */ + @JsonAdapter(PlansEnum.Adapter.class) + public enum PlansEnum { + REGULAR("regular"), + REVOLVING("revolving"); + + @JsonValue + private String value; + + PlansEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static PlansEnum fromValue(String text) { + for (PlansEnum b : PlansEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final PlansEnum enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public PlansEnum read(final JsonReader jsonReader) throws IOException { + Object value = jsonReader.nextString(); + return PlansEnum.fromValue(String.valueOf(value)); + } + } + } + + @SerializedName("plans") + private List plans = null; + + @SerializedName("preselectedValue") + private Integer preselectedValue = null; + + @SerializedName("values") + private List values = null; + + public InstallmentOption maxValue(Integer maxValue) { + this.maxValue = maxValue; + return this; + } + + /** + * The maximum number of installments offered for this payment method. + * + * @return maxValue + **/ + public Integer getMaxValue() { + return maxValue; + } + + public void setMaxValue(Integer maxValue) { + this.maxValue = maxValue; + } + + public InstallmentOption plans(List plans) { + this.plans = plans; + return this; + } + + public InstallmentOption addPlansItem(PlansEnum plansItem) { + if (this.plans == null) { + this.plans = new ArrayList<>(); + } + this.plans.add(plansItem); + return this; + } + + /** + * Defines the type of installment plan. If not set, defaults to **regular**. Possible values: * **regular** * **revolving** + * + * @return plans + **/ + public List getPlans() { + return plans; + } + + public void setPlans(List plans) { + this.plans = plans; + } + + public InstallmentOption preselectedValue(Integer preselectedValue) { + this.preselectedValue = preselectedValue; + return this; + } + + /** + * Preselected number of installments offered for this payment method. + * + * @return preselectedValue + **/ + public Integer getPreselectedValue() { + return preselectedValue; + } + + public void setPreselectedValue(Integer preselectedValue) { + this.preselectedValue = preselectedValue; + } + + public InstallmentOption values(List values) { + this.values = values; + return this; + } + + public InstallmentOption addValuesItem(Integer valuesItem) { + if (this.values == null) { + this.values = new ArrayList<>(); + } + this.values.add(valuesItem); + return this; + } + + /** + * An array of the number of installments that the shopper can choose from. For example, **[2,3,5]**. This cannot be specified simultaneously with `maxValue`. + * + * @return values + **/ + public List getValues() { + return values; + } - /** - * Gets or Sets plans - */ - @JsonAdapter(PlansEnum.Adapter.class) - public enum PlansEnum { - REGULAR("regular"), - REVOLVING("revolving"); + public void setValues(List values) { + this.values = values; + } - @JsonValue - private String value; - PlansEnum(String value) { - this.value = value; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InstallmentOption installmentOption = (InstallmentOption) o; + return Objects.equals(this.maxValue, installmentOption.maxValue) && + Objects.equals(this.plans, installmentOption.plans) && + Objects.equals(this.preselectedValue, installmentOption.preselectedValue) && + Objects.equals(this.values, installmentOption.values); } - public String getValue() { - return value; + + @Override + public int hashCode() { + return Objects.hash(maxValue, plans, preselectedValue, values); } + @Override public String toString() { - return String.valueOf(value); + + return "class InstallmentOption {\n" + + " maxValue: " + toIndentedString(maxValue) + "\n" + + " plans: " + toIndentedString(plans) + "\n" + + " preselectedValue: " + toIndentedString(preselectedValue) + "\n" + + " values: " + toIndentedString(values) + "\n" + + "}"; } - public static PlansEnum fromValue(String text) { - for (PlansEnum b : PlansEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } - } - return null; - } - public static class Adapter extends TypeAdapter { - @Override - public void write(final JsonWriter jsonWriter, final PlansEnum enumeration) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public PlansEnum read(final JsonReader jsonReader) throws IOException { - Object value = jsonReader.nextString(); - return PlansEnum.fromValue(String.valueOf(value)); - } - } - } @SerializedName("plans") - private List plans = null; - - @SerializedName("preselectedValue") - private Integer preselectedValue = null; - - @SerializedName("values") - private List values = null; - - public InstallmentOption maxValue(Integer maxValue) { - this.maxValue = maxValue; - return this; - } - - /** - * The maximum number of installments offered for this payment method. - * @return maxValue - **/ - public Integer getMaxValue() { - return maxValue; - } - - public void setMaxValue(Integer maxValue) { - this.maxValue = maxValue; - } - - public InstallmentOption plans(List plans) { - this.plans = plans; - return this; - } - - public InstallmentOption addPlansItem(PlansEnum plansItem) { - if (this.plans == null) { - this.plans = new ArrayList<>(); - } - this.plans.add(plansItem); - return this; - } - - /** - * Defines the type of installment plan. If not set, defaults to **regular**. Possible values: * **regular** * **revolving** - * @return plans - **/ - public List getPlans() { - return plans; - } - - public void setPlans(List plans) { - this.plans = plans; - } - - public InstallmentOption preselectedValue(Integer preselectedValue) { - this.preselectedValue = preselectedValue; - return this; - } - - /** - * Preselected number of installments offered for this payment method. - * @return preselectedValue - **/ - public Integer getPreselectedValue() { - return preselectedValue; - } - - public void setPreselectedValue(Integer preselectedValue) { - this.preselectedValue = preselectedValue; - } - - public InstallmentOption values(List values) { - this.values = values; - return this; - } - - public InstallmentOption addValuesItem(Integer valuesItem) { - if (this.values == null) { - this.values = new ArrayList<>(); - } - this.values.add(valuesItem); - return this; - } - - /** - * An array of the number of installments that the shopper can choose from. For example, **[2,3,5]**. This cannot be specified simultaneously with `maxValue`. - * @return values - **/ - public List getValues() { - return values; - } - - public void setValues(List values) { - this.values = values; - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - InstallmentOption installmentOption = (InstallmentOption) o; - return Objects.equals(this.maxValue, installmentOption.maxValue) && - Objects.equals(this.plans, installmentOption.plans) && - Objects.equals(this.preselectedValue, installmentOption.preselectedValue) && - Objects.equals(this.values, installmentOption.values); - } - - @Override - public int hashCode() { - return Objects.hash(maxValue, plans, preselectedValue, values); - } - - - @Override - public String toString() { - - return "class InstallmentOption {\n" + - " maxValue: " + toIndentedString(maxValue) + "\n" + - " plans: " + toIndentedString(plans) + "\n" + - " preselectedValue: " + toIndentedString(preselectedValue) + "\n" + - " values: " + toIndentedString(values) + "\n" + - "}"; - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + return o.toString().replace("\n", "\n "); + } }