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/paysend.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
class PaysendClient {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
const requiredFields = ['apiKey'];
|
|
6
|
+
for (let field of requiredFields) {
|
|
7
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
this.apiKey = config.apiKey;
|
|
11
|
+
this.isSandbox = config.sandbox || false;
|
|
12
|
+
|
|
13
|
+
this.URL = this.isSandbox
|
|
14
|
+
? 'https://sandbox.paysend.com/v1'
|
|
15
|
+
: 'https://api.paysend.com/v1';
|
|
16
|
+
|
|
17
|
+
this.client = axios.create({
|
|
18
|
+
baseURL: this.URL,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this.client.interceptors.response.use(response => {
|
|
26
|
+
return response;
|
|
27
|
+
}, error => {
|
|
28
|
+
if (error.response) {
|
|
29
|
+
throw new Error(`Paysend API error: ${error.response.data.message || error.message}`);
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`Paysend API error: ${error.message}`);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async createPayment(options) {
|
|
36
|
+
try {
|
|
37
|
+
const requestData = {
|
|
38
|
+
amount: parseFloat(options.amount),
|
|
39
|
+
currency: options.currency || 'USD',
|
|
40
|
+
recipient: {
|
|
41
|
+
type: options.recipientType || 'card',
|
|
42
|
+
card_number: options.cardNumber || '',
|
|
43
|
+
name: options.recipientName || options.name || 'Recipient'
|
|
44
|
+
},
|
|
45
|
+
sender: {
|
|
46
|
+
name: options.senderName || 'Sender',
|
|
47
|
+
email: options.senderEmail || options.email,
|
|
48
|
+
phone: options.senderPhone || options.phone || ''
|
|
49
|
+
},
|
|
50
|
+
reference: options.reference || options.orderId || `ORDER-${Date.now()}`,
|
|
51
|
+
description: options.description || options.name || 'Payment',
|
|
52
|
+
callback_url: options.callbackUrl || options.callback_link,
|
|
53
|
+
redirect_url: options.redirectUrl || options.callback_link
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const response = await this.client.post('/transfers', requestData);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
status: 'success',
|
|
60
|
+
data: {
|
|
61
|
+
transferId: response.data.id,
|
|
62
|
+
status: response.data.status,
|
|
63
|
+
amount: response.data.amount,
|
|
64
|
+
currency: response.data.currency,
|
|
65
|
+
reference: response.data.reference,
|
|
66
|
+
createdAt: response.data.created_at
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
throw new Error(`Payment creation error: ${error.message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getTransferStatus(transferId) {
|
|
75
|
+
try {
|
|
76
|
+
const response = await this.client.get(`/transfers/${transferId}`);
|
|
77
|
+
return response.data;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Transfer status error: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async handleCallback(callbackData) {
|
|
84
|
+
try {
|
|
85
|
+
const verification = await this.verifyCallback(callbackData);
|
|
86
|
+
|
|
87
|
+
if (!verification.status) {
|
|
88
|
+
throw new Error(verification.error.message);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const data = verification.data;
|
|
92
|
+
|
|
93
|
+
// Status mapping
|
|
94
|
+
const statusMapping = {
|
|
95
|
+
'completed': 'success',
|
|
96
|
+
'processing': 'pending',
|
|
97
|
+
'pending': 'pending',
|
|
98
|
+
'failed': 'failed',
|
|
99
|
+
'cancelled': 'cancelled'
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
status: statusMapping[data.status] || 'unknown',
|
|
104
|
+
transferId: data.id,
|
|
105
|
+
orderId: data.reference,
|
|
106
|
+
amount: parseFloat(data.amount),
|
|
107
|
+
currency: data.currency,
|
|
108
|
+
transferStatus: data.status,
|
|
109
|
+
completedAt: data.completed_at,
|
|
110
|
+
failureReason: data.failure_reason
|
|
111
|
+
};
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(`Error in Paysend callback handling: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async verifyCallback(data) {
|
|
118
|
+
try {
|
|
119
|
+
if (data.status === 'failed') {
|
|
120
|
+
return {
|
|
121
|
+
status: false,
|
|
122
|
+
error: {
|
|
123
|
+
code: 400,
|
|
124
|
+
message: data.failure_reason || 'Transfer failed'
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
status: true,
|
|
131
|
+
data: data
|
|
132
|
+
};
|
|
133
|
+
} catch (error) {
|
|
134
|
+
return {
|
|
135
|
+
status: false,
|
|
136
|
+
error: {
|
|
137
|
+
code: 500,
|
|
138
|
+
message: error.message
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async getBalance() {
|
|
145
|
+
try {
|
|
146
|
+
const response = await this.client.get('/balance');
|
|
147
|
+
return response.data;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(`Balance error: ${error.message}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async getExchangeRate(fromCurrency, toCurrency, amount) {
|
|
154
|
+
try {
|
|
155
|
+
const response = await this.client.get('/rates', {
|
|
156
|
+
params: {
|
|
157
|
+
from: fromCurrency,
|
|
158
|
+
to: toCurrency,
|
|
159
|
+
amount: amount
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return response.data;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
throw new Error(`Exchange rate error: ${error.message}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async getSupportedCountries() {
|
|
169
|
+
try {
|
|
170
|
+
const response = await this.client.get('/countries');
|
|
171
|
+
return response.data;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
throw new Error(`Supported countries error: ${error.message}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async validateCard(cardNumber) {
|
|
178
|
+
try {
|
|
179
|
+
const response = await this.client.post('/cards/validate', {
|
|
180
|
+
card_number: cardNumber
|
|
181
|
+
});
|
|
182
|
+
return response.data;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
throw new Error(`Card validation error: ${error.message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = PaysendClient;
|
package/lib/payspace.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class PaySpaceClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['merchantId', 'apiKey'];
|
|
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.apiKey = config.apiKey;
|
|
13
|
+
this.baseURL = 'https://api.payspace.com';
|
|
14
|
+
|
|
15
|
+
this.client = axios.create({
|
|
16
|
+
baseURL: this.baseURL,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
generateSignature(data) {
|
|
25
|
+
const signatureString = Object.keys(data)
|
|
26
|
+
.filter(key => key !== 'signature')
|
|
27
|
+
.sort()
|
|
28
|
+
.map(key => `${key}=${data[key]}`)
|
|
29
|
+
.join('&');
|
|
30
|
+
|
|
31
|
+
return crypto
|
|
32
|
+
.createHash('sha256')
|
|
33
|
+
.update(signatureString + this.apiKey)
|
|
34
|
+
.digest('hex');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async createPayment(options) {
|
|
38
|
+
try {
|
|
39
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
40
|
+
|
|
41
|
+
const paymentData = {
|
|
42
|
+
merchant_id: this.merchantId,
|
|
43
|
+
order_id: orderId,
|
|
44
|
+
amount: parseFloat(options.amount),
|
|
45
|
+
currency: options.currency || 'ZAR',
|
|
46
|
+
description: options.description || options.name || 'Payment',
|
|
47
|
+
return_url: options.successUrl || options.callback_link,
|
|
48
|
+
cancel_url: options.failUrl || options.callback_link,
|
|
49
|
+
notify_url: options.callbackUrl || options.callback_link,
|
|
50
|
+
customer_email: options.email || '',
|
|
51
|
+
customer_name: options.name || '',
|
|
52
|
+
customer_phone: options.phone || ''
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
paymentData.signature = this.generateSignature(paymentData);
|
|
56
|
+
|
|
57
|
+
const response = await this.client.post('/v1/payments', paymentData);
|
|
58
|
+
|
|
59
|
+
if (response.data.success) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'success',
|
|
62
|
+
data: {
|
|
63
|
+
url: response.data.payment_url,
|
|
64
|
+
orderId: orderId,
|
|
65
|
+
paymentId: response.data.payment_id,
|
|
66
|
+
amount: paymentData.amount,
|
|
67
|
+
currency: paymentData.currency
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
} else {
|
|
71
|
+
throw new Error(response.data.message || 'Payment creation failed');
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async handleCallback(callbackData) {
|
|
79
|
+
try {
|
|
80
|
+
const verification = await this.verifyCallback(callbackData);
|
|
81
|
+
|
|
82
|
+
if (!verification.status) {
|
|
83
|
+
throw new Error(verification.error.message);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Status mapping
|
|
87
|
+
const statusMapping = {
|
|
88
|
+
'completed': 'success',
|
|
89
|
+
'successful': 'success',
|
|
90
|
+
'failed': 'failed',
|
|
91
|
+
'cancelled': 'failed',
|
|
92
|
+
'pending': 'pending',
|
|
93
|
+
'processing': 'pending'
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
status: statusMapping[callbackData.status.toLowerCase()] || 'unknown',
|
|
98
|
+
orderId: callbackData.order_id,
|
|
99
|
+
transactionId: callbackData.payment_id || callbackData.transaction_id,
|
|
100
|
+
amount: parseFloat(callbackData.amount),
|
|
101
|
+
currency: callbackData.currency,
|
|
102
|
+
paymentStatus: callbackData.status,
|
|
103
|
+
paymentMethod: callbackData.payment_method
|
|
104
|
+
};
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new Error(`Error in PaySpace callback handling: ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async verifyCallback(data) {
|
|
111
|
+
try {
|
|
112
|
+
const receivedSign = data.signature;
|
|
113
|
+
const dataToVerify = { ...data };
|
|
114
|
+
delete dataToVerify.signature;
|
|
115
|
+
|
|
116
|
+
const expectedSign = this.generateSignature(dataToVerify);
|
|
117
|
+
|
|
118
|
+
if (receivedSign !== expectedSign) {
|
|
119
|
+
return {
|
|
120
|
+
status: false,
|
|
121
|
+
error: {
|
|
122
|
+
code: 401,
|
|
123
|
+
message: 'Invalid signature'
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
status: true,
|
|
130
|
+
data: data
|
|
131
|
+
};
|
|
132
|
+
} catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
status: false,
|
|
135
|
+
error: {
|
|
136
|
+
code: 500,
|
|
137
|
+
message: error.message
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async getPaymentStatus(paymentId) {
|
|
144
|
+
try {
|
|
145
|
+
const response = await this.client.get(`/v1/payments/${paymentId}`);
|
|
146
|
+
return response.data;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
throw new Error(`Error getting payment status: ${error.response?.data?.message || error.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async refundPayment(paymentId, options = {}) {
|
|
153
|
+
try {
|
|
154
|
+
const refundData = {
|
|
155
|
+
payment_id: paymentId,
|
|
156
|
+
amount: options.amount,
|
|
157
|
+
reason: options.reason || 'Customer request'
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const response = await this.client.post('/v1/refunds', refundData);
|
|
161
|
+
return response.data;
|
|
162
|
+
} catch (error) {
|
|
163
|
+
throw new Error(`Error creating refund: ${error.response?.data?.message || error.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = PaySpaceClient;
|
package/lib/payssion.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class PayssionClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['apiKey', 'secretKey'];
|
|
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.secretKey = config.secretKey;
|
|
13
|
+
this.baseURL = config.sandbox
|
|
14
|
+
? 'https://sandbox.payssion.com/api/v1'
|
|
15
|
+
: 'https://www.payssion.com/api/v1';
|
|
16
|
+
|
|
17
|
+
this.client = axios.create({
|
|
18
|
+
baseURL: this.baseURL,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json'
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
generateSignature(params) {
|
|
26
|
+
const sorted = Object.keys(params).sort().reduce((acc, key) => {
|
|
27
|
+
if (params[key]) acc[key] = params[key];
|
|
28
|
+
return acc;
|
|
29
|
+
}, {});
|
|
30
|
+
|
|
31
|
+
const signatureString = Object.entries(sorted)
|
|
32
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
33
|
+
.join('|');
|
|
34
|
+
|
|
35
|
+
return crypto
|
|
36
|
+
.createHash('md5')
|
|
37
|
+
.update(signatureString + '|' + this.secretKey)
|
|
38
|
+
.digest('hex');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async createPayment(options) {
|
|
42
|
+
try {
|
|
43
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
44
|
+
|
|
45
|
+
const params = {
|
|
46
|
+
api_key: this.apiKey,
|
|
47
|
+
pm_id: options.paymentMethod || 'boleto_br', // Payment method ID
|
|
48
|
+
amount: parseFloat(options.amount).toFixed(2),
|
|
49
|
+
currency: options.currency || 'USD',
|
|
50
|
+
description: options.description || options.name || 'Payment',
|
|
51
|
+
order_id: orderId,
|
|
52
|
+
return_url: options.successUrl || options.callback_link,
|
|
53
|
+
notify_url: options.callbackUrl || options.callback_link
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
params.api_sig = this.generateSignature(params);
|
|
57
|
+
|
|
58
|
+
const response = await this.client.post('/payment/create', params);
|
|
59
|
+
|
|
60
|
+
if (response.data.result_code === 200) {
|
|
61
|
+
return {
|
|
62
|
+
status: 'success',
|
|
63
|
+
data: {
|
|
64
|
+
transactionId: response.data.transaction.transaction_id,
|
|
65
|
+
url: response.data.transaction.redirect_url,
|
|
66
|
+
orderId: orderId,
|
|
67
|
+
amount: params.amount,
|
|
68
|
+
currency: params.currency,
|
|
69
|
+
state: response.data.transaction.state
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(response.data.description || 'Payment creation failed');
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new Error(`Payment creation error: ${error.response?.data?.description || error.message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async handleCallback(callbackData) {
|
|
81
|
+
try {
|
|
82
|
+
const verification = await this.verifyCallback(callbackData);
|
|
83
|
+
|
|
84
|
+
if (!verification.status) {
|
|
85
|
+
throw new Error(verification.error.message);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get transaction details
|
|
89
|
+
const transaction = await this.getTransactionDetails(callbackData.transaction_id);
|
|
90
|
+
|
|
91
|
+
// Status mapping
|
|
92
|
+
const statusMapping = {
|
|
93
|
+
'completed': 'success',
|
|
94
|
+
'paid_partial': 'pending',
|
|
95
|
+
'pending': 'pending',
|
|
96
|
+
'failed': 'failed',
|
|
97
|
+
'expired': 'failed',
|
|
98
|
+
'refund': 'refunded',
|
|
99
|
+
'cancelled': 'failed'
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
status: statusMapping[transaction.state] || 'unknown',
|
|
104
|
+
orderId: transaction.order_id,
|
|
105
|
+
transactionId: transaction.transaction_id,
|
|
106
|
+
amount: parseFloat(transaction.amount),
|
|
107
|
+
currency: transaction.currency,
|
|
108
|
+
paymentStatus: transaction.state,
|
|
109
|
+
paidAmount: parseFloat(transaction.paid || 0)
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw new Error(`Error in Payssion callback handling: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async verifyCallback(data) {
|
|
117
|
+
try {
|
|
118
|
+
const receivedSig = data.notify_sig;
|
|
119
|
+
const params = {
|
|
120
|
+
api_key: this.apiKey,
|
|
121
|
+
transaction_id: data.transaction_id,
|
|
122
|
+
order_id: data.order_id,
|
|
123
|
+
state: data.state,
|
|
124
|
+
amount: data.amount,
|
|
125
|
+
currency: data.currency
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const expectedSig = this.generateSignature(params);
|
|
129
|
+
|
|
130
|
+
if (receivedSig !== expectedSig) {
|
|
131
|
+
return {
|
|
132
|
+
status: false,
|
|
133
|
+
error: {
|
|
134
|
+
code: 401,
|
|
135
|
+
message: 'Invalid signature'
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
status: true,
|
|
142
|
+
data: data
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
status: false,
|
|
147
|
+
error: {
|
|
148
|
+
code: 500,
|
|
149
|
+
message: error.message
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async getTransactionDetails(transactionId) {
|
|
156
|
+
try {
|
|
157
|
+
const params = {
|
|
158
|
+
api_key: this.apiKey,
|
|
159
|
+
transaction_id: transactionId
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
params.api_sig = this.generateSignature(params);
|
|
163
|
+
|
|
164
|
+
const response = await this.client.post('/payment/details', params);
|
|
165
|
+
|
|
166
|
+
if (response.data.result_code === 200) {
|
|
167
|
+
return response.data.transaction;
|
|
168
|
+
} else {
|
|
169
|
+
throw new Error(response.data.description || 'Failed to get transaction details');
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
throw new Error(`Error getting transaction details: ${error.response?.data?.description || error.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = PayssionClient;
|
package/lib/paytabs.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class PayTabsClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['profileId', 'serverKey'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.profileId = config.profileId;
|
|
12
|
+
this.serverKey = config.serverKey;
|
|
13
|
+
this.region = config.region || 'ARE'; // ARE, SAU, OMN, JOR, EGY, etc.
|
|
14
|
+
|
|
15
|
+
const regionUrls = {
|
|
16
|
+
'ARE': 'https://secure.paytabs.com',
|
|
17
|
+
'SAU': 'https://secure.paytabs.sa',
|
|
18
|
+
'OMN': 'https://secure-oman.paytabs.com',
|
|
19
|
+
'JOR': 'https://secure-jordan.paytabs.com',
|
|
20
|
+
'EGY': 'https://secure-egypt.paytabs.com',
|
|
21
|
+
'global': 'https://secure-global.paytabs.com'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
this.baseURL = regionUrls[this.region] || regionUrls['global'];
|
|
25
|
+
|
|
26
|
+
this.client = axios.create({
|
|
27
|
+
baseURL: this.baseURL,
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
'Authorization': this.serverKey
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async createPayment(options) {
|
|
36
|
+
try {
|
|
37
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
38
|
+
|
|
39
|
+
const paymentData = {
|
|
40
|
+
profile_id: this.profileId,
|
|
41
|
+
tran_type: options.tranType || 'sale',
|
|
42
|
+
tran_class: options.tranClass || 'ecom',
|
|
43
|
+
cart_id: orderId,
|
|
44
|
+
cart_description: options.description || options.name || 'Payment',
|
|
45
|
+
cart_currency: options.currency || 'AED',
|
|
46
|
+
cart_amount: parseFloat(options.amount).toFixed(2),
|
|
47
|
+
callback: options.callbackUrl || options.callback_link,
|
|
48
|
+
return: options.successUrl || options.callback_link,
|
|
49
|
+
customer_details: {
|
|
50
|
+
name: options.name || options.customerName || '',
|
|
51
|
+
email: options.email || '',
|
|
52
|
+
phone: options.phone || '',
|
|
53
|
+
street1: options.address || '',
|
|
54
|
+
city: options.city || '',
|
|
55
|
+
state: options.state || '',
|
|
56
|
+
country: options.country || 'AE',
|
|
57
|
+
zip: options.zip || ''
|
|
58
|
+
},
|
|
59
|
+
hide_shipping: options.hideShipping !== false
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const response = await this.client.post('/payment/request', paymentData);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
status: 'success',
|
|
66
|
+
data: {
|
|
67
|
+
transactionRef: response.data.tran_ref,
|
|
68
|
+
url: response.data.redirect_url,
|
|
69
|
+
orderId: orderId,
|
|
70
|
+
amount: paymentData.cart_amount,
|
|
71
|
+
currency: paymentData.cart_currency
|
|
72
|
+
}
|
|
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 transactionRef = callbackData.tran_ref || callbackData.tranRef;
|
|
82
|
+
|
|
83
|
+
if (!transactionRef) {
|
|
84
|
+
throw new Error('Transaction reference not found in callback data');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Verify payment
|
|
88
|
+
const payment = await this.verifyPayment(transactionRef);
|
|
89
|
+
|
|
90
|
+
// Status mapping
|
|
91
|
+
const statusMapping = {
|
|
92
|
+
'A': 'success', // Authorized/Approved
|
|
93
|
+
'H': 'pending', // On Hold
|
|
94
|
+
'P': 'pending', // Pending
|
|
95
|
+
'V': 'pending', // Voided
|
|
96
|
+
'E': 'failed', // Error
|
|
97
|
+
'D': 'failed' // Declined
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
status: statusMapping[payment.payment_result?.response_status] || 'unknown',
|
|
102
|
+
orderId: payment.cart_id,
|
|
103
|
+
transactionRef: payment.tran_ref,
|
|
104
|
+
amount: parseFloat(payment.cart_amount),
|
|
105
|
+
currency: payment.cart_currency,
|
|
106
|
+
paymentStatus: payment.payment_result?.response_status,
|
|
107
|
+
responseCode: payment.payment_result?.response_code,
|
|
108
|
+
responseMessage: payment.payment_result?.response_message
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new Error(`Error in PayTabs callback handling: ${error.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async verifyPayment(transactionRef) {
|
|
116
|
+
try {
|
|
117
|
+
const response = await this.client.post('/payment/query', {
|
|
118
|
+
profile_id: this.profileId,
|
|
119
|
+
tran_ref: transactionRef
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return response.data;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new Error(`Error verifying payment: ${error.response?.data?.message || error.message}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async refundPayment(transactionRef, options = {}) {
|
|
129
|
+
try {
|
|
130
|
+
const response = await this.client.post('/payment/refund', {
|
|
131
|
+
profile_id: this.profileId,
|
|
132
|
+
tran_ref: transactionRef,
|
|
133
|
+
cart_amount: options.amount,
|
|
134
|
+
cart_description: options.description || 'Refund',
|
|
135
|
+
cart_id: options.orderId
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return response.data;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
throw new Error(`Error processing refund: ${error.response?.data?.message || error.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = PayTabsClient;
|