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.
Files changed (131) 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/examples/example-heleket.js +139 -0
  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-shurjopay.js +94 -0
  46. package/examples/example-toyyibpay.js +80 -0
  47. package/examples/example-tripay.js +89 -0
  48. package/examples/example-unitpay.js +26 -0
  49. package/examples/example-urway.js +28 -0
  50. package/examples/example-volet.js +80 -0
  51. package/examples/example-xendit.js +28 -0
  52. package/examples/example-yallapay.js +253 -0
  53. package/examples/example-yookassa.js +27 -0
  54. package/examples/example-youcanpay.js +28 -0
  55. package/examples/example-zarinpal.js +98 -0
  56. package/{example.js → examples/example.js} +1 -1
  57. package/lib/2checkout.js +165 -0
  58. package/lib/amazonpay.js +161 -0
  59. package/lib/bitpay.js +122 -0
  60. package/lib/cardcom.js +193 -0
  61. package/lib/cashfree.js +184 -0
  62. package/lib/checkout.js +248 -0
  63. package/lib/coinbase.js +150 -0
  64. package/lib/coingate.js +137 -0
  65. package/lib/coinpayments.js +245 -0
  66. package/lib/doku.js +173 -0
  67. package/lib/epay.js +175 -0
  68. package/lib/epoint.js +162 -0
  69. package/lib/freekassa.js +128 -0
  70. package/lib/heleket.js +67 -1
  71. package/lib/instamojo.js +158 -0
  72. package/lib/konnect.js +211 -0
  73. package/lib/midtrans.js +227 -0
  74. package/lib/noonpayments.js +650 -0
  75. package/lib/nowpayments.js +311 -0
  76. package/lib/omise.js +150 -0
  77. package/lib/paddle.js +180 -0
  78. package/lib/paycom.js +216 -0
  79. package/lib/payid19.js +211 -0
  80. package/lib/paykun.js +144 -0
  81. package/lib/payme.js +302 -0
  82. package/lib/paymentwall.js +205 -0
  83. package/lib/paynet.js +186 -0
  84. package/lib/paynettr.js +165 -0
  85. package/lib/payoneer.js +128 -0
  86. package/lib/payop.js +256 -0
  87. package/lib/paypal.js +542 -0
  88. package/lib/payriff.js +148 -0
  89. package/lib/paysend.js +189 -0
  90. package/lib/payspace.js +168 -0
  91. package/lib/payssion.js +177 -0
  92. package/lib/paytabs.js +145 -0
  93. package/lib/paytm.js +253 -0
  94. package/lib/payuindia.js +162 -0
  95. package/lib/payulatam.js +179 -0
  96. package/lib/perfectmoney.js +143 -0
  97. package/lib/phonepe.js +174 -0
  98. package/lib/picpay.js +119 -0
  99. package/lib/plisio.js +234 -0
  100. package/lib/portwallet.js +152 -0
  101. package/lib/primepayments.js +256 -0
  102. package/lib/razorpay.js +205 -0
  103. package/lib/senangpay.js +130 -0
  104. package/lib/shurjopay.js +159 -0
  105. package/lib/toyyibpay.js +151 -0
  106. package/lib/tripay.js +220 -0
  107. package/lib/unitpay.js +223 -0
  108. package/lib/urway.js +182 -0
  109. package/lib/volet.js +147 -0
  110. package/lib/xendit.js +206 -0
  111. package/lib/yallapay.js +279 -0
  112. package/lib/yookassa.js +193 -0
  113. package/lib/youcanpay.js +124 -0
  114. package/lib/zarinpal.js +157 -0
  115. package/package.json +138 -64
  116. package/readme.md +348 -105
  117. package/test.js +492 -0
  118. package/example-heleket.js +0 -83
  119. package/lib/vallet.js +0 -22
  120. /package/{example-anypay.js → examples/example-anypay.js} +0 -0
  121. /package/{example-bufpay.js → examples/example-bufpay.js} +0 -0
  122. /package/{example-cryptomus.js → examples/example-cryptomus.js} +0 -0
  123. /package/{example-esnekpos.js → examples/example-esnekpos.js} +0 -0
  124. /package/{example-fedapay.js → examples/example-fedapay.js} +0 -0
  125. /package/{example-iyzico.js → examples/example-iyzico.js} +0 -0
  126. /package/{example-papara.js → examples/example-papara.js} +0 -0
  127. /package/{example-payeer.js → examples/example-payeer.js} +0 -0
  128. /package/{example-paymaya.js → examples/example-paymaya.js} +0 -0
  129. /package/{example-shopier.js → examples/example-shopier.js} +0 -0
  130. /package/{ipaymu.js → examples/ipaymu.js} +0 -0
  131. /package/{oderopay.js → examples/oderopay.js} +0 -0
