quickpos 1.0.914 → 1.0.916
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/lib/paytr.js +190 -46
- package/package.json +1 -1
- package/lib/paytr_eft.js +0 -156
package/lib/paytr.js
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
|
-
const jsSHA = require('jssha');
|
|
3
2
|
const axios = require('axios');
|
|
4
3
|
|
|
5
4
|
class PayTR {
|
|
6
5
|
constructor(config) {
|
|
7
6
|
this.config = config || {};
|
|
7
|
+
|
|
8
8
|
const requiredFields = ['merchantId', 'merchantKey', 'merchantSalt'];
|
|
9
9
|
for (let field of requiredFields) {
|
|
10
|
-
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
10
|
+
if (!this.config[field]) throw new Error(`Missing required field: ${field}`);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
this.merchantId = config.merchantId;
|
|
14
|
-
this.merchantKey = config.merchantKey;
|
|
15
|
-
this.merchantSalt = config.merchantSalt;
|
|
16
|
-
this.
|
|
13
|
+
this.merchantId = this.config.merchantId;
|
|
14
|
+
this.merchantKey = this.config.merchantKey;
|
|
15
|
+
this.merchantSalt = this.config.merchantSalt;
|
|
16
|
+
this.testMode = this.config.testMode ? '1' : '0';
|
|
17
|
+
this.debugOn = this.config.debugOn ? '1' : '0';
|
|
18
|
+
|
|
19
|
+
this.iframe = {
|
|
20
|
+
createToken: this.createIframeToken.bind(this)
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.direct = {
|
|
24
|
+
createPayment: this.createDirectPayment.bind(this)
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
this.link = {
|
|
28
|
+
createPayment: this.createLinkPayment.bind(this)
|
|
29
|
+
};
|
|
17
30
|
}
|
|
18
31
|
|
|
19
|
-
async
|
|
32
|
+
async createLinkPayment(paymentDetails) {
|
|
20
33
|
try {
|
|
21
|
-
|
|
22
|
-
for (let
|
|
23
|
-
if (!paymentDetails[
|
|
34
|
+
const requiredFields = ['name', 'amount', 'currency', 'maxInstallment', 'expiry_date'];
|
|
35
|
+
for (let field of requiredFields) {
|
|
36
|
+
if (!paymentDetails[field]) throw new Error(`Missing required data: ${field}`);
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
const price = Math.round(paymentDetails.amount * 100).toString();
|
|
@@ -42,14 +55,16 @@ class PayTR {
|
|
|
42
55
|
lang: lang,
|
|
43
56
|
min_count: minCount,
|
|
44
57
|
paytr_token: paytrToken,
|
|
45
|
-
expiry_date: paymentDetails
|
|
58
|
+
expiry_date: paymentDetails.expiry_date,
|
|
46
59
|
get_qr: '1',
|
|
47
|
-
max_count: Number(paymentDetails
|
|
48
|
-
debug_on: this.
|
|
60
|
+
max_count: Number(paymentDetails.max_count) || '1',
|
|
61
|
+
debug_on: this.debugOn
|
|
49
62
|
};
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
for (let data of optionalData) {
|
|
64
|
+
const optionalData = ['email', 'callback_link', 'callback_id'];
|
|
65
|
+
for (let data of optionalData) {
|
|
66
|
+
if(paymentDetails[data]) formData[data] = paymentDetails[data];
|
|
67
|
+
}
|
|
53
68
|
|
|
54
69
|
const response = await axios({
|
|
55
70
|
method: 'POST',
|
|
@@ -77,42 +92,179 @@ class PayTR {
|
|
|
77
92
|
}
|
|
78
93
|
} catch (error) {
|
|
79
94
|
if (error.response) {
|
|
80
|
-
// The request was made and the server responded with a status code
|
|
81
|
-
// that falls out of the range of 2xx
|
|
82
95
|
throw new Error(`PayTR API error: ${error.response.data.reason || error.response.statusText}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async createDirectPayment(params) {
|
|
102
|
+
try {
|
|
103
|
+
const userBasket = JSON.stringify(params.userBasket);
|
|
104
|
+
const userIp = params.userIp;
|
|
105
|
+
const merchantOid = params.merchantOid;
|
|
106
|
+
const email = params.email;
|
|
107
|
+
const paymentAmount = params.paymentAmount.toString();
|
|
108
|
+
const currency = params.currency || 'TL';
|
|
109
|
+
const installmentCount = params.installmentCount || '0';
|
|
110
|
+
const paymentType = 'card';
|
|
111
|
+
const non3D = params.non3D ? params.non3D : '0';
|
|
112
|
+
|
|
113
|
+
const rawString = `${this.merchantId}${userIp}${merchantOid}${email}${paymentAmount}${paymentType}${installmentCount}${currency}${this.testMode}${non3D}`;
|
|
114
|
+
const paytrToken = this.generateToken(rawString);
|
|
115
|
+
|
|
116
|
+
const formData = new URLSearchParams();
|
|
117
|
+
formData.append('merchant_id', this.merchantId);
|
|
118
|
+
formData.append('user_ip', userIp);
|
|
119
|
+
formData.append('merchant_oid', merchantOid);
|
|
120
|
+
formData.append('email', email);
|
|
121
|
+
formData.append('payment_amount', paymentAmount);
|
|
122
|
+
formData.append('paytr_token', paytrToken);
|
|
123
|
+
formData.append('user_basket', userBasket);
|
|
124
|
+
formData.append('debug_on', this.debugOn);
|
|
125
|
+
formData.append('test_mode', this.testMode);
|
|
126
|
+
formData.append('payment_type', paymentType);
|
|
127
|
+
formData.append('installment_count', installmentCount);
|
|
128
|
+
formData.append('currency', currency);
|
|
129
|
+
formData.append('non_3d', non3D);
|
|
130
|
+
formData.append('cc_owner', params.cardOwner);
|
|
131
|
+
formData.append('card_number', params.cardNumber);
|
|
132
|
+
formData.append('expiry_month', params.cardExpireMonth);
|
|
133
|
+
formData.append('expiry_year', params.cardExpireYear);
|
|
134
|
+
formData.append('cvc', params.cardCvc);
|
|
135
|
+
formData.append('user_name', params.userName);
|
|
136
|
+
formData.append('user_address', params.userAddress);
|
|
137
|
+
formData.append('user_phone', params.userPhone);
|
|
138
|
+
formData.append('merchant_ok_url', params.merchantOkUrl);
|
|
139
|
+
formData.append('merchant_fail_url', params.merchantFailUrl);
|
|
140
|
+
|
|
141
|
+
const response = await axios({
|
|
142
|
+
method: 'POST',
|
|
143
|
+
url: 'https://www.paytr.com/odeme/api/direct',
|
|
144
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
145
|
+
data: formData
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const result = response.data;
|
|
149
|
+
|
|
150
|
+
if (result.status === 'success') {
|
|
151
|
+
return result;
|
|
86
152
|
} else {
|
|
87
|
-
|
|
88
|
-
throw new Error(`Error in PayTR payment creation: ${error.message}`);
|
|
153
|
+
throw new Error(result.reason || 'PayTR Direct API Hatası');
|
|
89
154
|
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error.response) throw new Error(`PayTR API Error: ${error.response.data.reason || error.response.statusText}`);
|
|
157
|
+
throw error;
|
|
90
158
|
}
|
|
91
159
|
}
|
|
92
160
|
|
|
93
|
-
async
|
|
161
|
+
async createIframeToken(params) {
|
|
94
162
|
try {
|
|
95
|
-
const
|
|
163
|
+
const userBasket = JSON.stringify(params.userBasket);
|
|
164
|
+
const userIp = params.userIp;
|
|
165
|
+
const merchantOid = params.merchantOid;
|
|
166
|
+
const email = params.email;
|
|
167
|
+
const paymentAmount = params.paymentAmount.toString();
|
|
168
|
+
const currency = params.currency || 'TL';
|
|
169
|
+
const noInstallment = params.noInstallment ? '1' : '0';
|
|
170
|
+
const maxInstallment = params.maxInstallment || '0';
|
|
171
|
+
const paymentType = params.paymentType || 'card';
|
|
96
172
|
|
|
97
|
-
let
|
|
98
|
-
|
|
99
|
-
|
|
173
|
+
let rawString;
|
|
174
|
+
|
|
175
|
+
// DÜZELTME BURADA YAPILDI:
|
|
176
|
+
if (paymentType === 'eft') {
|
|
177
|
+
// Python örneğindeki EFT Hash yapısı:
|
|
178
|
+
// merchant_id + user_ip + merchant_oid + email + payment_amount + payment_type + test_mode
|
|
179
|
+
rawString = `${this.merchantId}${userIp}${merchantOid}${email}${paymentAmount}${paymentType}${this.testMode}`;
|
|
180
|
+
} else {
|
|
181
|
+
// Standart Kredi Kartı Hash yapısı:
|
|
182
|
+
// merchant_id + user_ip + merchant_oid + email + payment_amount + user_basket + no_installment + max_installment + currency + test_mode
|
|
183
|
+
rawString = `${this.merchantId}${userIp}${merchantOid}${email}${paymentAmount}${userBasket}${noInstallment}${maxInstallment}${currency}${this.testMode}`;
|
|
100
184
|
}
|
|
101
185
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
186
|
+
// generateToken fonksiyonu sonuna merchantSalt ekleyip şifreler
|
|
187
|
+
const paytrToken = this.generateToken(rawString);
|
|
188
|
+
|
|
189
|
+
const formData = new URLSearchParams();
|
|
190
|
+
formData.append('merchant_id', this.merchantId);
|
|
191
|
+
formData.append('user_ip', userIp);
|
|
192
|
+
formData.append('merchant_oid', merchantOid);
|
|
193
|
+
formData.append('email', email);
|
|
194
|
+
formData.append('payment_amount', paymentAmount);
|
|
195
|
+
formData.append('paytr_token', paytrToken);
|
|
196
|
+
formData.append('debug_on', this.debugOn);
|
|
197
|
+
formData.append('test_mode', this.testMode);
|
|
198
|
+
formData.append('payment_type', paymentType);
|
|
199
|
+
|
|
200
|
+
// timeout_limit parametresi (Python kodunda vardı, ekleyelim)
|
|
201
|
+
formData.append('timeout_limit', params.timeoutLimit || '30');
|
|
202
|
+
|
|
203
|
+
// EFT değilse diğer parametreleri de ekleyelim
|
|
204
|
+
if (paymentType !== 'eft') {
|
|
205
|
+
formData.append('user_basket', userBasket);
|
|
206
|
+
formData.append('no_installment', noInstallment);
|
|
207
|
+
formData.append('max_installment', maxInstallment);
|
|
208
|
+
formData.append('user_name', params.userName);
|
|
209
|
+
formData.append('user_address', params.userAddress);
|
|
210
|
+
formData.append('user_phone', params.userPhone);
|
|
211
|
+
formData.append('merchant_ok_url', params.merchantOkUrl);
|
|
212
|
+
formData.append('merchant_fail_url', params.merchantFailUrl);
|
|
213
|
+
formData.append('currency', currency);
|
|
214
|
+
if (params.lang) formData.append('lang', params.lang);
|
|
111
215
|
} else {
|
|
112
|
-
|
|
216
|
+
// EFT ise banka parametresi varsa ekle
|
|
217
|
+
if (params.bank) formData.append('bank', params.bank);
|
|
113
218
|
}
|
|
219
|
+
|
|
220
|
+
const response = await axios({
|
|
221
|
+
method: 'POST',
|
|
222
|
+
url: 'https://www.paytr.com/odeme/api/get-token',
|
|
223
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
224
|
+
data: formData
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const result = response.data;
|
|
228
|
+
if (result.status === 'success') {
|
|
229
|
+
return { status: 'success', token: result.token };
|
|
230
|
+
} else {
|
|
231
|
+
// Hata detayını daha net görelim
|
|
232
|
+
throw new Error(result.reason || 'PayTR Token alma hatası');
|
|
233
|
+
}
|
|
234
|
+
|
|
114
235
|
} catch (error) {
|
|
115
|
-
throw new Error(`
|
|
236
|
+
if (error.response) throw new Error(`PayTR API Error: ${error.response.data.reason || error.response.statusText}`);
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
handleCallback(callbackData) {
|
|
242
|
+
const { merchant_oid, status, total_amount, hash } = callbackData;
|
|
243
|
+
|
|
244
|
+
if (!hash) throw new Error('Hash param missing');
|
|
245
|
+
|
|
246
|
+
const token = `${merchant_oid}${this.merchantSalt}${status}${total_amount}`;
|
|
247
|
+
|
|
248
|
+
const generatedHash = crypto
|
|
249
|
+
.createHmac('sha256', this.merchantKey)
|
|
250
|
+
.update(token)
|
|
251
|
+
.digest('base64');
|
|
252
|
+
|
|
253
|
+
if (generatedHash !== hash) {
|
|
254
|
+
throw new Error("PAYTR notification failed: bad hash");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (status === 'success') {
|
|
258
|
+
return {
|
|
259
|
+
status: 'success',
|
|
260
|
+
orderId: callbackData.callback_id || merchant_oid,
|
|
261
|
+
merchant_oid: merchant_oid,
|
|
262
|
+
amount: parseFloat(total_amount) / 100,
|
|
263
|
+
currency: callbackData.currency,
|
|
264
|
+
paymentType: callbackData.payment_type
|
|
265
|
+
};
|
|
266
|
+
} else {
|
|
267
|
+
throw new Error("Payment failed");
|
|
116
268
|
}
|
|
117
269
|
}
|
|
118
270
|
|
|
@@ -121,14 +273,6 @@ class PayTR {
|
|
|
121
273
|
.update(data + this.merchantSalt)
|
|
122
274
|
.digest('base64');
|
|
123
275
|
}
|
|
124
|
-
|
|
125
|
-
hashCheck(data, key) {
|
|
126
|
-
let shaObj = new jsSHA("SHA-256", "TEXT");
|
|
127
|
-
shaObj.setHMACKey(this.merchantKey, "TEXT");
|
|
128
|
-
shaObj.update(data);
|
|
129
|
-
if (shaObj.getHMAC("B64") === key) return true;
|
|
130
|
-
else return false;
|
|
131
|
-
}
|
|
132
276
|
}
|
|
133
277
|
|
|
134
278
|
module.exports = PayTR;
|
package/package.json
CHANGED
package/lib/paytr_eft.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
const crypto = require('crypto');
|
|
2
|
-
const axios = require('axios');
|
|
3
|
-
|
|
4
|
-
class PayTR {
|
|
5
|
-
/**
|
|
6
|
-
* PayTR Kurucu Metodu
|
|
7
|
-
* @param {Object} config - Yapılandırma ayarları
|
|
8
|
-
* @param {string} config.merchantId - Mağaza No
|
|
9
|
-
* @param {string} config.merchantKey - Mağaza Parola
|
|
10
|
-
* @param {string} config.merchantSalt - Mağaza Gizli Anahtar
|
|
11
|
-
* @param {boolean} [config.testMode=false] - Test modu (true/false)
|
|
12
|
-
* @param {boolean} [config.debugOn=false] - Hata ayıklama modu
|
|
13
|
-
*/
|
|
14
|
-
constructor(config) {
|
|
15
|
-
this.config = config || {};
|
|
16
|
-
|
|
17
|
-
// Zorunlu alan kontrolü
|
|
18
|
-
const requiredFields = ['merchantId', 'merchantKey', 'merchantSalt'];
|
|
19
|
-
for (let field of requiredFields) {
|
|
20
|
-
if (!this.config[field]) throw new Error(`Missing required field: ${field}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
this.merchantId = this.config.merchantId;
|
|
24
|
-
this.merchantKey = this.config.merchantKey;
|
|
25
|
-
this.merchantSalt = this.config.merchantSalt;
|
|
26
|
-
this.testMode = this.config.testMode ? '1' : '0';
|
|
27
|
-
this.debugOn = this.config.debugOn ? '1' : '0';
|
|
28
|
-
|
|
29
|
-
// iframe namespace'i tanımlama (örnekteki kullanıma uygun olması için)
|
|
30
|
-
this.iframe = {
|
|
31
|
-
createToken: this.createIframeToken.bind(this)
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* iFrame Token Oluşturma (EFT ve Kredi Kartı için)
|
|
37
|
-
* @param {Object} params - Ödeme parametreleri
|
|
38
|
-
*/
|
|
39
|
-
async createIframeToken(params) {
|
|
40
|
-
try {
|
|
41
|
-
const userBasket = JSON.stringify(params.userBasket);
|
|
42
|
-
const userIp = params.userIp;
|
|
43
|
-
const merchantOid = params.merchantOid;
|
|
44
|
-
const email = params.email;
|
|
45
|
-
const paymentAmount = params.paymentAmount.toString(); // Kuruş cinsinden (Örn: 10.00 TL -> 1000)
|
|
46
|
-
const currency = params.currency || 'TL';
|
|
47
|
-
const noInstallment = params.noInstallment ? '1' : '0';
|
|
48
|
-
const maxInstallment = params.maxInstallment || '0';
|
|
49
|
-
const paymentType = params.paymentType || 'card'; // 'eft' veya 'card'
|
|
50
|
-
|
|
51
|
-
// PayTR Token Oluşturma Sırası (Dökümantasyona Göre)
|
|
52
|
-
// merchant_id + user_ip + merchant_oid + email + payment_amount + user_basket + no_installment + max_installment + currency + test_mode
|
|
53
|
-
const rawString = `${this.merchantId}${userIp}${merchantOid}${email}${paymentAmount}${userBasket}${noInstallment}${maxInstallment}${currency}${this.testMode}`;
|
|
54
|
-
|
|
55
|
-
const paytrToken = this.generateToken(rawString);
|
|
56
|
-
|
|
57
|
-
// API'ye gönderilecek veri
|
|
58
|
-
const formData = new URLSearchParams();
|
|
59
|
-
formData.append('merchant_id', this.merchantId);
|
|
60
|
-
formData.append('user_ip', userIp);
|
|
61
|
-
formData.append('merchant_oid', merchantOid);
|
|
62
|
-
formData.append('email', email);
|
|
63
|
-
formData.append('payment_amount', paymentAmount);
|
|
64
|
-
formData.append('paytr_token', paytrToken);
|
|
65
|
-
formData.append('user_basket', userBasket);
|
|
66
|
-
formData.append('debug_on', this.debugOn);
|
|
67
|
-
formData.append('no_installment', noInstallment);
|
|
68
|
-
formData.append('max_installment', maxInstallment);
|
|
69
|
-
formData.append('user_name', params.userName);
|
|
70
|
-
formData.append('user_address', params.userAddress);
|
|
71
|
-
formData.append('user_phone', params.userPhone);
|
|
72
|
-
formData.append('merchant_ok_url', params.merchantOkUrl);
|
|
73
|
-
formData.append('merchant_fail_url', params.merchantFailUrl);
|
|
74
|
-
formData.append('timeout_limit', params.timeoutLimit || '30');
|
|
75
|
-
formData.append('currency', currency);
|
|
76
|
-
formData.append('test_mode', this.testMode);
|
|
77
|
-
formData.append('payment_type', paymentType); // 'eft' gönderimi için kritik
|
|
78
|
-
|
|
79
|
-
// Opsiyonel banka seçimi (Sadece payment_type='eft' ise işe yarar)
|
|
80
|
-
if (params.bank) {
|
|
81
|
-
formData.append('bank', params.bank);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Opsiyonel: Lang
|
|
85
|
-
if (params.lang) {
|
|
86
|
-
formData.append('lang', params.lang);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const response = await axios({
|
|
90
|
-
method: 'POST',
|
|
91
|
-
url: 'https://www.paytr.com/odeme/api/get-token',
|
|
92
|
-
headers: {
|
|
93
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
94
|
-
},
|
|
95
|
-
data: formData
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const result = response.data;
|
|
99
|
-
|
|
100
|
-
if (result.status === 'success') {
|
|
101
|
-
return {
|
|
102
|
-
status: 'success',
|
|
103
|
-
token: result.token
|
|
104
|
-
};
|
|
105
|
-
} else {
|
|
106
|
-
throw new Error(result.reason || 'PayTR Token alma hatası');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
} catch (error) {
|
|
110
|
-
if (error.response) {
|
|
111
|
-
throw new Error(`PayTR API Error: ${error.response.data.reason || error.response.statusText}`);
|
|
112
|
-
}
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Callback (Bildirim) Doğrulama
|
|
119
|
-
* PayTR'den gelen POST isteğinin hash'ini doğrular.
|
|
120
|
-
* @param {Object} reqBody - Express/Http request body
|
|
121
|
-
*/
|
|
122
|
-
validateCallback(reqBody) {
|
|
123
|
-
const { merchant_oid, status, total_amount, hash } = reqBody;
|
|
124
|
-
|
|
125
|
-
// Hash Oluşturma Sırası:
|
|
126
|
-
// merchant_oid + merchant_salt + status + total_amount
|
|
127
|
-
const rawString = `${merchant_oid}${this.merchantSalt}${status}${total_amount}`;
|
|
128
|
-
const generatedHash = this.generateToken(rawString);
|
|
129
|
-
|
|
130
|
-
if (hash === generatedHash) {
|
|
131
|
-
return {
|
|
132
|
-
success: true,
|
|
133
|
-
merchantOid: merchant_oid,
|
|
134
|
-
status: status,
|
|
135
|
-
totalAmount: total_amount
|
|
136
|
-
};
|
|
137
|
-
} else {
|
|
138
|
-
return {
|
|
139
|
-
success: false,
|
|
140
|
-
error: 'Hash mismatch'
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Helper: HMAC-SHA256 Token Üretici
|
|
147
|
-
*/
|
|
148
|
-
generateToken(data) {
|
|
149
|
-
return crypto
|
|
150
|
-
.createHmac('sha256', this.merchantKey)
|
|
151
|
-
.update(data + this.merchantSalt)
|
|
152
|
-
.digest('base64');
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
module.exports = PayTR;
|