node-ecpay-aio
Version:
A production-ready ECPay AIO SDK for Node.js with TypeScript support.
193 lines (192 loc) • 8.86 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FundingReconDetailQuery = exports.TradeNoAioQuery = exports.TradeV2Query = exports.CreditCardPeriodInfoQuery = exports.PaymentInfoQuery = exports.TradeInfoQuery = exports.Query = void 0;
const Error_1 = require("./Error");
const utils_1 = require("../utils");
const schema_1 = require("../schema");
const QUERY_RESULT_BASE_INT_FIELDS = [
'TradeAmt',
'HandlingCharge',
'PaymentTypeChargeFee',
'PeriodAmount',
'TotalAmount',
'Frequency',
'ExecTimes',
'TotalSuccessTimes',
'TotalSuccessAmount',
'RtnCode',
];
const QUERY_ADDITIONAL_INT_FIELDS = ['RtnCode', 'gwsr', 'amount', 'clsamt'];
const QUERY_EXTRAINFO_INT_FIELDS = [
'stage',
'stast',
'staed',
'eci',
'red_dan',
'red_de_amt',
'red_ok_amt',
'red_yet',
];
class Query {
constructor(merchant, params) {
this.responseDataEncoding = 'utf8';
this.merchant = merchant;
this.params = Object.assign({}, params);
}
_read() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.apiUrl || !this.apiUrl.startsWith('https://'))
throw new Error(`API url is not provided or infeasible for ${this.merchant.mode} mode.`);
const { MerchantID, HashKey, HashIV } = this.merchant.config;
// every query requires MerchantID and CheckMacValue
const postParams = Object.assign({ MerchantID }, this._params);
const CheckMacValue = (0, utils_1.generateCheckMacValue)(postParams, HashKey, HashIV);
const _result = yield (0, utils_1.postRequest)({
apiUrl: this.apiUrl,
params: Object.assign(Object.assign({}, postParams), { CheckMacValue }),
responseEncoding: this.responseDataEncoding,
});
const result = (0, utils_1.parseIntegerFileds)(_result, QUERY_RESULT_BASE_INT_FIELDS);
return result;
});
}
}
exports.Query = Query;
class TradeInfoQuery extends Query {
constructor(merchant, params) {
super(merchant, params);
schema_1.BaseQueryParamsSchema.validateSync(this.params);
this.apiUrl = merchant.ecpayServiceUrls.TradeInfo[merchant.mode];
this._params = Object.assign(Object.assign({}, this.params), { TimeStamp: (0, utils_1.getCurrentUnixTimestampOffset)(120), PlatformID: this.merchant.config.PlatformID });
}
read() {
return __awaiter(this, void 0, void 0, function* () {
const { HashKey, HashIV } = this.merchant.config;
const _data = yield this._read();
const result = (0, utils_1.parseIntegerFileds)(_data, [
...QUERY_ADDITIONAL_INT_FIELDS,
...QUERY_EXTRAINFO_INT_FIELDS,
]);
if (!(0, utils_1.isValidReceivedCheckMacValue)(_data, HashKey, HashIV))
throw new Error_1.CheckMacValueError(`Invalid CheckMacValue in TradeInfoQuery response. MerchantTradeNo: ${this.params.MerchantTradeNo}.`, result);
if (result.TradeStatus !== '0' &&
result.TradeStatus !== '1' &&
result.TradeStatus !== '10200095') {
throw new Error_1.QueryError('Trade info query failed.', parseInt(result.TradeStatus), result);
}
return result;
});
}
}
exports.TradeInfoQuery = TradeInfoQuery;
class PaymentInfoQuery extends Query {
constructor(merchant, params) {
super(merchant, params);
schema_1.BaseQueryParamsSchema.validateSync(this.params);
this.apiUrl = merchant.ecpayServiceUrls.PaymentInfo[merchant.mode];
this._params = Object.assign(Object.assign({}, this.params), { TimeStamp: (0, utils_1.getCurrentUnixTimestampOffset)(120), PlatformID: this.merchant.config.PlatformID });
}
read() {
return __awaiter(this, void 0, void 0, function* () {
const { HashKey, HashIV } = this.merchant.config;
const data = yield this._read();
if (!(0, utils_1.isValidReceivedCheckMacValue)(data, HashKey, HashIV))
throw new Error_1.CheckMacValueError(`Invalid CheckMacValue in PaymentInfoQuery response. MerchantTradeNo: ${this.params.MerchantTradeNo}.`, data);
// Check if RtnCode is successful
if (data.PaymentType.startsWith('ATM') && data.RtnCode !== 2)
throw new Error_1.QueryError(data.RtnMsg, data.RtnCode, data);
else if ((data.PaymentType.startsWith('CVS') ||
data.PaymentType.startsWith('BARCODE')) &&
data.RtnCode !== 10100073)
throw new Error_1.QueryError(data.RtnMsg, data.RtnCode, data);
return data;
});
}
}
exports.PaymentInfoQuery = PaymentInfoQuery;
class CreditCardPeriodInfoQuery extends Query {
constructor(merchant, params) {
super(merchant, params);
schema_1.BaseQueryParamsSchema.validateSync(this.params);
this.apiUrl =
merchant.ecpayServiceUrls.CreditCardPeriodInfo[merchant.mode];
this._params = Object.assign(Object.assign({}, this.params), { TimeStamp: (0, utils_1.getCurrentUnixTimestampOffset)(120), PlatformID: this.merchant.config.PlatformID });
}
read() {
return __awaiter(this, void 0, void 0, function* () {
const _result = yield this._read();
const result = (0, utils_1.parseIntegerFileds)(_result, QUERY_ADDITIONAL_INT_FIELDS);
if (result.RtnCode !== 1)
throw new Error_1.QueryError('Credit card period info query failed or first authorization for this order was rejected.', result.RtnCode, result);
if (Array.isArray(result.ExecLog)) {
result.ExecLog.forEach((log, index) => {
result.ExecLog[index] = (0, utils_1.parseIntegerFileds)(log, QUERY_ADDITIONAL_INT_FIELDS);
});
}
return result;
});
}
}
exports.CreditCardPeriodInfoQuery = CreditCardPeriodInfoQuery;
// note: 無測試環境可用, TBD: testing@production
class TradeV2Query extends Query {
// amount, clsamt
// amount
constructor(merchant, params) {
super(merchant, params);
schema_1.TradeV2QueryParamsSchema.validateSync(params);
this.apiUrl = merchant.ecpayServiceUrls.TradeV2[merchant.mode];
this._params = Object.assign({}, this.params);
}
read() {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this._read();
if (!result.RtnValue) {
// RtnMsg: '' for success
throw new Error_1.QueryError(result.RtnMsg, result.RtnValue, result);
}
return result;
});
}
}
exports.TradeV2Query = TradeV2Query;
class TradeNoAioQuery extends Query {
constructor(merchant, params) {
super(merchant, params);
schema_1.TradeNoAioQueryParamsSchema.validateSync(params);
this.apiUrl = merchant.ecpayServiceUrls.TradeNoAio[merchant.mode];
this.responseDataEncoding = (params === null || params === void 0 ? void 0 : params.CharSet) === '2' ? 'utf8' : 'Big5';
this._params = Object.assign({}, this.params);
}
read() {
return __awaiter(this, void 0, void 0, function* () {
return this._read();
});
}
}
exports.TradeNoAioQuery = TradeNoAioQuery;
// note: 無測試環境可用, TBD: testing@production
class FundingReconDetailQuery extends Query {
constructor(merchant, params) {
super(merchant, params);
schema_1.FundingReconDetailQueryParamsSchema.validateSync(params);
this.apiUrl = merchant.ecpayServiceUrls.FundingReconDetail[merchant.mode];
this.responseDataEncoding = (params === null || params === void 0 ? void 0 : params.CharSet) === '2' ? 'utf8' : 'Big5';
this._params = Object.assign({}, this.params);
}
read() {
return __awaiter(this, void 0, void 0, function* () {
return this._read();
});
}
}
exports.FundingReconDetailQuery = FundingReconDetailQuery;