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.
- 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/examples/example-heleket.js +139 -0
- 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-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/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/heleket.js +67 -1
- 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 +311 -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 +256 -0
- package/lib/paypal.js +542 -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 +256 -0
- package/lib/razorpay.js +205 -0
- package/lib/senangpay.js +130 -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 +279 -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/test.js +492 -0
- package/example-heleket.js +0 -83
- 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
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
const YallaPayService = require('./lib/yallapay');
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const bodyParser = require('body-parser');
|
|
4
|
+
const app = express();
|
|
5
|
+
|
|
6
|
+
// Body parser middleware
|
|
7
|
+
app.use(bodyParser.json());
|
|
8
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
9
|
+
|
|
10
|
+
// Tüm istekleri loglama
|
|
11
|
+
app.use((req, res, next) => {
|
|
12
|
+
console.log(`[${new Date().toISOString()}] Gelen istek: ${req.method} ${req.url}`);
|
|
13
|
+
if (Object.keys(req.query).length > 0) {
|
|
14
|
+
console.log('Query:', JSON.stringify(req.query));
|
|
15
|
+
}
|
|
16
|
+
if (req.body && Object.keys(req.body).length > 0) {
|
|
17
|
+
console.log('Body:', JSON.stringify(req.body));
|
|
18
|
+
}
|
|
19
|
+
next();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// YallaPay konfigürasyonu - kendi API anahtarınızı kullanmalısınız
|
|
23
|
+
const yallapayConfig = {
|
|
24
|
+
privateKey: 'YOUR_PRIVATE_KEY', // YallaPay Merchant Dashboard'dan alınır
|
|
25
|
+
currency: 'USD', // İşlem para birimi
|
|
26
|
+
webhookSecret: 'YOUR_WEBHOOK_SECRET_KEY', // YallaPay Webhook Dashboard'dan alınır
|
|
27
|
+
debug: true // Debug modu açık (geliştirme sırasında)
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// YallaPay servisini başlat
|
|
31
|
+
const yallapay = new YallaPayService(yallapayConfig);
|
|
32
|
+
|
|
33
|
+
// Ödeme oluşturma örneği
|
|
34
|
+
async function createPaymentExample() {
|
|
35
|
+
try {
|
|
36
|
+
console.log('Yeni ödeme isteği oluşturuluyor...');
|
|
37
|
+
|
|
38
|
+
const paymentResult = await yallapay.createPayment({
|
|
39
|
+
amount: 100, // Ödeme tutarı
|
|
40
|
+
purpose: 'Premium Üyelik', // Ödeme açıklaması
|
|
41
|
+
external_id: 'siparis-' + Date.now(), // Sipariş ID'si
|
|
42
|
+
is_fallback: '1', // Fallback URL kullan
|
|
43
|
+
fallback_url: 'https://test.quickpanel.net/success', // Başarılı ödeme dönüş sayfası
|
|
44
|
+
generateQr: true // QR kod oluştur
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log('Ödeme bağlantısı oluşturuldu:');
|
|
48
|
+
console.log(JSON.stringify(paymentResult, null, 2));
|
|
49
|
+
|
|
50
|
+
return paymentResult;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Ödeme oluşturma hatası:', error.message);
|
|
53
|
+
return { status: 'error', message: error.message };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Örnek işlem doğrulama
|
|
58
|
+
async function verifyTransactionExample(transactionId) {
|
|
59
|
+
try {
|
|
60
|
+
console.log(`${transactionId} işlemi doğrulanıyor...`);
|
|
61
|
+
|
|
62
|
+
const result = await yallapay.verifyTransaction(transactionId);
|
|
63
|
+
console.log('İşlem durumu:', result);
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('İşlem doğrulama hatası:', error.message);
|
|
68
|
+
return { status: 'error', message: error.message };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Webhook endpoint
|
|
73
|
+
app.post('/webhook/yallapay', async (req, res) => {
|
|
74
|
+
console.log('🔔 YallaPay webhook çağrısı alındı!');
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
// Webhook verilerini işle - artık webhook secret'ı ayrıca vermiyoruz
|
|
78
|
+
const result = await yallapay.handleWebhook(req.body);
|
|
79
|
+
console.log('✅ Ödeme durumu:', result);
|
|
80
|
+
|
|
81
|
+
if (result.status === 'success') {
|
|
82
|
+
console.log(`✅ Başarılı Ödeme: Sipariş ${result.orderId} için ${result.amount} ${result.currency} ödeme alındı`);
|
|
83
|
+
|
|
84
|
+
// Burada başarılı ödeme işlemleri yapılabilir
|
|
85
|
+
// - Veritabanı güncelleme
|
|
86
|
+
// - Sipariş durumu değiştirme
|
|
87
|
+
// - Kullanıcı hesabını aktifleştirme vb.
|
|
88
|
+
} else if (result.status === 'refunded') {
|
|
89
|
+
console.log(`♻️ İade Edilen Ödeme: Sipariş ${result.orderId} için ${result.amount} ${result.currency} iade edildi`);
|
|
90
|
+
} else if (result.status === 'failed') {
|
|
91
|
+
console.log(`❌ Başarısız Ödeme: Sipariş ${result.orderId}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// YallaPay'e başarılı yanıt gönder
|
|
95
|
+
res.status(200).json({ status: 'success' });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error('⚠️ Webhook işleme hatası:', error.message);
|
|
98
|
+
// YallaPay'e hata yanıtı gönder
|
|
99
|
+
res.status(400).json({ status: 'error', message: error.message });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Başarılı ödeme dönüş sayfası
|
|
104
|
+
app.get('/success', (req, res) => {
|
|
105
|
+
res.send(`
|
|
106
|
+
<html>
|
|
107
|
+
<head>
|
|
108
|
+
<title>Ödeme Başarılı</title>
|
|
109
|
+
<style>
|
|
110
|
+
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
|
|
111
|
+
.success { color: green; font-size: 24px; margin-bottom: 20px; }
|
|
112
|
+
</style>
|
|
113
|
+
</head>
|
|
114
|
+
<body>
|
|
115
|
+
<div class="success">Ödemeniz başarıyla tamamlandı!</div>
|
|
116
|
+
<p>Teşekkür ederiz. Siparişiniz işleme alındı.</p>
|
|
117
|
+
<pre>${JSON.stringify(req.query, null, 2)}</pre>
|
|
118
|
+
</body>
|
|
119
|
+
</html>
|
|
120
|
+
`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// İşlem doğrulama endpoint'i
|
|
124
|
+
app.get('/verify/:transactionId', async (req, res) => {
|
|
125
|
+
try {
|
|
126
|
+
const result = await verifyTransactionExample(req.params.transactionId);
|
|
127
|
+
res.json(result);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
res.status(400).json({ status: 'error', message: error.message });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Ana sayfa
|
|
134
|
+
app.get('/', (req, res) => {
|
|
135
|
+
res.send(`
|
|
136
|
+
<html>
|
|
137
|
+
<head>
|
|
138
|
+
<title>YallaPay Ödeme Testi</title>
|
|
139
|
+
<style>
|
|
140
|
+
body { font-family: Arial, sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; }
|
|
141
|
+
button { padding: 10px 15px; background: #0066ff; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
|
142
|
+
.container { margin-top: 20px; }
|
|
143
|
+
pre { background: #f4f4f4; padding: 10px; border-radius: 4px; overflow: auto; }
|
|
144
|
+
.error { color: red; }
|
|
145
|
+
.verify-form { margin-top: 30px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
|
|
146
|
+
input { padding: 8px; width: 300px; }
|
|
147
|
+
</style>
|
|
148
|
+
</head>
|
|
149
|
+
<body>
|
|
150
|
+
<h1>YallaPay Ödeme Testi</h1>
|
|
151
|
+
<p>YallaPay API ile ödeme bağlantısı oluşturma testi.</p>
|
|
152
|
+
<button onclick="createPayment()">Yeni Ödeme Oluştur</button>
|
|
153
|
+
|
|
154
|
+
<div class="container" id="result">
|
|
155
|
+
<p>Bu test için aşağıdaki bilgileri kullanıyoruz:</p>
|
|
156
|
+
<pre>Private Key: ${yallapayConfig.privateKey.substring(0, 10)}...
|
|
157
|
+
Para Birimi: ${yallapayConfig.currency}</pre>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="verify-form">
|
|
161
|
+
<h3>İşlem Doğrulama</h3>
|
|
162
|
+
<p>YallaPay işlem ID'si ile ödeme durumunu kontrol edin:</p>
|
|
163
|
+
<input type="text" id="transactionId" placeholder="İşlem ID'si girin">
|
|
164
|
+
<button onclick="verifyTransaction()">Doğrula</button>
|
|
165
|
+
<div id="verifyResult"></div>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<script>
|
|
169
|
+
function createPayment() {
|
|
170
|
+
document.getElementById('result').innerHTML = '<p>Ödeme oluşturuluyor...</p>';
|
|
171
|
+
|
|
172
|
+
fetch('/create-payment')
|
|
173
|
+
.then(response => response.json())
|
|
174
|
+
.then(data => {
|
|
175
|
+
if (data.status === 'success') {
|
|
176
|
+
let html = \`
|
|
177
|
+
<h3>Ödeme Bağlantısı Oluşturuldu</h3>
|
|
178
|
+
<p>İşlem ID: \${data.data.id}</p>
|
|
179
|
+
<p>Ödeme URL: <a href="\${data.data.url}" target="_blank">\${data.data.url}</a></p>
|
|
180
|
+
\`;
|
|
181
|
+
|
|
182
|
+
if (data.data.fallbackUrl) {
|
|
183
|
+
html += \`<p>Dönüş URL: \${data.data.fallbackUrl}</p>\`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (data.data.qr) {
|
|
187
|
+
html += \`<p>QR Kod:</p><img src="\${data.data.qr}" width="200" />\`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
document.getElementById('result').innerHTML = html;
|
|
191
|
+
} else {
|
|
192
|
+
document.getElementById('result').innerHTML = '<p class="error">Hata: ' + data.message + '</p>';
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
.catch(error => {
|
|
196
|
+
document.getElementById('result').innerHTML = '<p class="error">Hata: ' + error + '</p>';
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function verifyTransaction() {
|
|
201
|
+
const transactionId = document.getElementById('transactionId').value.trim();
|
|
202
|
+
if (!transactionId) {
|
|
203
|
+
alert('Lütfen bir işlem ID\'si girin');
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
document.getElementById('verifyResult').innerHTML = '<p>İşlem doğrulanıyor...</p>';
|
|
208
|
+
|
|
209
|
+
fetch(\`/verify/\${transactionId}\`)
|
|
210
|
+
.then(response => response.json())
|
|
211
|
+
.then(data => {
|
|
212
|
+
let html = '<pre>' + JSON.stringify(data, null, 2) + '</pre>';
|
|
213
|
+
document.getElementById('verifyResult').innerHTML = html;
|
|
214
|
+
})
|
|
215
|
+
.catch(error => {
|
|
216
|
+
document.getElementById('verifyResult').innerHTML = '<p class="error">Hata: ' + error + '</p>';
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
</script>
|
|
220
|
+
</body>
|
|
221
|
+
</html>
|
|
222
|
+
`);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// API endpoint - yeni ödeme oluşturma
|
|
226
|
+
app.get('/create-payment', async (req, res) => {
|
|
227
|
+
try {
|
|
228
|
+
const result = await createPaymentExample();
|
|
229
|
+
res.json(result);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
res.status(400).json({ status: 'error', message: error.message });
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Test sunucusunu başlat
|
|
236
|
+
const PORT = process.env.PORT || 3000;
|
|
237
|
+
app.listen(PORT, () => {
|
|
238
|
+
console.log(`🚀 Test sunucusu başlatıldı: http://localhost:${PORT}`);
|
|
239
|
+
console.log(`🔔 Webhook URL: http://localhost:${PORT}/webhook/yallapay`);
|
|
240
|
+
console.log('⚠️ YallaPay Entegrasyon Ayarları:');
|
|
241
|
+
console.log(` - Private Key: ${yallapayConfig.privateKey.substring(0, 10)}...`);
|
|
242
|
+
console.log(` - Para Birimi: ${yallapayConfig.currency}`);
|
|
243
|
+
console.log(` - Webhook Secret: ${yallapayConfig.webhookSecret ? (yallapayConfig.webhookSecret.substring(0, 10) + '...') : 'Ayarlanmadı'}`);
|
|
244
|
+
|
|
245
|
+
console.log('⚠️ Not: Gerçek ortamda, webhook URL\'inizi YallaPay panelinde ayarlayın');
|
|
246
|
+
console.log('⚠️ Ayrıca, example-yallapay.js dosyasındaki private key ve webhook secret\'ı kendi değerlerinizle değiştirmeyi unutmayın');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Sunucuyu kapatmak için CTRL+C
|
|
250
|
+
process.on('SIGINT', () => {
|
|
251
|
+
console.log('Test sunucusu kapatılıyor...');
|
|
252
|
+
process.exit(0);
|
|
253
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const YooKassaClient = require('../lib/yookassa');
|
|
2
|
+
|
|
3
|
+
const client = new YooKassaClient({
|
|
4
|
+
shopId: 'YOUR_SHOP_ID',
|
|
5
|
+
secretKey: 'YOUR_SECRET_KEY'
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
async function example() {
|
|
9
|
+
try {
|
|
10
|
+
const payment = await client.createPayment({
|
|
11
|
+
amount: 1000,
|
|
12
|
+
orderId: 'TEST-001',
|
|
13
|
+
currency: 'RUB',
|
|
14
|
+
callback_link: 'https://yoursite.com/callback',
|
|
15
|
+
description: 'Test Payment',
|
|
16
|
+
email: 'customer@example.com',
|
|
17
|
+
phone: '+79001234567'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
console.log('Payment URL:', payment.data.url);
|
|
21
|
+
console.log('Payment ID:', payment.data.id);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Error:', error.message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
example();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const YouCanPayClient = require('../lib/youcanpay');
|
|
2
|
+
|
|
3
|
+
const client = new YouCanPayClient({
|
|
4
|
+
privateKey: 'YOUR_PRIVATE_KEY',
|
|
5
|
+
publicKey: 'YOUR_PUBLIC_KEY',
|
|
6
|
+
sandbox: true
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
async function example() {
|
|
10
|
+
try {
|
|
11
|
+
const payment = await client.createPayment({
|
|
12
|
+
amount: 100,
|
|
13
|
+
orderId: 'TEST-001',
|
|
14
|
+
currency: 'MAD',
|
|
15
|
+
callback_link: 'https://yoursite.com/callback',
|
|
16
|
+
name: 'Hassan Alaoui',
|
|
17
|
+
email: 'hassan@example.com',
|
|
18
|
+
phone: '+212600000000'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
console.log('Payment URL:', payment.data.url);
|
|
22
|
+
console.log('Token:', payment.data.token);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('Error:', error.message);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
example();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const bodyParser = require('body-parser');
|
|
3
|
+
const QuickPos = require('./app');
|
|
4
|
+
|
|
5
|
+
const app = express();
|
|
6
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
7
|
+
app.use(bodyParser.json());
|
|
8
|
+
|
|
9
|
+
const quickPos = new QuickPos({
|
|
10
|
+
providers: {
|
|
11
|
+
zarinpal: {
|
|
12
|
+
merchantId: 'your-merchant-id',
|
|
13
|
+
sandbox: true // Set to false for production
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
app.use(quickPos.middleware());
|
|
19
|
+
|
|
20
|
+
// Payment form
|
|
21
|
+
app.get('/', (req, res) => {
|
|
22
|
+
res.send(`
|
|
23
|
+
<h1>Zarinpal Payment Example (Iran)</h1>
|
|
24
|
+
<form action="/payment/zarinpal" method="post">
|
|
25
|
+
<input type="text" name="amount" placeholder="Amount (Toman)" required>
|
|
26
|
+
<input type="email" name="email" placeholder="Email" required>
|
|
27
|
+
<input type="text" name="mobile" placeholder="Mobile" required>
|
|
28
|
+
<input type="text" name="orderId" placeholder="Order ID" required>
|
|
29
|
+
<input type="text" name="description" placeholder="Description" required>
|
|
30
|
+
<button type="submit">Pay with Zarinpal</button>
|
|
31
|
+
</form>
|
|
32
|
+
`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Create payment
|
|
36
|
+
app.post('/payment/:provider', async (req, res) => {
|
|
37
|
+
const { provider } = req.params;
|
|
38
|
+
|
|
39
|
+
if (!req.quickPos[provider]) {
|
|
40
|
+
return res.status(400).json({ error: 'Invalid payment provider' });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const result = await req.quickPos[provider].createPayment({
|
|
45
|
+
amount: req.body.amount,
|
|
46
|
+
description: req.body.description,
|
|
47
|
+
email: req.body.email,
|
|
48
|
+
mobile: req.body.mobile,
|
|
49
|
+
orderId: req.body.orderId,
|
|
50
|
+
callback_link: `http://localhost:3000/payment-callback/${provider}`
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (result.status === 'success') {
|
|
54
|
+
res.json({
|
|
55
|
+
success: true,
|
|
56
|
+
redirectUrl: result.data.url,
|
|
57
|
+
authority: result.data.authority
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
res.status(400).json(result);
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
res.status(500).json({ error: error.message });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Payment callback
|
|
68
|
+
app.get('/payment-callback/:provider', async (req, res) => {
|
|
69
|
+
const { provider } = req.params;
|
|
70
|
+
const authority = req.query.Authority;
|
|
71
|
+
const status = req.query.Status;
|
|
72
|
+
|
|
73
|
+
if (status === 'OK') {
|
|
74
|
+
try {
|
|
75
|
+
// You need to verify the payment with the amount stored in your database
|
|
76
|
+
const amount = 1000; // Get this from your database based on authority
|
|
77
|
+
|
|
78
|
+
const result = await quickPos.providers[provider].verifyPayment(authority, amount);
|
|
79
|
+
console.log('Payment verified:', result);
|
|
80
|
+
|
|
81
|
+
res.send(`
|
|
82
|
+
<h1>Payment Successful!</h1>
|
|
83
|
+
<p>Reference ID: ${result.data.refId}</p>
|
|
84
|
+
<p>Authority: ${authority}</p>
|
|
85
|
+
`);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
res.send(`<h1>Payment Verification Failed!</h1><p>${error.message}</p>`);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
res.send('<h1>Payment Cancelled!</h1>');
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const PORT = process.env.PORT || 3000;
|
|
95
|
+
app.listen(PORT, () => {
|
|
96
|
+
console.log(`Server is running on port ${PORT}`);
|
|
97
|
+
console.log(`Open http://localhost:${PORT} to test`);
|
|
98
|
+
});
|
package/lib/2checkout.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class TwoCheckoutClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['merchantCode', 'secretKey'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.merchantCode = config.merchantCode;
|
|
12
|
+
this.secretKey = config.secretKey;
|
|
13
|
+
this.baseURL = config.sandbox
|
|
14
|
+
? 'https://api.sandbox.2checkout.com'
|
|
15
|
+
: 'https://api.2checkout.com';
|
|
16
|
+
|
|
17
|
+
this.client = axios.create({
|
|
18
|
+
baseURL: this.baseURL,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json'
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
generateSignature(params) {
|
|
26
|
+
const signatureString = Object.keys(params)
|
|
27
|
+
.sort()
|
|
28
|
+
.map(key => params[key].length + params[key])
|
|
29
|
+
.join('');
|
|
30
|
+
|
|
31
|
+
return crypto
|
|
32
|
+
.createHmac('sha256', this.secretKey)
|
|
33
|
+
.update(signatureString)
|
|
34
|
+
.digest('hex');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async createPayment(options) {
|
|
38
|
+
try {
|
|
39
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
40
|
+
const timestamp = new Date().toISOString();
|
|
41
|
+
|
|
42
|
+
const params = {
|
|
43
|
+
'merchant': this.merchantCode,
|
|
44
|
+
'dynamic': '1',
|
|
45
|
+
'return-url': options.successUrl || options.callback_link,
|
|
46
|
+
'return-type': 'redirect',
|
|
47
|
+
'expiration': timestamp,
|
|
48
|
+
'order-ext-ref': orderId,
|
|
49
|
+
'item-ext-ref': orderId,
|
|
50
|
+
'customer-ext-ref': options.customerId || '',
|
|
51
|
+
'currency': options.currency || 'USD',
|
|
52
|
+
'language': options.language || 'en',
|
|
53
|
+
'test': options.sandbox ? '1' : '0',
|
|
54
|
+
'prod-name[0]': options.name || 'Payment',
|
|
55
|
+
'prod-type[0]': 'PRODUCT',
|
|
56
|
+
'prod-price[0]': parseFloat(options.amount).toString(),
|
|
57
|
+
'prod-qty[0]': '1',
|
|
58
|
+
'prod-description[0]': options.description || '',
|
|
59
|
+
'customer-email': options.email || '',
|
|
60
|
+
'customer-name': options.customerName || ''
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const signature = this.generateSignature(params);
|
|
64
|
+
params.signature = signature;
|
|
65
|
+
|
|
66
|
+
// Create form URL
|
|
67
|
+
const formParams = new URLSearchParams(params);
|
|
68
|
+
const paymentUrl = `https://secure.2checkout.com/order/checkout.php?${formParams.toString()}`;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
status: 'success',
|
|
72
|
+
data: {
|
|
73
|
+
url: paymentUrl,
|
|
74
|
+
orderId: orderId,
|
|
75
|
+
params: params
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Payment creation error: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async handleCallback(callbackData) {
|
|
84
|
+
try {
|
|
85
|
+
const verification = await this.verifyCallback(callbackData);
|
|
86
|
+
|
|
87
|
+
if (!verification.status) {
|
|
88
|
+
throw new Error(verification.error.message);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const data = verification.data;
|
|
92
|
+
|
|
93
|
+
// Status mapping
|
|
94
|
+
const statusMapping = {
|
|
95
|
+
'COMPLETE': 'success',
|
|
96
|
+
'PENDING': 'pending',
|
|
97
|
+
'REFUND': 'refunded',
|
|
98
|
+
'REVERSED': 'failed'
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
status: statusMapping[data.order_status] || 'unknown',
|
|
103
|
+
orderId: data['order-ext-ref'] || data.order_number,
|
|
104
|
+
transactionId: data.order_number,
|
|
105
|
+
amount: parseFloat(data.invoice_list_amount || data.order_amount),
|
|
106
|
+
currency: data.list_currency,
|
|
107
|
+
paymentStatus: data.order_status,
|
|
108
|
+
invoiceId: data.invoice_id
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new Error(`Error in 2Checkout callback handling: ${error.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async verifyCallback(data) {
|
|
116
|
+
try {
|
|
117
|
+
const hash = data.hash || data.HASH;
|
|
118
|
+
|
|
119
|
+
if (!hash) {
|
|
120
|
+
return {
|
|
121
|
+
status: false,
|
|
122
|
+
error: {
|
|
123
|
+
code: 400,
|
|
124
|
+
message: 'Hash not found in callback data'
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Verify IPN hash
|
|
130
|
+
const params = { ...data };
|
|
131
|
+
delete params.hash;
|
|
132
|
+
delete params.HASH;
|
|
133
|
+
|
|
134
|
+
const calculatedHash = crypto
|
|
135
|
+
.createHmac('md5', this.secretKey)
|
|
136
|
+
.update(JSON.stringify(params))
|
|
137
|
+
.digest('hex');
|
|
138
|
+
|
|
139
|
+
if (hash !== calculatedHash) {
|
|
140
|
+
return {
|
|
141
|
+
status: false,
|
|
142
|
+
error: {
|
|
143
|
+
code: 401,
|
|
144
|
+
message: 'Invalid hash'
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
status: true,
|
|
151
|
+
data: data
|
|
152
|
+
};
|
|
153
|
+
} catch (error) {
|
|
154
|
+
return {
|
|
155
|
+
status: false,
|
|
156
|
+
error: {
|
|
157
|
+
code: 500,
|
|
158
|
+
message: error.message
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = TwoCheckoutClient;
|