Skip to content

Commit

Permalink
Feature/terminal api local unencrypted + readme (#1130)
Browse files Browse the repository at this point in the history
* Add Terminal API local unencrypted class

* Add Terminal API local unencrypted test and readme

* remove copyright

* remove ApiKeyAuthenticatedService from terminal local api as API key is not used in local communications

* add imports to readme
  • Loading branch information
Aleffio authored Sep 14, 2023
1 parent 1219e39 commit 4bc5a2c
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 2 deletions.
196 changes: 196 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,202 @@ System.setProperty("https.proxyUser", "squid");
System.setProperty("https.proxyPassword", "ward");
~~~~

## Using the Cloud Terminal API Integration
In order to submit In-Person requests with [Terminal API over Cloud](https://docs.adyen.com/point-of-sale/design-your-integration/choose-your-architecture/cloud/) you need to initialize the client in a similar way as the steps listed above for Ecommerce transactions, but make sure to include `TerminalCloudAPI`:
``` java
// Step 1: Import the required classes
import com.adyen.Client;
import com.adyen.enums.Environment;
import com.adyen.service.TerminalCloudAPI;
import com.adyen.model.nexo.*;
import com.adyen.model.terminal.*;

// Step 2: Initialize the client object
Client client = new Client("Your YOUR_API_KEY", Environment.TEST);

// Step 3: Initialize the API object
TerminalCloudAPI terminalCloudApi = new TerminalCloudAPI(client);

// Step 4: Create the request object
String serviceID = "123456789";
String saleID = "POS-SystemID12345";
String POIID = "Your Device Name(eg V400m-123456789)";

// Use a unique transaction for every other transaction you perform
String transactionID = "TransactionID";
TerminalAPIRequest terminalAPIRequest = new TerminalAPIRequest();
SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();

MessageHeader messageHeader = new MessageHeader();
messageHeader.setMessageClass(MessageClassType.SERVICE);
messageHeader.setMessageCategory(MessageCategoryType.PAYMENT);
messageHeader.setMessageType(MessageType.REQUEST);
messageHeader.setProtocolVersion("3.0");
messageHeader.setServiceID(serviceID);
messageHeader.setSaleID(saleID);
messageHeader.setPOIID(POIID);

saleToPOIRequest.setMessageHeader(messageHeader);

com.adyen.model.nexo.PaymentRequest paymentRequest = new com.adyen.model.nexo.PaymentRequest();
SaleData saleData = new SaleData();
TransactionIdentification transactionIdentification = new TransactionIdentification();
transactionIdentification.setTransactionID("001");
XMLGregorianCalendar timestamp = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
transactionIdentification.setTimeStamp(timestamp);
saleData.setSaleTransactionID(transactionIdentification);

SaleToAcquirerData saleToAcquirerData = new SaleToAcquirerData();
ApplicationInfo applicationInfo = new ApplicationInfo();
CommonField merchantApplication = new CommonField();
merchantApplication.setVersion("1");
merchantApplication.setName("Test");
applicationInfo.setMerchantApplication(merchantApplication);
saleToAcquirerData.setApplicationInfo(applicationInfo);
saleData.setSaleToAcquirerData(saleToAcquirerData);

PaymentTransaction paymentTransaction = new PaymentTransaction();
AmountsReq amountsReq = new AmountsReq();
amountsReq.setCurrency("EUR");
amountsReq.setRequestedAmount(BigDecimal.valueOf(1000));
paymentTransaction.setAmountsReq(amountsReq);

paymentRequest.setPaymentTransaction(paymentTransaction);
paymentRequest.setSaleData(saleData);

saleToPOIRequest.setPaymentRequest(paymentRequest);

terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

// Step 5: Make the request
TerminalAPIResponse terminalAPIResponse = terminalCloudApi.sync(terminalAPIRequest);
```

### Optional: perform an abort request

To perform an [abort request](https://docs.adyen.com/point-of-sale/basic-tapi-integration/cancel-a-transaction/) you can use the following example:
``` java
TerminalAPIRequest terminalAPIRequest = new TerminalAPIRequest();
SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();

MessageHeader messageHeader = new MessageHeader();
messageHeader.setMessageClass(MessageClassType.SERVICE);
messageHeader.setMessageCategory(MessageCategoryType.ABORT);
messageHeader.setMessageType(MessageType.REQUEST);
messageHeader.setProtocolVersion("3.0");
messageHeader.setServiceID("Different service ID");
messageHeader.setSaleID(saleID);
messageHeader.setPOIID(POIID);

AbortRequest abortRequest = new AbortRequest();
abortRequest.setAbortReason("MerchantAbort");
MessageReference messageReference = new MessageReference();
messageReference.setMessageCategory(MessageCategoryType.PAYMENT);
messageReference.setSaleID(saleID);
messageReference.setPOIID(POIID);
// Service ID of the payment you're aborting
messageReference.setServiceID(serviceID);
abortRequest.setMessageReference(messageReference);

saleToPOIRequest.setAbortRequest(abortRequest);
saleToPOIRequest.setMessageHeader(messageHeader);

terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

TerminalAPIResponse terminalAPIResponse = terminalCloudApi.sync(terminalAPIRequest);
```

### Optional: perform a status request

To perform a [status request](https://docs.adyen.com/point-of-sale/basic-tapi-integration/verify-transaction-status/) you can use the following example:
```java
TerminalAPIRequest terminalAPIRequest = new TerminalAPIRequest();
SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();

MessageHeader messageHeader = new MessageHeader();
messageHeader.setMessageClass(MessageClassType.SERVICE);
messageHeader.setMessageCategory(MessageCategoryType.TRANSACTION_STATUS);
messageHeader.setMessageType(MessageType.REQUEST);
messageHeader.setProtocolVersion("3.0");
messageHeader.setServiceID("Different service ID");
messageHeader.setSaleID(saleID);
messageHeader.setPOIID(POIID);

TransactionStatusRequest transactionStatusRequest = new TransactionStatusRequest();
transactionStatusRequest.setReceiptReprintFlag(true);
transactionStatusRequest.getDocumentQualifier().add(DocumentQualifierType.CASHIER_RECEIPT);
transactionStatusRequest.getDocumentQualifier().add(DocumentQualifierType.CUSTOMER_RECEIPT);
MessageReference messageReference = new MessageReference();
messageReference.setMessageCategory(MessageCategoryType.PAYMENT);
messageReference.setSaleID(saleID);
// serviceID of the transaction you want the status update from
messageReference.setServiceID(serviceID);
transactionStatusRequest.setMessageReference(messageReference);

saleToPOIRequest.setTransactionStatusRequest(transactionStatusRequest);
saleToPOIRequest.setMessageHeader(messageHeader);

terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

TerminalAPIResponse terminalAPIResponse = terminalCloudApi.sync(terminalAPIRequest);
```

## Using the Local Terminal API Integration
The request and response payloads are identical to the Cloud Terminal API, however, additional encryption details are required to perform the requests.
```java
// Step 1: Import the required classes
import com.adyen.service.TerminalLocalAPI;
import com.adyen.model.nexo.*;
import com.adyen.model.terminal.*;

// Step 2: Add your Certificate Path and Local Endpoint to the config path. Install the certificate from [here](https://docs.adyen.com/point-of-sale/choose-your-architecture/local#protect-communications).
Client client = new Client();
client.getConfig().setTerminalApiLocalEndpoint("The IP of your terminal (eg https://192.168.47.169)");
client.getConfig().setEnvironment(Environment.TEST);
client.getConfig().setTerminalCertificate("YOUR_CERTIFICATE_PATH");

// Step 3: Setup a security password for you terminal in CA, and import the security key object:
SecurityKey securityKey = new SecurityKey();
securityKey.setKeyVersion(1);
securityKey.setAdyenCryptoVersion(1);
securityKey.setKeyIdentifier("keyIdentifier");
securityKey.setPassphrase("passphrase");

// Step 4 Initialize the API object
TerminalLocalAPI terminalLocalAPI = new TerminalLocalAPI(client, securityKey);

// Step 5: Create the request object
TerminalAPIRequest terminalAPIRequest = ///....same as the one used for Cloud API ;

// Step 6: Make the request
TerminalAPIResponse terminalAPIResponse = terminalLocalApi.request(terminalAPIRequest);
```

## Using the Local Terminal API Integration without Encryption (Only on TEST)
If you wish to develop the Local Terminal API integration parallel to your encryption implementation, you can opt for the unencrypted version. Be sure to remove any encryption details from the CA terminal config page.
```java
// Step 1: Import the required classes
import com.adyen.service.TerminalLocalAPIUnencrypted;
import com.adyen.model.nexo.*;
import com.adyen.model.terminal.*;

// Step 2: Add your Certificate Path and Local Endpoint to the config path.
Client client = new Client();
client.getConfig().setTerminalApiLocalEndpoint("The IP of your terminal (eg https://192.168.47.169)");
client.getConfig().setEnvironment(Environment.TEST);
client.getConfig().setTerminalCertificate("YOUR_CERTIFICATE_PATH");

// Step 3 Initialize the client and the API objects;
TerminalLocalAPIUnencrypted terminalLocalAPIUnencrypted = new TerminalLocalAPIUnencrypted(client);

// Step 4: Create the request object
TerminalAPIRequest terminalAPIPaymentRequest = ///....same as the one used in the other examples;

// Step 5: Make the request
TerminalAPIResponse terminalAPIResponse = terminalLocalAPIUnencrypted.request(terminalAPIPaymentRequest);
```


### Example integrations

For a closer look at how our Java library works, you can clone one of our example integrations:
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/adyen/service/TerminalLocalAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
*/
package com.adyen.service;

import com.adyen.ApiKeyAuthenticatedService;
import com.adyen.Client;
import com.adyen.Service;
import com.adyen.model.terminal.TerminalAPIRequest;
import com.adyen.model.terminal.TerminalAPIResponse;
import com.adyen.model.terminal.TerminalAPISecuredRequest;
Expand All @@ -35,7 +35,7 @@
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class TerminalLocalAPI extends ApiKeyAuthenticatedService {
public class TerminalLocalAPI extends Service {

private final LocalRequest localRequest;

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/adyen/service/TerminalLocalAPIUnencrypted.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.adyen.service;

import com.adyen.Client;
import com.adyen.Service;
import com.adyen.model.terminal.TerminalAPIRequest;
import com.adyen.model.terminal.TerminalAPIResponse;
import com.adyen.service.resource.terminal.local.LocalRequest;
import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
* [UNENCRYPTED] Local Terminal Api.
* Use this class (in TEST only) to experiment with the Local Terminal API separately
* from the encryption implementation required for live payments.
* <p>
* Be sure to remove the encryption key details on the Customer Area as it will not work with encryption key details set up.
*/
public class TerminalLocalAPIUnencrypted extends Service {

private final LocalRequest localRequest;

private final Gson terminalApiGson;

public TerminalLocalAPIUnencrypted(Client client) {
super(client);
localRequest = new LocalRequest(this);
terminalApiGson = TerminalAPIGsonBuilder.create();
}

/**
* Local Terminal API call
*
* @param terminalAPIRequest TerminalAPIRequest
* @return TerminalAPIResponse
* @throws Exception exception
*/
public TerminalAPIResponse request(TerminalAPIRequest terminalAPIRequest) throws Exception {
String jsonRequest = terminalApiGson.toJson(terminalAPIRequest);

String jsonResponse = localRequest.request(jsonRequest);

if (jsonResponse == null || jsonResponse.isEmpty() || "ok".equals(jsonResponse)) {
return null;
}

return terminalApiGson.fromJson(jsonResponse, new TypeToken<TerminalAPIResponse>() {
}.getType());
}
}
17 changes: 17 additions & 0 deletions src/test/java/com/adyen/TerminalLocalAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.adyen.model.terminal.TerminalAPIResponse;
import com.adyen.model.terminal.security.SecurityKey;
import com.adyen.service.TerminalLocalAPI;
import com.adyen.service.TerminalLocalAPIUnencrypted;
import org.junit.Test;

import java.math.BigDecimal;
Expand Down Expand Up @@ -135,4 +136,20 @@ public void syncPaymentRequestSuccess() throws Exception {
assertEquals("EUR", paymentResult.getAmountsResp().getCurrency());
assertEquals(BigDecimal.ONE, paymentResult.getAmountsResp().getAuthorizedAmount());
}

/**
* Test success flow for local request unencrypted
*/
@Test
public void unencryptedPaymentRequestSuccess() throws Exception {
Client client = createMockClientFromFile("mocks/terminal-api/payment-sync-success.json");
TerminalLocalAPIUnencrypted terminalLocalAPIUnencrypted = new TerminalLocalAPIUnencrypted(client);
TerminalAPIResponse response = terminalLocalAPIUnencrypted.request(createTerminalAPIPaymentRequest());
assertNotNull(response);
assertNotNull(response.getSaleToPOIResponse());

SaleToPOIResponse saleToPoiResponse = response.getSaleToPOIResponse();
assertNotNull(saleToPoiResponse.getMessageHeader());
assertNotNull(saleToPoiResponse.getPaymentResponse());
}
}

0 comments on commit 4bc5a2c

Please sign in to comment.