quickpos 1.0.911 → 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/{example-heleket.js → examples/example-heleket.js} +3 -3
- 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/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/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/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;
|
package/lib/konnect.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Konnect Ödeme Entegrasyonu
|
|
5
|
+
*
|
|
6
|
+
* Başlamadan önce:
|
|
7
|
+
* 1. Konnect hesabı oluşturun:
|
|
8
|
+
* - Sandbox (test): https://dashboard.sandbox.konnect.network
|
|
9
|
+
* - Üretim: https://dashboard.konnect.network
|
|
10
|
+
* 2. KYC/KYB doğrulamasını tamamlayın (kimlik ve kurum doğrulama)
|
|
11
|
+
* 3. API anahtarınızı ve cüzdan ID'nizi alın
|
|
12
|
+
*/
|
|
13
|
+
class KonnectService {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config || {};
|
|
16
|
+
const requiredFields = ['apiKey', 'receiverWalletId'];
|
|
17
|
+
for (let field of requiredFields) {
|
|
18
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.apiKey = config.apiKey;
|
|
22
|
+
this.receiverWalletId = config.receiverWalletId;
|
|
23
|
+
|
|
24
|
+
// Sandbox veya Production modu seçimi
|
|
25
|
+
this.sandbox = config.sandbox || false;
|
|
26
|
+
|
|
27
|
+
// API URL'ini ortama göre ayarla
|
|
28
|
+
if (this.sandbox) {
|
|
29
|
+
this.baseUrl = 'https://api.sandbox.konnect.network/api/v2';
|
|
30
|
+
} else {
|
|
31
|
+
this.baseUrl = config.baseUrl || 'https://api.konnect.network/api/v2';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(`Konnect API URL: ${this.baseUrl}`);
|
|
35
|
+
this.testMode = config.testMode || false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async createPayment(paymentDetails) {
|
|
39
|
+
try {
|
|
40
|
+
let requiredData = ['amount', 'token'];
|
|
41
|
+
for (let data of requiredData) {
|
|
42
|
+
if (!paymentDetails[data]) throw new Error(`Missing required data: ${data}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Temel ödeme verilerini hazırla
|
|
46
|
+
const paymentData = {
|
|
47
|
+
receiverWalletId: this.receiverWalletId,
|
|
48
|
+
token: paymentDetails.token || 'TND',
|
|
49
|
+
amount: paymentDetails.amount,
|
|
50
|
+
type: paymentDetails.type || 'immediate',
|
|
51
|
+
description: paymentDetails.description || 'Ödeme',
|
|
52
|
+
acceptedPaymentMethods: paymentDetails.acceptedPaymentMethods || ["wallet", "bank_card", "e-DINAR"],
|
|
53
|
+
lifespan: paymentDetails.lifespan || 60, // varsayılan 60 dakika
|
|
54
|
+
checkoutForm: paymentDetails.checkoutForm || false,
|
|
55
|
+
addPaymentFeesToAmount: paymentDetails.addPaymentFeesToAmount || false,
|
|
56
|
+
orderId: paymentDetails.orderId || `order-${Date.now()}`,
|
|
57
|
+
theme: paymentDetails.theme || 'light'
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Müşteri bilgilerini ekle (varsa)
|
|
61
|
+
if (paymentDetails.firstName) paymentData.firstName = paymentDetails.firstName;
|
|
62
|
+
if (paymentDetails.lastName) paymentData.lastName = paymentDetails.lastName;
|
|
63
|
+
if (paymentDetails.phoneNumber) paymentData.phoneNumber = paymentDetails.phoneNumber;
|
|
64
|
+
if (paymentDetails.email) paymentData.email = paymentDetails.email;
|
|
65
|
+
|
|
66
|
+
// Webhook URL'ini ekle (varsa)
|
|
67
|
+
if (paymentDetails.webhook) paymentData.webhook = paymentDetails.webhook;
|
|
68
|
+
|
|
69
|
+
console.log('Konnect ödeme isteği hazırlanıyor:', JSON.stringify(paymentData, null, 2));
|
|
70
|
+
|
|
71
|
+
// API isteği gönder
|
|
72
|
+
const response = await axios({
|
|
73
|
+
method: 'POST',
|
|
74
|
+
url: `${this.baseUrl}/payments/init-payment`,
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
'x-api-key': this.apiKey
|
|
78
|
+
},
|
|
79
|
+
data: paymentData
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const responseData = response.data;
|
|
83
|
+
console.log('Konnect API yanıtı:', JSON.stringify(responseData, null, 2));
|
|
84
|
+
|
|
85
|
+
// QR kod oluştur (isteğe bağlı)
|
|
86
|
+
let qrCode = null;
|
|
87
|
+
if (paymentDetails.generateQr) {
|
|
88
|
+
qrCode = await this.generateQrCode(responseData.payUrl);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
status: 'success',
|
|
93
|
+
data: {
|
|
94
|
+
transactionId: responseData.paymentRef,
|
|
95
|
+
url: responseData.payUrl,
|
|
96
|
+
id: responseData.paymentRef,
|
|
97
|
+
qr: qrCode
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('Konnect API hatası:', error);
|
|
102
|
+
|
|
103
|
+
if (error.response) {
|
|
104
|
+
console.error('Hata detayları:', {
|
|
105
|
+
statusCode: error.response.status,
|
|
106
|
+
statusText: error.response.statusText,
|
|
107
|
+
data: error.response.data
|
|
108
|
+
});
|
|
109
|
+
throw new Error(`Konnect API error (${error.response.status}): ${JSON.stringify(error.response.data)}`);
|
|
110
|
+
} else if (error.request) {
|
|
111
|
+
console.error('Yanıt alınamadı:', error.request);
|
|
112
|
+
throw new Error('No response received from Konnect API');
|
|
113
|
+
} else {
|
|
114
|
+
throw new Error(`Error in Konnect payment creation: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getPaymentDetails(paymentRef) {
|
|
120
|
+
try {
|
|
121
|
+
const response = await axios({
|
|
122
|
+
method: 'GET',
|
|
123
|
+
url: `${this.baseUrl}/payments/${paymentRef}`,
|
|
124
|
+
headers: {
|
|
125
|
+
'x-api-key': this.apiKey
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const paymentData = response.data.payment;
|
|
130
|
+
|
|
131
|
+
// İşlem durumunu belirle
|
|
132
|
+
let status = 'pending';
|
|
133
|
+
if (paymentData.status === 'completed') {
|
|
134
|
+
status = 'success';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
status: status,
|
|
139
|
+
paymentId: paymentData.id,
|
|
140
|
+
orderId: paymentData.orderId,
|
|
141
|
+
amount: paymentData.amount,
|
|
142
|
+
reachedAmount: paymentData.reachedAmount,
|
|
143
|
+
token: paymentData.token,
|
|
144
|
+
type: paymentData.type,
|
|
145
|
+
description: paymentData.details,
|
|
146
|
+
expirationDate: paymentData.expirationDate,
|
|
147
|
+
transactions: paymentData.transactions || [],
|
|
148
|
+
raw: paymentData
|
|
149
|
+
};
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error.response && error.response.status === 404) {
|
|
152
|
+
throw new Error(`Payment not found: ${paymentRef}`);
|
|
153
|
+
} else if (error.response) {
|
|
154
|
+
throw new Error(`Konnect API error: ${error.response.data.message || error.response.statusText}`);
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(`Error fetching payment details: ${error.message}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async handleCallback(callbackData) {
|
|
162
|
+
try {
|
|
163
|
+
if (!callbackData.payment_ref) {
|
|
164
|
+
throw new Error("Missing payment_ref in callback data");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Ödeme detaylarını al
|
|
168
|
+
const paymentDetails = await this.getPaymentDetails(callbackData.payment_ref);
|
|
169
|
+
|
|
170
|
+
if (paymentDetails.status === 'success') {
|
|
171
|
+
return {
|
|
172
|
+
status: 'success',
|
|
173
|
+
orderId: paymentDetails.orderId,
|
|
174
|
+
merchant_oid: paymentDetails.paymentId,
|
|
175
|
+
amount: paymentDetails.amount,
|
|
176
|
+
currency: paymentDetails.token,
|
|
177
|
+
paymentType: 'konnect'
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
return {
|
|
181
|
+
status: 'failed',
|
|
182
|
+
orderId: paymentDetails.orderId || callbackData.payment_ref,
|
|
183
|
+
reason: 'Payment is not completed'
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
throw new Error(`Error in Konnect callback handling: ${error.message}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// QR kod oluşturmak için yardımcı fonksiyon
|
|
192
|
+
async generateQrCode(paymentUrl) {
|
|
193
|
+
try {
|
|
194
|
+
const response = await axios.get('https://api.qrserver.com/v1/create-qr-code/', {
|
|
195
|
+
params: {
|
|
196
|
+
size: '300x300',
|
|
197
|
+
data: paymentUrl
|
|
198
|
+
},
|
|
199
|
+
responseType: 'arraybuffer'
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const base64Image = Buffer.from(response.data, 'binary').toString('base64');
|
|
203
|
+
return `data:image/png;base64,${base64Image}`;
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('QR code generation failed:', error);
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = KonnectService;
|