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
package/lib/paypal.js ADDED
@@ -0,0 +1,542 @@
1
+ const braintree = require('braintree');
2
+
3
+ class PayPal {
4
+ constructor(config) {
5
+ this.config = config || {};
6
+ const requiredFields = ['merchantId', 'publicKey', 'privateKey'];
7
+ for (let field of requiredFields) {
8
+ if (!config[field]) throw new Error(`Missing required field: ${field}`);
9
+ }
10
+
11
+ const environment = config.environment === 'production'
12
+ ? braintree.Environment.Production
13
+ : braintree.Environment.Sandbox;
14
+
15
+ this.gateway = new braintree.BraintreeGateway({
16
+ environment: environment,
17
+ merchantId: config.merchantId,
18
+ publicKey: config.publicKey,
19
+ privateKey: config.privateKey
20
+ });
21
+ }
22
+
23
+ async generateClientToken(options = {}) {
24
+ try {
25
+ const response = await this.gateway.clientToken.generate(options);
26
+ return response.clientToken;
27
+ } catch (error) {
28
+ throw new Error(`Client token oluşturma hatası: ${error.message}`);
29
+ }
30
+ }
31
+
32
+ async processPayment(saleData) {
33
+ try {
34
+ if (!saleData.amount || !saleData.paymentMethodNonce) {
35
+ throw new Error('Tutar ve payment method nonce gerekli');
36
+ }
37
+
38
+ const saleRequest = {
39
+ amount: saleData.amount,
40
+ paymentMethodNonce: saleData.paymentMethodNonce,
41
+ orderId: saleData.orderId,
42
+ customer: saleData.customer,
43
+ options: {
44
+ submitForSettlement: true,
45
+ ...saleData.options
46
+ }
47
+ };
48
+
49
+ const result = await this.gateway.transaction.sale(saleRequest);
50
+
51
+ if (result.success) {
52
+ return {
53
+ success: true,
54
+ transactionId: result.transaction.id,
55
+ status: result.transaction.status,
56
+ amount: result.transaction.amount,
57
+ currency: result.transaction.currencyIsoCode,
58
+ orderId: result.transaction.orderId,
59
+ paymentType: 'paypal',
60
+ createdAt: result.transaction.createdAt
61
+ };
62
+ } else {
63
+ throw new Error(result.message || 'İşlem başarısız');
64
+ }
65
+ } catch (error) {
66
+ throw new Error(`Ödeme işlemi hatası: ${error.message}`);
67
+ }
68
+ }
69
+
70
+ async getTransaction(transactionId) {
71
+ try {
72
+ const result = await this.gateway.transaction.find(transactionId);
73
+ return result;
74
+ } catch (error) {
75
+ throw new Error(`İşlem bulunamadı: ${error.message}`);
76
+ }
77
+ }
78
+
79
+ async searchTransactions(searchParams = {}) {
80
+ try {
81
+ const stream = await this.gateway.transaction.search((search) => {
82
+ if (searchParams.orderId) {
83
+ search.orderId().is(searchParams.orderId);
84
+ }
85
+ if (searchParams.status) {
86
+ search.status().is(searchParams.status);
87
+ }
88
+ if (searchParams.customerId) {
89
+ search.customerId().is(searchParams.customerId);
90
+ }
91
+ if (searchParams.startDate && searchParams.endDate) {
92
+ search.createdAt().between(searchParams.startDate, searchParams.endDate);
93
+ }
94
+ });
95
+
96
+ return new Promise((resolve, reject) => {
97
+ const transactions = [];
98
+ stream.on('data', (transaction) => {
99
+ transactions.push(transaction);
100
+ });
101
+ stream.on('end', () => {
102
+ resolve(transactions);
103
+ });
104
+ stream.on('error', (err) => {
105
+ reject(new Error(`İşlem arama hatası: ${err.message}`));
106
+ });
107
+ });
108
+ } catch (error) {
109
+ throw new Error(`İşlem arama hatası: ${error.message}`);
110
+ }
111
+ }
112
+
113
+ async refundTransaction(transactionId, amount = null) {
114
+ try {
115
+ let result;
116
+
117
+ if (amount) {
118
+ result = await this.gateway.transaction.refund(transactionId, amount);
119
+ } else {
120
+ result = await this.gateway.transaction.refund(transactionId);
121
+ }
122
+
123
+ if (result.success) {
124
+ return {
125
+ success: true,
126
+ refundId: result.transaction.id,
127
+ originalTransactionId: transactionId,
128
+ amount: result.transaction.amount,
129
+ status: result.transaction.status
130
+ };
131
+ } else {
132
+ throw new Error(result.message || 'İade işlemi başarısız');
133
+ }
134
+ } catch (error) {
135
+ throw new Error(`İade işlemi hatası: ${error.message}`);
136
+ }
137
+ }
138
+
139
+ async handleWebhook(signature, payload) {
140
+ try {
141
+ const webhookNotification = await this.gateway.webhookNotification.parse(signature, payload);
142
+
143
+ const kind = webhookNotification.kind;
144
+ const timestamp = webhookNotification.timestamp;
145
+
146
+ switch (kind) {
147
+ case 'subscription_went_active':
148
+ case 'subscription_charged_successfully':
149
+ return {
150
+ event: 'subscription_payment',
151
+ status: 'success',
152
+ subscriptionId: webhookNotification.subscription.id,
153
+ transactionId: webhookNotification.subscription.transactions[0]?.id,
154
+ planId: webhookNotification.subscription.planId,
155
+ amount: webhookNotification.subscription.transactions[0]?.amount,
156
+ timestamp: timestamp
157
+ };
158
+
159
+ case 'subscription_charged_unsuccessfully':
160
+ return {
161
+ event: 'subscription_payment',
162
+ status: 'failed',
163
+ subscriptionId: webhookNotification.subscription.id,
164
+ planId: webhookNotification.subscription.planId,
165
+ timestamp: timestamp
166
+ };
167
+
168
+ case 'subscription_canceled':
169
+ return {
170
+ event: 'subscription_canceled',
171
+ subscriptionId: webhookNotification.subscription.id,
172
+ planId: webhookNotification.subscription.planId,
173
+ timestamp: timestamp
174
+ };
175
+
176
+ case 'transaction_settled':
177
+ return {
178
+ event: 'payment_settled',
179
+ status: 'success',
180
+ transactionId: webhookNotification.transaction.id,
181
+ amount: webhookNotification.transaction.amount,
182
+ orderId: webhookNotification.transaction.orderId,
183
+ timestamp: timestamp
184
+ };
185
+
186
+ case 'transaction_settlement_declined':
187
+ return {
188
+ event: 'payment_settlement_declined',
189
+ status: 'failed',
190
+ transactionId: webhookNotification.transaction.id,
191
+ amount: webhookNotification.transaction.amount,
192
+ orderId: webhookNotification.transaction.orderId,
193
+ timestamp: timestamp
194
+ };
195
+
196
+ default:
197
+ return {
198
+ event: kind,
199
+ raw: webhookNotification
200
+ };
201
+ }
202
+ } catch (error) {
203
+ throw new Error(`Webhook işleme hatası: ${error.message}`);
204
+ }
205
+ }
206
+
207
+ async testWebhook(kind, id) {
208
+ try {
209
+ const result = await this.gateway.webhookTesting.sampleNotification(kind, id);
210
+ return {
211
+ btSignature: result.bt_signature,
212
+ btPayload: result.bt_payload
213
+ };
214
+ } catch (error) {
215
+ throw new Error(`Test webhook oluşturma hatası: ${error.message}`);
216
+ }
217
+ }
218
+
219
+ async createPaymentLink(linkData) {
220
+ try {
221
+ if (!linkData.amount || !linkData.currency) {
222
+ throw new Error('Tutar ve para birimi gerekli');
223
+ }
224
+
225
+ const orderId = linkData.orderId || `order-${Date.now()}`;
226
+
227
+ const returnUrl = linkData.successUrl || 'http://localhost:3000/success';
228
+ const cancelUrl = linkData.cancelUrl || 'http://localhost:3000/cancel';
229
+ const clientToken = await this.generateClientToken();
230
+
231
+ return {
232
+ success: true,
233
+ clientToken: clientToken,
234
+ amount: linkData.amount,
235
+ currency: linkData.currency,
236
+ orderId: orderId,
237
+ description: linkData.description || `Payment: ${linkData.amount} ${linkData.currency}`,
238
+ successUrl: returnUrl,
239
+ cancelUrl: cancelUrl,
240
+ paypalCheckoutDetails: {
241
+ clientToken: clientToken,
242
+ amount: linkData.amount,
243
+ currency: linkData.currency,
244
+ orderId: orderId,
245
+ description: linkData.description || `Payment: ${linkData.amount} ${linkData.currency}`,
246
+ successUrl: returnUrl,
247
+ cancelUrl: cancelUrl
248
+ }
249
+ };
250
+ } catch (error) {
251
+ throw new Error(`Ödeme bağlantısı oluşturma hatası: ${error.message}`);
252
+ }
253
+ }
254
+
255
+ async createCheckoutOptions(checkoutData) {
256
+ try {
257
+ if (!checkoutData.amount) {
258
+ throw new Error('Tutar bilgisi gerekli');
259
+ }
260
+
261
+ const clientToken = await this.generateClientToken();
262
+ const orderId = checkoutData.orderId || `order-${Date.now()}`;
263
+
264
+ const setupCode = Buffer.from(JSON.stringify({
265
+ amount: checkoutData.amount,
266
+ currency: checkoutData.currency || 'USD',
267
+ orderId: orderId,
268
+ intent: 'capture',
269
+ successUrl: checkoutData.successUrl || '',
270
+ cancelUrl: checkoutData.cancelUrl || ''
271
+ })).toString('base64');
272
+
273
+ return {
274
+ success: true,
275
+ clientToken: clientToken,
276
+ setupCode: setupCode,
277
+ orderId: orderId,
278
+ amount: checkoutData.amount,
279
+ currency: checkoutData.currency || 'USD',
280
+ successUrl: checkoutData.successUrl,
281
+ cancelUrl: checkoutData.cancelUrl,
282
+ paymentUrl: `https://your-app-domain.com/paypal-checkout?setup=${setupCode}`
283
+ };
284
+ } catch (error) {
285
+ throw new Error(`Checkout seçenekleri oluşturma hatası: ${error.message}`);
286
+ }
287
+ }
288
+
289
+ async completePayment(paymentNonce, setupCode) {
290
+ try {
291
+ const setupData = JSON.parse(Buffer.from(setupCode, 'base64').toString());
292
+
293
+ const paymentResult = await this.processPayment({
294
+ amount: setupData.amount,
295
+ paymentMethodNonce: paymentNonce,
296
+ orderId: setupData.orderId,
297
+ options: {
298
+ submitForSettlement: true
299
+ }
300
+ });
301
+
302
+ return {
303
+ success: true,
304
+ transactionId: paymentResult.transactionId,
305
+ status: paymentResult.status,
306
+ amount: paymentResult.amount,
307
+ orderId: paymentResult.orderId,
308
+ redirectUrl: setupData.successUrl || null
309
+ };
310
+ } catch (error) {
311
+ throw new Error(`Ödeme tamamlama hatası: ${error.message}`);
312
+ }
313
+ }
314
+
315
+ async renderHtmlCheckout(data) {
316
+ try {
317
+ if (!data.amount) {
318
+ throw new Error('Amount is required');
319
+ }
320
+
321
+ const amount = data.amount;
322
+ const currency = data.currency || 'USD';
323
+ const orderId = data.orderId || `order-${Date.now()}`;
324
+ const description = data.description || `Payment: ${amount} ${currency}`;
325
+ const successUrl = data.successUrl || 'http://localhost:3000/success';
326
+ const cancelUrl = data.cancelUrl || 'http://localhost:3000/cancel';
327
+
328
+ const clientToken = await this.generateClientToken();
329
+
330
+ return `
331
+ <!DOCTYPE html>
332
+ <html lang="en">
333
+ <head>
334
+ <meta charset="UTF-8">
335
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
336
+ <title>Secure Payment | QuickPos</title>
337
+ <script src="https://www.paypal.com/sdk/js?client-id=test&currency=${currency}"></script>
338
+ <style>
339
+ :root {
340
+ --primary-color: #0070ba;
341
+ --secondary-color: #003087;
342
+ --accent-color: #009cde;
343
+ --background-color: #f7f9fa;
344
+ --success-color: #26c281;
345
+ --text-color: #2c3e50;
346
+ --border-color: #e5e8ec;
347
+ }
348
+ * { margin: 0; padding: 0; box-sizing: border-box; }
349
+ body {
350
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
351
+ background: var(--background-color);
352
+ color: var(--text-color);
353
+ line-height: 1.6;
354
+ padding: 0;
355
+ margin: 0;
356
+ }
357
+ .header {
358
+ background: #fff;
359
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
360
+ padding: 15px 0;
361
+ position: relative;
362
+ }
363
+ .header-content {
364
+ display: flex;
365
+ justify-content: space-between;
366
+ align-items: center;
367
+ max-width: 1200px;
368
+ margin: 0 auto;
369
+ padding: 0 20px;
370
+ }
371
+ .logo {
372
+ font-weight: 700;
373
+ font-size: 1.5rem;
374
+ color: var(--primary-color);
375
+ }
376
+ .secure-badge {
377
+ display: flex;
378
+ align-items: center;
379
+ font-size: 14px;
380
+ color: #718096;
381
+ }
382
+ .secure-badge svg {
383
+ margin-right: 6px;
384
+ fill: #718096;
385
+ }
386
+ .container {
387
+ max-width: 500px;
388
+ margin: 30px auto;
389
+ background: white;
390
+ border-radius: 8px;
391
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
392
+ overflow: hidden;
393
+ }
394
+ .payment-header {
395
+ padding: 20px 25px;
396
+ border-bottom: 1px solid var(--border-color);
397
+ }
398
+ .payment-title {
399
+ font-size: 18px;
400
+ font-weight: 600;
401
+ color: var(--text-color);
402
+ }
403
+ .payment-details {
404
+ padding: 20px 25px;
405
+ border-bottom: 1px solid var(--border-color);
406
+ }
407
+ .detail-row {
408
+ display: flex;
409
+ justify-content: space-between;
410
+ padding: 10px 0;
411
+ border-bottom: 1px solid var(--border-color);
412
+ }
413
+ .detail-row:last-child {
414
+ border-bottom: none;
415
+ }
416
+ .detail-label {
417
+ color: #718096;
418
+ font-size: 14px;
419
+ }
420
+ .detail-value {
421
+ font-weight: 600;
422
+ font-size: 14px;
423
+ }
424
+ .payment-methods {
425
+ padding: 20px 25px;
426
+ }
427
+ .method-title {
428
+ font-size: 16px;
429
+ font-weight: 600;
430
+ margin-bottom: 15px;
431
+ color: var(--text-color);
432
+ }
433
+ #paypal-button-container {
434
+ margin: 15px 0;
435
+ }
436
+ .cancel-btn {
437
+ display: block;
438
+ width: 100%;
439
+ padding: 10px;
440
+ text-align: center;
441
+ background: #f1f5f9;
442
+ color: #475569;
443
+ border: none;
444
+ border-radius: 4px;
445
+ cursor: pointer;
446
+ font-weight: 500;
447
+ text-decoration: none;
448
+ margin-top: 15px;
449
+ transition: background 0.2s ease;
450
+ }
451
+ .cancel-btn:hover {
452
+ background: #e2e8f0;
453
+ }
454
+ .footer {
455
+ text-align: center;
456
+ padding: 20px;
457
+ color: #94a3b8;
458
+ font-size: 12px;
459
+ background: #fff;
460
+ border-top: 1px solid var(--border-color);
461
+ margin-top: 30px;
462
+ }
463
+ .footer a {
464
+ color: var(--primary-color);
465
+ text-decoration: none;
466
+ }
467
+ .footer a:hover {
468
+ text-decoration: underline;
469
+ }
470
+ </style>
471
+ </head>
472
+ <body>
473
+ <div class="container">
474
+ <div class="payment-header">
475
+ <h1 class="payment-title">${description}</h1>
476
+ </div>
477
+
478
+ <div class="payment-details">
479
+ <div class="detail-row">
480
+ <span class="detail-label">Amount</span>
481
+ <span class="detail-value">${currency} ${amount}</span>
482
+ </div>
483
+ <div class="detail-row">
484
+ <span class="detail-label">Order ID</span>
485
+ <span class="detail-value">${orderId}</span>
486
+ </div>
487
+ </div>
488
+
489
+ <div class="payment-methods">
490
+ <h2 class="method-title">Select Payment Method</h2>
491
+ <div id="paypal-button-container"></div>
492
+ <a href="/" class="cancel-btn">Cancel Payment</a>
493
+ </div>
494
+ </div>
495
+
496
+ <script>
497
+ paypal.Buttons({
498
+ style: {
499
+ layout: 'vertical',
500
+ color: 'blue',
501
+ shape: 'rect',
502
+ label: 'pay'
503
+ },
504
+ createOrder: function(data, actions) {
505
+ return actions.order.create({
506
+ purchase_units: [{
507
+ amount: {
508
+ value: "${amount}",
509
+ currency_code: "${currency}"
510
+ },
511
+ description: "${description}",
512
+ invoice_id: "${orderId}"
513
+ }]
514
+ });
515
+ },
516
+
517
+ onApprove: function(data, actions) {
518
+ return actions.order.capture().then(function(details) {
519
+ window.location.href = "${successUrl}?order_id=${orderId}&paymentId=" + data.orderID + "&PayerID=" + details.payer.payer_id;
520
+ });
521
+ },
522
+
523
+ onCancel: function(data) {
524
+ window.location.href = "${cancelUrl}";
525
+ },
526
+
527
+ onError: function(err) {
528
+ console.error('PayPal error:', err);
529
+ alert('Payment error occurred. Please try again.');
530
+ }
531
+ }).render('#paypal-button-container');
532
+ </script>
533
+ </body>
534
+ </html>
535
+ `;
536
+ } catch (error) {
537
+ throw new Error(`Checkout rendering error: ${error.message}`);
538
+ }
539
+ }
540
+ }
541
+
542
+ module.exports = PayPal;
package/lib/payriff.js ADDED
@@ -0,0 +1,148 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+
4
+ class PayriffClient {
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 = 'https://api.payriff.com';
14
+
15
+ this.client = axios.create({
16
+ baseURL: this.baseURL,
17
+ headers: {
18
+ 'Content-Type': 'application/json'
19
+ }
20
+ });
21
+ }
22
+
23
+ generateSignature(data) {
24
+ const signatureString = `${data.merchant}${data.order}${data.amount}${data.currency}${this.secretKey}`;
25
+ return crypto.createHash('sha256').update(signatureString).digest('hex').toUpperCase();
26
+ }
27
+
28
+ async createPayment(options) {
29
+ try {
30
+ const orderId = options.orderId || `ORDER-${Date.now()}`;
31
+ const amount = parseFloat(options.amount);
32
+
33
+ const paymentData = {
34
+ merchant: this.merchantId,
35
+ order: orderId,
36
+ amount: amount,
37
+ currency: options.currency || 'AZN',
38
+ description: options.description || options.name || 'Payment',
39
+ approveURL: options.successUrl || options.callback_link,
40
+ cancelURL: options.failUrl || options.callback_link,
41
+ declineURL: options.failUrl || options.callback_link,
42
+ callbackURL: options.callbackUrl || options.callback_link,
43
+ language: options.language || 'AZ'
44
+ };
45
+
46
+ paymentData.signature = this.generateSignature(paymentData);
47
+
48
+ const response = await this.client.post('/api/v2/createOrder', paymentData);
49
+
50
+ if (response.data.code === 1) {
51
+ return {
52
+ status: 'success',
53
+ data: {
54
+ url: response.data.payload.redirect,
55
+ orderId: orderId,
56
+ sessionId: response.data.payload.sessionId,
57
+ amount: amount,
58
+ currency: paymentData.currency
59
+ }
60
+ };
61
+ } else {
62
+ throw new Error(response.data.message || 'Payment creation failed');
63
+ }
64
+ } catch (error) {
65
+ throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
66
+ }
67
+ }
68
+
69
+ async handleCallback(callbackData) {
70
+ try {
71
+ const verification = await this.verifyCallback(callbackData);
72
+
73
+ if (!verification.status) {
74
+ throw new Error(verification.error.message);
75
+ }
76
+
77
+ // Status mapping
78
+ const statusMapping = {
79
+ 'APPROVED': 'success',
80
+ 'DECLINED': 'failed',
81
+ 'CANCELLED': 'failed',
82
+ 'PENDING': 'pending'
83
+ };
84
+
85
+ return {
86
+ status: statusMapping[callbackData.status] || 'unknown',
87
+ orderId: callbackData.order,
88
+ transactionId: callbackData.rrn || callbackData.sessionId,
89
+ amount: parseFloat(callbackData.amount),
90
+ currency: callbackData.currency,
91
+ paymentStatus: callbackData.status,
92
+ cardNumber: callbackData.cardNumber
93
+ };
94
+ } catch (error) {
95
+ throw new Error(`Error in Payriff callback handling: ${error.message}`);
96
+ }
97
+ }
98
+
99
+ async verifyCallback(data) {
100
+ try {
101
+ const receivedSign = data.signature;
102
+ const expectedSign = this.generateSignature({
103
+ merchant: data.merchant,
104
+ order: data.order,
105
+ amount: data.amount,
106
+ currency: data.currency
107
+ });
108
+
109
+ if (receivedSign !== expectedSign) {
110
+ return {
111
+ status: false,
112
+ error: {
113
+ code: 401,
114
+ message: 'Invalid signature'
115
+ }
116
+ };
117
+ }
118
+
119
+ return {
120
+ status: true,
121
+ data: data
122
+ };
123
+ } catch (error) {
124
+ return {
125
+ status: false,
126
+ error: {
127
+ code: 500,
128
+ message: error.message
129
+ }
130
+ };
131
+ }
132
+ }
133
+
134
+ async getOrderStatus(orderId) {
135
+ try {
136
+ const response = await this.client.post('/api/v2/getOrderStatus', {
137
+ merchant: this.merchantId,
138
+ order: orderId
139
+ });
140
+
141
+ return response.data;
142
+ } catch (error) {
143
+ throw new Error(`Error getting order status: ${error.response?.data?.message || error.message}`);
144
+ }
145
+ }
146
+ }
147
+
148
+ module.exports = PayriffClient;