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
package/lib/paypal.js ADDED
@@ -0,0 +1,596 @@
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
+ * Create payment (wrapper for processPayment)
543
+ * @param {Object} paymentData - Payment data
544
+ * @returns {Promise<Object>} - Payment result
545
+ */
546
+ async createPayment(paymentData) {
547
+ try {
548
+ // For PayPal, we can use processPayment or create a payment link
549
+ // Since Braintree is used, we'll simulate a payment creation
550
+ const clientToken = await this.generateClientToken();
551
+
552
+ return {
553
+ success: true,
554
+ paymentUrl: `https://www.paypal.com/checkout?token=${clientToken}`, // Simplified
555
+ transactionId: paymentData.orderId,
556
+ amount: paymentData.amount,
557
+ currency: paymentData.currency || 'USD',
558
+ clientToken: clientToken
559
+ };
560
+ } catch (error) {
561
+ throw new Error(`PayPal payment creation failed: ${error.message}`);
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Handle callback/webhook
567
+ * @param {Object} callbackData - Webhook data
568
+ * @returns {Promise<Object>} - Callback result
569
+ */
570
+ async handleCallback(callbackData) {
571
+ try {
572
+ // Use existing handleWebhook method
573
+ const result = await this.handleWebhook('', callbackData);
574
+
575
+ if (result && result.success) {
576
+ return {
577
+ success: true,
578
+ transactionId: result.transactionId,
579
+ status: 'completed',
580
+ amount: result.amount,
581
+ rawData: callbackData
582
+ };
583
+ } else {
584
+ return {
585
+ success: false,
586
+ status: 'failed',
587
+ rawData: callbackData
588
+ };
589
+ }
590
+ } catch (error) {
591
+ throw new Error(`PayPal callback handling failed: ${error.message}`);
592
+ }
593
+ }
594
+ }
595
+
596
+ module.exports = PayPal;