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
package/lib/konnect.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Konnect Ödeme Entegrasyonu
|
|
5
|
+
*
|
|
6
|
+
* Başlamadan önce:
|
|
7
|
+
* 1. Konnect hesabı oluşturun:
|
|
8
|
+
* - Sandbox (test): https://dashboard.sandbox.konnect.network
|
|
9
|
+
* - Üretim: https://dashboard.konnect.network
|
|
10
|
+
* 2. KYC/KYB doğrulamasını tamamlayın (kimlik ve kurum doğrulama)
|
|
11
|
+
* 3. API anahtarınızı ve cüzdan ID'nizi alın
|
|
12
|
+
*/
|
|
13
|
+
class KonnectService {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config || {};
|
|
16
|
+
const requiredFields = ['apiKey', 'receiverWalletId'];
|
|
17
|
+
for (let field of requiredFields) {
|
|
18
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.apiKey = config.apiKey;
|
|
22
|
+
this.receiverWalletId = config.receiverWalletId;
|
|
23
|
+
|
|
24
|
+
// Sandbox veya Production modu seçimi
|
|
25
|
+
this.sandbox = config.sandbox || false;
|
|
26
|
+
|
|
27
|
+
// API URL'ini ortama göre ayarla
|
|
28
|
+
if (this.sandbox) {
|
|
29
|
+
this.baseUrl = 'https://api.sandbox.konnect.network/api/v2';
|
|
30
|
+
} else {
|
|
31
|
+
this.baseUrl = config.baseUrl || 'https://api.konnect.network/api/v2';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(`Konnect API URL: ${this.baseUrl}`);
|
|
35
|
+
this.testMode = config.testMode || false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async createPayment(paymentDetails) {
|
|
39
|
+
try {
|
|
40
|
+
let requiredData = ['amount', 'token'];
|
|
41
|
+
for (let data of requiredData) {
|
|
42
|
+
if (!paymentDetails[data]) throw new Error(`Missing required data: ${data}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Temel ödeme verilerini hazırla
|
|
46
|
+
const paymentData = {
|
|
47
|
+
receiverWalletId: this.receiverWalletId,
|
|
48
|
+
token: paymentDetails.token || 'TND',
|
|
49
|
+
amount: paymentDetails.amount,
|
|
50
|
+
type: paymentDetails.type || 'immediate',
|
|
51
|
+
description: paymentDetails.description || 'Ödeme',
|
|
52
|
+
acceptedPaymentMethods: paymentDetails.acceptedPaymentMethods || ["wallet", "bank_card", "e-DINAR"],
|
|
53
|
+
lifespan: paymentDetails.lifespan || 60, // varsayılan 60 dakika
|
|
54
|
+
checkoutForm: paymentDetails.checkoutForm || false,
|
|
55
|
+
addPaymentFeesToAmount: paymentDetails.addPaymentFeesToAmount || false,
|
|
56
|
+
orderId: paymentDetails.orderId || `order-${Date.now()}`,
|
|
57
|
+
theme: paymentDetails.theme || 'light'
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Müşteri bilgilerini ekle (varsa)
|
|
61
|
+
if (paymentDetails.firstName) paymentData.firstName = paymentDetails.firstName;
|
|
62
|
+
if (paymentDetails.lastName) paymentData.lastName = paymentDetails.lastName;
|
|
63
|
+
if (paymentDetails.phoneNumber) paymentData.phoneNumber = paymentDetails.phoneNumber;
|
|
64
|
+
if (paymentDetails.email) paymentData.email = paymentDetails.email;
|
|
65
|
+
|
|
66
|
+
// Webhook URL'ini ekle (varsa)
|
|
67
|
+
if (paymentDetails.webhook) paymentData.webhook = paymentDetails.webhook;
|
|
68
|
+
|
|
69
|
+
console.log('Konnect ödeme isteği hazırlanıyor:', JSON.stringify(paymentData, null, 2));
|
|
70
|
+
|
|
71
|
+
// API isteği gönder
|
|
72
|
+
const response = await axios({
|
|
73
|
+
method: 'POST',
|
|
74
|
+
url: `${this.baseUrl}/payments/init-payment`,
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
'x-api-key': this.apiKey
|
|
78
|
+
},
|
|
79
|
+
data: paymentData
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const responseData = response.data;
|
|
83
|
+
console.log('Konnect API yanıtı:', JSON.stringify(responseData, null, 2));
|
|
84
|
+
|
|
85
|
+
// QR kod oluştur (isteğe bağlı)
|
|
86
|
+
let qrCode = null;
|
|
87
|
+
if (paymentDetails.generateQr) {
|
|
88
|
+
qrCode = await this.generateQrCode(responseData.payUrl);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
status: 'success',
|
|
93
|
+
data: {
|
|
94
|
+
transactionId: responseData.paymentRef,
|
|
95
|
+
url: responseData.payUrl,
|
|
96
|
+
id: responseData.paymentRef,
|
|
97
|
+
qr: qrCode
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('Konnect API hatası:', error);
|
|
102
|
+
|
|
103
|
+
if (error.response) {
|
|
104
|
+
console.error('Hata detayları:', {
|
|
105
|
+
statusCode: error.response.status,
|
|
106
|
+
statusText: error.response.statusText,
|
|
107
|
+
data: error.response.data
|
|
108
|
+
});
|
|
109
|
+
throw new Error(`Konnect API error (${error.response.status}): ${JSON.stringify(error.response.data)}`);
|
|
110
|
+
} else if (error.request) {
|
|
111
|
+
console.error('Yanıt alınamadı:', error.request);
|
|
112
|
+
throw new Error('No response received from Konnect API');
|
|
113
|
+
} else {
|
|
114
|
+
throw new Error(`Error in Konnect payment creation: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getPaymentDetails(paymentRef) {
|
|
120
|
+
try {
|
|
121
|
+
const response = await axios({
|
|
122
|
+
method: 'GET',
|
|
123
|
+
url: `${this.baseUrl}/payments/${paymentRef}`,
|
|
124
|
+
headers: {
|
|
125
|
+
'x-api-key': this.apiKey
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const paymentData = response.data.payment;
|
|
130
|
+
|
|
131
|
+
// İşlem durumunu belirle
|
|
132
|
+
let status = 'pending';
|
|
133
|
+
if (paymentData.status === 'completed') {
|
|
134
|
+
status = 'success';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
status: status,
|
|
139
|
+
paymentId: paymentData.id,
|
|
140
|
+
orderId: paymentData.orderId,
|
|
141
|
+
amount: paymentData.amount,
|
|
142
|
+
reachedAmount: paymentData.reachedAmount,
|
|
143
|
+
token: paymentData.token,
|
|
144
|
+
type: paymentData.type,
|
|
145
|
+
description: paymentData.details,
|
|
146
|
+
expirationDate: paymentData.expirationDate,
|
|
147
|
+
transactions: paymentData.transactions || [],
|
|
148
|
+
raw: paymentData
|
|
149
|
+
};
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error.response && error.response.status === 404) {
|
|
152
|
+
throw new Error(`Payment not found: ${paymentRef}`);
|
|
153
|
+
} else if (error.response) {
|
|
154
|
+
throw new Error(`Konnect API error: ${error.response.data.message || error.response.statusText}`);
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(`Error fetching payment details: ${error.message}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async handleCallback(callbackData) {
|
|
162
|
+
try {
|
|
163
|
+
if (!callbackData.payment_ref) {
|
|
164
|
+
throw new Error("Missing payment_ref in callback data");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Ödeme detaylarını al
|
|
168
|
+
const paymentDetails = await this.getPaymentDetails(callbackData.payment_ref);
|
|
169
|
+
|
|
170
|
+
if (paymentDetails.status === 'success') {
|
|
171
|
+
return {
|
|
172
|
+
status: 'success',
|
|
173
|
+
orderId: paymentDetails.orderId,
|
|
174
|
+
merchant_oid: paymentDetails.paymentId,
|
|
175
|
+
amount: paymentDetails.amount,
|
|
176
|
+
currency: paymentDetails.token,
|
|
177
|
+
paymentType: 'konnect'
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
return {
|
|
181
|
+
status: 'failed',
|
|
182
|
+
orderId: paymentDetails.orderId || callbackData.payment_ref,
|
|
183
|
+
reason: 'Payment is not completed'
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
throw new Error(`Error in Konnect callback handling: ${error.message}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// QR kod oluşturmak için yardımcı fonksiyon
|
|
192
|
+
async generateQrCode(paymentUrl) {
|
|
193
|
+
try {
|
|
194
|
+
const response = await axios.get('https://api.qrserver.com/v1/create-qr-code/', {
|
|
195
|
+
params: {
|
|
196
|
+
size: '300x300',
|
|
197
|
+
data: paymentUrl
|
|
198
|
+
},
|
|
199
|
+
responseType: 'arraybuffer'
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const base64Image = Buffer.from(response.data, 'binary').toString('base64');
|
|
203
|
+
return `data:image/png;base64,${base64Image}`;
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('QR code generation failed:', error);
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = KonnectService;
|
package/lib/midtrans.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class MidtransClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
const requiredFields = ['serverKey', 'clientKey'];
|
|
7
|
+
for (let field of requiredFields) {
|
|
8
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.serverKey = config.serverKey;
|
|
12
|
+
this.clientKey = config.clientKey;
|
|
13
|
+
this.isProduction = config.isProduction || false;
|
|
14
|
+
|
|
15
|
+
this.snapURL = this.isProduction
|
|
16
|
+
? 'https://app.midtrans.com/snap/v1'
|
|
17
|
+
: 'https://app.sandbox.midtrans.com/snap/v1';
|
|
18
|
+
|
|
19
|
+
this.coreURL = this.isProduction
|
|
20
|
+
? 'https://api.midtrans.com/v2'
|
|
21
|
+
: 'https://api.sandbox.midtrans.com/v2';
|
|
22
|
+
|
|
23
|
+
this.client = axios.create({
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
'Accept': 'application/json',
|
|
27
|
+
'Authorization': 'Basic ' + Buffer.from(this.serverKey + ':').toString('base64')
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.client.interceptors.response.use(response => {
|
|
32
|
+
return response;
|
|
33
|
+
}, error => {
|
|
34
|
+
if (error.response) {
|
|
35
|
+
throw new Error(`Midtrans API error: ${error.response.data.error_messages || error.response.data.status_message || error.message}`);
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Midtrans API error: ${error.message}`);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async createPayment(options) {
|
|
42
|
+
try {
|
|
43
|
+
const orderId = options.orderId || `ORDER-${Date.now()}`;
|
|
44
|
+
|
|
45
|
+
const transactionDetails = {
|
|
46
|
+
transaction_details: {
|
|
47
|
+
order_id: orderId,
|
|
48
|
+
gross_amount: parseFloat(options.amount)
|
|
49
|
+
},
|
|
50
|
+
customer_details: {
|
|
51
|
+
first_name: options.firstName || options.name || 'Customer',
|
|
52
|
+
last_name: options.lastName || '',
|
|
53
|
+
email: options.email,
|
|
54
|
+
phone: options.phone || '+62812345678'
|
|
55
|
+
},
|
|
56
|
+
callbacks: {
|
|
57
|
+
finish: options.callbackUrl || options.callback_link
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Item details ekleme
|
|
62
|
+
if (options.items && Array.isArray(options.items)) {
|
|
63
|
+
transactionDetails.item_details = options.items;
|
|
64
|
+
} else {
|
|
65
|
+
transactionDetails.item_details = [{
|
|
66
|
+
id: 'ITEM-' + orderId,
|
|
67
|
+
price: parseFloat(options.amount),
|
|
68
|
+
quantity: 1,
|
|
69
|
+
name: options.itemName || options.name || 'Product'
|
|
70
|
+
}];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Opsiyonel alanlar
|
|
74
|
+
if (options.creditCard) {
|
|
75
|
+
transactionDetails.credit_card = options.creditCard;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (options.customExpiry) {
|
|
79
|
+
transactionDetails.custom_expiry = options.customExpiry;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const response = await this.client.post(`${this.snapURL}/transactions`, transactionDetails);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
status: 'success',
|
|
86
|
+
data: {
|
|
87
|
+
token: response.data.token,
|
|
88
|
+
url: response.data.redirect_url,
|
|
89
|
+
orderId: orderId
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
throw new Error(`Payment creation error: ${error.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async getTransactionStatus(orderId) {
|
|
98
|
+
try {
|
|
99
|
+
const response = await this.client.get(`${this.coreURL}/${orderId}/status`);
|
|
100
|
+
return response.data;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new Error(`Transaction status error: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async handleCallback(callbackData) {
|
|
107
|
+
try {
|
|
108
|
+
const verification = await this.verifyNotification(callbackData);
|
|
109
|
+
|
|
110
|
+
if (!verification.status) {
|
|
111
|
+
throw new Error(verification.error.message);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const data = verification.data;
|
|
115
|
+
|
|
116
|
+
// Transaction status mapping
|
|
117
|
+
const statusMapping = {
|
|
118
|
+
'capture': 'success',
|
|
119
|
+
'settlement': 'success',
|
|
120
|
+
'pending': 'pending',
|
|
121
|
+
'deny': 'failed',
|
|
122
|
+
'cancel': 'cancelled',
|
|
123
|
+
'expire': 'expired',
|
|
124
|
+
'failure': 'failed'
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
status: statusMapping[data.transaction_status] || 'unknown',
|
|
129
|
+
orderId: data.order_id,
|
|
130
|
+
transactionId: data.transaction_id,
|
|
131
|
+
amount: parseFloat(data.gross_amount),
|
|
132
|
+
currency: data.currency || 'IDR',
|
|
133
|
+
paymentType: data.payment_type,
|
|
134
|
+
transactionStatus: data.transaction_status,
|
|
135
|
+
fraudStatus: data.fraud_status,
|
|
136
|
+
transactionTime: data.transaction_time
|
|
137
|
+
};
|
|
138
|
+
} catch (error) {
|
|
139
|
+
throw new Error(`Error in Midtrans callback handling: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async verifyNotification(data) {
|
|
144
|
+
try {
|
|
145
|
+
const orderId = data.order_id;
|
|
146
|
+
const statusCode = data.status_code;
|
|
147
|
+
const grossAmount = data.gross_amount;
|
|
148
|
+
const serverKey = this.serverKey;
|
|
149
|
+
|
|
150
|
+
// Signature verification
|
|
151
|
+
const signatureKey = crypto
|
|
152
|
+
.createHash('sha512')
|
|
153
|
+
.update(orderId + statusCode + grossAmount + serverKey)
|
|
154
|
+
.digest('hex');
|
|
155
|
+
|
|
156
|
+
if (data.signature_key !== signatureKey) {
|
|
157
|
+
return {
|
|
158
|
+
status: false,
|
|
159
|
+
error: {
|
|
160
|
+
code: 401,
|
|
161
|
+
message: 'Invalid signature key'
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Fraud status check
|
|
167
|
+
if (data.transaction_status === 'capture') {
|
|
168
|
+
if (data.fraud_status === 'challenge') {
|
|
169
|
+
return {
|
|
170
|
+
status: false,
|
|
171
|
+
error: {
|
|
172
|
+
code: 403,
|
|
173
|
+
message: 'Transaction challenged by FDS'
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
} else if (data.fraud_status === 'deny') {
|
|
177
|
+
return {
|
|
178
|
+
status: false,
|
|
179
|
+
error: {
|
|
180
|
+
code: 403,
|
|
181
|
+
message: 'Transaction denied by FDS'
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
status: true,
|
|
189
|
+
data: data
|
|
190
|
+
};
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return {
|
|
193
|
+
status: false,
|
|
194
|
+
error: {
|
|
195
|
+
code: 500,
|
|
196
|
+
message: error.message
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async cancelTransaction(orderId) {
|
|
203
|
+
try {
|
|
204
|
+
const response = await this.client.post(`${this.coreURL}/${orderId}/cancel`);
|
|
205
|
+
return response.data;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
throw new Error(`Cancel transaction error: ${error.message}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async refundTransaction(orderId, amount, reason) {
|
|
212
|
+
try {
|
|
213
|
+
const refundData = {
|
|
214
|
+
refund_key: `refund-${orderId}-${Date.now()}`,
|
|
215
|
+
amount: amount,
|
|
216
|
+
reason: reason || 'Customer request'
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const response = await this.client.post(`${this.coreURL}/${orderId}/refund`, refundData);
|
|
220
|
+
return response.data;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
throw new Error(`Refund transaction error: ${error.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = MidtransClient;
|