Skip to content

Commit 2c8a8e0

Browse files
authored
Merge pull request #1538 from Adyen/1439-terminal-cloud-response-type
Terminal Cloud API async: update return type
2 parents d2c0b16 + 47fcd3c commit 2c8a8e0

File tree

5 files changed

+155
-10
lines changed

5 files changed

+155
-10
lines changed

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,75 @@ const paymentRequest: SaleToPOIRequest = {
515515
// Step 5: Make the request
516516
const terminalApiResponse: terminal.TerminalApiResponse = await terminalLocalAPI.request(paymentRequest);
517517
```
518+
### Using the Cloud Terminal API Integration (async)
519+
If you choose to integrate [Terminal API over Cloud](https://docs.adyen.com/point-of-sale/design-your-integration/choose-your-architecture/cloud/) **asynchronously**, you need to follow similar steps to initialize the client and prepare the request object. However the response will be asynchronous:
520+
* a successful request will return `200` status code and `ok` as response body. Make sure to setup the [event notifications](https://docs.adyen.com/point-of-sale/design-your-integration/notifications/event-notifications/)
521+
* a request that fails will return `200` status code and the `TerminalApiResponse` as response body
522+
``` typescript
523+
// Step 1: Require the parts of the module you want to use
524+
const {Client, TerminalCloudAPI} from "@adyen/api-library";
525+
526+
// Step 2: Initialize the client object
527+
const client = new Client({apiKey: "YOUR_API_KEY", environment: "TEST"});
528+
529+
// Step 3: Initialize the API object
530+
const terminalCloudAPI = new TerminalCloudAPI(client);
531+
532+
// Step 4: Create the request object
533+
const serviceID = "123456789";
534+
const saleID = "POS-SystemID12345";
535+
const POIID = "Your Device Name(eg V400m-123456789)";
536+
537+
// Use a unique transaction for every transaction you perform
538+
const transactionID = "TransactionID";
539+
const paymentRequest: SaleToPOIRequest = {
540+
MessageHeader: {
541+
MessageClass: MessageClassType.Service,
542+
MessageCategory: MessageCategoryType.Payment,
543+
MessageType: MessageType.Request,
544+
ProtocolVersion: "3.0",
545+
ServiceID: serviceID,
546+
SaleID: saleID,
547+
POIID: POIID
548+
},
549+
PaymentRequest: {
550+
SaleData: {
551+
SaleTransactionID: {
552+
TransactionID: transactionID,
553+
TimeStamp: new Date().toISOString()
554+
},
555+
556+
SaleToAcquirerData: {
557+
applicationInfo: {
558+
merchantApplication: {
559+
version: "1",
560+
name: "test",
561+
}
562+
}
563+
}
564+
},
565+
PaymentTransaction: {
566+
AmountsReq: {
567+
Currency: "EUR",
568+
RequestedAmount: 1000
569+
}
570+
}
571+
}
572+
};
573+
574+
// Step 5: Make the request
575+
const response = await terminalCloudAPI.async(paymentRequest);
576+
// handle both `string` and `TerminalApiResponse`
577+
if (typeof response === "string") {
578+
// request was successful
579+
console.log("response:", response); // should be 'ok'
580+
} else {
581+
// request failed: see details in the EventNotification object
582+
console.log("EventToNotify:", response.SaleToPOIRequest?.EventNotification?.EventToNotify);
583+
console.log("EventDetails:", response.SaleToPOIRequest?.EventNotification?.EventDetails);
584+
}
585+
```
586+
518587
## Feedback
519588
We value your input! Help us enhance our API Libraries and improve the integration experience by providing your feedback. Please take a moment to fill out [our feedback form](https://forms.gle/A4EERrR6CWgKWe5r9) to share your thoughts, suggestions or ideas.
520589

src/__mocks__/terminalApi/async.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,25 @@
1818
*/
1919

2020
export const asyncRes = "ok";
21+
22+
export const asyncErrorRes = {
23+
SaleToPOIRequest: {
24+
EventNotification: {
25+
EventToNotify: "Reject",
26+
EventDetails: "message=Did+not+receive+a+response+from+the+POI.",
27+
RejectedMessage: "ewoi...0KfQo=",
28+
TimeStamp: "2020-03-31T10:28:39.515Z"
29+
},
30+
MessageHeader: {
31+
DeviceID: "666568147",
32+
MessageCategory: "Event",
33+
MessageClass: "Event",
34+
MessageType: "Notification",
35+
POIID: "P400Plus-123456789",
36+
ProtocolVersion: "3.0",
37+
SaleID: "saleid-4c32759faaa7",
38+
ServiceID: "31122609"
39+
}
40+
}
41+
};
42+

src/__tests__/terminalCloudAPI.spec.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import nock from "nock";
22
import { createClient, createTerminalAPIPaymentRequest, createTerminalAPIRefundRequest } from "../__mocks__/base";
3-
import { asyncRes } from "../__mocks__/terminalApi/async";
3+
import { asyncRes, asyncErrorRes } from "../__mocks__/terminalApi/async";
44
import { syncRefund, syncRes, syncResEventNotification, syncResEventNotificationWithAdditionalAttributes, syncResEventNotificationWithUnknownEnum } from "../__mocks__/terminalApi/sync";
55
import Client from "../client";
66
import TerminalCloudAPI from "../services/terminalCloudAPI";
@@ -30,11 +30,27 @@ describe("Terminal Cloud API", (): void => {
3030

3131
const terminalAPIPaymentRequest = createTerminalAPIPaymentRequest();
3232

33-
const requestResponse: string = await terminalCloudAPI.async(terminalAPIPaymentRequest);
33+
const requestResponse = await terminalCloudAPI.async(terminalAPIPaymentRequest);
3434

35+
expect(typeof requestResponse).toBe("string");
3536
expect(requestResponse).toEqual("ok");
3637
});
3738

39+
test("should get an error after async payment request", async (): Promise<void> => {
40+
scope.post("/async").reply(200, asyncErrorRes);
41+
42+
const terminalAPIPaymentRequest = createTerminalAPIPaymentRequest();
43+
44+
const requestResponse = await terminalCloudAPI.async(terminalAPIPaymentRequest);
45+
46+
if (typeof requestResponse === "object") {
47+
expect(requestResponse.SaleToPOIRequest?.EventNotification).toBeDefined();
48+
expect(requestResponse.SaleToPOIRequest?.EventNotification?.EventToNotify).toBe("Reject");
49+
} else {
50+
throw new Error("Expected structured response, but got raw string");
51+
}
52+
});
53+
3854
test("should make a sync payment request", async (): Promise<void> => {
3955
scope.post("/sync").reply(200, syncRes);
4056

@@ -453,4 +469,3 @@ export const syncTerminalPaymentResponse = {
453469
}
454470
}
455471
};
456-

src/helpers/getJsonResponse.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,36 @@
1919

2020
import Resource from "../services/resource";
2121
import { IRequest } from "../typings/requestOptions";
22+
import { TerminalApiResponse } from "../typings/terminal/models";
2223

23-
async function getJsonResponse<T>(resource: Resource, jsonRequest: T | string, requestOptions?: IRequest.Options): Promise<string>;
24+
/**
25+
* Sends a JSON request to the given resource and returns a string or a deserialized `TerminalApiResponse`.
26+
* Used by Terminal API /async method
27+
*
28+
* @template T The request type (usually a model or plain object).
29+
* @param {Resource} resource - The API resource to which the request is sent.
30+
* @param {T | string} jsonRequest - The request payload, either as an object or raw JSON string.
31+
* @param {IRequest.Options} [requestOptions] - Optional HTTP request options.
32+
* @returns {Promise<string | TerminalApiResponse>} A promise resolving to either a raw response string or a `TerminalApiResponse` object.
33+
*
34+
* @example
35+
* const response = await getJsonResponse<TerminalApiRequest>(terminalApiResource, request);
36+
*/
37+
async function getJsonResponse<T>(resource: Resource, jsonRequest: T | string, requestOptions?: IRequest.Options): Promise<string | TerminalApiResponse>;
38+
/**
39+
* Sends a JSON request to the given resource and returns a deserialized response of the expected type.
40+
* Used by all APIs and Terminal API sync method
41+
*
42+
* @template T The request type.
43+
* @template R The expected deserialized response type.
44+
* @param {Resource} resource - The API resource to which the request is sent.
45+
* @param {T | string} jsonRequest - The request payload, either as an object or raw JSON string.
46+
* @param {IRequest.Options} [requestOptions] - Optional HTTP request options.
47+
* @returns {Promise<R>} A promise resolving to the deserialized response object.
48+
*
49+
* @example
50+
* const response = await getJsonResponse<MyRequestType, MyResponseType>(resource, request);
51+
*/
2452
async function getJsonResponse<T, R>(resource: Resource, jsonRequest: T | string, requestOptions?: IRequest.Options): Promise<R>;
2553

2654
/**

src/services/terminalCloudAPI.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,34 @@ class TerminalCloudAPI extends Service {
4040
private static setApplicationInfo(request: TerminalApiRequest): TerminalApiRequest {
4141
if (request.SaleToPOIRequest.PaymentRequest) {
4242
const applicationInfo = new ApplicationInfo();
43-
const saleToAcquirerData = {applicationInfo};
44-
const saleData = {saleToAcquirerData};
45-
const paymentRequest = {saleData};
46-
const saleToPOIRequest = {paymentRequest};
47-
const reqWithAppInfo = {saleToPOIRequest};
43+
const saleToAcquirerData = { applicationInfo };
44+
const saleData = { saleToAcquirerData };
45+
const paymentRequest = { saleData };
46+
const saleToPOIRequest = { paymentRequest };
47+
const reqWithAppInfo = { saleToPOIRequest };
4848

4949
mergeDeep(request, reqWithAppInfo);
5050
}
5151

5252
return ObjectSerializer.serialize(request, "TerminalApiRequest");
5353
}
5454

55-
public async(terminalApiRequest: TerminalApiRequest): Promise<string> {
55+
/**
56+
* Send an asynchronous payment request to the Terminal API.
57+
*
58+
* @param terminalApiRequest - The request to send.
59+
* @returns A promise that resolves to "ok" if the request was successful, or a TerminalApiResponse if there is an error.
60+
*/
61+
public async(terminalApiRequest: TerminalApiRequest): Promise<string | TerminalApiResponse> {
5662
const request = TerminalCloudAPI.setApplicationInfo(terminalApiRequest);
5763
return getJsonResponse<TerminalApiRequest>(this.terminalApiAsync, request);
5864
}
5965

66+
/**
67+
* Send a synchronous payment request to the Terminal API.
68+
* @param terminalApiRequest - The request to send.
69+
* @returns A promise that resolves to a TerminalApiResponse.
70+
*/
6071
public async sync(terminalApiRequest: TerminalApiRequest): Promise<TerminalApiResponse> {
6172
const request = TerminalCloudAPI.setApplicationInfo(terminalApiRequest);
6273
const response = await getJsonResponse<TerminalApiRequest, TerminalApiResponse>(

0 commit comments

Comments
 (0)