Skip to content

Commit a2b4465

Browse files
authored
Merge pull request #689 from Adyen/develop
Release 8.1.0
2 parents db5d409 + b226ea1 commit a2b4465

31 files changed

+1595
-443
lines changed

README.md

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@
88
[![Total alerts](https://img.shields.io/lgtm/alerts/g/Adyen/adyen-node-api-library.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Adyen/adyen-node-api-library/alerts/)
99
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/Adyen/adyen-node-api-library.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Adyen/adyen-node-api-library/context:javascript)
1010

11-
The Adyen API Library for NodeJS enables you to work with Adyen APIs.
11+
This is the officially supported NodeJS library for using Adyen's APIs.
1212

1313
## Integration
1414
The Library supports all APIs under the following services:
1515

16-
* [x] checkout
17-
* [x] checkout utility
18-
* [x] payments
19-
* [x] modifications
20-
* [x] payouts
21-
* [x] recurring
22-
* [x] notifications
23-
* [x] BIN lookup
24-
* [x] Terminal API
16+
* [Checkout API](https://docs.adyen.com/api-explorer/#/CheckoutService/v67/overview): Our latest integration for accepting online payments. Current supported version: **v67**
17+
* [Payments API](https://docs.adyen.com/api-explorer/#/Payment/v64/overview): Our classic integration for online payments. Current supported version: **v64**
18+
* [Recurring API](https://docs.adyen.com/api-explorer/#/Recurring/v49/overview): Endpoints for managing saved payment details. Current supported version: **v49**
19+
* [Payouts API](https://docs.adyen.com/api-explorer/#/Payout/v64/overview): Endpoints for sending funds to your customers. Current supported version: **v64**
20+
* [Platforms APIs](https://docs.adyen.com/platforms/api): Set of APIs when using Adyen for Platforms.
21+
* [Account API](https://docs.adyen.com/api-explorer/#/Account/v6/overview) Current supported version: **v6**
22+
* [Fund API](https://docs.adyen.com/api-explorer/#/Fund/v6/overview) Current supported version: **v6**
23+
* [Notification Configuration API](https://docs.adyen.com/api-explorer/#/NotificationConfigurationService/v6/overview) Current supported version: **v6**
24+
* [Local/Cloud-based Terminal API](https://docs.adyen.com/point-of-sale/terminal-api-reference): Our point-of-sale integration.
25+
* [BIN lookup API](https://docs.adyen.com/api-explorer/#/BinLookup/v50/overview): The BIN Lookup API provides endpoints for retrieving information based on a given BIN. Current supported version: **v50**
2526

26-
## Requirements
27+
For more information, refer to our [documentation](https://docs.adyen.com/) or the [API Explorer](https://docs.adyen.com/api-explorer/).
2728

28-
* Node 10 or higher
29+
## Prerequisites
30+
- [Adyen test account](https://docs.adyen.com/get-started-with-adyen)
31+
- [API key](https://docs.adyen.com/development-resources/api-credentials#generate-api-key). For testing, your API credential needs to have the [API PCI Payments role](https://docs.adyen.com/development-resources/api-credentials#roles).
32+
- Node 10 or higher
2933

3034
## Installation
3135

@@ -37,12 +41,28 @@ You can use NPM to add our library to your project
3741
npm install --save @adyen/api-library
3842
```
3943

40-
## Documentation
41-
* https://docs.adyen.com/developers/development-resources/libraries
42-
* https://docs.adyen.com/developers/checkout
43-
44-
## HTTP Client Configuration
45-
44+
Alternatively, you can download the [release on GitHub](https://github.com/Adyen/adyen-node-api-library/releases).
45+
46+
47+
## Using the library
48+
49+
### General use with API key
50+
51+
Set up the client as a singleton resource; you can then use it to create service objects for the API calls that you make to Adyen:
52+
53+
```typescript
54+
const client = new Client({apiKey: "YOUR_API_KEY", environment: "TEST"});
55+
```
56+
### General use with API key for live environment
57+
```typescript
58+
const client = new Client({apiKey: "YOUR_API_KEY", environment: "LIVE"});
59+
```
60+
### General use with basic auth
61+
```typescript
62+
const client = new Client({username: "YOUR_USERNAME", password: "YOUR_PASSWORD", environment: "TEST"});
63+
```
64+
65+
### Custom HTTP Client Configuration
4666
By default, NodeJS [https](https://nodejs.org/api/https.html) will be used to submit requests to the API. But you can change that by injecting your own HttpClient on your client instance. In the example below, we use `axios`:
4767

4868
```javascript
@@ -89,20 +109,23 @@ client.httpClient = httpClient;
89109
...
90110
```
91111

92-
## Testing
93-
`$ npm run test`
94-
95-
## Support
96-
If you have a feature request, or spotted a bug or a technical problem, create a GitHub issue. For other questions, contact our [support team](https://support.adyen.com/hc/en-us/requests/new?ticket_form_id=360000705420).
112+
### Example integration
113+
114+
For a closer look at how our PHP library works, clone our [example integration](https://github.com/adyen-examples/adyen-node-online-payments). This includes commented code, highlighting key features and concepts, and examples of API calls that can be made using the library.
97115

98-
## Contributing
116+
## Contributing
99117
We strongly encourage you to join us in contributing to this repository so everyone can benefit from:
100118
* New features and functionality
101119
* Resolved bug fixes and issues
102120
* Any general improvements
103121

104-
Read our [**contribution guidelines**](CONTRIBUTING.md) to find out how.
122+
Read our [**contribution guidelines**](CONTRIBUTING.md) to find out how to create a pull request.
123+
124+
## Support
125+
If you have a feature request, or spotted a bug or a technical problem, create a GitHub issue. For other questions, contact our [support team](https://support.adyen.com/).
105126

106127
## Licence
128+
This repository is available under the [MIT license](LICENSE).
107129

108-
MIT license. For more information, see the LICENSE file.
130+
## See also
131+
* [example integration](https://github.com/adyen-examples/adyen-node-online-payments)

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@adyen/api-library",
3-
"version": "8.0.0",
3+
"version": "8.1.0",
44
"description": "The Adyen API Library for NodeJS enables you to work with Adyen APIs.",
55
"main": "lib/src/index.js",
66
"types": "lib/src/index.d.ts",
@@ -41,7 +41,7 @@
4141
"@typescript-eslint/parser": "2.34.0",
4242
"acorn": "^8.0.1",
4343
"coveralls": "3.1.0",
44-
"dotenv": "^8.2.0",
44+
"dotenv": "^9.0.0",
4545
"eslint": "6.8.0",
4646
"jest": "25.5.4",
4747
"jest-ts-auto-mock": "^2.0.0",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* ######
3+
* ######
4+
* ############ ####( ###### #####. ###### ############ ############
5+
* ############# #####( ###### #####. ###### ############# #############
6+
* ###### #####( ###### #####. ###### ##### ###### ##### ######
7+
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
8+
* ###### ###### #####( ###### #####. ###### ##### ##### ######
9+
* ############# ############# ############# ############# ##### ######
10+
* ############ ############ ############# ############ ##### ######
11+
* ######
12+
* #############
13+
* ############
14+
* Adyen NodeJS API Library
15+
* Copyright (c) 2020 Adyen B.V.
16+
* This file is open source and available under the MIT license.
17+
* See the LICENSE file for more info.
18+
*/
19+
20+
export const notifyShopperSuccess = {
21+
"message": "Request Processed Successfully",
22+
"resultCode": "Success",
23+
"shopperNotificationReference": "9915003646742627",
24+
"storedPaymentMethodId": "8415995487234100",
25+
"pspReference": "9915003646742627",
26+
"reference": "Example reference",
27+
"displayedReference": "Example displayed reference"
28+
};

src/__tests__/checkout.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ function createAmountObject(currency: string, value: number): Amount {
6161
function createPaymentsDetailsRequest(): DetailsRequest {
6262
return {
6363
details: {
64-
mD: "mdValue",
65-
paRes: "paResValue",
64+
MD: "mdValue",
65+
PaRes: "paResValue",
6666
},
6767
paymentData: "Ab02b4c0!BQABAgCJN1wRZuGJmq8dMncmypvknj9s7l5Tj...",
6868
};

src/__tests__/recurring.spec.ts

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,33 @@ import nock from "nock";
2121
import { createClient } from "../__mocks__/base";
2222
import { disableSuccess } from "../__mocks__/recurring/disableSuccess";
2323
import { listRecurringDetailsSuccess } from "../__mocks__/recurring/listRecurringDetailsSuccess";
24-
import Recurring from "../services/recurring";
24+
import { notifyShopperSuccess } from "../__mocks__/recurring/notifyShopperSuccess";
25+
import RecurringService from "../services/recurring";
2526
import Client from "../client";
2627
import { paymentsSuccess } from "../__mocks__/checkout/paymentsSuccess";
2728
import { createPaymentsCheckoutRequest } from "./checkout.spec";
2829
import Checkout from "../services/checkout";
2930
import { PaymentRequest } from "../typings/checkout/models";
30-
31-
const createRecurringDetailsRequest = (): IRecurring.RecurringDetailsRequest => {
31+
import {
32+
ScheduleAccountUpdaterRequest,
33+
ScheduleAccountUpdaterResult,
34+
DisableRequest,
35+
RecurringDetailsRequest,
36+
Recurring,
37+
NotifyShopperRequest
38+
} from "../typings/recurring/models";
39+
40+
const createRecurringDetailsRequest = (): RecurringDetailsRequest => {
3241
return {
3342
merchantAccount: process.env.ADYEN_MERCHANT!,
34-
recurring: { contract: "RECURRING" },
43+
recurring: { contract: Recurring.ContractEnum.Recurring },
3544
shopperReference: "shopperReference",
3645
};
3746
};
3847
const isCI = process.env.CI === "true" || (typeof process.env.CI === "boolean" && process.env.CI);
3948

4049
let client: Client;
41-
let recurring: Recurring;
50+
let recurring: RecurringService;
4251
let checkout: Checkout;
4352
let scope: nock.Scope;
4453

@@ -47,7 +56,7 @@ beforeEach((): void => {
4756
nock.activate();
4857
}
4958
client = createClient();
50-
recurring = new Recurring(client);
59+
recurring = new RecurringService(client);
5160
checkout = new Checkout(client);
5261
scope = nock(`${client.config.endpoint}/pal/servlet/Recurring/${Client.RECURRING_API_VERSION}`);
5362
});
@@ -82,7 +91,7 @@ describe("Recurring", (): void => {
8291
scope.post("/disable")
8392
.reply(200, disableSuccess);
8493

85-
const request: IRecurring.DisableRequest = {
94+
const request: DisableRequest = {
8695
merchantAccount: process.env.ADYEN_MERCHANT!,
8796
shopperReference: "shopperReference",
8897
recurringDetailReference: res.additionalData!["recurring.recurringDetailReference"]
@@ -96,19 +105,45 @@ describe("Recurring", (): void => {
96105
}
97106
});
98107

108+
test.each([isCI, true])("should send pre-debit Notification, isMock %p", async (isMock): Promise<void> => {
109+
!isMock && nock.restore();
110+
scope.post("/notifyShopper")
111+
.reply(200, notifyShopperSuccess);
112+
113+
const notifyShopperRequest: NotifyShopperRequest = {
114+
merchantAccount: process.env.ADYEN_MERCHANT!,
115+
shopperReference: "shopperReference",
116+
storedPaymentMethodId: "8415995487234100",
117+
amount: {
118+
currency: "INR",
119+
value: 1000
120+
},
121+
billingDate: "2021-03-16",
122+
reference: "Example reference",
123+
displayedReference: "Example displayed reference"
124+
};
125+
126+
try {
127+
const result = await recurring.notifyShopper(notifyShopperRequest);
128+
expect(result).toBeTruthy();
129+
} catch (e) {
130+
fail(e.message);
131+
}
132+
});
133+
99134

100135
// TODO: register account for AccountUpdater and unmock test
101136
test.each([true])("should schedule account updater, isMock: %p", async (isMock): Promise<void> => {
102137
!isMock && nock.restore();
103-
const scheduleAccountUpdaterSuccess: IRecurring.ScheduleAccountUpdaterResult = {
138+
const scheduleAccountUpdaterSuccess: ScheduleAccountUpdaterResult = {
104139
pspReference: "mocked_psp",
105140
result: "SUCCESS"
106141
};
107142

108143
scope.post("/scheduleAccountUpdater")
109144
.reply(200, scheduleAccountUpdaterSuccess);
110145

111-
const request: IRecurring.ScheduleAccountUpdaterRequest = {
146+
const request: ScheduleAccountUpdaterRequest = {
112147
merchantAccount: process.env.ADYEN_MERCHANT!,
113148
reference: "ref",
114149
card: {

src/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class Client {
111111
this.config.endpoint = Client.ENDPOINT_LIVE;
112112
this.config.marketPayEndpoint = Client.MARKETPAY_ENDPOINT_LIVE;
113113
this.config.hppEndpoint = Client.HPP_LIVE;
114+
this.config.terminalApiCloudEndpoint = Client.TERMINAL_API_ENDPOINT_LIVE;
114115
if (liveEndpointUrlPrefix) {
115116
this.config.endpoint =
116117
`${Client.ENDPOINT_PROTOCOL}${liveEndpointUrlPrefix}${Client.ENDPOINT_LIVE_SUFFIX}`;

src/security/nexoCrypto.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class NexoCrypto {
4242
securityKey: SecurityKey,
4343
): SaleToPOISecuredMessage {
4444
const derivedKey: NexoDerivedKey = NexoDerivedKeyGenerator.deriveKeyMaterial(securityKey.passphrase);
45-
const saleToPoiMessageByteArray = Buffer.from(saleToPoiMessageJson, "ascii");
45+
const saleToPoiMessageByteArray = Buffer.from(saleToPoiMessageJson, "utf-8");
4646
const ivNonce = NexoCrypto.generateRandomIvNonce();
4747
const encryptedSaleToPoiMessage = NexoCrypto.crypt(saleToPoiMessageByteArray, derivedKey, ivNonce, Modes.ENCRYPT);
4848
const encryptedSaleToPoiMessageHmac = NexoCrypto.hmac(saleToPoiMessageByteArray, derivedKey);
@@ -74,7 +74,7 @@ class NexoCrypto {
7474
const receivedHmac = Buffer.from(saleToPoiSecureMessage.securityTrailer.hmac, "base64");
7575
this.validateHmac(receivedHmac, decryptedSaleToPoiMessageByteArray, derivedKey);
7676

77-
return decryptedSaleToPoiMessageByteArray.toString("ascii");
77+
return decryptedSaleToPoiMessageByteArray.toString("utf-8");
7878
}
7979

8080
private static validateSecurityKey(securityKey: SecurityKey): void {

src/services/recurring.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,59 @@ import Service from "../service";
2323
import Disable from "./resource/recurring/disable";
2424
import ListRecurringDetails from "./resource/recurring/listRecurringDetails";
2525
import ScheduleAccountUpdater from "./resource/recurring/scheduleAccountUpdater";
26+
import NotifyShopper from "./resource/recurring/notifyShopper";
27+
import {
28+
RecurringDetailsRequest,
29+
RecurringDetailsResult,
30+
DisableRequest,
31+
DisableResult,
32+
ScheduleAccountUpdaterRequest,
33+
ScheduleAccountUpdaterResult,
34+
NotifyShopperRequest,
35+
NotifyShopperResult
36+
} from "../typings/recurring/models";
2637

2738
class Recurring extends Service {
2839
private readonly _listRecurringDetails: ListRecurringDetails;
2940
private readonly _disable: Disable;
3041
private readonly _scheduleAccountUpdater: ScheduleAccountUpdater;
42+
private readonly _notifyShopper: NotifyShopper
3143

3244
public constructor(client: Client) {
3345
super(client);
3446
this._listRecurringDetails = new ListRecurringDetails(this);
3547
this._disable = new Disable(this);
3648
this._scheduleAccountUpdater = new ScheduleAccountUpdater(this);
49+
this._notifyShopper = new NotifyShopper(this);
3750
}
3851

39-
public listRecurringDetails(request: IRecurring.RecurringDetailsRequest): Promise<IRecurring.RecurringDetailsResult> {
40-
return getJsonResponse<IRecurring.RecurringDetailsRequest, IRecurring.RecurringDetailsResult>(
52+
public listRecurringDetails(request: RecurringDetailsRequest): Promise<RecurringDetailsResult> {
53+
return getJsonResponse<RecurringDetailsRequest, RecurringDetailsResult>(
4154
this._listRecurringDetails,
4255
request,
4356
);
4457
}
4558

46-
public disable(request: IRecurring.DisableRequest): Promise<IRecurring.DisableResult> {
47-
return getJsonResponse<IRecurring.DisableRequest, IRecurring.DisableResult>(
59+
public disable(request: DisableRequest): Promise<DisableResult> {
60+
return getJsonResponse<DisableRequest, DisableResult>(
4861
this._disable,
4962
request,
5063
);
5164
}
5265

53-
public scheduleAccountUpdater(request: IRecurring.ScheduleAccountUpdaterRequest): Promise<IRecurring.ScheduleAccountUpdaterResult> {
54-
return getJsonResponse<IRecurring.ScheduleAccountUpdaterRequest, IRecurring.ScheduleAccountUpdaterResult>(
66+
public scheduleAccountUpdater(request: ScheduleAccountUpdaterRequest): Promise<ScheduleAccountUpdaterResult> {
67+
return getJsonResponse<ScheduleAccountUpdaterRequest, ScheduleAccountUpdaterResult>(
5568
this._scheduleAccountUpdater,
5669
request,
5770
);
5871
}
72+
73+
public notifyShopper(request: NotifyShopperRequest): Promise<NotifyShopperResult> {
74+
return getJsonResponse<NotifyShopperRequest, NotifyShopperResult>(
75+
this._notifyShopper,
76+
request
77+
);
78+
}
5979
}
6080

6181
export default Recurring;

0 commit comments

Comments
 (0)