From 132200301f771d6c27a72efb1540cc23b308a874 Mon Sep 17 00:00:00 2001 From: MESMUR Date: Tue, 4 Jan 2022 09:52:54 +0530 Subject: [PATCH 1/8] ADD Basic API Versioning Mechanism for Customer Service --- .gitignore | 1 + examples/with_async/customer.js | 8 +++++++- examples/with_promises/customer.js | 11 +++++++++-- src/customer/customer.d.ts | 9 +++++++-- src/customer/customer.js | 12 ++++++++++-- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 6ebe01f..7924267 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ .env .nyc_output coverage +.vscode/ \ No newline at end of file diff --git a/examples/with_async/customer.js b/examples/with_async/customer.js index 4358883..535ae8e 100644 --- a/examples/with_async/customer.js +++ b/examples/with_async/customer.js @@ -14,15 +14,20 @@ const c = new Customer({}); middleName: 'middle', surname: 'surname', addresses: [], + apiVersion: '2020-05-19', }); console.log('created customer', customer); // eslint-disable-line no-console - customer = await c.getCustomer({ id: customer.id }); + customer = await c.getCustomer({ + id: customer.id, + apiVersion: '2020-05-19', + }); // eslint-disable-next-line no-console console.log('retrieved customer', customer); const customers = await c.getCustomerByReferenceID({ referenceID: customer.reference_id, + apiVersion: '2020-05-19', }); // eslint-disable-next-line no-console console.log('retrieved customers', customers); @@ -45,6 +50,7 @@ const c = new Customer({}); city: 'Jakarta', }, ], + apiVersion: '2020-05-19', }); console.log('updated customer', customer); //eslint-disable-line no-console } catch (e) { diff --git a/examples/with_promises/customer.js b/examples/with_promises/customer.js index d4cae82..2cd0b06 100644 --- a/examples/with_promises/customer.js +++ b/examples/with_promises/customer.js @@ -12,17 +12,23 @@ c.createCustomer({ middleName: 'middle', surname: 'surname', addresses: [], + apiVersion: '2020-05-19', }) .then(r => { console.log('created customer', r); // eslint-disable-line no-console return r; }) - .then(r => c.getCustomer({ id: r.id })) + .then(r => c.getCustomer({ id: r.id, apiVersion: '2020-05-19' })) .then(r => { console.log('retrieved customer', r); // eslint-disable-line no-console return r; }) - .then(r => c.getCustomerByReferenceID({ referenceID: r.reference_id })) + .then(r => + c.getCustomerByReferenceID({ + referenceID: r.reference_id, + apiVersion: '2020-05-19', + }), + ) .then(r => { console.log('retrieved customers', r); // eslint-disable-line no-console return r[0]; @@ -46,6 +52,7 @@ c.createCustomer({ city: 'Jakarta', }, ], + apiVersion: '2020-05-19', }), ) .then(r => { diff --git a/src/customer/customer.d.ts b/src/customer/customer.d.ts index f8ce21c..0eed4ad 100644 --- a/src/customer/customer.d.ts +++ b/src/customer/customer.d.ts @@ -28,9 +28,13 @@ export = class Customer { addresses?: Address[]; dateOfBirth?: string; metadata?: object; + apiVersion?: string; + }): Promise; + getCustomer(data: { id: string; apiVersion?: string }): Promise; + getCustomerByReferenceID(data: { + referenceID: string; + apiVersion?: string; }): Promise; - getCustomer(data: { id: string }): Promise; - getCustomerByReferenceID(data: { referenceID: string }): Promise; updateCustomer(data: { id: string; referenceID?: string; @@ -44,5 +48,6 @@ export = class Customer { nationality?: string; dateOfBirth?: string; metadata?: object; + apiVersion?: string; }): Promise; }; diff --git a/src/customer/customer.js b/src/customer/customer.js index 4e86887..4351d34 100644 --- a/src/customer/customer.js +++ b/src/customer/customer.js @@ -37,6 +37,7 @@ Customer.prototype.createCustomer = function(data) { headers: { 'Content-Type': 'application/json', Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'API-VERSION': data.apiVersion ? data.apiVersion : '', }, body: JSON.stringify({ reference_id: data.referenceID, @@ -74,7 +75,10 @@ Customer.prototype.getCustomer = function(data) { fetchWithHTTPErr(`${this.API_ENDPOINT}/customers/${data.id}`, { method: 'GET', - headers: { Authorization: Auth.basicAuthHeader(this.opts.secretKey) }, + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'API-VERSION': data.apiVersion ? data.apiVersion : '', + }, }) .then(resolve) .catch(reject); @@ -89,7 +93,10 @@ Customer.prototype.getCustomerByReferenceID = function(data) { `${this.API_ENDPOINT}/customers?reference_id=${data.referenceID}`, { method: 'GET', - headers: { Authorization: Auth.basicAuthHeader(this.opts.secretKey) }, + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'API-VERSION': data.apiVersion ? data.apiVersion : '', + }, }, ) .then(resolve) @@ -104,6 +111,7 @@ Customer.prototype.updateCustomer = function(data) { headers: { 'Content-Type': 'application/json', Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'API-VERSION': data.apiVersion ? data.apiVersion : '', }, body: JSON.stringify({ reference_id: data.referenceID, From b362edd6e1f43e1ebf746f7030c5b604eda3fa69 Mon Sep 17 00:00:00 2001 From: MESMUR Date: Tue, 4 Jan 2022 13:49:25 +0530 Subject: [PATCH 2/8] ADD EWallet tokenization flow, link account + payment methods --- src/ewallet/ewallet.d.ts | 9 +++++ src/ewallet/ewallet.js | 35 ++++++++++++++----- src/ewallet/linked_account.d.ts | 18 ++++++++++ src/ewallet/linked_account.js | 60 +++++++++++++++++++++++++++++++++ src/ewallet/payment_method.d.ts | 18 ++++++++++ src/ewallet/payment_method.js | 50 +++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 src/ewallet/linked_account.d.ts create mode 100644 src/ewallet/linked_account.js create mode 100644 src/ewallet/payment_method.d.ts create mode 100644 src/ewallet/payment_method.js diff --git a/src/ewallet/ewallet.d.ts b/src/ewallet/ewallet.d.ts index d61d73f..f9324a4 100644 --- a/src/ewallet/ewallet.d.ts +++ b/src/ewallet/ewallet.d.ts @@ -1,4 +1,9 @@ import { XenditOptions } from '../xendit_opts'; +import { initializeTokenization, unlinkTokenization } from './linked_account'; +import { + createPaymentMethod, + getPaymentMethodsByCustomerID, +} from require('./payment_method'); enum CreateSupportWalletTypes { OVO = 'OVO', @@ -100,4 +105,8 @@ export = class EWallet { chargeID: string; forUserID?: string; }): Promise; + initializeTokenization = initializeTokenization; + unlinkTokenization = unlinkTokenization; + createPaymentMethod = createPaymentMethod; + getPaymentMethodsByCustomerID = getPaymentMethodsByCustomerID; }; diff --git a/src/ewallet/ewallet.js b/src/ewallet/ewallet.js index 1b9d3dd..e0f1774 100644 --- a/src/ewallet/ewallet.js +++ b/src/ewallet/ewallet.js @@ -7,7 +7,16 @@ const { } = require('../utils'); const errors = require('../errors'); -const EWALLET_PATH = '/ewallets'; +const { + initializeTokenization, + unlinkTokenization, +} = require('./linked_account'); +const { + createPaymentMethod, + getPaymentMethodsByCustomerID, +} = require('./payment_method'); + +const EWALLET_PATH = ''; function EWallet(options) { let aggOpts = options; @@ -78,7 +87,7 @@ EWallet.prototype.createPayment = function(data) { headers['X-API-VERSION'] = data.xApiVersion; } - fetchWithHTTPErr(this.API_ENDPOINT, { + fetchWithHTTPErr(this.API_ENDPOINT + '/ewallets', { method: 'POST', headers, body: JSON.stringify({ @@ -110,7 +119,7 @@ EWallet.prototype.getPayment = function(data) { }) : ''; - fetchWithHTTPErr(`${this.API_ENDPOINT}?${queryStr}`, { + fetchWithHTTPErr(this.API_ENDPOINT + `/ewallets?${queryStr}`, { method: 'GET', headers: { Authorization: Auth.basicAuthHeader(this.opts.secretKey), @@ -144,7 +153,7 @@ EWallet.prototype.createEWalletCharge = function(data) { headers['with-fee-rule'] = data.withFeeRule; } - fetchWithHTTPErr(`${this.API_ENDPOINT}/charges`, { + fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges`, { method: 'POST', headers: headers, body: JSON.stringify({ @@ -199,7 +208,7 @@ EWallet.prototype.getEWalletChargeStatus = function(data) { headers['for-user-id'] = data.forUserID; } - fetchWithHTTPErr(`${this.API_ENDPOINT}/charges/${data.chargeID}`, { + fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}`, { method: 'GET', headers: headers, }) @@ -221,13 +230,21 @@ EWallet.prototype.voidEWalletCharge = function(data) { headers['for-user-id'] = data.forUserID; } - fetchWithHTTPErr(`${this.API_ENDPOINT}/charges/${data.chargeID}/void`, { - method: 'POST', - headers: headers, - }) + fetchWithHTTPErr( + `${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}/void`, + { + method: 'POST', + headers: headers, + }, + ) .then(resolve) .catch(reject); }); }; +EWallet.prototype.initializeTokenization = initializeTokenization; +EWallet.prototype.unlinkTokenization = unlinkTokenization; +EWallet.prototype.createPaymentMethod = createPaymentMethod; +EWallet.prototype.getPaymentMethodsByCustomerID = getPaymentMethodsByCustomerID; + module.exports = EWallet; diff --git a/src/ewallet/linked_account.d.ts b/src/ewallet/linked_account.d.ts new file mode 100644 index 0000000..4b4cbd1 --- /dev/null +++ b/src/ewallet/linked_account.d.ts @@ -0,0 +1,18 @@ +interface OnlineBankingAccessProperties { + successRedirectURL: string; + failureRedirectURL: string; + cancelRedirectURL?: string; + callbackURL: string; + metadata?: object; +} + +export function initializeTokenization(data: { + customerID: string; + channelCode: ChannelCode; + properties?: OnlineBankingAccessProperties; + metadata?: object; +}): Promise; + +export function unlinkTokenization(data: { + linkedAccTokenID: string; +}): Promise; diff --git a/src/ewallet/linked_account.js b/src/ewallet/linked_account.js new file mode 100644 index 0000000..55e3ed6 --- /dev/null +++ b/src/ewallet/linked_account.js @@ -0,0 +1,60 @@ +const { Validate, Auth, fetchWithHTTPErr, promWithJsErr } = require('../utils'); + +function initializeTokenization(data) { + return promWithJsErr((resolve, reject) => { + const compulsoryFields = ['customerID', 'channelCode']; + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + fetchWithHTTPErr(`${this.API_ENDPOINT}/linked_account_tokens/auth`, { + method: 'POST', + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + customer_id: data.customerID, + channel_code: data.channelCode, + properties: + data.channelCode === 'PH_PAYMAYA' + ? { + success_redirect_url: data.properties.successRedirectURL, + failure_redirect_url: data.properties.failureRedirectURL, + cancel_redirect_url: data.properties.cancelRedirectURL, + callback_url: data.properties.callbackURL, + } + : { + success_redirect_url: data.properties.successRedirectURL, + failure_redirect_url: data.properties.failureRedirectURL, + callback_url: data.properties.callbackURL, + }, + metadata: data.metadata, + }), + }) + .then(resolve) + .catch(reject); + }); +} + +function unlinkTokenization(data) { + return promWithJsErr((resolve, reject) => { + const compulsoryFields = ['linkedAccTokenID']; + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + fetchWithHTTPErr( + `${this.API_ENDPOINT}/linked_account_tokens/${data.linkedAccTokenID}`, + { + method: 'DELETE', + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + }, + }, + ) + .then(resolve) + .catch(reject); + }); +} + +module.exports = { + initializeTokenization, + unlinkTokenization, +}; diff --git a/src/ewallet/payment_method.d.ts b/src/ewallet/payment_method.d.ts new file mode 100644 index 0000000..f0b7add --- /dev/null +++ b/src/ewallet/payment_method.d.ts @@ -0,0 +1,18 @@ +enum PaymentMethodType { + EWALLET = 'EWALLET', +} + +interface PaymentMethodProperties { + id: string; +} + +export function createPaymentMethod(data: { + customerID: string; + type: PaymentMethodType; + properties: PaymentMethodProperties; + metadata?: object; +}): Promise; + +export function getPaymentMethodsByCustomerID(data: { + customerID: string; +}): Promise; diff --git a/src/ewallet/payment_method.js b/src/ewallet/payment_method.js new file mode 100644 index 0000000..b371c66 --- /dev/null +++ b/src/ewallet/payment_method.js @@ -0,0 +1,50 @@ +const { Validate, Auth, fetchWithHTTPErr, promWithJsErr } = require('../utils'); + +function createPaymentMethod(data) { + return promWithJsErr((resolve, reject) => { + const compulsoryFields = ['customerID', 'type', 'properties']; + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + fetchWithHTTPErr(`${this.API_ENDPOINT}/payment_methods`, { + method: 'POST', + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + customer_id: data.customerID, + type: data.type, + properties: { + id: data.properties.id, + }, + metadata: data.metadata, + }), + }) + .then(resolve) + .catch(reject); + }); +} + +function getPaymentMethodsByCustomerID(data) { + return promWithJsErr((resolve, reject) => { + const compulsoryFields = ['customerID']; + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + fetchWithHTTPErr( + `${this.API_ENDPOINT}/payment_methods?customer_id=${data.customerID}`, + { + method: 'GET', + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + }, + }, + ) + .then(resolve) + .catch(reject); + }); +} + +module.exports = { + createPaymentMethod, + getPaymentMethodsByCustomerID, +}; From b306d75a68cb76c8e1938cc60f1373f8595c8dcc Mon Sep 17 00:00:00 2001 From: MESMUR Date: Thu, 6 Jan 2022 09:42:51 +0530 Subject: [PATCH 3/8] Refactor EWallet Service, add Tokenization flow, update examples --- examples/with_async/ewallet.js | 29 +++- examples/with_promises/ewallet.js | 37 ++++- src/ewallet/ewallet.d.ts | 101 ++------------ src/ewallet/ewallet.js | 221 ++---------------------------- src/ewallet/ewallet_charge.d.ts | 59 ++++++++ src/ewallet/ewallet_charge.js | 119 ++++++++++++++++ src/ewallet/ewallet_payment.d.ts | 34 +++++ src/ewallet/ewallet_payment.js | 105 ++++++++++++++ 8 files changed, 402 insertions(+), 303 deletions(-) create mode 100644 src/ewallet/ewallet_charge.d.ts create mode 100644 src/ewallet/ewallet_charge.js create mode 100644 src/ewallet/ewallet_payment.d.ts create mode 100644 src/ewallet/ewallet_payment.js diff --git a/examples/with_async/ewallet.js b/examples/with_async/ewallet.js index 55ae0fb..d68c56b 100644 --- a/examples/with_async/ewallet.js +++ b/examples/with_async/ewallet.js @@ -1,7 +1,8 @@ const x = require('../xendit'); -const EWallet = x.EWallet; +const { EWallet, Customer } = x; const ew = new EWallet({}); +const c = new Customer({}); (async function() { try { @@ -64,6 +65,32 @@ const ew = new EWallet({}); // eslint-disable-next-line no-console console.log('voided ewallet payment charge:', voidedCharge); + let customer = await c.createCustomer({ + referenceID: new Date().toISOString(), + givenNames: 'customer 1', + email: 'customer@website.com', + mobileNumber: '+6281212345678', + description: 'dummy customer', + middleName: 'middle', + surname: 'surname', + addresses: [], + apiVersion: '2020-05-19', + }); + // eslint-disable-next-line no-console + console.log('created customer', customer); + + let tokenization = await ew.initializeTokenization({ + customerID: customer.id, + channelCode: 'PH_GRABPAY', + properties: { + successRedirectURL: 'https://www.google.com', + failureRedirectURL: 'https://www.google.com', + callbackURL: 'https://www.google.com', + }, + }); + // eslint-disable-next-line no-console + console.log('initialized tokenization', tokenization); + process.exit(0); } catch (e) { console.error(e); // eslint-disable-line no-console diff --git a/examples/with_promises/ewallet.js b/examples/with_promises/ewallet.js index 2719d47..a347bbf 100644 --- a/examples/with_promises/ewallet.js +++ b/examples/with_promises/ewallet.js @@ -1,7 +1,8 @@ const x = require('../xendit'); -const EWallet = x.EWallet; +const { EWallet, Customer } = x; const ew = new EWallet({}); +const c = new Customer({}); ew.createPayment({ externalID: Date.now().toString(), @@ -80,6 +81,40 @@ ew.createPayment({ console.log('voided ewallet payment charge:', r); return r; }) + .then(() => + c.createCustomer({ + referenceID: new Date().toISOString(), + givenNames: 'customer 1', + email: 'customer@website.com', + mobileNumber: '+6281212345678', + description: 'dummy customer', + middleName: 'middle', + surname: 'surname', + addresses: [], + apiVersion: '2020-05-19', + }), + ) + .then(r => { + // eslint-disable-next-line no-console + console.log('created customer:', r); + return r; + }) + .then(r => + ew.initializeTokenization({ + customerID: r.id, + channelCode: 'PH_GRABPAY', + properties: { + successRedirectURL: 'https://www.google.com', + failureRedirectURL: 'https://www.google.com', + callbackURL: 'https://www.google.com', + }, + }), + ) + .then(r => { + // eslint-disable-next-line no-console + console.log('initialized tokenization:', r); + return r; + }) .catch(e => { console.error(e); // eslint-disable-line no-console process.exit(1); diff --git a/src/ewallet/ewallet.d.ts b/src/ewallet/ewallet.d.ts index f9324a4..c390cd3 100644 --- a/src/ewallet/ewallet.d.ts +++ b/src/ewallet/ewallet.d.ts @@ -1,63 +1,16 @@ import { XenditOptions } from '../xendit_opts'; +import { + createEWalletCharge, + getEWalletChargeStatus, + voidEWalletCharge, +} from './ewallet_charge'; +import { createPayment, getPayment } from './ewallet_payment'; import { initializeTokenization, unlinkTokenization } from './linked_account'; import { createPaymentMethod, getPaymentMethodsByCustomerID, } from require('./payment_method'); -enum CreateSupportWalletTypes { - OVO = 'OVO', - Dana = 'DANA', - Linkaja = 'LINKAJA', -} - -enum GetSupportWalletTypes { - OVO = 'OVO', - Dana = 'DANA', -} - -interface PaymentItem { - id: string; - name: string; - price: number; - quantity: number; -} - -enum Currency { - IDR = 'IDR', - PHP = 'PHP', -} - -enum ChannelCode { - ID_OVO = 'ID_OVO', - ID_DANA = 'ID_DANA', - ID_LINKAJA = 'ID_LINKAJA', - ID_SHOPEEPAY = 'ID_SHOPEEPAY', - PH_PAYMAYA = 'PH_PAYMAYA', -} - -interface ChannelProps { - mobileNumber?: string; - successRedirectURL?: string; - failureRedirectURL?: string; - cancelRedirectURL?: string; - redeemPoints?: string; -} - -interface Basket { - referenceID: string; - name: string; - category: string; - currency: string; - price: number; - quantity: number; - type: string; - url?: string; - description?: string; - subCategory?: string; - metadata?: object; -} - export = class EWallet { constructor({}); static _constructorWithInjectedXenditOpts: ( @@ -68,43 +21,11 @@ export = class EWallet { Dana: string; LinkAja: string; }; - createPayment(data: { - externalID: string; - amount: number; - phone?: string; - expirationDate?: Date; - callbackURL?: string; - redirectURL?: string; - items?: PaymentItem[]; - ewalletType: CreateSupportWalletTypes; - xApiVersion?: string; - }): Promise; - getPayment(data: { - externalID: string; - ewalletType: GetSupportWalletTypes; - }): Promise; - createEWalletCharge(data: { - referenceID: string; - currency: Currency; - amount: number; - checkoutMethod: string; - channelCode?: ChannelCode; - channelProperties?: ChannelProps; - paymentMethodId?: string; - customerID?: string; - basket?: Basket[]; - metadata?: object; - forUserID?: string; - withFeeRule?: string; - }): Promise; - getEWalletChargeStatus(data: { - chargeID: string; - forUserID?: string; - }): Promise; - voidEWalletCharge(data: { - chargeID: string; - forUserID?: string; - }): Promise; + createPayment = createPayment; + getPayment = getPayment; + createEWalletCharge = createEWalletCharge; + getEWalletChargeStatus = getEWalletChargeStatus; + voidEWalletCharge = voidEWalletCharge; initializeTokenization = initializeTokenization; unlinkTokenization = unlinkTokenization; createPaymentMethod = createPaymentMethod; diff --git a/src/ewallet/ewallet.js b/src/ewallet/ewallet.js index e0f1774..0835357 100644 --- a/src/ewallet/ewallet.js +++ b/src/ewallet/ewallet.js @@ -1,12 +1,9 @@ const { - promWithJsErr, - Auth, - Validate, - fetchWithHTTPErr, - queryStringWithoutUndefined, -} = require('../utils'); -const errors = require('../errors'); - + createEWalletCharge, + getEWalletChargeStatus, + voidEWalletCharge, +} = require('./ewallet_charge'); +const { createPayment, getPayment } = require('./ewallet_payment'); const { initializeTokenization, unlinkTokenization, @@ -39,209 +36,11 @@ EWallet.Type = { LinkAja: 'LINKAJA', }; -EWallet.prototype.createPayment = function(data) { - return promWithJsErr((resolve, reject) => { - let compulsoryFields = ['ewalletType']; - - if (data.ewalletType) { - switch (data.ewalletType) { - case EWallet.Type.OVO: - compulsoryFields = ['externalID', 'amount', 'phone', 'ewalletType']; - break; - case EWallet.Type.Dana: - compulsoryFields = [ - 'externalID', - 'amount', - 'callbackURL', - 'redirectURL', - 'ewalletType', - ]; - break; - case EWallet.Type.LinkAja: - compulsoryFields = [ - 'externalID', - 'phone', - 'amount', - 'items', - 'callbackURL', - 'redirectURL', - 'ewalletType', - ]; - break; - default: - reject({ - status: 400, - code: errors.API_VALIDATION_ERROR, - message: 'Invalid EWallet Type', - }); - } - } - - Validate.rejectOnMissingFields(compulsoryFields, data, reject); - - const headers = { - 'Content-Type': 'application/json', - Authorization: Auth.basicAuthHeader(this.opts.secretKey), - }; - if (data.xApiVersion) { - headers['X-API-VERSION'] = data.xApiVersion; - } - - fetchWithHTTPErr(this.API_ENDPOINT + '/ewallets', { - method: 'POST', - headers, - body: JSON.stringify({ - external_id: data.externalID, - amount: data.amount, - phone: data.phone, - expiration_date: data.expirationDate - ? data.expirationDate.toISOString() - : undefined, - callback_url: data.callbackURL, - redirect_url: data.redirectURL, - items: data.items, - ewallet_type: data.ewalletType, - }), - }) - .then(resolve) - .catch(reject); - }); -}; - -EWallet.prototype.getPayment = function(data) { - return promWithJsErr((resolve, reject) => { - Validate.rejectOnMissingFields(['externalID', 'ewalletType'], data, reject); - - const queryStr = data - ? queryStringWithoutUndefined({ - external_id: data.externalID, - ewallet_type: data.ewalletType, - }) - : ''; - - fetchWithHTTPErr(this.API_ENDPOINT + `/ewallets?${queryStr}`, { - method: 'GET', - headers: { - Authorization: Auth.basicAuthHeader(this.opts.secretKey), - }, - }) - .then(resolve) - .catch(reject); - }); -}; - -EWallet.prototype.createEWalletCharge = function(data) { - return promWithJsErr((resolve, reject) => { - let compulsoryFields = [ - 'referenceID', - 'currency', - 'amount', - 'checkoutMethod', - ]; - Validate.rejectOnMissingFields(compulsoryFields, data, reject); - - let headers = { - Authorization: Auth.basicAuthHeader(this.opts.secretKey), - 'Content-Type': 'application/json', - }; - - if (data.forUserID) { - headers['for-user-id'] = data.forUserID; - } - - if (data.withFeeRule) { - headers['with-fee-rule'] = data.withFeeRule; - } - - fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges`, { - method: 'POST', - headers: headers, - body: JSON.stringify({ - reference_id: data.referenceID, - currency: data.currency, - amount: data.amount, - checkout_method: data.checkoutMethod, - channel_code: data.channelCode, - channel_properties: data.channelProperties - ? { - mobile_number: data.channelProperties.mobileNumber, - success_redirect_url: data.channelProperties.successRedirectURL, - failure_redirect_url: data.channelProperties.failureRedirectURL, - cancel_redirect_url: data.channelProperties.cancelRedirectURL, - redeem_points: data.channelProperties.redeemPoints, - } - : data.channelProperties, - payment_method_id: data.paymentMethodId, - customer_id: data.customerID, - basket: data.basket - ? data.basket.map(product => ({ - reference_id: product.referenceID, - name: product.name, - category: product.category, - currency: product.currency, - price: product.price, - quantity: product.quantity, - type: product.type, - url: product.url, - description: product.description, - sub_category: product.subCategory, - metadata: product.metadata, - })) - : null, - metadata: data.metadata, - }), - }) - .then(resolve) - .catch(reject); - }); -}; - -EWallet.prototype.getEWalletChargeStatus = function(data) { - return promWithJsErr((resolve, reject) => { - Validate.rejectOnMissingFields(['chargeID'], data, reject); - - let headers = { - Authorization: Auth.basicAuthHeader(this.opts.secretKey), - }; - - if (data.forUserID) { - headers['for-user-id'] = data.forUserID; - } - - fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}`, { - method: 'GET', - headers: headers, - }) - .then(resolve) - .catch(reject); - }); -}; - -EWallet.prototype.voidEWalletCharge = function(data) { - return promWithJsErr((resolve, reject) => { - Validate.rejectOnMissingFields(['chargeID'], data, reject); - - let headers = { - Authorization: Auth.basicAuthHeader(this.opts.secretKey), - 'Content-Type': 'application/json', - }; - - if (data.forUserID) { - headers['for-user-id'] = data.forUserID; - } - - fetchWithHTTPErr( - `${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}/void`, - { - method: 'POST', - headers: headers, - }, - ) - .then(resolve) - .catch(reject); - }); -}; - +EWallet.prototype.createPayment = createPayment; +EWallet.prototype.getPayment = getPayment; +EWallet.prototype.createEWalletCharge = createEWalletCharge; +EWallet.prototype.getEWalletChargeStatus = getEWalletChargeStatus; +EWallet.prototype.voidEWalletCharge = voidEWalletCharge; EWallet.prototype.initializeTokenization = initializeTokenization; EWallet.prototype.unlinkTokenization = unlinkTokenization; EWallet.prototype.createPaymentMethod = createPaymentMethod; diff --git a/src/ewallet/ewallet_charge.d.ts b/src/ewallet/ewallet_charge.d.ts new file mode 100644 index 0000000..052f6ef --- /dev/null +++ b/src/ewallet/ewallet_charge.d.ts @@ -0,0 +1,59 @@ +enum Currency { + IDR = 'IDR', + PHP = 'PHP', +} + +enum ChannelCode { + ID_OVO = 'ID_OVO', + ID_DANA = 'ID_DANA', + ID_LINKAJA = 'ID_LINKAJA', + ID_SHOPEEPAY = 'ID_SHOPEEPAY', + PH_PAYMAYA = 'PH_PAYMAYA', +} + +interface ChannelProps { + mobileNumber?: string; + successRedirectURL?: string; + failureRedirectURL?: string; + cancelRedirectURL?: string; + redeemPoints?: string; +} + +interface Basket { + referenceID: string; + name: string; + category: string; + currency: string; + price: number; + quantity: number; + type: string; + url?: string; + description?: string; + subCategory?: string; + metadata?: object; +} + +export function createEWalletCharge(data: { + referenceID: string; + currency: Currency; + amount: number; + checkoutMethod: string; + channelCode?: ChannelCode; + channelProperties?: ChannelProps; + paymentMethodId?: string; + customerID?: string; + basket?: Basket[]; + metadata?: object; + forUserID?: string; + withFeeRule?: string; +}): Promise; + +export function getEWalletChargeStatus(data: { + chargeID: string; + forUserID?: string; +}): Promise; + +export function voidEWalletCharge(data: { + chargeID: string; + forUserID?: string; +}): Promise; diff --git a/src/ewallet/ewallet_charge.js b/src/ewallet/ewallet_charge.js new file mode 100644 index 0000000..988187b --- /dev/null +++ b/src/ewallet/ewallet_charge.js @@ -0,0 +1,119 @@ +const { Validate, Auth, fetchWithHTTPErr, promWithJsErr } = require('../utils'); + +function createEWalletCharge(data) { + return promWithJsErr((resolve, reject) => { + let compulsoryFields = [ + 'referenceID', + 'currency', + 'amount', + 'checkoutMethod', + ]; + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + let headers = { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'Content-Type': 'application/json', + }; + + if (data.forUserID) { + headers['for-user-id'] = data.forUserID; + } + + if (data.withFeeRule) { + headers['with-fee-rule'] = data.withFeeRule; + } + + fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges`, { + method: 'POST', + headers: headers, + body: JSON.stringify({ + reference_id: data.referenceID, + currency: data.currency, + amount: data.amount, + checkout_method: data.checkoutMethod, + channel_code: data.channelCode, + channel_properties: data.channelProperties + ? { + mobile_number: data.channelProperties.mobileNumber, + success_redirect_url: data.channelProperties.successRedirectURL, + failure_redirect_url: data.channelProperties.failureRedirectURL, + cancel_redirect_url: data.channelProperties.cancelRedirectURL, + redeem_points: data.channelProperties.redeemPoints, + } + : data.channelProperties, + payment_method_id: data.paymentMethodId, + customer_id: data.customerID, + basket: data.basket + ? data.basket.map(product => ({ + reference_id: product.referenceID, + name: product.name, + category: product.category, + currency: product.currency, + price: product.price, + quantity: product.quantity, + type: product.type, + url: product.url, + description: product.description, + sub_category: product.subCategory, + metadata: product.metadata, + })) + : null, + metadata: data.metadata, + }), + }) + .then(resolve) + .catch(reject); + }); +} + +function getEWalletChargeStatus(data) { + return promWithJsErr((resolve, reject) => { + Validate.rejectOnMissingFields(['chargeID'], data, reject); + + let headers = { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + }; + + if (data.forUserID) { + headers['for-user-id'] = data.forUserID; + } + + fetchWithHTTPErr(`${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}`, { + method: 'GET', + headers: headers, + }) + .then(resolve) + .catch(reject); + }); +} + +function voidEWalletCharge(data) { + return promWithJsErr((resolve, reject) => { + Validate.rejectOnMissingFields(['chargeID'], data, reject); + + let headers = { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + 'Content-Type': 'application/json', + }; + + if (data.forUserID) { + headers['for-user-id'] = data.forUserID; + } + + fetchWithHTTPErr( + `${this.API_ENDPOINT}/ewallets/charges/${data.chargeID}/void`, + { + method: 'POST', + headers: headers, + }, + ) + .then(resolve) + .catch(reject); + }); +} + +module.exports = { + createEWalletCharge, + getEWalletChargeStatus, + voidEWalletCharge, +}; diff --git a/src/ewallet/ewallet_payment.d.ts b/src/ewallet/ewallet_payment.d.ts new file mode 100644 index 0000000..39e7d6c --- /dev/null +++ b/src/ewallet/ewallet_payment.d.ts @@ -0,0 +1,34 @@ +enum CreateSupportWalletTypes { + OVO = 'OVO', + Dana = 'DANA', + Linkaja = 'LINKAJA', +} + +enum GetSupportWalletTypes { + OVO = 'OVO', + Dana = 'DANA', +} + +interface PaymentItem { + id: string; + name: string; + price: number; + quantity: number; +} + +export function createPayment(data: { + externalID: string; + amount: number; + phone?: string; + expirationDate?: Date; + callbackURL?: string; + redirectURL?: string; + items?: PaymentItem[]; + ewalletType: CreateSupportWalletTypes; + xApiVersion?: string; +}): Promise; + +export function getPayment(data: { + externalID: string; + ewalletType: GetSupportWalletTypes; +}): Promise; diff --git a/src/ewallet/ewallet_payment.js b/src/ewallet/ewallet_payment.js new file mode 100644 index 0000000..2a90f69 --- /dev/null +++ b/src/ewallet/ewallet_payment.js @@ -0,0 +1,105 @@ +const { + Validate, + Auth, + fetchWithHTTPErr, + promWithJsErr, + queryStringWithoutUndefined, +} = require('../utils'); +const errors = require('../errors'); + +function createPayment(data) { + const Type = Object.freeze({ OVO: 'OVO', Dana: 'DANA', LinkAja: 'LINKAJA' }); + return promWithJsErr((resolve, reject) => { + let compulsoryFields = ['ewalletType']; + + if (data.ewalletType) { + switch (data.ewalletType) { + case Type.OVO: + compulsoryFields = ['externalID', 'amount', 'phone', 'ewalletType']; + break; + case Type.Dana: + compulsoryFields = [ + 'externalID', + 'amount', + 'callbackURL', + 'redirectURL', + 'ewalletType', + ]; + break; + case Type.LinkAja: + compulsoryFields = [ + 'externalID', + 'phone', + 'amount', + 'items', + 'callbackURL', + 'redirectURL', + 'ewalletType', + ]; + break; + default: + reject({ + status: 400, + code: errors.API_VALIDATION_ERROR, + message: 'Invalid EWallet Type', + }); + } + } + + Validate.rejectOnMissingFields(compulsoryFields, data, reject); + + const headers = { + 'Content-Type': 'application/json', + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + }; + if (data.xApiVersion) { + headers['X-API-VERSION'] = data.xApiVersion; + } + + fetchWithHTTPErr(this.API_ENDPOINT + '/ewallets', { + method: 'POST', + headers, + body: JSON.stringify({ + external_id: data.externalID, + amount: data.amount, + phone: data.phone, + expiration_date: data.expirationDate + ? data.expirationDate.toISOString() + : undefined, + callback_url: data.callbackURL, + redirect_url: data.redirectURL, + items: data.items, + ewallet_type: data.ewalletType, + }), + }) + .then(resolve) + .catch(reject); + }); +} + +function getPayment(data) { + return promWithJsErr((resolve, reject) => { + Validate.rejectOnMissingFields(['externalID', 'ewalletType'], data, reject); + + const queryStr = data + ? queryStringWithoutUndefined({ + external_id: data.externalID, + ewallet_type: data.ewalletType, + }) + : ''; + + fetchWithHTTPErr(this.API_ENDPOINT + `/ewallets?${queryStr}`, { + method: 'GET', + headers: { + Authorization: Auth.basicAuthHeader(this.opts.secretKey), + }, + }) + .then(resolve) + .catch(reject); + }); +} + +module.exports = { + createPayment, + getPayment, +}; From 1f17eed429bcb47010e421d932bf0c1136a5c68a Mon Sep 17 00:00:00 2001 From: MESMUR Date: Mon, 10 Jan 2022 11:04:15 +0530 Subject: [PATCH 4/8] ADD and REFACTOR EWallet Unit Test --- test/ewallet/constants.js | 44 +++++ test/ewallet/ewallet.test.js | 249 ++------------------------- test/ewallet/ewallet_charge.test.js | 121 +++++++++++++ test/ewallet/ewallet_payment.test.js | 143 +++++++++++++++ test/ewallet/linked_account.test.js | 91 ++++++++++ test/ewallet/payment_method.test.js | 85 +++++++++ 6 files changed, 495 insertions(+), 238 deletions(-) create mode 100644 test/ewallet/ewallet_charge.test.js create mode 100644 test/ewallet/ewallet_payment.test.js create mode 100644 test/ewallet/linked_account.test.js create mode 100644 test/ewallet/payment_method.test.js diff --git a/test/ewallet/constants.js b/test/ewallet/constants.js index 93c0b56..b89ec2f 100644 --- a/test/ewallet/constants.js +++ b/test/ewallet/constants.js @@ -12,6 +12,12 @@ const CURRENCY = 'IDR'; const CHECKOUT_METHOD = 'ONE_TIME_PAYMENT'; const CHANNEL_CODE = 'ID_OVO'; const CHARGE_ID = 'ewc_f3925450-5c54-4777-98c1-fcf22b0d1e1c'; +const CUSTOMER_ID = '0e0dc5ee-0057-45c4-bd32-e6294348e6cc'; +const LINKED_ACCOUNT_TOKEN_ID = 'lat-531ad3f6-6c03-4b78-b084-c4fe9a14fbe7'; +const LINKED_ACCOUNT_ID = 'la-ddf78482-ca60-473b-91d1-eb87729a1606'; +const PAYMENT_METHOD_ID = 'pm-3d375a3e-7e9d-4727-b5c5-bff92fbb80c9'; +const SUCCESS_REDIRECT_URL = 'https://www.google.com'; +const FAILURE_REDIRECT_URL = 'https://www.google.com'; const ITEMS = [ { id: '123123', @@ -76,6 +82,35 @@ const VALID_EWALLET_PAYMENT_CHARGE = { metadata: null, }; +const VALID_CREATE_PAYMENT_METHOD_RESPONSE = { + id: PAYMENT_METHOD_ID, + customer_id: CUSTOMER_ID, + type: 'EWALLET', + status: 'ACTIVE', + properties: { + id: LINKED_ACCOUNT_ID, + }, + metadata: {}, + created: '2021-02-03T02:56:38.856Z', + updated: '2021-02-03T02:56:38.856Z', +}; + +const VALID_PAYMENT_METHOD_ARRAY = [ + VALID_CREATE_PAYMENT_METHOD_RESPONSE, + VALID_CREATE_PAYMENT_METHOD_RESPONSE, +]; + +const VALID_INITIALIZE_TOKENIZATION_RESPONSE = { + id: LINKED_ACCOUNT_TOKEN_ID, + customer_id: CUSTOMER_ID, + channel_code: 'PH_GRABPAY', + authorization_url: 'https://www.google.com', + status: 'PENDING', + metadata: null, +}; + +const VALID_UNLINK_TOKENIZATION_RESPONSE = {}; + module.exports = { OVO_EWALLET_TYPE, DANA_EWALLET_TYPE, @@ -90,8 +125,17 @@ module.exports = { CHECKOUT_METHOD, CHANNEL_CODE, CHARGE_ID, + CUSTOMER_ID, + LINKED_ACCOUNT_ID, + LINKED_ACCOUNT_TOKEN_ID, + SUCCESS_REDIRECT_URL, + FAILURE_REDIRECT_URL, ITEMS, + VALID_CREATE_PAYMENT_METHOD_RESPONSE, + VALID_PAYMENT_METHOD_ARRAY, VALID_CREATE_OVO_RESPONSE, VALID_GET_OVO_PAYMENT_STATUS_RESPONSE, VALID_EWALLET_PAYMENT_CHARGE, + VALID_INITIALIZE_TOKENIZATION_RESPONSE, + VALID_UNLINK_TOKENIZATION_RESPONSE, }; diff --git a/test/ewallet/ewallet.test.js b/test/ewallet/ewallet.test.js index 456463f..2d6555f 100644 --- a/test/ewallet/ewallet.test.js +++ b/test/ewallet/ewallet.test.js @@ -1,245 +1,18 @@ -const chai = require('chai'); -const chaiAsProm = require('chai-as-promised'); -const TestConstants = require('./constants'); -const { expect } = chai; -const nock = require('nock'); -const { Errors } = require('../../src/xendit'); +process.env.NODE_ENV = 'test'; + const Xendit = require('../../src/xendit'); +const eWalletPaymentTest = require('./ewallet_payment.test'); +const eWalletChargeTest = require('./ewallet_charge.test'); +const paymentMethodTest = require('./payment_method.test'); +const linkedAccountTest = require('./linked_account.test'); const x = new Xendit({ secretKey: 'fake_secret_key', }); -chai.use(chaiAsProm); - -const { EWallet } = x; -let ewallet; -beforeEach(function() { - ewallet = new EWallet({}); -}); -before(function() { - nock(x.opts.xenditURL) - .post('/ewallets', { - external_id: TestConstants.EXT_ID, - phone: TestConstants.PHONE, - amount: TestConstants.AMOUNT, - ewallet_type: TestConstants.OVO_EWALLET_TYPE, - }) - .reply(200, TestConstants.VALID_CREATE_OVO_RESPONSE); - nock(x.opts.xenditURL) - .get( - // eslint-disable-next-line max-len - `/ewallets?external_id=${TestConstants.EXT_ID}&ewallet_type=${TestConstants.OVO_EWALLET_TYPE}`, - ) - .reply(200, TestConstants.VALID_GET_OVO_PAYMENT_STATUS_RESPONSE); - nock(x.opts.xenditURL) - .post('/ewallets/charges', { - reference_id: TestConstants.REFERENCE_ID, - currency: TestConstants.CURRENCY, - amount: TestConstants.AMOUNT, - checkout_method: TestConstants.CHECKOUT_METHOD, - channel_code: TestConstants.CHANNEL_CODE, - channel_properties: { - mobile_number: TestConstants.PHONE, - }, - basket: null, - }) - .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); - nock(x.opts.xenditURL) - .get(`/ewallets/charges/${TestConstants.CHARGE_ID}`) - .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); - nock(x.opts.xenditURL) - .post(`/ewallets/charges/${TestConstants.CHARGE_ID}/void`) - .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); -}); - -describe('EWallet Service', function() { - describe('createPayment', () => { - it('should create an OVO Payment', done => { - expect( - ewallet.createPayment({ - externalID: TestConstants.EXT_ID, - phone: TestConstants.PHONE, - amount: TestConstants.AMOUNT, - ewalletType: TestConstants.OVO_EWALLET_TYPE, - }), - ) - .to.eventually.deep.equal(TestConstants.VALID_CREATE_OVO_RESPONSE) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing required fields', done => { - expect(ewallet.createPayment({})) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing OVO required fields', done => { - expect( - ewallet.createPayment({ - external_id: TestConstants.EXT_ID, - amount: TestConstants.AMOUNT, - ewallet_type: TestConstants.OVO_EWALLET_TYPE, - }), - ) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing Dana required fields', done => { - expect( - ewallet.createPayment({ - externalID: TestConstants.EXT_ID, - amount: TestConstants.AMOUNT, - redirectURL: TestConstants.REDIRECT_URL, - ewallet_type: TestConstants.DANA_EWALLET_TYPE, - }), - ) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing LinkAja required fields', done => { - expect( - ewallet.createPayment({ - externalID: TestConstants.EXT_ID, - phone: TestConstants.PHONE, - amount: TestConstants.AMOUNT, - callbackURL: TestConstants.CALLBACK_URL, - redirectURL: TestConstants.REDIRECT_URL, - }), - ) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - }); - - describe('getPayment', () => { - it('should get OVO Payment Status', done => { - expect( - ewallet.getPayment({ - externalID: TestConstants.EXT_ID, - ewalletType: TestConstants.OVO_EWALLET_TYPE, - }), - ) - .to.eventually.deep.equal( - TestConstants.VALID_GET_OVO_PAYMENT_STATUS_RESPONSE, - ) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing required fields', done => { - expect(ewallet.getPayment({})) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - }); - - describe('createEWalletCharge', () => { - it('should create a ewallet payment charge', done => { - expect( - ewallet.createEWalletCharge({ - referenceID: TestConstants.REFERENCE_ID, - currency: TestConstants.CURRENCY, - amount: TestConstants.AMOUNT, - checkoutMethod: TestConstants.CHECKOUT_METHOD, - channelCode: TestConstants.CHANNEL_CODE, - channelProperties: { - mobileNumber: TestConstants.PHONE, - }, - }), - ) - .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) - .then(() => done()) - .catch(e => done(e)); - }); - - it('should report missing required fields', done => { - expect(ewallet.createEWalletCharge({})) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - }); - - describe('getEWalletChargeStatus', () => { - it('should get ewallet payment charge', done => { - expect( - ewallet.getEWalletChargeStatus({ - chargeID: TestConstants.CHARGE_ID, - }), - ) - .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) - .then(() => done()) - .catch(e => done(e)); - }); - it('should report missing required fields', done => { - expect(ewallet.getEWalletChargeStatus({})) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - }); - - describe('voidEWalletCharge', () => { - it('should void an ewallet payment charge', done => { - expect( - ewallet.voidEWalletCharge({ - chargeID: TestConstants.CHARGE_ID, - }), - ) - .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) - .then(() => done()) - .catch(e => done(e)); - }); - - it('should report missing required fields', done => { - expect(ewallet.voidEWalletCharge({})) - .to.eventually.to.be.rejected.then(e => - Promise.all([ - expect(e).to.have.property('status', 400), - expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), - ]), - ) - .then(() => done()) - .catch(e => done(e)); - }); - }); +describe('EWallet Service Test', function() { + eWalletPaymentTest(x); + eWalletChargeTest(x); + paymentMethodTest(x); + linkedAccountTest(x); }); diff --git a/test/ewallet/ewallet_charge.test.js b/test/ewallet/ewallet_charge.test.js new file mode 100644 index 0000000..6482473 --- /dev/null +++ b/test/ewallet/ewallet_charge.test.js @@ -0,0 +1,121 @@ +const chai = require('chai'); +const chaiAsProm = require('chai-as-promised'); +const TestConstants = require('./constants'); +const { expect } = chai; +const nock = require('nock'); +const { Errors } = require('../../src/xendit'); + +chai.use(chaiAsProm); + +module.exports = function(x) { + const { EWallet } = x; + + let ew; + + beforeEach(function() { + ew = new EWallet({}); + }); + + before(function() { + nock(x.opts.xenditURL) + .post('/ewallets/charges', { + reference_id: TestConstants.REFERENCE_ID, + currency: TestConstants.CURRENCY, + amount: TestConstants.AMOUNT, + checkout_method: TestConstants.CHECKOUT_METHOD, + channel_code: TestConstants.CHANNEL_CODE, + channel_properties: { + mobile_number: TestConstants.PHONE, + }, + basket: null, + }) + .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); + nock(x.opts.xenditURL) + .get(`/ewallets/charges/${TestConstants.CHARGE_ID}`) + .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); + nock(x.opts.xenditURL) + .post(`/ewallets/charges/${TestConstants.CHARGE_ID}/void`) + .reply(200, TestConstants.VALID_EWALLET_PAYMENT_CHARGE); + }); + + describe('createEWalletCharge', () => { + it('should create a ewallet payment charge', done => { + expect( + ew.createEWalletCharge({ + referenceID: TestConstants.REFERENCE_ID, + currency: TestConstants.CURRENCY, + amount: TestConstants.AMOUNT, + checkoutMethod: TestConstants.CHECKOUT_METHOD, + channelCode: TestConstants.CHANNEL_CODE, + channelProperties: { + mobileNumber: TestConstants.PHONE, + }, + }), + ) + .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) + .then(() => done()) + .catch(e => done(e)); + }); + + it('should report missing required fields', done => { + expect(ew.createEWalletCharge({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); + + describe('getEWalletChargeStatus', () => { + it('should get ewallet payment charge', done => { + expect( + ew.getEWalletChargeStatus({ + chargeID: TestConstants.CHARGE_ID, + }), + ) + .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing required fields', done => { + expect(ew.getEWalletChargeStatus({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); + + describe('voidEWalletCharge', () => { + it('should void an ewallet payment charge', done => { + expect( + ew.voidEWalletCharge({ + chargeID: TestConstants.CHARGE_ID, + }), + ) + .to.eventually.deep.equal(TestConstants.VALID_EWALLET_PAYMENT_CHARGE) + .then(() => done()) + .catch(e => done(e)); + }); + + it('should report missing required fields', done => { + expect(ew.voidEWalletCharge({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); +}; diff --git a/test/ewallet/ewallet_payment.test.js b/test/ewallet/ewallet_payment.test.js new file mode 100644 index 0000000..2277580 --- /dev/null +++ b/test/ewallet/ewallet_payment.test.js @@ -0,0 +1,143 @@ +const chai = require('chai'); +const chaiAsProm = require('chai-as-promised'); +const TestConstants = require('./constants'); +const { expect } = chai; +const nock = require('nock'); +const { Errors } = require('../../src/xendit'); + +chai.use(chaiAsProm); + +module.exports = function(x) { + const { EWallet } = x; + + let ew; + + beforeEach(function() { + ew = new EWallet({}); + }); + + before(function() { + nock(x.opts.xenditURL) + .post('/ewallets', { + external_id: TestConstants.EXT_ID, + phone: TestConstants.PHONE, + amount: TestConstants.AMOUNT, + ewallet_type: TestConstants.OVO_EWALLET_TYPE, + }) + .reply(200, TestConstants.VALID_CREATE_OVO_RESPONSE); + nock(x.opts.xenditURL) + .get( + // eslint-disable-next-line max-len + `/ewallets?external_id=${TestConstants.EXT_ID}&ewallet_type=${TestConstants.OVO_EWALLET_TYPE}`, + ) + .reply(200, TestConstants.VALID_GET_OVO_PAYMENT_STATUS_RESPONSE); + }); + + describe('createPayment', () => { + it('should create an OVO Payment', done => { + expect( + ew.createPayment({ + externalID: TestConstants.EXT_ID, + phone: TestConstants.PHONE, + amount: TestConstants.AMOUNT, + ewalletType: TestConstants.OVO_EWALLET_TYPE, + }), + ) + .to.eventually.deep.equal(TestConstants.VALID_CREATE_OVO_RESPONSE) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing required fields', done => { + expect(ew.createPayment({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing OVO required fields', done => { + expect( + ew.createPayment({ + external_id: TestConstants.EXT_ID, + amount: TestConstants.AMOUNT, + ewallet_type: TestConstants.OVO_EWALLET_TYPE, + }), + ) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing Dana required fields', done => { + expect( + ew.createPayment({ + externalID: TestConstants.EXT_ID, + amount: TestConstants.AMOUNT, + redirectURL: TestConstants.REDIRECT_URL, + ewallet_type: TestConstants.DANA_EWALLET_TYPE, + }), + ) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing LinkAja required fields', done => { + expect( + ew.createPayment({ + externalID: TestConstants.EXT_ID, + phone: TestConstants.PHONE, + amount: TestConstants.AMOUNT, + callbackURL: TestConstants.CALLBACK_URL, + redirectURL: TestConstants.REDIRECT_URL, + }), + ) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); + + describe('getPayment', () => { + it('should get OVO Payment Status', done => { + expect( + ew.getPayment({ + externalID: TestConstants.EXT_ID, + ewalletType: TestConstants.OVO_EWALLET_TYPE, + }), + ) + .to.eventually.deep.equal( + TestConstants.VALID_GET_OVO_PAYMENT_STATUS_RESPONSE, + ) + .then(() => done()) + .catch(e => done(e)); + }); + it('should report missing required fields', done => { + expect(ew.getPayment({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); +}; diff --git a/test/ewallet/linked_account.test.js b/test/ewallet/linked_account.test.js new file mode 100644 index 0000000..252c281 --- /dev/null +++ b/test/ewallet/linked_account.test.js @@ -0,0 +1,91 @@ +const chai = require('chai'); +const chaiAsProm = require('chai-as-promised'); +const TestConstants = require('./constants'); +const { expect } = chai; +const nock = require('nock'); +const { Errors } = require('../../src/xendit'); + +chai.use(chaiAsProm); + +module.exports = function(x) { + const { EWallet } = x; + + let ew; + + beforeEach(function() { + ew = new EWallet({}); + }); + + before(function() { + nock(x.opts.xenditURL) + .post('/linked_account_tokens/auth', { + customer_id: TestConstants.CUSTOMER_ID, + channel_code: 'PH_GRABPAY', + properties: { + success_redirect_url: TestConstants.SUCCESS_REDIRECT_URL, + failure_redirect_url: TestConstants.FAILURE_REDIRECT_URL, + callback_url: TestConstants.CALLBACK_URL, + }, + }) + .reply(200, TestConstants.VALID_INITIALIZE_TOKENIZATION_RESPONSE); + nock(x.opts.xenditURL) + .delete(`/linked_account_tokens/${TestConstants.LINKED_ACCOUNT_TOKEN_ID}`) + .reply(200, TestConstants.VALID_UNLINK_TOKENIZATION_RESPONSE); + }); + + describe('initializeTokenization', () => { + it('should initialize the tokenization flow', done => { + expect( + ew.initializeTokenization({ + customerID: TestConstants.CUSTOMER_ID, + channelCode: 'PH_GRABPAY', + properties: { + successRedirectURL: TestConstants.SUCCESS_REDIRECT_URL, + failureRedirectURL: TestConstants.FAILURE_REDIRECT_URL, + callbackURL: TestConstants.CALLBACK_URL, + }, + }), + ) + .to.eventually.deep.equal( + TestConstants.VALID_INITIALIZE_TOKENIZATION_RESPONSE, + ) + .and.notify(done); + }); + it('should report missing required fields', done => { + expect(ew.initializeTokenization({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); + + describe('unlinkTokenization', () => { + it('should unlink the token', done => { + expect( + ew.unlinkTokenization({ + linkedAccTokenID: TestConstants.LINKED_ACCOUNT_TOKEN_ID, + }), + ) + .to.eventually.deep.equal( + TestConstants.VALID_UNLINK_TOKENIZATION_RESPONSE, + ) + .and.notify(done); + }); + it('should report missing required fields', done => { + expect(ew.unlinkTokenization({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); +}; diff --git a/test/ewallet/payment_method.test.js b/test/ewallet/payment_method.test.js new file mode 100644 index 0000000..52301a4 --- /dev/null +++ b/test/ewallet/payment_method.test.js @@ -0,0 +1,85 @@ +const chai = require('chai'); +const chaiAsProm = require('chai-as-promised'); +const TestConstants = require('./constants'); +const { expect } = chai; +const nock = require('nock'); +const { Errors } = require('../../src/xendit'); + +chai.use(chaiAsProm); + +module.exports = function(x) { + const { EWallet } = x; + + let ew; + + beforeEach(function() { + ew = new EWallet({}); + }); + + before(function() { + nock(x.opts.xenditURL) + .post('/payment_methods', { + customer_id: TestConstants.CUSTOMER_ID, + type: 'EWALLET', + properties: { + id: TestConstants.LINKED_ACCOUNT_ID, + }, + }) + .reply(200, TestConstants.VALID_CREATE_PAYMENT_METHOD_RESPONSE); + nock(x.opts.xenditURL) + .get(`/payment_methods?customer_id=${TestConstants.CUSTOMER_ID}`) + .reply(200, TestConstants.VALID_PAYMENT_METHOD_ARRAY); + }); + + describe('createPaymentMethod', () => { + it('should create payment method', done => { + expect( + ew.createPaymentMethod({ + customerID: TestConstants.CUSTOMER_ID, + type: 'EWALLET', + properties: { + id: TestConstants.LINKED_ACCOUNT_ID, + }, + }), + ) + .to.eventually.deep.equal( + TestConstants.VALID_CREATE_PAYMENT_METHOD_RESPONSE, + ) + .and.notify(done); + }); + it('should report missing required fields', done => { + expect(ew.createPaymentMethod({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); + + describe('getPaymentMethodsByCustomerID', () => { + it('should get payment methods', done => { + expect( + ew.getPaymentMethodsByCustomerID({ + customerID: TestConstants.CUSTOMER_ID, + }), + ) + .to.eventually.deep.equal(TestConstants.VALID_PAYMENT_METHOD_ARRAY) + .and.notify(done); + }); + it('should report missing required fields', done => { + expect(ew.getPaymentMethodsByCustomerID({})) + .to.eventually.to.be.rejected.then(e => + Promise.all([ + expect(e).to.have.property('status', 400), + expect(e).to.have.property('code', Errors.API_VALIDATION_ERROR), + ]), + ) + .then(() => done()) + .catch(e => done(e)); + }); + }); +}; From 74ba0262560a833dcd1f7d1407a6bdfe0f090f7b Mon Sep 17 00:00:00 2001 From: MESMUR Date: Mon, 10 Jan 2022 11:23:38 +0530 Subject: [PATCH 5/8] ADD integration test and comments --- examples/with_async/ewallet.js | 11 ++++++++++ integration_test/ewallet.test.js | 37 +++++++++++++++++++++++++++++++- integration_test/va.test.js | 10 +++++---- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/examples/with_async/ewallet.js b/examples/with_async/ewallet.js index d68c56b..659bfca 100644 --- a/examples/with_async/ewallet.js +++ b/examples/with_async/ewallet.js @@ -91,6 +91,17 @@ const c = new Customer({}); // eslint-disable-next-line no-console console.log('initialized tokenization', tokenization); + /* + * The entire EWallet tokenization flow, at this time, + * cannot be replicated through an example + * This is because of a limitation with the system, + * once a token is created it has + * to be verified manually by using the authorizer url. + * Subsequent methods `create payment method`, + * `get payment by ID`, and `unlink tokenization` + * can only be carried out after the manual authorization + */ + process.exit(0); } catch (e) { console.error(e); // eslint-disable-line no-console diff --git a/integration_test/ewallet.test.js b/integration_test/ewallet.test.js index fbebe63..807bc55 100644 --- a/integration_test/ewallet.test.js +++ b/integration_test/ewallet.test.js @@ -1,8 +1,19 @@ const x = require('./xendit.test'); -const { EWallet } = x; +const { EWallet, Customer } = x; const ew = new EWallet({}); +const c = new Customer({}); +/* + * The entire EWallet tokenization flow, at this time, + * cannot be replicated through an integration test + * This is because of a limitation with the system, + * once a token is created it has + * to be verified manually by using the authorizer url. + * Subsequent methods `create payment method`, + * `get payment by ID`, and `unlink tokenization` + * can only be carried out after the manual authorization + */ module.exports = function() { return ew .createPayment({ @@ -57,6 +68,30 @@ module.exports = function() { chargeID: r.id, }), ) + .then(() => + c.createCustomer({ + referenceID: new Date().toISOString(), + givenNames: 'Test Customer', + email: 'customer_test@website.com', + mobileNumber: '+6281212345678', + description: 'dummy customer', + middleName: 'middle', + surname: 'surname', + addresses: [], + apiVersion: '2020-05-19', + }), + ) + .then(r => + ew.initializeTokenization({ + customerID: r.id, + channelCode: 'PH_GRABPAY', + properties: { + successRedirectURL: 'https://www.google.com', + failureRedirectURL: 'https://www.google.com', + callbackURL: 'https://www.google.com', + }, + }), + ) .then(() => { // eslint-disable-next-line no-console console.log('EWallet integration test done...'); diff --git a/integration_test/va.test.js b/integration_test/va.test.js index c62cc13..580adf1 100644 --- a/integration_test/va.test.js +++ b/integration_test/va.test.js @@ -2,11 +2,13 @@ const x = require('./xendit.test'); const VirtualAcc = x.VirtualAcc; const va = new VirtualAcc({}); -function sleepFor(sleepDuration){ +function sleepFor(sleepDuration) { var now = new Date().getTime(); - while(new Date().getTime() < now + sleepDuration){ /* Do nothing */ } + while (new Date().getTime() < now + sleepDuration) { + /* Do nothing */ + } } -module.exports = function () { +module.exports = function() { return va .getVABanks() .then(banks => { @@ -20,7 +22,7 @@ module.exports = function () { }) .then(({ id }) => { sleepFor(3000); - return va.getFixedVA({ id }) + return va.getFixedVA({ id }); }) .then(({ id }) => { return va.updateFixedVA({ From 2d3198a614cafed6c1568dc49b4b92c2be091bcc Mon Sep 17 00:00:00 2001 From: MESMUR Date: Mon, 10 Jan 2022 11:37:16 +0530 Subject: [PATCH 6/8] UPDATE Readme with new EWallet Information: --- README.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a48bc1e..17451fa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Xendit API Node.js Client -![](https://github.com/xendit/xendit-node/workflows/Code%20Linting/badge.svg) -![](https://github.com/xendit/xendit-node/workflows/Integration%20Tests/badge.svg) +![Code Linting Badge](https://github.com/xendit/xendit-node/workflows/Code%20Linting/badge.svg) +![Integration Tests Badge](https://github.com/xendit/xendit-node/workflows/Integration%20Tests/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/xendit/xendit-node/badge.svg)](https://coveralls.io/github/xendit/xendit-node) This library is the abstraction of Xendit API for access from applications written with server-side Javascript. @@ -51,9 +51,15 @@ For PCI compliance to be maintained, tokenization of credit cards info should be + [Get a payout](#get-a-payout) + [Void a payout](#void-a-payout) * [EWallet Services](#ewallet-services) + + [Create payment](#create-payment) + + [Get payment](#get-payment) + [Create an ewallet charge](#create-an-ewallet-charge) + [Get an ewallet charge status](#get-an-ewallet-charge-status) + [Void an ewallet charge](#void-an-ewallet-charge) + + [Initialize tokenization](#initialize-tokenization) + + [Unlink tokenization](#unlink-tokenization) + + [Create payment method](#create-payment-method) + + [Get payment methods by customer ID](#get-payment-methods-by-customer-id) * [Balance Services](#balance-services) + [Get balance](#get-balance) * [Retail Outlet Services](#retail-outlet-services) @@ -74,8 +80,8 @@ For PCI compliance to be maintained, tokenization of credit cards info should be + [Initialize linked account tokenization](#initialize-linked-account-tokenization) + [Validate OTP for Linked Account Token](#validate-otp-for-linked-account-token) + [Retrieve accessible accounts by linked account token](#retrieve-accessible-accounts-by-linked-account-token) - + [Create payment method](#create-payment-method) - + [Get payment methods by customer ID](#get-payment-methods-by-customer-id) + + [Create payment method](#create-payment-method-1) + + [Get payment methods by customer ID](#get-payment-methods-by-customer-id-1) + [Create direct debit payment](#create-direct-debit-payment) + [Validate OTP for direct debit payment](#validate-otp-for-direct-debit-payment) + [Get direct debit payment status by ID](#get-direct-debit-payment-status-by-id) @@ -659,6 +665,31 @@ ew.createEWalletCharge({ Refer to [Xendit API Reference](https://developers.xendit.co/api-reference/#ewallets) for more info about methods' parameters +#### Create payment + +```ts +ew.createPayment(data: { + externalID: string; + amount: number; + phone?: string; + expirationDate?: Date; + callbackURL?: string; + redirectURL?: string; + items?: PaymentItem[]; + ewalletType: CreateSupportWalletTypes; + xApiVersion?: string; +}) +``` + +#### Get payment + +```ts +ew.getPayment(data: { + externalID: string; + ewalletType: GetSupportWalletTypes; +}) +``` + #### Create an ewallet charge ```ts @@ -696,6 +727,44 @@ ew.voidEWalletCharge(data: { }) ``` +#### Initialize tokenization + +```ts +ew.initializeTokenization(data: { + customerID: string; + channelCode: ChannelCode; + properties?: OnlineBankingAccessProperties; + metadata?: object; +}) +``` + +#### Unlink tokenization + +```ts +ew.unlinkTokenization(data: { + linkedAccTokenID: string; +}) +``` + +#### Create payment method + +```ts +ew.createPaymentMethod(data: { + customerID: string; + type: PaymentMethodType; + properties: PaymentMethodProperties; + metadata?: object; +}) +``` + +#### Get payment methods by customer ID + +```ts +ew.getPaymentMethodsByCustomerID(data: { + customerID: string; +}) +``` + ### Balance Services Instanitiate Balance service using constructor that has been injected with Xendit keys From eec976ddc76dcaaeb75e909db12ee24e5b000054 Mon Sep 17 00:00:00 2001 From: MESMUR Date: Mon, 10 Jan 2022 13:50:31 +0530 Subject: [PATCH 7/8] UPDATE EWallet Unit Test and Disclaimer on Tokenization Flow --- examples/with_async/ewallet.js | 23 +++++++++++------------ examples/with_promises/ewallet.js | 11 +++++++++++ integration_test/ewallet.test.js | 3 ++- test/ewallet/constants.js | 5 ++++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/examples/with_async/ewallet.js b/examples/with_async/ewallet.js index 659bfca..8acdf23 100644 --- a/examples/with_async/ewallet.js +++ b/examples/with_async/ewallet.js @@ -4,6 +4,17 @@ const { EWallet, Customer } = x; const ew = new EWallet({}); const c = new Customer({}); +/* + * The entire EWallet tokenization flow, at this time, + * cannot be replicated through an example + * This is because of the system design, + * once a token is created it has + * to be verified manually by using the authorizer url. + * Subsequent methods `create payment method`, + * `get payment by ID`, and `unlink tokenization` + * can only be carried out after the manual authorization + */ + (async function() { try { const payment = await ew.createPayment({ @@ -90,18 +101,6 @@ const c = new Customer({}); }); // eslint-disable-next-line no-console console.log('initialized tokenization', tokenization); - - /* - * The entire EWallet tokenization flow, at this time, - * cannot be replicated through an example - * This is because of a limitation with the system, - * once a token is created it has - * to be verified manually by using the authorizer url. - * Subsequent methods `create payment method`, - * `get payment by ID`, and `unlink tokenization` - * can only be carried out after the manual authorization - */ - process.exit(0); } catch (e) { console.error(e); // eslint-disable-line no-console diff --git a/examples/with_promises/ewallet.js b/examples/with_promises/ewallet.js index a347bbf..53e2184 100644 --- a/examples/with_promises/ewallet.js +++ b/examples/with_promises/ewallet.js @@ -4,6 +4,17 @@ const { EWallet, Customer } = x; const ew = new EWallet({}); const c = new Customer({}); +/* + * The entire EWallet tokenization flow, at this time, + * cannot be replicated through an example + * This is because of the system design, + * once a token is created it has + * to be verified manually by using the authorizer url. + * Subsequent methods `create payment method`, + * `get payment by ID`, and `unlink tokenization` + * can only be carried out after the manual authorization + */ + ew.createPayment({ externalID: Date.now().toString(), amount: 1, diff --git a/integration_test/ewallet.test.js b/integration_test/ewallet.test.js index 807bc55..fd6b8f0 100644 --- a/integration_test/ewallet.test.js +++ b/integration_test/ewallet.test.js @@ -7,13 +7,14 @@ const c = new Customer({}); /* * The entire EWallet tokenization flow, at this time, * cannot be replicated through an integration test - * This is because of a limitation with the system, + * This is because of the system design, * once a token is created it has * to be verified manually by using the authorizer url. * Subsequent methods `create payment method`, * `get payment by ID`, and `unlink tokenization` * can only be carried out after the manual authorization */ + module.exports = function() { return ew .createPayment({ diff --git a/test/ewallet/constants.js b/test/ewallet/constants.js index b89ec2f..f472345 100644 --- a/test/ewallet/constants.js +++ b/test/ewallet/constants.js @@ -109,7 +109,10 @@ const VALID_INITIALIZE_TOKENIZATION_RESPONSE = { metadata: null, }; -const VALID_UNLINK_TOKENIZATION_RESPONSE = {}; +const VALID_UNLINK_TOKENIZATION_RESPONSE = { + id: LINKED_ACCOUNT_TOKEN_ID, + is_deleted: true, +}; module.exports = { OVO_EWALLET_TYPE, From cfd880d7b0afefdc5080411080c44909390aac38 Mon Sep 17 00:00:00 2001 From: MESMUR Date: Wed, 12 Jan 2022 10:48:32 +0530 Subject: [PATCH 8/8] Updated Package JSON version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d03b6de..6923415 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xendit-node", - "version": "1.19.2", + "version": "1.19.4", "description": "NodeJS client for Xendit API", "main": "index.js", "types": "index.d.ts",