@@ -0,0 +1,161 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class AmazonPayClient {
5
+ constructor(config) {
6
+ const requiredFields = ['merchantId', 'accessKey', '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.accessKey = config.accessKey;
13
+ this.secretKey = config.secretKey;
14
+ this.region = config.region || 'us'; // us, eu, jp
15
+ this.sandbox = config.sandbox || false;
16
+
17
+ const regionUrls = {
18
+ us: this.sandbox ? 'https://pay-api.amazon.com/sandbox' : 'https://pay-api.amazon.com/live',
19
+ eu: this.sandbox ? 'https://pay-api.amazon.eu/sandbox' : 'https://pay-api.amazon.eu/live',
20
+ jp: this.sandbox ? 'https://pay-api.amazon.jp/sandbox' : 'https://pay-api.amazon.jp/live'
21
+ };
22
+
23
+ this.baseURL = regionUrls[this.region];
24
+
25
+ this.client = axios.create({
26
+ baseURL: this.baseURL,
27
+ headers: {
28
+ 'Content-Type': 'application/json'
29
+ }
30
+ });
31
+ }
32
+
33
+ generateSignature(payload) {
34
+ return crypto
35
+ .createHmac('sha256', this.secretKey)
36
+ .update(payload)
37
+ .digest('base64');
38
+ }
39
+
40
+ async createPayment(options) {
41
+ try {
42
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
43
+ const timestamp = new Date().toISOString();
44
+
45
+ const payloadData = {
46
+ webCheckoutDetails: {
47
+ checkoutReviewReturnUrl: options.successUrl || options.callback_link
48
+ },
49
+ storeId: this.merchantId,
50
+ chargePermissionType: 'OneTime',
51
+ recurringMetadata: null,
52
+ paymentDetails: {
53
+ paymentIntent: 'Authorize',
54
+ chargeAmount: {
55
+ amount: parseFloat(options.amount).toFixed(2),
56
+ currencyCode: options.currency || 'USD'
57
+ }
58
+ },
59
+ merchantMetadata: {
60
+ merchantReferenceId: orderId,
61
+ merchantStoreName: options.storeName || 'Store',
62
+ noteToBuyer: options.description || ''
63
+ }
64
+ };
65
+
66
+ const payload = JSON.stringify(payloadData);
67
+ const signature = this.generateSignature(payload);
68
+
69
+ const response = await this.client.post('/v2/checkoutSessions', payloadData, {
70
+ headers: {
71
+ 'x-amz-pay-date': timestamp,
72
+ 'x-amz-pay-region': this.region,
73
+ 'Authorization': `AMZN-PAY-RSASSA-PSS ${signature}`
74
+ }
75
+ });
76
+
77
+ return {
78
+ status: 'success',
79
+ data: {
80
+ checkoutSessionId: response.data.checkoutSessionId,
81
+ webCheckoutDetails: response.data.webCheckoutDetails,
82
+ url: response.data.webCheckoutDetails?.amazonPayRedirectUrl,
83
+ orderId: orderId,
84
+ amount: payloadData.paymentDetails.chargeAmount.amount,
85
+ currency: payloadData.paymentDetails.chargeAmount.currencyCode
86
+ }
87
+ };
88
+ } catch (error) {
89
+ throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
90
+ }
91
+ }
92
+
93
+ async handleCallback(callbackData) {
94
+ try {
95
+ const checkoutSessionId = callbackData.amazonCheckoutSessionId;
96
+
97
+ if (!checkoutSessionId) {
98
+ throw new Error('Checkout session ID not found in callback data');
99
+ }
100
+
101
+ // Get checkout session details
102
+ const session = await this.getCheckoutSession(checkoutSessionId);
103
+
104
+ // Status mapping
105
+ const statusMapping = {
106
+ 'Open': 'pending',
107
+ 'Completed': 'success',
108
+ 'Canceled': 'failed',
109
+ 'Expired': 'failed'
110
+ };
111
+
112
+ return {
113
+ status: statusMapping[session.statusDetails?.state] || 'unknown',
114
+ orderId: session.merchantMetadata?.merchantReferenceId,
115
+ transactionId: checkoutSessionId,
116
+ amount: parseFloat(session.chargeAmount?.amount || 0),
117
+ currency: session.chargeAmount?.currencyCode,
118
+ paymentStatus: session.statusDetails?.state,
119
+ buyer: session.buyer
120
+ };
121
+ } catch (error) {
122
+ throw new Error(`Error in Amazon Pay callback handling: ${error.message}`);
123
+ }
124
+ }
125
+
126
+ async getCheckoutSession(checkoutSessionId) {
127
+ try {
128
+ const timestamp = new Date().toISOString();
129
+
130
+ const response = await this.client.get(`/v2/checkoutSessions/${checkoutSessionId}`, {
131
+ headers: {
132
+ 'x-amz-pay-date': timestamp,
133
+ 'x-amz-pay-region': this.region
134
+ }
135
+ });
136
+
137
+ return response.data;
138
+ } catch (error) {
139
+ throw new Error(`Error fetching checkout session: ${error.response?.data?.message || error.message}`);
140
+ }
141
+ }
142
+
143
+ async updateCheckoutSession(checkoutSessionId, updates) {
144
+ try {
145
+ const timestamp = new Date().toISOString();
146
+
147
+ const response = await this.client.patch(`/v2/checkoutSessions/${checkoutSessionId}`, updates, {
148
+ headers: {
149
+ 'x-amz-pay-date': timestamp,
150
+ 'x-amz-pay-region': this.region
151
+ }
152
+ });
153
+
154
+ return response.data;
155
+ } catch (error) {
156
+ throw new Error(`Error updating checkout session: ${error.response?.data?.message || error.message}`);
157
+ }
158
+ }
159
+ }
160
+
161
+ module.exports = AmazonPayClient;
package/lib/bitpay.js ADDED
@@ -0,0 +1,122 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class BitPayClient {
5
+ constructor(config) {
6
+ const requiredFields = ['apiToken'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ this.apiToken = config.apiToken;
12
+ this.environment = config.environment || 'test'; // 'test' or 'prod'
13
+ this.baseURL = this.environment === 'prod'
14
+ ? 'https://bitpay.com'
15
+ : 'https://test.bitpay.com';
16
+
17
+ this.client = axios.create({
18
+ baseURL: this.baseURL,
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ 'X-Accept-Version': '2.0.0',
22
+ 'Authorization': `Bearer ${this.apiToken}`
23
+ }
24
+ });
25
+ }
26
+
27
+ async createPayment(options) {
28
+ try {
29
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
30
+
31
+ const invoiceData = {
32
+ price: parseFloat(options.amount),
33
+ currency: options.currency || 'USD',
34
+ orderId: orderId,
35
+ itemDesc: options.description || options.name || 'Payment',
36
+ notificationURL: options.callbackUrl || options.callback_link,
37
+ redirectURL: options.successUrl || options.callback_link,
38
+ buyer: {
39
+ email: options.email || '',
40
+ name: options.name || ''
41
+ }
42
+ };
43
+
44
+ const response = await this.client.post('/invoices', invoiceData);
45
+
46
+ return {
47
+ status: 'success',
48
+ data: {
49
+ invoiceId: response.data.data.id,
50
+ url: response.data.data.url,
51
+ orderId: orderId,
52
+ amount: response.data.data.price,
53
+ currency: response.data.data.currency,
54
+ status: response.data.data.status
55
+ }
56
+ };
57
+ } catch (error) {
58
+ throw new Error(`Payment creation error: ${error.response?.data?.error || error.message}`);
59
+ }
60
+ }
61
+
62
+ async handleCallback(callbackData) {
63
+ try {
64
+ const invoiceId = callbackData.id || callbackData.data?.id;
65
+
66
+ if (!invoiceId) {
67
+ throw new Error('Invoice ID not found in callback data');
68
+ }
69
+
70
+ // Get invoice details
71
+ const invoice = await this.getInvoice(invoiceId);
72
+
73
+ // Status mapping
74
+ const statusMapping = {
75
+ 'confirmed': 'success',
76
+ 'complete': 'success',
77
+ 'paid': 'success',
78
+ 'new': 'pending',
79
+ 'expired': 'failed',
80
+ 'invalid': 'failed'
81
+ };
82
+
83
+ return {
84
+ status: statusMapping[invoice.status.toLowerCase()] || 'unknown',
85
+ orderId: invoice.orderId,
86
+ transactionId: invoice.id,
87
+ amount: parseFloat(invoice.price),
88
+ currency: invoice.currency,
89
+ paymentStatus: invoice.status,
90
+ exceptionStatus: invoice.exceptionStatus
91
+ };
92
+ } catch (error) {
93
+ throw new Error(`Error in BitPay callback handling: ${error.message}`);
94
+ }
95
+ }
96
+
97
+ async getInvoice(invoiceId) {
98
+ try {
99
+ const response = await this.client.get(`/invoices/${invoiceId}`);
100
+ return response.data.data;
101
+ } catch (error) {
102
+ throw new Error(`Error fetching invoice: ${error.response?.data?.error || error.message}`);
103
+ }
104
+ }
105
+
106
+ async refundInvoice(invoiceId, options = {}) {
107
+ try {
108
+ const refundData = {
109
+ amount: options.amount,
110
+ currency: options.currency,
111
+ preview: options.preview || false
112
+ };
113
+
114
+ const response = await this.client.post(`/invoices/${invoiceId}/refunds`, refundData);
115
+ return response.data.data;
116
+ } catch (error) {
117
+ throw new Error(`Error creating refund: ${error.response?.data?.error || error.message}`);
118
+ }
119
+ }
120
+ }
121
+
122
+ module.exports = BitPayClient;
package/lib/cardcom.js ADDED
@@ -0,0 +1,193 @@
1
+ const axios = require('axios');
2
+
3
+ class CardcomClient {
4
+ constructor(config) {
5
+ const requiredFields = ['terminalNumber', 'userName'];
6
+ for (let field of requiredFields) {
7
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
8
+ }
9
+
10
+ this.terminalNumber = config.terminalNumber;
11
+ this.userName = config.userName;
12
+ this.apiName = config.apiName || this.userName;
13
+ this.URL = 'https://secure.cardcom.solutions/api/v11';
14
+
15
+ this.client = axios.create({
16
+ baseURL: this.URL,
17
+ headers: {
18
+ 'Content-Type': 'application/json'
19
+ }
20
+ });
21
+
22
+ this.client.interceptors.response.use(response => {
23
+ return response;
24
+ }, error => {
25
+ if (error.response) {
26
+ throw new Error(`Cardcom API error: ${error.response.data.ResponseMessage || error.message}`);
27
+ }
28
+ throw new Error(`Cardcom API error: ${error.message}`);
29
+ });
30
+ }
31
+
32
+ async createPayment(options) {
33
+ try {
34
+ const requestData = {
35
+ TerminalNumber: this.terminalNumber,
36
+ UserName: this.userName,
37
+ APILevel: 10,
38
+ Operation: {
39
+ Type: 2, // Create Invoice
40
+ SumToBill: parseFloat(options.amount),
41
+ Currency: options.currency || 'ILS',
42
+ Description: options.description || options.name || 'Payment',
43
+ InvoiceHead: {
44
+ CustName: options.customerName || options.name || 'Customer',
45
+ SendByEmail: true,
46
+ CustEmail: options.email,
47
+ CustMobile: options.mobile || options.phone || '',
48
+ ExtendedInvoiceType: 1,
49
+ InvoiceType: options.invoiceType || 1,
50
+ Language: options.language || 'he'
51
+ }
52
+ },
53
+ ReturnValue: options.returnUrl || options.callback_link,
54
+ IndicatorUrl: options.callbackUrl || options.callback_link,
55
+ InternalDealNumber: options.internalDealNumber || options.orderId || `ORDER-${Date.now()}`
56
+ };
57
+
58
+ if (options.items && Array.isArray(options.items)) {
59
+ requestData.Operation.InvoiceLines = {
60
+ InvoiceLine: options.items
61
+ };
62
+ }
63
+
64
+ const response = await this.client.post('/LowProfile/CreateInvoice', requestData);
65
+
66
+ if (response.data.ResponseCode === 0) {
67
+ return {
68
+ status: 'success',
69
+ data: {
70
+ lowProfileId: response.data.LowProfileId,
71
+ lowProfileCode: response.data.LowProfileCode,
72
+ url: response.data.Url,
73
+ internalDealNumber: requestData.InternalDealNumber
74
+ }
75
+ };
76
+ } else {
77
+ throw new Error(response.data.ResponseMessage || 'Payment creation failed');
78
+ }
79
+ } catch (error) {
80
+ throw new Error(`Payment creation error: ${error.message}`);
81
+ }
82
+ }
83
+
84
+ async getInvoiceDetails(lowProfileId) {
85
+ try {
86
+ const requestData = {
87
+ TerminalNumber: this.terminalNumber,
88
+ UserName: this.userName,
89
+ LowProfileId: lowProfileId
90
+ };
91
+
92
+ const response = await this.client.post('/LowProfile/GetLowProfileIndicator', requestData);
93
+ return response.data;
94
+ } catch (error) {
95
+ throw new Error(`Invoice details error: ${error.message}`);
96
+ }
97
+ }
98
+
99
+ async handleCallback(callbackData) {
100
+ try {
101
+ const verification = await this.verifyCallback(callbackData);
102
+
103
+ if (!verification.status) {
104
+ throw new Error(verification.error.message);
105
+ }
106
+
107
+ const data = verification.data;
108
+
109
+ // Status mapping based on OperationResponse
110
+ const statusMapping = {
111
+ '0': 'success',
112
+ '1': 'failed'
113
+ };
114
+
115
+ return {
116
+ status: statusMapping[data.OperationResponse] || 'unknown',
117
+ lowProfileId: data.LowProfileId,
118
+ internalDealNumber: data.InternalDealNumber,
119
+ orderId: data.InternalDealNumber,
120
+ operationResponse: data.OperationResponse,
121
+ operationResponseText: data.OperationResponseText,
122
+ extendedResponseText: data.ExtendedResponseText
123
+ };
124
+ } catch (error) {
125
+ throw new Error(`Error in Cardcom callback handling: ${error.message}`);
126
+ }
127
+ }
128
+
129
+ async verifyCallback(data) {
130
+ try {
131
+ if (data.OperationResponse !== '0') {
132
+ return {
133
+ status: false,
134
+ error: {
135
+ code: 400,
136
+ message: data.ExtendedResponseText || 'Payment failed'
137
+ }
138
+ };
139
+ }
140
+
141
+ return {
142
+ status: true,
143
+ data: data
144
+ };
145
+ } catch (error) {
146
+ return {
147
+ status: false,
148
+ error: {
149
+ code: 500,
150
+ message: error.message
151
+ }
152
+ };
153
+ }
154
+ }
155
+
156
+ async chargeCard(options) {
157
+ try {
158
+ const requestData = {
159
+ TerminalNumber: this.terminalNumber,
160
+ UserName: this.userName,
161
+ APILevel: 10,
162
+ CardNumber: options.cardNumber,
163
+ DateMMYY: options.expiryDate, // MMYY format
164
+ CVV: options.cvv,
165
+ SumToBill: parseFloat(options.amount),
166
+ Currency: options.currency || 'ILS',
167
+ CustomerName: options.customerName || options.name || 'Customer',
168
+ CustomerEmail: options.email,
169
+ InternalDealNumber: options.internalDealNumber || options.orderId || `ORDER-${Date.now()}`,
170
+ IndicatorUrl: options.callbackUrl || options.callback_link
171
+ };
172
+
173
+ const response = await this.client.post('/DealWasSuccessful', requestData);
174
+
175
+ if (response.data.ResponseCode === 0) {
176
+ return {
177
+ status: 'success',
178
+ data: {
179
+ dealResponse: response.data.DealResponse,
180
+ internalDealNumber: response.data.InternalDealNumber,
181
+ confirmationNumber: response.data.ConfirmationNumber
182
+ }
183
+ };
184
+ } else {
185
+ throw new Error(response.data.ResponseMessage || 'Card charge failed');
186
+ }
187
+ } catch (error) {
188
+ throw new Error(`Card charge error: ${error.message}`);
189
+ }
190
+ }
191
+ }
192
+
193
+ module.exports = CardcomClient;
@@ -0,0 +1,184 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class CashfreeClient {
5
+ constructor(config) {
6
+ const requiredFields = ['appId', 'secretKey'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ this.appId = config.appId;
12
+ this.secretKey = config.secretKey;
13
+ this.environment = config.environment || 'production'; // 'sandbox' or 'production'
14
+ this.baseURL = this.environment === 'sandbox'
15
+ ? 'https://sandbox.cashfree.com/pg'
16
+ : 'https://api.cashfree.com/pg';
17
+
18
+ this.client = axios.create({
19
+ baseURL: this.baseURL,
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ 'x-client-id': this.appId,
23
+ 'x-client-secret': this.secretKey,
24
+ 'x-api-version': '2023-08-01'
25
+ }
26
+ });
27
+ }
28
+
29
+ async createPayment(options) {
30
+ try {
31
+ const orderId = options.orderId || `order_${Date.now()}`;
32
+
33
+ const orderData = {
34
+ order_id: orderId,
35
+ order_amount: parseFloat(options.amount),
36
+ order_currency: options.currency || 'INR',
37
+ customer_details: {
38
+ customer_id: options.customerId || `customer_${Date.now()}`,
39
+ customer_email: options.email || '',
40
+ customer_phone: options.phone || '',
41
+ customer_name: options.name || options.customerName || ''
42
+ },
43
+ order_meta: {
44
+ return_url: options.successUrl || options.callback_link,
45
+ notify_url: options.callbackUrl || options.callback_link
46
+ },
47
+ order_note: options.description || ''
48
+ };
49
+
50
+ const response = await this.client.post('/orders', orderData);
51
+
52
+ if (response.data.order_status === 'ACTIVE') {
53
+ return {
54
+ status: 'success',
55
+ data: {
56
+ orderId: orderId,
57
+ paymentSessionId: response.data.payment_session_id,
58
+ orderStatus: response.data.order_status,
59
+ amount: orderData.order_amount,
60
+ currency: orderData.order_currency,
61
+ // Payment link construction
62
+ url: `${this.baseURL}/checkout?order_id=${orderId}&payment_session_id=${response.data.payment_session_id}`
63
+ }
64
+ };
65
+ } else {
66
+ throw new Error('Order creation failed');
67
+ }
68
+ } catch (error) {
69
+ throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
70
+ }
71
+ }
72
+
73
+ async handleCallback(callbackData) {
74
+ try {
75
+ const verification = await this.verifyCallback(callbackData);
76
+
77
+ if (!verification.status) {
78
+ throw new Error(verification.error.message);
79
+ }
80
+
81
+ const orderId = callbackData.order_id || callbackData.orderId;
82
+
83
+ // Get order details
84
+ const order = await this.getOrder(orderId);
85
+
86
+ // Status mapping
87
+ const statusMapping = {
88
+ 'PAID': 'success',
89
+ 'ACTIVE': 'pending',
90
+ 'EXPIRED': 'failed',
91
+ 'TERMINATED': 'failed',
92
+ 'PENDING': 'pending'
93
+ };
94
+
95
+ return {
96
+ status: statusMapping[order.order_status] || 'unknown',
97
+ orderId: order.order_id,
98
+ transactionId: order.cf_order_id,
99
+ amount: parseFloat(order.order_amount),
100
+ currency: order.order_currency,
101
+ paymentStatus: order.order_status,
102
+ paymentMethod: order.payment_method
103
+ };
104
+ } catch (error) {
105
+ throw new Error(`Error in Cashfree callback handling: ${error.message}`);
106
+ }
107
+ }
108
+
109
+ async verifyCallback(data) {
110
+ try {
111
+ // Verify signature if present
112
+ if (data.signature) {
113
+ const { signature, ...callbackData } = data;
114
+ const signatureString = Object.keys(callbackData)
115
+ .sort()
116
+ .map(key => `${key}=${callbackData[key]}`)
117
+ .join('&');
118
+
119
+ const expectedSignature = crypto
120
+ .createHmac('sha256', this.secretKey)
121
+ .update(signatureString)
122
+ .digest('hex');
123
+
124
+ if (signature !== expectedSignature) {
125
+ return {
126
+ status: false,
127
+ error: {
128
+ code: 401,
129
+ message: 'Invalid signature'
130
+ }
131
+ };
132
+ }
133
+ }
134
+
135
+ return {
136
+ status: true,
137
+ data: data
138
+ };
139
+ } catch (error) {
140
+ return {
141
+ status: false,
142
+ error: {
143
+ code: 500,
144
+ message: error.message
145
+ }
146
+ };
147
+ }
148
+ }
149
+
150
+ async getOrder(orderId) {
151
+ try {
152
+ const response = await this.client.get(`/orders/${orderId}`);
153
+ return response.data;
154
+ } catch (error) {
155
+ throw new Error(`Error fetching order: ${error.response?.data?.message || error.message}`);
156
+ }
157
+ }
158
+
159
+ async getPayments(orderId) {
160
+ try {
161
+ const response = await this.client.get(`/orders/${orderId}/payments`);
162
+ return response.data;
163
+ } catch (error) {
164
+ throw new Error(`Error fetching payments: ${error.response?.data?.message || error.message}`);
165
+ }
166
+ }
167
+
168
+ async refundPayment(orderId, options = {}) {
169
+ try {
170
+ const refundData = {
171
+ refund_amount: options.amount,
172
+ refund_id: options.refundId || `refund_${Date.now()}`,
173
+ refund_note: options.note || 'Refund'
174
+ };
175
+
176
+ const response = await this.client.post(`/orders/${orderId}/refunds`, refundData);
177
+ return response.data;
178
+ } catch (error) {
179
+ throw new Error(`Error creating refund: ${error.response?.data?.message || error.message}`);
180
+ }
181
+ }
182
+ }
183
+
184
+ module.exports = CashfreeClient;