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.
- package/PROVIDERS-DETAILS.md +1544 -0
- package/examples/example-2checkout.js +78 -0
- package/examples/example-bitpay.js +83 -0
- package/examples/example-cardcom.js +80 -0
- package/examples/example-cashfree.js +109 -0
- package/examples/example-checkout.js +85 -0
- package/examples/example-coingate.js +101 -0
- package/examples/example-coinpayments.js +89 -0
- package/examples/example-doku.js +27 -0
- package/examples/example-epay.js +64 -0
- package/examples/example-epoint.js +91 -0
- package/examples/example-freekassa.js +26 -0
- package/{example-heleket.js → examples/example-heleket.js} +3 -3
- package/examples/example-konnect.js +227 -0
- package/examples/example-midtrans.js +80 -0
- package/examples/example-noonpayments.js +297 -0
- package/examples/example-nowpayments.js +289 -0
- package/examples/example-omise.js +27 -0
- package/examples/example-paycom.js +82 -0
- package/{example-paydisini.js → examples/example-paydisini.js} +1 -1
- package/examples/example-payid19.js +87 -0
- package/examples/example-paykun.js +29 -0
- package/examples/example-payme.js +202 -0
- package/examples/example-paymentwall.js +201 -0
- package/examples/example-paynet.js +104 -0
- package/examples/example-paynettr.js +18 -0
- package/examples/example-payoneer.js +74 -0
- package/examples/example-payop.js +351 -0
- package/examples/example-paypal.js +200 -0
- package/examples/example-payriff.js +89 -0
- package/examples/example-paysend.js +81 -0
- package/examples/example-payspace.js +103 -0
- package/examples/example-payssion.js +27 -0
- package/examples/example-paytabs.js +28 -0
- package/examples/example-paytm.js +78 -0
- package/examples/example-payuindia.js +108 -0
- package/examples/example-payulatam.js +75 -0
- package/examples/example-phonepe.js +27 -0
- package/examples/example-picpay.js +27 -0
- package/examples/example-plisio.js +84 -0
- package/examples/example-portwallet.js +90 -0
- package/examples/example-primepayments.js +250 -0
- package/examples/example-razorpay.js +30 -0
- package/examples/example-senangpay.js +28 -0
- package/examples/example-shopier-card.js +67 -0
- package/examples/example-shurjopay.js +94 -0
- package/examples/example-toyyibpay.js +80 -0
- package/examples/example-tripay.js +89 -0
- package/examples/example-unitpay.js +26 -0
- package/examples/example-urway.js +28 -0
- package/examples/example-volet.js +80 -0
- package/examples/example-xendit.js +28 -0
- package/examples/example-yallapay.js +253 -0
- package/examples/example-yookassa.js +27 -0
- package/examples/example-youcanpay.js +28 -0
- package/examples/example-zarinpal.js +98 -0
- package/{example.js → examples/example.js} +1 -1
- package/lib/2checkout.js +165 -0
- package/lib/amazonpay.js +161 -0
- package/lib/billplz.js +79 -0
- package/lib/bitpay.js +122 -0
- package/lib/cardcom.js +193 -0
- package/lib/cashfree.js +184 -0
- package/lib/checkout.js +248 -0
- package/lib/coinbase.js +150 -0
- package/lib/coingate.js +137 -0
- package/lib/coinpayments.js +245 -0
- package/lib/doku.js +173 -0
- package/lib/epay.js +175 -0
- package/lib/epoint.js +162 -0
- package/lib/freekassa.js +128 -0
- package/lib/instamojo.js +158 -0
- package/lib/konnect.js +211 -0
- package/lib/midtrans.js +227 -0
- package/lib/noonpayments.js +650 -0
- package/lib/nowpayments.js +361 -0
- package/lib/omise.js +150 -0
- package/lib/paddle.js +180 -0
- package/lib/paycom.js +216 -0
- package/lib/payid19.js +211 -0
- package/lib/paykun.js +144 -0
- package/lib/payme.js +302 -0
- package/lib/paymentwall.js +205 -0
- package/lib/paynet.js +186 -0
- package/lib/paynettr.js +165 -0
- package/lib/payoneer.js +128 -0
- package/lib/payop.js +345 -0
- package/lib/paypal.js +596 -0
- package/lib/payriff.js +148 -0
- package/lib/paysend.js +189 -0
- package/lib/payspace.js +168 -0
- package/lib/payssion.js +177 -0
- package/lib/paytabs.js +145 -0
- package/lib/paytm.js +253 -0
- package/lib/payuindia.js +162 -0
- package/lib/payulatam.js +179 -0
- package/lib/perfectmoney.js +143 -0
- package/lib/phonepe.js +174 -0
- package/lib/picpay.js +119 -0
- package/lib/plisio.js +234 -0
- package/lib/portwallet.js +152 -0
- package/lib/primepayments.js +338 -0
- package/lib/razorpay.js +205 -0
- package/lib/senangpay.js +130 -0
- package/lib/shopier_card.js +188 -0
- package/lib/shurjopay.js +159 -0
- package/lib/toyyibpay.js +151 -0
- package/lib/tripay.js +220 -0
- package/lib/unitpay.js +223 -0
- package/lib/urway.js +182 -0
- package/lib/volet.js +147 -0
- package/lib/xendit.js +206 -0
- package/lib/yallapay.js +319 -0
- package/lib/yookassa.js +193 -0
- package/lib/youcanpay.js +124 -0
- package/lib/zarinpal.js +157 -0
- package/package.json +138 -64
- package/readme.md +348 -105
- package/reported.md +347 -0
- package/test.js +492 -0
- package/lib/vallet.js +0 -22
- /package/{example-anypay.js → examples/example-anypay.js} +0 -0
- /package/{example-bufpay.js → examples/example-bufpay.js} +0 -0
- /package/{example-cryptomus.js → examples/example-cryptomus.js} +0 -0
- /package/{example-esnekpos.js → examples/example-esnekpos.js} +0 -0
- /package/{example-fedapay.js → examples/example-fedapay.js} +0 -0
- /package/{example-iyzico.js → examples/example-iyzico.js} +0 -0
- /package/{example-papara.js → examples/example-papara.js} +0 -0
- /package/{example-payeer.js → examples/example-payeer.js} +0 -0
- /package/{example-paymaya.js → examples/example-paymaya.js} +0 -0
- /package/{example-shopier.js → examples/example-shopier.js} +0 -0
- /package/{ipaymu.js → examples/ipaymu.js} +0 -0
- /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¤cy=${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;
|