UNPKG

@orenda-inc/nestjs-webx-pay

Version:

NestJS module for WebX Pay integration

201 lines (200 loc) 9.68 kB
"use strict"; 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 __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); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebXPayController = void 0; const common_1 = require("@nestjs/common"); const payment_dto_1 = require("../dto/payment.dto"); const webx_pay_service_1 = require("../services/webx-pay.service"); let WebXPayController = class WebXPayController { constructor(webxPayService, config) { this.webxPayService = webxPayService; this.config = config; } /** * Process payment request */ async processPayment(paymentDto, req) { try { const result = await this.webxPayService.processPayment(paymentDto); if (!result.success) { throw new common_1.HttpException({ message: result.error, success: false }, common_1.HttpStatus.BAD_REQUEST); } this.config.onPaymentInitiated?.(req, paymentDto); return result; } catch (error) { this.config.onPaymentInitiatedFailed?.(req, paymentDto); throw new common_1.HttpException({ message: error instanceof Error ? error.message : 'Payment processing failed', success: false }, common_1.HttpStatus.INTERNAL_SERVER_ERROR); } } /** * Handle webhook notifications */ async handleWebhook(req, res, contentType = 'application/x-www-form-urlencoded') { // WebX Pay sends data in the request body let webhookData = {}; // Extract data from request body (this is the actual WebX Pay format) if (req.body && typeof req.body === 'object') { Object.entries(req.body).forEach(([key, value]) => { if (typeof value === 'string') { webhookData[key] = value; } else if (value !== null && value !== undefined) { webhookData[key] = value.toString(); } }); } // If body is empty, try query parameters as fallback if (Object.keys(webhookData).length === 0) { Object.entries(req.query).forEach(([key, value]) => { if (typeof value === 'string') { webhookData[key] = value; } else if (Array.isArray(value)) { webhookData[key] = value.join(', '); } }); } // Decode the payment data if present let decodedPaymentData = {}; if (webhookData.payment) { try { // Decode base64 payment data const decodedPayment = Buffer.from(webhookData.payment, 'base64').toString('utf8'); //payment format: order_id|order_refference_number|date_time_transaction|payment_gateway_used|status_code|comment; // Split and map payment fields with fallback for missing fields const [orderId, referenceNumber, timestamp, gatewayId, statusCode, ...rest] = decodedPayment.split('|'); decodedPaymentData = { orderId: orderId?.trim() || '', referenceNumber: referenceNumber?.trim() || '', timestamp: timestamp?.trim() || '', gatewayId: gatewayId?.trim() || '', statusCode: statusCode?.trim() || '', comment: rest.length > 0 ? rest.join('|').trim() : '' }; webhookData.payment = decodedPaymentData; // Execute custom callback functions try { // Always call the general webhook callback if provided if (this.config.onWebhookReceived) { await this.config.onWebhookReceived(req, webhookData); } // Determine success/failure based on status code const isSuccess = webhookData.status_code === '00' || decodedPaymentData.statusCode === '00'; // Call specific success/failure callbacks based on status if (isSuccess) { if (this.config.onPaymentSuccess) { await this.config.onPaymentSuccess(req, webhookData); } } else { if (this.config.onPaymentFailure) { await this.config.onPaymentFailure(req, webhookData); } } } catch (callbackError) { console.error('Callback execution error:', callbackError); // Continue processing even if callback fails } // Check if redirect URLs are configured const hasRedirectUrls = this.config.redirectOnSuccess && this.config.redirectOnFailure; // Determine success/failure for redirect const isSuccess = webhookData.status_code === '00' || decodedPaymentData.statusCode === '00'; delete webhookData.signature; delete webhookData.custom_fields; if (!isSuccess) { if (hasRedirectUrls) { // Build failure redirect URL with error parameters res.redirect(this.webxPayService.appendParamsToUrl(this.config.redirectOnFailure, webhookData)); return; } else { // Return JSON response return res.status(400).json({ success: false, status: 'failed', data: webhookData, timestamp: new Date().toISOString() }); } } if (hasRedirectUrls) { console.log(); // Build success redirect URL with webhook data res.redirect(this.webxPayService.appendParamsToUrl(this.config.redirectOnSuccess, webhookData)); return; } else { // Return JSON response return res.status(200).json({ success: true, status: 'success', data: webhookData, timestamp: new Date().toISOString() }); } } catch (error) { const hasRedirectUrls = this.config.redirectOnSuccess && this.config.redirectOnFailure; if (hasRedirectUrls) { // Build failure redirect URL with error parameters const failureUrl = new URL(this.config.redirectOnFailure); failureUrl.searchParams.set('status', 'error'); failureUrl.searchParams.set('error', error instanceof Error ? error.message : 'Webhook processing failed'); failureUrl.searchParams.set('timestamp', new Date().toISOString()); res.redirect(failureUrl.toString()); return; } else { // Return JSON error response return res.status(500).json({ success: false, status: 'error', error: error instanceof Error ? error.message : 'Webhook processing failed', timestamp: new Date().toISOString() }); } } } } }; exports.WebXPayController = WebXPayController; __decorate([ (0, common_1.Post)('payment'), __param(0, (0, common_1.Body)()), __param(1, (0, common_1.Req)()), __metadata("design:type", Function), __metadata("design:paramtypes", [payment_dto_1.PaymentRequestDto, Object]), __metadata("design:returntype", Promise) ], WebXPayController.prototype, "processPayment", null); __decorate([ (0, common_1.Post)('webhook'), __param(0, (0, common_1.Req)()), __param(1, (0, common_1.Res)()), __param(2, (0, common_1.Headers)('content-type')), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, String]), __metadata("design:returntype", Promise) ], WebXPayController.prototype, "handleWebhook", null); exports.WebXPayController = WebXPayController = __decorate([ (0, common_1.Controller)('webx-pay'), __param(1, (0, common_1.Inject)('WEBX_PAY_CONFIG')), __metadata("design:paramtypes", [webx_pay_service_1.WebXPayService, Object]) ], WebXPayController);