@crediblemark/buayar 0.2.1 → 0.3.1
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/README.md +292 -251
- package/dist/index.d.mts +338 -6
- package/dist/index.d.ts +338 -6
- package/dist/index.js +3039 -249
- package/dist/index.mjs +3009 -249
- package/package.json +43 -2
package/dist/index.js
CHANGED
|
@@ -30,7 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AdyenClient: () => AdyenClient,
|
|
34
|
+
AdyenProvider: () => AdyenProvider,
|
|
33
35
|
BasePaymentProvider: () => BasePaymentProvider,
|
|
36
|
+
BraintreeClient: () => BraintreeClient,
|
|
37
|
+
BraintreeProvider: () => BraintreeProvider,
|
|
34
38
|
Buayar: () => Buayar,
|
|
35
39
|
CANONICAL_TO_DOKU: () => CANONICAL_TO_DOKU,
|
|
36
40
|
CANONICAL_TO_DUITKU: () => CANONICAL_TO_DUITKU,
|
|
@@ -44,6 +48,8 @@ __export(index_exports, {
|
|
|
44
48
|
CANONICAL_TO_STRIPE: () => CANONICAL_TO_STRIPE,
|
|
45
49
|
CANONICAL_TO_XENDIT: () => CANONICAL_TO_XENDIT,
|
|
46
50
|
CORE_API_METHODS: () => CORE_API_METHODS,
|
|
51
|
+
CheckoutComClient: () => CheckoutComClient,
|
|
52
|
+
CheckoutComProvider: () => CheckoutComProvider,
|
|
47
53
|
DUITKU_TO_CANONICAL: () => DUITKU_TO_CANONICAL,
|
|
48
54
|
DokuClient: () => DokuClient,
|
|
49
55
|
DokuProvider: () => DokuProvider,
|
|
@@ -64,14 +70,29 @@ __export(index_exports, {
|
|
|
64
70
|
OyClient: () => OyClient,
|
|
65
71
|
OyProvider: () => OyProvider,
|
|
66
72
|
PaymentManager: () => PaymentManager,
|
|
73
|
+
PaypalClient: () => PaypalClient,
|
|
74
|
+
PaypalProvider: () => PaypalProvider,
|
|
75
|
+
PayuClient: () => PayuClient,
|
|
76
|
+
PayuProvider: () => PayuProvider,
|
|
67
77
|
PrismalinkClient: () => PrismalinkClient,
|
|
68
78
|
PrismalinkProvider: () => PrismalinkProvider,
|
|
79
|
+
RazorpayClient: () => RazorpayClient,
|
|
80
|
+
RazorpayProvider: () => RazorpayProvider,
|
|
81
|
+
SquareClient: () => SquareClient,
|
|
82
|
+
SquareProvider: () => SquareProvider,
|
|
69
83
|
StripeClient: () => StripeClient,
|
|
70
84
|
StripeProvider: () => StripeProvider,
|
|
85
|
+
TwoCheckoutClient: () => TwoCheckoutClient,
|
|
86
|
+
TwoCheckoutProvider: () => TwoCheckoutProvider,
|
|
71
87
|
XenditClient: () => XenditClient,
|
|
72
88
|
XenditProvider: () => XenditProvider,
|
|
73
89
|
buayar: () => buayar,
|
|
90
|
+
buildBraintreeBasicAuth: () => buildBraintreeBasicAuth,
|
|
74
91
|
buildCoreChargePayload: () => buildCoreChargePayload,
|
|
92
|
+
buildPaypalBasicAuth: () => buildPaypalBasicAuth,
|
|
93
|
+
buildPayuBasicAuth: () => buildPayuBasicAuth,
|
|
94
|
+
buildRazorpayBasicAuth: () => buildRazorpayBasicAuth,
|
|
95
|
+
buildTwoCheckoutAuth: () => buildTwoCheckoutAuth,
|
|
75
96
|
formatNicepayTimestamp: () => formatNicepayTimestamp,
|
|
76
97
|
generateDokuHeaders: () => generateDokuHeaders,
|
|
77
98
|
generateFaspaySignature: () => generateFaspaySignature,
|
|
@@ -91,6 +112,7 @@ __export(index_exports, {
|
|
|
91
112
|
paymentManager: () => paymentManager,
|
|
92
113
|
resolveConfigFromEnv: () => resolveConfigFromEnv,
|
|
93
114
|
safeCompare: () => safeCompare,
|
|
115
|
+
serializePaypalParams: () => serializePaypalParams,
|
|
94
116
|
serializeStripeParams: () => serializeStripeParams,
|
|
95
117
|
sha256: () => sha256,
|
|
96
118
|
sha512: () => sha512,
|
|
@@ -105,6 +127,9 @@ __export(index_exports, {
|
|
|
105
127
|
toPrismalinkPaymentMethod: () => toPrismalinkPaymentMethod,
|
|
106
128
|
toStripePaymentMethod: () => toStripePaymentMethod,
|
|
107
129
|
toXenditPaymentMethod: () => toXenditPaymentMethod,
|
|
130
|
+
verifyAdyenWebhook: () => verifyAdyenWebhook,
|
|
131
|
+
verifyBraintreeWebhook: () => verifyBraintreeWebhook,
|
|
132
|
+
verifyCheckoutComWebhook: () => verifyCheckoutComWebhook,
|
|
108
133
|
verifyDokuWebhookSignature: () => verifyDokuWebhookSignature,
|
|
109
134
|
verifyDuitkuCallbackSignature: () => verifyDuitkuCallbackSignature,
|
|
110
135
|
verifyFaspaySignature: () => verifyFaspaySignature,
|
|
@@ -112,8 +137,13 @@ __export(index_exports, {
|
|
|
112
137
|
verifyIpaymuCallback: () => verifyIpaymuCallback,
|
|
113
138
|
verifyNicepayWebhook: () => verifyNicepayWebhook,
|
|
114
139
|
verifyOyWebhook: () => verifyOyWebhook,
|
|
140
|
+
verifyPaypalWebhookSimple: () => verifyPaypalWebhookSimple,
|
|
141
|
+
verifyPayuWebhook: () => verifyPayuWebhook,
|
|
115
142
|
verifyPrismalinkSignature: () => verifyPrismalinkSignature,
|
|
143
|
+
verifyRazorpayWebhook: () => verifyRazorpayWebhook,
|
|
144
|
+
verifySquareWebhook: () => verifySquareWebhook,
|
|
116
145
|
verifyStripeWebhook: () => verifyStripeWebhook,
|
|
146
|
+
verifyTwoCheckoutWebhook: () => verifyTwoCheckoutWebhook,
|
|
117
147
|
verifyXenditWebhookToken: () => verifyXenditWebhookToken
|
|
118
148
|
});
|
|
119
149
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -536,7 +566,19 @@ function hmacSha256(data, secret) {
|
|
|
536
566
|
}
|
|
537
567
|
function safeCompare(a, b) {
|
|
538
568
|
if (typeof a !== "string" || typeof b !== "string") return false;
|
|
539
|
-
|
|
569
|
+
if (!a && !b) return true;
|
|
570
|
+
if (!a || !b) return false;
|
|
571
|
+
const isHexA = /^[0-9a-fA-F]+$/.test(a);
|
|
572
|
+
const isHexB = /^[0-9a-fA-F]+$/.test(b);
|
|
573
|
+
let strA = a;
|
|
574
|
+
let strB = b;
|
|
575
|
+
if (isHexA && isHexB && a.length === b.length) {
|
|
576
|
+
strA = a.toLowerCase();
|
|
577
|
+
strB = b.toLowerCase();
|
|
578
|
+
}
|
|
579
|
+
const hashA = import_crypto.default.createHash("sha256").update(strA).digest();
|
|
580
|
+
const hashB = import_crypto.default.createHash("sha256").update(strB).digest();
|
|
581
|
+
return import_crypto.default.timingSafeEqual(hashA, hashB);
|
|
540
582
|
}
|
|
541
583
|
|
|
542
584
|
// src/providers/duitku/signature.ts
|
|
@@ -2031,7 +2073,7 @@ function getXenditAuthHeader(secretKey) {
|
|
|
2031
2073
|
return `Basic ${token}`;
|
|
2032
2074
|
}
|
|
2033
2075
|
function verifyXenditWebhookToken(headerToken, expectedToken) {
|
|
2034
|
-
if (!headerToken || !expectedToken) return
|
|
2076
|
+
if (!headerToken || !expectedToken) return false;
|
|
2035
2077
|
return safeCompare(headerToken, expectedToken);
|
|
2036
2078
|
}
|
|
2037
2079
|
|
|
@@ -2219,8 +2261,14 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2219
2261
|
const orderId = body.external_id || body.reference_id || body.data?.reference_id || body.id || "";
|
|
2220
2262
|
const amount = body.paid_amount || body.amount || body.data?.amount || 0;
|
|
2221
2263
|
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
2264
|
+
const webhookToken = config.extra?.webhookToken;
|
|
2265
|
+
const headerToken = config.extra?.callbackToken || config.extra?.headers?.["x-callback-token"] || config.extra?.headers?.["X-Callback-Token"];
|
|
2266
|
+
let isValid = true;
|
|
2267
|
+
if (webhookToken || headerToken) {
|
|
2268
|
+
isValid = verifyXenditWebhookToken(headerToken, webhookToken);
|
|
2269
|
+
}
|
|
2222
2270
|
return {
|
|
2223
|
-
isValid
|
|
2271
|
+
isValid,
|
|
2224
2272
|
provider: "xendit",
|
|
2225
2273
|
orderId: String(orderId),
|
|
2226
2274
|
amount: Number(amount) || 0,
|
|
@@ -2498,11 +2546,12 @@ function verifyDokuWebhookSignature(headers, body, clientId, secretKey, requestT
|
|
|
2498
2546
|
const reqId = headers["request-id"] || headers["Request-Id"] || "";
|
|
2499
2547
|
const reqTimestamp = headers["request-timestamp"] || headers["Request-Timestamp"] || "";
|
|
2500
2548
|
const incomingSignature = headers["signature"] || headers["Signature"] || "";
|
|
2501
|
-
if (!incomingSignature || !secretKey) return
|
|
2549
|
+
if (!incomingSignature || !secretKey) return false;
|
|
2550
|
+
const target = headers["request-target"] || headers["Request-Target"] || requestTarget;
|
|
2502
2551
|
let component = `Client-Id:${reqClientId || clientId}
|
|
2503
2552
|
Request-Id:${reqId}
|
|
2504
2553
|
Request-Timestamp:${reqTimestamp}
|
|
2505
|
-
Request-Target:${
|
|
2554
|
+
Request-Target:${target}`;
|
|
2506
2555
|
if (body) {
|
|
2507
2556
|
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
2508
2557
|
const digest = import_crypto6.default.createHash("sha256").update(rawBody).digest("base64");
|
|
@@ -2726,8 +2775,16 @@ var DokuProvider = class extends BasePaymentProvider {
|
|
|
2726
2775
|
const orderId = body.order?.invoice_number || body.invoice_number || body.order_id || "";
|
|
2727
2776
|
const amount = body.order?.amount || body.amount || 0;
|
|
2728
2777
|
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
2778
|
+
const secretKey = config.secretKey || config.apiKey || "";
|
|
2779
|
+
const headers = config.extra?.headers || {};
|
|
2780
|
+
const signature = headers["signature"] || headers["Signature"] || config.extra?.dokuSignature || config.extra?.signatureHeader;
|
|
2781
|
+
const clientId = config.merchantCode || config.clientKey || "";
|
|
2782
|
+
let isValid = true;
|
|
2783
|
+
if (signature || headers && (headers["request-id"] || headers["Request-Id"])) {
|
|
2784
|
+
isValid = verifyDokuWebhookSignature(headers, body, clientId, secretKey);
|
|
2785
|
+
}
|
|
2729
2786
|
return {
|
|
2730
|
-
isValid
|
|
2787
|
+
isValid,
|
|
2731
2788
|
provider: "doku",
|
|
2732
2789
|
orderId: String(orderId),
|
|
2733
2790
|
amount: Number(amount) || 0,
|
|
@@ -2984,7 +3041,7 @@ function generatePrismalinkSignature(merchantId, orderId, amount, secretKey) {
|
|
|
2984
3041
|
return sha256(raw);
|
|
2985
3042
|
}
|
|
2986
3043
|
function verifyPrismalinkSignature(merchantId, orderId, amount, secretKey, incomingSignature) {
|
|
2987
|
-
if (!incomingSignature || !secretKey) return
|
|
3044
|
+
if (!incomingSignature || !secretKey) return false;
|
|
2988
3045
|
const computed = generatePrismalinkSignature(merchantId, orderId, amount, secretKey);
|
|
2989
3046
|
return safeCompare(incomingSignature, computed);
|
|
2990
3047
|
}
|
|
@@ -3375,7 +3432,7 @@ function generateFaspaySignature(userId, password, billNo) {
|
|
|
3375
3432
|
return import_crypto9.default.createHash("sha1").update(md5Hash).digest("hex");
|
|
3376
3433
|
}
|
|
3377
3434
|
function verifyFaspaySignature(userId, password, billNo, paymentStatusCode, incomingSignature) {
|
|
3378
|
-
if (!incomingSignature || !password) return
|
|
3435
|
+
if (!incomingSignature || !password) return false;
|
|
3379
3436
|
const md5Hash = import_crypto9.default.createHash("md5").update(`${userId}${password}${billNo}${paymentStatusCode}`).digest("hex");
|
|
3380
3437
|
const computed = import_crypto9.default.createHash("sha1").update(md5Hash).digest("hex");
|
|
3381
3438
|
const simpleComputed = generateFaspaySignature(userId, password, billNo);
|
|
@@ -3796,9 +3853,9 @@ function generateFinpaySignature(merchantId, orderId, amount, merchantKey) {
|
|
|
3796
3853
|
return import_crypto11.default.createHmac("sha512", merchantKey).update(data).digest("hex");
|
|
3797
3854
|
}
|
|
3798
3855
|
function verifyFinpaySignature(merchantId, orderId, amount, merchantKey, incomingSignature) {
|
|
3799
|
-
if (!incomingSignature || !merchantKey) return
|
|
3856
|
+
if (!incomingSignature || !merchantKey) return false;
|
|
3800
3857
|
const computed = generateFinpaySignature(merchantId, orderId, amount, merchantKey);
|
|
3801
|
-
return safeCompare(incomingSignature
|
|
3858
|
+
return safeCompare(incomingSignature, computed);
|
|
3802
3859
|
}
|
|
3803
3860
|
|
|
3804
3861
|
// src/providers/finpay/provider.ts
|
|
@@ -4183,9 +4240,9 @@ function generateNicepayToken(timeStamp, iMid, referenceNo, amt, merchantKey) {
|
|
|
4183
4240
|
return sha256(raw);
|
|
4184
4241
|
}
|
|
4185
4242
|
function verifyNicepayWebhook(timeStamp, iMid, referenceNo, amt, merchantKey, incomingToken) {
|
|
4186
|
-
if (!incomingToken || !merchantKey) return
|
|
4243
|
+
if (!incomingToken || !merchantKey) return false;
|
|
4187
4244
|
const computed = generateNicepayToken(timeStamp, iMid, referenceNo, amt, merchantKey);
|
|
4188
|
-
return safeCompare(incomingToken
|
|
4245
|
+
return safeCompare(incomingToken, computed);
|
|
4189
4246
|
}
|
|
4190
4247
|
|
|
4191
4248
|
// src/providers/nicepay/provider.ts
|
|
@@ -4612,9 +4669,9 @@ function generateOyHeaders(username, apiKey) {
|
|
|
4612
4669
|
};
|
|
4613
4670
|
}
|
|
4614
4671
|
function verifyOyWebhook(headers, expectedUsername) {
|
|
4615
|
-
if (!expectedUsername) return
|
|
4672
|
+
if (!expectedUsername) return false;
|
|
4616
4673
|
const username = headers["x-oy-username"] || headers["X-Oy-Username"] || "";
|
|
4617
|
-
if (!username) return
|
|
4674
|
+
if (!username) return false;
|
|
4618
4675
|
return safeCompare(username.toLowerCase(), expectedUsername.toLowerCase());
|
|
4619
4676
|
}
|
|
4620
4677
|
|
|
@@ -4776,7 +4833,7 @@ var OyProvider = class extends BasePaymentProvider {
|
|
|
4776
4833
|
}
|
|
4777
4834
|
}
|
|
4778
4835
|
async verifyCallback(body, config) {
|
|
4779
|
-
const username = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
4836
|
+
const username = config.clientKey || config.merchantCode || config.merchantId || config.extra?.username || "";
|
|
4780
4837
|
const orderId = body.partner_tx_id || body.partner_trx_id || body.trx_id || "";
|
|
4781
4838
|
const amount = body.amount || body.settlement_amount || 0;
|
|
4782
4839
|
const rawStatus = (body.status || body.tx_status || "").toUpperCase();
|
|
@@ -4785,8 +4842,14 @@ var OyProvider = class extends BasePaymentProvider {
|
|
|
4785
4842
|
const isExpired = rawStatus === "EXPIRED";
|
|
4786
4843
|
const isFailed = rawStatus === "FAILED" || !isPaid && !isPending && !isExpired;
|
|
4787
4844
|
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
4845
|
+
const headers = config.extra?.headers || {};
|
|
4846
|
+
const oyUsernameHeader = headers["x-oy-username"] || headers["X-Oy-Username"] || config.extra?.oyUsername;
|
|
4847
|
+
let isValid = true;
|
|
4848
|
+
if (oyUsernameHeader || username && headers && Object.keys(headers).length > 0) {
|
|
4849
|
+
isValid = verifyOyWebhook(headers, username);
|
|
4850
|
+
}
|
|
4788
4851
|
return {
|
|
4789
|
-
isValid
|
|
4852
|
+
isValid,
|
|
4790
4853
|
provider: "oy",
|
|
4791
4854
|
orderId: String(orderId),
|
|
4792
4855
|
amount: Number(amount) || 0,
|
|
@@ -5046,13 +5109,16 @@ function serializeStripeParams(obj, prefix = "") {
|
|
|
5046
5109
|
}
|
|
5047
5110
|
function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleranceSeconds = 300) {
|
|
5048
5111
|
if (!signatureHeader || !webhookSecret) {
|
|
5049
|
-
return
|
|
5112
|
+
return false;
|
|
5050
5113
|
}
|
|
5051
5114
|
const items = signatureHeader.split(",");
|
|
5052
5115
|
let timestamp = "";
|
|
5053
5116
|
const signatures = [];
|
|
5054
5117
|
for (const item of items) {
|
|
5055
|
-
const
|
|
5118
|
+
const eqIdx = item.indexOf("=");
|
|
5119
|
+
if (eqIdx === -1) continue;
|
|
5120
|
+
const key = item.slice(0, eqIdx).trim();
|
|
5121
|
+
const value = item.slice(eqIdx + 1).trim();
|
|
5056
5122
|
if (key === "t") {
|
|
5057
5123
|
timestamp = value;
|
|
5058
5124
|
} else if (key === "v1") {
|
|
@@ -5062,10 +5128,18 @@ function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleran
|
|
|
5062
5128
|
if (!timestamp || signatures.length === 0) {
|
|
5063
5129
|
return false;
|
|
5064
5130
|
}
|
|
5131
|
+
const tsNum = Number(timestamp);
|
|
5132
|
+
if (Number.isNaN(tsNum) || tsNum <= 0) {
|
|
5133
|
+
return false;
|
|
5134
|
+
}
|
|
5135
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
5136
|
+
if (Math.abs(nowSec - tsNum) > toleranceSeconds) {
|
|
5137
|
+
return false;
|
|
5138
|
+
}
|
|
5065
5139
|
const payloadString = typeof rawPayload === "string" ? rawPayload : JSON.stringify(rawPayload);
|
|
5066
5140
|
const signedPayload = `${timestamp}.${payloadString}`;
|
|
5067
5141
|
const expectedSignature = hmacSha256(signedPayload, webhookSecret);
|
|
5068
|
-
return signatures.some((sig) => safeCompare(sig
|
|
5142
|
+
return signatures.some((sig) => safeCompare(sig, expectedSignature));
|
|
5069
5143
|
}
|
|
5070
5144
|
|
|
5071
5145
|
// src/providers/stripe/provider.ts
|
|
@@ -5387,202 +5461,2189 @@ var StripeProvider = class extends BasePaymentProvider {
|
|
|
5387
5461
|
}
|
|
5388
5462
|
};
|
|
5389
5463
|
|
|
5390
|
-
// src/
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
const
|
|
5413
|
-
const
|
|
5414
|
-
const
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
"
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
headers
|
|
5425
|
-
};
|
|
5426
|
-
if (method === "POST" && body) {
|
|
5427
|
-
fetchOptions.body = JSON.stringify(body);
|
|
5428
|
-
}
|
|
5429
|
-
const response = await fetch(url, fetchOptions);
|
|
5464
|
+
// src/providers/paypal/signature.ts
|
|
5465
|
+
function buildPaypalBasicAuth(clientId, clientSecret) {
|
|
5466
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
5467
|
+
}
|
|
5468
|
+
function verifyPaypalWebhookSimple(transmissionId, timestamp, webhookId, body, transmissionSig, certUrl) {
|
|
5469
|
+
return !!(transmissionId && timestamp && webhookId && transmissionSig && certUrl);
|
|
5470
|
+
}
|
|
5471
|
+
function serializePaypalParams(obj) {
|
|
5472
|
+
return Object.entries(obj).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5475
|
+
// src/providers/paypal/provider.ts
|
|
5476
|
+
var PaypalProvider = class extends BasePaymentProvider {
|
|
5477
|
+
name = "paypal";
|
|
5478
|
+
getSandbox(config) {
|
|
5479
|
+
return config.sandbox !== false;
|
|
5480
|
+
}
|
|
5481
|
+
getBaseUrl(config) {
|
|
5482
|
+
return this.getSandbox(config) ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
5483
|
+
}
|
|
5484
|
+
/** OAuth2 Client Credentials — dapatkan access token */
|
|
5485
|
+
async getAccessToken(config) {
|
|
5486
|
+
const clientId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
5487
|
+
const clientSecret = config.apiKey || config.secretKey || "";
|
|
5488
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
5489
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5490
|
+
const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
|
|
5491
|
+
method: "POST",
|
|
5492
|
+
headers: {
|
|
5493
|
+
"Authorization": `Basic ${auth}`,
|
|
5494
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
5495
|
+
},
|
|
5496
|
+
body: "grant_type=client_credentials"
|
|
5497
|
+
});
|
|
5430
5498
|
const text = await response.text();
|
|
5431
5499
|
let data = null;
|
|
5432
5500
|
try {
|
|
5433
5501
|
data = JSON.parse(text);
|
|
5434
5502
|
} catch (e) {
|
|
5435
5503
|
}
|
|
5436
|
-
if (!response.ok) {
|
|
5437
|
-
throw new Error(data?.
|
|
5504
|
+
if (!response.ok || !data?.access_token) {
|
|
5505
|
+
throw new Error(data?.error_description || `Failed to get PayPal access token: ${response.status}`);
|
|
5438
5506
|
}
|
|
5439
|
-
return data
|
|
5440
|
-
}
|
|
5441
|
-
// ─── TRANSACTIONS & PAYMENT METHODS ──────────────────────────────────────────
|
|
5442
|
-
/**
|
|
5443
|
-
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
5444
|
-
*/
|
|
5445
|
-
async checkTransaction(merchantOrderId) {
|
|
5446
|
-
const { bodySignature } = getDuitkuStatusSignatures(
|
|
5447
|
-
this.merchantCode,
|
|
5448
|
-
merchantOrderId,
|
|
5449
|
-
this.apiKey
|
|
5450
|
-
);
|
|
5451
|
-
return this.request(
|
|
5452
|
-
"POST",
|
|
5453
|
-
"/api/merchant/transactionStatus",
|
|
5454
|
-
{
|
|
5455
|
-
merchantCode: this.merchantCode,
|
|
5456
|
-
merchantOrderId,
|
|
5457
|
-
signature: bodySignature
|
|
5458
|
-
},
|
|
5459
|
-
{ baseUrl: "api" }
|
|
5460
|
-
);
|
|
5461
|
-
}
|
|
5462
|
-
/**
|
|
5463
|
-
* Ambil daftar channel pembayaran aktif dan kalkulasi fee dinamis
|
|
5464
|
-
*/
|
|
5465
|
-
async getPaymentMethods(amount = 1e4) {
|
|
5466
|
-
const integerAmount = Math.round(amount);
|
|
5467
|
-
const datetime = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
5468
|
-
const signature = getDuitkuPaymentMethodsSignature(this.merchantCode, integerAmount, datetime, this.apiKey);
|
|
5469
|
-
return this.request("POST", "/api/merchant/paymentmethod/getpaymentmethod", {
|
|
5470
|
-
merchantcode: this.merchantCode,
|
|
5471
|
-
amount: integerAmount,
|
|
5472
|
-
datetime,
|
|
5473
|
-
signature
|
|
5474
|
-
});
|
|
5507
|
+
return data.access_token;
|
|
5475
5508
|
}
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
async checkBalance() {
|
|
5481
|
-
const timestamp = Date.now().toString();
|
|
5482
|
-
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
5509
|
+
async createInvoice(params, config) {
|
|
5510
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
5511
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5512
|
+
let accessToken;
|
|
5483
5513
|
try {
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5514
|
+
accessToken = await this.getAccessToken(config);
|
|
5515
|
+
} catch (e) {
|
|
5516
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5517
|
+
}
|
|
5518
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5519
|
+
const amountFormatted = (amount / 100).toFixed(2);
|
|
5520
|
+
const isDirect = !!params.paymentMethod;
|
|
5521
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5522
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5523
|
+
const body = {
|
|
5524
|
+
intent: isDirect ? "CAPTURE" : "CAPTURE",
|
|
5525
|
+
purchase_units: [
|
|
5487
5526
|
{
|
|
5488
|
-
|
|
5489
|
-
|
|
5527
|
+
reference_id: orderId,
|
|
5528
|
+
description: productDetails,
|
|
5529
|
+
amount: {
|
|
5530
|
+
currency_code: currency,
|
|
5531
|
+
value: amountFormatted
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
],
|
|
5535
|
+
application_context: {
|
|
5536
|
+
return_url: successUrl,
|
|
5537
|
+
cancel_url: cancelUrl,
|
|
5538
|
+
brand_name: productDetails,
|
|
5539
|
+
user_action: "PAY_NOW"
|
|
5540
|
+
}
|
|
5541
|
+
};
|
|
5542
|
+
if (isDirect) {
|
|
5543
|
+
body.application_context.shipping_preference = "NO_SHIPPING";
|
|
5544
|
+
}
|
|
5545
|
+
if (callbackUrl || config.callbackUrl) {
|
|
5546
|
+
}
|
|
5547
|
+
try {
|
|
5548
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders`, {
|
|
5549
|
+
method: "POST",
|
|
5550
|
+
headers: {
|
|
5551
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5552
|
+
"Content-Type": "application/json",
|
|
5553
|
+
"PayPal-Request-Id": orderId,
|
|
5554
|
+
"Prefer": "return=representation"
|
|
5490
5555
|
},
|
|
5491
|
-
|
|
5492
|
-
);
|
|
5556
|
+
body: JSON.stringify(body)
|
|
5557
|
+
});
|
|
5558
|
+
const text = await response.text();
|
|
5559
|
+
let data = null;
|
|
5560
|
+
try {
|
|
5561
|
+
data = JSON.parse(text);
|
|
5562
|
+
} catch (e) {
|
|
5563
|
+
}
|
|
5564
|
+
if (!response.ok || !data || data.name) {
|
|
5565
|
+
return {
|
|
5566
|
+
success: false,
|
|
5567
|
+
provider: "paypal",
|
|
5568
|
+
orderId,
|
|
5569
|
+
amount,
|
|
5570
|
+
rawResponse: data,
|
|
5571
|
+
error: data?.message || `HTTP error! Status: ${response.status}`
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
const approveLink = data.links?.find((l) => l.rel === "approve" || l.rel === "payer-action");
|
|
5575
|
+
const paymentUrl = approveLink?.href || "";
|
|
5493
5576
|
return {
|
|
5494
|
-
success:
|
|
5495
|
-
|
|
5577
|
+
success: true,
|
|
5578
|
+
provider: "paypal",
|
|
5579
|
+
orderId,
|
|
5580
|
+
amount,
|
|
5581
|
+
reference: data.id,
|
|
5582
|
+
paymentUrl,
|
|
5496
5583
|
rawResponse: data
|
|
5497
5584
|
};
|
|
5498
5585
|
} catch (e) {
|
|
5499
|
-
return {
|
|
5500
|
-
success: false,
|
|
5501
|
-
rawResponse: null,
|
|
5502
|
-
error: e.message || "Failed to check Duitku merchant balance"
|
|
5503
|
-
};
|
|
5586
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5504
5587
|
}
|
|
5505
5588
|
}
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
const
|
|
5511
|
-
const
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5589
|
+
async verifyCallback(body, config) {
|
|
5590
|
+
const eventType = body?.event_type || body?.event_name || "";
|
|
5591
|
+
const resource = body?.resource || {};
|
|
5592
|
+
const orderId = resource.reference_id || resource.purchase_units?.[0]?.reference_id || resource.supplementary_data?.related_ids?.order_id || resource.id || "";
|
|
5593
|
+
const amount = Number(resource.amount?.value || resource.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5594
|
+
const statusRaw = (resource.status || "").toUpperCase();
|
|
5595
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "PAYMENT.CAPTURE.COMPLETED";
|
|
5596
|
+
const isPending = statusRaw === "PENDING" || eventType === "PAYMENT.CAPTURE.PENDING";
|
|
5597
|
+
const isExpired = statusRaw === "EXPIRED" || eventType === "CHECKOUT.ORDER.EXPIRED";
|
|
5598
|
+
const isFailed = !isPaid && !isPending && !isExpired && (statusRaw === "DENIED" || statusRaw === "FAILED" || eventType.includes("FAILED") || eventType.includes("DENIED"));
|
|
5599
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5600
|
+
return {
|
|
5601
|
+
isValid: true,
|
|
5602
|
+
// Full cert-chain validation deferred to PayPal's verify API
|
|
5603
|
+
provider: "paypal",
|
|
5604
|
+
orderId: String(orderId),
|
|
5605
|
+
amount,
|
|
5606
|
+
status,
|
|
5607
|
+
isPaid,
|
|
5608
|
+
isPending,
|
|
5609
|
+
isFailed,
|
|
5610
|
+
isExpired,
|
|
5611
|
+
statusCode: eventType,
|
|
5612
|
+
rawPayload: body
|
|
5613
|
+
};
|
|
5521
5614
|
}
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
*/
|
|
5525
|
-
async inquiryBankAccount(bankCode, bankAccount) {
|
|
5526
|
-
const timestamp = Date.now().toString();
|
|
5527
|
-
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
5528
|
-
return this.request(
|
|
5529
|
-
"POST",
|
|
5530
|
-
"/api/disbursement/inquiry",
|
|
5615
|
+
async getPaymentMethods(params, config) {
|
|
5616
|
+
const methods = [
|
|
5531
5617
|
{
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5618
|
+
paymentMethod: "credit_card",
|
|
5619
|
+
code: "card",
|
|
5620
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)",
|
|
5621
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5622
|
+
totalFee: "3.49% + fixed fee",
|
|
5623
|
+
category: "Kartu Kredit"
|
|
5536
5624
|
},
|
|
5537
|
-
{ baseUrl: "api" }
|
|
5538
|
-
);
|
|
5539
|
-
}
|
|
5540
|
-
/**
|
|
5541
|
-
* Eksekusi transfer dana / payout (Disbursement Transfer)
|
|
5542
|
-
*/
|
|
5543
|
-
async disburse(params) {
|
|
5544
|
-
const integerAmount = Math.round(params.amount);
|
|
5545
|
-
const signature = sha256(
|
|
5546
|
-
this.merchantCode + params.merchantOrderId + params.bankCode + params.bankAccount + integerAmount.toString() + this.apiKey
|
|
5547
|
-
);
|
|
5548
|
-
const payload = {
|
|
5549
|
-
merchantCode: this.merchantCode,
|
|
5550
|
-
merchantOrderId: params.merchantOrderId,
|
|
5551
|
-
bankCode: params.bankCode,
|
|
5552
|
-
bankAccount: params.bankAccount,
|
|
5553
|
-
amount: integerAmount,
|
|
5554
|
-
purpose: params.purpose,
|
|
5555
|
-
senderName: params.senderName || "",
|
|
5556
|
-
senderPhone: params.senderPhone || "",
|
|
5557
|
-
callbackUrl: params.callbackUrl || "",
|
|
5558
|
-
signature
|
|
5559
|
-
};
|
|
5560
|
-
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
5561
|
-
}
|
|
5562
|
-
/**
|
|
5563
|
-
* Cek status disbursement berdasarkan merchant order ID
|
|
5564
|
-
*/
|
|
5565
|
-
async checkDisbursementStatus(merchantOrderId) {
|
|
5566
|
-
const signature = sha256(this.merchantCode + merchantOrderId + this.apiKey);
|
|
5567
|
-
return this.request(
|
|
5568
|
-
"POST",
|
|
5569
|
-
"/api/disbursement/checkStatus",
|
|
5570
5625
|
{
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5626
|
+
paymentMethod: "paypal",
|
|
5627
|
+
code: "paypal",
|
|
5628
|
+
paymentName: "PayPal Balance / PayPal Checkout",
|
|
5629
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5630
|
+
totalFee: "3.49% + fixed fee",
|
|
5631
|
+
category: "E-Wallet"
|
|
5574
5632
|
},
|
|
5575
|
-
{
|
|
5576
|
-
|
|
5633
|
+
{
|
|
5634
|
+
paymentMethod: "paylater",
|
|
5635
|
+
code: "pay_later",
|
|
5636
|
+
paymentName: "PayPal Pay Later / Buy Now Pay Later",
|
|
5637
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5638
|
+
totalFee: "3.49% + fixed fee",
|
|
5639
|
+
category: "Paylater / Cicilan"
|
|
5640
|
+
}
|
|
5641
|
+
];
|
|
5642
|
+
const categories = {};
|
|
5643
|
+
for (const item of methods) {
|
|
5644
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5645
|
+
categories[item.category].push(item);
|
|
5646
|
+
}
|
|
5647
|
+
return { success: true, provider: "paypal", methods, categories, rawResponse: methods };
|
|
5577
5648
|
}
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5649
|
+
async checkTransaction(params, config) {
|
|
5650
|
+
const { merchantOrderId } = params;
|
|
5651
|
+
let accessToken;
|
|
5652
|
+
try {
|
|
5653
|
+
accessToken = await this.getAccessToken(config);
|
|
5654
|
+
} catch (e) {
|
|
5655
|
+
return {
|
|
5656
|
+
success: false,
|
|
5657
|
+
provider: "paypal",
|
|
5658
|
+
orderId: merchantOrderId,
|
|
5659
|
+
reference: "",
|
|
5660
|
+
amount: 0,
|
|
5661
|
+
statusCode: "AUTH_ERROR",
|
|
5662
|
+
status: "failed",
|
|
5663
|
+
isPaid: false,
|
|
5664
|
+
isPending: false,
|
|
5665
|
+
isFailed: true,
|
|
5666
|
+
isExpired: false,
|
|
5667
|
+
statusMessage: e.message,
|
|
5668
|
+
error: e.message,
|
|
5669
|
+
rawResponse: null
|
|
5670
|
+
};
|
|
5671
|
+
}
|
|
5672
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5673
|
+
try {
|
|
5674
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
5675
|
+
method: "GET",
|
|
5676
|
+
headers: {
|
|
5677
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5678
|
+
"Content-Type": "application/json"
|
|
5679
|
+
}
|
|
5680
|
+
});
|
|
5681
|
+
const text = await response.text();
|
|
5682
|
+
let data = null;
|
|
5683
|
+
try {
|
|
5684
|
+
data = JSON.parse(text);
|
|
5685
|
+
} catch (e) {
|
|
5686
|
+
}
|
|
5687
|
+
if (!response.ok || !data || data.name) {
|
|
5688
|
+
return {
|
|
5689
|
+
success: false,
|
|
5690
|
+
provider: "paypal",
|
|
5691
|
+
orderId: merchantOrderId,
|
|
5692
|
+
reference: "",
|
|
5693
|
+
amount: 0,
|
|
5694
|
+
statusCode: response.status.toString(),
|
|
5695
|
+
status: "failed",
|
|
5696
|
+
isPaid: false,
|
|
5697
|
+
isPending: false,
|
|
5698
|
+
isFailed: true,
|
|
5699
|
+
isExpired: false,
|
|
5700
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5701
|
+
error: data?.message,
|
|
5702
|
+
rawResponse: data
|
|
5703
|
+
};
|
|
5704
|
+
}
|
|
5705
|
+
const statusRaw = (data.status || "").toUpperCase();
|
|
5706
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
5707
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED" || statusRaw === "CREATED";
|
|
5708
|
+
const isExpired = statusRaw === "VOIDED";
|
|
5709
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5710
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5711
|
+
const amountValue = Number(data.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5712
|
+
return {
|
|
5713
|
+
success: true,
|
|
5714
|
+
provider: "paypal",
|
|
5715
|
+
orderId: data.purchase_units?.[0]?.reference_id || merchantOrderId,
|
|
5716
|
+
reference: data.id || merchantOrderId,
|
|
5717
|
+
amount: amountValue,
|
|
5718
|
+
statusCode: statusRaw,
|
|
5719
|
+
status,
|
|
5720
|
+
isPaid,
|
|
5721
|
+
isPending,
|
|
5722
|
+
isFailed,
|
|
5723
|
+
isExpired,
|
|
5724
|
+
statusMessage: statusRaw,
|
|
5725
|
+
transactionTime: data.create_time ? new Date(data.create_time) : void 0,
|
|
5726
|
+
rawResponse: data
|
|
5727
|
+
};
|
|
5728
|
+
} catch (e) {
|
|
5729
|
+
return {
|
|
5730
|
+
success: false,
|
|
5731
|
+
provider: "paypal",
|
|
5732
|
+
orderId: merchantOrderId,
|
|
5733
|
+
reference: "",
|
|
5734
|
+
amount: 0,
|
|
5735
|
+
statusCode: "ERROR",
|
|
5736
|
+
status: "failed",
|
|
5737
|
+
isPaid: false,
|
|
5738
|
+
isPending: false,
|
|
5739
|
+
isFailed: true,
|
|
5740
|
+
isExpired: false,
|
|
5741
|
+
statusMessage: e.message,
|
|
5742
|
+
error: e.message,
|
|
5743
|
+
rawResponse: null
|
|
5744
|
+
};
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5747
|
+
};
|
|
5748
|
+
|
|
5749
|
+
// src/providers/adyen/signature.ts
|
|
5750
|
+
var import_crypto16 = require("crypto");
|
|
5751
|
+
function verifyAdyenWebhook(notificationItem, hmacKey) {
|
|
5752
|
+
if (!hmacKey || !notificationItem) return false;
|
|
5753
|
+
try {
|
|
5754
|
+
const amount = notificationItem.amount || {};
|
|
5755
|
+
const fields = [
|
|
5756
|
+
notificationItem.pspReference || "",
|
|
5757
|
+
notificationItem.originalReference || "",
|
|
5758
|
+
notificationItem.merchantAccountCode || "",
|
|
5759
|
+
notificationItem.merchantReference || "",
|
|
5760
|
+
String(amount.value || ""),
|
|
5761
|
+
amount.currency || "",
|
|
5762
|
+
notificationItem.eventCode || "",
|
|
5763
|
+
notificationItem.success || ""
|
|
5764
|
+
];
|
|
5765
|
+
const signedData = fields.join(":");
|
|
5766
|
+
const keyBytes = Buffer.from(hmacKey, "hex");
|
|
5767
|
+
const expected = (0, import_crypto16.createHmac)("sha256", keyBytes).update(signedData, "utf8").digest("base64");
|
|
5768
|
+
const provided = notificationItem.additionalData?.hmacSignature || "";
|
|
5769
|
+
return safeCompare(expected, provided);
|
|
5770
|
+
} catch {
|
|
5771
|
+
return false;
|
|
5772
|
+
}
|
|
5773
|
+
}
|
|
5774
|
+
|
|
5775
|
+
// src/providers/adyen/provider.ts
|
|
5776
|
+
var AdyenProvider = class extends BasePaymentProvider {
|
|
5777
|
+
name = "adyen";
|
|
5778
|
+
getBaseUrl(config) {
|
|
5779
|
+
if (!config.sandbox) {
|
|
5780
|
+
const prefix = config.extra?.liveUrlPrefix || config.projectId || "";
|
|
5781
|
+
if (prefix) {
|
|
5782
|
+
return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
return "https://checkout-test.adyen.com";
|
|
5786
|
+
}
|
|
5787
|
+
async createInvoice(params, config) {
|
|
5788
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5789
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5790
|
+
const merchantAccount = config.merchantCode || config.merchantId || config.extra?.merchantAccount || "";
|
|
5791
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5792
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5793
|
+
const isDirect = !!params.paymentMethod;
|
|
5794
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5795
|
+
try {
|
|
5796
|
+
if (isDirect) {
|
|
5797
|
+
const url = `${baseUrl}/v68/payments`;
|
|
5798
|
+
const body = {
|
|
5799
|
+
merchantAccount,
|
|
5800
|
+
reference: orderId,
|
|
5801
|
+
amount: { value: amount, currency },
|
|
5802
|
+
returnUrl: successUrl,
|
|
5803
|
+
shopperEmail: customer?.email,
|
|
5804
|
+
shopperName: customer?.name ? { firstName: customer.name.split(" ")[0], lastName: customer.name.split(" ").slice(1).join(" ") || "-" } : void 0,
|
|
5805
|
+
shopperReference: customer?.email || orderId,
|
|
5806
|
+
additionalData: { allow3DS2: true },
|
|
5807
|
+
metadata: { order_id: orderId },
|
|
5808
|
+
...params.providerParams
|
|
5809
|
+
};
|
|
5810
|
+
const response = await fetch(url, {
|
|
5811
|
+
method: "POST",
|
|
5812
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5813
|
+
body: JSON.stringify(body)
|
|
5814
|
+
});
|
|
5815
|
+
const text = await response.text();
|
|
5816
|
+
let data = null;
|
|
5817
|
+
try {
|
|
5818
|
+
data = JSON.parse(text);
|
|
5819
|
+
} catch (e) {
|
|
5820
|
+
}
|
|
5821
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5822
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5823
|
+
}
|
|
5824
|
+
const isPaid = data.resultCode === "Authorised";
|
|
5825
|
+
const isPending = data.resultCode === "Pending" || data.resultCode === "RedirectShopper" || data.resultCode === "IdentifyShopper" || data.resultCode === "ChallengeShopper";
|
|
5826
|
+
return {
|
|
5827
|
+
success: true,
|
|
5828
|
+
provider: "adyen",
|
|
5829
|
+
orderId,
|
|
5830
|
+
amount,
|
|
5831
|
+
reference: data.pspReference || data.merchantReference,
|
|
5832
|
+
paymentUrl: data.action?.url || data.redirect?.url || void 0,
|
|
5833
|
+
rawResponse: data
|
|
5834
|
+
};
|
|
5835
|
+
} else {
|
|
5836
|
+
const url = `${baseUrl}/v68/sessions`;
|
|
5837
|
+
const body = {
|
|
5838
|
+
merchantAccount,
|
|
5839
|
+
reference: orderId,
|
|
5840
|
+
amount: { value: amount, currency },
|
|
5841
|
+
returnUrl: successUrl,
|
|
5842
|
+
countryCode: config.extra?.countryCode || "US",
|
|
5843
|
+
shopperLocale: config.extra?.shopperLocale || "en-US",
|
|
5844
|
+
shopperEmail: customer?.email,
|
|
5845
|
+
shopperReference: customer?.email || orderId,
|
|
5846
|
+
metadata: { order_id: orderId },
|
|
5847
|
+
...params.providerParams
|
|
5848
|
+
};
|
|
5849
|
+
const response = await fetch(url, {
|
|
5850
|
+
method: "POST",
|
|
5851
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5852
|
+
body: JSON.stringify(body)
|
|
5853
|
+
});
|
|
5854
|
+
const text = await response.text();
|
|
5855
|
+
let data = null;
|
|
5856
|
+
try {
|
|
5857
|
+
data = JSON.parse(text);
|
|
5858
|
+
} catch (e) {
|
|
5859
|
+
}
|
|
5860
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5861
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5862
|
+
}
|
|
5863
|
+
return {
|
|
5864
|
+
success: true,
|
|
5865
|
+
provider: "adyen",
|
|
5866
|
+
orderId,
|
|
5867
|
+
amount,
|
|
5868
|
+
reference: data.id,
|
|
5869
|
+
paymentUrl: data.url,
|
|
5870
|
+
paymentCode: data.sessionData,
|
|
5871
|
+
rawResponse: data
|
|
5872
|
+
};
|
|
5873
|
+
}
|
|
5874
|
+
} catch (e) {
|
|
5875
|
+
return { success: false, provider: "adyen", orderId, amount, error: e.message, rawResponse: null };
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5878
|
+
async verifyCallback(body, config) {
|
|
5879
|
+
const hmacKey = config.extra?.hmacKey || config.secretKey || "";
|
|
5880
|
+
const notificationItems = body?.notificationItems || [body];
|
|
5881
|
+
const item = notificationItems[0]?.NotificationRequestItem || notificationItems[0] || body;
|
|
5882
|
+
const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : false;
|
|
5883
|
+
const eventCode = (item.eventCode || "").toUpperCase();
|
|
5884
|
+
const success = item.success === "true" || item.success === true;
|
|
5885
|
+
const orderId = item.merchantReference || item.pspReference || "";
|
|
5886
|
+
const amount = item.amount?.value ? Number(item.amount.value) : 0;
|
|
5887
|
+
const isPaid = eventCode === "AUTHORISATION" && success;
|
|
5888
|
+
const isPending = eventCode === "PENDING" || eventCode === "OFFER_CLOSED";
|
|
5889
|
+
const isExpired = eventCode === "EXPIRED" || eventCode === "CANCEL";
|
|
5890
|
+
const isFailed = !isPaid && !isPending && !isExpired && (!success || eventCode === "REFUSAL");
|
|
5891
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5892
|
+
return {
|
|
5893
|
+
isValid,
|
|
5894
|
+
provider: "adyen",
|
|
5895
|
+
orderId: String(orderId),
|
|
5896
|
+
amount,
|
|
5897
|
+
status,
|
|
5898
|
+
isPaid,
|
|
5899
|
+
isPending,
|
|
5900
|
+
isFailed,
|
|
5901
|
+
isExpired,
|
|
5902
|
+
statusCode: eventCode,
|
|
5903
|
+
rawPayload: body
|
|
5904
|
+
};
|
|
5905
|
+
}
|
|
5906
|
+
async getPaymentMethods(params, config) {
|
|
5907
|
+
const methods = [
|
|
5908
|
+
{ paymentMethod: "credit_card", code: "scheme", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex, JCB)", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Interchange++", category: "Kartu Kredit" },
|
|
5909
|
+
{ paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Variable", category: "E-Wallet" },
|
|
5910
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Card network fee", category: "E-Wallet" },
|
|
5911
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Card network fee", category: "E-Wallet" },
|
|
5912
|
+
{ paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Variable", category: "Paylater / Cicilan" },
|
|
5913
|
+
{ paymentMethod: "sepa", code: "sepadirectdebit", paymentName: "SEPA Direct Debit", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
5914
|
+
{ paymentMethod: "qris", code: "qris", paymentName: "QRIS (Indonesia)", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "0.7%", category: "QRIS" }
|
|
5915
|
+
];
|
|
5916
|
+
const categories = {};
|
|
5917
|
+
for (const item of methods) {
|
|
5918
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5919
|
+
categories[item.category].push(item);
|
|
5920
|
+
}
|
|
5921
|
+
return { success: true, provider: "adyen", methods, categories, rawResponse: methods };
|
|
5922
|
+
}
|
|
5923
|
+
async checkTransaction(params, config) {
|
|
5924
|
+
const { merchantOrderId } = params;
|
|
5925
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5926
|
+
const merchantAccount = config.merchantCode || config.merchantId || "";
|
|
5927
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5928
|
+
try {
|
|
5929
|
+
const response = await fetch(`${baseUrl}/v68/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
5930
|
+
method: "GET",
|
|
5931
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" }
|
|
5932
|
+
});
|
|
5933
|
+
const text = await response.text();
|
|
5934
|
+
let data = null;
|
|
5935
|
+
try {
|
|
5936
|
+
data = JSON.parse(text);
|
|
5937
|
+
} catch (e) {
|
|
5938
|
+
}
|
|
5939
|
+
if (!response.ok || !data) {
|
|
5940
|
+
return {
|
|
5941
|
+
success: false,
|
|
5942
|
+
provider: "adyen",
|
|
5943
|
+
orderId: merchantOrderId,
|
|
5944
|
+
reference: "",
|
|
5945
|
+
amount: 0,
|
|
5946
|
+
statusCode: response.status.toString(),
|
|
5947
|
+
status: "failed",
|
|
5948
|
+
isPaid: false,
|
|
5949
|
+
isPending: false,
|
|
5950
|
+
isFailed: true,
|
|
5951
|
+
isExpired: false,
|
|
5952
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5953
|
+
error: data?.message,
|
|
5954
|
+
rawResponse: data
|
|
5955
|
+
};
|
|
5956
|
+
}
|
|
5957
|
+
const resultCode = (data.resultCode || data.status || "").toUpperCase();
|
|
5958
|
+
const isPaid = resultCode === "AUTHORISED" || resultCode === "SETTLED";
|
|
5959
|
+
const isPending = resultCode === "PENDING" || resultCode === "RECEIVED" || resultCode === "REDIRECTSHOPPER";
|
|
5960
|
+
const isExpired = resultCode === "EXPIRED" || resultCode === "CANCELLED";
|
|
5961
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5962
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5963
|
+
return {
|
|
5964
|
+
success: true,
|
|
5965
|
+
provider: "adyen",
|
|
5966
|
+
orderId: data.merchantReference || merchantOrderId,
|
|
5967
|
+
reference: data.pspReference || merchantOrderId,
|
|
5968
|
+
amount: data.amount?.value ? Number(data.amount.value) : 0,
|
|
5969
|
+
statusCode: resultCode,
|
|
5970
|
+
status,
|
|
5971
|
+
isPaid,
|
|
5972
|
+
isPending,
|
|
5973
|
+
isFailed,
|
|
5974
|
+
isExpired,
|
|
5975
|
+
statusMessage: resultCode,
|
|
5976
|
+
rawResponse: data
|
|
5977
|
+
};
|
|
5978
|
+
} catch (e) {
|
|
5979
|
+
return {
|
|
5980
|
+
success: false,
|
|
5981
|
+
provider: "adyen",
|
|
5982
|
+
orderId: merchantOrderId,
|
|
5983
|
+
reference: "",
|
|
5984
|
+
amount: 0,
|
|
5985
|
+
statusCode: "ERROR",
|
|
5986
|
+
status: "failed",
|
|
5987
|
+
isPaid: false,
|
|
5988
|
+
isPending: false,
|
|
5989
|
+
isFailed: true,
|
|
5990
|
+
isExpired: false,
|
|
5991
|
+
statusMessage: e.message,
|
|
5992
|
+
error: e.message,
|
|
5993
|
+
rawResponse: null
|
|
5994
|
+
};
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
};
|
|
5998
|
+
|
|
5999
|
+
// src/providers/checkoutcom/signature.ts
|
|
6000
|
+
var import_crypto18 = require("crypto");
|
|
6001
|
+
function verifyCheckoutComWebhook(body, signatureHeader, secret) {
|
|
6002
|
+
if (!secret || !signatureHeader || !body) return false;
|
|
6003
|
+
try {
|
|
6004
|
+
const expected = (0, import_crypto18.createHmac)("sha256", secret).update(body, "utf8").digest("hex");
|
|
6005
|
+
const provided = signatureHeader.replace(/^sha256=/, "");
|
|
6006
|
+
return safeCompare(expected, provided);
|
|
6007
|
+
} catch {
|
|
6008
|
+
return false;
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
|
|
6012
|
+
// src/providers/checkoutcom/provider.ts
|
|
6013
|
+
var CheckoutComProvider = class extends BasePaymentProvider {
|
|
6014
|
+
name = "checkoutcom";
|
|
6015
|
+
getBaseUrl(config) {
|
|
6016
|
+
return config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
6017
|
+
}
|
|
6018
|
+
async createInvoice(params, config) {
|
|
6019
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
6020
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
6021
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6022
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6023
|
+
const isDirect = !!params.paymentMethod;
|
|
6024
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6025
|
+
try {
|
|
6026
|
+
if (isDirect) {
|
|
6027
|
+
const url = `${baseUrl}/payments`;
|
|
6028
|
+
const body = {
|
|
6029
|
+
amount,
|
|
6030
|
+
currency,
|
|
6031
|
+
reference: orderId,
|
|
6032
|
+
description: productDetails,
|
|
6033
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
6034
|
+
success_url: successUrl,
|
|
6035
|
+
failure_url: successUrl,
|
|
6036
|
+
metadata: { order_id: orderId },
|
|
6037
|
+
...params.providerParams
|
|
6038
|
+
};
|
|
6039
|
+
const response = await fetch(url, {
|
|
6040
|
+
method: "POST",
|
|
6041
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
6042
|
+
body: JSON.stringify(body)
|
|
6043
|
+
});
|
|
6044
|
+
const text = await response.text();
|
|
6045
|
+
let data = null;
|
|
6046
|
+
try {
|
|
6047
|
+
data = JSON.parse(text);
|
|
6048
|
+
} catch (e) {
|
|
6049
|
+
}
|
|
6050
|
+
if (!response.ok || !data || data.error_codes) {
|
|
6051
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
6052
|
+
}
|
|
6053
|
+
return {
|
|
6054
|
+
success: true,
|
|
6055
|
+
provider: "checkoutcom",
|
|
6056
|
+
orderId,
|
|
6057
|
+
amount: data.amount || amount,
|
|
6058
|
+
reference: data.id,
|
|
6059
|
+
paymentUrl: data._links?.redirect?.href,
|
|
6060
|
+
rawResponse: data
|
|
6061
|
+
};
|
|
6062
|
+
} else {
|
|
6063
|
+
const url = `${baseUrl}/payment-links`;
|
|
6064
|
+
const body = {
|
|
6065
|
+
amount,
|
|
6066
|
+
currency,
|
|
6067
|
+
reference: orderId,
|
|
6068
|
+
description: productDetails,
|
|
6069
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
6070
|
+
return_url: successUrl,
|
|
6071
|
+
metadata: { order_id: orderId },
|
|
6072
|
+
...params.providerParams
|
|
6073
|
+
};
|
|
6074
|
+
const response = await fetch(url, {
|
|
6075
|
+
method: "POST",
|
|
6076
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
6077
|
+
body: JSON.stringify(body)
|
|
6078
|
+
});
|
|
6079
|
+
const text = await response.text();
|
|
6080
|
+
let data = null;
|
|
6081
|
+
try {
|
|
6082
|
+
data = JSON.parse(text);
|
|
6083
|
+
} catch (e) {
|
|
6084
|
+
}
|
|
6085
|
+
if (!response.ok || !data || data.error_codes) {
|
|
6086
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
6087
|
+
}
|
|
6088
|
+
return {
|
|
6089
|
+
success: true,
|
|
6090
|
+
provider: "checkoutcom",
|
|
6091
|
+
orderId,
|
|
6092
|
+
amount,
|
|
6093
|
+
reference: data.id,
|
|
6094
|
+
paymentUrl: data._links?.redirect?.href || data.reference,
|
|
6095
|
+
rawResponse: data
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
} catch (e) {
|
|
6099
|
+
return { success: false, provider: "checkoutcom", orderId, amount, error: e.message, rawResponse: null };
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6102
|
+
async verifyCallback(body, config) {
|
|
6103
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
6104
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6105
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6106
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6107
|
+
const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : false;
|
|
6108
|
+
const eventType = parsedBody?.type || "";
|
|
6109
|
+
const data = parsedBody?.data || parsedBody;
|
|
6110
|
+
const orderId = data?.reference || data?.metadata?.order_id || data?.id || "";
|
|
6111
|
+
const amount = Number(data?.amount || 0);
|
|
6112
|
+
const isPaid = eventType === "payment_approved" || eventType === "payment_captured" || data?.approved === true;
|
|
6113
|
+
const isPending = eventType === "payment_pending" || eventType === "payment_voided";
|
|
6114
|
+
const isExpired = eventType === "payment_expired";
|
|
6115
|
+
const isFailed = eventType === "payment_declined" || eventType === "payment_capture_declined";
|
|
6116
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6117
|
+
return {
|
|
6118
|
+
isValid,
|
|
6119
|
+
provider: "checkoutcom",
|
|
6120
|
+
orderId: String(orderId),
|
|
6121
|
+
amount,
|
|
6122
|
+
status,
|
|
6123
|
+
isPaid,
|
|
6124
|
+
isPending,
|
|
6125
|
+
isFailed,
|
|
6126
|
+
isExpired,
|
|
6127
|
+
statusCode: eventType,
|
|
6128
|
+
rawPayload: parsedBody
|
|
6129
|
+
};
|
|
6130
|
+
}
|
|
6131
|
+
async getPaymentMethods(params, config) {
|
|
6132
|
+
const methods = [
|
|
6133
|
+
{ paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)", paymentImage: "https://checkout.com/favicon.ico", totalFee: "1.5% + $0.25", category: "Kartu Kredit" },
|
|
6134
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6135
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6136
|
+
{ paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
6137
|
+
{ paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" },
|
|
6138
|
+
{ paymentMethod: "sofort", code: "sofort", paymentName: "Sofort / SEPA", paymentImage: "https://checkout.com/favicon.ico", totalFee: "0.8% + \u20AC0.25", category: "Virtual Account" }
|
|
6139
|
+
];
|
|
6140
|
+
const categories = {};
|
|
6141
|
+
for (const item of methods) {
|
|
6142
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6143
|
+
categories[item.category].push(item);
|
|
6144
|
+
}
|
|
6145
|
+
return { success: true, provider: "checkoutcom", methods, categories, rawResponse: methods };
|
|
6146
|
+
}
|
|
6147
|
+
async checkTransaction(params, config) {
|
|
6148
|
+
const { merchantOrderId } = params;
|
|
6149
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
6150
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6151
|
+
try {
|
|
6152
|
+
const response = await fetch(`${baseUrl}/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
6153
|
+
method: "GET",
|
|
6154
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" }
|
|
6155
|
+
});
|
|
6156
|
+
const text = await response.text();
|
|
6157
|
+
let data = null;
|
|
6158
|
+
try {
|
|
6159
|
+
data = JSON.parse(text);
|
|
6160
|
+
} catch (e) {
|
|
6161
|
+
}
|
|
6162
|
+
if (!response.ok || !data) {
|
|
6163
|
+
return {
|
|
6164
|
+
success: false,
|
|
6165
|
+
provider: "checkoutcom",
|
|
6166
|
+
orderId: merchantOrderId,
|
|
6167
|
+
reference: "",
|
|
6168
|
+
amount: 0,
|
|
6169
|
+
statusCode: response.status.toString(),
|
|
6170
|
+
status: "failed",
|
|
6171
|
+
isPaid: false,
|
|
6172
|
+
isPending: false,
|
|
6173
|
+
isFailed: true,
|
|
6174
|
+
isExpired: false,
|
|
6175
|
+
statusMessage: "HTTP Error",
|
|
6176
|
+
rawResponse: data
|
|
6177
|
+
};
|
|
6178
|
+
}
|
|
6179
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
6180
|
+
const isPaid = statusRaw === "authorized" || statusRaw === "captured";
|
|
6181
|
+
const isPending = statusRaw === "pending" || statusRaw === "card_verified";
|
|
6182
|
+
const isExpired = statusRaw === "expired" || statusRaw === "voided";
|
|
6183
|
+
const isFailed = statusRaw === "declined" || statusRaw === "failed";
|
|
6184
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6185
|
+
return {
|
|
6186
|
+
success: true,
|
|
6187
|
+
provider: "checkoutcom",
|
|
6188
|
+
orderId: data.reference || merchantOrderId,
|
|
6189
|
+
reference: data.id || merchantOrderId,
|
|
6190
|
+
amount: Number(data.amount || 0),
|
|
6191
|
+
statusCode: statusRaw,
|
|
6192
|
+
status,
|
|
6193
|
+
isPaid,
|
|
6194
|
+
isPending,
|
|
6195
|
+
isFailed,
|
|
6196
|
+
isExpired,
|
|
6197
|
+
statusMessage: statusRaw,
|
|
6198
|
+
paymentType: data.payment_type || "card",
|
|
6199
|
+
transactionTime: data.requested_on ? new Date(data.requested_on) : void 0,
|
|
6200
|
+
rawResponse: data
|
|
6201
|
+
};
|
|
6202
|
+
} catch (e) {
|
|
6203
|
+
return {
|
|
6204
|
+
success: false,
|
|
6205
|
+
provider: "checkoutcom",
|
|
6206
|
+
orderId: merchantOrderId,
|
|
6207
|
+
reference: "",
|
|
6208
|
+
amount: 0,
|
|
6209
|
+
statusCode: "ERROR",
|
|
6210
|
+
status: "failed",
|
|
6211
|
+
isPaid: false,
|
|
6212
|
+
isPending: false,
|
|
6213
|
+
isFailed: true,
|
|
6214
|
+
isExpired: false,
|
|
6215
|
+
statusMessage: e.message,
|
|
6216
|
+
error: e.message,
|
|
6217
|
+
rawResponse: null
|
|
6218
|
+
};
|
|
6219
|
+
}
|
|
6220
|
+
}
|
|
6221
|
+
};
|
|
6222
|
+
|
|
6223
|
+
// src/providers/razorpay/signature.ts
|
|
6224
|
+
var import_crypto20 = require("crypto");
|
|
6225
|
+
function verifyRazorpayWebhook(rawBody, signature, webhookSecret) {
|
|
6226
|
+
if (!webhookSecret || !signature || !rawBody) return false;
|
|
6227
|
+
try {
|
|
6228
|
+
const expected = (0, import_crypto20.createHmac)("sha256", webhookSecret).update(rawBody).digest("hex");
|
|
6229
|
+
return safeCompare(expected, signature);
|
|
6230
|
+
} catch {
|
|
6231
|
+
return false;
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
function buildRazorpayBasicAuth(keyId, keySecret) {
|
|
6235
|
+
return Buffer.from(`${keyId}:${keySecret}`).toString("base64");
|
|
6236
|
+
}
|
|
6237
|
+
|
|
6238
|
+
// src/providers/razorpay/provider.ts
|
|
6239
|
+
var RazorpayProvider = class extends BasePaymentProvider {
|
|
6240
|
+
name = "razorpay";
|
|
6241
|
+
getBaseUrl() {
|
|
6242
|
+
return "https://api.razorpay.com/v1";
|
|
6243
|
+
}
|
|
6244
|
+
buildHeaders(config) {
|
|
6245
|
+
const keyId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
6246
|
+
const keySecret = config.apiKey || config.secretKey || "";
|
|
6247
|
+
return {
|
|
6248
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
6249
|
+
"Content-Type": "application/json"
|
|
6250
|
+
};
|
|
6251
|
+
}
|
|
6252
|
+
async createInvoice(params, config) {
|
|
6253
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6254
|
+
const currency = (params.currency || "INR").toUpperCase();
|
|
6255
|
+
const baseUrl = this.getBaseUrl();
|
|
6256
|
+
const headers = this.buildHeaders(config);
|
|
6257
|
+
const isDirect = !!params.paymentMethod;
|
|
6258
|
+
try {
|
|
6259
|
+
if (isDirect) {
|
|
6260
|
+
const body = {
|
|
6261
|
+
amount,
|
|
6262
|
+
currency,
|
|
6263
|
+
receipt: orderId,
|
|
6264
|
+
notes: { order_id: orderId, product: productDetails },
|
|
6265
|
+
...params.providerParams
|
|
6266
|
+
};
|
|
6267
|
+
const response = await fetch(`${baseUrl}/orders`, {
|
|
6268
|
+
method: "POST",
|
|
6269
|
+
headers,
|
|
6270
|
+
body: JSON.stringify(body)
|
|
6271
|
+
});
|
|
6272
|
+
const text = await response.text();
|
|
6273
|
+
let data = null;
|
|
6274
|
+
try {
|
|
6275
|
+
data = JSON.parse(text);
|
|
6276
|
+
} catch (e) {
|
|
6277
|
+
}
|
|
6278
|
+
if (!response.ok || !data || data.error) {
|
|
6279
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6280
|
+
}
|
|
6281
|
+
return {
|
|
6282
|
+
success: true,
|
|
6283
|
+
provider: "razorpay",
|
|
6284
|
+
orderId,
|
|
6285
|
+
amount: data.amount || amount,
|
|
6286
|
+
reference: data.id,
|
|
6287
|
+
paymentCode: data.id,
|
|
6288
|
+
rawResponse: data
|
|
6289
|
+
};
|
|
6290
|
+
} else {
|
|
6291
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6292
|
+
const body = {
|
|
6293
|
+
amount,
|
|
6294
|
+
currency,
|
|
6295
|
+
description: productDetails,
|
|
6296
|
+
reference_id: orderId,
|
|
6297
|
+
customer: { name: customer?.name, email: customer?.email, contact: customer?.phone || "" },
|
|
6298
|
+
notify: { sms: false, email: !!customer?.email },
|
|
6299
|
+
reminder_enable: false,
|
|
6300
|
+
callback_url: callbackUrl || config.callbackUrl || successUrl,
|
|
6301
|
+
callback_method: "get",
|
|
6302
|
+
notes: { order_id: orderId },
|
|
6303
|
+
...params.providerParams
|
|
6304
|
+
};
|
|
6305
|
+
const response = await fetch(`${baseUrl}/payment_links`, {
|
|
6306
|
+
method: "POST",
|
|
6307
|
+
headers,
|
|
6308
|
+
body: JSON.stringify(body)
|
|
6309
|
+
});
|
|
6310
|
+
const text = await response.text();
|
|
6311
|
+
let data = null;
|
|
6312
|
+
try {
|
|
6313
|
+
data = JSON.parse(text);
|
|
6314
|
+
} catch (e) {
|
|
6315
|
+
}
|
|
6316
|
+
if (!response.ok || !data || data.error) {
|
|
6317
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6318
|
+
}
|
|
6319
|
+
return {
|
|
6320
|
+
success: true,
|
|
6321
|
+
provider: "razorpay",
|
|
6322
|
+
orderId,
|
|
6323
|
+
amount: data.amount || amount,
|
|
6324
|
+
reference: data.id,
|
|
6325
|
+
paymentUrl: data.short_url,
|
|
6326
|
+
rawResponse: data
|
|
6327
|
+
};
|
|
6328
|
+
}
|
|
6329
|
+
} catch (e) {
|
|
6330
|
+
return { success: false, provider: "razorpay", orderId, amount, error: e.message, rawResponse: null };
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
async verifyCallback(body, config) {
|
|
6334
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
6335
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6336
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6337
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6338
|
+
const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : false;
|
|
6339
|
+
const eventType = parsedBody?.event || "";
|
|
6340
|
+
const payload = parsedBody?.payload;
|
|
6341
|
+
const paymentEntity = payload?.payment?.entity || payload?.payment_link?.entity || parsedBody;
|
|
6342
|
+
const orderId = paymentEntity?.notes?.order_id || paymentEntity?.order_id || paymentEntity?.reference_id || paymentEntity?.id || "";
|
|
6343
|
+
const amount = Number(paymentEntity?.amount || 0);
|
|
6344
|
+
const statusRaw = (paymentEntity?.status || "").toLowerCase();
|
|
6345
|
+
const isPaid = eventType === "payment.captured" || eventType === "payment_link.paid" || statusRaw === "captured";
|
|
6346
|
+
const isPending = eventType === "payment.authorized" || statusRaw === "authorized" || statusRaw === "created";
|
|
6347
|
+
const isExpired = eventType === "payment_link.expired" || statusRaw === "expired";
|
|
6348
|
+
const isFailed = eventType === "payment.failed" || statusRaw === "failed";
|
|
6349
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6350
|
+
return {
|
|
6351
|
+
isValid,
|
|
6352
|
+
provider: "razorpay",
|
|
6353
|
+
orderId: String(orderId),
|
|
6354
|
+
amount,
|
|
6355
|
+
status,
|
|
6356
|
+
isPaid,
|
|
6357
|
+
isPending,
|
|
6358
|
+
isFailed,
|
|
6359
|
+
isExpired,
|
|
6360
|
+
statusCode: eventType || statusRaw,
|
|
6361
|
+
rawPayload: parsedBody
|
|
6362
|
+
};
|
|
6363
|
+
}
|
|
6364
|
+
async getPaymentMethods(params, config) {
|
|
6365
|
+
const methods = [
|
|
6366
|
+
{ paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "2% + GST", category: "Kartu Kredit" },
|
|
6367
|
+
{ paymentMethod: "upi", code: "upi", paymentName: "UPI (GPay, PhonePe, Paytm)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Free", category: "QRIS" },
|
|
6368
|
+
{ paymentMethod: "netbanking", code: "netbanking", paymentName: "Net Banking (50+ banks)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "\u20B910", category: "Virtual Account" },
|
|
6369
|
+
{ paymentMethod: "wallet", code: "wallet", paymentName: "Wallets (Paytm, PhonePe, etc.)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
6370
|
+
{ paymentMethod: "emi", code: "emi", paymentName: "EMI (Card / Cardless)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Bank charge", category: "Paylater / Cicilan" }
|
|
6371
|
+
];
|
|
6372
|
+
const categories = {};
|
|
6373
|
+
for (const item of methods) {
|
|
6374
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6375
|
+
categories[item.category].push(item);
|
|
6376
|
+
}
|
|
6377
|
+
return { success: true, provider: "razorpay", methods, categories, rawResponse: methods };
|
|
6378
|
+
}
|
|
6379
|
+
async checkTransaction(params, config) {
|
|
6380
|
+
const { merchantOrderId } = params;
|
|
6381
|
+
const baseUrl = this.getBaseUrl();
|
|
6382
|
+
const headers = this.buildHeaders(config);
|
|
6383
|
+
try {
|
|
6384
|
+
const endpoint = merchantOrderId.startsWith("plink_") ? `/payment_links/${encodeURIComponent(merchantOrderId)}` : `/payments/${encodeURIComponent(merchantOrderId)}`;
|
|
6385
|
+
const response = await fetch(`${baseUrl}${endpoint}`, { method: "GET", headers });
|
|
6386
|
+
const text = await response.text();
|
|
6387
|
+
let data = null;
|
|
6388
|
+
try {
|
|
6389
|
+
data = JSON.parse(text);
|
|
6390
|
+
} catch (e) {
|
|
6391
|
+
}
|
|
6392
|
+
if (!response.ok || !data || data.error) {
|
|
6393
|
+
return {
|
|
6394
|
+
success: false,
|
|
6395
|
+
provider: "razorpay",
|
|
6396
|
+
orderId: merchantOrderId,
|
|
6397
|
+
reference: "",
|
|
6398
|
+
amount: 0,
|
|
6399
|
+
statusCode: response.status.toString(),
|
|
6400
|
+
status: "failed",
|
|
6401
|
+
isPaid: false,
|
|
6402
|
+
isPending: false,
|
|
6403
|
+
isFailed: true,
|
|
6404
|
+
isExpired: false,
|
|
6405
|
+
statusMessage: data?.error?.description || "HTTP Error",
|
|
6406
|
+
rawResponse: data
|
|
6407
|
+
};
|
|
6408
|
+
}
|
|
6409
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
6410
|
+
const isPaid = statusRaw === "captured" || statusRaw === "paid";
|
|
6411
|
+
const isPending = statusRaw === "authorized" || statusRaw === "created";
|
|
6412
|
+
const isExpired = statusRaw === "expired";
|
|
6413
|
+
const isFailed = statusRaw === "failed";
|
|
6414
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6415
|
+
return {
|
|
6416
|
+
success: true,
|
|
6417
|
+
provider: "razorpay",
|
|
6418
|
+
orderId: data.notes?.order_id || data.reference_id || merchantOrderId,
|
|
6419
|
+
reference: data.id || merchantOrderId,
|
|
6420
|
+
amount: Number(data.amount || 0),
|
|
6421
|
+
statusCode: statusRaw,
|
|
6422
|
+
status,
|
|
6423
|
+
isPaid,
|
|
6424
|
+
isPending,
|
|
6425
|
+
isFailed,
|
|
6426
|
+
isExpired,
|
|
6427
|
+
statusMessage: statusRaw,
|
|
6428
|
+
paymentType: data.method || "card",
|
|
6429
|
+
transactionTime: data.created_at ? new Date(data.created_at * 1e3) : void 0,
|
|
6430
|
+
rawResponse: data
|
|
6431
|
+
};
|
|
6432
|
+
} catch (e) {
|
|
6433
|
+
return {
|
|
6434
|
+
success: false,
|
|
6435
|
+
provider: "razorpay",
|
|
6436
|
+
orderId: merchantOrderId,
|
|
6437
|
+
reference: "",
|
|
6438
|
+
amount: 0,
|
|
6439
|
+
statusCode: "ERROR",
|
|
6440
|
+
status: "failed",
|
|
6441
|
+
isPaid: false,
|
|
6442
|
+
isPending: false,
|
|
6443
|
+
isFailed: true,
|
|
6444
|
+
isExpired: false,
|
|
6445
|
+
statusMessage: e.message,
|
|
6446
|
+
error: e.message,
|
|
6447
|
+
rawResponse: null
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6450
|
+
}
|
|
6451
|
+
};
|
|
6452
|
+
|
|
6453
|
+
// src/providers/square/signature.ts
|
|
6454
|
+
var import_crypto22 = require("crypto");
|
|
6455
|
+
function verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) {
|
|
6456
|
+
if (!signatureKey || !signatureHeader || !rawBody) return false;
|
|
6457
|
+
try {
|
|
6458
|
+
const payload = notificationUrl + rawBody;
|
|
6459
|
+
const expected = (0, import_crypto22.createHmac)("sha256", signatureKey).update(payload).digest("base64");
|
|
6460
|
+
return safeCompare(expected, signatureHeader);
|
|
6461
|
+
} catch {
|
|
6462
|
+
return false;
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
|
|
6466
|
+
// src/providers/square/provider.ts
|
|
6467
|
+
var SquareProvider = class extends BasePaymentProvider {
|
|
6468
|
+
name = "square";
|
|
6469
|
+
getBaseUrl(config) {
|
|
6470
|
+
return config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
6471
|
+
}
|
|
6472
|
+
buildHeaders(config) {
|
|
6473
|
+
return {
|
|
6474
|
+
"Authorization": `Bearer ${config.apiKey || config.secretKey || ""}`,
|
|
6475
|
+
"Content-Type": "application/json",
|
|
6476
|
+
"Square-Version": "2024-01-17"
|
|
6477
|
+
};
|
|
6478
|
+
}
|
|
6479
|
+
async createInvoice(params, config) {
|
|
6480
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
6481
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6482
|
+
const locationId = config.extra?.locationId || config.projectId || "";
|
|
6483
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6484
|
+
const headers = this.buildHeaders(config);
|
|
6485
|
+
const isDirect = !!params.paymentMethod;
|
|
6486
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6487
|
+
try {
|
|
6488
|
+
if (isDirect) {
|
|
6489
|
+
const sourceId = params.providerParams?.sourceId || params.providerParams?.nonce || "cnon:card-nonce-ok";
|
|
6490
|
+
const body = {
|
|
6491
|
+
idempotency_key: orderId,
|
|
6492
|
+
source_id: sourceId,
|
|
6493
|
+
amount_money: { amount, currency },
|
|
6494
|
+
reference_id: orderId,
|
|
6495
|
+
note: productDetails,
|
|
6496
|
+
buyer_email_address: customer?.email,
|
|
6497
|
+
...params.providerParams
|
|
6498
|
+
};
|
|
6499
|
+
const response = await fetch(`${baseUrl}/v2/payments`, {
|
|
6500
|
+
method: "POST",
|
|
6501
|
+
headers,
|
|
6502
|
+
body: JSON.stringify(body)
|
|
6503
|
+
});
|
|
6504
|
+
const text = await response.text();
|
|
6505
|
+
let data = null;
|
|
6506
|
+
try {
|
|
6507
|
+
data = JSON.parse(text);
|
|
6508
|
+
} catch (e) {
|
|
6509
|
+
}
|
|
6510
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6511
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6512
|
+
}
|
|
6513
|
+
const payment = data.payment || data;
|
|
6514
|
+
return {
|
|
6515
|
+
success: true,
|
|
6516
|
+
provider: "square",
|
|
6517
|
+
orderId,
|
|
6518
|
+
amount: payment.amount_money?.amount || amount,
|
|
6519
|
+
reference: payment.id,
|
|
6520
|
+
rawResponse: data
|
|
6521
|
+
};
|
|
6522
|
+
} else {
|
|
6523
|
+
const body = {
|
|
6524
|
+
idempotency_key: orderId,
|
|
6525
|
+
order: {
|
|
6526
|
+
location_id: locationId,
|
|
6527
|
+
reference_id: orderId,
|
|
6528
|
+
line_items: [
|
|
6529
|
+
{
|
|
6530
|
+
name: productDetails,
|
|
6531
|
+
quantity: "1",
|
|
6532
|
+
base_price_money: { amount, currency }
|
|
6533
|
+
}
|
|
6534
|
+
]
|
|
6535
|
+
},
|
|
6536
|
+
checkout_options: {
|
|
6537
|
+
redirect_url: successUrl,
|
|
6538
|
+
ask_for_shipping_address: false
|
|
6539
|
+
},
|
|
6540
|
+
pre_populated_data: {
|
|
6541
|
+
buyer_email: customer?.email
|
|
6542
|
+
},
|
|
6543
|
+
...params.providerParams
|
|
6544
|
+
};
|
|
6545
|
+
const response = await fetch(`${baseUrl}/v2/online-checkout/payment-links`, {
|
|
6546
|
+
method: "POST",
|
|
6547
|
+
headers,
|
|
6548
|
+
body: JSON.stringify(body)
|
|
6549
|
+
});
|
|
6550
|
+
const text = await response.text();
|
|
6551
|
+
let data = null;
|
|
6552
|
+
try {
|
|
6553
|
+
data = JSON.parse(text);
|
|
6554
|
+
} catch (e) {
|
|
6555
|
+
}
|
|
6556
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6557
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6558
|
+
}
|
|
6559
|
+
const link = data.payment_link || data;
|
|
6560
|
+
return {
|
|
6561
|
+
success: true,
|
|
6562
|
+
provider: "square",
|
|
6563
|
+
orderId,
|
|
6564
|
+
amount,
|
|
6565
|
+
reference: link.id,
|
|
6566
|
+
paymentUrl: link.url,
|
|
6567
|
+
rawResponse: data
|
|
6568
|
+
};
|
|
6569
|
+
}
|
|
6570
|
+
} catch (e) {
|
|
6571
|
+
return { success: false, provider: "square", orderId, amount, error: e.message, rawResponse: null };
|
|
6572
|
+
}
|
|
6573
|
+
}
|
|
6574
|
+
async verifyCallback(body, config) {
|
|
6575
|
+
const signatureKey = config.extra?.webhookSignatureKey || config.secretKey || "";
|
|
6576
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6577
|
+
const notificationUrl = config.callbackUrl || config.extra?.notificationUrl || "";
|
|
6578
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6579
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6580
|
+
const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : false;
|
|
6581
|
+
const eventType = parsedBody?.type || "";
|
|
6582
|
+
const data = parsedBody?.data?.object || parsedBody?.data || parsedBody;
|
|
6583
|
+
const payment = data?.payment || data;
|
|
6584
|
+
const orderId = payment?.reference_id || payment?.order_id || payment?.id || "";
|
|
6585
|
+
const amount = Number(payment?.amount_money?.amount || 0);
|
|
6586
|
+
const statusRaw = (payment?.status || "").toUpperCase();
|
|
6587
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "payment.completed";
|
|
6588
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6589
|
+
const isFailed = statusRaw === "FAILED" || statusRaw === "CANCELED";
|
|
6590
|
+
const isExpired = eventType === "payment.expired";
|
|
6591
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6592
|
+
return {
|
|
6593
|
+
isValid,
|
|
6594
|
+
provider: "square",
|
|
6595
|
+
orderId: String(orderId),
|
|
6596
|
+
amount,
|
|
6597
|
+
status,
|
|
6598
|
+
isPaid,
|
|
6599
|
+
isPending,
|
|
6600
|
+
isFailed,
|
|
6601
|
+
isExpired,
|
|
6602
|
+
statusCode: eventType || statusRaw,
|
|
6603
|
+
rawPayload: parsedBody
|
|
6604
|
+
};
|
|
6605
|
+
}
|
|
6606
|
+
async getPaymentMethods(params, config) {
|
|
6607
|
+
const methods = [
|
|
6608
|
+
{ paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex, JCB)", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "Kartu Kredit" },
|
|
6609
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6610
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6611
|
+
{ paymentMethod: "cash_app", code: "cashapp", paymentName: "Cash App Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6612
|
+
{ paymentMethod: "afterpay", code: "afterpay", paymentName: "Afterpay / Clearpay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "6% + $0.30", category: "Paylater / Cicilan" }
|
|
6613
|
+
];
|
|
6614
|
+
const categories = {};
|
|
6615
|
+
for (const item of methods) {
|
|
6616
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6617
|
+
categories[item.category].push(item);
|
|
6618
|
+
}
|
|
6619
|
+
return { success: true, provider: "square", methods, categories, rawResponse: methods };
|
|
6620
|
+
}
|
|
6621
|
+
async checkTransaction(params, config) {
|
|
6622
|
+
const { merchantOrderId } = params;
|
|
6623
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6624
|
+
const headers = this.buildHeaders(config);
|
|
6625
|
+
try {
|
|
6626
|
+
const response = await fetch(`${baseUrl}/v2/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
6627
|
+
method: "GET",
|
|
6628
|
+
headers
|
|
6629
|
+
});
|
|
6630
|
+
const text = await response.text();
|
|
6631
|
+
let data = null;
|
|
6632
|
+
try {
|
|
6633
|
+
data = JSON.parse(text);
|
|
6634
|
+
} catch (e) {
|
|
6635
|
+
}
|
|
6636
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6637
|
+
return {
|
|
6638
|
+
success: false,
|
|
6639
|
+
provider: "square",
|
|
6640
|
+
orderId: merchantOrderId,
|
|
6641
|
+
reference: "",
|
|
6642
|
+
amount: 0,
|
|
6643
|
+
statusCode: response.status.toString(),
|
|
6644
|
+
status: "failed",
|
|
6645
|
+
isPaid: false,
|
|
6646
|
+
isPending: false,
|
|
6647
|
+
isFailed: true,
|
|
6648
|
+
isExpired: false,
|
|
6649
|
+
statusMessage: data?.errors?.[0]?.detail || "HTTP Error",
|
|
6650
|
+
rawResponse: data
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
const payment = data.payment || data;
|
|
6654
|
+
const statusRaw = (payment.status || "").toUpperCase();
|
|
6655
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6656
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6657
|
+
const isExpired = statusRaw === "CANCELED";
|
|
6658
|
+
const isFailed = statusRaw === "FAILED";
|
|
6659
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6660
|
+
return {
|
|
6661
|
+
success: true,
|
|
6662
|
+
provider: "square",
|
|
6663
|
+
orderId: payment.reference_id || merchantOrderId,
|
|
6664
|
+
reference: payment.id || merchantOrderId,
|
|
6665
|
+
amount: Number(payment.amount_money?.amount || 0),
|
|
6666
|
+
statusCode: statusRaw,
|
|
6667
|
+
status,
|
|
6668
|
+
isPaid,
|
|
6669
|
+
isPending,
|
|
6670
|
+
isFailed,
|
|
6671
|
+
isExpired,
|
|
6672
|
+
statusMessage: statusRaw,
|
|
6673
|
+
paymentType: payment.source_type || "card",
|
|
6674
|
+
transactionTime: payment.created_at ? new Date(payment.created_at) : void 0,
|
|
6675
|
+
rawResponse: data
|
|
6676
|
+
};
|
|
6677
|
+
} catch (e) {
|
|
6678
|
+
return {
|
|
6679
|
+
success: false,
|
|
6680
|
+
provider: "square",
|
|
6681
|
+
orderId: merchantOrderId,
|
|
6682
|
+
reference: "",
|
|
6683
|
+
amount: 0,
|
|
6684
|
+
statusCode: "ERROR",
|
|
6685
|
+
status: "failed",
|
|
6686
|
+
isPaid: false,
|
|
6687
|
+
isPending: false,
|
|
6688
|
+
isFailed: true,
|
|
6689
|
+
isExpired: false,
|
|
6690
|
+
statusMessage: e.message,
|
|
6691
|
+
error: e.message,
|
|
6692
|
+
rawResponse: null
|
|
6693
|
+
};
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
};
|
|
6697
|
+
|
|
6698
|
+
// src/providers/payu/signature.ts
|
|
6699
|
+
var import_crypto24 = require("crypto");
|
|
6700
|
+
function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
|
|
6701
|
+
if (!md5Key || !signatureHeader || !rawBody) return false;
|
|
6702
|
+
try {
|
|
6703
|
+
const parts = {};
|
|
6704
|
+
for (const part of signatureHeader.split(";")) {
|
|
6705
|
+
const [k, v] = part.split("=");
|
|
6706
|
+
if (k && v) parts[k.trim()] = v.trim();
|
|
6707
|
+
}
|
|
6708
|
+
const providedSig = parts["signature"];
|
|
6709
|
+
const algorithm = (parts["algorithm"] || "MD5").toUpperCase();
|
|
6710
|
+
if (!providedSig) return false;
|
|
6711
|
+
if (algorithm === "MD5") {
|
|
6712
|
+
const expected = (0, import_crypto24.createHash)("md5").update(rawBody + md5Key).digest("hex");
|
|
6713
|
+
return safeCompare(expected, providedSig);
|
|
6714
|
+
} else if (algorithm === "SHA-256") {
|
|
6715
|
+
const expected = (0, import_crypto24.createHash)("sha256").update(rawBody + md5Key).digest("hex");
|
|
6716
|
+
return safeCompare(expected, providedSig);
|
|
6717
|
+
}
|
|
6718
|
+
return false;
|
|
6719
|
+
} catch {
|
|
6720
|
+
return false;
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
function buildPayuBasicAuth(clientId, clientSecret) {
|
|
6724
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
6725
|
+
}
|
|
6726
|
+
|
|
6727
|
+
// src/providers/payu/provider.ts
|
|
6728
|
+
var PayuProvider = class extends BasePaymentProvider {
|
|
6729
|
+
name = "payu";
|
|
6730
|
+
getBaseUrl(config) {
|
|
6731
|
+
return config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
6732
|
+
}
|
|
6733
|
+
/** OAuth2 Bearer Token untuk PayU */
|
|
6734
|
+
async getAccessToken(config) {
|
|
6735
|
+
const clientId = config.extra?.oauthClientId || config.clientKey || "";
|
|
6736
|
+
const clientSecret = config.extra?.oauthClientSecret || config.apiKey || config.secretKey || "";
|
|
6737
|
+
if (!clientId || !clientSecret) {
|
|
6738
|
+
return "";
|
|
6739
|
+
}
|
|
6740
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6741
|
+
const response = await fetch(`${baseUrl}/pl/standard/user/oauth/authorize`, {
|
|
6742
|
+
method: "POST",
|
|
6743
|
+
headers: {
|
|
6744
|
+
"Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`,
|
|
6745
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
6746
|
+
},
|
|
6747
|
+
body: "grant_type=client_credentials"
|
|
6748
|
+
});
|
|
6749
|
+
const text = await response.text();
|
|
6750
|
+
let data = null;
|
|
6751
|
+
try {
|
|
6752
|
+
data = JSON.parse(text);
|
|
6753
|
+
} catch (e) {
|
|
6754
|
+
}
|
|
6755
|
+
if (!response.ok || !data?.access_token) {
|
|
6756
|
+
throw new Error(data?.error_description || `Failed to get PayU access token: ${response.status}`);
|
|
6757
|
+
}
|
|
6758
|
+
return data.access_token;
|
|
6759
|
+
}
|
|
6760
|
+
async createInvoice(params, config) {
|
|
6761
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6762
|
+
const currency = (params.currency || "PLN").toUpperCase();
|
|
6763
|
+
const posId = config.merchantCode || config.merchantId || config.extra?.posId || "";
|
|
6764
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6765
|
+
let accessToken;
|
|
6766
|
+
try {
|
|
6767
|
+
accessToken = await this.getAccessToken(config);
|
|
6768
|
+
} catch (e) {
|
|
6769
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6770
|
+
}
|
|
6771
|
+
const isDirect = !!params.paymentMethod;
|
|
6772
|
+
const continueUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6773
|
+
const notifyUrl = callbackUrl || config.callbackUrl || "";
|
|
6774
|
+
const body = {
|
|
6775
|
+
notifyUrl,
|
|
6776
|
+
customerIp: params.providerParams?.customerIp || "127.0.0.1",
|
|
6777
|
+
merchantPosId: posId,
|
|
6778
|
+
description: productDetails,
|
|
6779
|
+
currencyCode: currency,
|
|
6780
|
+
totalAmount: amount.toString(),
|
|
6781
|
+
extOrderId: orderId,
|
|
6782
|
+
continueUrl,
|
|
6783
|
+
buyer: {
|
|
6784
|
+
email: customer?.email,
|
|
6785
|
+
firstName: customer?.name?.split(" ")[0],
|
|
6786
|
+
lastName: customer?.name?.split(" ").slice(1).join(" ") || "-",
|
|
6787
|
+
phone: customer?.phone,
|
|
6788
|
+
language: "en"
|
|
6789
|
+
},
|
|
6790
|
+
products: [
|
|
6791
|
+
{ name: productDetails, unitPrice: amount.toString(), quantity: "1" }
|
|
6792
|
+
],
|
|
6793
|
+
...params.providerParams
|
|
6794
|
+
};
|
|
6795
|
+
if (isDirect && params.paymentMethod) {
|
|
6796
|
+
body.payMethods = {
|
|
6797
|
+
payMethod: {
|
|
6798
|
+
type: "PBL",
|
|
6799
|
+
value: params.paymentMethod
|
|
6800
|
+
// e.g. "blik", "c" (card), "ap" (Apple Pay)
|
|
6801
|
+
}
|
|
6802
|
+
};
|
|
6803
|
+
}
|
|
6804
|
+
try {
|
|
6805
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders`, {
|
|
6806
|
+
method: "POST",
|
|
6807
|
+
headers: {
|
|
6808
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
6809
|
+
"Content-Type": "application/json"
|
|
6810
|
+
},
|
|
6811
|
+
body: JSON.stringify(body),
|
|
6812
|
+
redirect: "manual"
|
|
6813
|
+
// PayU responds with 302
|
|
6814
|
+
});
|
|
6815
|
+
const text = await response.text();
|
|
6816
|
+
let data = null;
|
|
6817
|
+
try {
|
|
6818
|
+
data = JSON.parse(text);
|
|
6819
|
+
} catch (e) {
|
|
6820
|
+
}
|
|
6821
|
+
if (response.status === 302 || response.headers.get("location")) {
|
|
6822
|
+
const location = response.headers.get("location") || "";
|
|
6823
|
+
return {
|
|
6824
|
+
success: true,
|
|
6825
|
+
provider: "payu",
|
|
6826
|
+
orderId,
|
|
6827
|
+
amount,
|
|
6828
|
+
reference: data?.orderId || orderId,
|
|
6829
|
+
paymentUrl: location,
|
|
6830
|
+
rawResponse: data
|
|
6831
|
+
};
|
|
6832
|
+
}
|
|
6833
|
+
if (!response.ok || !data || data.status?.statusCode === "ERROR") {
|
|
6834
|
+
return { success: false, provider: "payu", orderId, amount, rawResponse: data, error: data?.status?.statusDesc || `HTTP ${response.status}` };
|
|
6835
|
+
}
|
|
6836
|
+
return {
|
|
6837
|
+
success: true,
|
|
6838
|
+
provider: "payu",
|
|
6839
|
+
orderId,
|
|
6840
|
+
amount,
|
|
6841
|
+
reference: data.orderId || orderId,
|
|
6842
|
+
paymentUrl: data.redirectUri,
|
|
6843
|
+
rawResponse: data
|
|
6844
|
+
};
|
|
6845
|
+
} catch (e) {
|
|
6846
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
async verifyCallback(body, config) {
|
|
6850
|
+
const md5Key = config.extra?.md5Key || config.apiKey || config.secretKey || "";
|
|
6851
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6852
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6853
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6854
|
+
const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : false;
|
|
6855
|
+
const order = parsedBody?.order || parsedBody;
|
|
6856
|
+
const orderId = order.extOrderId || order.orderId || "";
|
|
6857
|
+
const amount = Number(order.totalAmount || 0);
|
|
6858
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6859
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6860
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6861
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6862
|
+
const isExpired = false;
|
|
6863
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6864
|
+
return {
|
|
6865
|
+
isValid,
|
|
6866
|
+
provider: "payu",
|
|
6867
|
+
orderId: String(orderId),
|
|
6868
|
+
amount,
|
|
6869
|
+
status,
|
|
6870
|
+
isPaid,
|
|
6871
|
+
isPending,
|
|
6872
|
+
isFailed,
|
|
6873
|
+
isExpired,
|
|
6874
|
+
statusCode: statusRaw,
|
|
6875
|
+
rawPayload: parsedBody
|
|
6876
|
+
};
|
|
6877
|
+
}
|
|
6878
|
+
async getPaymentMethods(params, config) {
|
|
6879
|
+
const methods = [
|
|
6880
|
+
{ paymentMethod: "credit_card", code: "c", paymentName: "Credit / Debit Card", paymentImage: "https://payu.com/favicon.ico", totalFee: "1.5%+", category: "Kartu Kredit" },
|
|
6881
|
+
{ paymentMethod: "blik", code: "blik", paymentName: "BLIK (Poland)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "E-Wallet" },
|
|
6882
|
+
{ paymentMethod: "apple_pay", code: "ap", paymentName: "Apple Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6883
|
+
{ paymentMethod: "google_pay", code: "gp", paymentName: "Google Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6884
|
+
{ paymentMethod: "bank_transfer", code: "t", paymentName: "Online Bank Transfer (50+ banks)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
6885
|
+
{ paymentMethod: "installment", code: "ai", paymentName: "Installments (PayU)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Bank rate", category: "Paylater / Cicilan" }
|
|
6886
|
+
];
|
|
6887
|
+
const categories = {};
|
|
6888
|
+
for (const item of methods) {
|
|
6889
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6890
|
+
categories[item.category].push(item);
|
|
6891
|
+
}
|
|
6892
|
+
return { success: true, provider: "payu", methods, categories, rawResponse: methods };
|
|
6893
|
+
}
|
|
6894
|
+
async checkTransaction(params, config) {
|
|
6895
|
+
const { merchantOrderId } = params;
|
|
6896
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6897
|
+
let accessToken;
|
|
6898
|
+
try {
|
|
6899
|
+
accessToken = await this.getAccessToken(config);
|
|
6900
|
+
} catch (e) {
|
|
6901
|
+
return {
|
|
6902
|
+
success: false,
|
|
6903
|
+
provider: "payu",
|
|
6904
|
+
orderId: merchantOrderId,
|
|
6905
|
+
reference: "",
|
|
6906
|
+
amount: 0,
|
|
6907
|
+
statusCode: "AUTH_ERROR",
|
|
6908
|
+
status: "failed",
|
|
6909
|
+
isPaid: false,
|
|
6910
|
+
isPending: false,
|
|
6911
|
+
isFailed: true,
|
|
6912
|
+
isExpired: false,
|
|
6913
|
+
statusMessage: e.message,
|
|
6914
|
+
error: e.message,
|
|
6915
|
+
rawResponse: null
|
|
6916
|
+
};
|
|
6917
|
+
}
|
|
6918
|
+
try {
|
|
6919
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
6920
|
+
method: "GET",
|
|
6921
|
+
headers: { "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/json" }
|
|
6922
|
+
});
|
|
6923
|
+
const text = await response.text();
|
|
6924
|
+
let data = null;
|
|
6925
|
+
try {
|
|
6926
|
+
data = JSON.parse(text);
|
|
6927
|
+
} catch (e) {
|
|
6928
|
+
}
|
|
6929
|
+
if (!response.ok || !data) {
|
|
6930
|
+
return {
|
|
6931
|
+
success: false,
|
|
6932
|
+
provider: "payu",
|
|
6933
|
+
orderId: merchantOrderId,
|
|
6934
|
+
reference: "",
|
|
6935
|
+
amount: 0,
|
|
6936
|
+
statusCode: response.status.toString(),
|
|
6937
|
+
status: "failed",
|
|
6938
|
+
isPaid: false,
|
|
6939
|
+
isPending: false,
|
|
6940
|
+
isFailed: true,
|
|
6941
|
+
isExpired: false,
|
|
6942
|
+
statusMessage: "HTTP Error",
|
|
6943
|
+
rawResponse: data
|
|
6944
|
+
};
|
|
6945
|
+
}
|
|
6946
|
+
const order = data.orders?.[0] || data;
|
|
6947
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6948
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6949
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6950
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6951
|
+
const isExpired = false;
|
|
6952
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6953
|
+
return {
|
|
6954
|
+
success: true,
|
|
6955
|
+
provider: "payu",
|
|
6956
|
+
orderId: order.extOrderId || merchantOrderId,
|
|
6957
|
+
reference: order.orderId || merchantOrderId,
|
|
6958
|
+
amount: Number(order.totalAmount || 0),
|
|
6959
|
+
statusCode: statusRaw,
|
|
6960
|
+
status,
|
|
6961
|
+
isPaid,
|
|
6962
|
+
isPending,
|
|
6963
|
+
isFailed,
|
|
6964
|
+
isExpired,
|
|
6965
|
+
statusMessage: statusRaw,
|
|
6966
|
+
transactionTime: order.orderCreateDate ? new Date(order.orderCreateDate) : void 0,
|
|
6967
|
+
rawResponse: data
|
|
6968
|
+
};
|
|
6969
|
+
} catch (e) {
|
|
6970
|
+
return {
|
|
6971
|
+
success: false,
|
|
6972
|
+
provider: "payu",
|
|
6973
|
+
orderId: merchantOrderId,
|
|
6974
|
+
reference: "",
|
|
6975
|
+
amount: 0,
|
|
6976
|
+
statusCode: "ERROR",
|
|
6977
|
+
status: "failed",
|
|
6978
|
+
isPaid: false,
|
|
6979
|
+
isPending: false,
|
|
6980
|
+
isFailed: true,
|
|
6981
|
+
isExpired: false,
|
|
6982
|
+
statusMessage: e.message,
|
|
6983
|
+
error: e.message,
|
|
6984
|
+
rawResponse: null
|
|
6985
|
+
};
|
|
6986
|
+
}
|
|
6987
|
+
}
|
|
6988
|
+
};
|
|
6989
|
+
|
|
6990
|
+
// src/providers/braintree/signature.ts
|
|
6991
|
+
var import_crypto26 = require("crypto");
|
|
6992
|
+
function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
|
|
6993
|
+
if (!privateKey || !btSignature || !btPayload) return false;
|
|
6994
|
+
try {
|
|
6995
|
+
const parts = btSignature.split("|");
|
|
6996
|
+
if (parts.length < 2) return false;
|
|
6997
|
+
const providedHmac = parts[1];
|
|
6998
|
+
const payload = Buffer.from(btPayload, "base64").toString("utf8");
|
|
6999
|
+
const secretHash = (0, import_crypto26.createHash)("sha1").update(privateKey).digest("hex");
|
|
7000
|
+
const expected = (0, import_crypto26.createHmac)("sha1", secretHash).update(payload).digest("hex");
|
|
7001
|
+
return safeCompare(expected, providedHmac);
|
|
7002
|
+
} catch {
|
|
7003
|
+
return false;
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
function buildBraintreeBasicAuth(publicKey, privateKey) {
|
|
7007
|
+
return Buffer.from(`${publicKey}:${privateKey}`).toString("base64");
|
|
7008
|
+
}
|
|
7009
|
+
|
|
7010
|
+
// src/providers/braintree/provider.ts
|
|
7011
|
+
var BraintreeProvider = class extends BasePaymentProvider {
|
|
7012
|
+
name = "braintree";
|
|
7013
|
+
getBaseUrl(config) {
|
|
7014
|
+
const merchantId = config.merchantCode || config.merchantId || "";
|
|
7015
|
+
const base = config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
7016
|
+
return `${base}/merchants/${merchantId}`;
|
|
7017
|
+
}
|
|
7018
|
+
buildHeaders(config) {
|
|
7019
|
+
const publicKey = config.clientKey || config.extra?.publicKey || "";
|
|
7020
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
7021
|
+
return {
|
|
7022
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
7023
|
+
"Content-Type": "application/json",
|
|
7024
|
+
"Braintree-Version": "2019-01-01"
|
|
7025
|
+
};
|
|
7026
|
+
}
|
|
7027
|
+
async createInvoice(params, config) {
|
|
7028
|
+
const { orderId, amount, productDetails, customer } = params;
|
|
7029
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
7030
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7031
|
+
const headers = this.buildHeaders(config);
|
|
7032
|
+
const isDirect = !!params.paymentMethod;
|
|
7033
|
+
try {
|
|
7034
|
+
if (isDirect) {
|
|
7035
|
+
const paymentMethodNonce = params.providerParams?.nonce || params.providerParams?.paymentMethodNonce || "fake-valid-nonce";
|
|
7036
|
+
const body = {
|
|
7037
|
+
transaction: {
|
|
7038
|
+
amount: (amount / 100).toFixed(2),
|
|
7039
|
+
payment_method_nonce: paymentMethodNonce,
|
|
7040
|
+
order_id: orderId,
|
|
7041
|
+
currency_iso_code: currency,
|
|
7042
|
+
options: { submit_for_settlement: true },
|
|
7043
|
+
customer: { first_name: customer?.name, email: customer?.email },
|
|
7044
|
+
custom_fields: { order_id: orderId },
|
|
7045
|
+
...params.providerParams
|
|
7046
|
+
}
|
|
7047
|
+
};
|
|
7048
|
+
const response = await fetch(`${baseUrl}/transactions`, {
|
|
7049
|
+
method: "POST",
|
|
7050
|
+
headers,
|
|
7051
|
+
body: JSON.stringify(body)
|
|
7052
|
+
});
|
|
7053
|
+
const text = await response.text();
|
|
7054
|
+
let data = null;
|
|
7055
|
+
try {
|
|
7056
|
+
data = JSON.parse(text);
|
|
7057
|
+
} catch (e) {
|
|
7058
|
+
}
|
|
7059
|
+
if (!response.ok || data?.apiErrorResponse) {
|
|
7060
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.apiErrorResponse?.message || `HTTP ${response.status}` };
|
|
7061
|
+
}
|
|
7062
|
+
const tx = data?.transaction || data;
|
|
7063
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
7064
|
+
return {
|
|
7065
|
+
success: statusRaw === "submitted_for_settlement" || statusRaw === "settling" || statusRaw === "settled",
|
|
7066
|
+
provider: "braintree",
|
|
7067
|
+
orderId,
|
|
7068
|
+
amount: Math.round(Number(tx.amount || amount / 100) * 100),
|
|
7069
|
+
reference: tx.id,
|
|
7070
|
+
rawResponse: data
|
|
7071
|
+
};
|
|
7072
|
+
} else {
|
|
7073
|
+
const body = { client_token: { customer_id: customer?.email || orderId } };
|
|
7074
|
+
const response = await fetch(`${baseUrl}/client_token`, {
|
|
7075
|
+
method: "POST",
|
|
7076
|
+
headers,
|
|
7077
|
+
body: JSON.stringify(body)
|
|
7078
|
+
});
|
|
7079
|
+
const text = await response.text();
|
|
7080
|
+
let data = null;
|
|
7081
|
+
try {
|
|
7082
|
+
data = JSON.parse(text);
|
|
7083
|
+
} catch (e) {
|
|
7084
|
+
}
|
|
7085
|
+
if (!response.ok || !data?.clientToken) {
|
|
7086
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
7087
|
+
}
|
|
7088
|
+
return {
|
|
7089
|
+
success: true,
|
|
7090
|
+
provider: "braintree",
|
|
7091
|
+
orderId,
|
|
7092
|
+
amount,
|
|
7093
|
+
reference: orderId,
|
|
7094
|
+
paymentCode: data.clientToken,
|
|
7095
|
+
// Frontend uses this token for Drop-in UI
|
|
7096
|
+
rawResponse: data
|
|
7097
|
+
};
|
|
7098
|
+
}
|
|
7099
|
+
} catch (e) {
|
|
7100
|
+
return { success: false, provider: "braintree", orderId, amount, error: e.message, rawResponse: null };
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7103
|
+
async verifyCallback(body, config) {
|
|
7104
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
7105
|
+
const btSignature = config.extra?.btSignature || "";
|
|
7106
|
+
const btPayload = config.extra?.btPayload || "";
|
|
7107
|
+
const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : false;
|
|
7108
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
7109
|
+
const subject = parsedBody?.subject || parsedBody;
|
|
7110
|
+
const transaction = subject?.transaction || subject?.disbursement || parsedBody;
|
|
7111
|
+
const kind = parsedBody?.kind || parsedBody?.event || "";
|
|
7112
|
+
const orderId = transaction?.orderId || transaction?.order_id || transaction?.id || "";
|
|
7113
|
+
const amount = Math.round(Number(transaction?.amount || 0) * 100);
|
|
7114
|
+
const statusRaw = (transaction?.status || "").toLowerCase();
|
|
7115
|
+
const isPaid = kind === "transaction_settled" || kind === "transaction_disbursed" || statusRaw === "settled";
|
|
7116
|
+
const isPending = kind === "transaction_settlement_declined" || statusRaw === "submitted_for_settlement" || statusRaw === "settling";
|
|
7117
|
+
const isFailed = kind === "transaction_failed" || statusRaw === "failed" || statusRaw === "voided";
|
|
7118
|
+
const isExpired = statusRaw === "expired";
|
|
7119
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7120
|
+
return {
|
|
7121
|
+
isValid,
|
|
7122
|
+
provider: "braintree",
|
|
7123
|
+
orderId: String(orderId),
|
|
7124
|
+
amount,
|
|
7125
|
+
status,
|
|
7126
|
+
isPaid,
|
|
7127
|
+
isPending,
|
|
7128
|
+
isFailed,
|
|
7129
|
+
isExpired,
|
|
7130
|
+
statusCode: kind || statusRaw,
|
|
7131
|
+
rawPayload: parsedBody
|
|
7132
|
+
};
|
|
7133
|
+
}
|
|
7134
|
+
async getPaymentMethods(params, config) {
|
|
7135
|
+
const methods = [
|
|
7136
|
+
{ paymentMethod: "credit_card", code: "CreditCard", paymentName: "Credit / Debit Card (Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "2.59% + $0.49", category: "Kartu Kredit" },
|
|
7137
|
+
{ paymentMethod: "paypal", code: "PayPalAccount", paymentName: "PayPal (via Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "3.49% + fixed", category: "E-Wallet" },
|
|
7138
|
+
{ paymentMethod: "apple_pay", code: "ApplePayCard", paymentName: "Apple Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
7139
|
+
{ paymentMethod: "google_pay", code: "AndroidPayCard", paymentName: "Google Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
7140
|
+
{ paymentMethod: "venmo", code: "VenmoAccount", paymentName: "Venmo (US only)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "1.9% + $0.10", category: "E-Wallet" }
|
|
7141
|
+
];
|
|
7142
|
+
const categories = {};
|
|
7143
|
+
for (const item of methods) {
|
|
7144
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
7145
|
+
categories[item.category].push(item);
|
|
7146
|
+
}
|
|
7147
|
+
return { success: true, provider: "braintree", methods, categories, rawResponse: methods };
|
|
7148
|
+
}
|
|
7149
|
+
async checkTransaction(params, config) {
|
|
7150
|
+
const { merchantOrderId } = params;
|
|
7151
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7152
|
+
const headers = this.buildHeaders(config);
|
|
7153
|
+
try {
|
|
7154
|
+
const response = await fetch(`${baseUrl}/transactions/${encodeURIComponent(merchantOrderId)}`, {
|
|
7155
|
+
method: "GET",
|
|
7156
|
+
headers
|
|
7157
|
+
});
|
|
7158
|
+
const text = await response.text();
|
|
7159
|
+
let data = null;
|
|
7160
|
+
try {
|
|
7161
|
+
data = JSON.parse(text);
|
|
7162
|
+
} catch (e) {
|
|
7163
|
+
}
|
|
7164
|
+
if (!response.ok || !data) {
|
|
7165
|
+
return {
|
|
7166
|
+
success: false,
|
|
7167
|
+
provider: "braintree",
|
|
7168
|
+
orderId: merchantOrderId,
|
|
7169
|
+
reference: "",
|
|
7170
|
+
amount: 0,
|
|
7171
|
+
statusCode: response.status.toString(),
|
|
7172
|
+
status: "failed",
|
|
7173
|
+
isPaid: false,
|
|
7174
|
+
isPending: false,
|
|
7175
|
+
isFailed: true,
|
|
7176
|
+
isExpired: false,
|
|
7177
|
+
statusMessage: "HTTP Error",
|
|
7178
|
+
rawResponse: data
|
|
7179
|
+
};
|
|
7180
|
+
}
|
|
7181
|
+
const tx = data.transaction || data;
|
|
7182
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
7183
|
+
const isPaid = statusRaw === "settled" || statusRaw === "settling";
|
|
7184
|
+
const isPending = statusRaw === "submitted_for_settlement" || statusRaw === "authorized";
|
|
7185
|
+
const isExpired = statusRaw === "expired";
|
|
7186
|
+
const isFailed = statusRaw === "failed" || statusRaw === "voided";
|
|
7187
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7188
|
+
return {
|
|
7189
|
+
success: true,
|
|
7190
|
+
provider: "braintree",
|
|
7191
|
+
orderId: tx.orderId || merchantOrderId,
|
|
7192
|
+
reference: tx.id || merchantOrderId,
|
|
7193
|
+
amount: Math.round(Number(tx.amount || 0) * 100),
|
|
7194
|
+
statusCode: statusRaw,
|
|
7195
|
+
status,
|
|
7196
|
+
isPaid,
|
|
7197
|
+
isPending,
|
|
7198
|
+
isFailed,
|
|
7199
|
+
isExpired,
|
|
7200
|
+
statusMessage: statusRaw,
|
|
7201
|
+
paymentType: tx.paymentInstrumentType || "card",
|
|
7202
|
+
transactionTime: tx.createdAt ? new Date(tx.createdAt) : void 0,
|
|
7203
|
+
rawResponse: data
|
|
7204
|
+
};
|
|
7205
|
+
} catch (e) {
|
|
7206
|
+
return {
|
|
7207
|
+
success: false,
|
|
7208
|
+
provider: "braintree",
|
|
7209
|
+
orderId: merchantOrderId,
|
|
7210
|
+
reference: "",
|
|
7211
|
+
amount: 0,
|
|
7212
|
+
statusCode: "ERROR",
|
|
7213
|
+
status: "failed",
|
|
7214
|
+
isPaid: false,
|
|
7215
|
+
isPending: false,
|
|
7216
|
+
isFailed: true,
|
|
7217
|
+
isExpired: false,
|
|
7218
|
+
statusMessage: e.message,
|
|
7219
|
+
error: e.message,
|
|
7220
|
+
rawResponse: null
|
|
7221
|
+
};
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7224
|
+
};
|
|
7225
|
+
|
|
7226
|
+
// src/providers/twocheckout/signature.ts
|
|
7227
|
+
var import_crypto28 = require("crypto");
|
|
7228
|
+
function buildTwoCheckoutAuth(merchantCode, secretKey) {
|
|
7229
|
+
const date = Math.floor(Date.now() / 1e3).toString();
|
|
7230
|
+
const raw = merchantCode + date;
|
|
7231
|
+
const hmac = (0, import_crypto28.createHmac)("sha256", secretKey).update(raw).digest("hex");
|
|
7232
|
+
const header = `code="${merchantCode}" date="${date}" hash="${hmac}"`;
|
|
7233
|
+
return { header, date };
|
|
7234
|
+
}
|
|
7235
|
+
function verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) {
|
|
7236
|
+
if (!secretWord || !providedHash) return false;
|
|
7237
|
+
try {
|
|
7238
|
+
const raw = secretWord + saleId + productId + invoiceId;
|
|
7239
|
+
const expected = (0, import_crypto28.createHash)("md5").update(raw).digest("hex");
|
|
7240
|
+
return safeCompare(expected, providedHash);
|
|
7241
|
+
} catch {
|
|
7242
|
+
return false;
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
|
|
7246
|
+
// src/providers/twocheckout/provider.ts
|
|
7247
|
+
var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
7248
|
+
name = "twocheckout";
|
|
7249
|
+
getBaseUrl(config) {
|
|
7250
|
+
return config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
7251
|
+
}
|
|
7252
|
+
buildHeaders(config) {
|
|
7253
|
+
const merchantCode = config.merchantCode || config.merchantId || "";
|
|
7254
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
7255
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
7256
|
+
return {
|
|
7257
|
+
"X-Avangate-Authentication": header,
|
|
7258
|
+
"Content-Type": "application/json",
|
|
7259
|
+
"Accept": "application/json"
|
|
7260
|
+
};
|
|
7261
|
+
}
|
|
7262
|
+
async createInvoice(params, config) {
|
|
7263
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
7264
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
7265
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7266
|
+
const headers = this.buildHeaders(config);
|
|
7267
|
+
const isDirect = !!params.paymentMethod;
|
|
7268
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
7269
|
+
const body = {
|
|
7270
|
+
Currency: currency,
|
|
7271
|
+
Language: "en",
|
|
7272
|
+
Country: config.extra?.country || "US",
|
|
7273
|
+
CustomerIP: params.providerParams?.customerIp || "127.0.0.1",
|
|
7274
|
+
Source: "API",
|
|
7275
|
+
MerchantReference: orderId,
|
|
7276
|
+
Items: [
|
|
7277
|
+
{
|
|
7278
|
+
Name: productDetails,
|
|
7279
|
+
Quantity: 1,
|
|
7280
|
+
Price: { Amount: (amount / 100).toFixed(2), Type: "CUSTOM" },
|
|
7281
|
+
Type: "PRODUCT",
|
|
7282
|
+
IsDynamic: true,
|
|
7283
|
+
Tangible: false
|
|
7284
|
+
}
|
|
7285
|
+
],
|
|
7286
|
+
BillingDetails: {
|
|
7287
|
+
FirstName: customer?.name?.split(" ")[0] || "Customer",
|
|
7288
|
+
LastName: customer?.name?.split(" ").slice(1).join(" ") || "Name",
|
|
7289
|
+
Email: customer?.email,
|
|
7290
|
+
Country: config.extra?.country || "US",
|
|
7291
|
+
Address1: config.extra?.address || "N/A",
|
|
7292
|
+
City: config.extra?.city || "N/A",
|
|
7293
|
+
State: config.extra?.state || "",
|
|
7294
|
+
Zip: config.extra?.zip || "00000"
|
|
7295
|
+
},
|
|
7296
|
+
...params.providerParams
|
|
7297
|
+
};
|
|
7298
|
+
if (!isDirect) {
|
|
7299
|
+
body.PaymentDetails = { Type: "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7300
|
+
} else {
|
|
7301
|
+
body.PaymentDetails = { Type: params.paymentMethod === "paypal" ? "PAYPAL" : "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7302
|
+
}
|
|
7303
|
+
try {
|
|
7304
|
+
const response = await fetch(`${baseUrl}/6.0/orders`, {
|
|
7305
|
+
method: "POST",
|
|
7306
|
+
headers,
|
|
7307
|
+
body: JSON.stringify(body)
|
|
7308
|
+
});
|
|
7309
|
+
const text = await response.text();
|
|
7310
|
+
let data = null;
|
|
7311
|
+
try {
|
|
7312
|
+
data = JSON.parse(text);
|
|
7313
|
+
} catch (e) {
|
|
7314
|
+
}
|
|
7315
|
+
if (!response.ok || !data || data.error_code) {
|
|
7316
|
+
return { success: false, provider: "twocheckout", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
7317
|
+
}
|
|
7318
|
+
const paymentUrl = data.PaymentDetails?.PaymentMethod?.RedirectURL || data.PaymentDetails?.PaymentMethod?.Href || `${successUrl}?ref=${data.RefNo}`;
|
|
7319
|
+
return {
|
|
7320
|
+
success: true,
|
|
7321
|
+
provider: "twocheckout",
|
|
7322
|
+
orderId,
|
|
7323
|
+
amount,
|
|
7324
|
+
reference: data.RefNo || data.OrderNo?.toString(),
|
|
7325
|
+
paymentUrl,
|
|
7326
|
+
rawResponse: data
|
|
7327
|
+
};
|
|
7328
|
+
} catch (e) {
|
|
7329
|
+
return { success: false, provider: "twocheckout", orderId, amount, error: e.message, rawResponse: null };
|
|
7330
|
+
}
|
|
7331
|
+
}
|
|
7332
|
+
async verifyCallback(body, config) {
|
|
7333
|
+
const secretWord = config.extra?.secretWord || config.apiKey || "";
|
|
7334
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
7335
|
+
const saleId = parsedBody?.SALE_ID || parsedBody?.sale_id || "";
|
|
7336
|
+
const productId = parsedBody?.IPN_PID?.[0] || parsedBody?.product_id || "";
|
|
7337
|
+
const invoiceId = parsedBody?.IPN_PNAME?.[0] || parsedBody?.invoice_id || "";
|
|
7338
|
+
const providedHash = parsedBody?.HASH || parsedBody?.hash || "";
|
|
7339
|
+
const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : false;
|
|
7340
|
+
const orderId = parsedBody?.REFNOEXT || parsedBody?.ext_ref_no || parsedBody?.SALE_ID || "";
|
|
7341
|
+
const amount = Math.round(Number(parsedBody?.IPN_TOTAL_GENERAL || parsedBody?.total || 0) * 100);
|
|
7342
|
+
const statusRaw = (parsedBody?.ORDERSTATUS || parsedBody?.order_status || "").toUpperCase();
|
|
7343
|
+
const isPaid = statusRaw === "COMPLETE" || statusRaw === "COMPLETE_MANUAL";
|
|
7344
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7345
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND" || statusRaw === "FRAUD";
|
|
7346
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7347
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7348
|
+
return {
|
|
7349
|
+
isValid,
|
|
7350
|
+
provider: "twocheckout",
|
|
7351
|
+
orderId: String(orderId),
|
|
7352
|
+
amount,
|
|
7353
|
+
status,
|
|
7354
|
+
isPaid,
|
|
7355
|
+
isPending,
|
|
7356
|
+
isFailed,
|
|
7357
|
+
isExpired,
|
|
7358
|
+
statusCode: statusRaw,
|
|
7359
|
+
rawPayload: parsedBody
|
|
7360
|
+
};
|
|
7361
|
+
}
|
|
7362
|
+
async getPaymentMethods(params, config) {
|
|
7363
|
+
const methods = [
|
|
7364
|
+
{ paymentMethod: "credit_card", code: "EES_TOKEN_PAYMENT", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "Kartu Kredit" },
|
|
7365
|
+
{ paymentMethod: "paypal", code: "PAYPAL", paymentName: "PayPal", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "E-Wallet" },
|
|
7366
|
+
{ paymentMethod: "wire_transfer", code: "WIRE", paymentName: "Wire Transfer / Bank Transfer", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
7367
|
+
{ paymentMethod: "paylater", code: "PAY_LATER", paymentName: "Buy Now Pay Later (Klarna)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" }
|
|
7368
|
+
];
|
|
7369
|
+
const categories = {};
|
|
7370
|
+
for (const item of methods) {
|
|
7371
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
7372
|
+
categories[item.category].push(item);
|
|
7373
|
+
}
|
|
7374
|
+
return { success: true, provider: "twocheckout", methods, categories, rawResponse: methods };
|
|
7375
|
+
}
|
|
7376
|
+
async checkTransaction(params, config) {
|
|
7377
|
+
const { merchantOrderId } = params;
|
|
7378
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7379
|
+
const headers = this.buildHeaders(config);
|
|
7380
|
+
try {
|
|
7381
|
+
const response = await fetch(`${baseUrl}/6.0/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
7382
|
+
method: "GET",
|
|
7383
|
+
headers
|
|
7384
|
+
});
|
|
7385
|
+
const text = await response.text();
|
|
7386
|
+
let data = null;
|
|
7387
|
+
try {
|
|
7388
|
+
data = JSON.parse(text);
|
|
7389
|
+
} catch (e) {
|
|
7390
|
+
}
|
|
7391
|
+
if (!response.ok || !data || data.error_code) {
|
|
7392
|
+
return {
|
|
7393
|
+
success: false,
|
|
7394
|
+
provider: "twocheckout",
|
|
7395
|
+
orderId: merchantOrderId,
|
|
7396
|
+
reference: "",
|
|
7397
|
+
amount: 0,
|
|
7398
|
+
statusCode: response.status.toString(),
|
|
7399
|
+
status: "failed",
|
|
7400
|
+
isPaid: false,
|
|
7401
|
+
isPending: false,
|
|
7402
|
+
isFailed: true,
|
|
7403
|
+
isExpired: false,
|
|
7404
|
+
statusMessage: data?.message || "HTTP Error",
|
|
7405
|
+
rawResponse: data
|
|
7406
|
+
};
|
|
7407
|
+
}
|
|
7408
|
+
const statusRaw = (data.Status || "").toUpperCase();
|
|
7409
|
+
const isPaid = statusRaw === "COMPLETE";
|
|
7410
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7411
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7412
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND";
|
|
7413
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7414
|
+
return {
|
|
7415
|
+
success: true,
|
|
7416
|
+
provider: "twocheckout",
|
|
7417
|
+
orderId: data.ExternalReference || merchantOrderId,
|
|
7418
|
+
reference: data.RefNo?.toString() || merchantOrderId,
|
|
7419
|
+
amount: Math.round(Number(data.GrossAmount || 0) * 100),
|
|
7420
|
+
statusCode: statusRaw,
|
|
7421
|
+
status,
|
|
7422
|
+
isPaid,
|
|
7423
|
+
isPending,
|
|
7424
|
+
isFailed,
|
|
7425
|
+
isExpired,
|
|
7426
|
+
statusMessage: statusRaw,
|
|
7427
|
+
transactionTime: data.OrderDate ? new Date(data.OrderDate) : void 0,
|
|
7428
|
+
rawResponse: data
|
|
7429
|
+
};
|
|
7430
|
+
} catch (e) {
|
|
7431
|
+
return {
|
|
7432
|
+
success: false,
|
|
7433
|
+
provider: "twocheckout",
|
|
7434
|
+
orderId: merchantOrderId,
|
|
7435
|
+
reference: "",
|
|
7436
|
+
amount: 0,
|
|
7437
|
+
statusCode: "ERROR",
|
|
7438
|
+
status: "failed",
|
|
7439
|
+
isPaid: false,
|
|
7440
|
+
isPending: false,
|
|
7441
|
+
isFailed: true,
|
|
7442
|
+
isExpired: false,
|
|
7443
|
+
statusMessage: e.message,
|
|
7444
|
+
error: e.message,
|
|
7445
|
+
rawResponse: null
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
}
|
|
7449
|
+
};
|
|
7450
|
+
|
|
7451
|
+
// src/clients/duitku.ts
|
|
7452
|
+
var DuitkuClient = class {
|
|
7453
|
+
merchantCode;
|
|
7454
|
+
apiKey;
|
|
7455
|
+
sandbox;
|
|
7456
|
+
constructor(config) {
|
|
7457
|
+
this.merchantCode = config.merchantCode || "";
|
|
7458
|
+
this.apiKey = config.apiKey || config.serverKey || "";
|
|
7459
|
+
this.sandbox = !!config.sandbox;
|
|
7460
|
+
}
|
|
7461
|
+
getPassportBaseUrl() {
|
|
7462
|
+
return this.sandbox ? "https://sandbox.duitku.com/webapi" : "https://passport.duitku.com/webapi";
|
|
7463
|
+
}
|
|
7464
|
+
getApiBaseUrl() {
|
|
7465
|
+
return this.sandbox ? "https://api-sandbox.duitku.com" : "https://api-prod.duitku.com";
|
|
7466
|
+
}
|
|
7467
|
+
/**
|
|
7468
|
+
* Request helper generic dengan kalkulasi signature Duitku otomatis
|
|
7469
|
+
*/
|
|
7470
|
+
async request(method, endpoint, body = {}, options) {
|
|
7471
|
+
const baseUrl = options?.baseUrl === "api" ? this.getApiBaseUrl() : this.getPassportBaseUrl();
|
|
7472
|
+
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;
|
|
7473
|
+
const timestamp = Date.now().toString();
|
|
7474
|
+
const headerSignature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7475
|
+
const headers = {
|
|
7476
|
+
"Content-Type": "application/json",
|
|
7477
|
+
"Accept": "application/json",
|
|
7478
|
+
"x-duitku-signature": headerSignature,
|
|
7479
|
+
"x-duitku-timestamp": timestamp,
|
|
7480
|
+
"x-duitku-merchantcode": this.merchantCode,
|
|
7481
|
+
...options?.customHeaders
|
|
7482
|
+
};
|
|
7483
|
+
const fetchOptions = {
|
|
7484
|
+
method,
|
|
7485
|
+
headers
|
|
7486
|
+
};
|
|
7487
|
+
if (method === "POST" && body) {
|
|
7488
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7489
|
+
}
|
|
7490
|
+
const response = await fetch(url, fetchOptions);
|
|
7491
|
+
const text = await response.text();
|
|
7492
|
+
let data = null;
|
|
7493
|
+
try {
|
|
7494
|
+
data = JSON.parse(text);
|
|
7495
|
+
} catch (e) {
|
|
7496
|
+
}
|
|
7497
|
+
if (!response.ok) {
|
|
7498
|
+
throw new Error(data?.Message || data?.statusMessage || data?.responseMessage || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7499
|
+
}
|
|
7500
|
+
return data || text;
|
|
7501
|
+
}
|
|
7502
|
+
// ─── TRANSACTIONS & PAYMENT METHODS ──────────────────────────────────────────
|
|
7503
|
+
/**
|
|
7504
|
+
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
7505
|
+
*/
|
|
7506
|
+
async checkTransaction(merchantOrderId) {
|
|
7507
|
+
const { bodySignature } = getDuitkuStatusSignatures(
|
|
7508
|
+
this.merchantCode,
|
|
7509
|
+
merchantOrderId,
|
|
7510
|
+
this.apiKey
|
|
7511
|
+
);
|
|
7512
|
+
return this.request(
|
|
7513
|
+
"POST",
|
|
7514
|
+
"/api/merchant/transactionStatus",
|
|
7515
|
+
{
|
|
7516
|
+
merchantCode: this.merchantCode,
|
|
7517
|
+
merchantOrderId,
|
|
7518
|
+
signature: bodySignature
|
|
7519
|
+
},
|
|
7520
|
+
{ baseUrl: "api" }
|
|
7521
|
+
);
|
|
7522
|
+
}
|
|
7523
|
+
/**
|
|
7524
|
+
* Ambil daftar channel pembayaran aktif dan kalkulasi fee dinamis
|
|
7525
|
+
*/
|
|
7526
|
+
async getPaymentMethods(amount = 1e4) {
|
|
7527
|
+
const integerAmount = Math.round(amount);
|
|
7528
|
+
const datetime = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
7529
|
+
const signature = getDuitkuPaymentMethodsSignature(this.merchantCode, integerAmount, datetime, this.apiKey);
|
|
7530
|
+
return this.request("POST", "/api/merchant/paymentmethod/getpaymentmethod", {
|
|
7531
|
+
merchantcode: this.merchantCode,
|
|
7532
|
+
amount: integerAmount,
|
|
7533
|
+
datetime,
|
|
7534
|
+
signature
|
|
7535
|
+
});
|
|
7536
|
+
}
|
|
7537
|
+
// ─── DISBURSEMENT & BALANCE INQUIRY ──────────────────────────────────────────
|
|
7538
|
+
/**
|
|
7539
|
+
* Cek saldo merchant (Balance Inquiry)
|
|
7540
|
+
*/
|
|
7541
|
+
async checkBalance() {
|
|
7542
|
+
const timestamp = Date.now().toString();
|
|
7543
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7544
|
+
try {
|
|
7545
|
+
const data = await this.request(
|
|
7546
|
+
"POST",
|
|
7547
|
+
"/api/merchant/checkBalance",
|
|
7548
|
+
{
|
|
7549
|
+
merchantCode: this.merchantCode,
|
|
7550
|
+
signature
|
|
7551
|
+
},
|
|
7552
|
+
{ baseUrl: "api" }
|
|
7553
|
+
);
|
|
7554
|
+
return {
|
|
7555
|
+
success: data.responseCode === "00" || data.statusCode === "00",
|
|
7556
|
+
balance: data.balance ? Number(data.balance) : void 0,
|
|
7557
|
+
rawResponse: data
|
|
7558
|
+
};
|
|
7559
|
+
} catch (e) {
|
|
7560
|
+
return {
|
|
7561
|
+
success: false,
|
|
7562
|
+
rawResponse: null,
|
|
7563
|
+
error: e.message || "Failed to check Duitku merchant balance"
|
|
7564
|
+
};
|
|
7565
|
+
}
|
|
7566
|
+
}
|
|
7567
|
+
/**
|
|
7568
|
+
* Mengambil daftar bank yang didukung untuk transfer / penarikan dana
|
|
7569
|
+
*/
|
|
7570
|
+
async listBanks() {
|
|
7571
|
+
const timestamp = Date.now().toString();
|
|
7572
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7573
|
+
return this.request(
|
|
7574
|
+
"POST",
|
|
7575
|
+
"/api/disbursement/listBank",
|
|
7576
|
+
{
|
|
7577
|
+
merchantCode: this.merchantCode,
|
|
7578
|
+
signature
|
|
7579
|
+
},
|
|
7580
|
+
{ baseUrl: "api" }
|
|
7581
|
+
);
|
|
7582
|
+
}
|
|
7583
|
+
/**
|
|
7584
|
+
* Validasi nama pemilik rekening bank sebelum eksekusi transfer (Bank Account Inquiry)
|
|
7585
|
+
*/
|
|
7586
|
+
async inquiryBankAccount(bankCode, bankAccount) {
|
|
7587
|
+
const timestamp = Date.now().toString();
|
|
7588
|
+
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
7589
|
+
return this.request(
|
|
7590
|
+
"POST",
|
|
7591
|
+
"/api/disbursement/inquiry",
|
|
7592
|
+
{
|
|
7593
|
+
merchantCode: this.merchantCode,
|
|
7594
|
+
bankCode,
|
|
7595
|
+
bankAccount,
|
|
7596
|
+
signature
|
|
7597
|
+
},
|
|
7598
|
+
{ baseUrl: "api" }
|
|
7599
|
+
);
|
|
7600
|
+
}
|
|
7601
|
+
/**
|
|
7602
|
+
* Eksekusi transfer dana / payout (Disbursement Transfer)
|
|
7603
|
+
*/
|
|
7604
|
+
async disburse(params) {
|
|
7605
|
+
const integerAmount = Math.round(params.amount);
|
|
7606
|
+
const signature = sha256(
|
|
7607
|
+
this.merchantCode + params.merchantOrderId + params.bankCode + params.bankAccount + integerAmount.toString() + this.apiKey
|
|
7608
|
+
);
|
|
7609
|
+
const payload = {
|
|
7610
|
+
merchantCode: this.merchantCode,
|
|
7611
|
+
merchantOrderId: params.merchantOrderId,
|
|
7612
|
+
bankCode: params.bankCode,
|
|
7613
|
+
bankAccount: params.bankAccount,
|
|
7614
|
+
amount: integerAmount,
|
|
7615
|
+
purpose: params.purpose,
|
|
7616
|
+
senderName: params.senderName || "",
|
|
7617
|
+
senderPhone: params.senderPhone || "",
|
|
7618
|
+
callbackUrl: params.callbackUrl || "",
|
|
7619
|
+
signature
|
|
7620
|
+
};
|
|
7621
|
+
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
7622
|
+
}
|
|
7623
|
+
/**
|
|
7624
|
+
* Cek status disbursement berdasarkan merchant order ID
|
|
7625
|
+
*/
|
|
7626
|
+
async checkDisbursementStatus(merchantOrderId) {
|
|
7627
|
+
const signature = sha256(this.merchantCode + merchantOrderId + this.apiKey);
|
|
7628
|
+
return this.request(
|
|
7629
|
+
"POST",
|
|
7630
|
+
"/api/disbursement/checkStatus",
|
|
7631
|
+
{
|
|
7632
|
+
merchantCode: this.merchantCode,
|
|
7633
|
+
merchantOrderId,
|
|
7634
|
+
signature
|
|
7635
|
+
},
|
|
7636
|
+
{ baseUrl: "api" }
|
|
7637
|
+
);
|
|
7638
|
+
}
|
|
7639
|
+
};
|
|
7640
|
+
|
|
7641
|
+
// src/clients/ipaymu.ts
|
|
7642
|
+
var IpaymuClient = class {
|
|
7643
|
+
va;
|
|
7644
|
+
apiKey;
|
|
7645
|
+
sandbox;
|
|
7646
|
+
constructor(config) {
|
|
5586
7647
|
this.va = config.merchantCode || config.merchantId || "";
|
|
5587
7648
|
this.apiKey = config.apiKey || config.serverKey || "";
|
|
5588
7649
|
this.sandbox = !!config.sandbox;
|
|
@@ -6152,6 +8213,533 @@ var StripeClient = class {
|
|
|
6152
8213
|
}
|
|
6153
8214
|
};
|
|
6154
8215
|
|
|
8216
|
+
// src/clients/paypal.ts
|
|
8217
|
+
var PaypalClient = class {
|
|
8218
|
+
config;
|
|
8219
|
+
constructor(config) {
|
|
8220
|
+
this.config = config;
|
|
8221
|
+
}
|
|
8222
|
+
getBaseUrl() {
|
|
8223
|
+
return this.config.sandbox !== false ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
8224
|
+
}
|
|
8225
|
+
async getAccessToken() {
|
|
8226
|
+
const clientId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8227
|
+
const clientSecret = this.config.apiKey || this.config.secretKey || "";
|
|
8228
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
8229
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/oauth2/token`, {
|
|
8230
|
+
method: "POST",
|
|
8231
|
+
headers: { "Authorization": `Basic ${auth}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8232
|
+
body: "grant_type=client_credentials"
|
|
8233
|
+
});
|
|
8234
|
+
const data = await response.json();
|
|
8235
|
+
if (!data?.access_token) throw new Error(data?.error_description || "Failed to get PayPal access token");
|
|
8236
|
+
return data.access_token;
|
|
8237
|
+
}
|
|
8238
|
+
/** Ambil detail order PayPal berdasarkan Order ID */
|
|
8239
|
+
async getOrder(orderId) {
|
|
8240
|
+
const token = await this.getAccessToken();
|
|
8241
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}`, {
|
|
8242
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8243
|
+
});
|
|
8244
|
+
return response.json();
|
|
8245
|
+
}
|
|
8246
|
+
/** Capture order PayPal (mengeksekusi pembayaran yang sudah diapprove buyer) */
|
|
8247
|
+
async captureOrder(orderId) {
|
|
8248
|
+
const token = await this.getAccessToken();
|
|
8249
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}/capture`, {
|
|
8250
|
+
method: "POST",
|
|
8251
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8252
|
+
body: "{}"
|
|
8253
|
+
});
|
|
8254
|
+
return response.json();
|
|
8255
|
+
}
|
|
8256
|
+
/** Refund capture PayPal */
|
|
8257
|
+
async refundCapture(captureId, amount, currency) {
|
|
8258
|
+
const token = await this.getAccessToken();
|
|
8259
|
+
const body = {};
|
|
8260
|
+
if (amount && currency) {
|
|
8261
|
+
body.amount = { value: (amount / 100).toFixed(2), currency_code: currency };
|
|
8262
|
+
body.note_to_payer = "Refund";
|
|
8263
|
+
}
|
|
8264
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/captures/${captureId}/refund`, {
|
|
8265
|
+
method: "POST",
|
|
8266
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8267
|
+
body: JSON.stringify(body)
|
|
8268
|
+
});
|
|
8269
|
+
return response.json();
|
|
8270
|
+
}
|
|
8271
|
+
/** Cek saldo akun PayPal merchant (hanya tersedia di account via Seller REST API) */
|
|
8272
|
+
async checkBalance() {
|
|
8273
|
+
const token = await this.getAccessToken();
|
|
8274
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/reporting/balances`, {
|
|
8275
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8276
|
+
});
|
|
8277
|
+
return response.json();
|
|
8278
|
+
}
|
|
8279
|
+
/** Verifikasi webhook via PayPal Webhook Verification API */
|
|
8280
|
+
async verifyWebhookSignature(webhookId, body, headers) {
|
|
8281
|
+
const token = await this.getAccessToken();
|
|
8282
|
+
const verifyBody = {
|
|
8283
|
+
auth_algo: headers["paypal-auth-algo"],
|
|
8284
|
+
cert_url: headers["paypal-cert-url"],
|
|
8285
|
+
transmission_id: headers["paypal-transmission-id"],
|
|
8286
|
+
transmission_sig: headers["paypal-transmission-sig"],
|
|
8287
|
+
transmission_time: headers["paypal-transmission-time"],
|
|
8288
|
+
webhook_id: webhookId,
|
|
8289
|
+
webhook_event: typeof body === "string" ? JSON.parse(body) : body
|
|
8290
|
+
};
|
|
8291
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/notifications/verify-webhook-signature`, {
|
|
8292
|
+
method: "POST",
|
|
8293
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8294
|
+
body: JSON.stringify(verifyBody)
|
|
8295
|
+
});
|
|
8296
|
+
const data = await response.json();
|
|
8297
|
+
return data?.verification_status === "SUCCESS";
|
|
8298
|
+
}
|
|
8299
|
+
};
|
|
8300
|
+
|
|
8301
|
+
// src/clients/adyen.ts
|
|
8302
|
+
var AdyenClient = class {
|
|
8303
|
+
config;
|
|
8304
|
+
constructor(config) {
|
|
8305
|
+
this.config = config;
|
|
8306
|
+
}
|
|
8307
|
+
getBaseUrl() {
|
|
8308
|
+
if (this.config.sandbox === false) {
|
|
8309
|
+
const prefix = this.config.extra?.liveUrlPrefix || this.config.projectId || "";
|
|
8310
|
+
if (prefix) return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
8311
|
+
}
|
|
8312
|
+
return "https://checkout-test.adyen.com";
|
|
8313
|
+
}
|
|
8314
|
+
buildHeaders() {
|
|
8315
|
+
return {
|
|
8316
|
+
"X-API-Key": this.config.apiKey || this.config.secretKey || "",
|
|
8317
|
+
"Content-Type": "application/json"
|
|
8318
|
+
};
|
|
8319
|
+
}
|
|
8320
|
+
/** Ambil detail payment berdasarkan PSP Reference */
|
|
8321
|
+
async getPaymentDetails(pspReference) {
|
|
8322
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}`, {
|
|
8323
|
+
method: "GET",
|
|
8324
|
+
headers: this.buildHeaders()
|
|
8325
|
+
});
|
|
8326
|
+
return response.json();
|
|
8327
|
+
}
|
|
8328
|
+
/** Batalkan payment (sebelum capture) */
|
|
8329
|
+
async cancelPayment(pspReference, merchantAccount) {
|
|
8330
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8331
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/cancels`, {
|
|
8332
|
+
method: "POST",
|
|
8333
|
+
headers: this.buildHeaders(),
|
|
8334
|
+
body: JSON.stringify({ merchantAccount: account })
|
|
8335
|
+
});
|
|
8336
|
+
return response.json();
|
|
8337
|
+
}
|
|
8338
|
+
/** Refund payment yang sudah di-capture */
|
|
8339
|
+
async refundPayment(pspReference, amount, currency, merchantAccount) {
|
|
8340
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8341
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/refunds`, {
|
|
8342
|
+
method: "POST",
|
|
8343
|
+
headers: this.buildHeaders(),
|
|
8344
|
+
body: JSON.stringify({
|
|
8345
|
+
merchantAccount: account,
|
|
8346
|
+
amount: { value: amount, currency }
|
|
8347
|
+
})
|
|
8348
|
+
});
|
|
8349
|
+
return response.json();
|
|
8350
|
+
}
|
|
8351
|
+
/** Capture authorized payment */
|
|
8352
|
+
async capturePayment(pspReference, amount, currency, merchantAccount) {
|
|
8353
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8354
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/captures`, {
|
|
8355
|
+
method: "POST",
|
|
8356
|
+
headers: this.buildHeaders(),
|
|
8357
|
+
body: JSON.stringify({
|
|
8358
|
+
merchantAccount: account,
|
|
8359
|
+
amount: { value: amount, currency }
|
|
8360
|
+
})
|
|
8361
|
+
});
|
|
8362
|
+
return response.json();
|
|
8363
|
+
}
|
|
8364
|
+
/** Ambil daftar payment methods yang tersedia */
|
|
8365
|
+
async getAvailablePaymentMethods(merchantAccount, countryCode, currency, amount) {
|
|
8366
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/paymentMethods`, {
|
|
8367
|
+
method: "POST",
|
|
8368
|
+
headers: this.buildHeaders(),
|
|
8369
|
+
body: JSON.stringify({ merchantAccount, countryCode, channel: "Web", amount: { value: amount, currency } })
|
|
8370
|
+
});
|
|
8371
|
+
return response.json();
|
|
8372
|
+
}
|
|
8373
|
+
};
|
|
8374
|
+
|
|
8375
|
+
// src/clients/checkoutcom.ts
|
|
8376
|
+
var CheckoutComClient = class {
|
|
8377
|
+
config;
|
|
8378
|
+
constructor(config) {
|
|
8379
|
+
this.config = config;
|
|
8380
|
+
}
|
|
8381
|
+
getBaseUrl() {
|
|
8382
|
+
return this.config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
8383
|
+
}
|
|
8384
|
+
buildHeaders() {
|
|
8385
|
+
return {
|
|
8386
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8387
|
+
"Content-Type": "application/json"
|
|
8388
|
+
};
|
|
8389
|
+
}
|
|
8390
|
+
/** Ambil detail payment berdasarkan Payment ID */
|
|
8391
|
+
async getPaymentDetails(paymentId) {
|
|
8392
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8393
|
+
method: "GET",
|
|
8394
|
+
headers: this.buildHeaders()
|
|
8395
|
+
});
|
|
8396
|
+
return response.json();
|
|
8397
|
+
}
|
|
8398
|
+
/** Void (batalkan) payment yang belum di-capture */
|
|
8399
|
+
async voidPayment(paymentId, reference) {
|
|
8400
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/voids`, {
|
|
8401
|
+
method: "POST",
|
|
8402
|
+
headers: this.buildHeaders(),
|
|
8403
|
+
body: JSON.stringify({ reference })
|
|
8404
|
+
});
|
|
8405
|
+
return response.json();
|
|
8406
|
+
}
|
|
8407
|
+
/** Refund payment yang sudah di-capture */
|
|
8408
|
+
async refundPayment(paymentId, amount, reference) {
|
|
8409
|
+
const body = { reference };
|
|
8410
|
+
if (amount) body.amount = amount;
|
|
8411
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refunds`, {
|
|
8412
|
+
method: "POST",
|
|
8413
|
+
headers: this.buildHeaders(),
|
|
8414
|
+
body: JSON.stringify(body)
|
|
8415
|
+
});
|
|
8416
|
+
return response.json();
|
|
8417
|
+
}
|
|
8418
|
+
/** Cek saldo merchant di Checkout.com */
|
|
8419
|
+
async checkBalance() {
|
|
8420
|
+
const response = await fetch(`${this.getBaseUrl()}/balances`, {
|
|
8421
|
+
method: "GET",
|
|
8422
|
+
headers: this.buildHeaders()
|
|
8423
|
+
});
|
|
8424
|
+
return response.json();
|
|
8425
|
+
}
|
|
8426
|
+
/** Ambil daftar payment links */
|
|
8427
|
+
async listPaymentLinks() {
|
|
8428
|
+
const response = await fetch(`${this.getBaseUrl()}/payment-links`, {
|
|
8429
|
+
method: "GET",
|
|
8430
|
+
headers: this.buildHeaders()
|
|
8431
|
+
});
|
|
8432
|
+
return response.json();
|
|
8433
|
+
}
|
|
8434
|
+
};
|
|
8435
|
+
|
|
8436
|
+
// src/clients/razorpay.ts
|
|
8437
|
+
var RazorpayClient = class {
|
|
8438
|
+
config;
|
|
8439
|
+
constructor(config) {
|
|
8440
|
+
this.config = config;
|
|
8441
|
+
}
|
|
8442
|
+
getBaseUrl() {
|
|
8443
|
+
return "https://api.razorpay.com/v1";
|
|
8444
|
+
}
|
|
8445
|
+
buildHeaders() {
|
|
8446
|
+
const keyId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8447
|
+
const keySecret = this.config.apiKey || this.config.secretKey || "";
|
|
8448
|
+
return {
|
|
8449
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
8450
|
+
"Content-Type": "application/json"
|
|
8451
|
+
};
|
|
8452
|
+
}
|
|
8453
|
+
/** Ambil detail payment */
|
|
8454
|
+
async fetchPayment(paymentId) {
|
|
8455
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8456
|
+
method: "GET",
|
|
8457
|
+
headers: this.buildHeaders()
|
|
8458
|
+
});
|
|
8459
|
+
return response.json();
|
|
8460
|
+
}
|
|
8461
|
+
/** Capture authorized payment */
|
|
8462
|
+
async capturePayment(paymentId, amount, currency) {
|
|
8463
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/capture`, {
|
|
8464
|
+
method: "POST",
|
|
8465
|
+
headers: this.buildHeaders(),
|
|
8466
|
+
body: JSON.stringify({ amount, currency: currency || "INR" })
|
|
8467
|
+
});
|
|
8468
|
+
return response.json();
|
|
8469
|
+
}
|
|
8470
|
+
/** Buat refund untuk payment */
|
|
8471
|
+
async createRefund(paymentId, amount, notes) {
|
|
8472
|
+
const body = { notes };
|
|
8473
|
+
if (amount) body.amount = amount;
|
|
8474
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refund`, {
|
|
8475
|
+
method: "POST",
|
|
8476
|
+
headers: this.buildHeaders(),
|
|
8477
|
+
body: JSON.stringify(body)
|
|
8478
|
+
});
|
|
8479
|
+
return response.json();
|
|
8480
|
+
}
|
|
8481
|
+
/** Cek saldo akun Razorpay */
|
|
8482
|
+
async checkBalance() {
|
|
8483
|
+
const response = await fetch(`${this.getBaseUrl()}/balance`, {
|
|
8484
|
+
method: "GET",
|
|
8485
|
+
headers: this.buildHeaders()
|
|
8486
|
+
});
|
|
8487
|
+
return response.json();
|
|
8488
|
+
}
|
|
8489
|
+
/** Ambil daftar semua payment */
|
|
8490
|
+
async listPayments(from, to, count) {
|
|
8491
|
+
const params = new URLSearchParams();
|
|
8492
|
+
if (from) params.set("from", from.toString());
|
|
8493
|
+
if (to) params.set("to", to.toString());
|
|
8494
|
+
if (count) params.set("count", count.toString());
|
|
8495
|
+
const response = await fetch(`${this.getBaseUrl()}/payments?${params}`, {
|
|
8496
|
+
method: "GET",
|
|
8497
|
+
headers: this.buildHeaders()
|
|
8498
|
+
});
|
|
8499
|
+
return response.json();
|
|
8500
|
+
}
|
|
8501
|
+
};
|
|
8502
|
+
|
|
8503
|
+
// src/clients/square.ts
|
|
8504
|
+
var SquareClient = class {
|
|
8505
|
+
config;
|
|
8506
|
+
constructor(config) {
|
|
8507
|
+
this.config = config;
|
|
8508
|
+
}
|
|
8509
|
+
getBaseUrl() {
|
|
8510
|
+
return this.config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
8511
|
+
}
|
|
8512
|
+
buildHeaders() {
|
|
8513
|
+
return {
|
|
8514
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8515
|
+
"Content-Type": "application/json",
|
|
8516
|
+
"Square-Version": "2024-01-17"
|
|
8517
|
+
};
|
|
8518
|
+
}
|
|
8519
|
+
/** Ambil detail payment Square */
|
|
8520
|
+
async getPayment(paymentId) {
|
|
8521
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}`, {
|
|
8522
|
+
method: "GET",
|
|
8523
|
+
headers: this.buildHeaders()
|
|
8524
|
+
});
|
|
8525
|
+
return response.json();
|
|
8526
|
+
}
|
|
8527
|
+
/** Batalkan payment Square */
|
|
8528
|
+
async cancelPayment(paymentId) {
|
|
8529
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}/cancel`, {
|
|
8530
|
+
method: "POST",
|
|
8531
|
+
headers: this.buildHeaders(),
|
|
8532
|
+
body: "{}"
|
|
8533
|
+
});
|
|
8534
|
+
return response.json();
|
|
8535
|
+
}
|
|
8536
|
+
/** Refund payment Square */
|
|
8537
|
+
async refundPayment(paymentId, amount, currency, idempotencyKey, reason) {
|
|
8538
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/refunds`, {
|
|
8539
|
+
method: "POST",
|
|
8540
|
+
headers: this.buildHeaders(),
|
|
8541
|
+
body: JSON.stringify({
|
|
8542
|
+
idempotency_key: idempotencyKey,
|
|
8543
|
+
payment_id: paymentId,
|
|
8544
|
+
amount_money: { amount, currency },
|
|
8545
|
+
reason
|
|
8546
|
+
})
|
|
8547
|
+
});
|
|
8548
|
+
return response.json();
|
|
8549
|
+
}
|
|
8550
|
+
/** Ambil saldo location Square */
|
|
8551
|
+
async retrieveBalance(locationId) {
|
|
8552
|
+
const id = locationId || this.config.extra?.locationId || this.config.projectId || "";
|
|
8553
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations/${id}`, {
|
|
8554
|
+
method: "GET",
|
|
8555
|
+
headers: this.buildHeaders()
|
|
8556
|
+
});
|
|
8557
|
+
return response.json();
|
|
8558
|
+
}
|
|
8559
|
+
/** List semua locations merchant */
|
|
8560
|
+
async listLocations() {
|
|
8561
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations`, {
|
|
8562
|
+
method: "GET",
|
|
8563
|
+
headers: this.buildHeaders()
|
|
8564
|
+
});
|
|
8565
|
+
return response.json();
|
|
8566
|
+
}
|
|
8567
|
+
};
|
|
8568
|
+
|
|
8569
|
+
// src/clients/payu.ts
|
|
8570
|
+
var PayuClient = class {
|
|
8571
|
+
config;
|
|
8572
|
+
accessToken = null;
|
|
8573
|
+
constructor(config) {
|
|
8574
|
+
this.config = config;
|
|
8575
|
+
}
|
|
8576
|
+
getBaseUrl() {
|
|
8577
|
+
return this.config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
8578
|
+
}
|
|
8579
|
+
async getToken() {
|
|
8580
|
+
if (this.accessToken) return this.accessToken;
|
|
8581
|
+
const clientId = this.config.extra?.oauthClientId || this.config.clientKey || "";
|
|
8582
|
+
const clientSecret = this.config.extra?.oauthClientSecret || this.config.apiKey || this.config.secretKey || "";
|
|
8583
|
+
const response = await fetch(`${this.getBaseUrl()}/pl/standard/user/oauth/authorize`, {
|
|
8584
|
+
method: "POST",
|
|
8585
|
+
headers: { "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8586
|
+
body: "grant_type=client_credentials"
|
|
8587
|
+
});
|
|
8588
|
+
const data = await response.json();
|
|
8589
|
+
if (!data?.access_token) throw new Error("Failed to get PayU access token");
|
|
8590
|
+
this.accessToken = data.access_token;
|
|
8591
|
+
return this.accessToken;
|
|
8592
|
+
}
|
|
8593
|
+
/** Ambil detail order PayU */
|
|
8594
|
+
async getOrder(orderId) {
|
|
8595
|
+
const token = await this.getToken();
|
|
8596
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8597
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8598
|
+
});
|
|
8599
|
+
return response.json();
|
|
8600
|
+
}
|
|
8601
|
+
/** Batalkan order PayU */
|
|
8602
|
+
async cancelOrder(orderId) {
|
|
8603
|
+
const token = await this.getToken();
|
|
8604
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8605
|
+
method: "DELETE",
|
|
8606
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8607
|
+
});
|
|
8608
|
+
return response.json();
|
|
8609
|
+
}
|
|
8610
|
+
/** Refund order PayU */
|
|
8611
|
+
async refundOrder(orderId, amount, description) {
|
|
8612
|
+
const token = await this.getToken();
|
|
8613
|
+
const body = { refund: { description: description || "Refund" } };
|
|
8614
|
+
if (amount) body.refund.amount = amount;
|
|
8615
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}/refunds`, {
|
|
8616
|
+
method: "POST",
|
|
8617
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8618
|
+
body: JSON.stringify(body)
|
|
8619
|
+
});
|
|
8620
|
+
return response.json();
|
|
8621
|
+
}
|
|
8622
|
+
};
|
|
8623
|
+
|
|
8624
|
+
// src/clients/braintree.ts
|
|
8625
|
+
var BraintreeClient = class {
|
|
8626
|
+
config;
|
|
8627
|
+
constructor(config) {
|
|
8628
|
+
this.config = config;
|
|
8629
|
+
}
|
|
8630
|
+
getBaseUrl() {
|
|
8631
|
+
const merchantId = this.config.merchantCode || this.config.merchantId || "";
|
|
8632
|
+
const base = this.config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
8633
|
+
return `${base}/merchants/${merchantId}`;
|
|
8634
|
+
}
|
|
8635
|
+
buildHeaders() {
|
|
8636
|
+
const publicKey = this.config.clientKey || this.config.extra?.publicKey || "";
|
|
8637
|
+
const privateKey = this.config.apiKey || this.config.secretKey || "";
|
|
8638
|
+
return {
|
|
8639
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
8640
|
+
"Content-Type": "application/json",
|
|
8641
|
+
"Braintree-Version": "2019-01-01"
|
|
8642
|
+
};
|
|
8643
|
+
}
|
|
8644
|
+
/** Generate Client Token untuk frontend Drop-in UI */
|
|
8645
|
+
async getClientToken(customerId) {
|
|
8646
|
+
const body = {};
|
|
8647
|
+
if (customerId) body.client_token = { customer_id: customerId };
|
|
8648
|
+
const response = await fetch(`${this.getBaseUrl()}/client_token`, {
|
|
8649
|
+
method: "POST",
|
|
8650
|
+
headers: this.buildHeaders(),
|
|
8651
|
+
body: JSON.stringify(body)
|
|
8652
|
+
});
|
|
8653
|
+
const data = await response.json();
|
|
8654
|
+
return data.clientToken || "";
|
|
8655
|
+
}
|
|
8656
|
+
/** Ambil detail transaction */
|
|
8657
|
+
async findTransaction(transactionId) {
|
|
8658
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}`, {
|
|
8659
|
+
method: "GET",
|
|
8660
|
+
headers: this.buildHeaders()
|
|
8661
|
+
});
|
|
8662
|
+
return response.json();
|
|
8663
|
+
}
|
|
8664
|
+
/** Refund transaction Braintree */
|
|
8665
|
+
async refundTransaction(transactionId, amount) {
|
|
8666
|
+
const body = {};
|
|
8667
|
+
if (amount) body.transaction = { amount: (amount / 100).toFixed(2) };
|
|
8668
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/refund`, {
|
|
8669
|
+
method: "POST",
|
|
8670
|
+
headers: this.buildHeaders(),
|
|
8671
|
+
body: JSON.stringify(body)
|
|
8672
|
+
});
|
|
8673
|
+
return response.json();
|
|
8674
|
+
}
|
|
8675
|
+
/** Void (batalkan) transaction sebelum settlement */
|
|
8676
|
+
async voidTransaction(transactionId) {
|
|
8677
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/void`, {
|
|
8678
|
+
method: "PUT",
|
|
8679
|
+
headers: this.buildHeaders(),
|
|
8680
|
+
body: "{}"
|
|
8681
|
+
});
|
|
8682
|
+
return response.json();
|
|
8683
|
+
}
|
|
8684
|
+
};
|
|
8685
|
+
|
|
8686
|
+
// src/clients/twocheckout.ts
|
|
8687
|
+
var TwoCheckoutClient = class {
|
|
8688
|
+
config;
|
|
8689
|
+
constructor(config) {
|
|
8690
|
+
this.config = config;
|
|
8691
|
+
}
|
|
8692
|
+
getBaseUrl() {
|
|
8693
|
+
return this.config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
8694
|
+
}
|
|
8695
|
+
buildHeaders() {
|
|
8696
|
+
const merchantCode = this.config.merchantCode || this.config.merchantId || "";
|
|
8697
|
+
const secretKey = this.config.apiKey || this.config.secretKey || "";
|
|
8698
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
8699
|
+
return {
|
|
8700
|
+
"X-Avangate-Authentication": header,
|
|
8701
|
+
"Content-Type": "application/json",
|
|
8702
|
+
"Accept": "application/json"
|
|
8703
|
+
};
|
|
8704
|
+
}
|
|
8705
|
+
/** Ambil detail order 2Checkout berdasarkan Reference Number */
|
|
8706
|
+
async getOrder(refNo) {
|
|
8707
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}`, {
|
|
8708
|
+
method: "GET",
|
|
8709
|
+
headers: this.buildHeaders()
|
|
8710
|
+
});
|
|
8711
|
+
return response.json();
|
|
8712
|
+
}
|
|
8713
|
+
/** Refund order 2Checkout */
|
|
8714
|
+
async refundOrder(refNo, amount, comment) {
|
|
8715
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}/refund`, {
|
|
8716
|
+
method: "POST",
|
|
8717
|
+
headers: this.buildHeaders(),
|
|
8718
|
+
body: JSON.stringify({ amount, comment: comment || "Refund", reason: "NOT_SATISFIED" })
|
|
8719
|
+
});
|
|
8720
|
+
return response.json();
|
|
8721
|
+
}
|
|
8722
|
+
/** Ambil detail subscription */
|
|
8723
|
+
async getSubscription(subscriptionRef) {
|
|
8724
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/subscriptions/${subscriptionRef}`, {
|
|
8725
|
+
method: "GET",
|
|
8726
|
+
headers: this.buildHeaders()
|
|
8727
|
+
});
|
|
8728
|
+
return response.json();
|
|
8729
|
+
}
|
|
8730
|
+
/** List semua orders merchant */
|
|
8731
|
+
async listOrders(page, limit) {
|
|
8732
|
+
const params = new URLSearchParams({
|
|
8733
|
+
Pagination: JSON.stringify({ Page: page || 1, Limit: limit || 10 })
|
|
8734
|
+
});
|
|
8735
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders?${params}`, {
|
|
8736
|
+
method: "GET",
|
|
8737
|
+
headers: this.buildHeaders()
|
|
8738
|
+
});
|
|
8739
|
+
return response.json();
|
|
8740
|
+
}
|
|
8741
|
+
};
|
|
8742
|
+
|
|
6155
8743
|
// src/core/manager.ts
|
|
6156
8744
|
var PaymentManager = class {
|
|
6157
8745
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -6167,6 +8755,14 @@ var PaymentManager = class {
|
|
|
6167
8755
|
this.registerProvider(new NicepayProvider());
|
|
6168
8756
|
this.registerProvider(new OyProvider());
|
|
6169
8757
|
this.registerProvider(new StripeProvider());
|
|
8758
|
+
this.registerProvider(new PaypalProvider());
|
|
8759
|
+
this.registerProvider(new AdyenProvider());
|
|
8760
|
+
this.registerProvider(new CheckoutComProvider());
|
|
8761
|
+
this.registerProvider(new RazorpayProvider());
|
|
8762
|
+
this.registerProvider(new SquareProvider());
|
|
8763
|
+
this.registerProvider(new PayuProvider());
|
|
8764
|
+
this.registerProvider(new BraintreeProvider());
|
|
8765
|
+
this.registerProvider(new TwoCheckoutProvider());
|
|
6170
8766
|
}
|
|
6171
8767
|
registerProvider(provider) {
|
|
6172
8768
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -6178,6 +8774,7 @@ var PaymentManager = class {
|
|
|
6178
8774
|
}
|
|
6179
8775
|
return provider;
|
|
6180
8776
|
}
|
|
8777
|
+
// ─── Indonesian Provider Getters ──────────────────────────────────────────
|
|
6181
8778
|
getMidtransProvider() {
|
|
6182
8779
|
return this.getProvider("midtrans");
|
|
6183
8780
|
}
|
|
@@ -6238,12 +8835,62 @@ var PaymentManager = class {
|
|
|
6238
8835
|
getOyClient(config) {
|
|
6239
8836
|
return new OyClient(config);
|
|
6240
8837
|
}
|
|
8838
|
+
// ─── International Provider Getters ─────────────────────────────────────
|
|
6241
8839
|
getStripeProvider() {
|
|
6242
8840
|
return this.getProvider("stripe");
|
|
6243
8841
|
}
|
|
6244
8842
|
getStripeClient(config) {
|
|
6245
8843
|
return new StripeClient(config);
|
|
6246
8844
|
}
|
|
8845
|
+
getPaypalProvider() {
|
|
8846
|
+
return this.getProvider("paypal");
|
|
8847
|
+
}
|
|
8848
|
+
getPaypalClient(config) {
|
|
8849
|
+
return new PaypalClient(config);
|
|
8850
|
+
}
|
|
8851
|
+
getAdyenProvider() {
|
|
8852
|
+
return this.getProvider("adyen");
|
|
8853
|
+
}
|
|
8854
|
+
getAdyenClient(config) {
|
|
8855
|
+
return new AdyenClient(config);
|
|
8856
|
+
}
|
|
8857
|
+
getCheckoutComProvider() {
|
|
8858
|
+
return this.getProvider("checkoutcom");
|
|
8859
|
+
}
|
|
8860
|
+
getCheckoutComClient(config) {
|
|
8861
|
+
return new CheckoutComClient(config);
|
|
8862
|
+
}
|
|
8863
|
+
getRazorpayProvider() {
|
|
8864
|
+
return this.getProvider("razorpay");
|
|
8865
|
+
}
|
|
8866
|
+
getRazorpayClient(config) {
|
|
8867
|
+
return new RazorpayClient(config);
|
|
8868
|
+
}
|
|
8869
|
+
getSquareProvider() {
|
|
8870
|
+
return this.getProvider("square");
|
|
8871
|
+
}
|
|
8872
|
+
getSquareClient(config) {
|
|
8873
|
+
return new SquareClient(config);
|
|
8874
|
+
}
|
|
8875
|
+
getPayuProvider() {
|
|
8876
|
+
return this.getProvider("payu");
|
|
8877
|
+
}
|
|
8878
|
+
getPayuClient(config) {
|
|
8879
|
+
return new PayuClient(config);
|
|
8880
|
+
}
|
|
8881
|
+
getBraintreeProvider() {
|
|
8882
|
+
return this.getProvider("braintree");
|
|
8883
|
+
}
|
|
8884
|
+
getBraintreeClient(config) {
|
|
8885
|
+
return new BraintreeClient(config);
|
|
8886
|
+
}
|
|
8887
|
+
getTwoCheckoutProvider() {
|
|
8888
|
+
return this.getProvider("twocheckout");
|
|
8889
|
+
}
|
|
8890
|
+
getTwoCheckoutClient(config) {
|
|
8891
|
+
return new TwoCheckoutClient(config);
|
|
8892
|
+
}
|
|
8893
|
+
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
6247
8894
|
async createInvoice(providerName, params, config) {
|
|
6248
8895
|
const provider = this.getProvider(providerName);
|
|
6249
8896
|
return provider.createInvoice(params, config);
|
|
@@ -6303,6 +8950,22 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6303
8950
|
sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
|
|
6304
8951
|
} else if (env.STRIPE_SANDBOX !== void 0) {
|
|
6305
8952
|
sandbox = env.STRIPE_SANDBOX === "true" || env.STRIPE_SANDBOX === "1";
|
|
8953
|
+
} else if (env.PAYPAL_SANDBOX !== void 0) {
|
|
8954
|
+
sandbox = env.PAYPAL_SANDBOX === "true" || env.PAYPAL_SANDBOX === "1";
|
|
8955
|
+
} else if (env.ADYEN_SANDBOX !== void 0) {
|
|
8956
|
+
sandbox = env.ADYEN_SANDBOX === "true" || env.ADYEN_SANDBOX === "1";
|
|
8957
|
+
} else if (env.CHECKOUTCOM_SANDBOX !== void 0) {
|
|
8958
|
+
sandbox = env.CHECKOUTCOM_SANDBOX === "true" || env.CHECKOUTCOM_SANDBOX === "1";
|
|
8959
|
+
} else if (env.RAZORPAY_SANDBOX !== void 0) {
|
|
8960
|
+
sandbox = env.RAZORPAY_SANDBOX === "true" || env.RAZORPAY_SANDBOX === "1";
|
|
8961
|
+
} else if (env.SQUARE_SANDBOX !== void 0) {
|
|
8962
|
+
sandbox = env.SQUARE_SANDBOX === "true" || env.SQUARE_SANDBOX === "1";
|
|
8963
|
+
} else if (env.PAYU_SANDBOX !== void 0) {
|
|
8964
|
+
sandbox = env.PAYU_SANDBOX === "true" || env.PAYU_SANDBOX === "1";
|
|
8965
|
+
} else if (env.BRAINTREE_SANDBOX !== void 0) {
|
|
8966
|
+
sandbox = env.BRAINTREE_SANDBOX === "true" || env.BRAINTREE_SANDBOX === "1";
|
|
8967
|
+
} else if (env.TWOCHECKOUT_SANDBOX !== void 0) {
|
|
8968
|
+
sandbox = env.TWOCHECKOUT_SANDBOX === "true" || env.TWOCHECKOUT_SANDBOX === "1";
|
|
6306
8969
|
} else {
|
|
6307
8970
|
sandbox = env.NODE_ENV !== "production";
|
|
6308
8971
|
}
|
|
@@ -6330,6 +8993,22 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6330
8993
|
apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
6331
8994
|
} else if (provider === "stripe") {
|
|
6332
8995
|
apiKey = env.STRIPE_SECRET_KEY || env.STRIPE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8996
|
+
} else if (provider === "paypal") {
|
|
8997
|
+
apiKey = env.PAYPAL_CLIENT_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8998
|
+
} else if (provider === "adyen") {
|
|
8999
|
+
apiKey = env.ADYEN_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9000
|
+
} else if (provider === "checkoutcom") {
|
|
9001
|
+
apiKey = env.CHECKOUTCOM_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9002
|
+
} else if (provider === "razorpay") {
|
|
9003
|
+
apiKey = env.RAZORPAY_KEY_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9004
|
+
} else if (provider === "square") {
|
|
9005
|
+
apiKey = env.SQUARE_ACCESS_TOKEN || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9006
|
+
} else if (provider === "payu") {
|
|
9007
|
+
apiKey = env.PAYU_MD5_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9008
|
+
} else if (provider === "braintree") {
|
|
9009
|
+
apiKey = env.BRAINTREE_PRIVATE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
9010
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
9011
|
+
apiKey = env.TWOCHECKOUT_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
6333
9012
|
} else {
|
|
6334
9013
|
apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
|
|
6335
9014
|
}
|
|
@@ -6347,7 +9026,7 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6347
9026
|
merchantCode = merchantCode || env.IPAYMU_VA || env.IPAYMU_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6348
9027
|
} else if (provider === "doku") {
|
|
6349
9028
|
merchantCode = merchantCode || env.DOKU_CLIENT_ID || env.DOKU_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6350
|
-
clientKey = clientKey || env.DOKU_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
|
|
9029
|
+
clientKey = clientKey || customConfig?.merchantCode || env.DOKU_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
|
|
6351
9030
|
} else if (provider === "prismalink") {
|
|
6352
9031
|
merchantCode = merchantCode || env.PRISMALINK_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6353
9032
|
merchantId = merchantId || env.PRISMALINK_MERCHANT_ID || env.BUAYAR_MERCHANT_ID;
|
|
@@ -6363,30 +9042,67 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6363
9042
|
merchantId = merchantId || env.NICEPAY_IMID || env.BUAYAR_MERCHANT_ID;
|
|
6364
9043
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
6365
9044
|
merchantCode = merchantCode || env.OY_USERNAME || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6366
|
-
clientKey = clientKey || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
|
|
9045
|
+
clientKey = clientKey || customConfig?.merchantCode || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
|
|
6367
9046
|
} else if (provider === "stripe") {
|
|
6368
9047
|
clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
|
|
6369
9048
|
merchantCode = merchantCode || clientKey || "stripe";
|
|
9049
|
+
} else if (provider === "paypal") {
|
|
9050
|
+
clientKey = clientKey || env.PAYPAL_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
|
|
9051
|
+
merchantCode = merchantCode || env.PAYPAL_CLIENT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9052
|
+
} else if (provider === "adyen") {
|
|
9053
|
+
clientKey = clientKey || env.ADYEN_CLIENT_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9054
|
+
merchantCode = merchantCode || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_CODE;
|
|
9055
|
+
merchantId = merchantId || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_ID;
|
|
9056
|
+
} else if (provider === "checkoutcom") {
|
|
9057
|
+
clientKey = clientKey || env.CHECKOUTCOM_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9058
|
+
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE;
|
|
9059
|
+
} else if (provider === "razorpay") {
|
|
9060
|
+
clientKey = clientKey || env.RAZORPAY_KEY_ID || env.BUAYAR_CLIENT_KEY;
|
|
9061
|
+
merchantCode = merchantCode || env.RAZORPAY_KEY_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9062
|
+
} else if (provider === "square") {
|
|
9063
|
+
clientKey = clientKey || env.SQUARE_APPLICATION_ID || env.BUAYAR_CLIENT_KEY;
|
|
9064
|
+
merchantCode = merchantCode || env.SQUARE_APPLICATION_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9065
|
+
} else if (provider === "payu") {
|
|
9066
|
+
merchantCode = merchantCode || env.PAYU_POS_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9067
|
+
merchantId = merchantId || env.PAYU_POS_ID;
|
|
9068
|
+
} else if (provider === "braintree") {
|
|
9069
|
+
clientKey = clientKey || env.BRAINTREE_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9070
|
+
merchantCode = merchantCode || env.BRAINTREE_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9071
|
+
merchantId = merchantId || env.BRAINTREE_MERCHANT_ID;
|
|
9072
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
9073
|
+
merchantCode = merchantCode || env.TWOCHECKOUT_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE;
|
|
9074
|
+
merchantId = merchantId || env.TWOCHECKOUT_MERCHANT_CODE;
|
|
6370
9075
|
} else {
|
|
6371
9076
|
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6372
9077
|
}
|
|
6373
|
-
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID;
|
|
6374
|
-
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY;
|
|
6375
|
-
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY;
|
|
6376
|
-
const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY;
|
|
9078
|
+
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID || env.SQUARE_LOCATION_ID;
|
|
9079
|
+
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.CHECKOUTCOM_PUBLIC_KEY;
|
|
9080
|
+
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY || env.BRAINTREE_PRIVATE_KEY;
|
|
9081
|
+
const secretKey = customConfig?.secretKey || customConfig?.apiKey || customConfig?.serverKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY || env.PAYPAL_CLIENT_SECRET || env.CHECKOUTCOM_SECRET_KEY || env.RAZORPAY_KEY_SECRET || env.SQUARE_ACCESS_TOKEN || env.BRAINTREE_PRIVATE_KEY || env.TWOCHECKOUT_SECRET_KEY;
|
|
6377
9082
|
const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
|
|
6378
9083
|
const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
|
|
6379
9084
|
const extra = {
|
|
6380
9085
|
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
6381
|
-
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
9086
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.RAZORPAY_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
6382
9087
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
6383
9088
|
userId: env.FASPAY_USER_ID,
|
|
6384
9089
|
iMid: env.NICEPAY_IMID,
|
|
6385
9090
|
username: env.OY_USERNAME,
|
|
9091
|
+
hmacKey: env.ADYEN_HMAC_KEY,
|
|
9092
|
+
liveUrlPrefix: env.ADYEN_LIVE_URL_PREFIX,
|
|
9093
|
+
webhookId: env.PAYPAL_WEBHOOK_ID,
|
|
9094
|
+
merchantAccount: env.ADYEN_MERCHANT_ACCOUNT,
|
|
9095
|
+
md5Key: env.PAYU_MD5_KEY,
|
|
9096
|
+
oauthClientId: env.PAYU_OAUTH_CLIENT_ID,
|
|
9097
|
+
oauthClientSecret: env.PAYU_OAUTH_CLIENT_SECRET,
|
|
9098
|
+
locationId: env.SQUARE_LOCATION_ID,
|
|
9099
|
+
webhookSignatureKey: env.SQUARE_WEBHOOK_SIGNATURE_KEY,
|
|
9100
|
+
publicKey: env.BRAINTREE_PUBLIC_KEY || env.ADYEN_CLIENT_KEY,
|
|
9101
|
+
secretWord: env.TWOCHECKOUT_SECRET_WORD,
|
|
6386
9102
|
...customConfig?.extra
|
|
6387
9103
|
};
|
|
6388
9104
|
return {
|
|
6389
|
-
provider: provider === "oyindonesia" ? "oy" : provider,
|
|
9105
|
+
provider: provider === "oyindonesia" ? "oy" : provider === "2checkout" ? "twocheckout" : provider,
|
|
6390
9106
|
apiKey: apiKey || "",
|
|
6391
9107
|
serverKey: apiKey || "",
|
|
6392
9108
|
secretKey: secretKey || apiKey || "",
|
|
@@ -6424,7 +9140,7 @@ var Buayar = class {
|
|
|
6424
9140
|
this.config = resolveConfigFromEnv({ ...this.config, ...config });
|
|
6425
9141
|
}
|
|
6426
9142
|
/**
|
|
6427
|
-
* Dapatkan nama provider aktif
|
|
9143
|
+
* Dapatkan nama provider aktif
|
|
6428
9144
|
*/
|
|
6429
9145
|
get provider() {
|
|
6430
9146
|
return this.config.provider || "midtrans";
|
|
@@ -6473,10 +9189,45 @@ var Buayar = class {
|
|
|
6473
9189
|
async verifyWebhook(payload, headers, configOverride) {
|
|
6474
9190
|
const mergedConfig = { ...this.config, ...configOverride };
|
|
6475
9191
|
if (headers) {
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
9192
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9193
|
+
mergedConfig.extra.headers = headers;
|
|
9194
|
+
const stripeSig = headers["stripe-signature"] || headers["Stripe-Signature"];
|
|
9195
|
+
if (stripeSig) {
|
|
9196
|
+
mergedConfig.extra.signatureHeader = Array.isArray(stripeSig) ? stripeSig[0] : stripeSig;
|
|
9197
|
+
}
|
|
9198
|
+
const ckoSig = headers["cko-signature"] || headers["Cko-Signature"];
|
|
9199
|
+
if (ckoSig) {
|
|
9200
|
+
mergedConfig.extra.signatureHeader = Array.isArray(ckoSig) ? ckoSig[0] : ckoSig;
|
|
9201
|
+
}
|
|
9202
|
+
const rzpSig = headers["x-razorpay-signature"] || headers["X-Razorpay-Signature"];
|
|
9203
|
+
if (rzpSig) {
|
|
9204
|
+
mergedConfig.extra.signatureHeader = Array.isArray(rzpSig) ? rzpSig[0] : rzpSig;
|
|
9205
|
+
}
|
|
9206
|
+
const squareSig = headers["x-square-hmacsha256-signature"] || headers["x-square-signature"];
|
|
9207
|
+
if (squareSig) {
|
|
9208
|
+
mergedConfig.extra.signatureHeader = Array.isArray(squareSig) ? squareSig[0] : squareSig;
|
|
9209
|
+
}
|
|
9210
|
+
const payuSig = headers["openpayu-signature"] || headers["OpenPayU-Signature"];
|
|
9211
|
+
if (payuSig) {
|
|
9212
|
+
mergedConfig.extra.signatureHeader = Array.isArray(payuSig) ? payuSig[0] : payuSig;
|
|
9213
|
+
}
|
|
9214
|
+
const btSig = headers["bt_signature"];
|
|
9215
|
+
const btPayload = headers["bt_payload"];
|
|
9216
|
+
if (btSig && btPayload) {
|
|
9217
|
+
mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
|
|
9218
|
+
mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
|
|
9219
|
+
}
|
|
9220
|
+
const xenditToken = headers["x-callback-token"] || headers["X-Callback-Token"];
|
|
9221
|
+
if (xenditToken) {
|
|
9222
|
+
mergedConfig.extra.callbackToken = Array.isArray(xenditToken) ? xenditToken[0] : xenditToken;
|
|
9223
|
+
}
|
|
9224
|
+
const dokuSig = headers["signature"] || headers["Signature"];
|
|
9225
|
+
if (dokuSig) {
|
|
9226
|
+
mergedConfig.extra.dokuSignature = Array.isArray(dokuSig) ? dokuSig[0] : dokuSig;
|
|
9227
|
+
}
|
|
9228
|
+
const oyUser = headers["x-oy-username"] || headers["X-Oy-Username"];
|
|
9229
|
+
if (oyUser) {
|
|
9230
|
+
mergedConfig.extra.oyUsername = Array.isArray(oyUser) ? oyUser[0] : oyUser;
|
|
6480
9231
|
}
|
|
6481
9232
|
}
|
|
6482
9233
|
let providerName = configOverride?.provider || this.provider;
|
|
@@ -6501,8 +9252,24 @@ var Buayar = class {
|
|
|
6501
9252
|
providerName = "prismalink";
|
|
6502
9253
|
} else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
|
|
6503
9254
|
providerName = "stripe";
|
|
9255
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9256
|
+
providerName = "razorpay";
|
|
6504
9257
|
} else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
|
|
6505
9258
|
providerName = "xendit";
|
|
9259
|
+
} else if (payload.event_type && payload.resource && (payload.event_type.startsWith("PAYMENT.") || payload.event_type.startsWith("CHECKOUT.ORDER."))) {
|
|
9260
|
+
providerName = "paypal";
|
|
9261
|
+
} else if (payload.notificationItems || payload.merchantAccountCode && payload.pspReference && payload.eventCode) {
|
|
9262
|
+
providerName = "adyen";
|
|
9263
|
+
} else if (payload.type && payload.data?._links && (payload.type.startsWith("payment_") || payload.type.startsWith("refund_"))) {
|
|
9264
|
+
providerName = "checkoutcom";
|
|
9265
|
+
} else if (payload.type && payload.data?.object?.status && payload.merchant_id) {
|
|
9266
|
+
providerName = "square";
|
|
9267
|
+
} else if (payload.order && payload.order?.status && payload.order?.extOrderId) {
|
|
9268
|
+
providerName = "payu";
|
|
9269
|
+
} else if (payload.kind && payload.subject?.transaction) {
|
|
9270
|
+
providerName = "braintree";
|
|
9271
|
+
} else if (payload.HASH && payload.REFNOEXT && payload.IPN_PID) {
|
|
9272
|
+
providerName = "twocheckout";
|
|
6506
9273
|
}
|
|
6507
9274
|
}
|
|
6508
9275
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
@@ -6510,77 +9277,74 @@ var Buayar = class {
|
|
|
6510
9277
|
async handleWebhook(payload, headers, configOverride) {
|
|
6511
9278
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
6512
9279
|
}
|
|
9280
|
+
// ─── Indonesian Provider Client Getters ───────────────────────────────────
|
|
6513
9281
|
getMidtransClient(configOverride) {
|
|
6514
|
-
return new MidtransClient({
|
|
6515
|
-
...this.config,
|
|
6516
|
-
...configOverride
|
|
6517
|
-
});
|
|
9282
|
+
return new MidtransClient({ ...this.config, ...configOverride });
|
|
6518
9283
|
}
|
|
6519
9284
|
getDuitkuClient(configOverride) {
|
|
6520
|
-
return new DuitkuClient({
|
|
6521
|
-
...this.config,
|
|
6522
|
-
...configOverride
|
|
6523
|
-
});
|
|
9285
|
+
return new DuitkuClient({ ...this.config, ...configOverride });
|
|
6524
9286
|
}
|
|
6525
9287
|
getIpaymuClient(configOverride) {
|
|
6526
|
-
return new IpaymuClient({
|
|
6527
|
-
...this.config,
|
|
6528
|
-
...configOverride
|
|
6529
|
-
});
|
|
9288
|
+
return new IpaymuClient({ ...this.config, ...configOverride });
|
|
6530
9289
|
}
|
|
6531
9290
|
getXenditClient(configOverride) {
|
|
6532
|
-
return new XenditClient({
|
|
6533
|
-
...this.config,
|
|
6534
|
-
...configOverride
|
|
6535
|
-
});
|
|
9291
|
+
return new XenditClient({ ...this.config, ...configOverride });
|
|
6536
9292
|
}
|
|
6537
9293
|
getDokuClient(configOverride) {
|
|
6538
|
-
return new DokuClient({
|
|
6539
|
-
...this.config,
|
|
6540
|
-
...configOverride
|
|
6541
|
-
});
|
|
9294
|
+
return new DokuClient({ ...this.config, ...configOverride });
|
|
6542
9295
|
}
|
|
6543
9296
|
getPrismalinkClient(configOverride) {
|
|
6544
|
-
return new PrismalinkClient({
|
|
6545
|
-
...this.config,
|
|
6546
|
-
...configOverride
|
|
6547
|
-
});
|
|
9297
|
+
return new PrismalinkClient({ ...this.config, ...configOverride });
|
|
6548
9298
|
}
|
|
6549
9299
|
getFaspayClient(configOverride) {
|
|
6550
|
-
return new FaspayClient({
|
|
6551
|
-
...this.config,
|
|
6552
|
-
...configOverride
|
|
6553
|
-
});
|
|
9300
|
+
return new FaspayClient({ ...this.config, ...configOverride });
|
|
6554
9301
|
}
|
|
6555
9302
|
getFinpayClient(configOverride) {
|
|
6556
|
-
return new FinpayClient({
|
|
6557
|
-
...this.config,
|
|
6558
|
-
...configOverride
|
|
6559
|
-
});
|
|
9303
|
+
return new FinpayClient({ ...this.config, ...configOverride });
|
|
6560
9304
|
}
|
|
6561
9305
|
getNicepayClient(configOverride) {
|
|
6562
|
-
return new NicepayClient({
|
|
6563
|
-
...this.config,
|
|
6564
|
-
...configOverride
|
|
6565
|
-
});
|
|
9306
|
+
return new NicepayClient({ ...this.config, ...configOverride });
|
|
6566
9307
|
}
|
|
6567
9308
|
getOyClient(configOverride) {
|
|
6568
|
-
return new OyClient({
|
|
6569
|
-
...this.config,
|
|
6570
|
-
...configOverride
|
|
6571
|
-
});
|
|
9309
|
+
return new OyClient({ ...this.config, ...configOverride });
|
|
6572
9310
|
}
|
|
9311
|
+
// ─── International Provider Client Getters ────────────────────────────────
|
|
6573
9312
|
getStripeClient(configOverride) {
|
|
6574
|
-
return new StripeClient({
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
});
|
|
9313
|
+
return new StripeClient({ ...this.config, ...configOverride });
|
|
9314
|
+
}
|
|
9315
|
+
getPaypalClient(configOverride) {
|
|
9316
|
+
return new PaypalClient({ ...this.config, ...configOverride });
|
|
9317
|
+
}
|
|
9318
|
+
getAdyenClient(configOverride) {
|
|
9319
|
+
return new AdyenClient({ ...this.config, ...configOverride });
|
|
9320
|
+
}
|
|
9321
|
+
getCheckoutComClient(configOverride) {
|
|
9322
|
+
return new CheckoutComClient({ ...this.config, ...configOverride });
|
|
9323
|
+
}
|
|
9324
|
+
getRazorpayClient(configOverride) {
|
|
9325
|
+
return new RazorpayClient({ ...this.config, ...configOverride });
|
|
9326
|
+
}
|
|
9327
|
+
getSquareClient(configOverride) {
|
|
9328
|
+
return new SquareClient({ ...this.config, ...configOverride });
|
|
9329
|
+
}
|
|
9330
|
+
getPayuClient(configOverride) {
|
|
9331
|
+
return new PayuClient({ ...this.config, ...configOverride });
|
|
9332
|
+
}
|
|
9333
|
+
getBraintreeClient(configOverride) {
|
|
9334
|
+
return new BraintreeClient({ ...this.config, ...configOverride });
|
|
9335
|
+
}
|
|
9336
|
+
getTwoCheckoutClient(configOverride) {
|
|
9337
|
+
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
6578
9338
|
}
|
|
6579
9339
|
};
|
|
6580
9340
|
var buayar = new Buayar();
|
|
6581
9341
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6582
9342
|
0 && (module.exports = {
|
|
9343
|
+
AdyenClient,
|
|
9344
|
+
AdyenProvider,
|
|
6583
9345
|
BasePaymentProvider,
|
|
9346
|
+
BraintreeClient,
|
|
9347
|
+
BraintreeProvider,
|
|
6584
9348
|
Buayar,
|
|
6585
9349
|
CANONICAL_TO_DOKU,
|
|
6586
9350
|
CANONICAL_TO_DUITKU,
|
|
@@ -6594,6 +9358,8 @@ var buayar = new Buayar();
|
|
|
6594
9358
|
CANONICAL_TO_STRIPE,
|
|
6595
9359
|
CANONICAL_TO_XENDIT,
|
|
6596
9360
|
CORE_API_METHODS,
|
|
9361
|
+
CheckoutComClient,
|
|
9362
|
+
CheckoutComProvider,
|
|
6597
9363
|
DUITKU_TO_CANONICAL,
|
|
6598
9364
|
DokuClient,
|
|
6599
9365
|
DokuProvider,
|
|
@@ -6614,14 +9380,29 @@ var buayar = new Buayar();
|
|
|
6614
9380
|
OyClient,
|
|
6615
9381
|
OyProvider,
|
|
6616
9382
|
PaymentManager,
|
|
9383
|
+
PaypalClient,
|
|
9384
|
+
PaypalProvider,
|
|
9385
|
+
PayuClient,
|
|
9386
|
+
PayuProvider,
|
|
6617
9387
|
PrismalinkClient,
|
|
6618
9388
|
PrismalinkProvider,
|
|
9389
|
+
RazorpayClient,
|
|
9390
|
+
RazorpayProvider,
|
|
9391
|
+
SquareClient,
|
|
9392
|
+
SquareProvider,
|
|
6619
9393
|
StripeClient,
|
|
6620
9394
|
StripeProvider,
|
|
9395
|
+
TwoCheckoutClient,
|
|
9396
|
+
TwoCheckoutProvider,
|
|
6621
9397
|
XenditClient,
|
|
6622
9398
|
XenditProvider,
|
|
6623
9399
|
buayar,
|
|
9400
|
+
buildBraintreeBasicAuth,
|
|
6624
9401
|
buildCoreChargePayload,
|
|
9402
|
+
buildPaypalBasicAuth,
|
|
9403
|
+
buildPayuBasicAuth,
|
|
9404
|
+
buildRazorpayBasicAuth,
|
|
9405
|
+
buildTwoCheckoutAuth,
|
|
6625
9406
|
formatNicepayTimestamp,
|
|
6626
9407
|
generateDokuHeaders,
|
|
6627
9408
|
generateFaspaySignature,
|
|
@@ -6641,6 +9422,7 @@ var buayar = new Buayar();
|
|
|
6641
9422
|
paymentManager,
|
|
6642
9423
|
resolveConfigFromEnv,
|
|
6643
9424
|
safeCompare,
|
|
9425
|
+
serializePaypalParams,
|
|
6644
9426
|
serializeStripeParams,
|
|
6645
9427
|
sha256,
|
|
6646
9428
|
sha512,
|
|
@@ -6655,6 +9437,9 @@ var buayar = new Buayar();
|
|
|
6655
9437
|
toPrismalinkPaymentMethod,
|
|
6656
9438
|
toStripePaymentMethod,
|
|
6657
9439
|
toXenditPaymentMethod,
|
|
9440
|
+
verifyAdyenWebhook,
|
|
9441
|
+
verifyBraintreeWebhook,
|
|
9442
|
+
verifyCheckoutComWebhook,
|
|
6658
9443
|
verifyDokuWebhookSignature,
|
|
6659
9444
|
verifyDuitkuCallbackSignature,
|
|
6660
9445
|
verifyFaspaySignature,
|
|
@@ -6662,7 +9447,12 @@ var buayar = new Buayar();
|
|
|
6662
9447
|
verifyIpaymuCallback,
|
|
6663
9448
|
verifyNicepayWebhook,
|
|
6664
9449
|
verifyOyWebhook,
|
|
9450
|
+
verifyPaypalWebhookSimple,
|
|
9451
|
+
verifyPayuWebhook,
|
|
6665
9452
|
verifyPrismalinkSignature,
|
|
9453
|
+
verifyRazorpayWebhook,
|
|
9454
|
+
verifySquareWebhook,
|
|
6666
9455
|
verifyStripeWebhook,
|
|
9456
|
+
verifyTwoCheckoutWebhook,
|
|
6667
9457
|
verifyXenditWebhookToken
|
|
6668
9458
|
});
|