quickpos 1.0.911 → 1.0.913

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.
Files changed (133) hide show
  1. package/PROVIDERS-DETAILS.md +1544 -0
  2. package/examples/example-2checkout.js +78 -0
  3. package/examples/example-bitpay.js +83 -0
  4. package/examples/example-cardcom.js +80 -0
  5. package/examples/example-cashfree.js +109 -0
  6. package/examples/example-checkout.js +85 -0
  7. package/examples/example-coingate.js +101 -0
  8. package/examples/example-coinpayments.js +89 -0
  9. package/examples/example-doku.js +27 -0
  10. package/examples/example-epay.js +64 -0
  11. package/examples/example-epoint.js +91 -0
  12. package/examples/example-freekassa.js +26 -0
  13. package/{example-heleket.js → examples/example-heleket.js} +3 -3
  14. package/examples/example-konnect.js +227 -0
  15. package/examples/example-midtrans.js +80 -0
  16. package/examples/example-noonpayments.js +297 -0
  17. package/examples/example-nowpayments.js +289 -0
  18. package/examples/example-omise.js +27 -0
  19. package/examples/example-paycom.js +82 -0
  20. package/{example-paydisini.js → examples/example-paydisini.js} +1 -1
  21. package/examples/example-payid19.js +87 -0
  22. package/examples/example-paykun.js +29 -0
  23. package/examples/example-payme.js +202 -0
  24. package/examples/example-paymentwall.js +201 -0
  25. package/examples/example-paynet.js +104 -0
  26. package/examples/example-paynettr.js +18 -0
  27. package/examples/example-payoneer.js +74 -0
  28. package/examples/example-payop.js +351 -0
  29. package/examples/example-paypal.js +200 -0
  30. package/examples/example-payriff.js +89 -0
  31. package/examples/example-paysend.js +81 -0
  32. package/examples/example-payspace.js +103 -0
  33. package/examples/example-payssion.js +27 -0
  34. package/examples/example-paytabs.js +28 -0
  35. package/examples/example-paytm.js +78 -0
  36. package/examples/example-payuindia.js +108 -0
  37. package/examples/example-payulatam.js +75 -0
  38. package/examples/example-phonepe.js +27 -0
  39. package/examples/example-picpay.js +27 -0
  40. package/examples/example-plisio.js +84 -0
  41. package/examples/example-portwallet.js +90 -0
  42. package/examples/example-primepayments.js +250 -0
  43. package/examples/example-razorpay.js +30 -0
  44. package/examples/example-senangpay.js +28 -0
  45. package/examples/example-shopier-card.js +67 -0
  46. package/examples/example-shurjopay.js +94 -0
  47. package/examples/example-toyyibpay.js +80 -0
  48. package/examples/example-tripay.js +89 -0
  49. package/examples/example-unitpay.js +26 -0
  50. package/examples/example-urway.js +28 -0
  51. package/examples/example-volet.js +80 -0
  52. package/examples/example-xendit.js +28 -0
  53. package/examples/example-yallapay.js +253 -0
  54. package/examples/example-yookassa.js +27 -0
  55. package/examples/example-youcanpay.js +28 -0
  56. package/examples/example-zarinpal.js +98 -0
  57. package/{example.js → examples/example.js} +1 -1
  58. package/lib/2checkout.js +165 -0
  59. package/lib/amazonpay.js +161 -0
  60. package/lib/billplz.js +79 -0
  61. package/lib/bitpay.js +122 -0
  62. package/lib/cardcom.js +193 -0
  63. package/lib/cashfree.js +184 -0
  64. package/lib/checkout.js +248 -0
  65. package/lib/coinbase.js +150 -0
  66. package/lib/coingate.js +137 -0
  67. package/lib/coinpayments.js +245 -0
  68. package/lib/doku.js +173 -0
  69. package/lib/epay.js +175 -0
  70. package/lib/epoint.js +162 -0
  71. package/lib/freekassa.js +128 -0
  72. package/lib/instamojo.js +158 -0
  73. package/lib/konnect.js +211 -0
  74. package/lib/midtrans.js +227 -0
  75. package/lib/noonpayments.js +650 -0
  76. package/lib/nowpayments.js +361 -0
  77. package/lib/omise.js +150 -0
  78. package/lib/paddle.js +180 -0
  79. package/lib/paycom.js +216 -0
  80. package/lib/payid19.js +211 -0
  81. package/lib/paykun.js +144 -0
  82. package/lib/payme.js +302 -0
  83. package/lib/paymentwall.js +205 -0
  84. package/lib/paynet.js +186 -0
  85. package/lib/paynettr.js +165 -0
  86. package/lib/payoneer.js +128 -0
  87. package/lib/payop.js +345 -0
  88. package/lib/paypal.js +596 -0
  89. package/lib/payriff.js +148 -0
  90. package/lib/paysend.js +189 -0
  91. package/lib/payspace.js +168 -0
  92. package/lib/payssion.js +177 -0
  93. package/lib/paytabs.js +145 -0
  94. package/lib/paytm.js +253 -0
  95. package/lib/payuindia.js +162 -0
  96. package/lib/payulatam.js +179 -0
  97. package/lib/perfectmoney.js +143 -0
  98. package/lib/phonepe.js +174 -0
  99. package/lib/picpay.js +119 -0
  100. package/lib/plisio.js +234 -0
  101. package/lib/portwallet.js +152 -0
  102. package/lib/primepayments.js +338 -0
  103. package/lib/razorpay.js +205 -0
  104. package/lib/senangpay.js +130 -0
  105. package/lib/shopier_card.js +188 -0
  106. package/lib/shurjopay.js +159 -0
  107. package/lib/toyyibpay.js +151 -0
  108. package/lib/tripay.js +220 -0
  109. package/lib/unitpay.js +223 -0
  110. package/lib/urway.js +182 -0
  111. package/lib/volet.js +147 -0
  112. package/lib/xendit.js +206 -0
  113. package/lib/yallapay.js +319 -0
  114. package/lib/yookassa.js +193 -0
  115. package/lib/youcanpay.js +124 -0
  116. package/lib/zarinpal.js +157 -0
  117. package/package.json +138 -64
  118. package/readme.md +348 -105
  119. package/reported.md +347 -0
  120. package/test.js +492 -0
  121. package/lib/vallet.js +0 -22
  122. /package/{example-anypay.js → examples/example-anypay.js} +0 -0
  123. /package/{example-bufpay.js → examples/example-bufpay.js} +0 -0
  124. /package/{example-cryptomus.js → examples/example-cryptomus.js} +0 -0
  125. /package/{example-esnekpos.js → examples/example-esnekpos.js} +0 -0
  126. /package/{example-fedapay.js → examples/example-fedapay.js} +0 -0
  127. /package/{example-iyzico.js → examples/example-iyzico.js} +0 -0
  128. /package/{example-papara.js → examples/example-papara.js} +0 -0
  129. /package/{example-payeer.js → examples/example-payeer.js} +0 -0
  130. /package/{example-paymaya.js → examples/example-paymaya.js} +0 -0
  131. /package/{example-shopier.js → examples/example-shopier.js} +0 -0
  132. /package/{ipaymu.js → examples/ipaymu.js} +0 -0
  133. /package/{oderopay.js → examples/oderopay.js} +0 -0
