node-paytmpg 4.1.0 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +23 -9
- package/app/controllers/adapters/open_money.js +514 -0
- package/app/controllers/payment_controller.js +102 -17
- package/app/views/init.hbs +11 -1
- package/package.json +1 -1
- package/public/layer_checkout.js +38 -0
package/README.MD
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
## Node JS Payments Easy Integration
|
|
2
2
|
|
|
3
|
-
[](https://github.com/shiveshnavin/node_paytm/actions/workflows/npm-publish.yml)
|
|
4
4
|
[](https://github.com/shiveshnavin/node_paytm/actions/workflows/nodejs.yml)
|
|
5
5
|
|
|
6
6
|
Support for :
|
|
7
7
|
- Paytm
|
|
8
8
|
- RazorPay
|
|
9
|
+
- Open Money
|
|
9
10
|
|
|
10
11
|
Does all the hardwork for you while integrating payments in any express app. Comes with inbuilt UI and REST APIs for lightning fast development and prototyping .
|
|
11
12
|
|
|
@@ -22,7 +23,7 @@ Example App Sourcecode : https://github.com/shiveshnavin/payment-gateway-example
|
|
|
22
23
|
### Requirments
|
|
23
24
|
|
|
24
25
|
1. MongoDB / Firestore / SQlite
|
|
25
|
-
2. Your
|
|
26
|
+
2. Your Merchant Credentials
|
|
26
27
|
3. Express . This only works with NodeJS express server
|
|
27
28
|
|
|
28
29
|
You can get your paytm credentials here
|
|
@@ -78,8 +79,25 @@ homepage : Homepage of your website where user can go after payment confirmation
|
|
|
78
79
|
path_prefix : All node_paytm_pg apis/pages will be available relative to this path prefix
|
|
79
80
|
db_url : Your MongoDB url in case you want to use legacy mongodb connection . You can use multidborm to support MongoDB/Firestore/Sqlite
|
|
80
81
|
id_length: Length of Order ID and User ID
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### For Open Money
|
|
86
|
+
In case you want to use Open Money https://app.open.money/settings/developer-api/api . Use the below configuration
|
|
87
|
+
```
|
|
88
|
+
host_url : Host URL of your server . This will be used to redirect user after payment
|
|
89
|
+
view_path : Ignore and dont change unless you know what you are doing . This is the useful in case you want to modify payment init page UI from node_paytm_pg library
|
|
90
|
+
open_money_url : SANDBOX https://sandbox-icp-api.bankopen.co/api OR LIVE https://icp-api.bankopen.co/api
|
|
91
|
+
KEY : Your generated API Key
|
|
92
|
+
SECRET : Your API secret
|
|
93
|
+
homepage : Homepage of your website where user can go after payment confirmation page
|
|
94
|
+
path_prefix : All node_paytm_pg apis/pages will be available relative to this path prefix
|
|
95
|
+
db_url : Your MongoDB url in case you want to use legacy mongodb connection . You can use multidborm to support MongoDB/Firestore/Sqlite
|
|
96
|
+
id_length: Length of Order ID and User ID (Optional)
|
|
97
|
+
|
|
81
98
|
```
|
|
82
99
|
|
|
100
|
+
|
|
83
101
|
Place these 2 statements in your main nodejs file before calling app.listen(..)
|
|
84
102
|
|
|
85
103
|
```javascript
|
|
@@ -206,13 +224,6 @@ var User=PayTMPG.User;
|
|
|
206
224
|
|
|
207
225
|
Webhooks can issued at at `/_pay/api/webhook` and are useful for payments captured late.
|
|
208
226
|
|
|
209
|
-
If you are using `bodyparser` , make sure to remove these from your express app since the body parsers will be already added with the library .
|
|
210
|
-
```
|
|
211
|
-
Comment these if present in your app
|
|
212
|
-
app.use(bodyParser.json());
|
|
213
|
-
app.use(bodyParser.urlencoded({ extended: true }));
|
|
214
|
-
```
|
|
215
|
-
|
|
216
227
|
#### For razorpay webhook
|
|
217
228
|
Make sure to use the same secret in your webhook as the merchant secret.
|
|
218
229
|
https://razorpay.com/docs/webhooks/
|
|
@@ -221,6 +232,9 @@ https://razorpay.com/docs/webhooks/
|
|
|
221
232
|
Nothing extra needed
|
|
222
233
|
https://developer.paytm.com/docs/callback-and-webhook/?ref=callbackWebhook
|
|
223
234
|
|
|
235
|
+
#### For Open Money
|
|
236
|
+
Nothing extra needed
|
|
237
|
+
https://docs.bankopen.com/reference/webhook-url
|
|
224
238
|
|
|
225
239
|
|
|
226
240
|
License : GPL
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
const { resolve } = require('path');
|
|
3
|
+
var reqpost = require('request');
|
|
4
|
+
|
|
5
|
+
class OpenMoney {
|
|
6
|
+
config
|
|
7
|
+
constructor(npconfig) {
|
|
8
|
+
npconfig.accesskey = npconfig.KEY
|
|
9
|
+
npconfig.secretkey = npconfig.SECRET
|
|
10
|
+
npconfig.url = npconfig.open_money_url
|
|
11
|
+
npconfig.script_url = (npconfig.url.indexOf("sandbox") == -1) ? "https://payments.open.money/layer" : "https://sandbox-payments.open.money/layer"
|
|
12
|
+
this.config = npconfig;
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
generatePaymentToken(params) {
|
|
17
|
+
|
|
18
|
+
let config = this.config;
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
var payment_token_data;
|
|
21
|
+
let open_txn = {
|
|
22
|
+
"amount": params['TXN_AMOUNT'],
|
|
23
|
+
"currency": params['CURRENCY'] || "INR",
|
|
24
|
+
"name": params['NAME'],
|
|
25
|
+
"email_id": params['EMAIL'],
|
|
26
|
+
"contact_number": ("" + params['MOBILE_NO']).replace("+91", ""),
|
|
27
|
+
"mtx": params['ORDER_ID']
|
|
28
|
+
}
|
|
29
|
+
create_payment_token(open_txn,
|
|
30
|
+
config.accesskey,
|
|
31
|
+
config.secretkey,
|
|
32
|
+
config.url, function (layer_payment_token_data) {
|
|
33
|
+
/*Object.keys(layer_payment_token_data).forEach(function(key) {
|
|
34
|
+
console.log(key + layer_payment_token_data[key]);
|
|
35
|
+
});*/
|
|
36
|
+
|
|
37
|
+
if (typeof layer_payment_token_data['error'] != 'undefined')
|
|
38
|
+
return reject(JSON.stringify('E55 Payment error. ' + layer_payment_token_data['error']));
|
|
39
|
+
|
|
40
|
+
if (typeof layer_payment_token_data["id"] == 'undefined' || !layer_payment_token_data["id"])
|
|
41
|
+
return reject(JSON.stringify('Payment error. ' + 'Layer token ID cannot be empty.'));
|
|
42
|
+
|
|
43
|
+
if (typeof layer_payment_token_data["id"] != 'undefined') {
|
|
44
|
+
|
|
45
|
+
get_payment_token(layer_payment_token_data["id"], config.accesskey, config.secretkey, config.url, function (payment_token_data) {
|
|
46
|
+
|
|
47
|
+
if (payment_token_data.error) {
|
|
48
|
+
return reject({
|
|
49
|
+
error: payment_token_data.error
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
payment_token_data = JSON.parse(payment_token_data);
|
|
53
|
+
|
|
54
|
+
if (typeof payment_token_data['error'] != 'undefined')
|
|
55
|
+
return reject({ error: (JSON.stringify('E56 Payment error. ' + payment_token_data['error'])) })
|
|
56
|
+
if (typeof payment_token_data['status'] != 'undefined' && payment_token_data['status'] == "paid")
|
|
57
|
+
return reject({ error: (JSON.stringify("Layer: this order has already been paid.")) })
|
|
58
|
+
if (parseFloat(payment_token_data['amount']) != parseFloat(params['TXN_AMOUNT']))
|
|
59
|
+
return reject({ error: (JSON.stringify("Layer: an amount mismatch occurred.")) })
|
|
60
|
+
|
|
61
|
+
var hash = create_hash({
|
|
62
|
+
'layer_pay_token_id': payment_token_data['id'],
|
|
63
|
+
'layer_order_amount': payment_token_data['amount'],
|
|
64
|
+
'tranid': params['ORDER_ID'],
|
|
65
|
+
}, config.accesskey, config.secretkey);
|
|
66
|
+
params['CHECKSUM'] = hash;
|
|
67
|
+
|
|
68
|
+
var html = `<form action='${params['CALLBACK_URL']}' method='post' style='display: none' name='layer_payment_int_form'>`;
|
|
69
|
+
html += "<input type='hidden' name='layer_pay_token_id' value='" + payment_token_data['id'] + "'>";
|
|
70
|
+
html += "<input type='hidden' name='tranid' value='" + params['ORDER_ID'] + "'>";
|
|
71
|
+
html += "<input type='hidden' name='layer_order_amount' value='" + payment_token_data['amount'] + "'>";
|
|
72
|
+
html += "<input type='hidden' id='layer_payment_id' name='layer_payment_id' value=''>";
|
|
73
|
+
html += "<input type='hidden' id='fallback_url' name='fallback_url' value=''>";
|
|
74
|
+
html += "<input type='hidden' name='hash' value='" + hash + "'></form>";
|
|
75
|
+
html += "<script>";
|
|
76
|
+
html += "var layer_params = {payment_token_id:'" + payment_token_data['id'] + "',accesskey:'" + config.accesskey + "'};";
|
|
77
|
+
html += "</script>";
|
|
78
|
+
html += `<script src="layer_checkout.js"></script>`;
|
|
79
|
+
|
|
80
|
+
return resolve({
|
|
81
|
+
html: html,
|
|
82
|
+
params: params,
|
|
83
|
+
data: config,
|
|
84
|
+
tokenid: payment_token_data['id'],
|
|
85
|
+
amount: payment_token_data['amount'],
|
|
86
|
+
hash: hash
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
verifyResult(req) {
|
|
95
|
+
let config = this.config;
|
|
96
|
+
return new Promise((resolve, reje) => {
|
|
97
|
+
|
|
98
|
+
var txnid = "";
|
|
99
|
+
var amount = "";
|
|
100
|
+
var status = "";
|
|
101
|
+
var msg = "";
|
|
102
|
+
var tokenid = "";
|
|
103
|
+
var paymentid = "";
|
|
104
|
+
var payment_data = {};
|
|
105
|
+
|
|
106
|
+
if (!req.body.layer_payment_id) {
|
|
107
|
+
return resolve({
|
|
108
|
+
STATUS: 'TXN_FAILURE',
|
|
109
|
+
ORDERID: txnid,
|
|
110
|
+
TXNID: paymentid,
|
|
111
|
+
reason: 'invalid response'
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
txnid = req.body.tranid;
|
|
116
|
+
amount = req.body.layer_order_amount;
|
|
117
|
+
tokenid = req.body.layer_pay_token_id;
|
|
118
|
+
paymentid = req.body.layer_payment_id;
|
|
119
|
+
}
|
|
120
|
+
var data = {
|
|
121
|
+
'layer_pay_token_id': tokenid,
|
|
122
|
+
'layer_order_amount': amount,
|
|
123
|
+
'tranid': txnid,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (verify_hash(data, req.body.hash, config.accesskey, config.secretkey, config.url)) {
|
|
127
|
+
get_payment_details(paymentid, config.accesskey, config.secretkey, config.url, function (response) {
|
|
128
|
+
if (response === "{}") {
|
|
129
|
+
|
|
130
|
+
return resolve({
|
|
131
|
+
STATUS: 'TXN_FAILURE',
|
|
132
|
+
ORDERID: txnid,
|
|
133
|
+
TXNID: paymentid,
|
|
134
|
+
message: 'Invalid Response',
|
|
135
|
+
data: payment_data
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
payment_data = JSON.parse(response);
|
|
141
|
+
if (!payment_data['payment_token'] || payment_data['payment_token']['id'] != tokenid) {
|
|
142
|
+
return resolve({
|
|
143
|
+
STATUS: 'TXN_FAILURE',
|
|
144
|
+
ORDERID: txnid,
|
|
145
|
+
TXNID: paymentid,
|
|
146
|
+
message: 'received layer_pay_token_id and collected layer_pay_token_id doesnt match',
|
|
147
|
+
data: payment_data
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
let status = ""
|
|
152
|
+
if (payment_data.status == "captured" ||
|
|
153
|
+
payment_data.status == "late_authorized") {
|
|
154
|
+
status = 'TXN_SUCCESS'
|
|
155
|
+
}
|
|
156
|
+
else if (payment_data.status == "pending") {
|
|
157
|
+
status = 'TXN_PENDING'
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
status = 'TXN_FAILURE'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return resolve({
|
|
164
|
+
STATUS: status,
|
|
165
|
+
ORDERID: txnid,
|
|
166
|
+
TXNID: paymentid,
|
|
167
|
+
data: (payment_data)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
return resolve({
|
|
176
|
+
STATUS: 'TXN_FAILURE',
|
|
177
|
+
ORDERID: txnid,
|
|
178
|
+
TXNID: paymentid,
|
|
179
|
+
message: 'Invalid Response'
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
processWebhook(req, res, updateTransaction) {
|
|
186
|
+
let config = this.config;
|
|
187
|
+
let events = [
|
|
188
|
+
"payment_captured", "payment_pending",
|
|
189
|
+
"payment_failed",
|
|
190
|
+
"payment_cancelled"]
|
|
191
|
+
if (req.body.event && events.indexOf(req.body.event) > -1) {
|
|
192
|
+
if (req.body.payment_token) {
|
|
193
|
+
|
|
194
|
+
let payment_token = req.body.payment_token;
|
|
195
|
+
let orderId = payment_token.mtx
|
|
196
|
+
let paymentid = req.body.id
|
|
197
|
+
let tokenid = payment_token.id
|
|
198
|
+
let payment_data = {}
|
|
199
|
+
let amount = req.body.amount;
|
|
200
|
+
|
|
201
|
+
setTimeout(() => {
|
|
202
|
+
|
|
203
|
+
req.body.layer_pay_token_id = tokenid;
|
|
204
|
+
// var data = {
|
|
205
|
+
// 'layer_pay_token_id': tokenid,
|
|
206
|
+
// 'layer_order_amount': amount,
|
|
207
|
+
// 'tranid': orderId,
|
|
208
|
+
// };
|
|
209
|
+
|
|
210
|
+
// if (verify_hash(data, req.headers['x-webhook-signature'], config.accesskey, config.secretkey, config.url)) {
|
|
211
|
+
// console.log('TODO verify signature')
|
|
212
|
+
// }
|
|
213
|
+
get_payment_details(paymentid, config.accesskey, config.secretkey, config.url, function (response) {
|
|
214
|
+
if (response === "{}") {
|
|
215
|
+
req.body.STATUS = 'TXN_FAILURE';
|
|
216
|
+
req.body.ORDERID = orderId;
|
|
217
|
+
req.body.TXNID = paymentid;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
payment_data = JSON.parse(response);
|
|
221
|
+
if (!payment_data['payment_token'] || payment_data['payment_token']['id'] != tokenid) {
|
|
222
|
+
req.body.STATUS = 'TXN_FAILURE';
|
|
223
|
+
req.body.ORDERID = orderId;
|
|
224
|
+
req.body.TXNID = paymentid;
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
let status = "INITIATED"
|
|
228
|
+
if (payment_data.status == "captured" ||
|
|
229
|
+
payment_data.status == "late_authorized") {
|
|
230
|
+
status = 'TXN_SUCCESS'
|
|
231
|
+
}
|
|
232
|
+
else if (payment_data.status == "pending") {
|
|
233
|
+
status = 'TXN_PENDING'
|
|
234
|
+
}
|
|
235
|
+
// else {
|
|
236
|
+
// status = 'TXN_FAILURE'
|
|
237
|
+
// }
|
|
238
|
+
|
|
239
|
+
if (status != 'TXN_SUCCESS') {
|
|
240
|
+
if (req.body.status == "paid" || req.body.status == 'captured') {
|
|
241
|
+
status = 'TXN_SUCCESS'
|
|
242
|
+
}
|
|
243
|
+
// else if (req.body.status == 'failed') {
|
|
244
|
+
// status = 'TXN_FAILURE'
|
|
245
|
+
// }
|
|
246
|
+
else if (req.body.status == 'pending') {
|
|
247
|
+
status = 'TXN_PENDING'
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
console.log(`Open Money ${req.body.event} webhook for order=${payment_token.mtx} payid=${paymentid} status=${req.body.status} || ${status}`)
|
|
251
|
+
|
|
252
|
+
req.body.STATUS = status;
|
|
253
|
+
req.body.ORDERID = orderId;
|
|
254
|
+
req.body.TXNID = paymentid;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
}
|
|
258
|
+
updateTransaction(req, res)
|
|
259
|
+
|
|
260
|
+
});
|
|
261
|
+
}, 3000)
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
res.status(401)
|
|
265
|
+
res.send({ message: "Missing payment_token" })
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
res.status(201)
|
|
270
|
+
res.send({ message: "Webhook not supported" })
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
getPaymentStatus(paymentTokenId, cb) {
|
|
275
|
+
return new Promise((resolve, reject) => {
|
|
276
|
+
get_payment_token_details(paymentTokenId, this.config.accesskey, this.config.secretkey, this.config.url, (data) => {
|
|
277
|
+
resolve(data)
|
|
278
|
+
if (cb) {
|
|
279
|
+
cb(data)
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
renderProcessingPage(params, pmttoken, res) {
|
|
286
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
287
|
+
res.write(`<html><head><title>Merchant Checkout Page</title>
|
|
288
|
+
<script src="${this.config.script_url}"></script>
|
|
289
|
+
</head><body><center><h1>Processing ! Please do not refresh this page...</h1><br>${pmttoken.html}<br></center><script>triggerLayer();</script></body></html>`);
|
|
290
|
+
res.end();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
renderError(params, error, res) {
|
|
294
|
+
|
|
295
|
+
console.log('ERROR:::', error, '\n');
|
|
296
|
+
res.status(500)
|
|
297
|
+
var form_fields = "";
|
|
298
|
+
let errorResp = {
|
|
299
|
+
TXNID: "na",
|
|
300
|
+
STATUS: "TXN_FAILURE",
|
|
301
|
+
CANCELLED: "cancelled",
|
|
302
|
+
ORDERID: params["ORDER_ID"]
|
|
303
|
+
}
|
|
304
|
+
for (var x in errorResp) {
|
|
305
|
+
form_fields += "<input type='hidden' name='" + x + "' value='" + errorResp[x] + "' >";
|
|
306
|
+
}
|
|
307
|
+
form_fields += "<input type='hidden' name='CHECKSUMHASH' value='" + params["CHECKSUM"] + "' >";
|
|
308
|
+
|
|
309
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
310
|
+
res.write(`<html>
|
|
311
|
+
|
|
312
|
+
<head>
|
|
313
|
+
<title>Merchant Checkout Error</title>
|
|
314
|
+
</head>
|
|
315
|
+
|
|
316
|
+
<body>
|
|
317
|
+
<center>
|
|
318
|
+
<h1>Something went wrong. Please wait you will be redirected automatically...</h1>
|
|
319
|
+
</center>
|
|
320
|
+
<form method="post" action="${params['CALLBACK_URL']}" name="f1">${form_fields}</form>
|
|
321
|
+
<script type="text/javascript">document.f1.submit();</script>
|
|
322
|
+
</body>
|
|
323
|
+
|
|
324
|
+
</html>`);
|
|
325
|
+
res.end();
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
//Layer functions
|
|
335
|
+
function create_payment_token(data, accesskey, secretkey, baseurl, callback) {
|
|
336
|
+
try {
|
|
337
|
+
var pay_token_request_data = {
|
|
338
|
+
'amount': (data['amount']) ? data['amount'] : null,
|
|
339
|
+
'currency': (data['currency']) ? data['currency'] : null,
|
|
340
|
+
'name': (data['name']) ? data['name'] : null,
|
|
341
|
+
'email_id': (data['email_id']) ? data['email_id'] : null,
|
|
342
|
+
'contact_number': (data['contact_number']) ? data['contact_number'] : null,
|
|
343
|
+
'mtx': (data['mtx']) ? data['mtx'] : null,
|
|
344
|
+
'udf': (data['udf']) ? data['udf'] : null,
|
|
345
|
+
};
|
|
346
|
+
http_post(pay_token_request_data, "payment_token", accesskey, secretkey, baseurl, function (response) {
|
|
347
|
+
return callback(response);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
} catch (e) {
|
|
351
|
+
return callback({
|
|
352
|
+
'error': e
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function get_payment_token(payment_token_id, accesskey, secretkey, url, callback) {
|
|
358
|
+
if (!payment_token_id) {
|
|
359
|
+
throw new Error("payment_token_id cannot be empty");
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
http_get("payment_token/" + payment_token_id, accesskey, secretkey, url, function (response) {
|
|
364
|
+
return callback(response);
|
|
365
|
+
});
|
|
366
|
+
} catch (e) {
|
|
367
|
+
return callback({
|
|
368
|
+
'error': e
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function get_payment_token_details(payment_tokenid, accesskey, secretkey, baseurl, callback) {
|
|
374
|
+
|
|
375
|
+
if (!payment_tokenid) {
|
|
376
|
+
throw new Error("payment_id cannot be empty");
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
http_get("payment_token/" + payment_tokenid + '/payment', accesskey, secretkey, baseurl, function (response) {
|
|
380
|
+
return callback(response);
|
|
381
|
+
});
|
|
382
|
+
} catch (e) {
|
|
383
|
+
callback({
|
|
384
|
+
'error': e
|
|
385
|
+
})
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function get_payment_details(payment_id, accesskey, secretkey, baseurl, callback) {
|
|
390
|
+
|
|
391
|
+
if (!payment_id) {
|
|
392
|
+
throw new Error("payment_id cannot be empty");
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
http_get("payment/" + payment_id, accesskey, secretkey, baseurl, function (response) {
|
|
396
|
+
return callback(response);
|
|
397
|
+
});
|
|
398
|
+
} catch (e) {
|
|
399
|
+
callback({
|
|
400
|
+
'error': e
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function http_post(data, route, accesskey, secretkey, baseurl, callback) {
|
|
406
|
+
Object.keys(data).forEach(function (key) {
|
|
407
|
+
if (data[key] === null)
|
|
408
|
+
delete data[key];
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
var url = baseurl + "/" + route;
|
|
412
|
+
|
|
413
|
+
var options = {
|
|
414
|
+
method: 'POST',
|
|
415
|
+
uri: url,
|
|
416
|
+
json: true,
|
|
417
|
+
form: {
|
|
418
|
+
amount: data['amount'],
|
|
419
|
+
currency: data['currency'],
|
|
420
|
+
name: data['name'],
|
|
421
|
+
email_id: data['email_id'],
|
|
422
|
+
contact_number: data['contact_number'],
|
|
423
|
+
mtx: data['mtx']
|
|
424
|
+
},
|
|
425
|
+
headers: {
|
|
426
|
+
'Content-Type': 'application/json',
|
|
427
|
+
'Authorization': 'Bearer ' + accesskey + ':' + secretkey
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
reqpost(options)
|
|
432
|
+
.on('response', function (resp) {
|
|
433
|
+
//console.log('STATUS:'+resp.statusCode);
|
|
434
|
+
resp.setEncoding('utf8');
|
|
435
|
+
resp.on('data', function (chunk) {
|
|
436
|
+
var data = JSON.parse(chunk);
|
|
437
|
+
var rdata = "";
|
|
438
|
+
if ("error" in data) {
|
|
439
|
+
Object.keys(data).forEach(function (key) {
|
|
440
|
+
if (key == "error_data") {
|
|
441
|
+
var obj = data[key];
|
|
442
|
+
Object.keys(obj).forEach(function (k) {
|
|
443
|
+
rdata += obj[k] + ' ';
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
return callback({ "error": rdata });
|
|
448
|
+
}
|
|
449
|
+
else
|
|
450
|
+
return callback(data);
|
|
451
|
+
|
|
452
|
+
});
|
|
453
|
+
})
|
|
454
|
+
.on('error', function (err) {
|
|
455
|
+
return callback(err);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function http_get(route, accesskey, secretkey, baseurl, callback) {
|
|
460
|
+
|
|
461
|
+
var url = baseurl + "/" + route;
|
|
462
|
+
|
|
463
|
+
var options = {
|
|
464
|
+
method: 'GET',
|
|
465
|
+
uri: url,
|
|
466
|
+
headers: {
|
|
467
|
+
'Content-Type': 'application/json',
|
|
468
|
+
'Authorization': 'Bearer ' + accesskey + ':' + secretkey
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
reqpost(options)
|
|
473
|
+
.on('response', function (resp) {
|
|
474
|
+
resp.setEncoding('utf8');
|
|
475
|
+
resp.on('data', function (chunk) {
|
|
476
|
+
return callback(chunk);
|
|
477
|
+
});
|
|
478
|
+
})
|
|
479
|
+
.on('error', function (err) {
|
|
480
|
+
return callback(err);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function create_hash(data, accesskey, secretkey) {
|
|
485
|
+
data = ksort(data);
|
|
486
|
+
hash_string = accesskey;
|
|
487
|
+
Object.keys(data).forEach(function (key) {
|
|
488
|
+
hash_string += '|' + data[key];
|
|
489
|
+
});
|
|
490
|
+
var cryp = crypto.createHash('sha256', secretkey);
|
|
491
|
+
cryp.update(hash_string);
|
|
492
|
+
return cryp.digest('hex');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function verify_hash(data, rec_hash, accesskey, secretkey) {
|
|
496
|
+
var gen_hash = create_hash(data, accesskey, secretkey);
|
|
497
|
+
if (gen_hash === rec_hash) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function ksort(obj) {
|
|
504
|
+
var keys = Object.keys(obj).sort(), sortedObj = {};
|
|
505
|
+
|
|
506
|
+
for (var i in keys) {
|
|
507
|
+
sortedObj[keys[i]] = obj[keys[i]];
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return sortedObj;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
module.exports = OpenMoney;
|
|
@@ -5,8 +5,10 @@ var Transaction;
|
|
|
5
5
|
var IDLEN = 10;
|
|
6
6
|
var nodeBase64 = require('nodejs-base64-converter');
|
|
7
7
|
var RazorPay = require('razorpay');
|
|
8
|
+
var OpenMoney = require('./adapters/open_money')
|
|
8
9
|
const PaytmChecksum = require('./checksum/PaytmChecksum.js');
|
|
9
10
|
const { stat } = require('fs');
|
|
11
|
+
const { config } = require('process');
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
function sanitizeRequest(body) {
|
|
@@ -21,8 +23,14 @@ module.exports = function (app, callbacks) {
|
|
|
21
23
|
var config = (app.get('np_config'))
|
|
22
24
|
var useController = require('./np_user.controller.js')(app, callbacks);
|
|
23
25
|
|
|
26
|
+
var razorPayInstance;
|
|
27
|
+
var openMoneyInstance = new OpenMoney(config);
|
|
28
|
+
|
|
24
29
|
if (config.razor_url)
|
|
25
|
-
|
|
30
|
+
razorPayInstance = new RazorPay({ key_id: config.KEY, key_secret: config.SECRET })
|
|
31
|
+
if (config.open_money_url) {
|
|
32
|
+
openMoneyInstance = new OpenMoney(config);
|
|
33
|
+
}
|
|
26
34
|
|
|
27
35
|
let usingMultiDbOrm = false;
|
|
28
36
|
if (config.db_url) {
|
|
@@ -358,8 +366,6 @@ module.exports = function (app, callbacks) {
|
|
|
358
366
|
}
|
|
359
367
|
else if (config.razor_url) {
|
|
360
368
|
|
|
361
|
-
|
|
362
|
-
|
|
363
369
|
let fail = `<div style="display:none">
|
|
364
370
|
|
|
365
371
|
<form method="post" action="${params['CALLBACK_URL']}" id="fail">
|
|
@@ -402,6 +408,29 @@ module.exports = function (app, callbacks) {
|
|
|
402
408
|
res.end();
|
|
403
409
|
|
|
404
410
|
}
|
|
411
|
+
else if (config.open_money_url) {
|
|
412
|
+
try {
|
|
413
|
+
let pmttoken = await openMoneyInstance.generatePaymentToken(params);
|
|
414
|
+
openMoneyInstance.renderProcessingPage(params, pmttoken, res);
|
|
415
|
+
|
|
416
|
+
var myquery = { orderId: params['ORDER_ID'] };
|
|
417
|
+
Transaction.findOne(myquery, function (err, objForUpdate) {
|
|
418
|
+
|
|
419
|
+
objForUpdate.extra = JSON.stringify({
|
|
420
|
+
layer_pay_token_id: pmttoken.tokenid
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
var newvalues = { $set: objForUpdate };
|
|
424
|
+
Transaction.updateOne(myquery, newvalues, function (err, saveRes) {
|
|
425
|
+
let status = 'Updated TXNID'
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
}, usingMultiDbOrm ? Transaction : undefined)
|
|
429
|
+
|
|
430
|
+
} catch (e) {
|
|
431
|
+
openMoneyInstance.renderError(params, e, res)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
405
434
|
if (callbacks !== undefined)
|
|
406
435
|
callbacks.onStart(params['ORDER_ID'], params);
|
|
407
436
|
}
|
|
@@ -460,6 +489,8 @@ module.exports = function (app, callbacks) {
|
|
|
460
489
|
checksum_lib.genchecksum(params, config.KEY, showConfirmation);
|
|
461
490
|
else if (config.razor_url) {
|
|
462
491
|
showConfirmation()
|
|
492
|
+
} else if (config.open_money_url) {
|
|
493
|
+
showConfirmation()
|
|
463
494
|
}
|
|
464
495
|
|
|
465
496
|
};
|
|
@@ -470,9 +501,9 @@ module.exports = function (app, callbacks) {
|
|
|
470
501
|
|
|
471
502
|
|
|
472
503
|
var myquery = { orderId: req.body.ORDER_ID };
|
|
473
|
-
Transaction.findOne(myquery, function (err,
|
|
504
|
+
Transaction.findOne(myquery, function (err, orderData) {
|
|
474
505
|
|
|
475
|
-
onTxn(
|
|
506
|
+
onTxn(orderData);
|
|
476
507
|
|
|
477
508
|
}, usingMultiDbOrm ? Transaction : undefined);
|
|
478
509
|
|
|
@@ -532,6 +563,10 @@ module.exports = function (app, callbacks) {
|
|
|
532
563
|
onOrder(orderId)
|
|
533
564
|
})
|
|
534
565
|
}
|
|
566
|
+
else if (config.open_money_url) {
|
|
567
|
+
orderId = "pay_" + makeid(config.id_length || IDLEN)
|
|
568
|
+
onOrder(orderId)
|
|
569
|
+
}
|
|
535
570
|
|
|
536
571
|
|
|
537
572
|
|
|
@@ -585,7 +620,11 @@ module.exports = function (app, callbacks) {
|
|
|
585
620
|
return;
|
|
586
621
|
}
|
|
587
622
|
if (objForUpdate.status != ("INITIATED") && objForUpdate.status != ("TXN_PENDING")) {
|
|
588
|
-
|
|
623
|
+
objForUpdate.readonly = "readonly"
|
|
624
|
+
objForUpdate.action = config.homepage
|
|
625
|
+
res.render(vp + "result.hbs", objForUpdate);
|
|
626
|
+
console.log("Transaction already processed ", req.body.ORDERID)
|
|
627
|
+
// res.send({ message: "Transaction already processed", status: objForUpdate.status, ORDERID: objForUpdate.orderId, TXNID: objForUpdate.TXNID, TXNID: req.body.TXNID })
|
|
589
628
|
return;
|
|
590
629
|
}
|
|
591
630
|
if (req.body.status == "paid" && !req.body.STATUS) {
|
|
@@ -614,7 +653,7 @@ module.exports = function (app, callbacks) {
|
|
|
614
653
|
}, usingMultiDbOrm ? Transaction : undefined)
|
|
615
654
|
}
|
|
616
655
|
|
|
617
|
-
module.callback = (req, res) => {
|
|
656
|
+
module.callback = async (req, res) => {
|
|
618
657
|
|
|
619
658
|
var result = false;
|
|
620
659
|
let isCancelled = false;
|
|
@@ -649,6 +688,15 @@ module.exports = function (app, callbacks) {
|
|
|
649
688
|
isCancelled = true;
|
|
650
689
|
}
|
|
651
690
|
}
|
|
691
|
+
else if (config.open_money_url) {
|
|
692
|
+
let openRest = await openMoneyInstance.verifyResult(req);
|
|
693
|
+
result = true;
|
|
694
|
+
req.body.STATUS = openRest.STATUS
|
|
695
|
+
req.body.TXNID = openRest.TXNID
|
|
696
|
+
req.body.ORDERID = openRest.ORDERID || req.query.order_id
|
|
697
|
+
req.body.extras = openRest.data
|
|
698
|
+
}
|
|
699
|
+
|
|
652
700
|
|
|
653
701
|
//console.log("Checksum Result => ", result, "\n");
|
|
654
702
|
console.log("NodePayTMPG::Transaction => ", req.body.ORDERID, req.body.STATUS);
|
|
@@ -689,7 +737,7 @@ module.exports = function (app, callbacks) {
|
|
|
689
737
|
|
|
690
738
|
result = RazorPay.validateWebhookSignature(reqBody, req.headers['x-razorpay-signature'], config.SECRET)
|
|
691
739
|
req.signatureVerified = result;
|
|
692
|
-
if (
|
|
740
|
+
if (result) {
|
|
693
741
|
if (event == events[0]) {
|
|
694
742
|
req.body.STATUS = "TXN_SUCCESS";
|
|
695
743
|
}
|
|
@@ -720,6 +768,9 @@ module.exports = function (app, callbacks) {
|
|
|
720
768
|
res.send({ message: "Unsupported event : " + req.body.event })
|
|
721
769
|
}
|
|
722
770
|
}
|
|
771
|
+
else if (config.open_money_url) {
|
|
772
|
+
openMoneyInstance.processWebhook(req, res, updateTransaction)
|
|
773
|
+
}
|
|
723
774
|
}
|
|
724
775
|
|
|
725
776
|
module.createTxn = (req, res) => {
|
|
@@ -743,6 +794,9 @@ module.exports = function (app, callbacks) {
|
|
|
743
794
|
let order = await razorPayInstance.orders.create(options);
|
|
744
795
|
id = order.id;
|
|
745
796
|
}
|
|
797
|
+
else if(config.open_money_url){
|
|
798
|
+
id = "pay_" + makeid(config.id_length || IDLEN)
|
|
799
|
+
}
|
|
746
800
|
|
|
747
801
|
var txnTask = new Transaction({
|
|
748
802
|
id: id,
|
|
@@ -788,15 +842,18 @@ module.exports = function (app, callbacks) {
|
|
|
788
842
|
|
|
789
843
|
module.status = (req, res) => {
|
|
790
844
|
|
|
845
|
+
if (!req.body.ORDER_ID && req.query.ORDER_ID) {
|
|
846
|
+
req.body.ORDER_ID = req.query.ORDER_ID
|
|
847
|
+
}
|
|
791
848
|
var myquery = { orderId: req.body.ORDER_ID };
|
|
792
|
-
Transaction.findOne(myquery, async function (err,
|
|
849
|
+
Transaction.findOne(myquery, async function (err, orderData) {
|
|
793
850
|
|
|
794
851
|
|
|
795
852
|
if (err) {
|
|
796
853
|
res.send(err)
|
|
797
854
|
return
|
|
798
855
|
}
|
|
799
|
-
if (
|
|
856
|
+
if (orderData.status === "INITIATED") {
|
|
800
857
|
|
|
801
858
|
var params = {}
|
|
802
859
|
params["MID"] = config.MID;
|
|
@@ -804,10 +861,10 @@ module.exports = function (app, callbacks) {
|
|
|
804
861
|
|
|
805
862
|
async function onStatusUpdate(paytmResponse) {
|
|
806
863
|
if (paytmResponse.TXNID.length > 4) {
|
|
807
|
-
|
|
808
|
-
|
|
864
|
+
orderData.status = paytmResponse.STATUS;
|
|
865
|
+
orderData.extra = JSON.stringify(paytmResponse);
|
|
809
866
|
|
|
810
|
-
var newvalues = { $set:
|
|
867
|
+
var newvalues = { $set: orderData };
|
|
811
868
|
Transaction.updateOne(myquery, newvalues, function (err, saveRes) {
|
|
812
869
|
|
|
813
870
|
if (err) {
|
|
@@ -815,13 +872,13 @@ module.exports = function (app, callbacks) {
|
|
|
815
872
|
}
|
|
816
873
|
else {
|
|
817
874
|
if (callbacks !== undefined)
|
|
818
|
-
callbacks.onFinish(req.body.ORDER_ID,
|
|
875
|
+
callbacks.onFinish(req.body.ORDER_ID, orderData);
|
|
819
876
|
res.send(paytmResponse)
|
|
820
877
|
}
|
|
821
878
|
});
|
|
822
879
|
}
|
|
823
880
|
else {
|
|
824
|
-
res.send(
|
|
881
|
+
res.send(orderData)
|
|
825
882
|
|
|
826
883
|
}
|
|
827
884
|
}
|
|
@@ -864,13 +921,41 @@ module.exports = function (app, callbacks) {
|
|
|
864
921
|
onStatusUpdate(result)
|
|
865
922
|
}
|
|
866
923
|
else {
|
|
867
|
-
res.send(
|
|
924
|
+
res.send(orderData);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
else if (config.open_money_url) {
|
|
928
|
+
let extras = JSON.parse(orderData.extra)
|
|
929
|
+
if (!extras || !extras.layer_pay_token_id) {
|
|
930
|
+
res.status(500)
|
|
931
|
+
return res.send({ message: 'An unexpected error occured. No payment token exists' })
|
|
932
|
+
}
|
|
933
|
+
let result = await openMoneyInstance.getPaymentStatus(extras.layer_pay_token_id)
|
|
934
|
+
result = JSON.parse(result)
|
|
935
|
+
result.ORDERID = req.body.ORDER_ID
|
|
936
|
+
if (result.status == 'paid' || result.status == 'captured') {
|
|
937
|
+
result.STATUS = 'TXN_SUCCESS'
|
|
938
|
+
result.TXNID = result.id
|
|
939
|
+
onStatusUpdate(result)
|
|
940
|
+
}
|
|
941
|
+
else if (result.status == 'pending' || result.status == 'attempted') {
|
|
942
|
+
result.STATUS = 'TXN_PENDING'
|
|
943
|
+
result.TXNID = result.id
|
|
944
|
+
onStatusUpdate(result)
|
|
945
|
+
}
|
|
946
|
+
// else if (result.status == 'failed' || result.status == 'cancelled') {
|
|
947
|
+
// result.STATUS = 'TXN_FAILED'
|
|
948
|
+
// result.TXNID = result.id
|
|
949
|
+
// onStatusUpdate(result)
|
|
950
|
+
// }
|
|
951
|
+
else {
|
|
952
|
+
res.send(orderData);
|
|
868
953
|
}
|
|
869
954
|
}
|
|
870
955
|
|
|
871
956
|
}
|
|
872
957
|
else {
|
|
873
|
-
res.send(
|
|
958
|
+
res.send(orderData);
|
|
874
959
|
}
|
|
875
960
|
|
|
876
961
|
|
package/app/views/init.hbs
CHANGED
|
@@ -60,8 +60,18 @@
|
|
|
60
60
|
{{/if}}
|
|
61
61
|
|
|
62
62
|
<li>
|
|
63
|
-
<button type="submit" class="button">{{BUTTON}}</button>
|
|
63
|
+
<button id="show_button" type="submit" class="button">{{BUTTON}}</button>
|
|
64
64
|
</li>
|
|
65
|
+
|
|
66
|
+
<script>
|
|
67
|
+
var button = document.getElementById('show_button')
|
|
68
|
+
button.addEventListener('click',hideshow,false);
|
|
69
|
+
|
|
70
|
+
function hideshow() {
|
|
71
|
+
document.getElementById('show_button').style.display = 'none';
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
|
|
65
75
|
</ul>
|
|
66
76
|
|
|
67
77
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function triggerLayer() {
|
|
2
|
+
|
|
3
|
+
Layer.checkout(
|
|
4
|
+
{
|
|
5
|
+
token: layer_params.payment_token_id,
|
|
6
|
+
accesskey: layer_params.accesskey,
|
|
7
|
+
},
|
|
8
|
+
function (response) {
|
|
9
|
+
console.log(response)
|
|
10
|
+
if(response !== null || response.length > 0 ){
|
|
11
|
+
|
|
12
|
+
if(response.payment_id !== undefined){
|
|
13
|
+
|
|
14
|
+
document.getElementById('layer_payment_id').value = response.payment_id;
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
document.layer_payment_int_form.submit();
|
|
21
|
+
},
|
|
22
|
+
function (err) {
|
|
23
|
+
alert(err.message);
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
/*
|
|
28
|
+
var checkExist = setInterval(function() {
|
|
29
|
+
if (typeof Layer !== 'undefined') {
|
|
30
|
+
console.log('Layer Loaded...');
|
|
31
|
+
clearInterval(checkExist);
|
|
32
|
+
triggerLayer();
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log('Layer undefined...');
|
|
36
|
+
}
|
|
37
|
+
}, 1000);
|
|
38
|
+
*/
|