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,143 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class PerfectMoneyClient {
5
+ constructor(config) {
6
+ const requiredFields = ['accountId', 'passPhrase'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ this.accountId = config.accountId;
12
+ this.passPhrase = config.passPhrase;
13
+ this.alternatePassPhrase = config.alternatePassPhrase || this.passPhrase;
14
+ this.payeeAccount = config.payeeAccount || this.accountId;
15
+ this.baseURL = 'https://perfectmoney.com/api';
16
+ }
17
+
18
+ generateHash(data) {
19
+ const hashString = `${data.PAYMENT_ID}:${data.PAYEE_ACCOUNT}:${data.PAYMENT_AMOUNT}:${data.PAYMENT_UNITS}:${data.PAYMENT_BATCH_NUM}:${data.PAYER_ACCOUNT}:${this.alternatePassPhrase}:${data.TIMESTAMPGMT}`;
20
+
21
+ return crypto
22
+ .createHash('md5')
23
+ .update(hashString)
24
+ .digest('hex')
25
+ .toUpperCase();
26
+ }
27
+
28
+ async createPayment(options) {
29
+ try {
30
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
31
+
32
+ const paymentData = {
33
+ PAYEE_ACCOUNT: this.payeeAccount,
34
+ PAYEE_NAME: options.payeeName || 'Merchant',
35
+ PAYMENT_ID: orderId,
36
+ PAYMENT_AMOUNT: parseFloat(options.amount).toFixed(2),
37
+ PAYMENT_UNITS: options.currency || 'USD',
38
+ STATUS_URL: options.callbackUrl || options.callback_link,
39
+ PAYMENT_URL: options.successUrl || options.callback_link,
40
+ PAYMENT_URL_METHOD: 'GET',
41
+ NOPAYMENT_URL: options.failUrl || options.callback_link,
42
+ NOPAYMENT_URL_METHOD: 'GET',
43
+ SUGGESTED_MEMO: options.description || options.name || 'Payment',
44
+ BAGGAGE_FIELDS: `email=${options.email || ''}&name=${options.name || ''}`
45
+ };
46
+
47
+ // Create payment URL
48
+ const params = new URLSearchParams(paymentData);
49
+ const paymentUrl = `https://perfectmoney.com/api/step1.asp?${params.toString()}`;
50
+
51
+ return {
52
+ status: 'success',
53
+ data: {
54
+ url: paymentUrl,
55
+ orderId: orderId,
56
+ amount: paymentData.PAYMENT_AMOUNT,
57
+ currency: paymentData.PAYMENT_UNITS,
58
+ payeeAccount: this.payeeAccount
59
+ }
60
+ };
61
+ } catch (error) {
62
+ throw new Error(`Payment creation error: ${error.message}`);
63
+ }
64
+ }
65
+
66
+ async handleCallback(callbackData) {
67
+ try {
68
+ const verification = await this.verifyCallback(callbackData);
69
+
70
+ if (!verification.status) {
71
+ throw new Error(verification.error.message);
72
+ }
73
+
74
+ return {
75
+ status: 'success',
76
+ orderId: callbackData.PAYMENT_ID,
77
+ transactionId: callbackData.PAYMENT_BATCH_NUM,
78
+ amount: parseFloat(callbackData.PAYMENT_AMOUNT),
79
+ currency: callbackData.PAYMENT_UNITS,
80
+ paymentStatus: 'completed',
81
+ payerAccount: callbackData.PAYER_ACCOUNT,
82
+ timestampGMT: callbackData.TIMESTAMPGMT
83
+ };
84
+ } catch (error) {
85
+ throw new Error(`Error in Perfect Money callback handling: ${error.message}`);
86
+ }
87
+ }
88
+
89
+ async verifyCallback(data) {
90
+ try {
91
+ const receivedHash = data.V2_HASH;
92
+ const expectedHash = this.generateHash(data);
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 getBalance(accountId, password) {
120
+ try {
121
+ const response = await axios.get('https://perfectmoney.com/acct/balance.asp', {
122
+ params: {
123
+ AccountID: accountId || this.accountId,
124
+ PassPhrase: password || this.passPhrase
125
+ }
126
+ });
127
+
128
+ // Parse response (XML-like format)
129
+ const balances = {};
130
+ const matches = response.data.matchAll(/<input name='(.+?)' type='hidden' value='(.+?)'>/g);
131
+
132
+ for (const match of matches) {
133
+ balances[match[1]] = match[2];
134
+ }
135
+
136
+ return balances;
137
+ } catch (error) {
138
+ throw new Error(`Error getting balance: ${error.message}`);
139
+ }
140
+ }
141
+ }
142
+
143
+ module.exports = PerfectMoneyClient;
package/lib/phonepe.js ADDED
@@ -0,0 +1,174 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class PhonePeClient {
5
+ constructor(config) {
6
+ const requiredFields = ['merchantId', 'saltKey', 'saltIndex'];
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.saltKey = config.saltKey;
13
+ this.saltIndex = config.saltIndex;
14
+ this.baseURL = config.sandbox
15
+ ? 'https://api-preprod.phonepe.com/apis/pg-sandbox'
16
+ : 'https://api.phonepe.com/apis/hermes';
17
+
18
+ this.client = axios.create({
19
+ baseURL: this.baseURL,
20
+ headers: {
21
+ 'Content-Type': 'application/json'
22
+ }
23
+ });
24
+ }
25
+
26
+ generateChecksum(payload) {
27
+ const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');
28
+ const checksumString = base64Payload + '/pg/v1/pay' + this.saltKey;
29
+ const checksum = crypto.createHash('sha256').update(checksumString).digest('hex');
30
+ return checksum + '###' + this.saltIndex;
31
+ }
32
+
33
+ verifyChecksum(base64Response, checksumHeader) {
34
+ const [receivedChecksum] = checksumHeader.split('###');
35
+ const checksumString = base64Response + this.saltKey;
36
+ const expectedChecksum = crypto.createHash('sha256').update(checksumString).digest('hex');
37
+
38
+ return receivedChecksum === expectedChecksum;
39
+ }
40
+
41
+ async createPayment(options) {
42
+ try {
43
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
44
+ const transactionId = `TXN-${Date.now()}`;
45
+
46
+ const payload = {
47
+ merchantId: this.merchantId,
48
+ merchantTransactionId: transactionId,
49
+ merchantUserId: options.userId || `USER-${Date.now()}`,
50
+ amount: Math.round(parseFloat(options.amount) * 100), // Amount in paise
51
+ redirectUrl: options.successUrl || options.callback_link,
52
+ redirectMode: 'POST',
53
+ callbackUrl: options.callbackUrl || options.callback_link,
54
+ mobileNumber: options.phone || '',
55
+ paymentInstrument: {
56
+ type: options.paymentType || 'PAY_PAGE' // PAY_PAGE, UPI_COLLECT, etc.
57
+ }
58
+ };
59
+
60
+ const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');
61
+ const checksum = this.generateChecksum(payload);
62
+
63
+ const response = await this.client.post('/pg/v1/pay', {
64
+ request: base64Payload
65
+ }, {
66
+ headers: {
67
+ 'X-VERIFY': checksum
68
+ }
69
+ });
70
+
71
+ if (response.data.success) {
72
+ return {
73
+ status: 'success',
74
+ data: {
75
+ url: response.data.data.instrumentResponse.redirectInfo.url,
76
+ transactionId: transactionId,
77
+ orderId: orderId,
78
+ amount: payload.amount / 100,
79
+ currency: 'INR'
80
+ }
81
+ };
82
+ } else {
83
+ throw new Error(response.data.message || 'Payment creation failed');
84
+ }
85
+ } catch (error) {
86
+ throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
87
+ }
88
+ }
89
+
90
+ async handleCallback(callbackData) {
91
+ try {
92
+ const base64Response = callbackData.response;
93
+ const checksumHeader = callbackData['X-VERIFY'];
94
+
95
+ // Verify checksum
96
+ if (!this.verifyChecksum(base64Response, checksumHeader)) {
97
+ throw new Error('Invalid checksum');
98
+ }
99
+
100
+ // Decode response
101
+ const response = JSON.parse(Buffer.from(base64Response, 'base64').toString());
102
+
103
+ // Status mapping
104
+ const statusMapping = {
105
+ 'PAYMENT_SUCCESS': 'success',
106
+ 'PAYMENT_PENDING': 'pending',
107
+ 'PAYMENT_DECLINED': 'failed',
108
+ 'PAYMENT_ERROR': 'failed',
109
+ 'INTERNAL_SERVER_ERROR': 'failed'
110
+ };
111
+
112
+ return {
113
+ status: statusMapping[response.code] || 'unknown',
114
+ orderId: response.data.merchantOrderId,
115
+ transactionId: response.data.merchantTransactionId,
116
+ amount: response.data.amount / 100,
117
+ currency: 'INR',
118
+ paymentStatus: response.code,
119
+ paymentMethod: response.data.paymentInstrument?.type
120
+ };
121
+ } catch (error) {
122
+ throw new Error(`Error in PhonePe callback handling: ${error.message}`);
123
+ }
124
+ }
125
+
126
+ async checkStatus(transactionId) {
127
+ try {
128
+ const checksumString = `/pg/v1/status/${this.merchantId}/${transactionId}` + this.saltKey;
129
+ const checksum = crypto.createHash('sha256').update(checksumString).digest('hex') + '###' + this.saltIndex;
130
+
131
+ const response = await this.client.get(`/pg/v1/status/${this.merchantId}/${transactionId}`, {
132
+ headers: {
133
+ 'X-VERIFY': checksum,
134
+ 'X-MERCHANT-ID': this.merchantId
135
+ }
136
+ });
137
+
138
+ return response.data;
139
+ } catch (error) {
140
+ throw new Error(`Error checking status: ${error.response?.data?.message || error.message}`);
141
+ }
142
+ }
143
+
144
+ async refund(transactionId, options = {}) {
145
+ try {
146
+ const refundId = `REFUND-${Date.now()}`;
147
+
148
+ const payload = {
149
+ merchantId: this.merchantId,
150
+ merchantTransactionId: refundId,
151
+ originalTransactionId: transactionId,
152
+ amount: Math.round(parseFloat(options.amount) * 100),
153
+ callbackUrl: options.callbackUrl
154
+ };
155
+
156
+ const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');
157
+ const checksum = this.generateChecksum(payload);
158
+
159
+ const response = await this.client.post('/pg/v1/refund', {
160
+ request: base64Payload
161
+ }, {
162
+ headers: {
163
+ 'X-VERIFY': checksum
164
+ }
165
+ });
166
+
167
+ return response.data;
168
+ } catch (error) {
169
+ throw new Error(`Error processing refund: ${error.response?.data?.message || error.message}`);
170
+ }
171
+ }
172
+ }
173
+
174
+ module.exports = PhonePeClient;
package/lib/picpay.js ADDED
@@ -0,0 +1,119 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class PicPayClient {
5
+ constructor(config) {
6
+ const requiredFields = ['token', 'sellerToken'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ this.token = config.token;
12
+ this.sellerToken = config.sellerToken;
13
+ this.baseURL = 'https://appws.picpay.com/ecommerce/public';
14
+
15
+ this.client = axios.create({
16
+ baseURL: this.baseURL,
17
+ headers: {
18
+ 'Content-Type': 'application/json',
19
+ 'x-picpay-token': this.token,
20
+ 'x-seller-token': this.sellerToken
21
+ }
22
+ });
23
+ }
24
+
25
+ async createPayment(options) {
26
+ try {
27
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
28
+
29
+ const paymentData = {
30
+ referenceId: orderId,
31
+ callbackUrl: options.callbackUrl || options.callback_link,
32
+ returnUrl: options.successUrl || options.callback_link,
33
+ value: parseFloat(options.amount),
34
+ expiresAt: options.expiresAt || new Date(Date.now() + 24*60*60*1000).toISOString(),
35
+ buyer: {
36
+ firstName: options.firstName || options.name?.split(' ')[0] || '',
37
+ lastName: options.lastName || options.name?.split(' ').slice(1).join(' ') || '',
38
+ document: options.document || '',
39
+ email: options.email || '',
40
+ phone: options.phone || ''
41
+ }
42
+ };
43
+
44
+ const response = await this.client.post('/payments', paymentData);
45
+
46
+ return {
47
+ status: 'success',
48
+ data: {
49
+ referenceId: orderId,
50
+ paymentUrl: response.data.paymentUrl,
51
+ qrcode: response.data.qrcode,
52
+ amount: paymentData.value,
53
+ currency: 'BRL',
54
+ expiresAt: response.data.expiresAt
55
+ }
56
+ };
57
+ } catch (error) {
58
+ throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
59
+ }
60
+ }
61
+
62
+ async handleCallback(callbackData) {
63
+ try {
64
+ const referenceId = callbackData.referenceId;
65
+
66
+ if (!referenceId) {
67
+ throw new Error('Reference ID not found in callback data');
68
+ }
69
+
70
+ // Get payment status
71
+ const payment = await this.getPaymentStatus(referenceId);
72
+
73
+ // Status mapping
74
+ const statusMapping = {
75
+ 'paid': 'success',
76
+ 'completed': 'success',
77
+ 'analysis': 'pending',
78
+ 'created': 'pending',
79
+ 'expired': 'failed',
80
+ 'refunded': 'refunded',
81
+ 'chargeback': 'disputed'
82
+ };
83
+
84
+ return {
85
+ status: statusMapping[payment.status] || 'unknown',
86
+ orderId: payment.referenceId,
87
+ transactionId: payment.authorizationId,
88
+ amount: parseFloat(payment.value),
89
+ currency: 'BRL',
90
+ paymentStatus: payment.status
91
+ };
92
+ } catch (error) {
93
+ throw new Error(`Error in PicPay callback handling: ${error.message}`);
94
+ }
95
+ }
96
+
97
+ async getPaymentStatus(referenceId) {
98
+ try {
99
+ const response = await this.client.get(`/payments/${referenceId}/status`);
100
+ return response.data;
101
+ } catch (error) {
102
+ throw new Error(`Error getting payment status: ${error.response?.data?.message || error.message}`);
103
+ }
104
+ }
105
+
106
+ async cancelPayment(referenceId, authorizationId) {
107
+ try {
108
+ const response = await this.client.post(`/payments/${referenceId}/cancellations`, {
109
+ authorizationId: authorizationId
110
+ });
111
+
112
+ return response.data;
113
+ } catch (error) {
114
+ throw new Error(`Error canceling payment: ${error.response?.data?.message || error.message}`);
115
+ }
116
+ }
117
+ }
118
+
119
+ module.exports = PicPayClient;
package/lib/plisio.js ADDED
@@ -0,0 +1,234 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class PlisioClient {
5
+ constructor(config) {
6
+ const requiredFields = ['apiKey'];
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.URL = 'https://api.plisio.net/api/v1';
13
+
14
+ this.client = axios.create({
15
+ baseURL: this.URL,
16
+ headers: {
17
+ 'Content-Type': 'application/json'
18
+ }
19
+ });
20
+
21
+ this.client.interceptors.response.use(response => {
22
+ return response;
23
+ }, error => {
24
+ if (error.response) {
25
+ throw new Error(`Plisio API error: ${error.response.data.message || error.message}`);
26
+ }
27
+ throw new Error(`Plisio API error: ${error.message}`);
28
+ });
29
+ }
30
+
31
+ async createPayment(options) {
32
+ try {
33
+ const params = {
34
+ api_key: this.apiKey,
35
+ order_name: options.orderName || options.name || 'Order',
36
+ order_number: options.orderNumber || options.orderId || `ORDER-${Date.now()}`,
37
+ amount: parseFloat(options.amount),
38
+ currency: options.currency || 'USD',
39
+ source_currency: options.sourceCurrency || options.currency || 'USD',
40
+ source_amount: options.sourceAmount || parseFloat(options.amount),
41
+ callback_url: options.callbackUrl || options.callback_link,
42
+ email: options.email,
43
+ language: options.language || 'en_US'
44
+ };
45
+
46
+ // Opsiyonel parametreler
47
+ if (options.plugin) params.plugin = options.plugin;
48
+ if (options.version) params.version = options.version;
49
+ if (options.success_callback) params.success_callback = options.success_callback;
50
+ if (options.fail_callback) params.fail_callback = options.fail_callback;
51
+
52
+ const response = await this.client.get('/invoices/new', { params });
53
+
54
+ if (response.data.status !== 'success') {
55
+ throw new Error(response.data.message || 'Payment creation failed');
56
+ }
57
+
58
+ return {
59
+ status: 'success',
60
+ data: {
61
+ txnId: response.data.data.txn_id,
62
+ url: response.data.data.invoice_url,
63
+ amount: response.data.data.amount,
64
+ currency: response.data.data.source_currency,
65
+ orderId: params.order_number
66
+ }
67
+ };
68
+ } catch (error) {
69
+ throw new Error(`Payment creation error: ${error.message}`);
70
+ }
71
+ }
72
+
73
+ async getTransactionDetails(txnId) {
74
+ try {
75
+ const params = {
76
+ api_key: this.apiKey,
77
+ id: txnId
78
+ };
79
+
80
+ const response = await this.client.get('/operations/invoice', { params });
81
+
82
+ if (response.data.status !== 'success') {
83
+ throw new Error(response.data.message || 'Failed to get transaction details');
84
+ }
85
+
86
+ return response.data.data;
87
+ } catch (error) {
88
+ throw new Error(`Transaction details error: ${error.message}`);
89
+ }
90
+ }
91
+
92
+ async getBalance(currency) {
93
+ try {
94
+ const params = {
95
+ api_key: this.apiKey,
96
+ currency: currency || 'BTC'
97
+ };
98
+
99
+ const response = await this.client.get('/balances', { params });
100
+
101
+ if (response.data.status !== 'success') {
102
+ throw new Error(response.data.message || 'Failed to get balance');
103
+ }
104
+
105
+ return response.data.data;
106
+ } catch (error) {
107
+ throw new Error(`Balance error: ${error.message}`);
108
+ }
109
+ }
110
+
111
+ async handleCallback(callbackData) {
112
+ try {
113
+ const verification = await this.verifyCallback(callbackData);
114
+
115
+ if (!verification.status) {
116
+ throw new Error(verification.error.message);
117
+ }
118
+
119
+ const data = verification.data;
120
+
121
+ // Status mapping
122
+ const statusMapping = {
123
+ 'completed': 'success',
124
+ 'pending': 'pending',
125
+ 'expired': 'expired',
126
+ 'error': 'failed',
127
+ 'mismatch': 'failed',
128
+ 'cancelled': 'cancelled'
129
+ };
130
+
131
+ return {
132
+ status: statusMapping[data.status] || 'unknown',
133
+ orderId: data.order_number,
134
+ txnId: data.txn_id,
135
+ amount: parseFloat(data.amount),
136
+ currency: data.currency,
137
+ sourceCurrency: data.source_currency,
138
+ sourceAmount: parseFloat(data.source_amount),
139
+ paymentStatus: data.status,
140
+ confirmations: data.confirmations || 0
141
+ };
142
+ } catch (error) {
143
+ throw new Error(`Error in Plisio callback handling: ${error.message}`);
144
+ }
145
+ }
146
+
147
+ async verifyCallback(data) {
148
+ try {
149
+ // Verify hash signature
150
+ if (data.verify_hash) {
151
+ const expectedHash = this.generateVerifyHash(data);
152
+
153
+ if (data.verify_hash !== expectedHash) {
154
+ return {
155
+ status: false,
156
+ error: {
157
+ code: 401,
158
+ message: 'Invalid verify hash'
159
+ }
160
+ };
161
+ }
162
+ }
163
+
164
+ // Check if payment is completed
165
+ if (data.status === 'error' || data.status === 'cancelled') {
166
+ return {
167
+ status: false,
168
+ error: {
169
+ code: 400,
170
+ message: `Payment ${data.status}`
171
+ }
172
+ };
173
+ }
174
+
175
+ return {
176
+ status: true,
177
+ data: data
178
+ };
179
+ } catch (error) {
180
+ return {
181
+ status: false,
182
+ error: {
183
+ code: 500,
184
+ message: error.message
185
+ }
186
+ };
187
+ }
188
+ }
189
+
190
+ generateVerifyHash(data) {
191
+ // Plisio verify hash generation
192
+ const params = {
193
+ 'currency': data.currency || '',
194
+ 'order_number': data.order_number || '',
195
+ 'order_name': data.order_name || '',
196
+ 'source_currency': data.source_currency || '',
197
+ 'source_rate': data.source_rate || '',
198
+ 'amount': data.amount || '',
199
+ 'status': data.status || '',
200
+ 'tx_urls': data.tx_urls || '',
201
+ 'txn_id': data.txn_id || ''
202
+ };
203
+
204
+ const orderedParams = Object.keys(params)
205
+ .sort()
206
+ .map(key => params[key])
207
+ .join('|');
208
+
209
+ return crypto
210
+ .createHash('sha1')
211
+ .update(orderedParams + '|' + this.apiKey)
212
+ .digest('hex');
213
+ }
214
+
215
+ async getSupportedCurrencies() {
216
+ try {
217
+ const params = {
218
+ api_key: this.apiKey
219
+ };
220
+
221
+ const response = await this.client.get('/currencies', { params });
222
+
223
+ if (response.data.status !== 'success') {
224
+ throw new Error(response.data.message || 'Failed to get currencies');
225
+ }
226
+
227
+ return response.data.data;
228
+ } catch (error) {
229
+ throw new Error(`Supported currencies error: ${error.message}`);
230
+ }
231
+ }
232
+ }
233
+
234
+ module.exports = PlisioClient;