@@ -0,0 +1,338 @@
1
+ /**
2
+ * PrimePayments - JavaScript client for PrimePayments payment service
3
+ */
4
+ class PrimePayments {
5
+ /**
6
+ * Create a new PrimePayments client
7
+ * @param {Object} config - Configuration options
8
+ * @param {string} config.projectId - Project ID
9
+ * @param {string} config.secretWord1 - Secret word 1 for signing requests
10
+ * @param {string} config.secretWord2 - Secret word 2 for verifying notifications
11
+ * @param {string} config.payoutKey - Key for payout operations
12
+ */
13
+ constructor(config) {
14
+ this.config = config;
15
+ this.apiUrl = 'https://pay.primepayments.io/API/v2/';
16
+ }
17
+
18
+ /**
19
+ * Calculate MD5 hash
20
+ * @param {string} str - Input string
21
+ * @returns {string} - MD5 hash
22
+ */
23
+ md5(str) {
24
+ return require('crypto').createHash('md5').update(str).digest('hex');
25
+ }
26
+
27
+ /**
28
+ * Make an API request to PrimePayments
29
+ * @param {Object} data - Request data
30
+ * @returns {Promise<Object>} - Response data
31
+ */
32
+ async makeRequest(data) {
33
+ const queryString = Object.entries(data)
34
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
35
+ .join('&');
36
+
37
+ try {
38
+ const response = await fetch(this.apiUrl, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/x-www-form-urlencoded',
42
+ },
43
+ body: queryString
44
+ });
45
+
46
+ const result = await response.json();
47
+ return result;
48
+ } catch (error) {
49
+ throw new Error(`PrimePayments API request failed: ${error.message}`);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Initialize a payment and get payment form URL
55
+ * @param {Object} options - Payment options
56
+ * @param {number} options.sum - Payment amount
57
+ * @param {string} options.currency - Payment currency (RUB, UAH, USD, EUR)
58
+ * @param {string} options.innerID - Internal ID in your system
59
+ * @param {string} options.email - Customer email
60
+ * @param {string} [options.payWay] - Preferred payment method (1-cards, 2-Yandex, etc.)
61
+ * @param {string} [options.comment] - Payment description
62
+ * @param {boolean} [options.needFailNotice] - Send notification on payment failure
63
+ * @param {string} [options.lang] - Form language
64
+ * @param {boolean} [options.strict_payWay] - Force specified payment method
65
+ * @param {boolean} [options.block_payWay] - Block other payment methods
66
+ * @param {boolean} [options.directPay] - Direct payment without intermediate page
67
+ * @returns {Promise<Object>} - Response with payment URL
68
+ */
69
+ async initPayment(options) {
70
+ const data = {
71
+ action: 'initPayment',
72
+ project: this.config.projectId,
73
+ sum: options.sum,
74
+ currency: options.currency,
75
+ innerID: options.innerID,
76
+ email: options.email,
77
+ };
78
+
79
+ if (options.payWay) data.payWay = options.payWay;
80
+ if (options.comment) data.comment = options.comment;
81
+ if (options.needFailNotice) data.needFailNotice = options.needFailNotice;
82
+ if (options.lang) data.lang = options.lang;
83
+ if (options.strict_payWay) data.strict_payWay = options.strict_payWay;
84
+ if (options.block_payWay) data.block_payWay = options.block_payWay;
85
+ if (options.directPay) data.directPay = options.directPay;
86
+
87
+ // Calculate signature
88
+ let signString = this.config.secretWord1 + data.action + data.project +
89
+ data.sum + data.currency + data.innerID + data.email;
90
+
91
+ if (data.payWay) signString += data.payWay;
92
+
93
+ data.sign = this.md5(signString);
94
+
95
+ return this.makeRequest(data);
96
+ }
97
+
98
+ /**
99
+ * Initialize a payout
100
+ * @param {Object} options - Payout options
101
+ * @param {number} options.sum - Payout amount
102
+ * @param {string} options.currency - Payout currency
103
+ * @param {string} options.payWay - Payout method
104
+ * @param {string} options.email - Recipient email
105
+ * @param {string} options.purse - Card number or wallet
106
+ * @param {string} [options.comment] - Payout description
107
+ * @param {string} [options.cardholder] - Card holder name
108
+ * @param {string} [options.SBP_id] - SBP bank identifier
109
+ * @param {string} [options.needUnique] - Unique identifier for the payout
110
+ * @returns {Promise<Object>} - Response with payout ID
111
+ */
112
+ async initPayout(options) {
113
+ const data = {
114
+ action: 'initPayout',
115
+ project: this.config.projectId,
116
+ sum: options.sum,
117
+ currency: options.currency,
118
+ payWay: options.payWay,
119
+ email: options.email,
120
+ purse: options.purse
121
+ };
122
+
123
+ if (options.comment) data.comment = options.comment;
124
+ if (options.cardholder) data.cardholder = options.cardholder;
125
+ if (options.SBP_id) data.SBP_id = options.SBP_id;
126
+ if (options.needUnique) data.needUnique = options.needUnique;
127
+
128
+ // Calculate signature
129
+ const signString = this.config.payoutKey + data.action + data.project +
130
+ data.sum + data.currency + data.payWay + data.email + data.purse;
131
+
132
+ data.sign = this.md5(signString);
133
+
134
+ return this.makeRequest(data);
135
+ }
136
+
137
+ /**
138
+ * Get order information
139
+ * @param {string} orderID - Order ID
140
+ * @returns {Promise<Object>} - Order information
141
+ */
142
+ async getOrderInfo(orderID) {
143
+ const data = {
144
+ action: 'getOrderInfo',
145
+ project: this.config.projectId,
146
+ orderID: orderID
147
+ };
148
+
149
+ // Calculate signature
150
+ data.sign = this.md5(this.config.secretWord1 + data.action + data.project + data.orderID);
151
+
152
+ return this.makeRequest(data);
153
+ }
154
+
155
+ /**
156
+ * Refund a payment
157
+ * @param {string} orderID - Order ID to refund
158
+ * @returns {Promise<Object>} - Refund result
159
+ */
160
+ async refund(orderID) {
161
+ const data = {
162
+ action: 'refund',
163
+ orderID: orderID
164
+ };
165
+
166
+ // Calculate signature
167
+ data.sign = this.md5(this.config.secretWord1 + data.action + data.orderID);
168
+
169
+ return this.makeRequest(data);
170
+ }
171
+
172
+ /**
173
+ * Get project balance
174
+ * @returns {Promise<Object>} - Project balance information
175
+ */
176
+ async getProjectBalance() {
177
+ const data = {
178
+ action: 'getProjectBalance',
179
+ project: this.config.projectId
180
+ };
181
+
182
+ // Calculate signature
183
+ data.sign = this.md5(this.config.secretWord1 + data.action + data.project);
184
+
185
+ return this.makeRequest(data);
186
+ }
187
+
188
+ /**
189
+ * Get payout information
190
+ * @param {string} payoutID - Payout ID
191
+ * @returns {Promise<Object>} - Payout information
192
+ */
193
+ async getPayoutInfo(payoutID) {
194
+ const data = {
195
+ action: 'getPayoutInfo',
196
+ project: this.config.projectId,
197
+ payoutID: payoutID
198
+ };
199
+
200
+ // Calculate signature
201
+ data.sign = this.md5(this.config.secretWord1 + data.action + data.project + data.payoutID);
202
+
203
+ return this.makeRequest(data);
204
+ }
205
+
206
+ /**
207
+ * Get project information
208
+ * @returns {Promise<Object>} - Project information and available payment methods
209
+ */
210
+ async getProjectInfo() {
211
+ const data = {
212
+ action: 'getProjectInfo',
213
+ project: this.config.projectId
214
+ };
215
+
216
+ // Calculate signature
217
+ data.sign = this.md5(this.config.secretWord1 + data.action + data.project);
218
+
219
+ return this.makeRequest(data);
220
+ }
221
+
222
+ /**
223
+ * Get exchange rates
224
+ * @returns {Promise<Object>} - Exchange rates information
225
+ */
226
+ async getExchangeRates() {
227
+ const data = {
228
+ action: 'getExchangeRates'
229
+ };
230
+
231
+ return this.makeRequest(data);
232
+ }
233
+
234
+ /**
235
+ * Verify payment notification
236
+ * @param {Object} postData - POST data from notification
237
+ * @returns {boolean} - True if signature is valid
238
+ */
239
+ verifyPaymentNotification(postData) {
240
+ if (postData.action === 'order_payed') {
241
+ const hash = this.md5(this.config.secretWord2 + postData.orderID +
242
+ postData.payWay + postData.innerID +
243
+ postData.sum + postData.webmaster_profit);
244
+
245
+ return hash === postData.sign;
246
+ } else if (postData.action === 'order_cancel') {
247
+ const hash = this.md5(this.config.secretWord2 + postData.orderID + postData.innerID);
248
+
249
+ return hash === postData.sign;
250
+ }
251
+
252
+ return false;
253
+ }
254
+
255
+ /**
256
+ * Create payment (wrapper for initPayment)
257
+ * @param {Object} paymentData - Payment data
258
+ * @returns {Promise<Object>} - Payment result
259
+ */
260
+ async createPayment(paymentData) {
261
+ try {
262
+ const result = await this.initPayment({
263
+ amount: paymentData.amount,
264
+ currency: paymentData.currency || 'USD',
265
+ description: paymentData.description || 'Payment',
266
+ order_id: paymentData.orderId,
267
+ success_url: paymentData.callback_link,
268
+ fail_url: paymentData.fail_link
269
+ });
270
+
271
+ if (result.result === 'ok') {
272
+ return {
273
+ success: true,
274
+ paymentUrl: result.payment_url,
275
+ transactionId: result.order_id,
276
+ amount: paymentData.amount,
277
+ currency: paymentData.currency
278
+ };
279
+ } else {
280
+ throw new Error(result.message || 'Payment creation failed');
281
+ }
282
+ } catch (error) {
283
+ throw new Error(`PrimePayments payment creation failed: ${error.message}`);
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Handle callback/notification
289
+ * @param {Object} callbackData - Callback data
290
+ * @returns {Promise<Object>} - Callback result
291
+ */
292
+ async handleCallback(callbackData) {
293
+ try {
294
+ // Verify notification with secret word 2
295
+ const isValid = this.verifyNotification(callbackData);
296
+
297
+ if (!isValid) {
298
+ return {
299
+ success: false,
300
+ status: 'invalid',
301
+ rawData: callbackData
302
+ };
303
+ }
304
+
305
+ const orderStatus = callbackData.status;
306
+ const orderId = callbackData.order_id;
307
+
308
+ if (orderStatus === 'success') {
309
+ return {
310
+ success: true,
311
+ transactionId: orderId,
312
+ status: 'completed',
313
+ amount: parseFloat(callbackData.amount),
314
+ currency: callbackData.currency,
315
+ rawData: callbackData
316
+ };
317
+ } else if (orderStatus === 'fail') {
318
+ return {
319
+ success: false,
320
+ status: 'failed',
321
+ transactionId: orderId,
322
+ rawData: callbackData
323
+ };
324
+ } else {
325
+ return {
326
+ success: false,
327
+ status: 'pending',
328
+ transactionId: orderId,
329
+ rawData: callbackData
330
+ };
331
+ }
332
+ } catch (error) {
333
+ throw new Error(`PrimePayments callback handling failed: ${error.message}`);
334
+ }
335
+ }
336
+ }
337
+
338
+ module.exports = PrimePayments;
@@ -0,0 +1,205 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class RazorpayClient {
5
+ constructor(config) {
6
+ const requiredFields = ['keyId', 'keySecret'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ this.keyId = config.keyId;
12
+ this.keySecret = config.keySecret;
13
+ this.baseURL = 'https://api.razorpay.com/v1';
14
+
15
+ this.client = axios.create({
16
+ baseURL: this.baseURL,
17
+ auth: {
18
+ username: this.keyId,
19
+ password: this.keySecret
20
+ },
21
+ headers: {
22
+ 'Content-Type': 'application/json'
23
+ }
24
+ });
25
+ }
26
+
27
+ async createPayment(options) {
28
+ try {
29
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
30
+
31
+ // Create Razorpay order
32
+ const orderData = {
33
+ amount: Math.round(parseFloat(options.amount) * 100), // Amount in paise
34
+ currency: options.currency || 'INR',
35
+ receipt: orderId,
36
+ notes: {
37
+ description: options.description || options.name || 'Payment',
38
+ customer_name: options.name || '',
39
+ customer_email: options.email || '',
40
+ customer_phone: options.phone || ''
41
+ }
42
+ };
43
+
44
+ const response = await this.client.post('/orders', orderData);
45
+
46
+ // For Razorpay, you need to use Checkout.js on frontend
47
+ // This returns the order details needed for checkout
48
+ return {
49
+ status: 'success',
50
+ data: {
51
+ orderId: response.data.id,
52
+ orderIdCustom: orderId,
53
+ amount: response.data.amount / 100,
54
+ currency: response.data.currency,
55
+ status: response.data.status,
56
+ // These are needed for Razorpay Checkout.js
57
+ keyId: this.keyId,
58
+ name: options.merchantName || 'Your Business',
59
+ description: options.description || 'Payment',
60
+ prefill: {
61
+ name: options.name || '',
62
+ email: options.email || '',
63
+ contact: options.phone || ''
64
+ },
65
+ callback_url: options.callbackUrl || options.callback_link,
66
+ redirect: options.redirect !== false
67
+ }
68
+ };
69
+ } catch (error) {
70
+ throw new Error(`Payment creation error: ${error.response?.data?.error?.description || error.message}`);
71
+ }
72
+ }
73
+
74
+ async handleCallback(callbackData) {
75
+ try {
76
+ // Verify payment signature
77
+ const verification = await this.verifyPaymentSignature(callbackData);
78
+
79
+ if (!verification.status) {
80
+ throw new Error(verification.error.message);
81
+ }
82
+
83
+ // Get payment details
84
+ const payment = await this.getPaymentDetails(callbackData.razorpay_payment_id);
85
+
86
+ // Status mapping
87
+ const statusMapping = {
88
+ 'captured': 'success',
89
+ 'authorized': 'success',
90
+ 'refunded': 'refunded',
91
+ 'failed': 'failed'
92
+ };
93
+
94
+ return {
95
+ status: statusMapping[payment.status] || 'unknown',
96
+ orderId: payment.notes?.order_id || payment.order_id,
97
+ paymentId: payment.id,
98
+ amount: payment.amount / 100,
99
+ currency: payment.currency,
100
+ paymentStatus: payment.status,
101
+ method: payment.method,
102
+ email: payment.email,
103
+ contact: payment.contact,
104
+ fee: payment.fee / 100,
105
+ tax: payment.tax / 100
106
+ };
107
+ } catch (error) {
108
+ throw new Error(`Error in Razorpay callback handling: ${error.message}`);
109
+ }
110
+ }
111
+
112
+ async verifyPaymentSignature(data) {
113
+ try {
114
+ const expectedSignature = crypto
115
+ .createHmac('sha256', this.keySecret)
116
+ .update(data.razorpay_order_id + '|' + data.razorpay_payment_id)
117
+ .digest('hex');
118
+
119
+ if (expectedSignature !== data.razorpay_signature) {
120
+ return {
121
+ status: false,
122
+ error: {
123
+ code: 401,
124
+ message: 'Invalid payment signature'
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 getPaymentDetails(paymentId) {
145
+ try {
146
+ const response = await this.client.get(`/payments/${paymentId}`);
147
+ return response.data;
148
+ } catch (error) {
149
+ throw new Error(`Error getting payment details: ${error.response?.data?.error?.description || error.message}`);
150
+ }
151
+ }
152
+
153
+ async getOrderDetails(orderId) {
154
+ try {
155
+ const response = await this.client.get(`/orders/${orderId}`);
156
+ return response.data;
157
+ } catch (error) {
158
+ throw new Error(`Error getting order details: ${error.response?.data?.error?.description || error.message}`);
159
+ }
160
+ }
161
+
162
+ async capturePayment(paymentId, amount) {
163
+ try {
164
+ const response = await this.client.post(`/payments/${paymentId}/capture`, {
165
+ amount: Math.round(parseFloat(amount) * 100),
166
+ currency: 'INR'
167
+ });
168
+
169
+ return response.data;
170
+ } catch (error) {
171
+ throw new Error(`Error capturing payment: ${error.response?.data?.error?.description || error.message}`);
172
+ }
173
+ }
174
+
175
+ async createRefund(paymentId, options = {}) {
176
+ try {
177
+ const refundData = {
178
+ amount: options.amount ? Math.round(parseFloat(options.amount) * 100) : undefined,
179
+ speed: options.speed || 'normal', // normal or optimum
180
+ notes: options.notes || {},
181
+ receipt: options.receipt
182
+ };
183
+
184
+ const response = await this.client.post(`/payments/${paymentId}/refund`, refundData);
185
+ return response.data;
186
+ } catch (error) {
187
+ throw new Error(`Error creating refund: ${error.response?.data?.error?.description || error.message}`);
188
+ }
189
+ }
190
+
191
+ async verifyWebhookSignature(webhookBody, webhookSignature, webhookSecret) {
192
+ try {
193
+ const expectedSignature = crypto
194
+ .createHmac('sha256', webhookSecret)
195
+ .update(webhookBody)
196
+ .digest('hex');
197
+
198
+ return expectedSignature === webhookSignature;
199
+ } catch (error) {
200
+ return false;
201
+ }
202
+ }
203
+ }
204
+
205
+ module.exports = RazorpayClient;
@@ -0,0 +1,130 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class SenangPayClient {
5
+ constructor(config) {
6
+ const requiredFields = ['merchantId', 'secretKey'];
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.secretKey = config.secretKey;
13
+ this.baseURL = config.sandbox
14
+ ? 'https://sandbox.senangpay.my/payment'
15
+ : 'https://app.senangpay.my/payment';
16
+ }
17
+
18
+ generateHash(detail, amount, orderId) {
19
+ const hashString = this.secretKey + detail + amount + orderId;
20
+ return crypto.createHash('md5').update(hashString).digest('hex');
21
+ }
22
+
23
+ async createPayment(options) {
24
+ try {
25
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
26
+ const amount = parseFloat(options.amount).toFixed(2);
27
+ const detail = options.description || options.name || 'Payment';
28
+
29
+ const hash = this.generateHash(detail, amount, orderId);
30
+
31
+ const paymentData = {
32
+ detail: detail,
33
+ amount: amount,
34
+ order_id: orderId,
35
+ name: options.name || options.customerName || '',
36
+ email: options.email || '',
37
+ phone: options.phone || '',
38
+ hash: hash
39
+ };
40
+
41
+ // Create payment URL
42
+ const params = new URLSearchParams(paymentData);
43
+ const paymentUrl = `${this.baseURL}/${this.merchantId}?${params.toString()}`;
44
+
45
+ return {
46
+ status: 'success',
47
+ data: {
48
+ url: paymentUrl,
49
+ orderId: orderId,
50
+ amount: amount,
51
+ currency: 'MYR',
52
+ hash: hash
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
+ // Status mapping
69
+ const statusMapping = {
70
+ '1': 'success', // Success
71
+ '0': 'failed' // Failed
72
+ };
73
+
74
+ return {
75
+ status: statusMapping[callbackData.status_id] || 'unknown',
76
+ orderId: callbackData.order_id,
77
+ transactionId: callbackData.transaction_id,
78
+ amount: parseFloat(callbackData.amount),
79
+ currency: 'MYR',
80
+ paymentStatus: callbackData.status_id === '1' ? 'completed' : 'failed',
81
+ message: callbackData.msg
82
+ };
83
+ } catch (error) {
84
+ throw new Error(`Error in SenangPay callback handling: ${error.message}`);
85
+ }
86
+ }
87
+
88
+ async verifyCallback(data) {
89
+ try {
90
+ const receivedHash = data.hash;
91
+ const hashString = this.secretKey + data.status_id + data.order_id + data.transaction_id + data.msg;
92
+ const expectedHash = crypto.createHash('md5').update(hashString).digest('hex');
93
+
94
+ if (receivedHash !== expectedHash) {
95
+ return {
96
+ status: false,
97
+ error: {
98
+ code: 401,
99
+ message: 'Invalid hash'
100
+ }
101
+ };
102
+ }
103
+
104
+ return {
105
+ status: true,
106
+ data: data
107
+ };
108
+ } catch (error) {
109
+ return {
110
+ status: false,
111
+ error: {
112
+ code: 500,
113
+ message: error.message
114
+ }
115
+ };
116
+ }
117
+ }
118
+
119
+ async getTransactionStatus(orderId) {
120
+ try {
121
+ // SenangPay doesn't have a standard API for checking transaction status
122
+ // This would need to be implemented based on their specific API if available
123
+ throw new Error('Transaction status check not available in standard SenangPay integration');
124
+ } catch (error) {
125
+ throw new Error(`Error getting transaction status: ${error.message}`);
126
+ }
127
+ }
128
+ }
129
+
130
+ module.exports = SenangPayClient;