Refactoring of Notification type definitions and Object.serializer

This commit is contained in:
Ricardo Ambrogi
2020-05-22 08:58:56 +02:00
parent 4ebc4caa53
commit 364da4ffde
14 changed files with 570 additions and 279 deletions

View File

@@ -22,4 +22,4 @@
}
}
]
}
}

View File

@@ -1,21 +1,21 @@
import HmacValidator from "../utils/hmacValidator";
import {NotificationRequestItem} from "../typings/notification";
import {AdditionalData, NotificationRequestItem} from "../typings/notification/models";
import {ApiConstants} from "../constants/apiConstants";
const key = "DFB1EB5485895CFA84146406857104ABB4CBCABDC8AAF103A624C8F6A3EAAB00";
const expectedSign = "ipnxGCaUZ4l8TUW75a71/ghd2Fe5ffvX0pV4TLTntIc=";
const expectedSign = "xhpHvYq2u2Np0rstbZ6QjLGu7JWhvf7Iwaa6EviJSX0=";
const notificationRequestItem: NotificationRequestItem = {
pspReference: "pspReference",
originalReference: "originalReference",
merchantAccountCode: "merchantAccount",
merchantReference: "reference",
amount: {currency: "EUR", value: 1000},
eventCode: "EVENT",
eventDate: new Date("01-01-1970"),
eventCode: NotificationRequestItem.EventCodeEnum.CAPTURE,
eventDate: new Date("01-01-1970").toISOString(),
paymentMethod: "VISA",
reason: "reason",
success: "true",
additionalData: { [ApiConstants.HMAC_SIGNATURE]: expectedSign },
success: NotificationRequestItem.SuccessEnum.True,
additionalData: { [ApiConstants.HMAC_SIGNATURE as keyof AdditionalData]: expectedSign },
};
describe("HMAC Validator", function (): void {
@@ -39,7 +39,7 @@ describe("HMAC Validator", function (): void {
});
it("should get correct data to sign", function (): void {
const data = hmacValidator.getDataToSign(notificationRequestItem);
expect(data).toEqual("pspReference:originalReference:merchantAccount:reference:1000:EUR:EVENT:true");
expect(data).toEqual("pspReference:originalReference:merchantAccount:reference:1000:EUR:CAPTURE:true");
});
it("should have valid hmac", function (): void {
@@ -51,7 +51,7 @@ describe("HMAC Validator", function (): void {
it("should have invalid hmac", function (): void {
const invalidNotification = {
...notificationRequestItem,
additionalData: { [ApiConstants.HMAC_SIGNATURE]: "notValidSign" }
additionalData: { [ApiConstants.HMAC_SIGNATURE as keyof NotificationRequestItem]: "notValidSign" }
};
const result = hmacValidator.validateHMAC(invalidNotification, key);
expect(result).toBeFalsy();

View File

@@ -4,7 +4,10 @@ import captureFalse from "../__mocks__/notification/captureFalse.json";
import refundTrue from "../__mocks__/notification/refundTrue.json";
import refundFalse from "../__mocks__/notification/refundFalse.json";
import NotificationRequest from "../notification/notificationRequest";
import {Notification, NotificationEnum, NotificationRequestItem} from "../typings/notification";
import {Notification, NotificationRequestItem} from "../typings/notification/models";
import NotificationEnum = NotificationRequestItem.EventCodeEnum;
import SuccessEnum = NotificationRequestItem.SuccessEnum;
describe("Notification Test", function (): void {
it("should return authorisation success", function (): void {
@@ -13,8 +16,8 @@ describe("Notification Test", function (): void {
if (notificationRequest.notificationItems) {
const notificationRequestItem: NotificationRequestItem = notificationRequest.notificationItems[0];
expect(NotificationEnum.EVENT_CODE_AUTHORISATION).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === "true").toBeTruthy();
expect(NotificationEnum.AUTHORISATION).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === SuccessEnum.True).toBeTruthy();
expect(notificationRequestItem.pspReference).toEqual("123456789");
} else {
fail();
@@ -27,8 +30,8 @@ describe("Notification Test", function (): void {
if (notificationRequest.notificationItems) {
const notificationRequestItem = notificationRequest.notificationItems[0];
expect(NotificationEnum.EVENT_CODE_CAPTURE).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === "true").toBeTruthy();
expect(NotificationEnum.CAPTURE).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === SuccessEnum.True).toBeTruthy();
expect(notificationRequestItem.pspReference).toEqual("PSP_REFERENCE");
expect(notificationRequestItem.originalReference).toEqual("ORIGINAL_PSP");
} else {
@@ -42,8 +45,8 @@ describe("Notification Test", function (): void {
if (notificationRequest.notificationItems) {
const notificationRequestItem = notificationRequest.notificationItems[0];
expect(NotificationEnum.EVENT_CODE_CAPTURE).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === "true").toBeFalsy();
expect(NotificationEnum.CAPTURE).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === SuccessEnum.True).toBeFalsy();
expect(notificationRequestItem.pspReference).toEqual("PSP_REFERENCE");
expect(notificationRequestItem.originalReference).toEqual("ORIGINAL_PSP");
} else {
@@ -57,8 +60,8 @@ describe("Notification Test", function (): void {
if (notificationRequest.notificationItems) {
const notificationRequestItem = notificationRequest.notificationItems[0];
expect(NotificationEnum.EVENT_CODE_REFUND).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === "true").toBeTruthy();
expect(NotificationEnum.REFUND).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === SuccessEnum.True).toBeTruthy();
expect(notificationRequestItem.pspReference).toEqual("PSP_REFERENCE");
expect(notificationRequestItem.originalReference).toEqual("ORIGINAL_PSP");
expect(notificationRequestItem.eventDate).toBeDefined();
@@ -73,8 +76,8 @@ describe("Notification Test", function (): void {
if (notificationRequest.notificationItems) {
const notificationRequestItem = notificationRequest.notificationItems[0];
expect(NotificationEnum.EVENT_CODE_REFUND).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === "true").toBeFalsy();
expect(NotificationEnum.REFUND).toEqual(notificationRequestItem.eventCode);
expect(notificationRequestItem.success === SuccessEnum.True).toBeFalsy();
expect(notificationRequestItem.pspReference).toEqual("PSP_REFERENCE");
expect(notificationRequestItem.originalReference).toEqual("ORIGINAL_PSP");
expect(notificationRequestItem.eventDate).toBeDefined();

View File

@@ -23,7 +23,7 @@ let accountHolderToUnSuspend: A.CreateAccountHolderResponse;
let accountHolderToClose: A.CreateAccountHolderResponse;
let notificationConfigurationToRetrieve: N.GetNotificationConfigurationResponse;
const generateRandomCode = () => Math.floor(Math.random() * Date.now()).toString();
const generateRandomCode = (): string => Math.floor(Math.random() * Date.now()).toString();
const accountHolderDetails: AccountHolderDetails = {
email: "random_email@example.com",
fullPhoneNumber: "312030291928",

View File

@@ -18,25 +18,30 @@
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/
import {Convert, Notification, NotificationItem, NotificationRequestItem} from "../typings/notification";
import {
Notification,
NotificationItem,
NotificationRequestItem,
ObjectSerializer
} from "../typings/notification/models";
class NotificationRequest {
public constructor(json: Notification) {
const notification = Convert.toNotification(JSON.stringify(json));
const notification: Notification = ObjectSerializer.deserialize(json, "Notification");
this.notificationItemContainers = notification.notificationItems;
this.live = notification.live;
}
public get notificationItems(): NotificationRequestItem[] | undefined {
public get notificationItems(): Array<NotificationRequestItem> | undefined {
if (!this.notificationItemContainers) {
return undefined;
}
return this.notificationItemContainers.map((container): NotificationRequestItem => container.NotificationRequestItem);
return this.notificationItemContainers.map((container): NotificationRequestItem => container.notificationRequestItem);
}
public live: string;
public notificationItemContainers: NotificationItem[];
public notificationItemContainers: Array<NotificationItem>;
}
export default NotificationRequest;

View File

@@ -7,7 +7,7 @@
/// <reference path="enums/environment.ts" />
/// <reference path="enums/vatCategory.ts" />
/// <reference path="nexo.ts" />
/// <reference path="notification.ts" />
/// <reference path="notification/notification.ts" />
/// <reference path="payments.ts" />
/// <reference path="payouts.ts" />
/// <reference path="recurring.ts" />

View File

@@ -1,250 +0,0 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen NodeJS API Library
*
* Copyright (c) 2019 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/
// To parse this data:
//
// import { Convert, Notification } from "./file";
//
// const notification = Convert.toNotification(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface Notification {
live: string;
notificationItems: NotificationItem[];
}
export interface NotificationItem {
NotificationRequestItem: NotificationRequestItem;
}
export interface NotificationRequestItem {
additionalData: AdditionalData;
amount: Amount;
eventCode: string;
eventDate: Date;
merchantAccountCode: string;
merchantReference: string;
operations?: string[];
originalReference?: string;
paymentMethod: string;
pspReference: string;
reason: string;
success: string;
}
export interface AdditionalData {
[key: string]: string;
}
export interface Amount {
currency: string;
value: number;
}
export enum NotificationEnum {
EVENT_CODE_AUTHORISATION = "AUTHORISATION",
//Event codes
EVENT_CODE_CANCELLATION = "CANCELLATION",
EVENT_CODE_REFUND = "REFUND",
EVENT_CODE_CANCEL_OR_REFUND = "CANCEL_OR_REFUND",
EVENT_CODE_CAPTURE = "CAPTURE",
EVENT_CODE_CAPTURE_FAILED = "CAPTURE_FAILED",
EVENT_CODE_REFUND_FAILED = "REFUND_FAILED",
EVENT_CODE_REFUNDED_REVERSED = "REFUNDED_REVERSED",
EVENT_CODE_PAIDOUT_REVERSED = "PAIDOUT_REVERSED",
//Additional Data
ADDITIONAL_DATA_TOTAL_FRAUD_SCORE = "totalFraudScore",
ADDITIONAL_DATA_FRAUD_CHECK_PATTERN = "fraudCheck-(\\d+)-([A-Za-z0-9]+)",
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toNotification(json: string): Notification {
return cast(JSON.parse(json), r("Notification"));
}
public static notificationToJson(value: Notification): string {
return JSON.stringify(uncast(value, r("Notification")), null, 2);
}
}
function invalidValue(typ: any, val: any): never {
throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`);
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
var map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
var map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
var l = typs.length;
for (var i = 0; i < l; i++) {
var typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases, val);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue("array", val);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(typ: any, val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue("Date", val);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue("object", val);
}
var result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val);
}
if (typ === false) return invalidValue(typ, val);
while (typeof typ === "object" && typ.ref !== undefined) {
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(typ, val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
// @ts-ignore
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"Notification": o([
{ json: "live", js: "live", typ: "" },
{ json: "notificationItems", js: "notificationItems", typ: a(r("NotificationItem")) },
], false),
"NotificationItem": o([
{ json: "NotificationRequestItem", js: "NotificationRequestItem", typ: r("NotificationRequestItem") },
], false),
"NotificationRequestItem": o([
{ json: "additionalData", js: "additionalData", typ: u(undefined, m("any")) },
{ json: "amount", js: "amount", typ: r("Amount") },
{ json: "eventCode", js: "eventCode", typ: "" },
{ json: "eventDate", js: "eventDate", typ: Date },
{ json: "merchantAccountCode", js: "merchantAccountCode", typ: "" },
{ json: "merchantReference", js: "merchantReference", typ: "" },
{ json: "operations", js: "operations", typ: u(undefined, a("")) },
{ json: "originalReference", js: "originalReference", typ: u(undefined, "") },
{ json: "paymentMethod", js: "paymentMethod", typ: "" },
{ json: "pspReference", js: "pspReference", typ: "" },
{ json: "reason", js: "reason", typ: "" },
{ json: "success", js: "success", typ: "" },
], false),
"Amount": o([
{ json: "currency", js: "currency", typ: "" },
{ json: "value", js: "value", typ: 0 },
], false),
};

View File

@@ -0,0 +1,89 @@
/**
* Notification API
* Definition of Notification API Schema
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* The additionalData object is a generic container that can hold extra fields. For more information, refer to NotificationRequestItem.additionalData .
*/
export class AdditionalData {
/**
* The ID that uniquely identifies the shopper. This shopperReference is the same as the shopperReference used in the initial payment.
*/
'shopperReference'?: string;
/**
* The shopper\'s email address.
*/
'shopperEmail'?: string;
/**
* Authorisation code: When the payment is authorised successfully, this field holds the authorisation code for the payment. When the payment is not authorised, this field is empty.
*/
'authCode'?: string;
/**
* Returns the last 4 digits of the credit card.
*/
'cardSummary'?: string;
/**
* Returns the card expiry date.
*/
'expiryDate'?: string;
/**
* Value of the amount authorised.
*/
'authorisedAmountValue'?: string;
/**
* Currency of the authorised amount.
*/
'authorisedAmountCurrency'?: string;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "shopperReference",
"baseName": "shopperReference",
"type": "string"
},
{
"name": "shopperEmail",
"baseName": "shopperEmail",
"type": "string"
},
{
"name": "authCode",
"baseName": "authCode",
"type": "string"
},
{
"name": "cardSummary",
"baseName": "cardSummary",
"type": "string"
},
{
"name": "expiryDate",
"baseName": "expiryDate",
"type": "string"
},
{
"name": "authorisedAmountValue",
"baseName": "authorisedAmountValue",
"type": "string"
},
{
"name": "authorisedAmountCurrency",
"baseName": "authorisedAmountCurrency",
"type": "string"
} ];
static getAttributeTypeMap() {
return AdditionalData.attributeTypeMap;
}
}

View File

@@ -0,0 +1,45 @@
/**
* Notification API
* Definition of Notification API Schema
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* A container object for the payable amount information for the transaction.For HTTP POST notifications, currency and value are returned as URL parameters.
*/
export class Amount {
/**
* The three-character ISO currency code. https://docs.adyen.com/development-resources/currency-codes
*/
'currency'?: string;
/**
* The payable amount that can be charged for the transaction. The transaction amount needs to be represented in minor units according to the following table: https://docs.adyen.com/development-resources/currency-codes
*/
'value'?: number;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "currency",
"baseName": "currency",
"type": "string"
},
{
"name": "value",
"baseName": "value",
"type": "number"
} ];
static getAttributeTypeMap() {
return Amount.attributeTypeMap;
}
}

View File

@@ -0,0 +1,148 @@
export * from './additionalData';
export * from './amount';
export * from './notification';
export * from './notificationItem';
export * from './notificationRequestItem';
import { AdditionalData } from './additionalData';
import { Amount } from './amount';
import { Notification } from './notification';
import { NotificationItem } from './notificationItem';
import { NotificationRequestItem } from './notificationRequestItem';
/* tslint:disable:no-unused-variable */
let primitives = [
"string",
"boolean",
"double",
"integer",
"long",
"float",
"number",
"any"
];
let enumsMap: {[index: string]: any} = {
"NotificationRequestItem.EventCodeEnum": NotificationRequestItem.EventCodeEnum,
"NotificationRequestItem.OperationsEnum": NotificationRequestItem.OperationsEnum,
"NotificationRequestItem.SuccessEnum": NotificationRequestItem.SuccessEnum,
}
let typeMap: {[index: string]: any} = {
"AdditionalData": AdditionalData,
"Amount": Amount,
"Notification": Notification,
"NotificationItem": NotificationItem,
"NotificationRequestItem": NotificationRequestItem,
}
export class ObjectSerializer {
public static findCorrectType(data: any, expectedType: string) {
if (data == undefined) {
return expectedType;
} else if (primitives.indexOf(expectedType.toLowerCase()) !== -1) {
return expectedType;
} else if (expectedType === "Date") {
return expectedType;
} else {
if (enumsMap[expectedType]) {
return expectedType;
}
if (!typeMap[expectedType]) {
return expectedType; // w/e we don't know the type
}
// Check the discriminator
let discriminatorProperty = typeMap[expectedType].discriminator;
if (discriminatorProperty == null) {
return expectedType; // the type does not have a discriminator. use it.
} else {
if (data[discriminatorProperty]) {
var discriminatorType = data[discriminatorProperty];
if(typeMap[discriminatorType]){
return discriminatorType; // use the type given in the discriminator
} else {
return expectedType; // discriminator did not map to a type
}
} else {
return expectedType; // discriminator was not present (or an empty string)
}
}
}
}
public static serialize(data: any, type: string) {
if (data == undefined) {
return data;
} else if (primitives.indexOf(type.toLowerCase()) !== -1) {
return data;
} else if (type.lastIndexOf("Array<", 0) === 0) { // string.startsWith pre es6
let subType: string = type.replace("Array<", ""); // Array<Type> => Type>
subType = subType.substring(0, subType.length - 1); // Type> => Type
let transformedData: any[] = [];
for (let index in data) {
let date = data[index];
transformedData.push(ObjectSerializer.serialize(date, subType));
}
return transformedData;
} else if (type === "Date") {
return data.toISOString();
} else {
if (enumsMap[type]) {
return data;
}
if (!typeMap[type]) { // in case we dont know the type
return data;
}
// Get the actual type of this object
type = this.findCorrectType(data, type);
// get the map for the correct type.
let attributeTypes = typeMap[type].getAttributeTypeMap();
let instance: {[index: string]: any} = {};
for (let index in attributeTypes) {
let attributeType = attributeTypes[index];
instance[attributeType.baseName] = ObjectSerializer.serialize(data[attributeType.name], attributeType.type);
}
return instance;
}
}
public static deserialize(data: any, type: string) {
// polymorphism may change the actual type.
type = ObjectSerializer.findCorrectType(data, type);
if (data == undefined) {
return data;
} else if (primitives.indexOf(type.toLowerCase()) !== -1) {
return data;
} else if (type.lastIndexOf("Array<", 0) === 0) { // string.startsWith pre es6
let subType: string = type.replace("Array<", ""); // Array<Type> => Type>
subType = subType.substring(0, subType.length - 1); // Type> => Type
let transformedData: any[] = [];
for (let index in data) {
let date = data[index];
transformedData.push(ObjectSerializer.deserialize(date, subType));
}
return transformedData;
} else if (type === "Date") {
return new Date(data);
} else {
if (enumsMap[type]) {// is Enum
return data;
}
if (!typeMap[type]) { // dont know the type
return data;
}
let instance = new typeMap[type]();
let attributeTypes = typeMap[type].getAttributeTypeMap();
for (let index in attributeTypes) {
let attributeType = attributeTypes[index];
instance[attributeType.name] = ObjectSerializer.deserialize(data[attributeType.baseName], attributeType.type);
}
return instance;
}
}
}

View File

@@ -0,0 +1,43 @@
/**
* Notification API
* Definition of Notification API Schema
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { NotificationItem } from './notificationItem';
export class Notification {
/**
* Informs about the origin of the notification: - true: the notification originated from the live environment. - false: the notification originated from the test environment.
*/
'live': string;
/**
* A container object for the details included in the notification.
*/
'notificationItems': Array<NotificationItem>;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "live",
"baseName": "live",
"type": "string"
},
{
"name": "notificationItems",
"baseName": "notificationItems",
"type": "Array<NotificationItem>"
} ];
static getAttributeTypeMap() {
return Notification.attributeTypeMap;
}
}

View File

@@ -0,0 +1,31 @@
/**
* Notification API
* Definition of Notification API Schema
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { NotificationRequestItem } from './notificationRequestItem';
export class NotificationItem {
'notificationRequestItem': NotificationRequestItem;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "notificationRequestItem",
"baseName": "NotificationRequestItem",
"type": "NotificationRequestItem"
} ];
static getAttributeTypeMap() {
return NotificationItem.attributeTypeMap;
}
}

View File

@@ -0,0 +1,177 @@
/**
* Notification API
* Definition of Notification API Schema
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { AdditionalData } from './additionalData';
import { Amount } from './amount';
export class NotificationRequestItem {
'additionalData'?: AdditionalData;
'amount': Amount;
/**
* Adyen\'s 16-character unique reference associated with the transaction/the request. This value is globally unique; quote it when communicating with us about this request.
*/
'pspReference': string;
/**
* The type of event the notification item refers to. When eventCode returns AUTHORISATION, it does not necessarily mean that the payment authorisation request has been successfully processed. The authorisation is successful if success = true. If success = false, check the the reason value for further information on the authorisation failure cause. This can occur, for example, if an error occurs or if the transaction is refused.
*/
'eventCode': NotificationRequestItem.EventCodeEnum;
/**
* The time when the event was generated.
*/
'eventDate': string;
/**
* The merchant account identifier used in the transaction the notification item refers to.
*/
'merchantAccountCode': string;
/**
* This field holds a list of the modification operations supported by the transaction the notification item refers to. The available operations in the list give information on the follow-up actions concerning the payment. You may be requested to: Capture the payment (for example, if auto-capture is not set up), Cancel the payment (if the payment has not been captured yet), or Refund the payment (if the payment has already been captured).
*/
'operations'?: Array<NotificationRequestItem.OperationsEnum>;
/**
* A reference to uniquely identify the payment.This reference is used in all communication with you about the payment status.We recommend using a unique value per payment; however, it is not a requirement. If you need to provide multiple references for a transaction, you can enter them in this field. Separate each reference value with a hyphen character (\'-\'). This field has a length restriction: you can enter max. 80 characters.
*/
'merchantReference': string;
/**
* If the notification item is about a payment authorisation, this field is not populated and is blank. If the notification item is about a modification, the originalReference value corresponds to the payment request assigned to the original payment.
*/
'originalReference'?: string;
/**
* The payment method used in the transaction the notification item refers to.
*/
'paymentMethod'?: string;
/**
* This field holds plain text. For more information, refer to the reason field values below.
*/
'reason'?: string;
/**
* Informs about the outcome of the event ( eventCode ) the notification refers to. true: the event ( eventCode ) the notification refers to was executed successfully. false: the event was not executed successfully.
*/
'success': NotificationRequestItem.SuccessEnum;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "additionalData",
"baseName": "additionalData",
"type": "AdditionalData"
},
{
"name": "amount",
"baseName": "amount",
"type": "Amount"
},
{
"name": "pspReference",
"baseName": "pspReference",
"type": "string"
},
{
"name": "eventCode",
"baseName": "eventCode",
"type": "NotificationRequestItem.EventCodeEnum"
},
{
"name": "eventDate",
"baseName": "eventDate",
"type": "string"
},
{
"name": "merchantAccountCode",
"baseName": "merchantAccountCode",
"type": "string"
},
{
"name": "operations",
"baseName": "operations",
"type": "Array<NotificationRequestItem.OperationsEnum>"
},
{
"name": "merchantReference",
"baseName": "merchantReference",
"type": "string"
},
{
"name": "originalReference",
"baseName": "originalReference",
"type": "string"
},
{
"name": "paymentMethod",
"baseName": "paymentMethod",
"type": "string"
},
{
"name": "reason",
"baseName": "reason",
"type": "string"
},
{
"name": "success",
"baseName": "success",
"type": "NotificationRequestItem.SuccessEnum"
} ];
static getAttributeTypeMap() {
return NotificationRequestItem.attributeTypeMap;
}
}
export namespace NotificationRequestItem {
export enum EventCodeEnum {
AUTHORISATION = <any> 'AUTHORISATION',
AUTHORISATIONADJUSTMENT = <any> 'AUTHORISATION_ADJUSTMENT',
CANCELLATION = <any> 'CANCELLATION',
CANCELORREFUND = <any> 'CANCEL_OR_REFUND',
CAPTURE = <any> 'CAPTURE',
CAPTUREFAILED = <any> 'CAPTURE_FAILED',
HANDLEDEXTERNALLY = <any> 'HANDLED_EXTERNALLY',
ORDEROPENED = <any> 'ORDER_OPENED',
ORDERCLOSED = <any> 'ORDER_CLOSED',
PENDING = <any> 'PENDING',
PROCESSRETRY = <any> 'PROCESS_RETRY',
REFUND = <any> 'REFUND',
REFUNDFAILED = <any> 'REFUND_FAILED',
REFUNDEDREVERSED = <any> 'REFUNDED_REVERSED',
REFUNDWITHDATA = <any> 'REFUND_WITH_DATA',
REPORTAVAILABLE = <any> 'REPORT_AVAILABLE',
VOIDPENDINGREFUND = <any> 'VOID_PENDING_REFUND',
CHARGEBACK = <any> 'CHARGEBACK',
CHARGEBACKREVERSED = <any> 'CHARGEBACK_REVERSED',
NOTIFICATIONOFCHARGEBACK = <any> 'NOTIFICATION_OF_CHARGEBACK',
NOTIFICATIONOFFRAUD = <any> 'NOTIFICATION_OF_FRAUD',
PREARBITRATIONLOST = <any> 'PREARBITRATION_LOST',
PREARBITRATIONWON = <any> 'PREARBITRATION_WON',
REQUESTFORINFORMATION = <any> 'REQUEST_FOR_INFORMATION',
SECONDCHARGEBACK = <any> 'SECOND_CHARGEBACK',
PAYOUTEXPIRE = <any> 'PAYOUT_EXPIRE',
PAYOUTDECLINE = <any> 'PAYOUT_DECLINE',
PAYOUTTHIRDPARTY = <any> 'PAYOUT_THIRDPARTY',
PAIDOUTREVERSED = <any> 'PAIDOUT_REVERSED',
AUTORESCUE = <any> 'AUTORESCUE',
CANCELAUTORESCUE = <any> 'CANCEL_AUTORESCUE',
RECURRINGCONTRACT = <any> 'RECURRING_CONTRACT',
POSTPONEDREFUND = <any> 'POSTPONED_REFUND',
OFFERCLOSED = <any> 'OFFER_CLOSED',
MANUALREVIEWACCEPT = <any> 'MANUAL_REVIEW_ACCEPT',
MANUALREVIEWREJECT = <any> 'MANUAL_REVIEW_REJECT'
}
export enum OperationsEnum {
CANCEL = <any> 'CANCEL',
CAPTURE = <any> 'CAPTURE',
REFUND = <any> 'REFUND'
}
export enum SuccessEnum {
True = <any> 'true',
False = <any> 'false'
}
}

View File

@@ -1,5 +1,5 @@
import {createHmac} from "crypto";
import {NotificationRequestItem} from "../typings/notification";
import {NotificationRequestItem} from "../typings/notification/models";
import {ApiConstants} from "../constants/apiConstants";
type DataToSign = NotificationRequestItem | { [key: string]: string }
@@ -16,7 +16,7 @@ class HmacValidator {
public validateHMAC(notificationRequestItem: NotificationRequestItem, key: string): boolean {
const expectedSign = this.calculateHmac(notificationRequestItem, key);
const merchantSign = notificationRequestItem.additionalData[ApiConstants.HMAC_SIGNATURE];
const merchantSign = notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE];
return expectedSign === merchantSign;
}