UNPKG

node-paytmpg

Version:

Payment Gateway Integration using NodeJS

1,068 lines (870 loc) 45 kB
var packageInfo = require('../../package.json') const checksum_lib = require('./checksum/checksum.js'); var request = require('request') var Transaction; var IDLEN = 10; var nodeBase64 = require('nodejs-base64-converter'); var RazorPay = require('razorpay'); var OpenMoney = require('./adapters/open_money') const PaytmChecksum = require('./checksum/PaytmChecksum.js'); const { stat } = require('fs'); const { config } = require('process'); let loadingSVG = ` <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:#fff;display:block;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"> <g transform="rotate(0 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(30 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(60 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(90 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(120 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(150 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(180 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(210 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(240 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(270 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(300 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"></animate> </rect> </g><g transform="rotate(330 50 50)"> <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7"> <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animate> </rect> </g> </svg>` function sanitizeRequest(body) { if (body.amount) body.amount = parseFloat(body.amount); if (body.TXN_AMOUNT) body.amount = parseFloat(body.TXN_AMOUNT); } module.exports = function (app, callbacks) { var config = (app.get('np_config')) var useController = require('./np_user.controller.js')(app, callbacks); var razorPayInstance; var openMoneyInstance = new OpenMoney(config); if (config.razor_url) razorPayInstance = new RazorPay({ key_id: config.KEY, key_secret: config.SECRET }) if (config.open_money_url) { openMoneyInstance = new OpenMoney(config); } let usingMultiDbOrm = false; if (config.db_url) { Transaction = require('../models/np_transaction.model.js'); usingMultiDbOrm = false; } else if (app.multidborm) { Transaction = require('../models/np_multidbplugin.js')('nptransactions', app.multidborm); Transaction.db = app.multidborm; Transaction.modelname = 'nptransactions' Transaction.idFieldName = 'orderId' app.NPTransaction = Transaction; usingMultiDbOrm = true; } var module = {}; var config = (app.get('np_config')) function makeid(length) { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < length; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; } var vp = __dirname + config.view_path module.home = (req, res) => { packageInfo.repository.url = packageInfo.repository.url.replace('git+', '') res.render(vp + "home.hbs", packageInfo) } module.init = async function (req, res) { if (!req.body.ORDER_ID && !req.body.EMAIL && req.query.to) { let toData = JSON.parse(nodeBase64.decode(req.query.to)); req.body.NAME = toData.NAME req.body.EMAIL = toData.EMAIL req.body.MOBILE_NO = toData.MOBILE_NO req.body.ORDER_ID = toData.ORDER_ID } sanitizeRequest(req.body); let gotAllParams = true; if (req.body !== undefined) { let checks = [req.body.TXN_AMOUNT, req.body.PRODUCT_NAME, req.body.MOBILE_NO, req.body.NAME, req.body.EMAIL] for (var i = 0; i < checks.length; i++) { if (checks[i] === undefined) { gotAllParams = false; break; } } } else { gotAllParams = false; } // console.log(req.body) if ((req.body.ORDER_ID !== undefined && req.body.ORDER_ID.length > 2) && (req.body.CUST_ID !== undefined && req.body.CUST_ID.length > 2)) { // console.log('redirect') // console.log(req.body) var params = {}; params['MID'] = req.body.MID; params['WEBSITE'] = req.body.WEBSITE; params['CHANNEL_ID'] = req.body.CHANNEL_ID; params['INDUSTRY_TYPE_ID'] = req.body.INDUSTRY_TYPE_ID; params['ORDER_ID'] = req.body.ORDER_ID; params['CUST_ID'] = req.body.CUST_ID; params['TXN_AMOUNT'] = req.body.TXN_AMOUNT; params['CALLBACK_URL'] = req.body.CALLBACK_URL + "?order_id=" + req.body.ORDER_ID; params['EMAIL'] = req.body.EMAIL; params['MOBILE_NO'] = req.body.MOBILE_NO; params['PRODUCT_NAME'] = req.body.PRODUCT_NAME; params['NAME'] = req.body.NAME; if (config.paytm_url) { let initTxnbody = { "requestType": "Payment", "mid": params['MID'], "websiteName": params['WEBSITE'], "orderId": params['ORDER_ID'], "callbackUrl": params['CALLBACK_URL'], "txnAmount": { "value": params['TXN_AMOUNT'], "currency": params['CURRENCY'] || "INR", }, "userInfo": { "custId": params['CUST_ID'], "mobile": params['MOBILE_NO'], "firstName": params['NAME'], "email": params['EMAIL'] } }; if (config.mode) { initTxnbody["enablePaymentMode"] = JSON.parse(config.mode) } let checksum = await PaytmChecksum.generateSignature(JSON.stringify(initTxnbody), config.KEY) let initTxnUrl = config.paytm_url + `/theia/api/v1/initiateTransaction?mid=${params['MID']}&orderId=${params['ORDER_ID']}`; request.post( initTxnUrl, { json: { "body": initTxnbody, "head": { "signature": checksum, "channelId": params['CHANNEL_ID'] } } }, function (error, response, body) { if (!error && response.statusCode != undefined && response.statusCode != NaN && response.statusCode == 200 && body.body && body.body.resultInfo && body.body.resultInfo.resultStatus == "S") { let paytmJsToken = {} paytmJsToken.CALLBACK_URL = params['CALLBACK_URL'] paytmJsToken.ORDERID = params['ORDER_ID'] paytmJsToken.ORDER_ID = params['ORDER_ID'] paytmJsToken.CANCELLED = "cancelled" paytmJsToken.TOKEN = body.body.txnToken paytmJsToken.TXN_AMOUNT = params['TXN_AMOUNT'] paytmJsToken.MID = params['MID'] paytmJsToken.CALLBACK_URL = params['CALLBACK_URL'] paytmJsToken.CALLBACK_URL = params['CALLBACK_URL'] let paytmJsCheckouHtml = `<html> <head> <title>Merchant Checkout</title> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0"/> </head> <body> <center> <h1>Please donot close this page or press the back button. Processing...</h1> ${loadingSVG} </center> <form id="cancelform" action="${params['CALLBACK_URL']}" method="post"> <input type="hidden" name="TXNID" value="na"/> <input type="hidden" name="STATUS" value="TXN_FAILURE"/> <input type="hidden" name="CANCELLED" value="cancelled"/> <input id="RESPMSG" type="hidden" name="RESPMSG" value=""/> <input type="hidden" name="ORDERID" value="${params["ORDER_ID"]}"/> </form> <script> function getBodyColor(color){ const hex = color.replace('#', ''); const c_r = parseInt(hex.substr(0, 2), 16); const c_g = parseInt(hex.substr(2, 2), 16); const c_b = parseInt(hex.substr(4, 2), 16); const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000; // console.log(brightness , brightness > 155 ? "#fff" : "#1a1a1c") return brightness > 155 ? "#1a1a1c" : "#ffffff"; } function shadeColor(color, percent) { var R = parseInt(color.substring(1,3),16); var G = parseInt(color.substring(3,5),16); var B = parseInt(color.substring(5,7),16); R = parseInt(R * (100 + percent) / 100); G = parseInt(G * (100 + percent) / 100); B = parseInt(B * (100 + percent) / 100); R = (R<255)?R:255; G = (G<255)?G:255; B = (B<255)?B:255; var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); return "#"+RR+GG+BB; } function failTxn(reason) { var form = document.getElementById("cancelform"); var element2 = document.getElementById("RESPMSG"); element2.value=reason; form.submit(); } function onScriptLoad(){ var config = { "root": "", "flow": "DEFAULT", "style": { // "bodyColor": shadeColor("${config.theme_color}",+40), "themeBackgroundColor": "${config.theme_color}", "themeColor": getBodyColor("${config.theme_color}"), "headerBackgroundColor": "${config.theme_color}", "headerColor": getBodyColor("${config.theme_color}") }, "data": { "orderId": "${params['ORDER_ID']}", /* update order id */ "token": "${body.body.txnToken}", /* update token value */ "tokenType": "TXN_TOKEN", "amount": "${params['TXN_AMOUNT']}" /* update amount */ }, "handler": { "notifyMerchant": function(eventName,data){ // console.log("notifyMerchant handler function called"); // console.log("eventName => ",eventName); // console.log("data => ",data); if(eventName == "APP_CLOSED"){ failTxn(eventName) } } } }; if(window.Paytm && window.Paytm.CheckoutJS){ window.Paytm.CheckoutJS.onLoad(function excecuteAfterCompleteLoad() { // initialze configuration using init method window.Paytm.CheckoutJS.init(config).then(function onSuccess() { // after successfully updating configuration, invoke JS Checkout window.Paytm.CheckoutJS.invoke(); }).catch(function onError(error){ // console.log("error => ",error); failTxn(error.message) }); }); } } </script> <script type="application/javascript" crossorigin="anonymous" src="${config.paytm_url}/merchantpgpui/checkoutjs/merchants/${params['MID']}.js" onload="onScriptLoad();" crossorigin="anonymous"></script> </body> </html>` if (res.token) { res.token(paytmJsToken) } return res.send(paytmJsCheckouHtml) } else { console.log('ERROR:::', error, '\n', body); res.status(500) var form_fields = ""; let errorResp = { TXNID: "na", STATUS: "TXN_FAILURE", CANCELLED: "cancelled", ORDERID: params["ORDER_ID"] } for (var x in errorResp) { form_fields += "<input type='hidden' name='" + x + "' value='" + errorResp[x] + "' >"; } form_fields += "<input type='hidden' name='CHECKSUMHASH' value='" + checksum + "' >"; if (res.token) { res.token(undefined) } res.writeHead(200, { 'Content-Type': 'text/html' }); res.write(`<html> <head> <title>Merchant Checkout Error</title> </head> <body> <center> <h1>Something went wrong. Please wait you will be redirected automatically...</h1> </center> <form method="post" action="${params['CALLBACK_URL']}" name="f1">${form_fields}</form> <script type="text/javascript">document.f1.submit();</script> </body> </html>`); res.end(); } } ); } else if (config.razor_url) { let fail = `<div style="display:none"> <form method="post" action="${params['CALLBACK_URL']}" id="fail"> <input name="razorpay_order_id" value="${params['ORDER_ID']}" hidden="true"/> </form> </div>`; let html = ` <script src="https://checkout.razorpay.com/v1/checkout.js"></script> <script> var options = { "key": "${config.KEY}", "amount": "${parseFloat(params['TXN_AMOUNT']) * 100}", "currency": "INR", "name": "${params['PRODUCT_NAME']}", "description": "Order # ${params['ORDER_ID']}", "image": "${config.logo}", "order_id": "${params['ORDER_ID']}", "callback_url": "${params['CALLBACK_URL']}", "prefill": { "name": "${params['NAME']}", "email": "${params['EMAIL']}", "contact": "${params['MOBILE_NO']}" }, "theme": { "color": "${config.theme_color}" }, "modal": { "ondismiss": function(){ document.getElementById("fail").submit() } } }; var rzp1 = new Razorpay(options); rzp1.open(); </script>`; res.writeHead(200, { 'Content-Type': 'text/html' }); res.write(`<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Processing ! Please do not refresh this page...</h1><br>${html}<br>${fail}<br>${loadingSVG}</center></body></html>`); res.end(); } else if (config.open_money_url) { try { let pmttoken = await openMoneyInstance.generatePaymentToken(params); openMoneyInstance.renderProcessingPage(params, pmttoken, res, loadingSVG); var myquery = { orderId: params['ORDER_ID'] }; Transaction.findOne(myquery, function (err, objForUpdate) { objForUpdate.extra = JSON.stringify({ layer_pay_token_id: pmttoken.tokenid }); var newvalues = { $set: objForUpdate }; Transaction.updateOne(myquery, newvalues, function (err, saveRes) { let status = 'Updated TXNID' }); }, usingMultiDbOrm ? Transaction : undefined) } catch (e) { openMoneyInstance.renderError(params, e, res) } } if (callbacks !== undefined) callbacks.onStart(params['ORDER_ID'], params); } else if ((req.body.ORDER_ID !== undefined && req.body.ORDER_ID.length > 2) || gotAllParams) { useController.create({ name: req.body.NAME, email: req.body.EMAIL, phone: req.body.MOBILE_NO }, function (user) { //console.log(user) let onTxn = async function (txnData) { //console.log(txnData) var params = {}; params['MID'] = config.MID; params['WEBSITE'] = config.WEBSITE; params['CHANNEL_ID'] = config.CHANNEL_ID; params['INDUSTRY_TYPE_ID'] = config.INDUSTRY_TYPE_ID; params['ORDER_ID'] = txnData.orderId; params['CUST_ID'] = txnData.cusId; params['TXN_AMOUNT'] = JSON.stringify(txnData.amount); params['CALLBACK_URL'] = config.host_url + '/' + config.path_prefix + '/callback' params['EMAIL'] = txnData.email; params['MOBILE_NO'] = txnData.phone; params['NAME'] = txnData.name; params['PRODUCT_NAME'] = txnData.pname; let showConfirmation = function (err, checksum) { res.render(vp + "init.hbs", { action: '', readonly: 'readonly', BUTTON: 'Pay', NAME: params['NAME'], EMAIL: params['EMAIL'], MOBILE_NO: params['MOBILE_NO'], PRODUCT_NAME: params['PRODUCT_NAME'], TXN_AMOUNT: params['TXN_AMOUNT'], MID: params['MID'], WEBSITE: params['WEBSITE'], ORDER_ID: params['ORDER_ID'], CUST_ID: params['CUST_ID'], INDUSTRY_TYPE_ID: params['INDUSTRY_TYPE_ID'], CHANNEL_ID: params['CHANNEL_ID'], CALLBACK_URL: params['CALLBACK_URL'], CHECKSUMHASH: checksum }) } if (config.paytm_url) checksum_lib.genchecksum(params, config.KEY, showConfirmation); else if (config.razor_url) { showConfirmation() } else if (config.open_money_url) { showConfirmation() } }; if ((req.body.ORDER_ID !== undefined && req.body.ORDER_ID.length > 2)) { var myquery = { orderId: req.body.ORDER_ID }; Transaction.findOne(myquery, function (err, orderData) { onTxn(orderData); }, usingMultiDbOrm ? Transaction : undefined); } else { function onOrder(orderId) { var txnTask = new Transaction({ orderId: orderId, cusId: user.id, time: Date.now(), timeStamp: Date.now(), status: 'INITIATED', name: user.name, email: user.email, phone: user.phone, amount: req.body.TXN_AMOUNT, pname: req.body.PRODUCT_NAME, extra: '' }); txnTask.save().then(onTxn) .catch(err => { console.log(err) res.redirect('') }); } let orderId; if (config.paytm_url) { orderId = "pay_" + makeid(config.id_length || IDLEN) onOrder(orderId) } else if (config.razor_url) { var options = { amount: req.body.TXN_AMOUNT * 100, currency: "INR", receipt: user.id + '_' + Date.now() }; razorPayInstance.orders.create(options, function (err, order) { if (err) { res.send({ message: "An error occurred ! " + err.description }) return; } orderId = order.id onOrder(orderId) }) } else if (config.open_money_url) { orderId = "pay_" + makeid(config.id_length || IDLEN) onOrder(orderId) } } }); } else { res.render(vp + "init.hbs", { action: '', readonly: '', check: true, BUTTON: 'Submit', NAME: (req.body.NAME === undefined ? '' : req.body.NAME), EMAIL: (req.body.EMAIL === undefined ? '' : req.body.EMAIL), MOBILE_NO: (req.body.MOBILE_NO === undefined ? '' : req.body.MOBILE_NO), PRODUCT_NAME: (req.body.PRODUCT_NAME === undefined ? '' : req.body.PRODUCT_NAME), TXN_AMOUNT: (req.body.TXN_AMOUNT === undefined ? '' : req.body.TXN_AMOUNT), MID: config.MID, WEBSITE: config.WEBSITE, ORDER_ID: '', CUST_ID: '', INDUSTRY_TYPE_ID: config.INDUSTRY_TYPE_ID, CHANNEL_ID: config.CHANNEL_ID, CALLBACK_URL: config.CALLBACK_URL, CHECKSUMHASH: '' }) } } function updateTransaction(req, res) { var myquery = { orderId: req.body.ORDERID }; Transaction.findOne(myquery, function (err, objForUpdate) { if (err) { res.send({ message: "Transaction Not Found !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID }) return; } if (objForUpdate.status != ("INITIATED") && objForUpdate.status != ("TXN_PENDING") && objForUpdate.status != ("PENDING")) { objForUpdate.readonly = "readonly" objForUpdate.action = config.homepage res.render(vp + "result.hbs", objForUpdate); console.log("Transaction already processed ", req.body.ORDERID) // res.send({ message: "Transaction already processed", status: objForUpdate.status, ORDERID: objForUpdate.orderId, TXNID: objForUpdate.TXNID, TXNID: req.body.TXNID }) return; } if (req.body.status == "paid" && !req.body.STATUS) { req.body.STATUS = "TXN_SUCCESS" } objForUpdate.status = req.body.STATUS; objForUpdate.TXNID = req.body.TXNID; objForUpdate.extra = JSON.stringify(req.body); var newvalues = { $set: objForUpdate }; Transaction.updateOne(myquery, newvalues, function (err, saveRes) { if (err) { res.send({ message: "Error Occured !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID }) } else { if (callbacks !== undefined) callbacks.onFinish(req.body.ORDERID, req.body); objForUpdate.readonly = "readonly" objForUpdate.action = config.homepage res.render(vp + "result.hbs", objForUpdate); } }); }, usingMultiDbOrm ? Transaction : undefined) } module.callback = async (req, res) => { console.log("request_data ", req.originalUrl, JSON.stringify(req.body)) var result = false; let isCancelled = false; if (config.paytm_url) { var checksumhash = req.body.CHECKSUMHASH; if (checksumhash) { result = checksum_lib.verifychecksum(req.body, config.KEY, checksumhash); } else { let liveStatus = await new Promise((resolve, reject) => { getStatusFromPaytm(req.body, req.body.ORDERID, (paytmResponse) => { resolve(paytmResponse) }) }) result = liveStatus.STATUS == req.body.STATUS; } if (req.body.STATUS == 'TXN_FAILURE' && req.body.CANCELLED == "cancelled" && req.body.TXNID) { isCancelled = true; } } else if (config.razor_url) { if (req.body.razorpay_payment_id) { result = checksum_lib.checkRazorSignature(req.body.razorpay_order_id, req.body.razorpay_payment_id, config.SECRET, req.body.razorpay_signature) if (result) { req.body.STATUS = 'TXN_SUCCESS' req.body.ORDERID = req.body.razorpay_order_id req.body.TXNID = req.body.razorpay_payment_id } } else { if (req.body.error && req.body.error.metadata && JSON.parse(req.body.error.metadata)) { let orderId = JSON.parse(req.body.error.metadata).order_id req.body.razorpay_order_id = orderId } req.body.STATUS = 'TXN_FAILURE' req.body.ORDERID = req.body.razorpay_order_id || req.query.order_id isCancelled = true; } } else if (config.open_money_url) { let openRest = await openMoneyInstance.verifyResult(req); result = true; req.body.STATUS = openRest.STATUS req.body.TXNID = openRest.TXNID req.body.ORDERID = openRest.ORDERID || req.query.order_id req.body.extras = openRest.data } //console.log("Checksum Result => ", result, "\n"); console.log("NodePayTMPG::Transaction => ", req.body.ORDERID, req.body.STATUS); //console.log(req.body) if (result || isCancelled) { updateTransaction(req, res); } else { res.send({ message: "Something went wrong ! Please try again later .", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID }) } } module.webhook = (req, res) => { console.log("request_data ", req.originalUrl, JSON.stringify(req.body)) if (config.paytm_url) { module.callback(req, res) } else if (config.razor_url) { let events = ["payment.captured", "payment.pending", "payment.failed"] if (req.body.event && events.indexOf(req.body.event) > -1) { if (req.body.payload && req.body.payload.payment && req.body.payload.payment.entity) { let entity = req.body.payload.payment.entity; let razorpay_order_id = entity.order_id; let razorpay_payment_id = entity.id; let status = entity.status; let event = req.body.event; console.log(`Razorpay webhook payment order=${razorpay_order_id} payid=${razorpay_payment_id} status=${status}`) let reqBody = req.rawBody, signature = req.headers["x-razorpay-signature"]; result = RazorPay.validateWebhookSignature(reqBody, req.headers['x-razorpay-signature'], config.SECRET) req.signatureVerified = result; if (result) { if (event == events[0]) { req.body.STATUS = "TXN_SUCCESS"; } else if (event == events[1]) { //pending req.body.STATUS = "TXN_PENDING"; } else { // failed req.body.STATUS = "TXN_FAILURE"; } req.body.ORDERID = razorpay_order_id; req.body.TXNID = razorpay_payment_id; setTimeout(() => { updateTransaction(req, res) }, 3000) } else { res.status(401) res.send({ message: "Invalid Rzpay signature" }) } } else { res.status(400) res.send({ message: "Invalid Payload" }) } } else { res.status(400) res.send({ message: "Unsupported event : " + req.body.event }) } } else if (config.open_money_url) { openMoneyInstance.processWebhook(req, res, updateTransaction) } } module.createTxn = (req, res) => { useController.create({ name: req.body.NAME, email: req.body.EMAIL, phone: req.body.MOBILE_NO }, async function (user) { let id; if (config.paytm_url) { id = "pay_" + makeid(config.id_length || IDLEN) } else if (config.razor_url) { var options = { amount: req.body.TXN_AMOUNT * 100, currency: "INR", receipt: user.id + '_' + Date.now() }; let order = await razorPayInstance.orders.create(options); id = order.id; } else if (config.open_money_url) { id = "pay_" + makeid(config.id_length || IDLEN) } var txnTask = new Transaction({ id: id, orderId: id, cusId: user.id, time: Date.now(), status: 'INITIATED', name: user.name, email: user.email, phone: user.phone, amount: req.body.TXN_AMOUNT, pname: req.body.PRODUCT_NAME, extra: (req.body.EXTRA || '') }); txnTask.save().then(function (txn) { var urlData64 = nodeBase64.encode(JSON.stringify({ NAME: txn.name, EMAIL: txn.email, MOBILE_NO: txn.phone, ORDER_ID: txn.orderId })) txn.payurl = config.host_url + '/' + config.path_prefix + '/init?to=' + urlData64; res.send(txn) }) .catch(err => { console.log(err) res.redirect('') }); }); }; module.createTxnToken = (req, res) => { module.createTxn(req, { send: function (createTxnResult) { // console.log(createTxnResult) req.body.NAME = createTxnResult.name req.body.EMAIL = createTxnResult.email req.body.MOBILE_NO = createTxnResult.phone req.body.ORDER_ID = createTxnResult.orderId module.init(req, { render: (renderPath, initResultRender) => { // console.log(initResultRender) req.body = initResultRender module.init(req, { send: (initResult) => { }, status: (status) => { console.log('status', status) }, token: (tokenData) => { if (!tokenData) { res.status(500) res.send('Something went wrong. Please try again later.') } else { tokenData.payurl = createTxnResult.payurl; res.send(tokenData) } }, render: (renderPath2, init2ResultRender) => { console.log('init2ResultRender', init2ResultRender) }, end: (initResultWrite) => { console.log('initResultWrite', initResultWrite) }, write: (initResultWrite) => { console.log('initResultWrite', initResultWrite) }, writeHead: (initResultWriteHead) => { console.log('initResultWriteHead', initResultWriteHead) } }) } }) }, redirect: res.redirect }) }; module.status = (req, res) => { if (!req.body.ORDER_ID && req.query.ORDER_ID) { req.body.ORDER_ID = req.query.ORDER_ID } var myquery = { orderId: req.body.ORDER_ID }; Transaction.findOne(myquery, async function (err, orderData) { if (err) { res.send(err) return } if (orderData.status === "INITIATED") { var params = {} params["MID"] = config.MID; params["ORDERID"] = req.body.ORDER_ID; async function onStatusUpdate(paytmResponse) { if (paytmResponse.TXNID.length > 4) { orderData.status = paytmResponse.STATUS; orderData.extra = JSON.stringify(paytmResponse); var newvalues = { $set: orderData }; Transaction.updateOne(myquery, newvalues, function (err, saveRes) { if (err) { res.send({ message: "Error Occured !", ORDERID: paytmResponse.ORDERID, TXNID: paytmResponse.TXNID }) } else { if (callbacks !== undefined) callbacks.onFinish(req.body.ORDER_ID, orderData); res.send(paytmResponse) } }); } else { res.send(orderData) } } if (config.paytm_url) { getStatusFromPaytm(params, req.body.ORDER_ID, onStatusUpdate) } else if (config.razor_url) { let result = await razorPayInstance.orders.fetch(req.body.ORDER_ID) result.ORDERID = req.body.ORDER_ID if (result.status == 'paid' && result.amount_due == 0) { result.STATUS = 'TXN_SUCCESS' let payments = await razorPayInstance.orders.fetchPayments(req.body.ORDER_ID) payments.items.forEach(item => { if (item.status == 'captured') { result.TXNID = item.id } }); result.payments = payments; onStatusUpdate(result) } else { res.send(orderData); } } else if (config.open_money_url) { let extras = JSON.parse(orderData.extra) if (!extras || !extras.layer_pay_token_id) { res.status(500) return res.send({ message: 'An unexpected error occured. No payment token exists' }) } let result = await openMoneyInstance.getPaymentStatus(extras.layer_pay_token_id) result = JSON.parse(result) result.ORDERID = req.body.ORDER_ID if (result.status == 'paid' || result.status == 'captured') { result.STATUS = 'TXN_SUCCESS' result.TXNID = result.id onStatusUpdate(result) } else if (result.status == 'pending' || result.status == 'attempted') { result.STATUS = 'TXN_PENDING' result.TXNID = result.id onStatusUpdate(result) } // else if (result.status == 'failed' || result.status == 'cancelled') { // result.STATUS = 'TXN_FAILED' // result.TXNID = result.id // onStatusUpdate(result) // } else { res.send(orderData); } } } else { res.send(orderData); } }, usingMultiDbOrm ? Transaction : undefined); } function getStatusFromPaytm(params, orderId, cb) { checksum_lib.genchecksum(params, config.KEY, function (err, checksum) { request.post( config.paytm_url + "/order/status", { json: { MID: config.MID, ORDERID: orderId, CHECKSUMHASH: checksum, } }, function (error, response, body) { if (!error && response.statusCode == 200) { var paytmResponse = JSON.parse(JSON.stringify(body)) cb(paytmResponse) } else { console.log('ERROR:::', error, '\n', response); cb({ message: "Error Occured !", ORDERID: orderId }) } } ); }); } return module; }