UNPKG

nestjs-esewa

Version:

This is simple wrapper for Esewa Payment extended from @dallotech/nestjs-esewa. It supports Epay-V2 and transaction verification for Esewa SDK, but later more will be added. Just ping us or open pull request and contribute :)

209 lines 11 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var EsewaService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.EsewaService = void 0; const common_1 = require("@nestjs/common"); const esewa_interface_1 = require("./esewa.interface"); const axios_1 = require("@nestjs/axios"); const CryptoJS = __importStar(require("crypto-js")); const rxjs_1 = require("rxjs"); let EsewaService = EsewaService_1 = class EsewaService { constructor(options, httpService) { this.options = options; this.httpService = httpService; this.paymentMode = null; this.productCode = null; this.paymentUrlTest = null; this.paymentUrl = null; this.validateUrlTest = null; this.validateUrl = null; this.validateUrlMobile = null; this.merchantId = null; this.merchantSecret = null; this.secretKey = null; if (!options.productCode) { throw new common_1.InternalServerErrorException("Product Code for esewa payment is missing"); } if (!options.secretKey) { throw new common_1.InternalServerErrorException("Secret Ket for esewa payment is missing"); } this.paymentMode = options.paymentMode || esewa_interface_1.PaymentMode.TEST; this.productCode = options.productCode; this.paymentUrlTest = options.paymentUrlTest || esewa_interface_1.ESEWA_PAYMENT_TEST_URL; this.paymentUrl = options.paymentUrl || esewa_interface_1.ESEWA_PAYMENT_URL; this.validateUrlTest = options.validateUrlTest || esewa_interface_1.ESEWA_VALIDATE_TEST_URL; this.validateUrl = options.validateUrl || esewa_interface_1.ESEWA_VALIDATE_URL; this.validateUrlMobile = options.validateUrlMobile || esewa_interface_1.ESEWA_VALIDATE_MOBILE_URL; this.merchantId = options.merchantId; this.merchantSecret = options.merchantSecret; this.secretKey = options.secretKey; } static getMessage(fieldNameList, data) { const keyValuePairs = fieldNameList.map(fieldName => `${fieldName}=${data[fieldName]}`); return keyValuePairs.join(','); } static decodeBase64ToJson(encodedData) { const decodedBuffer = Buffer.from(encodedData, 'base64'); const decodedData = decodedBuffer.toString('utf-8'); return JSON.parse(decodedData); } init(data) { let { amount, productServiceCharge = 0, productDeliveryCharge = 0, taxAmount = 0, totalAmount, transactionUuid, successUrl, failureUrl } = data; if (!amount || !totalAmount || !transactionUuid || !successUrl || !failureUrl) { throw new common_1.BadRequestException("Data missing for initiating Esewa payment"); } const requestData = { total_amount: totalAmount, transaction_uuid: transactionUuid, product_code: this.productCode }; const fieldNameString = "total_amount,transaction_uuid,product_code"; const message = EsewaService_1.getMessage(fieldNameString.split(','), requestData); const hashInBase64 = this.generateSignature(message); const esewaData = { amount: amount.toString(), // Amount of the product or item product_service_charge: productServiceCharge.toString(), // Service charge by the merchant product_delivery_charge: productDeliveryCharge.toString(), // Delivery charge by the merchant tax_amount: taxAmount.toString(), // Tax amount on the product total_amount: totalAmount.toString(), // Total payment amount including tax, service, and delivery charge transaction_uuid: transactionUuid, // Unique ID of the product product_code: this.productCode, // Merchant code provided by eSewa success_url: successUrl, // Success URL failure_url: failureUrl, // Failure URL signed_field_names: fieldNameString, signature: hashInBase64, payment_url: this.paymentMode.localeCompare(esewa_interface_1.PaymentMode.TEST) == 0 ? this.paymentUrlTest : this.paymentUrl }; return esewaData; } async verify(data) { var _a, _b, _c, _d, _e, _f; const { encodedData } = data; if (!encodedData) { throw new common_1.BadRequestException('Data missing for validating eSewa payment'); } let jsonData; try { jsonData = EsewaService_1.decodeBase64ToJson(encodedData); } catch (error) { throw new common_1.BadRequestException('Invalid encodedData format.'); } /** * total_amount field contains comma which needs to be removed before generating signature * so that signature generated in server matches with the signature from encoded data */ jsonData['total_amount'] = (_a = jsonData['total_amount']) === null || _a === void 0 ? void 0 : _a.replace(',', ''); const { product_code, total_amount, transaction_uuid, signature, signed_field_names } = jsonData; const signedFieldNameList = signed_field_names.split(','); const message = EsewaService_1.getMessage(signedFieldNameList, jsonData); const serverSignature = this.generateSignature(message); if (signature.localeCompare(serverSignature) !== 0) { throw new common_1.BadRequestException('Signature mismatch during eSewa payment validation.'); } const validateUrl = this.paymentMode.localeCompare('TEST') == 0 ? this.validateUrlTest : this.validateUrl; try { const response = await (0, rxjs_1.firstValueFrom)(this.httpService.get(`${validateUrl}?product_code=${this.productCode}&total_amount=${total_amount}&transaction_uuid=${transaction_uuid}`)); if ((response === null || response === void 0 ? void 0 : response.status) == 200 && response.data) { return { productCode: (_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.product_code, transactionUuid: (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.transaction_uuid, totalAmount: (_d = response === null || response === void 0 ? void 0 : response.data) === null || _d === void 0 ? void 0 : _d.total_amount, refId: (_e = response === null || response === void 0 ? void 0 : response.data) === null || _e === void 0 ? void 0 : _e.ref_id, status: (_f = response === null || response === void 0 ? void 0 : response.data) === null || _f === void 0 ? void 0 : _f.status, }; } throw new common_1.InternalServerErrorException('Unexpected response from eSewa verification endpoint.'); } catch (error) { throw new common_1.InternalServerErrorException(`Error in payment verification \n ${error === null || error === void 0 ? void 0 : error.message}`); } } async verifyMobile(data) { if (!this.merchantId) { throw new common_1.InternalServerErrorException("Merchant Id for esewa payment is missing"); } if (!this.merchantSecret) { throw new common_1.InternalServerErrorException("Merchant Secret for esewa payment is missing"); } const { refId } = data; if (!refId) { throw new common_1.BadRequestException('Data missing for validating eSewa payment'); } if (!this.merchantId) { throw new common_1.BadRequestException('Merchant ID is missing'); } if (!this.merchantSecret) { throw new common_1.BadRequestException('Merchant Secret is missing'); } const headers = { 'merchantId': this.merchantId, 'merchantSecret': this.merchantSecret, }; // Add the headers to the options object const requestOptions = { headers, }; return await (0, rxjs_1.firstValueFrom)(this.httpService.get(`${this.validateUrlMobile}?txnRefId=${refId}`, requestOptions)); } generateSignature(message) { const hash = CryptoJS.HmacSHA256(message, this.secretKey); return CryptoJS.enc.Base64.stringify(hash); } }; exports.EsewaService = EsewaService; exports.EsewaService = EsewaService = EsewaService_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(esewa_interface_1.ESEWA_CONFIG_OPTIONS)), __metadata("design:paramtypes", [Object, axios_1.HttpService]) ], EsewaService); //# sourceMappingURL=esewa.service.js.map