Finalized GET and POST redirect handling. Updated /payments request formating to support listed payment methods. Added config file initialization and updated README.md and .gitignore

This commit is contained in:
Tyler Douglas
2020-04-10 16:39:19 -07:00
parent 331f1918d2
commit da4fe96e33
9 changed files with 193 additions and 56 deletions

12
.gitignore vendored
View File

@@ -1,10 +1,14 @@
.gradle
.idea
.gradle/
.idea/
.DS_Store
gradle
build
gradle/
build/
bin/
gen/
*.class
gradlew
gradlew.bat

View File

@@ -8,7 +8,7 @@ This repository includes examples of PCI-compliant UI integrations for online pa
* [Drop-in](https://docs.adyen.com/checkout/drop-in-web)
* [Component](https://docs.adyen.com/checkout/components-web)
* ACH
* ACH (not supported ATM b/c Java API Library doesn't support)
* Alipay
* Boleto
* Card
@@ -19,15 +19,24 @@ This repository includes examples of PCI-compliant UI integrations for online pa
* Sofort
## Requirements - TODO
## Requirements
* Java 1.8
* Gradle
## Dependencies
The Gradle build will install the following files from maven central
* Java Spark v2.8.0
* Simple Logging Facade (slf4j-simple v1.7.25)
* Jinjava template v2.7.1
* org.apache.http URLEncodedUtils v4.5.11
* Adyen Java API Library v5.0.0
## Installation - TODO
1. Clone this repo
2. ...
2. Make sure you have Java 1.8 and Gradle installed on your machine
## Usage - TODO
@@ -37,10 +46,7 @@ This repository includes examples of PCI-compliant UI integrations for online pa
checkout_apikey = SampleAPIKey
origin_key = SampleOriginKey
```
2. Make sure your (venv) is activated by running `source ./venv/bin/activate` from your projects root.
3. Run `./start.sh` to:
* Initialize the required environment variables. This step is necessary every time you re-activate your (venv)
* Run flask
3. Run `gradle run`
3. Visit [http://localhost:8080](http://localhost:8080) and select an integration type!
## Contributing

View File

@@ -6,6 +6,11 @@ version "0.1"
sourceCompatibility = 1.8
description ="""
Demo Adyen checkout integration with a Java Spark based backend
Project name: ${project.name}
"""
application {
mainClassName = 'controller.Main'
}
@@ -19,5 +24,6 @@ dependencies {
implementation "org.slf4j:slf4j-simple:1.7.25"
implementation "com.sparkjava:spark-template-jinjava:2.7.1"
implementation 'org.apache.httpcomponents:httpclient:4.5.11'
implementation 'com.adyen:adyen-java-api-library:4.0.1'
implementation 'com.adyen:adyen-java-api-library:5.0.0'
implementation 'org.jetbrains:annotations:15.0'
}

View File

@@ -1,6 +1,5 @@
package controller;
import com.adyen.model.PaymentResult;
import com.adyen.model.checkout.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

View File

@@ -1,6 +1,5 @@
package controller;
import com.adyen.model.checkout.PaymentDetails;
import com.adyen.model.checkout.PaymentsDetailsRequest;
import com.adyen.model.checkout.PaymentsRequest;
import com.adyen.model.checkout.PaymentsResponse;
@@ -8,12 +7,11 @@ import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import com.google.common.net.MediaType;
import org.apache.http.NameValuePair;
import spark.QueryParamsMap;
import view.RenderUtil;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import model.PaymentMethods;
@@ -27,6 +25,7 @@ import spark.Response;
public class Main {
private static final File FAVICON_PATH = new File("src/main/resources/static/img/favicon.ico");
private static final String configFile = "config.properties";
public static String merchantAccount = "";
public static String apiKey = "";
@@ -38,7 +37,7 @@ public class Main {
public static void main(String[] args) {
port(8080);
staticFiles.location("/static");
initalizeConstants();
readConfigFile();
// Routes
get("/", (req, res) -> {
@@ -59,7 +58,7 @@ public class Main {
String integrationType = req.params(":integration");
Map<String, Object> context = new HashMap<>();
context.put("paymentMethods", PaymentMethods.getPaymentMethods());
context.put("paymentMethods", PaymentMethods.getPaymentMethods(integrationType));
context.put("originKey", originKey);
context.put("integrationType", integrationType);
@@ -67,11 +66,13 @@ public class Main {
});
post("/api/getPaymentMethods", (req, res) -> {
String paymentMethods = PaymentMethods.getPaymentMethods();
String paymentMethods = PaymentMethods.getPaymentMethods("");
return paymentMethods;
});
post("/api/initiatePayment", (req, res) -> {
System.out.println("Response received from client:\n" + req.body());
PaymentsRequest request = FrontendParser.parsePayment(req.body());
String response = Payments.makePayment(request);
@@ -86,24 +87,46 @@ public class Main {
});
get("/api/handleShopperRedirect", (req, res) -> {
System.out.println("GET result\n" + req.body());
res.redirect("/error"); //TODO: Evaluate contents of res at this point to handle redirect
return res;
System.out.println("GET redirect handler");
QueryParamsMap queryMap = req.queryMap();
String key = "";
String value = "";
if (queryMap.hasKey("redirectResult")) {
key = "redirectResult";
value = queryMap.value("redirectResult");
} else if (queryMap.hasKey("payload")) {
key = "payload";
value = queryMap.value("payload");
}
Map<String, Object> context = new HashMap<>();
String valuesArray = "{\n" +
"\"" + key + "\": \"" + value + "\"" +
"}";
context.put("valuesArray", valuesArray);
return RenderUtil.render(context, "templates/fetch-payment-data.html"); // Get paymentData from localStorage
});
post("/api/handleShopperRedirect", (req, res) -> {
System.out.println("POST result\n" + req.body() + "\n");
System.out.println("POST redirect handler");
// Triggers when POST contains query params. Triggers on call back from issuer after 3DS2 challenge w/ MD & PaRes
if (req.body().contains("&")) {
if (!req.body().contains("paymentData")) {
List<NameValuePair> params = FrontendParser.parseQueryParams(req.body());
System.out.println(params.toString());
String md = params.get(0).getValue();
String paRes = params.get(1).getValue();
Map<String, Object> context = new HashMap<>();
context.put("MD", md);
context.put("PaRes", paRes);
String valuesArray = "{\n" +
"\"MD\": \"" + md + "\",\n" +
"\"PaRes\": \"" + paRes + "\"\n" +
"}";
context.put("valuesArray", valuesArray);
return RenderUtil.render(context, "templates/fetch-payment-data.html"); // Get paymentData from localStorage
} else {
@@ -115,8 +138,10 @@ public class Main {
switch (result) {
case AUTHORISED:
res.redirect("/success");
break;
case RECEIVED: case PENDING:
res.redirect("/pending");
break;
default:
res.redirect("/failed");
}
@@ -149,15 +174,6 @@ public class Main {
});
}
private static void initalizeConstants() {
merchantAccount = "TylerDouglas";
apiKey = "AQEyhmfxL4jIYhVBw0m/n3Q5qf3VaY9UCJ1+XWZe9W27jmlZiiSaWGoa4mOFeQne5hiuhQsQwV1bDb7kfNy1WIxIIkxgBw==-hJYG90gqLYPclLs6We+q8CUtAsa+KgXr/iWftd+rrCM=-89EKHpWfW8ABmGF3";
originKey = "pub.v2.8115499067697722.aHR0cDovL2xvY2FsaG9zdDo4MDgw.I4ixvXum4JGOjgI0Nd3YQ49P4AWvIncxMv41suCoW1Y";
paymentMethodsUrl = "https://checkout-test.adyen.com/v52/paymentMethods";
paymentsUrl = "https://checkout-test.adyen.com/v52/payments";
paymentsDetailsUrl = "https://checkout-test.adyen.com/v52/payments/details";
}
private static Object getFavicon(Response res) {
try {
InputStream in = null;
@@ -180,4 +196,25 @@ public class Main {
return ex.getMessage();
}
}
private static void readConfigFile() {
Properties prop = new Properties();
try {
BufferedInputStream in = new BufferedInputStream(new FileInputStream(configFile));
prop.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
merchantAccount = prop.getProperty("merchantAccount");
apiKey = prop.getProperty("apiKey");
originKey = prop.getProperty("originKey");
paymentMethodsUrl = prop.getProperty("paymentMethodsUrl");
paymentsUrl = prop.getProperty("paymentsUrl");
paymentsDetailsUrl = prop.getProperty("paymentsDetailsUrl");
}
}

View File

@@ -3,7 +3,6 @@ package model;
import com.adyen.Client;
import com.adyen.enums.Environment;
import com.adyen.model.Amount;
import com.adyen.model.checkout.PaymentMethodDetails;
import com.adyen.model.checkout.PaymentMethodsRequest;
import com.adyen.model.checkout.PaymentMethodsResponse;
import com.adyen.service.Checkout;
@@ -16,15 +15,19 @@ import java.io.IOException;
public class PaymentMethods {
public static String getPaymentMethods() {
public static String getPaymentMethods(String type) {
Client client = new Client(Main.apiKey, Environment.TEST);
Checkout checkout = new Checkout(client);
PaymentMethodsRequest paymentMethodsRequest = new PaymentMethodsRequest();
paymentMethodsRequest.setMerchantAccount(Main.merchantAccount);
paymentMethodsRequest.setCountryCode("NL");
Amount amount = new Amount();
amount.setCurrency("EUR");
if (type.equals("dotpay")) {
amount.setCurrency("PLN");
} else {
amount.setCurrency("EUR");
}
amount.setValue(1000L);
paymentMethodsRequest.setAmount(amount);
paymentMethodsRequest.setChannel(PaymentMethodsRequest.ChannelEnum.WEB);

View File

@@ -2,8 +2,8 @@ package model;
import com.adyen.Client;
import com.adyen.enums.Environment;
import com.adyen.model.Address;
import com.adyen.model.Amount;
import com.adyen.model.checkout.LineItem;
import com.adyen.model.checkout.PaymentsRequest;
import com.adyen.model.checkout.PaymentsResponse;
import com.adyen.service.Checkout;
@@ -21,16 +21,43 @@ public class Payments {
Client client = new Client(Main.apiKey, Environment.TEST);
Checkout checkout = new Checkout(client);
paymentsRequest.setMerchantAccount(Main.merchantAccount);
paymentsRequest.setCountryCode("NL");
Amount amount = new Amount();
amount.setCurrency("EUR");
amount.setValue(1000L);
paymentsRequest.setAmount(amount);
paymentsRequest.setReference("Test Reference");
paymentsRequest.setReturnUrl("http://localhost:8080/api/handleShopperRedirect");
String type = paymentsRequest.getPaymentMethod().getType();
setAmount(paymentsRequest, type);
paymentsRequest.setChannel(PaymentsRequest.ChannelEnum.WEB);
System.out.println("/paymentMethods response:\n" + paymentsRequest.toString());
paymentsRequest.setMerchantAccount(Main.merchantAccount);
paymentsRequest.setReturnUrl("http://localhost:8080/api/handleShopperRedirect");
paymentsRequest.setReference("Java Integration Test Reference");
paymentsRequest.setShopperReference("Java Checkout Shopper");
paymentsRequest.setCountryCode("NL");
if (type.equals("alipay")) {
paymentsRequest.setCountryCode("CN");
} else if (type.contains("klarna")) {
paymentsRequest.setShopperEmail("myEmail@adyen.com");
paymentsRequest.setShopperLocale("en_US");
addLineItems(paymentsRequest);
} else if (type.equals("directEbanking") || type.equals("giropay")) {
paymentsRequest.countryCode("DE");
} else if (type.equals("dotpay")) {
paymentsRequest.countryCode("PL");
paymentsRequest.getAmount().setCurrency("PLN");
} else if (type.equals("scheme")) {
paymentsRequest.setOrigin("http://localhost:8080");
paymentsRequest.putAdditionalDataItem("allow3DS2", "true");
} else if (type.equals("ach")) {
paymentsRequest.countryCode("US");
}
System.out.println("/payments request:\n" + paymentsRequest.toString());
try {
PaymentsResponse response = checkout.payments(paymentsRequest);
@@ -45,4 +72,62 @@ public class Payments {
return e.toString();
}
}
private static void setAmount(PaymentsRequest paymentsRequest, String type) {
Amount amount = new Amount();
String currency;
switch (type) {
case "alipay":
currency = "CNY";
break;
case "dotpay":
currency = "PLN";
break;
case "boletobancario":
currency = "BRL";
break;
case "ach":
currency = "USD";
break;
default:
currency = "EUR";
}
amount.setCurrency(currency);
amount.setValue(1000L);
paymentsRequest.setAmount(amount);
}
private static void addLineItems(PaymentsRequest paymentsRequest) {
String item1 = "{\n" +
" \"quantity\": \"1\",\n" +
" \"amountExcludingTax\": \"450\",\n" +
" \"taxPercentage\": \"1111\",\n" +
" \"description\": \"Sunglasses\",\n" +
" \"id\": \"Item #1\",\n" +
" \"taxAmount\": \"50\",\n" +
" \"amountIncludingTax\": \"500\",\n" +
" \"taxCategory\": \"High\"\n" +
" }";
String item2 = "{\n" +
" \"quantity\": \"1\",\n" +
" \"amountExcludingTax\": \"450\",\n" +
" \"taxPercentage\": \"1111\",\n" +
" \"description\": \"Headphones\",\n" +
" \"id\": \"Item #2\",\n" +
" \"taxAmount\": \"50\",\n" +
" \"amountIncludingTax\": \"500\",\n" +
" \"taxCategory\": \"High\"\n" +
" }";
Gson gson = new GsonBuilder().create();
LineItem lineItem1 = gson.fromJson(item1, LineItem.class);
LineItem lineItem2 = gson.fromJson(item2, LineItem.class);
paymentsRequest.addLineItemsItem(lineItem1);
paymentsRequest.addLineItemsItem(lineItem2);
}
}

View File

@@ -8,10 +8,7 @@
const structurePaymentRequest = () => {
const paymentData = localStorage.getItem('redirectPaymentData');
let values_array = {
"MD": "{{ MD }}",
"PaRes": "{{ PaRes }}"
};
let values_array = {{ valuesArray }};
const values = {
paymentData: paymentData,
details: values_array

View File

@@ -42,7 +42,7 @@
</a>
</li>
<li class="integration-list-item">
<a class="integration-list-item-link" href="cart/directEBanking">
<a class="integration-list-item-link" href="cart/directEbanking">
<div class="title-container">
<p class="integration-list-item-title">Sofort</p>
</div>