node-paytmpg 6.4.7 → 7.1.1
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 +132 -182
- package/app/views/layouts/index.hbs +7 -7
- package/app/views/result.hbs +1 -1
- package/dist/app/controllers/adapters/open_money.js +400 -0
- package/dist/app/controllers/adapters/paytm.js +34 -0
- package/{app → dist/app}/controllers/adapters/payu.js +208 -239
- package/dist/app/controllers/checksum/PaytmChecksum.js +118 -0
- package/dist/app/controllers/checksum/checksum.js +158 -0
- package/dist/app/controllers/checksum/crypt.js +117 -0
- package/dist/app/controllers/checksum/server.js +130 -0
- package/dist/app/controllers/payment.controller.js +1089 -0
- package/dist/app/controllers/static/loadingsvg.js +54 -0
- package/dist/app/controllers/user.controller.js +53 -0
- package/dist/app/models/index.js +2 -0
- package/dist/app/routes/payment_route.js +46 -0
- package/dist/app/utils/buildConfig.js +210 -0
- package/dist/app/utils/utils.js +20 -0
- package/dist/app/views/home.hbs +22 -0
- package/dist/app/views/init.hbs +98 -0
- package/dist/app/views/layouts/index.hbs +53 -0
- package/dist/app/views/result.hbs +33 -0
- package/dist/index.js +119 -0
- package/dist/package.json +67 -0
- package/dist/public/css/style.css +455 -0
- package/dist/public/js/index.js +283 -0
- package/dist/public/layer_checkout.js +38 -0
- package/dist/public/pay.png +0 -0
- package/dist/public/start.png +0 -0
- package/dist/public/start2.png +0 -0
- package/dist/public/stat.png +0 -0
- package/dist/public/test.html +24 -0
- package/dist/public/test.html~ +24 -0
- package/package.json +29 -6
- package/public/test.html~ +24 -0
- package/.github/workflows/codeql-analysis.yml +0 -71
- package/.github/workflows/nodejs.yml +0 -24
- package/.github/workflows/npm-publish.yml +0 -23
- package/Dockerfile +0 -9
- package/app/controllers/adapters/open_money.js +0 -515
- package/app/controllers/checksum/PaytmChecksum.js +0 -94
- package/app/controllers/checksum/checksum.js +0 -154
- package/app/controllers/checksum/crypt.js +0 -98
- package/app/controllers/checksum/server.js +0 -132
- package/app/controllers/np_user.controller.js +0 -89
- package/app/controllers/payment_controller.js +0 -1295
- package/app/models/np_multidbplugin.js +0 -111
- package/app/models/np_transaction.model.js +0 -16
- package/app/models/np_user.model.js +0 -12
- package/app/routes/payment_route.js +0 -73
- package/app.yaml +0 -18
- package/example.js +0 -34
- package/index.js +0 -90
- package/lib/config/buildConfig.js +0 -113
- package/lib/config/defaults.js +0 -37
- package/lib/config/validator.js +0 -103
- package/lib/services/database.service.js +0 -153
- package/lib/utils/id-generator.js +0 -30
- package/lib/utils/sanitizer.js +0 -25
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoadingSVG = void 0;
|
|
4
|
+
exports.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">
|
|
5
|
+
<g transform="rotate(0 50 50)">
|
|
6
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
7
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate>
|
|
8
|
+
</rect>
|
|
9
|
+
</g><g transform="rotate(30 50 50)">
|
|
10
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
11
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate>
|
|
12
|
+
</rect>
|
|
13
|
+
</g><g transform="rotate(60 50 50)">
|
|
14
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
15
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate>
|
|
16
|
+
</rect>
|
|
17
|
+
</g><g transform="rotate(90 50 50)">
|
|
18
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
19
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"></animate>
|
|
20
|
+
</rect>
|
|
21
|
+
</g><g transform="rotate(120 50 50)">
|
|
22
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
23
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"></animate>
|
|
24
|
+
</rect>
|
|
25
|
+
</g><g transform="rotate(150 50 50)">
|
|
26
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
27
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"></animate>
|
|
28
|
+
</rect>
|
|
29
|
+
</g><g transform="rotate(180 50 50)">
|
|
30
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
31
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"></animate>
|
|
32
|
+
</rect>
|
|
33
|
+
</g><g transform="rotate(210 50 50)">
|
|
34
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
35
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"></animate>
|
|
36
|
+
</rect>
|
|
37
|
+
</g><g transform="rotate(240 50 50)">
|
|
38
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
39
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"></animate>
|
|
40
|
+
</rect>
|
|
41
|
+
</g><g transform="rotate(270 50 50)">
|
|
42
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
43
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"></animate>
|
|
44
|
+
</rect>
|
|
45
|
+
</g><g transform="rotate(300 50 50)">
|
|
46
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
47
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"></animate>
|
|
48
|
+
</rect>
|
|
49
|
+
</g><g transform="rotate(330 50 50)">
|
|
50
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#0097a7">
|
|
51
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animate>
|
|
52
|
+
</rect>
|
|
53
|
+
</g>
|
|
54
|
+
</svg>`;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NPUserController = void 0;
|
|
4
|
+
const utils_1 = require("../utils/utils");
|
|
5
|
+
class NPUserController {
|
|
6
|
+
constructor(db, tableName = 'npusers') {
|
|
7
|
+
this.db = db;
|
|
8
|
+
this.tableName = tableName;
|
|
9
|
+
}
|
|
10
|
+
async init() {
|
|
11
|
+
const sample = {
|
|
12
|
+
id: "user_aB3dE9xY1Z",
|
|
13
|
+
name: "tset",
|
|
14
|
+
email: "testgmailcom",
|
|
15
|
+
phone: "12345678",
|
|
16
|
+
};
|
|
17
|
+
this.db.create(this.tableName, sample);
|
|
18
|
+
}
|
|
19
|
+
async create(userData) {
|
|
20
|
+
try {
|
|
21
|
+
let user = await this.db.getOne(this.tableName, { email: userData.email });
|
|
22
|
+
if (user) {
|
|
23
|
+
const myquery = { email: userData.email };
|
|
24
|
+
const objForUpdate = Object.assign({}, user);
|
|
25
|
+
if (userData.email && userData.email.indexOf("@") !== -1)
|
|
26
|
+
objForUpdate.email = userData.email;
|
|
27
|
+
if (userData.phone && userData.phone.length > 2)
|
|
28
|
+
objForUpdate.phone = userData.phone;
|
|
29
|
+
if (userData.name && userData.name.length > 2)
|
|
30
|
+
objForUpdate.name = userData.name;
|
|
31
|
+
const newvalues = { $set: objForUpdate };
|
|
32
|
+
try {
|
|
33
|
+
await this.db.update(this.tableName, myquery, newvalues);
|
|
34
|
+
return objForUpdate;
|
|
35
|
+
}
|
|
36
|
+
catch (uErr) {
|
|
37
|
+
throw new Error(uErr.message || 'Some error occurred while updating users.');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
userData.id = "user_" + utils_1.Utils.makeid();
|
|
42
|
+
await this.db.insert(this.tableName, userData);
|
|
43
|
+
return userData;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
throw new Error(err.message || 'Some error occurred while creating users.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
;
|
|
51
|
+
}
|
|
52
|
+
exports.NPUserController = NPUserController;
|
|
53
|
+
;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const body_parser_1 = __importDefault(require("body-parser"));
|
|
7
|
+
const express_handlebars_1 = __importDefault(require("express-handlebars"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const payment_controller_1 = require("../controllers/payment.controller");
|
|
10
|
+
const paymentRoute = function (app, express, callbacks) {
|
|
11
|
+
const config = app.get('np_config');
|
|
12
|
+
const pc = new payment_controller_1.PaymentController(app, callbacks);
|
|
13
|
+
const router = express.Router();
|
|
14
|
+
app.set('view_path', __dirname + config.view_path);
|
|
15
|
+
const vp = app.get('view_path');
|
|
16
|
+
console.log('PaytmPG : Using MultiDB ORM');
|
|
17
|
+
app.engine('hbs', (0, express_handlebars_1.default)({
|
|
18
|
+
extname: 'hbs',
|
|
19
|
+
defaultLayout: vp + '/layouts/index.hbs',
|
|
20
|
+
helpers: {
|
|
21
|
+
theme_color: function () {
|
|
22
|
+
return config.theme_color;
|
|
23
|
+
},
|
|
24
|
+
logo: function () {
|
|
25
|
+
return config.logo;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
app.set('view engine', 'handlebars');
|
|
30
|
+
let saveRawBody = function (req, res, buf, encoding) {
|
|
31
|
+
req.rawBody = buf.toString();
|
|
32
|
+
};
|
|
33
|
+
app.use(body_parser_1.default.urlencoded({ extended: true }));
|
|
34
|
+
app.use(body_parser_1.default.json({ verify: saveRawBody }));
|
|
35
|
+
app.use('/' + config.path_prefix, express.static(path_1.default.join(__dirname, '../../public')));
|
|
36
|
+
app.use('/' + config.path_prefix, router);
|
|
37
|
+
router.all('/', pc.init);
|
|
38
|
+
router.all('/init', pc.init);
|
|
39
|
+
router.all('/callback', pc.callback);
|
|
40
|
+
router.all('/api/webhook', pc.webhook);
|
|
41
|
+
router.all('/api/status', pc.status);
|
|
42
|
+
router.all('/api/createTxn/token', pc.createTxnToken);
|
|
43
|
+
router.all('/api/createTxn', pc.createTxn);
|
|
44
|
+
return router;
|
|
45
|
+
};
|
|
46
|
+
exports.default = paymentRoute;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildConfig = buildConfig;
|
|
4
|
+
const defaults = {
|
|
5
|
+
// Server configuration
|
|
6
|
+
host_url: 'http://localhost:3000',
|
|
7
|
+
path_prefix: '_pay',
|
|
8
|
+
homepage: '/',
|
|
9
|
+
// Template configuration
|
|
10
|
+
templateDir: null, // null = use built-in views, or provide path to custom templates
|
|
11
|
+
templateEngine: 'handlebars',
|
|
12
|
+
// UI Customization
|
|
13
|
+
theme_color: '#3399cc',
|
|
14
|
+
logo: '/favicon.ico',
|
|
15
|
+
// Transaction ID configuration
|
|
16
|
+
id_length: 10,
|
|
17
|
+
// Database
|
|
18
|
+
db_url: null, // MongoDB URL (legacy), leave null to use multidborm
|
|
19
|
+
// Payment Gateway URLs
|
|
20
|
+
// paytm_url: null, // e.g., 'https://securegw-stage.paytm.in' for test, 'https://securegw.paytm.in' for production
|
|
21
|
+
// razor_url: null, // e.g., 'https://api.razorpay.com/v1/'
|
|
22
|
+
// payu_url: null, // e.g., 'https://test.payu.in' for test, 'https://secure.payu.in' for production
|
|
23
|
+
// open_money_url: null, // e.g., 'https://sandbox-icp-api.bankopen.co/api' for sandbox, 'https://icp-api.bankopen.co/api' for live
|
|
24
|
+
// Gateway Credentials (must be provided by user)
|
|
25
|
+
// MID: null,
|
|
26
|
+
// WEBSITE: null,
|
|
27
|
+
// KEY: null,
|
|
28
|
+
// SECRET: null,
|
|
29
|
+
// CHANNEL_ID: 'WEB',
|
|
30
|
+
// INDUSTRY_TYPE_ID: 'Retail',
|
|
31
|
+
// Payment mode configuration (optional)
|
|
32
|
+
// mode: null // JSON string of enabled payment modes for Paytm
|
|
33
|
+
};
|
|
34
|
+
function pickEnv(keys) {
|
|
35
|
+
const output = {};
|
|
36
|
+
keys.forEach((key) => {
|
|
37
|
+
if (process.env[key] !== undefined) {
|
|
38
|
+
output[key] = process.env[key];
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return output;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validates and merges config with defaults
|
|
45
|
+
* @param {Object} userConfig - User-provided configuration
|
|
46
|
+
* @returns {Object} Merged and validated configuration
|
|
47
|
+
* @throws {Error} If required fields are missing
|
|
48
|
+
*/
|
|
49
|
+
function validateConfig(userConfig) {
|
|
50
|
+
if (!userConfig || typeof userConfig !== 'object') {
|
|
51
|
+
throw new Error('Config must be an object');
|
|
52
|
+
}
|
|
53
|
+
// Merge with defaults
|
|
54
|
+
const config = { ...defaults, ...userConfig };
|
|
55
|
+
// Detect which payment gateway is being used
|
|
56
|
+
const hasPaytm = !!config.paytm_url;
|
|
57
|
+
const hasRazorpay = !!config.razor_url;
|
|
58
|
+
const hasPayU = !!config.payu_url;
|
|
59
|
+
const hasOpenMoney = !!config.open_money_url;
|
|
60
|
+
if (!hasPaytm && !hasRazorpay && !hasPayU && !hasOpenMoney) {
|
|
61
|
+
throw new Error('At least one payment gateway must be configured. ' +
|
|
62
|
+
'Please provide one of: paytm_url, razor_url, payu_url, or open_money_url');
|
|
63
|
+
}
|
|
64
|
+
// Validate required credentials based on gateway
|
|
65
|
+
if (hasPaytm) {
|
|
66
|
+
validatePaytmConfig(config);
|
|
67
|
+
}
|
|
68
|
+
if (hasRazorpay) {
|
|
69
|
+
validateRazorpayConfig(config);
|
|
70
|
+
}
|
|
71
|
+
if (hasPayU) {
|
|
72
|
+
validatePayUConfig(config);
|
|
73
|
+
}
|
|
74
|
+
if (hasOpenMoney) {
|
|
75
|
+
validateOpenMoneyConfig(config);
|
|
76
|
+
}
|
|
77
|
+
// Validate common fields
|
|
78
|
+
if (!config.host_url) {
|
|
79
|
+
throw new Error('host_url is required');
|
|
80
|
+
}
|
|
81
|
+
if (!config.path_prefix) {
|
|
82
|
+
throw new Error('path_prefix is required');
|
|
83
|
+
}
|
|
84
|
+
return config;
|
|
85
|
+
}
|
|
86
|
+
function validatePaytmConfig(config) {
|
|
87
|
+
const required = ['MID', 'WEBSITE', 'KEY', 'CHANNEL_ID', 'INDUSTRY_TYPE_ID'];
|
|
88
|
+
const missing = required.filter(field => !config[field]);
|
|
89
|
+
if (missing.length > 0) {
|
|
90
|
+
throw new Error(`Paytm configuration incomplete. Missing fields: ${missing.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function validateRazorpayConfig(config) {
|
|
94
|
+
const required = ['KEY', 'SECRET'];
|
|
95
|
+
const missing = required.filter(field => !config[field]);
|
|
96
|
+
if (missing.length > 0) {
|
|
97
|
+
throw new Error(`Razorpay configuration incomplete. Missing fields: ${missing.join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function validatePayUConfig(config) {
|
|
101
|
+
const required = ['KEY', 'SECRET'];
|
|
102
|
+
const missing = required.filter(field => !config[field]);
|
|
103
|
+
if (missing.length > 0) {
|
|
104
|
+
throw new Error(`PayU configuration incomplete. Missing fields: ${missing.join(', ')}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function validateOpenMoneyConfig(config) {
|
|
108
|
+
const required = ['KEY', 'SECRET'];
|
|
109
|
+
const missing = required.filter(field => !config[field]);
|
|
110
|
+
if (missing.length > 0) {
|
|
111
|
+
throw new Error(`OpenMoney configuration incomplete. Missing fields: ${missing.join(', ')}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function buildConfig(userConfig = {}) {
|
|
115
|
+
var _a, _b, _c, _d, _e, _f;
|
|
116
|
+
const envOverrides = pickEnv([
|
|
117
|
+
'NP_HOST_URL',
|
|
118
|
+
'NP_PATH_PREFIX',
|
|
119
|
+
'NP_HOMEPAGE',
|
|
120
|
+
'NP_TEMPLATE_DIR',
|
|
121
|
+
'NP_THEME_COLOR',
|
|
122
|
+
'NP_LOGO',
|
|
123
|
+
'NP_DB_URL',
|
|
124
|
+
'NP_PAYTM_URL',
|
|
125
|
+
'NP_RAZOR_URL',
|
|
126
|
+
'NP_PAYU_URL',
|
|
127
|
+
'NP_OPEN_MONEY_URL',
|
|
128
|
+
'NP_MID',
|
|
129
|
+
'NP_WEBSITE',
|
|
130
|
+
'NP_KEY',
|
|
131
|
+
'NP_SECRET',
|
|
132
|
+
'NP_CHANNEL_ID',
|
|
133
|
+
'NP_INDUSTRY_TYPE_ID',
|
|
134
|
+
'NP_MODE',
|
|
135
|
+
'NP_THEME_NAME',
|
|
136
|
+
]);
|
|
137
|
+
const merged = {
|
|
138
|
+
...defaults,
|
|
139
|
+
...normalizeEnv(envOverrides),
|
|
140
|
+
...userConfig,
|
|
141
|
+
};
|
|
142
|
+
// theme normalization
|
|
143
|
+
const themeName = (userConfig.themeName || ((_a = userConfig.theme) === null || _a === void 0 ? void 0 : _a.name) || merged.theme_name || 'dark').toLowerCase();
|
|
144
|
+
const theme = {
|
|
145
|
+
primary: getThemeColor(userConfig, merged),
|
|
146
|
+
accent: ((_b = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _b === void 0 ? void 0 : _b.accent) || merged.theme_accent || '#4ae0ff',
|
|
147
|
+
surface: ((_c = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _c === void 0 ? void 0 : _c.surface) || '#0f1021',
|
|
148
|
+
text: ((_d = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _d === void 0 ? void 0 : _d.text) || '#e9ecf2',
|
|
149
|
+
success: ((_e = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _e === void 0 ? void 0 : _e.success) || '#24cf5f',
|
|
150
|
+
danger: ((_f = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _f === void 0 ? void 0 : _f.danger) || '#ff6b6b',
|
|
151
|
+
name: themeName,
|
|
152
|
+
};
|
|
153
|
+
merged.theme = theme;
|
|
154
|
+
merged.theme_color = theme.primary;
|
|
155
|
+
merged.logo = userConfig.logo || merged.logo;
|
|
156
|
+
merged.brand = userConfig.brand || 'Secure Pay';
|
|
157
|
+
merged.callbacks = userConfig.callbacks || userConfig.hooks || merged.callbacks || {};
|
|
158
|
+
merged.templateDir = userConfig.templateDir || merged.templateDir;
|
|
159
|
+
merged.themeName = themeName;
|
|
160
|
+
// ensure view path remains compatible with legacy controllers
|
|
161
|
+
if (!merged.view_path) {
|
|
162
|
+
merged.view_path = '/../views/';
|
|
163
|
+
}
|
|
164
|
+
if (userConfig.host_url) {
|
|
165
|
+
merged.host_url = userConfig.host_url;
|
|
166
|
+
}
|
|
167
|
+
else if (process.env.NP_HOST_URL) {
|
|
168
|
+
merged.host_url = process.env.NP_HOST_URL;
|
|
169
|
+
}
|
|
170
|
+
return validateConfig(merged);
|
|
171
|
+
}
|
|
172
|
+
function getThemeColor(userConfig, merged) {
|
|
173
|
+
var _a;
|
|
174
|
+
if ((_a = userConfig === null || userConfig === void 0 ? void 0 : userConfig.theme) === null || _a === void 0 ? void 0 : _a.primary)
|
|
175
|
+
return userConfig.theme.primary;
|
|
176
|
+
if (userConfig.theme_color)
|
|
177
|
+
return userConfig.theme_color;
|
|
178
|
+
if (merged.NP_THEME_COLOR)
|
|
179
|
+
return merged.NP_THEME_COLOR;
|
|
180
|
+
return merged.theme_color;
|
|
181
|
+
}
|
|
182
|
+
function normalizeEnv(env) {
|
|
183
|
+
const mapping = {
|
|
184
|
+
NP_HOST_URL: 'host_url',
|
|
185
|
+
NP_PATH_PREFIX: 'path_prefix',
|
|
186
|
+
NP_HOMEPAGE: 'homepage',
|
|
187
|
+
NP_TEMPLATE_DIR: 'templateDir',
|
|
188
|
+
NP_THEME_COLOR: 'theme_color',
|
|
189
|
+
NP_LOGO: 'logo',
|
|
190
|
+
NP_DB_URL: 'db_url',
|
|
191
|
+
NP_PAYTM_URL: 'paytm_url',
|
|
192
|
+
NP_RAZOR_URL: 'razor_url',
|
|
193
|
+
NP_PAYU_URL: 'payu_url',
|
|
194
|
+
NP_OPEN_MONEY_URL: 'open_money_url',
|
|
195
|
+
NP_MID: 'MID',
|
|
196
|
+
NP_WEBSITE: 'WEBSITE',
|
|
197
|
+
NP_KEY: 'KEY',
|
|
198
|
+
NP_SECRET: 'SECRET',
|
|
199
|
+
NP_CHANNEL_ID: 'CHANNEL_ID',
|
|
200
|
+
NP_INDUSTRY_TYPE_ID: 'INDUSTRY_TYPE_ID',
|
|
201
|
+
NP_MODE: 'mode',
|
|
202
|
+
NP_THEME_NAME: 'themeName',
|
|
203
|
+
};
|
|
204
|
+
return Object.keys(env).reduce((acc, key) => {
|
|
205
|
+
const target = mapping[key];
|
|
206
|
+
if (target)
|
|
207
|
+
acc[target] = env[key];
|
|
208
|
+
return acc;
|
|
209
|
+
}, {});
|
|
210
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Utils = void 0;
|
|
4
|
+
const IDLEN = 10;
|
|
5
|
+
class Utils {
|
|
6
|
+
static makeid(length = IDLEN) {
|
|
7
|
+
let text = "";
|
|
8
|
+
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
9
|
+
for (let i = 0; i < length; i++)
|
|
10
|
+
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
11
|
+
return text;
|
|
12
|
+
}
|
|
13
|
+
static sanitizeRequest(body) {
|
|
14
|
+
if (body.amount)
|
|
15
|
+
body.amount = parseFloat(body.amount);
|
|
16
|
+
if (body.TXN_AMOUNT)
|
|
17
|
+
body.amount = parseFloat(body.TXN_AMOUNT);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.Utils = Utils;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<p>
|
|
2
|
+
<h4>About</h4>
|
|
3
|
+
<div>
|
|
4
|
+
|
|
5
|
+
<table border="1">
|
|
6
|
+
|
|
7
|
+
<tr>
|
|
8
|
+
<td>Name</td><td>{{name}}</td>
|
|
9
|
+
</tr>
|
|
10
|
+
<tr>
|
|
11
|
+
<td>Version</td><td>{{version}}</td>
|
|
12
|
+
</tr>
|
|
13
|
+
<tr>
|
|
14
|
+
<td>Repository</td><td><a href='{{repository.url}}'>GITHUB</a></td>
|
|
15
|
+
</tr>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
</table>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
</p>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<div class="checkout-grid">
|
|
2
|
+
<aside class="product-panel card">
|
|
3
|
+
{{#if productImage}}
|
|
4
|
+
<div class="product-preview">
|
|
5
|
+
<img src="{{productImage}}" alt="{{PRODUCT_NAME}}" style="width:100%;height:100%;object-fit:cover" />
|
|
6
|
+
</div>
|
|
7
|
+
{{/if}}
|
|
8
|
+
|
|
9
|
+
<div class="product-price">
|
|
10
|
+
<div class="pill">Product</div>
|
|
11
|
+
<div class="price">{{PRODUCT_NAME}}</div>
|
|
12
|
+
</div>
|
|
13
|
+
{{#if PRODUCT_DESC}}
|
|
14
|
+
<p class="helper" style="margin-top:14px;">{{PRODUCT_DESC}}</p>
|
|
15
|
+
{{/if}}
|
|
16
|
+
</aside>
|
|
17
|
+
|
|
18
|
+
<section class="form-panel card">
|
|
19
|
+
<header class="card__header">
|
|
20
|
+
<div>
|
|
21
|
+
<p class="eyebrow">Payment</p>
|
|
22
|
+
<h2>Review & pay</h2>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="amount-chip">₹ {{TXN_AMOUNT}}</div>
|
|
25
|
+
</header>
|
|
26
|
+
|
|
27
|
+
<p class="helper">Your payment is processed over an encrypted channel. Double-check the details before you continue.</p>
|
|
28
|
+
|
|
29
|
+
<form action="{{action}}" method="POST" class="form-grid" id="payment-form">
|
|
30
|
+
{{#if check}}
|
|
31
|
+
<label class="field">
|
|
32
|
+
<span class="field__label">Full Name</span>
|
|
33
|
+
<input type="text" name="NAME" required value="{{NAME}}" {{readonly}} />
|
|
34
|
+
</label>
|
|
35
|
+
{{else}}
|
|
36
|
+
<input type="hidden" name="NAME" required value="{{NAME}}" {{readonly}} />
|
|
37
|
+
{{/if}}
|
|
38
|
+
|
|
39
|
+
<label class="field">
|
|
40
|
+
<span class="field__label">Email address</span>
|
|
41
|
+
<input type="email" name="EMAIL" required value="{{EMAIL}}" {{readonly}} />
|
|
42
|
+
</label>
|
|
43
|
+
|
|
44
|
+
<label class="field">
|
|
45
|
+
<span class="field__label">Phone</span>
|
|
46
|
+
<input type="text" name="MOBILE_NO" required value="{{MOBILE_NO}}" {{readonly}} />
|
|
47
|
+
</label>
|
|
48
|
+
|
|
49
|
+
{{#if check}}
|
|
50
|
+
<label class="field">
|
|
51
|
+
<span class="field__label">Product</span>
|
|
52
|
+
<input type="text" name="PRODUCT_NAME" required value="{{PRODUCT_NAME}}" {{readonly}} />
|
|
53
|
+
</label>
|
|
54
|
+
{{else}}
|
|
55
|
+
<input type="hidden" name="PRODUCT_NAME" required value="{{PRODUCT_NAME}}" {{readonly}} />
|
|
56
|
+
{{/if}}
|
|
57
|
+
|
|
58
|
+
<label class="field">
|
|
59
|
+
<span class="field__label">Amount</span>
|
|
60
|
+
<input type="text" name="TXN_AMOUNT" required value="{{TXN_AMOUNT}}" {{readonly}} />
|
|
61
|
+
</label>
|
|
62
|
+
|
|
63
|
+
<div style="grid-column:1 / -1; display:flex; gap:10px; align-items:center; justify-content:space-between;">
|
|
64
|
+
<label class="checkbox" style="margin:0">
|
|
65
|
+
<input type="checkbox" name="save_cc" checked="checked" />
|
|
66
|
+
<span>I agree to the merchant terms</span>
|
|
67
|
+
</label>
|
|
68
|
+
<div style="font-size:12px; color:rgba(255,255,255,0.6)">Secure by PCI-DSS</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<button id="pay-button" type="submit" class="button">{{BUTTON}}</button>
|
|
72
|
+
|
|
73
|
+
<input type="hidden" name="MID" value="{{MID}}" {{readonly}} />
|
|
74
|
+
<input type="hidden" name="WEBSITE" value="{{WEBSITE}}" {{readonly}} />
|
|
75
|
+
<input type="hidden" name="ORDER_ID" value="{{ORDER_ID}}" {{readonly}} />
|
|
76
|
+
<input type="hidden" name="CUST_ID" value="{{CUST_ID}}" {{readonly}} />
|
|
77
|
+
<input type="hidden" name="INDUSTRY_TYPE_ID" value="{{INDUSTRY_TYPE_ID}}" {{readonly}} />
|
|
78
|
+
<input type="hidden" name="CHANNEL_ID" value="{{CHANNEL_ID}}" {{readonly}} />
|
|
79
|
+
<input type="hidden" name="CALLBACK_URL" value="{{CALLBACK_URL}}" {{readonly}} />
|
|
80
|
+
<input type="hidden" name="CHECKSUMHASH" value="{{CHECKSUMHASH}}" {{readonly}} />
|
|
81
|
+
</form>
|
|
82
|
+
</section>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{{!-- <script>
|
|
86
|
+
(function(){
|
|
87
|
+
if (window.__npPayBtnBound) return;
|
|
88
|
+
window.__npPayBtnBound = true;
|
|
89
|
+
const payBtn = document.getElementById('pay-button');
|
|
90
|
+
if (payBtn) {
|
|
91
|
+
payBtn.addEventListener('click', () => {
|
|
92
|
+
payBtn.setAttribute('data-loading', 'true');
|
|
93
|
+
payBtn.setAttribute('disabled', 'disabled');
|
|
94
|
+
setTimeout(() => payBtn.innerText = 'Processing…', 10);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
})();
|
|
98
|
+
</script> --}}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{brand}} · Secure Checkout</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
10
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" />
|
|
11
|
+
<link rel="stylesheet" href="/{{path_prefix}}/css/style.css" />
|
|
12
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Crect%20width='16'%20height='16'%20rx='3'%20fill='%23ff5722'/%3E%3C/svg%3E" />
|
|
13
|
+
<link rel="shortcut icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Crect%20width='16'%20height='16'%20rx='3'%20fill='%23ff5722'/%3E%3C/svg%3E" />
|
|
14
|
+
<style>
|
|
15
|
+
:root {
|
|
16
|
+
--color-primary: {{#if theme.primary}}{{theme.primary}}{{else}}#2f8bff{{/if}};
|
|
17
|
+
--color-accent: {{#if theme.accent}}{{theme.accent}}{{else}}#5ce1e6{{/if}};
|
|
18
|
+
--color-surface: {{#if theme.surface}}{{theme.surface}}{{else}}#0f1021{{/if}};
|
|
19
|
+
--color-text: {{#if theme.text}}{{theme.text}}{{else}}#e9ecf2{{/if}};
|
|
20
|
+
--color-success: {{#if theme.success}}{{theme.success}}{{else}}#24cf5f{{/if}};
|
|
21
|
+
--color-danger: {{#if theme.danger}}{{theme.danger}}{{else}}#ff6b6b{{/if}};
|
|
22
|
+
--color-outline: rgba(255,255,255,0.08);
|
|
23
|
+
--radius: 14px;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
26
|
+
</head>
|
|
27
|
+
<body class="theme-{{#if themeName}}{{themeName}}{{else}}dark{{/if}}">
|
|
28
|
+
<div class="shell">
|
|
29
|
+
<header class="shell__header">
|
|
30
|
+
<div class="brand">
|
|
31
|
+
{{#if logo}}
|
|
32
|
+
<span class="brand__mark brand__mark--img"><img src="{{logo}}" alt="{{brand}} logo"></span>
|
|
33
|
+
{{else}}
|
|
34
|
+
<span class="brand__mark">{{brand}}</span>
|
|
35
|
+
{{/if}}
|
|
36
|
+
<div class="brand__text">
|
|
37
|
+
<div class="brand__title">{{brand}}</div>
|
|
38
|
+
<div class="brand__meta">Secure checkout</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="pill">Encrypted</div>
|
|
42
|
+
</header>
|
|
43
|
+
|
|
44
|
+
<main class="shell__content">
|
|
45
|
+
{{{body}}}
|
|
46
|
+
</main>
|
|
47
|
+
|
|
48
|
+
<footer class="shell__footer">
|
|
49
|
+
<span>Protected by {{brand}}</span>
|
|
50
|
+
</footer>
|
|
51
|
+
</div>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<section class="card" style="text-align:center; padding:36px 28px;">
|
|
2
|
+
<div style="display:flex; flex-direction:column; align-items:center; gap:18px;" class="status-{{status}}">
|
|
3
|
+
<div style="width:84px; height:84px; border-radius:999px; display:grid; place-items:center; background:rgba(255,255,255,0.03);">
|
|
4
|
+
<svg class="icon-success" width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20 6L9 17l-5-5" stroke="#4cff9f" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
5
|
+
<svg class="icon-fail" width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display:none"><circle cx="12" cy="12" r="9" stroke="#ff9b9b" stroke-width="2.2"/><path d="M12 8v5" stroke="#ff9b9b" stroke-width="2.2" stroke-linecap="round"/><path d="M12 16h.01" stroke="#ff9b9b" stroke-width="2.2" stroke-linecap="round"/></svg>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div>
|
|
9
|
+
<h2 style="margin:0">Payment</h2>
|
|
10
|
+
<p class="helper" style="margin-top:6px">{{message}}</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="result-grid" style="max-width:560px; width:100%;">
|
|
14
|
+
<div class="result-item">
|
|
15
|
+
<p class="label">Order ID</p>
|
|
16
|
+
<p class="value">{{orderId}}</p>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="result-item">
|
|
19
|
+
<p class="label">Transaction ID</p>
|
|
20
|
+
<p class="value">{{txnId}}</p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="result-item">
|
|
23
|
+
<p class="label">Amount</p>
|
|
24
|
+
<p class="value">{{amount}}</p>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="result-item">
|
|
27
|
+
<p class="label">Status</p>
|
|
28
|
+
<p class="value">{{status}}</p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|