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
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
class Shopier {
|
|
4
|
+
/**
|
|
5
|
+
* @param {Object} config
|
|
6
|
+
* @param {string} config.apiKey - Shopier API Key
|
|
7
|
+
* @param {string} config.apiSecret - Shopier API Secret
|
|
8
|
+
*/
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config || {};
|
|
11
|
+
const requiredFields = ['apiKey', 'apiSecret', 'website'];
|
|
12
|
+
|
|
13
|
+
for (let field of requiredFields) {
|
|
14
|
+
if (!config[field]) throw new Error(`Shopier: Missing required config field: ${field}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
this.apiKey = config.apiKey;
|
|
18
|
+
this.websiteIndex = Number(config.website);
|
|
19
|
+
this.apiSecret = config.apiSecret;
|
|
20
|
+
this.paymentUrl = 'https://www.shopier.com/ShowProduct/api_pay4.php';
|
|
21
|
+
this.moduleVersion = '1.0.4';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Ödeme Formunu Oluşturur
|
|
26
|
+
* @param {Object} paymentDetails
|
|
27
|
+
* @param {number} paymentDetails.amount - Ödenecek tutar (Örn: 15.50)
|
|
28
|
+
* @param {string} paymentDetails.currency - Para birimi (TRY, USD, EUR) varsayılan: TRY
|
|
29
|
+
* @param {string} paymentDetails.orderId - Sipariş numarası (Benzersiz olmalı)
|
|
30
|
+
* @param {Object} paymentDetails.buyer - Alıcı bilgileri { first_name, last_name, email, phone, id_nr }
|
|
31
|
+
* @param {Object} paymentDetails.billingAddress - Fatura adresi { address, city, country, postcode }
|
|
32
|
+
* @param {Object} paymentDetails.shippingAddress - Teslimat adresi { address, city, country, postcode }
|
|
33
|
+
*/
|
|
34
|
+
createPayment(paymentDetails) {
|
|
35
|
+
try {
|
|
36
|
+
// 1. Temel Doğrulamalar
|
|
37
|
+
if (!paymentDetails.amount) throw new Error('Shopier: Amount is required');
|
|
38
|
+
if (!paymentDetails.buyer) throw new Error('Shopier: Buyer information is required');
|
|
39
|
+
if (!paymentDetails.billingAddress) throw new Error('Shopier: Billing address is required');
|
|
40
|
+
if (!paymentDetails.shippingAddress) throw new Error('Shopier: Shipping address is required');
|
|
41
|
+
|
|
42
|
+
const currency = paymentDetails.currency || 'TRY';
|
|
43
|
+
const currentLang = 0; // 0: TR, 1: EN (Otomatik TR ayarlandı, isteğe göre parametreye bağlanabilir)
|
|
44
|
+
const randomNr = Math.floor(Math.random() * (999999 - 100000 + 1)) + 100000;
|
|
45
|
+
|
|
46
|
+
// Sipariş ID yoksa rastgele oluştur
|
|
47
|
+
const platformOrderId = paymentDetails.orderId || `Ord-${randomNr}`;
|
|
48
|
+
|
|
49
|
+
// 2. Shopier İçin Argümanları Hazırla
|
|
50
|
+
const args = {
|
|
51
|
+
API_key: this.apiKey,
|
|
52
|
+
website_index: this.websiteIndex || 0,
|
|
53
|
+
platform_order_id: platformOrderId,
|
|
54
|
+
product_name: paymentDetails.product_name || 'Balance Payment',
|
|
55
|
+
product_type: 0, // 0: Reel nesne, 1: Sanal
|
|
56
|
+
buyer_name: paymentDetails.buyer.first_name,
|
|
57
|
+
buyer_surname: paymentDetails.buyer.last_name,
|
|
58
|
+
buyer_email: paymentDetails.buyer.email,
|
|
59
|
+
buyer_account_age: 0,
|
|
60
|
+
buyer_id_nr: paymentDetails.buyer.id_nr || '0', // Opsiyonel ID
|
|
61
|
+
buyer_phone: paymentDetails.buyer.phone,
|
|
62
|
+
|
|
63
|
+
// Fatura
|
|
64
|
+
billing_address: paymentDetails.billingAddress.address,
|
|
65
|
+
billing_city: paymentDetails.billingAddress.city,
|
|
66
|
+
billing_country: paymentDetails.billingAddress.country,
|
|
67
|
+
billing_postcode: paymentDetails.billingAddress.postcode,
|
|
68
|
+
|
|
69
|
+
// Teslimat
|
|
70
|
+
shipping_address: paymentDetails.shippingAddress.address,
|
|
71
|
+
shipping_city: paymentDetails.shippingAddress.city,
|
|
72
|
+
shipping_country: paymentDetails.shippingAddress.country,
|
|
73
|
+
shipping_postcode: paymentDetails.shippingAddress.postcode,
|
|
74
|
+
|
|
75
|
+
total_order_value: paymentDetails.amount,
|
|
76
|
+
currency: this._mapCurrency(currency),
|
|
77
|
+
platform: 0,
|
|
78
|
+
is_in_frame: 0,
|
|
79
|
+
current_language: currentLang,
|
|
80
|
+
modul_version: this.moduleVersion,
|
|
81
|
+
random_nr: randomNr
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// 3. Eksik Alan Kontrolü
|
|
85
|
+
Object.keys(args).forEach(key => {
|
|
86
|
+
if (args[key] === undefined || args[key] === null) {
|
|
87
|
+
// Opsiyonel alanlar için esneklik sağlanabilir ama kritik alanlar için hata fırlatıyoruz
|
|
88
|
+
// throw new Error(`Shopier: Parameter ${key} is missing`);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 4. İmza Oluşturma (Native Crypto)
|
|
93
|
+
const dataToSign = args.random_nr + args.platform_order_id + args.total_order_value + args.currency;
|
|
94
|
+
const signature = crypto.createHmac('sha256', this.apiSecret)
|
|
95
|
+
.update(dataToSign)
|
|
96
|
+
.digest('base64');
|
|
97
|
+
|
|
98
|
+
args.signature = signature;
|
|
99
|
+
|
|
100
|
+
// 5. HTML Formunu Oluştur
|
|
101
|
+
const formHtml = this._generateHtml(args);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
status: 'success',
|
|
105
|
+
data: {
|
|
106
|
+
orderId: platformOrderId,
|
|
107
|
+
amount: paymentDetails.amount,
|
|
108
|
+
html: formHtml // Frontend'de bu HTML'i ekrana basıp formu submit edeceksin
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(`Error in Shopier payment creation: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Callback (Geri Dönüş) İşleme
|
|
119
|
+
* @param {Object} body - POST request body
|
|
120
|
+
*/
|
|
121
|
+
handleCallback(body) {
|
|
122
|
+
try {
|
|
123
|
+
const data = body.random_nr + body.platform_order_id;
|
|
124
|
+
// Gelen imza base64, bunu normal stringe çevirip karşılaştırmalıyız ya da direkt ürettiğimizi karşılaştırmalıyız.
|
|
125
|
+
// Shopier dökümantasyonuna göre: HmacSHA256(random_nr + platform_order_id, secret) == signature (base64)
|
|
126
|
+
|
|
127
|
+
const expectedSignature = crypto.createHmac('sha256', this.apiSecret)
|
|
128
|
+
.update(data)
|
|
129
|
+
.digest('base64');
|
|
130
|
+
|
|
131
|
+
if (body.signature === expectedSignature) {
|
|
132
|
+
if (body.status === 'success') {
|
|
133
|
+
return {
|
|
134
|
+
success: true,
|
|
135
|
+
order_id: body.platform_order_id,
|
|
136
|
+
payment_id: body.payment_id,
|
|
137
|
+
installment: body.installment,
|
|
138
|
+
random_nr: body.random_nr
|
|
139
|
+
};
|
|
140
|
+
} else {
|
|
141
|
+
return { success: false, message: "Shopier: Payment status is not success." };
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
throw new Error('Shopier: Signature mismatch. Invalid callback.');
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw new Error(`Error in Shopier callback handling: ${error.message}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// --- Private Helpers ---
|
|
152
|
+
|
|
153
|
+
_generateHtml(args) {
|
|
154
|
+
let inputs = '';
|
|
155
|
+
Object.keys(args).forEach(key => {
|
|
156
|
+
inputs += `<input type="hidden" name="${key}" value="${args[key]}">`;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return `<!doctype html>
|
|
160
|
+
<html lang="tr">
|
|
161
|
+
<head>
|
|
162
|
+
<meta charset="UTF-8">
|
|
163
|
+
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
164
|
+
<title>Ödeme Yapılıyor...</title>
|
|
165
|
+
</head>
|
|
166
|
+
<body>
|
|
167
|
+
<form id="shopier_payment_form" method="post" action="${this.paymentUrl}">
|
|
168
|
+
${inputs}
|
|
169
|
+
</form>
|
|
170
|
+
<script type="text/javascript">
|
|
171
|
+
document.getElementById("shopier_payment_form").submit();
|
|
172
|
+
</script>
|
|
173
|
+
</body>
|
|
174
|
+
</html>`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
_mapCurrency(currency) {
|
|
178
|
+
switch(currency) {
|
|
179
|
+
case 'TL':
|
|
180
|
+
case 'TRY': return 0;
|
|
181
|
+
case 'USD': return 1;
|
|
182
|
+
case 'EUR': return 2;
|
|
183
|
+
default: return 0;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = Shopier;
|
package/lib/shurjopay.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class ShurjoPayClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['username', 'password', 'prefix'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.username = config.username;
|
|
12
|
+
this.password = config.password;
|
|
13
|
+
this.prefix = config.prefix;
|
|
14
|
+
this.baseURL = config.sandbox
|
|
15
|
+
? 'https://sandbox.shurjopayment.com'
|
|
16
|
+
: 'https://engine.shurjopayment.com';
|
|
17
|
+
|
|
18
|
+
this.token = null;
|
|
19
|
+
|
|
20
|
+
this.client = axios.create({
|
|
21
|
+
baseURL: this.baseURL,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json'
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async authenticate() {
|
|
29
|
+
try {
|
|
30
|
+
const response = await this.client.post('/api/get_token', {
|
|
31
|
+
username: this.username,
|
|
32
|
+
password: this.password
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (response.data.token) {
|
|
36
|
+
this.token = response.data.token;
|
|
37
|
+
this.client.defaults.headers['Authorization'] = `Bearer ${this.token}`;
|
|
38
|
+
return this.token;
|
|
39
|
+
} else {
|
|
40
|
+
throw new Error('Authentication failed');
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
throw new Error(`Authentication error: ${error.response?.data?.message || error.message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async createPayment(options) {
|
|
48
|
+
try {
|
|
49
|
+
if (!this.token) {
|
|
50
|
+
await this.authenticate();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const orderId = options.orderId || `${this.prefix}${Date.now()}`;
|
|
54
|
+
|
|
55
|
+
const paymentData = {
|
|
56
|
+
prefix: this.prefix,
|
|
57
|
+
token: this.token,
|
|
58
|
+
return_url: options.successUrl || options.callback_link,
|
|
59
|
+
cancel_url: options.failUrl || options.callback_link,
|
|
60
|
+
store_id: this.prefix,
|
|
61
|
+
amount: parseFloat(options.amount),
|
|
62
|
+
order_id: orderId,
|
|
63
|
+
currency: options.currency || 'BDT',
|
|
64
|
+
customer_name: options.name || options.customerName || '',
|
|
65
|
+
customer_address: options.address || '',
|
|
66
|
+
customer_city: options.city || 'Dhaka',
|
|
67
|
+
customer_phone: options.phone || '',
|
|
68
|
+
customer_email: options.email || '',
|
|
69
|
+
client_ip: options.clientIp || '127.0.0.1',
|
|
70
|
+
intent: 'sale',
|
|
71
|
+
discsount_amount: options.discount || 0,
|
|
72
|
+
disc_percent: options.discountPercent || 0
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const response = await this.client.post('/api/secret-pay', paymentData);
|
|
76
|
+
|
|
77
|
+
if (response.data.checkout_url) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'success',
|
|
80
|
+
data: {
|
|
81
|
+
url: response.data.checkout_url,
|
|
82
|
+
orderId: orderId,
|
|
83
|
+
amount: paymentData.amount,
|
|
84
|
+
currency: paymentData.currency,
|
|
85
|
+
sp_order_id: response.data.sp_order_id
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error(response.data.message || 'Payment creation failed');
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
throw new Error(`Payment creation error: ${error.response?.data?.message || error.message}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async handleCallback(callbackData) {
|
|
97
|
+
try {
|
|
98
|
+
const orderId = callbackData.order_id;
|
|
99
|
+
|
|
100
|
+
if (!orderId) {
|
|
101
|
+
throw new Error('Order ID not found in callback data');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Verify payment
|
|
105
|
+
const verification = await this.verifyPayment(orderId);
|
|
106
|
+
|
|
107
|
+
// Status mapping
|
|
108
|
+
const statusMapping = {
|
|
109
|
+
'success': 'success',
|
|
110
|
+
'Success': 'success',
|
|
111
|
+
'failed': 'failed',
|
|
112
|
+
'Failed': 'failed',
|
|
113
|
+
'pending': 'pending',
|
|
114
|
+
'Pending': 'pending',
|
|
115
|
+
'cancel': 'failed',
|
|
116
|
+
'Cancel': 'failed'
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
status: statusMapping[verification[0].sp_status] || 'unknown',
|
|
121
|
+
orderId: verification[0].order_id,
|
|
122
|
+
transactionId: verification[0].bank_trx_id,
|
|
123
|
+
amount: parseFloat(verification[0].amount),
|
|
124
|
+
currency: verification[0].currency,
|
|
125
|
+
paymentStatus: verification[0].sp_status,
|
|
126
|
+
method: verification[0].method,
|
|
127
|
+
bankStatus: verification[0].bank_status
|
|
128
|
+
};
|
|
129
|
+
} catch (error) {
|
|
130
|
+
throw new Error(`Error in ShurjoPay callback handling: ${error.message}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async verifyPayment(orderId) {
|
|
135
|
+
try {
|
|
136
|
+
if (!this.token) {
|
|
137
|
+
await this.authenticate();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const response = await this.client.post('/api/verification', {
|
|
141
|
+
order_id: orderId
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return response.data;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`Error verifying payment: ${error.response?.data?.message || error.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async getPaymentStatus(orderId) {
|
|
151
|
+
try {
|
|
152
|
+
return await this.verifyPayment(orderId);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
throw new Error(`Error getting payment status: ${error.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = ShurjoPayClient;
|
package/lib/toyyibpay.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class ToyyibPayClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['secretKey', 'categoryCode'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.secretKey = config.secretKey;
|
|
12
|
+
this.categoryCode = config.categoryCode;
|
|
13
|
+
this.URL = 'https://dev.toyyibpay.com';
|
|
14
|
+
|
|
15
|
+
this.client = axios.create({
|
|
16
|
+
baseURL: this.URL,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.client.interceptors.response.use(response => {
|
|
23
|
+
return response;
|
|
24
|
+
}, error => {
|
|
25
|
+
if (error.response) {
|
|
26
|
+
throw new Error(`ToyyibPay API error: ${error.response.data.message || error.message}`);
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`ToyyibPay API error: ${error.message}`);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async createPayment(options) {
|
|
33
|
+
try {
|
|
34
|
+
const params = new URLSearchParams();
|
|
35
|
+
params.append('userSecretKey', this.secretKey);
|
|
36
|
+
params.append('categoryCode', this.categoryCode);
|
|
37
|
+
params.append('billName', options.billName || options.name || 'Bill');
|
|
38
|
+
params.append('billDescription', options.billDescription || options.description || 'Payment');
|
|
39
|
+
params.append('billPriceSetting', '1');
|
|
40
|
+
params.append('billPayorInfo', '1');
|
|
41
|
+
params.append('billAmount', Math.round(parseFloat(options.amount) * 100));
|
|
42
|
+
params.append('billReturnUrl', options.returnUrl || options.callback_link);
|
|
43
|
+
params.append('billCallbackUrl', options.callbackUrl || options.callback_link);
|
|
44
|
+
params.append('billExternalReferenceNo', options.referenceNo || options.orderId || `ORDER-${Date.now()}`);
|
|
45
|
+
params.append('billTo', options.billTo || options.customerName || options.name || 'Customer');
|
|
46
|
+
params.append('billEmail', options.billEmail || options.email);
|
|
47
|
+
params.append('billPhone', options.billPhone || options.phone || '60123456789');
|
|
48
|
+
params.append('billSplitPayment', '0');
|
|
49
|
+
params.append('billSplitPaymentArgs', '');
|
|
50
|
+
params.append('billPaymentChannel', options.paymentChannel || '0');
|
|
51
|
+
params.append('billContentEmail', options.contentEmail || 'Thank you for your payment');
|
|
52
|
+
|
|
53
|
+
if (options.billChargeToCustomer) {
|
|
54
|
+
params.append('billChargeToCustomer', options.billChargeToCustomer);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const response = await this.client.post('/index.php/api/createBill', params);
|
|
58
|
+
|
|
59
|
+
if (response.data[0].BillCode) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'success',
|
|
62
|
+
data: {
|
|
63
|
+
billCode: response.data[0].BillCode,
|
|
64
|
+
url: `${this.URL}/${response.data[0].BillCode}`,
|
|
65
|
+
referenceNo: options.referenceNo || options.orderId
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(response.data[0].error || 'Payment creation failed');
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error(`Payment creation error: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getBillTransactions(billCode) {
|
|
77
|
+
try {
|
|
78
|
+
const params = new URLSearchParams();
|
|
79
|
+
params.append('billCode', billCode);
|
|
80
|
+
|
|
81
|
+
const response = await this.client.post('/index.php/api/getBillTransactions', params);
|
|
82
|
+
return response.data;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw new Error(`Bill transactions error: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async handleCallback(callbackData) {
|
|
89
|
+
try {
|
|
90
|
+
const verification = await this.verifyCallback(callbackData);
|
|
91
|
+
|
|
92
|
+
if (!verification.status) {
|
|
93
|
+
throw new Error(verification.error.message);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const data = verification.data;
|
|
97
|
+
|
|
98
|
+
// Status mapping: 1 = success, 2 = pending, 3 = failed
|
|
99
|
+
const statusMapping = {
|
|
100
|
+
'1': 'success',
|
|
101
|
+
'2': 'pending',
|
|
102
|
+
'3': 'failed'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
status: statusMapping[data.status_id] || 'unknown',
|
|
107
|
+
billCode: data.billcode,
|
|
108
|
+
orderId: data.order_id || data.billExternalReferenceNo,
|
|
109
|
+
amount: parseFloat(data.amount) / 100,
|
|
110
|
+
transactionId: data.transaction_id,
|
|
111
|
+
paymentStatus: data.status_id,
|
|
112
|
+
transactionTime: data.transaction_time,
|
|
113
|
+
payerName: data.billpayorname,
|
|
114
|
+
payerEmail: data.billpayoremail,
|
|
115
|
+
payerPhone: data.billpayorphone
|
|
116
|
+
};
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(`Error in ToyyibPay callback handling: ${error.message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async verifyCallback(data) {
|
|
123
|
+
try {
|
|
124
|
+
// ToyyibPay uses hash verification
|
|
125
|
+
if (data.status_id === '3') {
|
|
126
|
+
return {
|
|
127
|
+
status: false,
|
|
128
|
+
error: {
|
|
129
|
+
code: 400,
|
|
130
|
+
message: 'Payment failed'
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
status: true,
|
|
137
|
+
data: data
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
status: false,
|
|
142
|
+
error: {
|
|
143
|
+
code: 500,
|
|
144
|
+
message: error.message
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = ToyyibPayClient;
|