quickpos 1.0.910 → 1.0.912
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/PROVIDERS-DETAILS.md +1544 -0
- package/examples/example-2checkout.js +78 -0
- package/examples/example-bitpay.js +83 -0
- package/examples/example-cardcom.js +80 -0
- package/examples/example-cashfree.js +109 -0
- package/examples/example-checkout.js +85 -0
- package/examples/example-coingate.js +101 -0
- package/examples/example-coinpayments.js +89 -0
- package/examples/example-doku.js +27 -0
- package/examples/example-epay.js +64 -0
- package/examples/example-epoint.js +91 -0
- package/examples/example-freekassa.js +26 -0
- package/examples/example-heleket.js +139 -0
- package/examples/example-konnect.js +227 -0
- package/examples/example-midtrans.js +80 -0
- package/examples/example-noonpayments.js +297 -0
- package/examples/example-nowpayments.js +289 -0
- package/examples/example-omise.js +27 -0
- package/examples/example-paycom.js +82 -0
- package/{example-paydisini.js → examples/example-paydisini.js} +1 -1
- package/examples/example-payid19.js +87 -0
- package/examples/example-paykun.js +29 -0
- package/examples/example-payme.js +202 -0
- package/examples/example-paymentwall.js +201 -0
- package/examples/example-paynet.js +104 -0
- package/examples/example-paynettr.js +18 -0
- package/examples/example-payoneer.js +74 -0
- package/examples/example-payop.js +351 -0
- package/examples/example-paypal.js +200 -0
- package/examples/example-payriff.js +89 -0
- package/examples/example-paysend.js +81 -0
- package/examples/example-payspace.js +103 -0
- package/examples/example-payssion.js +27 -0
- package/examples/example-paytabs.js +28 -0
- package/examples/example-paytm.js +78 -0
- package/examples/example-payuindia.js +108 -0
- package/examples/example-payulatam.js +75 -0
- package/examples/example-phonepe.js +27 -0
- package/examples/example-picpay.js +27 -0
- package/examples/example-plisio.js +84 -0
- package/examples/example-portwallet.js +90 -0
- package/examples/example-primepayments.js +250 -0
- package/examples/example-razorpay.js +30 -0
- package/examples/example-senangpay.js +28 -0
- package/examples/example-shurjopay.js +94 -0
- package/examples/example-toyyibpay.js +80 -0
- package/examples/example-tripay.js +89 -0
- package/examples/example-unitpay.js +26 -0
- package/examples/example-urway.js +28 -0
- package/examples/example-volet.js +80 -0
- package/examples/example-xendit.js +28 -0
- package/examples/example-yallapay.js +253 -0
- package/examples/example-yookassa.js +27 -0
- package/examples/example-youcanpay.js +28 -0
- package/examples/example-zarinpal.js +98 -0
- package/{example.js → examples/example.js} +1 -1
- package/lib/2checkout.js +165 -0
- package/lib/amazonpay.js +161 -0
- package/lib/bitpay.js +122 -0
- package/lib/cardcom.js +193 -0
- package/lib/cashfree.js +184 -0
- package/lib/checkout.js +248 -0
- package/lib/coinbase.js +150 -0
- package/lib/coingate.js +137 -0
- package/lib/coinpayments.js +245 -0
- package/lib/doku.js +173 -0
- package/lib/epay.js +175 -0
- package/lib/epoint.js +162 -0
- package/lib/freekassa.js +128 -0
- package/lib/heleket.js +67 -1
- package/lib/instamojo.js +158 -0
- package/lib/konnect.js +211 -0
- package/lib/midtrans.js +227 -0
- package/lib/noonpayments.js +650 -0
- package/lib/nowpayments.js +311 -0
- package/lib/omise.js +150 -0
- package/lib/paddle.js +180 -0
- package/lib/paycom.js +216 -0
- package/lib/payid19.js +211 -0
- package/lib/paykun.js +144 -0
- package/lib/payme.js +302 -0
- package/lib/paymentwall.js +205 -0
- package/lib/paynet.js +186 -0
- package/lib/paynettr.js +165 -0
- package/lib/payoneer.js +128 -0
- package/lib/payop.js +256 -0
- package/lib/paypal.js +542 -0
- package/lib/payriff.js +148 -0
- package/lib/paysend.js +189 -0
- package/lib/payspace.js +168 -0
- package/lib/payssion.js +177 -0
- package/lib/paytabs.js +145 -0
- package/lib/paytm.js +253 -0
- package/lib/payuindia.js +162 -0
- package/lib/payulatam.js +179 -0
- package/lib/perfectmoney.js +143 -0
- package/lib/phonepe.js +174 -0
- package/lib/picpay.js +119 -0
- package/lib/plisio.js +234 -0
- package/lib/portwallet.js +152 -0
- package/lib/primepayments.js +256 -0
- package/lib/razorpay.js +205 -0
- package/lib/senangpay.js +130 -0
- package/lib/shurjopay.js +159 -0
- package/lib/toyyibpay.js +151 -0
- package/lib/tripay.js +220 -0
- package/lib/unitpay.js +223 -0
- package/lib/urway.js +182 -0
- package/lib/volet.js +147 -0
- package/lib/xendit.js +206 -0
- package/lib/yallapay.js +279 -0
- package/lib/yookassa.js +193 -0
- package/lib/youcanpay.js +124 -0
- package/lib/zarinpal.js +157 -0
- package/package.json +138 -64
- package/readme.md +348 -105
- package/test.js +492 -0
- package/example-heleket.js +0 -83
- package/lib/vallet.js +0 -22
- /package/{example-anypay.js → examples/example-anypay.js} +0 -0
- /package/{example-bufpay.js → examples/example-bufpay.js} +0 -0
- /package/{example-cryptomus.js → examples/example-cryptomus.js} +0 -0
- /package/{example-esnekpos.js → examples/example-esnekpos.js} +0 -0
- /package/{example-fedapay.js → examples/example-fedapay.js} +0 -0
- /package/{example-iyzico.js → examples/example-iyzico.js} +0 -0
- /package/{example-papara.js → examples/example-papara.js} +0 -0
- /package/{example-payeer.js → examples/example-payeer.js} +0 -0
- /package/{example-paymaya.js → examples/example-paymaya.js} +0 -0
- /package/{example-shopier.js → examples/example-shopier.js} +0 -0
- /package/{ipaymu.js → examples/ipaymu.js} +0 -0
- /package/{oderopay.js → examples/oderopay.js} +0 -0
package/lib/epoint.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class EpointClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['merchantId', 'privateKey'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.merchantId = config.merchantId;
|
|
12
|
+
this.privateKey = config.privateKey;
|
|
13
|
+
this.baseURL = 'https://epoint.az/api';
|
|
14
|
+
|
|
15
|
+
this.client = axios.create({
|
|
16
|
+
baseURL: this.baseURL,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json'
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
generateSignature(data) {
|
|
24
|
+
const signatureString = Object.keys(data)
|
|
25
|
+
.filter(key => key !== 'signature')
|
|
26
|
+
.sort()
|
|
27
|
+
.map(key => `${key}=${data[key]}`)
|
|
28
|
+
.join('&');
|
|
29
|
+
|
|
30
|
+
return crypto
|
|
31
|
+
.createHmac('sha256', this.privateKey)
|
|
32
|
+
.update(signatureString)
|
|
33
|
+
.digest('hex')
|
|
34
|
+
.toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async createPayment(options) {
|
|
38
|
+
try {
|
|
39
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
40
|
+
const amount = parseFloat(options.amount) * 100; // Convert to cents
|
|
41
|
+
|
|
42
|
+
const paymentData = {
|
|
43
|
+
merchant_id: this.merchantId,
|
|
44
|
+
order_id: orderId,
|
|
45
|
+
amount: amount,
|
|
46
|
+
currency: options.currency || 'AZN',
|
|
47
|
+
description: options.description || options.name || 'Payment',
|
|
48
|
+
success_url: options.successUrl || options.callback_link,
|
|
49
|
+
fail_url: options.failUrl || options.callback_link,
|
|
50
|
+
callback_url: options.callbackUrl || options.callback_link,
|
|
51
|
+
language: options.language || 'az',
|
|
52
|
+
email: options.email || '',
|
|
53
|
+
phone: options.phone || ''
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
paymentData.signature = this.generateSignature(paymentData);
|
|
57
|
+
|
|
58
|
+
const response = await this.client.post('/payment/create', paymentData);
|
|
59
|
+
|
|
60
|
+
if (response.data.success) {
|
|
61
|
+
return {
|
|
62
|
+
status: 'success',
|
|
63
|
+
data: {
|
|
64
|
+
url: response.data.data.payment_url,
|
|
65
|
+
orderId: orderId,
|
|
66
|
+
paymentId: response.data.data.payment_id,
|
|
67
|
+
amount: amount / 100,
|
|
68
|
+
currency: paymentData.currency
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
} else {
|
|
72
|
+
throw new Error(response.data.message || 'Payment creation failed');
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async handleCallback(callbackData) {
|
|
80
|
+
try {
|
|
81
|
+
const verification = await this.verifyCallback(callbackData);
|
|
82
|
+
|
|
83
|
+
if (!verification.status) {
|
|
84
|
+
throw new Error(verification.error.message);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const data = verification.data;
|
|
88
|
+
|
|
89
|
+
// Status mapping
|
|
90
|
+
const statusMapping = {
|
|
91
|
+
'success': 'success',
|
|
92
|
+
'completed': 'success',
|
|
93
|
+
'failed': 'failed',
|
|
94
|
+
'cancelled': 'failed',
|
|
95
|
+
'pending': 'pending'
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
status: statusMapping[data.status] || 'unknown',
|
|
100
|
+
orderId: data.order_id,
|
|
101
|
+
transactionId: data.payment_id,
|
|
102
|
+
amount: parseFloat(data.amount) / 100,
|
|
103
|
+
currency: data.currency,
|
|
104
|
+
paymentStatus: data.status,
|
|
105
|
+
paymentMethod: data.payment_method
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(`Error in Epoint callback handling: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async verifyCallback(data) {
|
|
113
|
+
try {
|
|
114
|
+
const receivedSign = data.signature;
|
|
115
|
+
const dataToVerify = { ...data };
|
|
116
|
+
delete dataToVerify.signature;
|
|
117
|
+
|
|
118
|
+
const expectedSign = this.generateSignature(dataToVerify);
|
|
119
|
+
|
|
120
|
+
if (receivedSign !== expectedSign) {
|
|
121
|
+
return {
|
|
122
|
+
status: false,
|
|
123
|
+
error: {
|
|
124
|
+
code: 401,
|
|
125
|
+
message: 'Invalid signature'
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
status: true,
|
|
132
|
+
data: data
|
|
133
|
+
};
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return {
|
|
136
|
+
status: false,
|
|
137
|
+
error: {
|
|
138
|
+
code: 500,
|
|
139
|
+
message: error.message
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getPaymentStatus(paymentId) {
|
|
146
|
+
try {
|
|
147
|
+
const data = {
|
|
148
|
+
merchant_id: this.merchantId,
|
|
149
|
+
payment_id: paymentId
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
data.signature = this.generateSignature(data);
|
|
153
|
+
|
|
154
|
+
const response = await this.client.post('/payment/status', data);
|
|
155
|
+
return response.data;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw new Error(`Error getting payment status: ${error.response?.data?.message || error.message}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = EpointClient;
|
package/lib/freekassa.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class FreeKassaClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['shopId', 'secretKey1', 'secretKey2'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.shopId = config.shopId;
|
|
12
|
+
this.secretKey1 = config.secretKey1; // For payment form signature
|
|
13
|
+
this.secretKey2 = config.secretKey2; // For callback verification
|
|
14
|
+
this.baseURL = 'https://pay.freekassa.ru';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
generateSignature(amount, orderId, secretKey) {
|
|
18
|
+
const signatureString = `${this.shopId}:${amount}:${secretKey}:${orderId}`;
|
|
19
|
+
return crypto.createHash('md5').update(signatureString).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async createPayment(options) {
|
|
23
|
+
try {
|
|
24
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
25
|
+
const amount = parseFloat(options.amount).toFixed(2);
|
|
26
|
+
|
|
27
|
+
const signature = this.generateSignature(amount, orderId, this.secretKey1);
|
|
28
|
+
|
|
29
|
+
const paymentData = {
|
|
30
|
+
m: this.shopId,
|
|
31
|
+
oa: amount,
|
|
32
|
+
currency: options.currency || 'RUB',
|
|
33
|
+
o: orderId,
|
|
34
|
+
s: signature,
|
|
35
|
+
email: options.email || '',
|
|
36
|
+
phone: options.phone || '',
|
|
37
|
+
i: options.paymentMethod || '', // Payment system ID
|
|
38
|
+
us_customer_name: options.name || ''
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Create payment URL
|
|
42
|
+
const params = new URLSearchParams(paymentData);
|
|
43
|
+
const paymentUrl = `${this.baseURL}/?${params.toString()}`;
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
status: 'success',
|
|
47
|
+
data: {
|
|
48
|
+
url: paymentUrl,
|
|
49
|
+
orderId: orderId,
|
|
50
|
+
amount: amount,
|
|
51
|
+
currency: paymentData.currency,
|
|
52
|
+
signature: signature
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(`Payment creation error: ${error.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async handleCallback(callbackData) {
|
|
61
|
+
try {
|
|
62
|
+
const verification = await this.verifyCallback(callbackData);
|
|
63
|
+
|
|
64
|
+
if (!verification.status) {
|
|
65
|
+
throw new Error(verification.error.message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
status: 'success',
|
|
70
|
+
orderId: callbackData.MERCHANT_ORDER_ID,
|
|
71
|
+
transactionId: callbackData.intid,
|
|
72
|
+
amount: parseFloat(callbackData.AMOUNT),
|
|
73
|
+
currency: callbackData.MERCHANT_CURRENCY || 'RUB',
|
|
74
|
+
paymentStatus: 'completed',
|
|
75
|
+
paymentMethod: callbackData.PAYMENT_ID
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
throw new Error(`Error in FreeKassa callback handling: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async verifyCallback(data) {
|
|
83
|
+
try {
|
|
84
|
+
const receivedSign = data.SIGN;
|
|
85
|
+
const signatureString = `${this.shopId}:${data.AMOUNT}:${this.secretKey2}:${data.MERCHANT_ORDER_ID}`;
|
|
86
|
+
const expectedSign = crypto.createHash('md5').update(signatureString).digest('hex');
|
|
87
|
+
|
|
88
|
+
if (receivedSign !== expectedSign) {
|
|
89
|
+
return {
|
|
90
|
+
status: false,
|
|
91
|
+
error: {
|
|
92
|
+
code: 401,
|
|
93
|
+
message: 'Invalid signature'
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
status: true,
|
|
100
|
+
data: data
|
|
101
|
+
};
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return {
|
|
104
|
+
status: false,
|
|
105
|
+
error: {
|
|
106
|
+
code: 500,
|
|
107
|
+
message: error.message
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async getBalance() {
|
|
114
|
+
try {
|
|
115
|
+
// FreeKassa API for balance check
|
|
116
|
+
const response = await axios.post('https://api.freekassa.ru/v1/balance', {
|
|
117
|
+
shopId: this.shopId,
|
|
118
|
+
nonce: Date.now()
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return response.data;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(`Error getting balance: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = FreeKassaClient;
|
package/lib/heleket.js
CHANGED
|
@@ -129,7 +129,7 @@ class Heleket {
|
|
|
129
129
|
const data = {...webhookData};
|
|
130
130
|
|
|
131
131
|
// Process successful payments
|
|
132
|
-
if (data.status === '
|
|
132
|
+
if (data.status === 'paid') {
|
|
133
133
|
return {
|
|
134
134
|
status: 'success',
|
|
135
135
|
orderId: data.order_id,
|
|
@@ -146,6 +146,72 @@ class Heleket {
|
|
|
146
146
|
throw new Error(`Error in Heleket callback handling: ${error.message}`);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Test payment webhook
|
|
152
|
+
* @param {object} params - Test parameters
|
|
153
|
+
* @param {string} params.url_callback - URL to which webhooks will be sent
|
|
154
|
+
* @param {string} params.currency - Invoice currency code
|
|
155
|
+
* @param {string} params.network - Invoice network code
|
|
156
|
+
* @param {string} [params.uuid] - UUID of the invoice
|
|
157
|
+
* @param {string} [params.order_id] - Order ID of the invoice
|
|
158
|
+
* @param {string} [params.status=paid] - Payment status
|
|
159
|
+
* @returns {Promise} - Promise resolving to test result
|
|
160
|
+
*/
|
|
161
|
+
testPaymentWebhook(params) {
|
|
162
|
+
if (!params.url_callback || !params.currency || !params.network) {
|
|
163
|
+
throw new Error('Missing required parameters: url_callback, currency, network');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Set default status if not provided
|
|
167
|
+
params.status = params.status || 'paid';
|
|
168
|
+
|
|
169
|
+
return this.request('/v1/test-webhook/payment', params);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Test payout webhook
|
|
174
|
+
* @param {object} params - Test parameters
|
|
175
|
+
* @param {string} params.url_callback - URL to which webhooks will be sent
|
|
176
|
+
* @param {string} params.currency - Payout currency code
|
|
177
|
+
* @param {string} params.network - Payout network code
|
|
178
|
+
* @param {string} [params.uuid] - UUID of the payout
|
|
179
|
+
* @param {string} [params.order_id] - Order ID of the payout
|
|
180
|
+
* @param {string} [params.status=paid] - Payout status
|
|
181
|
+
* @returns {Promise} - Promise resolving to test result
|
|
182
|
+
*/
|
|
183
|
+
testPayoutWebhook(params) {
|
|
184
|
+
if (!params.url_callback || !params.currency || !params.network) {
|
|
185
|
+
throw new Error('Missing required parameters: url_callback, currency, network');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Set default status if not provided
|
|
189
|
+
params.status = params.status || 'paid';
|
|
190
|
+
|
|
191
|
+
return this.request('/v1/test-webhook/payout', params);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Test wallet webhook
|
|
196
|
+
* @param {object} params - Test parameters
|
|
197
|
+
* @param {string} params.url_callback - URL to which webhooks will be sent
|
|
198
|
+
* @param {string} params.currency - Payment currency code
|
|
199
|
+
* @param {string} params.network - Payment network code
|
|
200
|
+
* @param {string} [params.uuid] - UUID of business wallet
|
|
201
|
+
* @param {string} [params.order_id] - Order ID of the invoice
|
|
202
|
+
* @param {string} [params.status=paid] - Payment status
|
|
203
|
+
* @returns {Promise} - Promise resolving to test result
|
|
204
|
+
*/
|
|
205
|
+
testWalletWebhook(params) {
|
|
206
|
+
if (!params.url_callback || !params.currency || !params.network) {
|
|
207
|
+
throw new Error('Missing required parameters: url_callback, currency, network');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Set default status if not provided
|
|
211
|
+
params.status = params.status || 'paid';
|
|
212
|
+
|
|
213
|
+
return this.request('/v1/test-webhook/wallet', params);
|
|
214
|
+
}
|
|
149
215
|
}
|
|
150
216
|
|
|
151
217
|
module.exports = Heleket;
|
package/lib/instamojo.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class InstamojoClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['apiKey', 'authToken'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.apiKey = config.apiKey;
|
|
12
|
+
this.authToken = config.authToken;
|
|
13
|
+
this.baseURL = config.sandbox
|
|
14
|
+
? 'https://test.instamojo.com/api/1.1'
|
|
15
|
+
: 'https://www.instamojo.com/api/1.1';
|
|
16
|
+
|
|
17
|
+
this.client = axios.create({
|
|
18
|
+
baseURL: this.baseURL,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'X-Api-Key': this.apiKey,
|
|
22
|
+
'X-Auth-Token': this.authToken
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async createPayment(options) {
|
|
28
|
+
try {
|
|
29
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
30
|
+
|
|
31
|
+
const paymentData = {
|
|
32
|
+
purpose: options.purpose || options.name || 'Payment',
|
|
33
|
+
amount: parseFloat(options.amount).toFixed(2),
|
|
34
|
+
buyer_name: options.name || options.buyerName || '',
|
|
35
|
+
email: options.email || '',
|
|
36
|
+
phone: options.phone || '',
|
|
37
|
+
send_email: options.sendEmail !== false,
|
|
38
|
+
send_sms: options.sendSms || false,
|
|
39
|
+
redirect_url: options.successUrl || options.callback_link,
|
|
40
|
+
webhook: options.callbackUrl || options.callback_link,
|
|
41
|
+
allow_repeated_payments: false
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const response = await this.client.post('/payment-requests/', paymentData);
|
|
45
|
+
|
|
46
|
+
if (response.data.success) {
|
|
47
|
+
return {
|
|
48
|
+
status: 'success',
|
|
49
|
+
data: {
|
|
50
|
+
id: response.data.payment_request.id,
|
|
51
|
+
url: response.data.payment_request.longurl,
|
|
52
|
+
orderId: orderId,
|
|
53
|
+
amount: response.data.payment_request.amount,
|
|
54
|
+
currency: 'INR',
|
|
55
|
+
status: response.data.payment_request.status
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(response.data.message || 'Payment request creation failed');
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async handleCallback(callbackData) {
|
|
67
|
+
try {
|
|
68
|
+
// Get payment details
|
|
69
|
+
const paymentId = callbackData.payment_id;
|
|
70
|
+
|
|
71
|
+
if (!paymentId) {
|
|
72
|
+
throw new Error('Payment ID not found in callback data');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const payment = await this.getPaymentDetails(paymentId);
|
|
76
|
+
|
|
77
|
+
// Status mapping
|
|
78
|
+
const statusMapping = {
|
|
79
|
+
'Credit': 'success',
|
|
80
|
+
'Pending': 'pending',
|
|
81
|
+
'Failed': 'failed',
|
|
82
|
+
'Initiated': 'pending'
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
status: statusMapping[payment.status] || 'unknown',
|
|
87
|
+
orderId: payment.payment_request?.id,
|
|
88
|
+
transactionId: payment.payment_id,
|
|
89
|
+
amount: parseFloat(payment.amount),
|
|
90
|
+
currency: payment.currency || 'INR',
|
|
91
|
+
paymentStatus: payment.status,
|
|
92
|
+
paymentMethod: payment.instrument_type,
|
|
93
|
+
fees: parseFloat(payment.fees || 0),
|
|
94
|
+
buyer: {
|
|
95
|
+
name: payment.buyer_name,
|
|
96
|
+
email: payment.buyer_email,
|
|
97
|
+
phone: payment.buyer_phone
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`Error in Instamojo callback handling: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async getPaymentDetails(paymentId) {
|
|
106
|
+
try {
|
|
107
|
+
const response = await this.client.get(`/payments/${paymentId}/`);
|
|
108
|
+
|
|
109
|
+
if (response.data.success) {
|
|
110
|
+
return response.data.payment;
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error(response.data.message || 'Failed to get payment details');
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
throw new Error(`Error getting payment details: ${error.response?.data?.message || error.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getPaymentRequestDetails(requestId) {
|
|
120
|
+
try {
|
|
121
|
+
const response = await this.client.get(`/payment-requests/${requestId}/`);
|
|
122
|
+
|
|
123
|
+
if (response.data.success) {
|
|
124
|
+
return response.data.payment_request;
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error(response.data.message || 'Failed to get payment request details');
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
throw new Error(`Error getting payment request details: ${error.response?.data?.message || error.message}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async initiateRefund(paymentId, options = {}) {
|
|
134
|
+
try {
|
|
135
|
+
const refundData = {
|
|
136
|
+
payment_id: paymentId,
|
|
137
|
+
type: options.type || 'RFD', // RFD or TNR
|
|
138
|
+
body: options.reason || 'Customer request'
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
if (options.refund_amount) {
|
|
142
|
+
refundData.refund_amount = parseFloat(options.refund_amount).toFixed(2);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const response = await this.client.post('/refunds/', refundData);
|
|
146
|
+
|
|
147
|
+
if (response.data.success) {
|
|
148
|
+
return response.data.refund;
|
|
149
|
+
} else {
|
|
150
|
+
throw new Error(response.data.message || 'Refund initiation failed');
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`Error initiating refund: ${error.response?.data?.message || error.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
module.exports = InstamojoClient;
|