@crediblemark/buayar 0.2.1 → 0.3.0
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/dist/index.d.mts +317 -2
- package/dist/index.d.ts +317 -2
- package/dist/index.js +2792 -54
- package/dist/index.mjs +2762 -54
- package/package.json +1 -1
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);
|
|
@@ -5387,6 +5417,1991 @@ var StripeProvider = class extends BasePaymentProvider {
|
|
|
5387
5417
|
}
|
|
5388
5418
|
};
|
|
5389
5419
|
|
|
5420
|
+
// src/providers/paypal/signature.ts
|
|
5421
|
+
function buildPaypalBasicAuth(clientId, clientSecret) {
|
|
5422
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
5423
|
+
}
|
|
5424
|
+
function verifyPaypalWebhookSimple(transmissionId, timestamp, webhookId, body, transmissionSig, certUrl) {
|
|
5425
|
+
return !!(transmissionId && timestamp && webhookId && transmissionSig && certUrl);
|
|
5426
|
+
}
|
|
5427
|
+
function serializePaypalParams(obj) {
|
|
5428
|
+
return Object.entries(obj).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
|
|
5429
|
+
}
|
|
5430
|
+
|
|
5431
|
+
// src/providers/paypal/provider.ts
|
|
5432
|
+
var PaypalProvider = class extends BasePaymentProvider {
|
|
5433
|
+
name = "paypal";
|
|
5434
|
+
getSandbox(config) {
|
|
5435
|
+
return config.sandbox !== false;
|
|
5436
|
+
}
|
|
5437
|
+
getBaseUrl(config) {
|
|
5438
|
+
return this.getSandbox(config) ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
5439
|
+
}
|
|
5440
|
+
/** OAuth2 Client Credentials — dapatkan access token */
|
|
5441
|
+
async getAccessToken(config) {
|
|
5442
|
+
const clientId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
5443
|
+
const clientSecret = config.apiKey || config.secretKey || "";
|
|
5444
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
5445
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5446
|
+
const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
|
|
5447
|
+
method: "POST",
|
|
5448
|
+
headers: {
|
|
5449
|
+
"Authorization": `Basic ${auth}`,
|
|
5450
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
5451
|
+
},
|
|
5452
|
+
body: "grant_type=client_credentials"
|
|
5453
|
+
});
|
|
5454
|
+
const text = await response.text();
|
|
5455
|
+
let data = null;
|
|
5456
|
+
try {
|
|
5457
|
+
data = JSON.parse(text);
|
|
5458
|
+
} catch (e) {
|
|
5459
|
+
}
|
|
5460
|
+
if (!response.ok || !data?.access_token) {
|
|
5461
|
+
throw new Error(data?.error_description || `Failed to get PayPal access token: ${response.status}`);
|
|
5462
|
+
}
|
|
5463
|
+
return data.access_token;
|
|
5464
|
+
}
|
|
5465
|
+
async createInvoice(params, config) {
|
|
5466
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
5467
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5468
|
+
let accessToken;
|
|
5469
|
+
try {
|
|
5470
|
+
accessToken = await this.getAccessToken(config);
|
|
5471
|
+
} catch (e) {
|
|
5472
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5473
|
+
}
|
|
5474
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5475
|
+
const amountFormatted = (amount / 100).toFixed(2);
|
|
5476
|
+
const isDirect = !!params.paymentMethod;
|
|
5477
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5478
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5479
|
+
const body = {
|
|
5480
|
+
intent: isDirect ? "CAPTURE" : "CAPTURE",
|
|
5481
|
+
purchase_units: [
|
|
5482
|
+
{
|
|
5483
|
+
reference_id: orderId,
|
|
5484
|
+
description: productDetails,
|
|
5485
|
+
amount: {
|
|
5486
|
+
currency_code: currency,
|
|
5487
|
+
value: amountFormatted
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
],
|
|
5491
|
+
application_context: {
|
|
5492
|
+
return_url: successUrl,
|
|
5493
|
+
cancel_url: cancelUrl,
|
|
5494
|
+
brand_name: productDetails,
|
|
5495
|
+
user_action: "PAY_NOW"
|
|
5496
|
+
}
|
|
5497
|
+
};
|
|
5498
|
+
if (isDirect) {
|
|
5499
|
+
body.application_context.shipping_preference = "NO_SHIPPING";
|
|
5500
|
+
}
|
|
5501
|
+
if (callbackUrl || config.callbackUrl) {
|
|
5502
|
+
}
|
|
5503
|
+
try {
|
|
5504
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders`, {
|
|
5505
|
+
method: "POST",
|
|
5506
|
+
headers: {
|
|
5507
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5508
|
+
"Content-Type": "application/json",
|
|
5509
|
+
"PayPal-Request-Id": orderId,
|
|
5510
|
+
"Prefer": "return=representation"
|
|
5511
|
+
},
|
|
5512
|
+
body: JSON.stringify(body)
|
|
5513
|
+
});
|
|
5514
|
+
const text = await response.text();
|
|
5515
|
+
let data = null;
|
|
5516
|
+
try {
|
|
5517
|
+
data = JSON.parse(text);
|
|
5518
|
+
} catch (e) {
|
|
5519
|
+
}
|
|
5520
|
+
if (!response.ok || !data || data.name) {
|
|
5521
|
+
return {
|
|
5522
|
+
success: false,
|
|
5523
|
+
provider: "paypal",
|
|
5524
|
+
orderId,
|
|
5525
|
+
amount,
|
|
5526
|
+
rawResponse: data,
|
|
5527
|
+
error: data?.message || `HTTP error! Status: ${response.status}`
|
|
5528
|
+
};
|
|
5529
|
+
}
|
|
5530
|
+
const approveLink = data.links?.find((l) => l.rel === "approve" || l.rel === "payer-action");
|
|
5531
|
+
const paymentUrl = approveLink?.href || "";
|
|
5532
|
+
return {
|
|
5533
|
+
success: true,
|
|
5534
|
+
provider: "paypal",
|
|
5535
|
+
orderId,
|
|
5536
|
+
amount,
|
|
5537
|
+
reference: data.id,
|
|
5538
|
+
paymentUrl,
|
|
5539
|
+
rawResponse: data
|
|
5540
|
+
};
|
|
5541
|
+
} catch (e) {
|
|
5542
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
async verifyCallback(body, config) {
|
|
5546
|
+
const eventType = body?.event_type || body?.event_name || "";
|
|
5547
|
+
const resource = body?.resource || {};
|
|
5548
|
+
const orderId = resource.reference_id || resource.purchase_units?.[0]?.reference_id || resource.supplementary_data?.related_ids?.order_id || resource.id || "";
|
|
5549
|
+
const amount = Number(resource.amount?.value || resource.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5550
|
+
const statusRaw = (resource.status || "").toUpperCase();
|
|
5551
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "PAYMENT.CAPTURE.COMPLETED";
|
|
5552
|
+
const isPending = statusRaw === "PENDING" || eventType === "PAYMENT.CAPTURE.PENDING";
|
|
5553
|
+
const isExpired = statusRaw === "EXPIRED" || eventType === "CHECKOUT.ORDER.EXPIRED";
|
|
5554
|
+
const isFailed = !isPaid && !isPending && !isExpired && (statusRaw === "DENIED" || statusRaw === "FAILED" || eventType.includes("FAILED") || eventType.includes("DENIED"));
|
|
5555
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5556
|
+
return {
|
|
5557
|
+
isValid: true,
|
|
5558
|
+
// Full cert-chain validation deferred to PayPal's verify API
|
|
5559
|
+
provider: "paypal",
|
|
5560
|
+
orderId: String(orderId),
|
|
5561
|
+
amount,
|
|
5562
|
+
status,
|
|
5563
|
+
isPaid,
|
|
5564
|
+
isPending,
|
|
5565
|
+
isFailed,
|
|
5566
|
+
isExpired,
|
|
5567
|
+
statusCode: eventType,
|
|
5568
|
+
rawPayload: body
|
|
5569
|
+
};
|
|
5570
|
+
}
|
|
5571
|
+
async getPaymentMethods(params, config) {
|
|
5572
|
+
const methods = [
|
|
5573
|
+
{
|
|
5574
|
+
paymentMethod: "credit_card",
|
|
5575
|
+
code: "card",
|
|
5576
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)",
|
|
5577
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5578
|
+
totalFee: "3.49% + fixed fee",
|
|
5579
|
+
category: "Kartu Kredit"
|
|
5580
|
+
},
|
|
5581
|
+
{
|
|
5582
|
+
paymentMethod: "paypal",
|
|
5583
|
+
code: "paypal",
|
|
5584
|
+
paymentName: "PayPal Balance / PayPal Checkout",
|
|
5585
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5586
|
+
totalFee: "3.49% + fixed fee",
|
|
5587
|
+
category: "E-Wallet"
|
|
5588
|
+
},
|
|
5589
|
+
{
|
|
5590
|
+
paymentMethod: "paylater",
|
|
5591
|
+
code: "pay_later",
|
|
5592
|
+
paymentName: "PayPal Pay Later / Buy Now Pay Later",
|
|
5593
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5594
|
+
totalFee: "3.49% + fixed fee",
|
|
5595
|
+
category: "Paylater / Cicilan"
|
|
5596
|
+
}
|
|
5597
|
+
];
|
|
5598
|
+
const categories = {};
|
|
5599
|
+
for (const item of methods) {
|
|
5600
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5601
|
+
categories[item.category].push(item);
|
|
5602
|
+
}
|
|
5603
|
+
return { success: true, provider: "paypal", methods, categories, rawResponse: methods };
|
|
5604
|
+
}
|
|
5605
|
+
async checkTransaction(params, config) {
|
|
5606
|
+
const { merchantOrderId } = params;
|
|
5607
|
+
let accessToken;
|
|
5608
|
+
try {
|
|
5609
|
+
accessToken = await this.getAccessToken(config);
|
|
5610
|
+
} catch (e) {
|
|
5611
|
+
return {
|
|
5612
|
+
success: false,
|
|
5613
|
+
provider: "paypal",
|
|
5614
|
+
orderId: merchantOrderId,
|
|
5615
|
+
reference: "",
|
|
5616
|
+
amount: 0,
|
|
5617
|
+
statusCode: "AUTH_ERROR",
|
|
5618
|
+
status: "failed",
|
|
5619
|
+
isPaid: false,
|
|
5620
|
+
isPending: false,
|
|
5621
|
+
isFailed: true,
|
|
5622
|
+
isExpired: false,
|
|
5623
|
+
statusMessage: e.message,
|
|
5624
|
+
error: e.message,
|
|
5625
|
+
rawResponse: null
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
5628
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5629
|
+
try {
|
|
5630
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
5631
|
+
method: "GET",
|
|
5632
|
+
headers: {
|
|
5633
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5634
|
+
"Content-Type": "application/json"
|
|
5635
|
+
}
|
|
5636
|
+
});
|
|
5637
|
+
const text = await response.text();
|
|
5638
|
+
let data = null;
|
|
5639
|
+
try {
|
|
5640
|
+
data = JSON.parse(text);
|
|
5641
|
+
} catch (e) {
|
|
5642
|
+
}
|
|
5643
|
+
if (!response.ok || !data || data.name) {
|
|
5644
|
+
return {
|
|
5645
|
+
success: false,
|
|
5646
|
+
provider: "paypal",
|
|
5647
|
+
orderId: merchantOrderId,
|
|
5648
|
+
reference: "",
|
|
5649
|
+
amount: 0,
|
|
5650
|
+
statusCode: response.status.toString(),
|
|
5651
|
+
status: "failed",
|
|
5652
|
+
isPaid: false,
|
|
5653
|
+
isPending: false,
|
|
5654
|
+
isFailed: true,
|
|
5655
|
+
isExpired: false,
|
|
5656
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5657
|
+
error: data?.message,
|
|
5658
|
+
rawResponse: data
|
|
5659
|
+
};
|
|
5660
|
+
}
|
|
5661
|
+
const statusRaw = (data.status || "").toUpperCase();
|
|
5662
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
5663
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED" || statusRaw === "CREATED";
|
|
5664
|
+
const isExpired = statusRaw === "VOIDED";
|
|
5665
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5666
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5667
|
+
const amountValue = Number(data.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5668
|
+
return {
|
|
5669
|
+
success: true,
|
|
5670
|
+
provider: "paypal",
|
|
5671
|
+
orderId: data.purchase_units?.[0]?.reference_id || merchantOrderId,
|
|
5672
|
+
reference: data.id || merchantOrderId,
|
|
5673
|
+
amount: amountValue,
|
|
5674
|
+
statusCode: statusRaw,
|
|
5675
|
+
status,
|
|
5676
|
+
isPaid,
|
|
5677
|
+
isPending,
|
|
5678
|
+
isFailed,
|
|
5679
|
+
isExpired,
|
|
5680
|
+
statusMessage: statusRaw,
|
|
5681
|
+
transactionTime: data.create_time ? new Date(data.create_time) : void 0,
|
|
5682
|
+
rawResponse: data
|
|
5683
|
+
};
|
|
5684
|
+
} catch (e) {
|
|
5685
|
+
return {
|
|
5686
|
+
success: false,
|
|
5687
|
+
provider: "paypal",
|
|
5688
|
+
orderId: merchantOrderId,
|
|
5689
|
+
reference: "",
|
|
5690
|
+
amount: 0,
|
|
5691
|
+
statusCode: "ERROR",
|
|
5692
|
+
status: "failed",
|
|
5693
|
+
isPaid: false,
|
|
5694
|
+
isPending: false,
|
|
5695
|
+
isFailed: true,
|
|
5696
|
+
isExpired: false,
|
|
5697
|
+
statusMessage: e.message,
|
|
5698
|
+
error: e.message,
|
|
5699
|
+
rawResponse: null
|
|
5700
|
+
};
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
};
|
|
5704
|
+
|
|
5705
|
+
// src/providers/adyen/signature.ts
|
|
5706
|
+
var import_crypto16 = require("crypto");
|
|
5707
|
+
function verifyAdyenWebhook(notificationItem, hmacKey) {
|
|
5708
|
+
if (!hmacKey || !notificationItem) return false;
|
|
5709
|
+
try {
|
|
5710
|
+
const amount = notificationItem.amount || {};
|
|
5711
|
+
const fields = [
|
|
5712
|
+
notificationItem.pspReference || "",
|
|
5713
|
+
notificationItem.originalReference || "",
|
|
5714
|
+
notificationItem.merchantAccountCode || "",
|
|
5715
|
+
notificationItem.merchantReference || "",
|
|
5716
|
+
String(amount.value || ""),
|
|
5717
|
+
amount.currency || "",
|
|
5718
|
+
notificationItem.eventCode || "",
|
|
5719
|
+
notificationItem.success || ""
|
|
5720
|
+
];
|
|
5721
|
+
const signedData = fields.join(":");
|
|
5722
|
+
const keyBytes = Buffer.from(hmacKey, "hex");
|
|
5723
|
+
const expected = (0, import_crypto16.createHmac)("sha256", keyBytes).update(signedData, "utf8").digest("base64");
|
|
5724
|
+
return expected === notificationItem.additionalData?.hmacSignature;
|
|
5725
|
+
} catch {
|
|
5726
|
+
return false;
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5729
|
+
|
|
5730
|
+
// src/providers/adyen/provider.ts
|
|
5731
|
+
var AdyenProvider = class extends BasePaymentProvider {
|
|
5732
|
+
name = "adyen";
|
|
5733
|
+
getBaseUrl(config) {
|
|
5734
|
+
if (!config.sandbox) {
|
|
5735
|
+
const prefix = config.extra?.liveUrlPrefix || config.projectId || "";
|
|
5736
|
+
if (prefix) {
|
|
5737
|
+
return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
return "https://checkout-test.adyen.com";
|
|
5741
|
+
}
|
|
5742
|
+
async createInvoice(params, config) {
|
|
5743
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5744
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5745
|
+
const merchantAccount = config.merchantCode || config.merchantId || config.extra?.merchantAccount || "";
|
|
5746
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5747
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5748
|
+
const isDirect = !!params.paymentMethod;
|
|
5749
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5750
|
+
try {
|
|
5751
|
+
if (isDirect) {
|
|
5752
|
+
const url = `${baseUrl}/v68/payments`;
|
|
5753
|
+
const body = {
|
|
5754
|
+
merchantAccount,
|
|
5755
|
+
reference: orderId,
|
|
5756
|
+
amount: { value: amount, currency },
|
|
5757
|
+
returnUrl: successUrl,
|
|
5758
|
+
shopperEmail: customer?.email,
|
|
5759
|
+
shopperName: customer?.name ? { firstName: customer.name.split(" ")[0], lastName: customer.name.split(" ").slice(1).join(" ") || "-" } : void 0,
|
|
5760
|
+
shopperReference: customer?.email || orderId,
|
|
5761
|
+
additionalData: { allow3DS2: true },
|
|
5762
|
+
metadata: { order_id: orderId },
|
|
5763
|
+
...params.providerParams
|
|
5764
|
+
};
|
|
5765
|
+
const response = await fetch(url, {
|
|
5766
|
+
method: "POST",
|
|
5767
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5768
|
+
body: JSON.stringify(body)
|
|
5769
|
+
});
|
|
5770
|
+
const text = await response.text();
|
|
5771
|
+
let data = null;
|
|
5772
|
+
try {
|
|
5773
|
+
data = JSON.parse(text);
|
|
5774
|
+
} catch (e) {
|
|
5775
|
+
}
|
|
5776
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5777
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5778
|
+
}
|
|
5779
|
+
const isPaid = data.resultCode === "Authorised";
|
|
5780
|
+
const isPending = data.resultCode === "Pending" || data.resultCode === "RedirectShopper" || data.resultCode === "IdentifyShopper" || data.resultCode === "ChallengeShopper";
|
|
5781
|
+
return {
|
|
5782
|
+
success: true,
|
|
5783
|
+
provider: "adyen",
|
|
5784
|
+
orderId,
|
|
5785
|
+
amount,
|
|
5786
|
+
reference: data.pspReference || data.merchantReference,
|
|
5787
|
+
paymentUrl: data.action?.url || data.redirect?.url || void 0,
|
|
5788
|
+
rawResponse: data
|
|
5789
|
+
};
|
|
5790
|
+
} else {
|
|
5791
|
+
const url = `${baseUrl}/v68/sessions`;
|
|
5792
|
+
const body = {
|
|
5793
|
+
merchantAccount,
|
|
5794
|
+
reference: orderId,
|
|
5795
|
+
amount: { value: amount, currency },
|
|
5796
|
+
returnUrl: successUrl,
|
|
5797
|
+
countryCode: config.extra?.countryCode || "US",
|
|
5798
|
+
shopperLocale: config.extra?.shopperLocale || "en-US",
|
|
5799
|
+
shopperEmail: customer?.email,
|
|
5800
|
+
shopperReference: customer?.email || orderId,
|
|
5801
|
+
metadata: { order_id: orderId },
|
|
5802
|
+
...params.providerParams
|
|
5803
|
+
};
|
|
5804
|
+
const response = await fetch(url, {
|
|
5805
|
+
method: "POST",
|
|
5806
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5807
|
+
body: JSON.stringify(body)
|
|
5808
|
+
});
|
|
5809
|
+
const text = await response.text();
|
|
5810
|
+
let data = null;
|
|
5811
|
+
try {
|
|
5812
|
+
data = JSON.parse(text);
|
|
5813
|
+
} catch (e) {
|
|
5814
|
+
}
|
|
5815
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5816
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5817
|
+
}
|
|
5818
|
+
return {
|
|
5819
|
+
success: true,
|
|
5820
|
+
provider: "adyen",
|
|
5821
|
+
orderId,
|
|
5822
|
+
amount,
|
|
5823
|
+
reference: data.id,
|
|
5824
|
+
paymentUrl: data.url,
|
|
5825
|
+
paymentCode: data.sessionData,
|
|
5826
|
+
rawResponse: data
|
|
5827
|
+
};
|
|
5828
|
+
}
|
|
5829
|
+
} catch (e) {
|
|
5830
|
+
return { success: false, provider: "adyen", orderId, amount, error: e.message, rawResponse: null };
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5833
|
+
async verifyCallback(body, config) {
|
|
5834
|
+
const hmacKey = config.extra?.hmacKey || config.secretKey || "";
|
|
5835
|
+
const notificationItems = body?.notificationItems || [body];
|
|
5836
|
+
const item = notificationItems[0]?.NotificationRequestItem || notificationItems[0] || body;
|
|
5837
|
+
const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : true;
|
|
5838
|
+
const eventCode = (item.eventCode || "").toUpperCase();
|
|
5839
|
+
const success = item.success === "true" || item.success === true;
|
|
5840
|
+
const orderId = item.merchantReference || item.pspReference || "";
|
|
5841
|
+
const amount = item.amount?.value ? Number(item.amount.value) : 0;
|
|
5842
|
+
const isPaid = eventCode === "AUTHORISATION" && success;
|
|
5843
|
+
const isPending = eventCode === "PENDING" || eventCode === "OFFER_CLOSED";
|
|
5844
|
+
const isExpired = eventCode === "EXPIRED" || eventCode === "CANCEL";
|
|
5845
|
+
const isFailed = !isPaid && !isPending && !isExpired && (!success || eventCode === "REFUSAL");
|
|
5846
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5847
|
+
return {
|
|
5848
|
+
isValid,
|
|
5849
|
+
provider: "adyen",
|
|
5850
|
+
orderId: String(orderId),
|
|
5851
|
+
amount,
|
|
5852
|
+
status,
|
|
5853
|
+
isPaid,
|
|
5854
|
+
isPending,
|
|
5855
|
+
isFailed,
|
|
5856
|
+
isExpired,
|
|
5857
|
+
statusCode: eventCode,
|
|
5858
|
+
rawPayload: body
|
|
5859
|
+
};
|
|
5860
|
+
}
|
|
5861
|
+
async getPaymentMethods(params, config) {
|
|
5862
|
+
const methods = [
|
|
5863
|
+
{ 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" },
|
|
5864
|
+
{ 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" },
|
|
5865
|
+
{ 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" },
|
|
5866
|
+
{ 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" },
|
|
5867
|
+
{ 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" },
|
|
5868
|
+
{ 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" },
|
|
5869
|
+
{ 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" }
|
|
5870
|
+
];
|
|
5871
|
+
const categories = {};
|
|
5872
|
+
for (const item of methods) {
|
|
5873
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5874
|
+
categories[item.category].push(item);
|
|
5875
|
+
}
|
|
5876
|
+
return { success: true, provider: "adyen", methods, categories, rawResponse: methods };
|
|
5877
|
+
}
|
|
5878
|
+
async checkTransaction(params, config) {
|
|
5879
|
+
const { merchantOrderId } = params;
|
|
5880
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5881
|
+
const merchantAccount = config.merchantCode || config.merchantId || "";
|
|
5882
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5883
|
+
try {
|
|
5884
|
+
const response = await fetch(`${baseUrl}/v68/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
5885
|
+
method: "GET",
|
|
5886
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" }
|
|
5887
|
+
});
|
|
5888
|
+
const text = await response.text();
|
|
5889
|
+
let data = null;
|
|
5890
|
+
try {
|
|
5891
|
+
data = JSON.parse(text);
|
|
5892
|
+
} catch (e) {
|
|
5893
|
+
}
|
|
5894
|
+
if (!response.ok || !data) {
|
|
5895
|
+
return {
|
|
5896
|
+
success: false,
|
|
5897
|
+
provider: "adyen",
|
|
5898
|
+
orderId: merchantOrderId,
|
|
5899
|
+
reference: "",
|
|
5900
|
+
amount: 0,
|
|
5901
|
+
statusCode: response.status.toString(),
|
|
5902
|
+
status: "failed",
|
|
5903
|
+
isPaid: false,
|
|
5904
|
+
isPending: false,
|
|
5905
|
+
isFailed: true,
|
|
5906
|
+
isExpired: false,
|
|
5907
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5908
|
+
error: data?.message,
|
|
5909
|
+
rawResponse: data
|
|
5910
|
+
};
|
|
5911
|
+
}
|
|
5912
|
+
const resultCode = (data.resultCode || data.status || "").toUpperCase();
|
|
5913
|
+
const isPaid = resultCode === "AUTHORISED" || resultCode === "SETTLED";
|
|
5914
|
+
const isPending = resultCode === "PENDING" || resultCode === "RECEIVED" || resultCode === "REDIRECTSHOPPER";
|
|
5915
|
+
const isExpired = resultCode === "EXPIRED" || resultCode === "CANCELLED";
|
|
5916
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5917
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5918
|
+
return {
|
|
5919
|
+
success: true,
|
|
5920
|
+
provider: "adyen",
|
|
5921
|
+
orderId: data.merchantReference || merchantOrderId,
|
|
5922
|
+
reference: data.pspReference || merchantOrderId,
|
|
5923
|
+
amount: data.amount?.value ? Number(data.amount.value) : 0,
|
|
5924
|
+
statusCode: resultCode,
|
|
5925
|
+
status,
|
|
5926
|
+
isPaid,
|
|
5927
|
+
isPending,
|
|
5928
|
+
isFailed,
|
|
5929
|
+
isExpired,
|
|
5930
|
+
statusMessage: resultCode,
|
|
5931
|
+
rawResponse: data
|
|
5932
|
+
};
|
|
5933
|
+
} catch (e) {
|
|
5934
|
+
return {
|
|
5935
|
+
success: false,
|
|
5936
|
+
provider: "adyen",
|
|
5937
|
+
orderId: merchantOrderId,
|
|
5938
|
+
reference: "",
|
|
5939
|
+
amount: 0,
|
|
5940
|
+
statusCode: "ERROR",
|
|
5941
|
+
status: "failed",
|
|
5942
|
+
isPaid: false,
|
|
5943
|
+
isPending: false,
|
|
5944
|
+
isFailed: true,
|
|
5945
|
+
isExpired: false,
|
|
5946
|
+
statusMessage: e.message,
|
|
5947
|
+
error: e.message,
|
|
5948
|
+
rawResponse: null
|
|
5949
|
+
};
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5952
|
+
};
|
|
5953
|
+
|
|
5954
|
+
// src/providers/checkoutcom/signature.ts
|
|
5955
|
+
var import_crypto17 = require("crypto");
|
|
5956
|
+
function verifyCheckoutComWebhook(body, signatureHeader, secret) {
|
|
5957
|
+
if (!secret || !signatureHeader || !body) return false;
|
|
5958
|
+
try {
|
|
5959
|
+
const expected = (0, import_crypto17.createHmac)("sha256", secret).update(body, "utf8").digest("hex");
|
|
5960
|
+
const provided = signatureHeader.replace(/^sha256=/, "");
|
|
5961
|
+
return expected === provided;
|
|
5962
|
+
} catch {
|
|
5963
|
+
return false;
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
|
|
5967
|
+
// src/providers/checkoutcom/provider.ts
|
|
5968
|
+
var CheckoutComProvider = class extends BasePaymentProvider {
|
|
5969
|
+
name = "checkoutcom";
|
|
5970
|
+
getBaseUrl(config) {
|
|
5971
|
+
return config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
5972
|
+
}
|
|
5973
|
+
async createInvoice(params, config) {
|
|
5974
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5975
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
5976
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5977
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5978
|
+
const isDirect = !!params.paymentMethod;
|
|
5979
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5980
|
+
try {
|
|
5981
|
+
if (isDirect) {
|
|
5982
|
+
const url = `${baseUrl}/payments`;
|
|
5983
|
+
const body = {
|
|
5984
|
+
amount,
|
|
5985
|
+
currency,
|
|
5986
|
+
reference: orderId,
|
|
5987
|
+
description: productDetails,
|
|
5988
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
5989
|
+
success_url: successUrl,
|
|
5990
|
+
failure_url: successUrl,
|
|
5991
|
+
metadata: { order_id: orderId },
|
|
5992
|
+
...params.providerParams
|
|
5993
|
+
};
|
|
5994
|
+
const response = await fetch(url, {
|
|
5995
|
+
method: "POST",
|
|
5996
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
5997
|
+
body: JSON.stringify(body)
|
|
5998
|
+
});
|
|
5999
|
+
const text = await response.text();
|
|
6000
|
+
let data = null;
|
|
6001
|
+
try {
|
|
6002
|
+
data = JSON.parse(text);
|
|
6003
|
+
} catch (e) {
|
|
6004
|
+
}
|
|
6005
|
+
if (!response.ok || !data || data.error_codes) {
|
|
6006
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
6007
|
+
}
|
|
6008
|
+
return {
|
|
6009
|
+
success: true,
|
|
6010
|
+
provider: "checkoutcom",
|
|
6011
|
+
orderId,
|
|
6012
|
+
amount: data.amount || amount,
|
|
6013
|
+
reference: data.id,
|
|
6014
|
+
paymentUrl: data._links?.redirect?.href,
|
|
6015
|
+
rawResponse: data
|
|
6016
|
+
};
|
|
6017
|
+
} else {
|
|
6018
|
+
const url = `${baseUrl}/payment-links`;
|
|
6019
|
+
const body = {
|
|
6020
|
+
amount,
|
|
6021
|
+
currency,
|
|
6022
|
+
reference: orderId,
|
|
6023
|
+
description: productDetails,
|
|
6024
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
6025
|
+
return_url: successUrl,
|
|
6026
|
+
metadata: { order_id: orderId },
|
|
6027
|
+
...params.providerParams
|
|
6028
|
+
};
|
|
6029
|
+
const response = await fetch(url, {
|
|
6030
|
+
method: "POST",
|
|
6031
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
6032
|
+
body: JSON.stringify(body)
|
|
6033
|
+
});
|
|
6034
|
+
const text = await response.text();
|
|
6035
|
+
let data = null;
|
|
6036
|
+
try {
|
|
6037
|
+
data = JSON.parse(text);
|
|
6038
|
+
} catch (e) {
|
|
6039
|
+
}
|
|
6040
|
+
if (!response.ok || !data || data.error_codes) {
|
|
6041
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
6042
|
+
}
|
|
6043
|
+
return {
|
|
6044
|
+
success: true,
|
|
6045
|
+
provider: "checkoutcom",
|
|
6046
|
+
orderId,
|
|
6047
|
+
amount,
|
|
6048
|
+
reference: data.id,
|
|
6049
|
+
paymentUrl: data._links?.redirect?.href || data.reference,
|
|
6050
|
+
rawResponse: data
|
|
6051
|
+
};
|
|
6052
|
+
}
|
|
6053
|
+
} catch (e) {
|
|
6054
|
+
return { success: false, provider: "checkoutcom", orderId, amount, error: e.message, rawResponse: null };
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
6057
|
+
async verifyCallback(body, config) {
|
|
6058
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
6059
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6060
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6061
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6062
|
+
const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : true;
|
|
6063
|
+
const eventType = parsedBody?.type || "";
|
|
6064
|
+
const data = parsedBody?.data || parsedBody;
|
|
6065
|
+
const orderId = data?.reference || data?.metadata?.order_id || data?.id || "";
|
|
6066
|
+
const amount = Number(data?.amount || 0);
|
|
6067
|
+
const isPaid = eventType === "payment_approved" || eventType === "payment_captured" || data?.approved === true;
|
|
6068
|
+
const isPending = eventType === "payment_pending" || eventType === "payment_voided";
|
|
6069
|
+
const isExpired = eventType === "payment_expired";
|
|
6070
|
+
const isFailed = eventType === "payment_declined" || eventType === "payment_capture_declined";
|
|
6071
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6072
|
+
return {
|
|
6073
|
+
isValid,
|
|
6074
|
+
provider: "checkoutcom",
|
|
6075
|
+
orderId: String(orderId),
|
|
6076
|
+
amount,
|
|
6077
|
+
status,
|
|
6078
|
+
isPaid,
|
|
6079
|
+
isPending,
|
|
6080
|
+
isFailed,
|
|
6081
|
+
isExpired,
|
|
6082
|
+
statusCode: eventType,
|
|
6083
|
+
rawPayload: parsedBody
|
|
6084
|
+
};
|
|
6085
|
+
}
|
|
6086
|
+
async getPaymentMethods(params, config) {
|
|
6087
|
+
const methods = [
|
|
6088
|
+
{ 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" },
|
|
6089
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6090
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6091
|
+
{ paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
6092
|
+
{ paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" },
|
|
6093
|
+
{ paymentMethod: "sofort", code: "sofort", paymentName: "Sofort / SEPA", paymentImage: "https://checkout.com/favicon.ico", totalFee: "0.8% + \u20AC0.25", category: "Virtual Account" }
|
|
6094
|
+
];
|
|
6095
|
+
const categories = {};
|
|
6096
|
+
for (const item of methods) {
|
|
6097
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6098
|
+
categories[item.category].push(item);
|
|
6099
|
+
}
|
|
6100
|
+
return { success: true, provider: "checkoutcom", methods, categories, rawResponse: methods };
|
|
6101
|
+
}
|
|
6102
|
+
async checkTransaction(params, config) {
|
|
6103
|
+
const { merchantOrderId } = params;
|
|
6104
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
6105
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6106
|
+
try {
|
|
6107
|
+
const response = await fetch(`${baseUrl}/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
6108
|
+
method: "GET",
|
|
6109
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" }
|
|
6110
|
+
});
|
|
6111
|
+
const text = await response.text();
|
|
6112
|
+
let data = null;
|
|
6113
|
+
try {
|
|
6114
|
+
data = JSON.parse(text);
|
|
6115
|
+
} catch (e) {
|
|
6116
|
+
}
|
|
6117
|
+
if (!response.ok || !data) {
|
|
6118
|
+
return {
|
|
6119
|
+
success: false,
|
|
6120
|
+
provider: "checkoutcom",
|
|
6121
|
+
orderId: merchantOrderId,
|
|
6122
|
+
reference: "",
|
|
6123
|
+
amount: 0,
|
|
6124
|
+
statusCode: response.status.toString(),
|
|
6125
|
+
status: "failed",
|
|
6126
|
+
isPaid: false,
|
|
6127
|
+
isPending: false,
|
|
6128
|
+
isFailed: true,
|
|
6129
|
+
isExpired: false,
|
|
6130
|
+
statusMessage: "HTTP Error",
|
|
6131
|
+
rawResponse: data
|
|
6132
|
+
};
|
|
6133
|
+
}
|
|
6134
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
6135
|
+
const isPaid = statusRaw === "authorized" || statusRaw === "captured";
|
|
6136
|
+
const isPending = statusRaw === "pending" || statusRaw === "card_verified";
|
|
6137
|
+
const isExpired = statusRaw === "expired" || statusRaw === "voided";
|
|
6138
|
+
const isFailed = statusRaw === "declined" || statusRaw === "failed";
|
|
6139
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6140
|
+
return {
|
|
6141
|
+
success: true,
|
|
6142
|
+
provider: "checkoutcom",
|
|
6143
|
+
orderId: data.reference || merchantOrderId,
|
|
6144
|
+
reference: data.id || merchantOrderId,
|
|
6145
|
+
amount: Number(data.amount || 0),
|
|
6146
|
+
statusCode: statusRaw,
|
|
6147
|
+
status,
|
|
6148
|
+
isPaid,
|
|
6149
|
+
isPending,
|
|
6150
|
+
isFailed,
|
|
6151
|
+
isExpired,
|
|
6152
|
+
statusMessage: statusRaw,
|
|
6153
|
+
paymentType: data.payment_type || "card",
|
|
6154
|
+
transactionTime: data.requested_on ? new Date(data.requested_on) : void 0,
|
|
6155
|
+
rawResponse: data
|
|
6156
|
+
};
|
|
6157
|
+
} catch (e) {
|
|
6158
|
+
return {
|
|
6159
|
+
success: false,
|
|
6160
|
+
provider: "checkoutcom",
|
|
6161
|
+
orderId: merchantOrderId,
|
|
6162
|
+
reference: "",
|
|
6163
|
+
amount: 0,
|
|
6164
|
+
statusCode: "ERROR",
|
|
6165
|
+
status: "failed",
|
|
6166
|
+
isPaid: false,
|
|
6167
|
+
isPending: false,
|
|
6168
|
+
isFailed: true,
|
|
6169
|
+
isExpired: false,
|
|
6170
|
+
statusMessage: e.message,
|
|
6171
|
+
error: e.message,
|
|
6172
|
+
rawResponse: null
|
|
6173
|
+
};
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
};
|
|
6177
|
+
|
|
6178
|
+
// src/providers/razorpay/signature.ts
|
|
6179
|
+
var import_crypto18 = require("crypto");
|
|
6180
|
+
function verifyRazorpayWebhook(rawBody, signature, webhookSecret) {
|
|
6181
|
+
if (!webhookSecret || !signature || !rawBody) return false;
|
|
6182
|
+
try {
|
|
6183
|
+
const expected = (0, import_crypto18.createHmac)("sha256", webhookSecret).update(rawBody).digest("hex");
|
|
6184
|
+
return expected === signature;
|
|
6185
|
+
} catch {
|
|
6186
|
+
return false;
|
|
6187
|
+
}
|
|
6188
|
+
}
|
|
6189
|
+
function buildRazorpayBasicAuth(keyId, keySecret) {
|
|
6190
|
+
return Buffer.from(`${keyId}:${keySecret}`).toString("base64");
|
|
6191
|
+
}
|
|
6192
|
+
|
|
6193
|
+
// src/providers/razorpay/provider.ts
|
|
6194
|
+
var RazorpayProvider = class extends BasePaymentProvider {
|
|
6195
|
+
name = "razorpay";
|
|
6196
|
+
getBaseUrl() {
|
|
6197
|
+
return "https://api.razorpay.com/v1";
|
|
6198
|
+
}
|
|
6199
|
+
buildHeaders(config) {
|
|
6200
|
+
const keyId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
6201
|
+
const keySecret = config.apiKey || config.secretKey || "";
|
|
6202
|
+
return {
|
|
6203
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
6204
|
+
"Content-Type": "application/json"
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
async createInvoice(params, config) {
|
|
6208
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6209
|
+
const currency = (params.currency || "INR").toUpperCase();
|
|
6210
|
+
const baseUrl = this.getBaseUrl();
|
|
6211
|
+
const headers = this.buildHeaders(config);
|
|
6212
|
+
const isDirect = !!params.paymentMethod;
|
|
6213
|
+
try {
|
|
6214
|
+
if (isDirect) {
|
|
6215
|
+
const body = {
|
|
6216
|
+
amount,
|
|
6217
|
+
currency,
|
|
6218
|
+
receipt: orderId,
|
|
6219
|
+
notes: { order_id: orderId, product: productDetails },
|
|
6220
|
+
...params.providerParams
|
|
6221
|
+
};
|
|
6222
|
+
const response = await fetch(`${baseUrl}/orders`, {
|
|
6223
|
+
method: "POST",
|
|
6224
|
+
headers,
|
|
6225
|
+
body: JSON.stringify(body)
|
|
6226
|
+
});
|
|
6227
|
+
const text = await response.text();
|
|
6228
|
+
let data = null;
|
|
6229
|
+
try {
|
|
6230
|
+
data = JSON.parse(text);
|
|
6231
|
+
} catch (e) {
|
|
6232
|
+
}
|
|
6233
|
+
if (!response.ok || !data || data.error) {
|
|
6234
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6235
|
+
}
|
|
6236
|
+
return {
|
|
6237
|
+
success: true,
|
|
6238
|
+
provider: "razorpay",
|
|
6239
|
+
orderId,
|
|
6240
|
+
amount: data.amount || amount,
|
|
6241
|
+
reference: data.id,
|
|
6242
|
+
paymentCode: data.id,
|
|
6243
|
+
rawResponse: data
|
|
6244
|
+
};
|
|
6245
|
+
} else {
|
|
6246
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6247
|
+
const body = {
|
|
6248
|
+
amount,
|
|
6249
|
+
currency,
|
|
6250
|
+
description: productDetails,
|
|
6251
|
+
reference_id: orderId,
|
|
6252
|
+
customer: { name: customer?.name, email: customer?.email, contact: customer?.phone || "" },
|
|
6253
|
+
notify: { sms: false, email: !!customer?.email },
|
|
6254
|
+
reminder_enable: false,
|
|
6255
|
+
callback_url: callbackUrl || config.callbackUrl || successUrl,
|
|
6256
|
+
callback_method: "get",
|
|
6257
|
+
notes: { order_id: orderId },
|
|
6258
|
+
...params.providerParams
|
|
6259
|
+
};
|
|
6260
|
+
const response = await fetch(`${baseUrl}/payment_links`, {
|
|
6261
|
+
method: "POST",
|
|
6262
|
+
headers,
|
|
6263
|
+
body: JSON.stringify(body)
|
|
6264
|
+
});
|
|
6265
|
+
const text = await response.text();
|
|
6266
|
+
let data = null;
|
|
6267
|
+
try {
|
|
6268
|
+
data = JSON.parse(text);
|
|
6269
|
+
} catch (e) {
|
|
6270
|
+
}
|
|
6271
|
+
if (!response.ok || !data || data.error) {
|
|
6272
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6273
|
+
}
|
|
6274
|
+
return {
|
|
6275
|
+
success: true,
|
|
6276
|
+
provider: "razorpay",
|
|
6277
|
+
orderId,
|
|
6278
|
+
amount: data.amount || amount,
|
|
6279
|
+
reference: data.id,
|
|
6280
|
+
paymentUrl: data.short_url,
|
|
6281
|
+
rawResponse: data
|
|
6282
|
+
};
|
|
6283
|
+
}
|
|
6284
|
+
} catch (e) {
|
|
6285
|
+
return { success: false, provider: "razorpay", orderId, amount, error: e.message, rawResponse: null };
|
|
6286
|
+
}
|
|
6287
|
+
}
|
|
6288
|
+
async verifyCallback(body, config) {
|
|
6289
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
6290
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6291
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6292
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6293
|
+
const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : true;
|
|
6294
|
+
const eventType = parsedBody?.event || "";
|
|
6295
|
+
const payload = parsedBody?.payload;
|
|
6296
|
+
const paymentEntity = payload?.payment?.entity || payload?.payment_link?.entity || parsedBody;
|
|
6297
|
+
const orderId = paymentEntity?.notes?.order_id || paymentEntity?.order_id || paymentEntity?.reference_id || paymentEntity?.id || "";
|
|
6298
|
+
const amount = Number(paymentEntity?.amount || 0);
|
|
6299
|
+
const statusRaw = (paymentEntity?.status || "").toLowerCase();
|
|
6300
|
+
const isPaid = eventType === "payment.captured" || eventType === "payment_link.paid" || statusRaw === "captured";
|
|
6301
|
+
const isPending = eventType === "payment.authorized" || statusRaw === "authorized" || statusRaw === "created";
|
|
6302
|
+
const isExpired = eventType === "payment_link.expired" || statusRaw === "expired";
|
|
6303
|
+
const isFailed = eventType === "payment.failed" || statusRaw === "failed";
|
|
6304
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6305
|
+
return {
|
|
6306
|
+
isValid,
|
|
6307
|
+
provider: "razorpay",
|
|
6308
|
+
orderId: String(orderId),
|
|
6309
|
+
amount,
|
|
6310
|
+
status,
|
|
6311
|
+
isPaid,
|
|
6312
|
+
isPending,
|
|
6313
|
+
isFailed,
|
|
6314
|
+
isExpired,
|
|
6315
|
+
statusCode: eventType || statusRaw,
|
|
6316
|
+
rawPayload: parsedBody
|
|
6317
|
+
};
|
|
6318
|
+
}
|
|
6319
|
+
async getPaymentMethods(params, config) {
|
|
6320
|
+
const methods = [
|
|
6321
|
+
{ paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "2% + GST", category: "Kartu Kredit" },
|
|
6322
|
+
{ paymentMethod: "upi", code: "upi", paymentName: "UPI (GPay, PhonePe, Paytm)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Free", category: "QRIS" },
|
|
6323
|
+
{ paymentMethod: "netbanking", code: "netbanking", paymentName: "Net Banking (50+ banks)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "\u20B910", category: "Virtual Account" },
|
|
6324
|
+
{ paymentMethod: "wallet", code: "wallet", paymentName: "Wallets (Paytm, PhonePe, etc.)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
6325
|
+
{ paymentMethod: "emi", code: "emi", paymentName: "EMI (Card / Cardless)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Bank charge", category: "Paylater / Cicilan" }
|
|
6326
|
+
];
|
|
6327
|
+
const categories = {};
|
|
6328
|
+
for (const item of methods) {
|
|
6329
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6330
|
+
categories[item.category].push(item);
|
|
6331
|
+
}
|
|
6332
|
+
return { success: true, provider: "razorpay", methods, categories, rawResponse: methods };
|
|
6333
|
+
}
|
|
6334
|
+
async checkTransaction(params, config) {
|
|
6335
|
+
const { merchantOrderId } = params;
|
|
6336
|
+
const baseUrl = this.getBaseUrl();
|
|
6337
|
+
const headers = this.buildHeaders(config);
|
|
6338
|
+
try {
|
|
6339
|
+
const endpoint = merchantOrderId.startsWith("plink_") ? `/payment_links/${encodeURIComponent(merchantOrderId)}` : `/payments/${encodeURIComponent(merchantOrderId)}`;
|
|
6340
|
+
const response = await fetch(`${baseUrl}${endpoint}`, { method: "GET", headers });
|
|
6341
|
+
const text = await response.text();
|
|
6342
|
+
let data = null;
|
|
6343
|
+
try {
|
|
6344
|
+
data = JSON.parse(text);
|
|
6345
|
+
} catch (e) {
|
|
6346
|
+
}
|
|
6347
|
+
if (!response.ok || !data || data.error) {
|
|
6348
|
+
return {
|
|
6349
|
+
success: false,
|
|
6350
|
+
provider: "razorpay",
|
|
6351
|
+
orderId: merchantOrderId,
|
|
6352
|
+
reference: "",
|
|
6353
|
+
amount: 0,
|
|
6354
|
+
statusCode: response.status.toString(),
|
|
6355
|
+
status: "failed",
|
|
6356
|
+
isPaid: false,
|
|
6357
|
+
isPending: false,
|
|
6358
|
+
isFailed: true,
|
|
6359
|
+
isExpired: false,
|
|
6360
|
+
statusMessage: data?.error?.description || "HTTP Error",
|
|
6361
|
+
rawResponse: data
|
|
6362
|
+
};
|
|
6363
|
+
}
|
|
6364
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
6365
|
+
const isPaid = statusRaw === "captured" || statusRaw === "paid";
|
|
6366
|
+
const isPending = statusRaw === "authorized" || statusRaw === "created";
|
|
6367
|
+
const isExpired = statusRaw === "expired";
|
|
6368
|
+
const isFailed = statusRaw === "failed";
|
|
6369
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6370
|
+
return {
|
|
6371
|
+
success: true,
|
|
6372
|
+
provider: "razorpay",
|
|
6373
|
+
orderId: data.notes?.order_id || data.reference_id || merchantOrderId,
|
|
6374
|
+
reference: data.id || merchantOrderId,
|
|
6375
|
+
amount: Number(data.amount || 0),
|
|
6376
|
+
statusCode: statusRaw,
|
|
6377
|
+
status,
|
|
6378
|
+
isPaid,
|
|
6379
|
+
isPending,
|
|
6380
|
+
isFailed,
|
|
6381
|
+
isExpired,
|
|
6382
|
+
statusMessage: statusRaw,
|
|
6383
|
+
paymentType: data.method || "card",
|
|
6384
|
+
transactionTime: data.created_at ? new Date(data.created_at * 1e3) : void 0,
|
|
6385
|
+
rawResponse: data
|
|
6386
|
+
};
|
|
6387
|
+
} catch (e) {
|
|
6388
|
+
return {
|
|
6389
|
+
success: false,
|
|
6390
|
+
provider: "razorpay",
|
|
6391
|
+
orderId: merchantOrderId,
|
|
6392
|
+
reference: "",
|
|
6393
|
+
amount: 0,
|
|
6394
|
+
statusCode: "ERROR",
|
|
6395
|
+
status: "failed",
|
|
6396
|
+
isPaid: false,
|
|
6397
|
+
isPending: false,
|
|
6398
|
+
isFailed: true,
|
|
6399
|
+
isExpired: false,
|
|
6400
|
+
statusMessage: e.message,
|
|
6401
|
+
error: e.message,
|
|
6402
|
+
rawResponse: null
|
|
6403
|
+
};
|
|
6404
|
+
}
|
|
6405
|
+
}
|
|
6406
|
+
};
|
|
6407
|
+
|
|
6408
|
+
// src/providers/square/signature.ts
|
|
6409
|
+
var import_crypto19 = require("crypto");
|
|
6410
|
+
function verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) {
|
|
6411
|
+
if (!signatureKey || !signatureHeader || !rawBody) return false;
|
|
6412
|
+
try {
|
|
6413
|
+
const payload = notificationUrl + rawBody;
|
|
6414
|
+
const expected = (0, import_crypto19.createHmac)("sha256", signatureKey).update(payload).digest("base64");
|
|
6415
|
+
return expected === signatureHeader;
|
|
6416
|
+
} catch {
|
|
6417
|
+
return false;
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
|
|
6421
|
+
// src/providers/square/provider.ts
|
|
6422
|
+
var SquareProvider = class extends BasePaymentProvider {
|
|
6423
|
+
name = "square";
|
|
6424
|
+
getBaseUrl(config) {
|
|
6425
|
+
return config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
6426
|
+
}
|
|
6427
|
+
buildHeaders(config) {
|
|
6428
|
+
return {
|
|
6429
|
+
"Authorization": `Bearer ${config.apiKey || config.secretKey || ""}`,
|
|
6430
|
+
"Content-Type": "application/json",
|
|
6431
|
+
"Square-Version": "2024-01-17"
|
|
6432
|
+
};
|
|
6433
|
+
}
|
|
6434
|
+
async createInvoice(params, config) {
|
|
6435
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
6436
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6437
|
+
const locationId = config.extra?.locationId || config.projectId || "";
|
|
6438
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6439
|
+
const headers = this.buildHeaders(config);
|
|
6440
|
+
const isDirect = !!params.paymentMethod;
|
|
6441
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6442
|
+
try {
|
|
6443
|
+
if (isDirect) {
|
|
6444
|
+
const sourceId = params.providerParams?.sourceId || params.providerParams?.nonce || "cnon:card-nonce-ok";
|
|
6445
|
+
const body = {
|
|
6446
|
+
idempotency_key: orderId,
|
|
6447
|
+
source_id: sourceId,
|
|
6448
|
+
amount_money: { amount, currency },
|
|
6449
|
+
reference_id: orderId,
|
|
6450
|
+
note: productDetails,
|
|
6451
|
+
buyer_email_address: customer?.email,
|
|
6452
|
+
...params.providerParams
|
|
6453
|
+
};
|
|
6454
|
+
const response = await fetch(`${baseUrl}/v2/payments`, {
|
|
6455
|
+
method: "POST",
|
|
6456
|
+
headers,
|
|
6457
|
+
body: JSON.stringify(body)
|
|
6458
|
+
});
|
|
6459
|
+
const text = await response.text();
|
|
6460
|
+
let data = null;
|
|
6461
|
+
try {
|
|
6462
|
+
data = JSON.parse(text);
|
|
6463
|
+
} catch (e) {
|
|
6464
|
+
}
|
|
6465
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6466
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6467
|
+
}
|
|
6468
|
+
const payment = data.payment || data;
|
|
6469
|
+
return {
|
|
6470
|
+
success: true,
|
|
6471
|
+
provider: "square",
|
|
6472
|
+
orderId,
|
|
6473
|
+
amount: payment.amount_money?.amount || amount,
|
|
6474
|
+
reference: payment.id,
|
|
6475
|
+
rawResponse: data
|
|
6476
|
+
};
|
|
6477
|
+
} else {
|
|
6478
|
+
const body = {
|
|
6479
|
+
idempotency_key: orderId,
|
|
6480
|
+
order: {
|
|
6481
|
+
location_id: locationId,
|
|
6482
|
+
reference_id: orderId,
|
|
6483
|
+
line_items: [
|
|
6484
|
+
{
|
|
6485
|
+
name: productDetails,
|
|
6486
|
+
quantity: "1",
|
|
6487
|
+
base_price_money: { amount, currency }
|
|
6488
|
+
}
|
|
6489
|
+
]
|
|
6490
|
+
},
|
|
6491
|
+
checkout_options: {
|
|
6492
|
+
redirect_url: successUrl,
|
|
6493
|
+
ask_for_shipping_address: false
|
|
6494
|
+
},
|
|
6495
|
+
pre_populated_data: {
|
|
6496
|
+
buyer_email: customer?.email
|
|
6497
|
+
},
|
|
6498
|
+
...params.providerParams
|
|
6499
|
+
};
|
|
6500
|
+
const response = await fetch(`${baseUrl}/v2/online-checkout/payment-links`, {
|
|
6501
|
+
method: "POST",
|
|
6502
|
+
headers,
|
|
6503
|
+
body: JSON.stringify(body)
|
|
6504
|
+
});
|
|
6505
|
+
const text = await response.text();
|
|
6506
|
+
let data = null;
|
|
6507
|
+
try {
|
|
6508
|
+
data = JSON.parse(text);
|
|
6509
|
+
} catch (e) {
|
|
6510
|
+
}
|
|
6511
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6512
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6513
|
+
}
|
|
6514
|
+
const link = data.payment_link || data;
|
|
6515
|
+
return {
|
|
6516
|
+
success: true,
|
|
6517
|
+
provider: "square",
|
|
6518
|
+
orderId,
|
|
6519
|
+
amount,
|
|
6520
|
+
reference: link.id,
|
|
6521
|
+
paymentUrl: link.url,
|
|
6522
|
+
rawResponse: data
|
|
6523
|
+
};
|
|
6524
|
+
}
|
|
6525
|
+
} catch (e) {
|
|
6526
|
+
return { success: false, provider: "square", orderId, amount, error: e.message, rawResponse: null };
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
async verifyCallback(body, config) {
|
|
6530
|
+
const signatureKey = config.extra?.webhookSignatureKey || config.secretKey || "";
|
|
6531
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6532
|
+
const notificationUrl = config.callbackUrl || config.extra?.notificationUrl || "";
|
|
6533
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6534
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6535
|
+
const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : true;
|
|
6536
|
+
const eventType = parsedBody?.type || "";
|
|
6537
|
+
const data = parsedBody?.data?.object || parsedBody?.data || parsedBody;
|
|
6538
|
+
const payment = data?.payment || data;
|
|
6539
|
+
const orderId = payment?.reference_id || payment?.order_id || payment?.id || "";
|
|
6540
|
+
const amount = Number(payment?.amount_money?.amount || 0);
|
|
6541
|
+
const statusRaw = (payment?.status || "").toUpperCase();
|
|
6542
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "payment.completed";
|
|
6543
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6544
|
+
const isFailed = statusRaw === "FAILED" || statusRaw === "CANCELED";
|
|
6545
|
+
const isExpired = eventType === "payment.expired";
|
|
6546
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6547
|
+
return {
|
|
6548
|
+
isValid,
|
|
6549
|
+
provider: "square",
|
|
6550
|
+
orderId: String(orderId),
|
|
6551
|
+
amount,
|
|
6552
|
+
status,
|
|
6553
|
+
isPaid,
|
|
6554
|
+
isPending,
|
|
6555
|
+
isFailed,
|
|
6556
|
+
isExpired,
|
|
6557
|
+
statusCode: eventType || statusRaw,
|
|
6558
|
+
rawPayload: parsedBody
|
|
6559
|
+
};
|
|
6560
|
+
}
|
|
6561
|
+
async getPaymentMethods(params, config) {
|
|
6562
|
+
const methods = [
|
|
6563
|
+
{ 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" },
|
|
6564
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6565
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6566
|
+
{ paymentMethod: "cash_app", code: "cashapp", paymentName: "Cash App Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6567
|
+
{ paymentMethod: "afterpay", code: "afterpay", paymentName: "Afterpay / Clearpay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "6% + $0.30", category: "Paylater / Cicilan" }
|
|
6568
|
+
];
|
|
6569
|
+
const categories = {};
|
|
6570
|
+
for (const item of methods) {
|
|
6571
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6572
|
+
categories[item.category].push(item);
|
|
6573
|
+
}
|
|
6574
|
+
return { success: true, provider: "square", methods, categories, rawResponse: methods };
|
|
6575
|
+
}
|
|
6576
|
+
async checkTransaction(params, config) {
|
|
6577
|
+
const { merchantOrderId } = params;
|
|
6578
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6579
|
+
const headers = this.buildHeaders(config);
|
|
6580
|
+
try {
|
|
6581
|
+
const response = await fetch(`${baseUrl}/v2/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
6582
|
+
method: "GET",
|
|
6583
|
+
headers
|
|
6584
|
+
});
|
|
6585
|
+
const text = await response.text();
|
|
6586
|
+
let data = null;
|
|
6587
|
+
try {
|
|
6588
|
+
data = JSON.parse(text);
|
|
6589
|
+
} catch (e) {
|
|
6590
|
+
}
|
|
6591
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6592
|
+
return {
|
|
6593
|
+
success: false,
|
|
6594
|
+
provider: "square",
|
|
6595
|
+
orderId: merchantOrderId,
|
|
6596
|
+
reference: "",
|
|
6597
|
+
amount: 0,
|
|
6598
|
+
statusCode: response.status.toString(),
|
|
6599
|
+
status: "failed",
|
|
6600
|
+
isPaid: false,
|
|
6601
|
+
isPending: false,
|
|
6602
|
+
isFailed: true,
|
|
6603
|
+
isExpired: false,
|
|
6604
|
+
statusMessage: data?.errors?.[0]?.detail || "HTTP Error",
|
|
6605
|
+
rawResponse: data
|
|
6606
|
+
};
|
|
6607
|
+
}
|
|
6608
|
+
const payment = data.payment || data;
|
|
6609
|
+
const statusRaw = (payment.status || "").toUpperCase();
|
|
6610
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6611
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6612
|
+
const isExpired = statusRaw === "CANCELED";
|
|
6613
|
+
const isFailed = statusRaw === "FAILED";
|
|
6614
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6615
|
+
return {
|
|
6616
|
+
success: true,
|
|
6617
|
+
provider: "square",
|
|
6618
|
+
orderId: payment.reference_id || merchantOrderId,
|
|
6619
|
+
reference: payment.id || merchantOrderId,
|
|
6620
|
+
amount: Number(payment.amount_money?.amount || 0),
|
|
6621
|
+
statusCode: statusRaw,
|
|
6622
|
+
status,
|
|
6623
|
+
isPaid,
|
|
6624
|
+
isPending,
|
|
6625
|
+
isFailed,
|
|
6626
|
+
isExpired,
|
|
6627
|
+
statusMessage: statusRaw,
|
|
6628
|
+
paymentType: payment.source_type || "card",
|
|
6629
|
+
transactionTime: payment.created_at ? new Date(payment.created_at) : void 0,
|
|
6630
|
+
rawResponse: data
|
|
6631
|
+
};
|
|
6632
|
+
} catch (e) {
|
|
6633
|
+
return {
|
|
6634
|
+
success: false,
|
|
6635
|
+
provider: "square",
|
|
6636
|
+
orderId: merchantOrderId,
|
|
6637
|
+
reference: "",
|
|
6638
|
+
amount: 0,
|
|
6639
|
+
statusCode: "ERROR",
|
|
6640
|
+
status: "failed",
|
|
6641
|
+
isPaid: false,
|
|
6642
|
+
isPending: false,
|
|
6643
|
+
isFailed: true,
|
|
6644
|
+
isExpired: false,
|
|
6645
|
+
statusMessage: e.message,
|
|
6646
|
+
error: e.message,
|
|
6647
|
+
rawResponse: null
|
|
6648
|
+
};
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
};
|
|
6652
|
+
|
|
6653
|
+
// src/providers/payu/signature.ts
|
|
6654
|
+
var import_crypto20 = require("crypto");
|
|
6655
|
+
function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
|
|
6656
|
+
if (!md5Key || !signatureHeader || !rawBody) return false;
|
|
6657
|
+
try {
|
|
6658
|
+
const parts = {};
|
|
6659
|
+
for (const part of signatureHeader.split(";")) {
|
|
6660
|
+
const [k, v] = part.split("=");
|
|
6661
|
+
if (k && v) parts[k.trim()] = v.trim();
|
|
6662
|
+
}
|
|
6663
|
+
const providedSig = parts["signature"];
|
|
6664
|
+
const algorithm = (parts["algorithm"] || "MD5").toUpperCase();
|
|
6665
|
+
if (algorithm === "MD5") {
|
|
6666
|
+
const expected = (0, import_crypto20.createHash)("md5").update(rawBody + md5Key).digest("hex");
|
|
6667
|
+
return expected === providedSig;
|
|
6668
|
+
} else if (algorithm === "SHA-256") {
|
|
6669
|
+
const expected = (0, import_crypto20.createHash)("sha256").update(rawBody + md5Key).digest("hex");
|
|
6670
|
+
return expected === providedSig;
|
|
6671
|
+
}
|
|
6672
|
+
return false;
|
|
6673
|
+
} catch {
|
|
6674
|
+
return false;
|
|
6675
|
+
}
|
|
6676
|
+
}
|
|
6677
|
+
function buildPayuBasicAuth(clientId, clientSecret) {
|
|
6678
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6681
|
+
// src/providers/payu/provider.ts
|
|
6682
|
+
var PayuProvider = class extends BasePaymentProvider {
|
|
6683
|
+
name = "payu";
|
|
6684
|
+
getBaseUrl(config) {
|
|
6685
|
+
return config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
6686
|
+
}
|
|
6687
|
+
/** OAuth2 Bearer Token untuk PayU */
|
|
6688
|
+
async getAccessToken(config) {
|
|
6689
|
+
const clientId = config.extra?.oauthClientId || config.clientKey || "";
|
|
6690
|
+
const clientSecret = config.extra?.oauthClientSecret || config.apiKey || config.secretKey || "";
|
|
6691
|
+
if (!clientId || !clientSecret) {
|
|
6692
|
+
return "";
|
|
6693
|
+
}
|
|
6694
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6695
|
+
const response = await fetch(`${baseUrl}/pl/standard/user/oauth/authorize`, {
|
|
6696
|
+
method: "POST",
|
|
6697
|
+
headers: {
|
|
6698
|
+
"Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`,
|
|
6699
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
6700
|
+
},
|
|
6701
|
+
body: "grant_type=client_credentials"
|
|
6702
|
+
});
|
|
6703
|
+
const text = await response.text();
|
|
6704
|
+
let data = null;
|
|
6705
|
+
try {
|
|
6706
|
+
data = JSON.parse(text);
|
|
6707
|
+
} catch (e) {
|
|
6708
|
+
}
|
|
6709
|
+
if (!response.ok || !data?.access_token) {
|
|
6710
|
+
throw new Error(data?.error_description || `Failed to get PayU access token: ${response.status}`);
|
|
6711
|
+
}
|
|
6712
|
+
return data.access_token;
|
|
6713
|
+
}
|
|
6714
|
+
async createInvoice(params, config) {
|
|
6715
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6716
|
+
const currency = (params.currency || "PLN").toUpperCase();
|
|
6717
|
+
const posId = config.merchantCode || config.merchantId || config.extra?.posId || "";
|
|
6718
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6719
|
+
let accessToken;
|
|
6720
|
+
try {
|
|
6721
|
+
accessToken = await this.getAccessToken(config);
|
|
6722
|
+
} catch (e) {
|
|
6723
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6724
|
+
}
|
|
6725
|
+
const isDirect = !!params.paymentMethod;
|
|
6726
|
+
const continueUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6727
|
+
const notifyUrl = callbackUrl || config.callbackUrl || "";
|
|
6728
|
+
const body = {
|
|
6729
|
+
notifyUrl,
|
|
6730
|
+
customerIp: params.providerParams?.customerIp || "127.0.0.1",
|
|
6731
|
+
merchantPosId: posId,
|
|
6732
|
+
description: productDetails,
|
|
6733
|
+
currencyCode: currency,
|
|
6734
|
+
totalAmount: amount.toString(),
|
|
6735
|
+
extOrderId: orderId,
|
|
6736
|
+
continueUrl,
|
|
6737
|
+
buyer: {
|
|
6738
|
+
email: customer?.email,
|
|
6739
|
+
firstName: customer?.name?.split(" ")[0],
|
|
6740
|
+
lastName: customer?.name?.split(" ").slice(1).join(" ") || "-",
|
|
6741
|
+
phone: customer?.phone,
|
|
6742
|
+
language: "en"
|
|
6743
|
+
},
|
|
6744
|
+
products: [
|
|
6745
|
+
{ name: productDetails, unitPrice: amount.toString(), quantity: "1" }
|
|
6746
|
+
],
|
|
6747
|
+
...params.providerParams
|
|
6748
|
+
};
|
|
6749
|
+
if (isDirect && params.paymentMethod) {
|
|
6750
|
+
body.payMethods = {
|
|
6751
|
+
payMethod: {
|
|
6752
|
+
type: "PBL",
|
|
6753
|
+
value: params.paymentMethod
|
|
6754
|
+
// e.g. "blik", "c" (card), "ap" (Apple Pay)
|
|
6755
|
+
}
|
|
6756
|
+
};
|
|
6757
|
+
}
|
|
6758
|
+
try {
|
|
6759
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders`, {
|
|
6760
|
+
method: "POST",
|
|
6761
|
+
headers: {
|
|
6762
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
6763
|
+
"Content-Type": "application/json"
|
|
6764
|
+
},
|
|
6765
|
+
body: JSON.stringify(body),
|
|
6766
|
+
redirect: "manual"
|
|
6767
|
+
// PayU responds with 302
|
|
6768
|
+
});
|
|
6769
|
+
const text = await response.text();
|
|
6770
|
+
let data = null;
|
|
6771
|
+
try {
|
|
6772
|
+
data = JSON.parse(text);
|
|
6773
|
+
} catch (e) {
|
|
6774
|
+
}
|
|
6775
|
+
if (response.status === 302 || response.headers.get("location")) {
|
|
6776
|
+
const location = response.headers.get("location") || "";
|
|
6777
|
+
return {
|
|
6778
|
+
success: true,
|
|
6779
|
+
provider: "payu",
|
|
6780
|
+
orderId,
|
|
6781
|
+
amount,
|
|
6782
|
+
reference: data?.orderId || orderId,
|
|
6783
|
+
paymentUrl: location,
|
|
6784
|
+
rawResponse: data
|
|
6785
|
+
};
|
|
6786
|
+
}
|
|
6787
|
+
if (!response.ok || !data || data.status?.statusCode === "ERROR") {
|
|
6788
|
+
return { success: false, provider: "payu", orderId, amount, rawResponse: data, error: data?.status?.statusDesc || `HTTP ${response.status}` };
|
|
6789
|
+
}
|
|
6790
|
+
return {
|
|
6791
|
+
success: true,
|
|
6792
|
+
provider: "payu",
|
|
6793
|
+
orderId,
|
|
6794
|
+
amount,
|
|
6795
|
+
reference: data.orderId || orderId,
|
|
6796
|
+
paymentUrl: data.redirectUri,
|
|
6797
|
+
rawResponse: data
|
|
6798
|
+
};
|
|
6799
|
+
} catch (e) {
|
|
6800
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
async verifyCallback(body, config) {
|
|
6804
|
+
const md5Key = config.extra?.md5Key || config.apiKey || config.secretKey || "";
|
|
6805
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6806
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6807
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6808
|
+
const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : true;
|
|
6809
|
+
const order = parsedBody?.order || parsedBody;
|
|
6810
|
+
const orderId = order.extOrderId || order.orderId || "";
|
|
6811
|
+
const amount = Number(order.totalAmount || 0);
|
|
6812
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6813
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6814
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6815
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6816
|
+
const isExpired = false;
|
|
6817
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6818
|
+
return {
|
|
6819
|
+
isValid,
|
|
6820
|
+
provider: "payu",
|
|
6821
|
+
orderId: String(orderId),
|
|
6822
|
+
amount,
|
|
6823
|
+
status,
|
|
6824
|
+
isPaid,
|
|
6825
|
+
isPending,
|
|
6826
|
+
isFailed,
|
|
6827
|
+
isExpired,
|
|
6828
|
+
statusCode: statusRaw,
|
|
6829
|
+
rawPayload: parsedBody
|
|
6830
|
+
};
|
|
6831
|
+
}
|
|
6832
|
+
async getPaymentMethods(params, config) {
|
|
6833
|
+
const methods = [
|
|
6834
|
+
{ paymentMethod: "credit_card", code: "c", paymentName: "Credit / Debit Card", paymentImage: "https://payu.com/favicon.ico", totalFee: "1.5%+", category: "Kartu Kredit" },
|
|
6835
|
+
{ paymentMethod: "blik", code: "blik", paymentName: "BLIK (Poland)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "E-Wallet" },
|
|
6836
|
+
{ paymentMethod: "apple_pay", code: "ap", paymentName: "Apple Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6837
|
+
{ paymentMethod: "google_pay", code: "gp", paymentName: "Google Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6838
|
+
{ paymentMethod: "bank_transfer", code: "t", paymentName: "Online Bank Transfer (50+ banks)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
6839
|
+
{ paymentMethod: "installment", code: "ai", paymentName: "Installments (PayU)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Bank rate", category: "Paylater / Cicilan" }
|
|
6840
|
+
];
|
|
6841
|
+
const categories = {};
|
|
6842
|
+
for (const item of methods) {
|
|
6843
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6844
|
+
categories[item.category].push(item);
|
|
6845
|
+
}
|
|
6846
|
+
return { success: true, provider: "payu", methods, categories, rawResponse: methods };
|
|
6847
|
+
}
|
|
6848
|
+
async checkTransaction(params, config) {
|
|
6849
|
+
const { merchantOrderId } = params;
|
|
6850
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6851
|
+
let accessToken;
|
|
6852
|
+
try {
|
|
6853
|
+
accessToken = await this.getAccessToken(config);
|
|
6854
|
+
} catch (e) {
|
|
6855
|
+
return {
|
|
6856
|
+
success: false,
|
|
6857
|
+
provider: "payu",
|
|
6858
|
+
orderId: merchantOrderId,
|
|
6859
|
+
reference: "",
|
|
6860
|
+
amount: 0,
|
|
6861
|
+
statusCode: "AUTH_ERROR",
|
|
6862
|
+
status: "failed",
|
|
6863
|
+
isPaid: false,
|
|
6864
|
+
isPending: false,
|
|
6865
|
+
isFailed: true,
|
|
6866
|
+
isExpired: false,
|
|
6867
|
+
statusMessage: e.message,
|
|
6868
|
+
error: e.message,
|
|
6869
|
+
rawResponse: null
|
|
6870
|
+
};
|
|
6871
|
+
}
|
|
6872
|
+
try {
|
|
6873
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
6874
|
+
method: "GET",
|
|
6875
|
+
headers: { "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/json" }
|
|
6876
|
+
});
|
|
6877
|
+
const text = await response.text();
|
|
6878
|
+
let data = null;
|
|
6879
|
+
try {
|
|
6880
|
+
data = JSON.parse(text);
|
|
6881
|
+
} catch (e) {
|
|
6882
|
+
}
|
|
6883
|
+
if (!response.ok || !data) {
|
|
6884
|
+
return {
|
|
6885
|
+
success: false,
|
|
6886
|
+
provider: "payu",
|
|
6887
|
+
orderId: merchantOrderId,
|
|
6888
|
+
reference: "",
|
|
6889
|
+
amount: 0,
|
|
6890
|
+
statusCode: response.status.toString(),
|
|
6891
|
+
status: "failed",
|
|
6892
|
+
isPaid: false,
|
|
6893
|
+
isPending: false,
|
|
6894
|
+
isFailed: true,
|
|
6895
|
+
isExpired: false,
|
|
6896
|
+
statusMessage: "HTTP Error",
|
|
6897
|
+
rawResponse: data
|
|
6898
|
+
};
|
|
6899
|
+
}
|
|
6900
|
+
const order = data.orders?.[0] || data;
|
|
6901
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6902
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6903
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6904
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6905
|
+
const isExpired = false;
|
|
6906
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6907
|
+
return {
|
|
6908
|
+
success: true,
|
|
6909
|
+
provider: "payu",
|
|
6910
|
+
orderId: order.extOrderId || merchantOrderId,
|
|
6911
|
+
reference: order.orderId || merchantOrderId,
|
|
6912
|
+
amount: Number(order.totalAmount || 0),
|
|
6913
|
+
statusCode: statusRaw,
|
|
6914
|
+
status,
|
|
6915
|
+
isPaid,
|
|
6916
|
+
isPending,
|
|
6917
|
+
isFailed,
|
|
6918
|
+
isExpired,
|
|
6919
|
+
statusMessage: statusRaw,
|
|
6920
|
+
transactionTime: order.orderCreateDate ? new Date(order.orderCreateDate) : void 0,
|
|
6921
|
+
rawResponse: data
|
|
6922
|
+
};
|
|
6923
|
+
} catch (e) {
|
|
6924
|
+
return {
|
|
6925
|
+
success: false,
|
|
6926
|
+
provider: "payu",
|
|
6927
|
+
orderId: merchantOrderId,
|
|
6928
|
+
reference: "",
|
|
6929
|
+
amount: 0,
|
|
6930
|
+
statusCode: "ERROR",
|
|
6931
|
+
status: "failed",
|
|
6932
|
+
isPaid: false,
|
|
6933
|
+
isPending: false,
|
|
6934
|
+
isFailed: true,
|
|
6935
|
+
isExpired: false,
|
|
6936
|
+
statusMessage: e.message,
|
|
6937
|
+
error: e.message,
|
|
6938
|
+
rawResponse: null
|
|
6939
|
+
};
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6942
|
+
};
|
|
6943
|
+
|
|
6944
|
+
// src/providers/braintree/signature.ts
|
|
6945
|
+
var import_crypto21 = require("crypto");
|
|
6946
|
+
function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
|
|
6947
|
+
if (!privateKey || !btSignature || !btPayload) return false;
|
|
6948
|
+
try {
|
|
6949
|
+
const parts = btSignature.split("|");
|
|
6950
|
+
if (parts.length < 2) return false;
|
|
6951
|
+
const providedHmac = parts[1];
|
|
6952
|
+
const payload = Buffer.from(btPayload, "base64").toString("utf8");
|
|
6953
|
+
const secretHash = (0, import_crypto21.createHash)("sha1").update(privateKey).digest("hex");
|
|
6954
|
+
const expected = (0, import_crypto21.createHmac)("sha1", secretHash).update(payload).digest("hex");
|
|
6955
|
+
return expected === providedHmac;
|
|
6956
|
+
} catch {
|
|
6957
|
+
return false;
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6960
|
+
function buildBraintreeBasicAuth(publicKey, privateKey) {
|
|
6961
|
+
return Buffer.from(`${publicKey}:${privateKey}`).toString("base64");
|
|
6962
|
+
}
|
|
6963
|
+
|
|
6964
|
+
// src/providers/braintree/provider.ts
|
|
6965
|
+
var BraintreeProvider = class extends BasePaymentProvider {
|
|
6966
|
+
name = "braintree";
|
|
6967
|
+
getBaseUrl(config) {
|
|
6968
|
+
const merchantId = config.merchantCode || config.merchantId || "";
|
|
6969
|
+
const base = config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
6970
|
+
return `${base}/merchants/${merchantId}`;
|
|
6971
|
+
}
|
|
6972
|
+
buildHeaders(config) {
|
|
6973
|
+
const publicKey = config.clientKey || config.extra?.publicKey || "";
|
|
6974
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
6975
|
+
return {
|
|
6976
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
6977
|
+
"Content-Type": "application/json",
|
|
6978
|
+
"Braintree-Version": "2019-01-01"
|
|
6979
|
+
};
|
|
6980
|
+
}
|
|
6981
|
+
async createInvoice(params, config) {
|
|
6982
|
+
const { orderId, amount, productDetails, customer } = params;
|
|
6983
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6984
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6985
|
+
const headers = this.buildHeaders(config);
|
|
6986
|
+
const isDirect = !!params.paymentMethod;
|
|
6987
|
+
try {
|
|
6988
|
+
if (isDirect) {
|
|
6989
|
+
const paymentMethodNonce = params.providerParams?.nonce || params.providerParams?.paymentMethodNonce || "fake-valid-nonce";
|
|
6990
|
+
const body = {
|
|
6991
|
+
transaction: {
|
|
6992
|
+
amount: (amount / 100).toFixed(2),
|
|
6993
|
+
payment_method_nonce: paymentMethodNonce,
|
|
6994
|
+
order_id: orderId,
|
|
6995
|
+
currency_iso_code: currency,
|
|
6996
|
+
options: { submit_for_settlement: true },
|
|
6997
|
+
customer: { first_name: customer?.name, email: customer?.email },
|
|
6998
|
+
custom_fields: { order_id: orderId },
|
|
6999
|
+
...params.providerParams
|
|
7000
|
+
}
|
|
7001
|
+
};
|
|
7002
|
+
const response = await fetch(`${baseUrl}/transactions`, {
|
|
7003
|
+
method: "POST",
|
|
7004
|
+
headers,
|
|
7005
|
+
body: JSON.stringify(body)
|
|
7006
|
+
});
|
|
7007
|
+
const text = await response.text();
|
|
7008
|
+
let data = null;
|
|
7009
|
+
try {
|
|
7010
|
+
data = JSON.parse(text);
|
|
7011
|
+
} catch (e) {
|
|
7012
|
+
}
|
|
7013
|
+
if (!response.ok || data?.apiErrorResponse) {
|
|
7014
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.apiErrorResponse?.message || `HTTP ${response.status}` };
|
|
7015
|
+
}
|
|
7016
|
+
const tx = data?.transaction || data;
|
|
7017
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
7018
|
+
return {
|
|
7019
|
+
success: statusRaw === "submitted_for_settlement" || statusRaw === "settling" || statusRaw === "settled",
|
|
7020
|
+
provider: "braintree",
|
|
7021
|
+
orderId,
|
|
7022
|
+
amount: Math.round(Number(tx.amount || amount / 100) * 100),
|
|
7023
|
+
reference: tx.id,
|
|
7024
|
+
rawResponse: data
|
|
7025
|
+
};
|
|
7026
|
+
} else {
|
|
7027
|
+
const body = { client_token: { customer_id: customer?.email || orderId } };
|
|
7028
|
+
const response = await fetch(`${baseUrl}/client_token`, {
|
|
7029
|
+
method: "POST",
|
|
7030
|
+
headers,
|
|
7031
|
+
body: JSON.stringify(body)
|
|
7032
|
+
});
|
|
7033
|
+
const text = await response.text();
|
|
7034
|
+
let data = null;
|
|
7035
|
+
try {
|
|
7036
|
+
data = JSON.parse(text);
|
|
7037
|
+
} catch (e) {
|
|
7038
|
+
}
|
|
7039
|
+
if (!response.ok || !data?.clientToken) {
|
|
7040
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
7041
|
+
}
|
|
7042
|
+
return {
|
|
7043
|
+
success: true,
|
|
7044
|
+
provider: "braintree",
|
|
7045
|
+
orderId,
|
|
7046
|
+
amount,
|
|
7047
|
+
reference: orderId,
|
|
7048
|
+
paymentCode: data.clientToken,
|
|
7049
|
+
// Frontend uses this token for Drop-in UI
|
|
7050
|
+
rawResponse: data
|
|
7051
|
+
};
|
|
7052
|
+
}
|
|
7053
|
+
} catch (e) {
|
|
7054
|
+
return { success: false, provider: "braintree", orderId, amount, error: e.message, rawResponse: null };
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
async verifyCallback(body, config) {
|
|
7058
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
7059
|
+
const btSignature = config.extra?.btSignature || "";
|
|
7060
|
+
const btPayload = config.extra?.btPayload || "";
|
|
7061
|
+
const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : true;
|
|
7062
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
7063
|
+
const subject = parsedBody?.subject || parsedBody;
|
|
7064
|
+
const transaction = subject?.transaction || subject?.disbursement || parsedBody;
|
|
7065
|
+
const kind = parsedBody?.kind || parsedBody?.event || "";
|
|
7066
|
+
const orderId = transaction?.orderId || transaction?.order_id || transaction?.id || "";
|
|
7067
|
+
const amount = Math.round(Number(transaction?.amount || 0) * 100);
|
|
7068
|
+
const statusRaw = (transaction?.status || "").toLowerCase();
|
|
7069
|
+
const isPaid = kind === "transaction_settled" || kind === "transaction_disbursed" || statusRaw === "settled";
|
|
7070
|
+
const isPending = kind === "transaction_settlement_declined" || statusRaw === "submitted_for_settlement" || statusRaw === "settling";
|
|
7071
|
+
const isFailed = kind === "transaction_failed" || statusRaw === "failed" || statusRaw === "voided";
|
|
7072
|
+
const isExpired = statusRaw === "expired";
|
|
7073
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7074
|
+
return {
|
|
7075
|
+
isValid,
|
|
7076
|
+
provider: "braintree",
|
|
7077
|
+
orderId: String(orderId),
|
|
7078
|
+
amount,
|
|
7079
|
+
status,
|
|
7080
|
+
isPaid,
|
|
7081
|
+
isPending,
|
|
7082
|
+
isFailed,
|
|
7083
|
+
isExpired,
|
|
7084
|
+
statusCode: kind || statusRaw,
|
|
7085
|
+
rawPayload: parsedBody
|
|
7086
|
+
};
|
|
7087
|
+
}
|
|
7088
|
+
async getPaymentMethods(params, config) {
|
|
7089
|
+
const methods = [
|
|
7090
|
+
{ 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" },
|
|
7091
|
+
{ paymentMethod: "paypal", code: "PayPalAccount", paymentName: "PayPal (via Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "3.49% + fixed", category: "E-Wallet" },
|
|
7092
|
+
{ paymentMethod: "apple_pay", code: "ApplePayCard", paymentName: "Apple Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
7093
|
+
{ paymentMethod: "google_pay", code: "AndroidPayCard", paymentName: "Google Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
7094
|
+
{ paymentMethod: "venmo", code: "VenmoAccount", paymentName: "Venmo (US only)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "1.9% + $0.10", category: "E-Wallet" }
|
|
7095
|
+
];
|
|
7096
|
+
const categories = {};
|
|
7097
|
+
for (const item of methods) {
|
|
7098
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
7099
|
+
categories[item.category].push(item);
|
|
7100
|
+
}
|
|
7101
|
+
return { success: true, provider: "braintree", methods, categories, rawResponse: methods };
|
|
7102
|
+
}
|
|
7103
|
+
async checkTransaction(params, config) {
|
|
7104
|
+
const { merchantOrderId } = params;
|
|
7105
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7106
|
+
const headers = this.buildHeaders(config);
|
|
7107
|
+
try {
|
|
7108
|
+
const response = await fetch(`${baseUrl}/transactions/${encodeURIComponent(merchantOrderId)}`, {
|
|
7109
|
+
method: "GET",
|
|
7110
|
+
headers
|
|
7111
|
+
});
|
|
7112
|
+
const text = await response.text();
|
|
7113
|
+
let data = null;
|
|
7114
|
+
try {
|
|
7115
|
+
data = JSON.parse(text);
|
|
7116
|
+
} catch (e) {
|
|
7117
|
+
}
|
|
7118
|
+
if (!response.ok || !data) {
|
|
7119
|
+
return {
|
|
7120
|
+
success: false,
|
|
7121
|
+
provider: "braintree",
|
|
7122
|
+
orderId: merchantOrderId,
|
|
7123
|
+
reference: "",
|
|
7124
|
+
amount: 0,
|
|
7125
|
+
statusCode: response.status.toString(),
|
|
7126
|
+
status: "failed",
|
|
7127
|
+
isPaid: false,
|
|
7128
|
+
isPending: false,
|
|
7129
|
+
isFailed: true,
|
|
7130
|
+
isExpired: false,
|
|
7131
|
+
statusMessage: "HTTP Error",
|
|
7132
|
+
rawResponse: data
|
|
7133
|
+
};
|
|
7134
|
+
}
|
|
7135
|
+
const tx = data.transaction || data;
|
|
7136
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
7137
|
+
const isPaid = statusRaw === "settled" || statusRaw === "settling";
|
|
7138
|
+
const isPending = statusRaw === "submitted_for_settlement" || statusRaw === "authorized";
|
|
7139
|
+
const isExpired = statusRaw === "expired";
|
|
7140
|
+
const isFailed = statusRaw === "failed" || statusRaw === "voided";
|
|
7141
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7142
|
+
return {
|
|
7143
|
+
success: true,
|
|
7144
|
+
provider: "braintree",
|
|
7145
|
+
orderId: tx.orderId || merchantOrderId,
|
|
7146
|
+
reference: tx.id || merchantOrderId,
|
|
7147
|
+
amount: Math.round(Number(tx.amount || 0) * 100),
|
|
7148
|
+
statusCode: statusRaw,
|
|
7149
|
+
status,
|
|
7150
|
+
isPaid,
|
|
7151
|
+
isPending,
|
|
7152
|
+
isFailed,
|
|
7153
|
+
isExpired,
|
|
7154
|
+
statusMessage: statusRaw,
|
|
7155
|
+
paymentType: tx.paymentInstrumentType || "card",
|
|
7156
|
+
transactionTime: tx.createdAt ? new Date(tx.createdAt) : void 0,
|
|
7157
|
+
rawResponse: data
|
|
7158
|
+
};
|
|
7159
|
+
} catch (e) {
|
|
7160
|
+
return {
|
|
7161
|
+
success: false,
|
|
7162
|
+
provider: "braintree",
|
|
7163
|
+
orderId: merchantOrderId,
|
|
7164
|
+
reference: "",
|
|
7165
|
+
amount: 0,
|
|
7166
|
+
statusCode: "ERROR",
|
|
7167
|
+
status: "failed",
|
|
7168
|
+
isPaid: false,
|
|
7169
|
+
isPending: false,
|
|
7170
|
+
isFailed: true,
|
|
7171
|
+
isExpired: false,
|
|
7172
|
+
statusMessage: e.message,
|
|
7173
|
+
error: e.message,
|
|
7174
|
+
rawResponse: null
|
|
7175
|
+
};
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
};
|
|
7179
|
+
|
|
7180
|
+
// src/providers/twocheckout/signature.ts
|
|
7181
|
+
var import_crypto22 = require("crypto");
|
|
7182
|
+
function buildTwoCheckoutAuth(merchantCode, secretKey) {
|
|
7183
|
+
const date = Math.floor(Date.now() / 1e3).toString();
|
|
7184
|
+
const raw = merchantCode + date;
|
|
7185
|
+
const hmac = (0, import_crypto22.createHmac)("sha256", secretKey).update(raw).digest("hex");
|
|
7186
|
+
const header = `code="${merchantCode}" date="${date}" hash="${hmac}"`;
|
|
7187
|
+
return { header, date };
|
|
7188
|
+
}
|
|
7189
|
+
function verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) {
|
|
7190
|
+
if (!secretWord || !providedHash) return false;
|
|
7191
|
+
try {
|
|
7192
|
+
const raw = secretWord + saleId + productId + invoiceId;
|
|
7193
|
+
const expected = (0, import_crypto22.createHash)("md5").update(raw).digest("hex").toUpperCase();
|
|
7194
|
+
return expected === (providedHash || "").toUpperCase();
|
|
7195
|
+
} catch {
|
|
7196
|
+
return false;
|
|
7197
|
+
}
|
|
7198
|
+
}
|
|
7199
|
+
|
|
7200
|
+
// src/providers/twocheckout/provider.ts
|
|
7201
|
+
var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
7202
|
+
name = "twocheckout";
|
|
7203
|
+
getBaseUrl(config) {
|
|
7204
|
+
return config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
7205
|
+
}
|
|
7206
|
+
buildHeaders(config) {
|
|
7207
|
+
const merchantCode = config.merchantCode || config.merchantId || "";
|
|
7208
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
7209
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
7210
|
+
return {
|
|
7211
|
+
"X-Avangate-Authentication": header,
|
|
7212
|
+
"Content-Type": "application/json",
|
|
7213
|
+
"Accept": "application/json"
|
|
7214
|
+
};
|
|
7215
|
+
}
|
|
7216
|
+
async createInvoice(params, config) {
|
|
7217
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
7218
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
7219
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7220
|
+
const headers = this.buildHeaders(config);
|
|
7221
|
+
const isDirect = !!params.paymentMethod;
|
|
7222
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
7223
|
+
const body = {
|
|
7224
|
+
Currency: currency,
|
|
7225
|
+
Language: "en",
|
|
7226
|
+
Country: config.extra?.country || "US",
|
|
7227
|
+
CustomerIP: params.providerParams?.customerIp || "127.0.0.1",
|
|
7228
|
+
Source: "API",
|
|
7229
|
+
MerchantReference: orderId,
|
|
7230
|
+
Items: [
|
|
7231
|
+
{
|
|
7232
|
+
Name: productDetails,
|
|
7233
|
+
Quantity: 1,
|
|
7234
|
+
Price: { Amount: (amount / 100).toFixed(2), Type: "CUSTOM" },
|
|
7235
|
+
Type: "PRODUCT",
|
|
7236
|
+
IsDynamic: true,
|
|
7237
|
+
Tangible: false
|
|
7238
|
+
}
|
|
7239
|
+
],
|
|
7240
|
+
BillingDetails: {
|
|
7241
|
+
FirstName: customer?.name?.split(" ")[0] || "Customer",
|
|
7242
|
+
LastName: customer?.name?.split(" ").slice(1).join(" ") || "Name",
|
|
7243
|
+
Email: customer?.email,
|
|
7244
|
+
Country: config.extra?.country || "US",
|
|
7245
|
+
Address1: config.extra?.address || "N/A",
|
|
7246
|
+
City: config.extra?.city || "N/A",
|
|
7247
|
+
State: config.extra?.state || "",
|
|
7248
|
+
Zip: config.extra?.zip || "00000"
|
|
7249
|
+
},
|
|
7250
|
+
...params.providerParams
|
|
7251
|
+
};
|
|
7252
|
+
if (!isDirect) {
|
|
7253
|
+
body.PaymentDetails = { Type: "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7254
|
+
} else {
|
|
7255
|
+
body.PaymentDetails = { Type: params.paymentMethod === "paypal" ? "PAYPAL" : "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7256
|
+
}
|
|
7257
|
+
try {
|
|
7258
|
+
const response = await fetch(`${baseUrl}/6.0/orders`, {
|
|
7259
|
+
method: "POST",
|
|
7260
|
+
headers,
|
|
7261
|
+
body: JSON.stringify(body)
|
|
7262
|
+
});
|
|
7263
|
+
const text = await response.text();
|
|
7264
|
+
let data = null;
|
|
7265
|
+
try {
|
|
7266
|
+
data = JSON.parse(text);
|
|
7267
|
+
} catch (e) {
|
|
7268
|
+
}
|
|
7269
|
+
if (!response.ok || !data || data.error_code) {
|
|
7270
|
+
return { success: false, provider: "twocheckout", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
7271
|
+
}
|
|
7272
|
+
const paymentUrl = data.PaymentDetails?.PaymentMethod?.RedirectURL || data.PaymentDetails?.PaymentMethod?.Href || `${successUrl}?ref=${data.RefNo}`;
|
|
7273
|
+
return {
|
|
7274
|
+
success: true,
|
|
7275
|
+
provider: "twocheckout",
|
|
7276
|
+
orderId,
|
|
7277
|
+
amount,
|
|
7278
|
+
reference: data.RefNo || data.OrderNo?.toString(),
|
|
7279
|
+
paymentUrl,
|
|
7280
|
+
rawResponse: data
|
|
7281
|
+
};
|
|
7282
|
+
} catch (e) {
|
|
7283
|
+
return { success: false, provider: "twocheckout", orderId, amount, error: e.message, rawResponse: null };
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7286
|
+
async verifyCallback(body, config) {
|
|
7287
|
+
const secretWord = config.extra?.secretWord || config.apiKey || "";
|
|
7288
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
7289
|
+
const saleId = parsedBody?.SALE_ID || parsedBody?.sale_id || "";
|
|
7290
|
+
const productId = parsedBody?.IPN_PID?.[0] || parsedBody?.product_id || "";
|
|
7291
|
+
const invoiceId = parsedBody?.IPN_PNAME?.[0] || parsedBody?.invoice_id || "";
|
|
7292
|
+
const providedHash = parsedBody?.HASH || parsedBody?.hash || "";
|
|
7293
|
+
const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : true;
|
|
7294
|
+
const orderId = parsedBody?.REFNOEXT || parsedBody?.ext_ref_no || parsedBody?.SALE_ID || "";
|
|
7295
|
+
const amount = Math.round(Number(parsedBody?.IPN_TOTAL_GENERAL || parsedBody?.total || 0) * 100);
|
|
7296
|
+
const statusRaw = (parsedBody?.ORDERSTATUS || parsedBody?.order_status || "").toUpperCase();
|
|
7297
|
+
const isPaid = statusRaw === "COMPLETE" || statusRaw === "COMPLETE_MANUAL";
|
|
7298
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7299
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND" || statusRaw === "FRAUD";
|
|
7300
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7301
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7302
|
+
return {
|
|
7303
|
+
isValid,
|
|
7304
|
+
provider: "twocheckout",
|
|
7305
|
+
orderId: String(orderId),
|
|
7306
|
+
amount,
|
|
7307
|
+
status,
|
|
7308
|
+
isPaid,
|
|
7309
|
+
isPending,
|
|
7310
|
+
isFailed,
|
|
7311
|
+
isExpired,
|
|
7312
|
+
statusCode: statusRaw,
|
|
7313
|
+
rawPayload: parsedBody
|
|
7314
|
+
};
|
|
7315
|
+
}
|
|
7316
|
+
async getPaymentMethods(params, config) {
|
|
7317
|
+
const methods = [
|
|
7318
|
+
{ 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" },
|
|
7319
|
+
{ paymentMethod: "paypal", code: "PAYPAL", paymentName: "PayPal", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "E-Wallet" },
|
|
7320
|
+
{ paymentMethod: "wire_transfer", code: "WIRE", paymentName: "Wire Transfer / Bank Transfer", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
7321
|
+
{ paymentMethod: "paylater", code: "PAY_LATER", paymentName: "Buy Now Pay Later (Klarna)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" }
|
|
7322
|
+
];
|
|
7323
|
+
const categories = {};
|
|
7324
|
+
for (const item of methods) {
|
|
7325
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
7326
|
+
categories[item.category].push(item);
|
|
7327
|
+
}
|
|
7328
|
+
return { success: true, provider: "twocheckout", methods, categories, rawResponse: methods };
|
|
7329
|
+
}
|
|
7330
|
+
async checkTransaction(params, config) {
|
|
7331
|
+
const { merchantOrderId } = params;
|
|
7332
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7333
|
+
const headers = this.buildHeaders(config);
|
|
7334
|
+
try {
|
|
7335
|
+
const response = await fetch(`${baseUrl}/6.0/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
7336
|
+
method: "GET",
|
|
7337
|
+
headers
|
|
7338
|
+
});
|
|
7339
|
+
const text = await response.text();
|
|
7340
|
+
let data = null;
|
|
7341
|
+
try {
|
|
7342
|
+
data = JSON.parse(text);
|
|
7343
|
+
} catch (e) {
|
|
7344
|
+
}
|
|
7345
|
+
if (!response.ok || !data || data.error_code) {
|
|
7346
|
+
return {
|
|
7347
|
+
success: false,
|
|
7348
|
+
provider: "twocheckout",
|
|
7349
|
+
orderId: merchantOrderId,
|
|
7350
|
+
reference: "",
|
|
7351
|
+
amount: 0,
|
|
7352
|
+
statusCode: response.status.toString(),
|
|
7353
|
+
status: "failed",
|
|
7354
|
+
isPaid: false,
|
|
7355
|
+
isPending: false,
|
|
7356
|
+
isFailed: true,
|
|
7357
|
+
isExpired: false,
|
|
7358
|
+
statusMessage: data?.message || "HTTP Error",
|
|
7359
|
+
rawResponse: data
|
|
7360
|
+
};
|
|
7361
|
+
}
|
|
7362
|
+
const statusRaw = (data.Status || "").toUpperCase();
|
|
7363
|
+
const isPaid = statusRaw === "COMPLETE";
|
|
7364
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7365
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7366
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND";
|
|
7367
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7368
|
+
return {
|
|
7369
|
+
success: true,
|
|
7370
|
+
provider: "twocheckout",
|
|
7371
|
+
orderId: data.ExternalReference || merchantOrderId,
|
|
7372
|
+
reference: data.RefNo?.toString() || merchantOrderId,
|
|
7373
|
+
amount: Math.round(Number(data.GrossAmount || 0) * 100),
|
|
7374
|
+
statusCode: statusRaw,
|
|
7375
|
+
status,
|
|
7376
|
+
isPaid,
|
|
7377
|
+
isPending,
|
|
7378
|
+
isFailed,
|
|
7379
|
+
isExpired,
|
|
7380
|
+
statusMessage: statusRaw,
|
|
7381
|
+
transactionTime: data.OrderDate ? new Date(data.OrderDate) : void 0,
|
|
7382
|
+
rawResponse: data
|
|
7383
|
+
};
|
|
7384
|
+
} catch (e) {
|
|
7385
|
+
return {
|
|
7386
|
+
success: false,
|
|
7387
|
+
provider: "twocheckout",
|
|
7388
|
+
orderId: merchantOrderId,
|
|
7389
|
+
reference: "",
|
|
7390
|
+
amount: 0,
|
|
7391
|
+
statusCode: "ERROR",
|
|
7392
|
+
status: "failed",
|
|
7393
|
+
isPaid: false,
|
|
7394
|
+
isPending: false,
|
|
7395
|
+
isFailed: true,
|
|
7396
|
+
isExpired: false,
|
|
7397
|
+
statusMessage: e.message,
|
|
7398
|
+
error: e.message,
|
|
7399
|
+
rawResponse: null
|
|
7400
|
+
};
|
|
7401
|
+
}
|
|
7402
|
+
}
|
|
7403
|
+
};
|
|
7404
|
+
|
|
5390
7405
|
// src/clients/duitku.ts
|
|
5391
7406
|
var DuitkuClient = class {
|
|
5392
7407
|
merchantCode;
|
|
@@ -6152,6 +8167,533 @@ var StripeClient = class {
|
|
|
6152
8167
|
}
|
|
6153
8168
|
};
|
|
6154
8169
|
|
|
8170
|
+
// src/clients/paypal.ts
|
|
8171
|
+
var PaypalClient = class {
|
|
8172
|
+
config;
|
|
8173
|
+
constructor(config) {
|
|
8174
|
+
this.config = config;
|
|
8175
|
+
}
|
|
8176
|
+
getBaseUrl() {
|
|
8177
|
+
return this.config.sandbox !== false ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
8178
|
+
}
|
|
8179
|
+
async getAccessToken() {
|
|
8180
|
+
const clientId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8181
|
+
const clientSecret = this.config.apiKey || this.config.secretKey || "";
|
|
8182
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
8183
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/oauth2/token`, {
|
|
8184
|
+
method: "POST",
|
|
8185
|
+
headers: { "Authorization": `Basic ${auth}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8186
|
+
body: "grant_type=client_credentials"
|
|
8187
|
+
});
|
|
8188
|
+
const data = await response.json();
|
|
8189
|
+
if (!data?.access_token) throw new Error(data?.error_description || "Failed to get PayPal access token");
|
|
8190
|
+
return data.access_token;
|
|
8191
|
+
}
|
|
8192
|
+
/** Ambil detail order PayPal berdasarkan Order ID */
|
|
8193
|
+
async getOrder(orderId) {
|
|
8194
|
+
const token = await this.getAccessToken();
|
|
8195
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}`, {
|
|
8196
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8197
|
+
});
|
|
8198
|
+
return response.json();
|
|
8199
|
+
}
|
|
8200
|
+
/** Capture order PayPal (mengeksekusi pembayaran yang sudah diapprove buyer) */
|
|
8201
|
+
async captureOrder(orderId) {
|
|
8202
|
+
const token = await this.getAccessToken();
|
|
8203
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}/capture`, {
|
|
8204
|
+
method: "POST",
|
|
8205
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8206
|
+
body: "{}"
|
|
8207
|
+
});
|
|
8208
|
+
return response.json();
|
|
8209
|
+
}
|
|
8210
|
+
/** Refund capture PayPal */
|
|
8211
|
+
async refundCapture(captureId, amount, currency) {
|
|
8212
|
+
const token = await this.getAccessToken();
|
|
8213
|
+
const body = {};
|
|
8214
|
+
if (amount && currency) {
|
|
8215
|
+
body.amount = { value: (amount / 100).toFixed(2), currency_code: currency };
|
|
8216
|
+
body.note_to_payer = "Refund";
|
|
8217
|
+
}
|
|
8218
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/captures/${captureId}/refund`, {
|
|
8219
|
+
method: "POST",
|
|
8220
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8221
|
+
body: JSON.stringify(body)
|
|
8222
|
+
});
|
|
8223
|
+
return response.json();
|
|
8224
|
+
}
|
|
8225
|
+
/** Cek saldo akun PayPal merchant (hanya tersedia di account via Seller REST API) */
|
|
8226
|
+
async checkBalance() {
|
|
8227
|
+
const token = await this.getAccessToken();
|
|
8228
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/reporting/balances`, {
|
|
8229
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8230
|
+
});
|
|
8231
|
+
return response.json();
|
|
8232
|
+
}
|
|
8233
|
+
/** Verifikasi webhook via PayPal Webhook Verification API */
|
|
8234
|
+
async verifyWebhookSignature(webhookId, body, headers) {
|
|
8235
|
+
const token = await this.getAccessToken();
|
|
8236
|
+
const verifyBody = {
|
|
8237
|
+
auth_algo: headers["paypal-auth-algo"],
|
|
8238
|
+
cert_url: headers["paypal-cert-url"],
|
|
8239
|
+
transmission_id: headers["paypal-transmission-id"],
|
|
8240
|
+
transmission_sig: headers["paypal-transmission-sig"],
|
|
8241
|
+
transmission_time: headers["paypal-transmission-time"],
|
|
8242
|
+
webhook_id: webhookId,
|
|
8243
|
+
webhook_event: typeof body === "string" ? JSON.parse(body) : body
|
|
8244
|
+
};
|
|
8245
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/notifications/verify-webhook-signature`, {
|
|
8246
|
+
method: "POST",
|
|
8247
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8248
|
+
body: JSON.stringify(verifyBody)
|
|
8249
|
+
});
|
|
8250
|
+
const data = await response.json();
|
|
8251
|
+
return data?.verification_status === "SUCCESS";
|
|
8252
|
+
}
|
|
8253
|
+
};
|
|
8254
|
+
|
|
8255
|
+
// src/clients/adyen.ts
|
|
8256
|
+
var AdyenClient = class {
|
|
8257
|
+
config;
|
|
8258
|
+
constructor(config) {
|
|
8259
|
+
this.config = config;
|
|
8260
|
+
}
|
|
8261
|
+
getBaseUrl() {
|
|
8262
|
+
if (this.config.sandbox === false) {
|
|
8263
|
+
const prefix = this.config.extra?.liveUrlPrefix || this.config.projectId || "";
|
|
8264
|
+
if (prefix) return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
8265
|
+
}
|
|
8266
|
+
return "https://checkout-test.adyen.com";
|
|
8267
|
+
}
|
|
8268
|
+
buildHeaders() {
|
|
8269
|
+
return {
|
|
8270
|
+
"X-API-Key": this.config.apiKey || this.config.secretKey || "",
|
|
8271
|
+
"Content-Type": "application/json"
|
|
8272
|
+
};
|
|
8273
|
+
}
|
|
8274
|
+
/** Ambil detail payment berdasarkan PSP Reference */
|
|
8275
|
+
async getPaymentDetails(pspReference) {
|
|
8276
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}`, {
|
|
8277
|
+
method: "GET",
|
|
8278
|
+
headers: this.buildHeaders()
|
|
8279
|
+
});
|
|
8280
|
+
return response.json();
|
|
8281
|
+
}
|
|
8282
|
+
/** Batalkan payment (sebelum capture) */
|
|
8283
|
+
async cancelPayment(pspReference, merchantAccount) {
|
|
8284
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8285
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/cancels`, {
|
|
8286
|
+
method: "POST",
|
|
8287
|
+
headers: this.buildHeaders(),
|
|
8288
|
+
body: JSON.stringify({ merchantAccount: account })
|
|
8289
|
+
});
|
|
8290
|
+
return response.json();
|
|
8291
|
+
}
|
|
8292
|
+
/** Refund payment yang sudah di-capture */
|
|
8293
|
+
async refundPayment(pspReference, amount, currency, merchantAccount) {
|
|
8294
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8295
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/refunds`, {
|
|
8296
|
+
method: "POST",
|
|
8297
|
+
headers: this.buildHeaders(),
|
|
8298
|
+
body: JSON.stringify({
|
|
8299
|
+
merchantAccount: account,
|
|
8300
|
+
amount: { value: amount, currency }
|
|
8301
|
+
})
|
|
8302
|
+
});
|
|
8303
|
+
return response.json();
|
|
8304
|
+
}
|
|
8305
|
+
/** Capture authorized payment */
|
|
8306
|
+
async capturePayment(pspReference, amount, currency, merchantAccount) {
|
|
8307
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8308
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/captures`, {
|
|
8309
|
+
method: "POST",
|
|
8310
|
+
headers: this.buildHeaders(),
|
|
8311
|
+
body: JSON.stringify({
|
|
8312
|
+
merchantAccount: account,
|
|
8313
|
+
amount: { value: amount, currency }
|
|
8314
|
+
})
|
|
8315
|
+
});
|
|
8316
|
+
return response.json();
|
|
8317
|
+
}
|
|
8318
|
+
/** Ambil daftar payment methods yang tersedia */
|
|
8319
|
+
async getAvailablePaymentMethods(merchantAccount, countryCode, currency, amount) {
|
|
8320
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/paymentMethods`, {
|
|
8321
|
+
method: "POST",
|
|
8322
|
+
headers: this.buildHeaders(),
|
|
8323
|
+
body: JSON.stringify({ merchantAccount, countryCode, channel: "Web", amount: { value: amount, currency } })
|
|
8324
|
+
});
|
|
8325
|
+
return response.json();
|
|
8326
|
+
}
|
|
8327
|
+
};
|
|
8328
|
+
|
|
8329
|
+
// src/clients/checkoutcom.ts
|
|
8330
|
+
var CheckoutComClient = class {
|
|
8331
|
+
config;
|
|
8332
|
+
constructor(config) {
|
|
8333
|
+
this.config = config;
|
|
8334
|
+
}
|
|
8335
|
+
getBaseUrl() {
|
|
8336
|
+
return this.config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
8337
|
+
}
|
|
8338
|
+
buildHeaders() {
|
|
8339
|
+
return {
|
|
8340
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8341
|
+
"Content-Type": "application/json"
|
|
8342
|
+
};
|
|
8343
|
+
}
|
|
8344
|
+
/** Ambil detail payment berdasarkan Payment ID */
|
|
8345
|
+
async getPaymentDetails(paymentId) {
|
|
8346
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8347
|
+
method: "GET",
|
|
8348
|
+
headers: this.buildHeaders()
|
|
8349
|
+
});
|
|
8350
|
+
return response.json();
|
|
8351
|
+
}
|
|
8352
|
+
/** Void (batalkan) payment yang belum di-capture */
|
|
8353
|
+
async voidPayment(paymentId, reference) {
|
|
8354
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/voids`, {
|
|
8355
|
+
method: "POST",
|
|
8356
|
+
headers: this.buildHeaders(),
|
|
8357
|
+
body: JSON.stringify({ reference })
|
|
8358
|
+
});
|
|
8359
|
+
return response.json();
|
|
8360
|
+
}
|
|
8361
|
+
/** Refund payment yang sudah di-capture */
|
|
8362
|
+
async refundPayment(paymentId, amount, reference) {
|
|
8363
|
+
const body = { reference };
|
|
8364
|
+
if (amount) body.amount = amount;
|
|
8365
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refunds`, {
|
|
8366
|
+
method: "POST",
|
|
8367
|
+
headers: this.buildHeaders(),
|
|
8368
|
+
body: JSON.stringify(body)
|
|
8369
|
+
});
|
|
8370
|
+
return response.json();
|
|
8371
|
+
}
|
|
8372
|
+
/** Cek saldo merchant di Checkout.com */
|
|
8373
|
+
async checkBalance() {
|
|
8374
|
+
const response = await fetch(`${this.getBaseUrl()}/balances`, {
|
|
8375
|
+
method: "GET",
|
|
8376
|
+
headers: this.buildHeaders()
|
|
8377
|
+
});
|
|
8378
|
+
return response.json();
|
|
8379
|
+
}
|
|
8380
|
+
/** Ambil daftar payment links */
|
|
8381
|
+
async listPaymentLinks() {
|
|
8382
|
+
const response = await fetch(`${this.getBaseUrl()}/payment-links`, {
|
|
8383
|
+
method: "GET",
|
|
8384
|
+
headers: this.buildHeaders()
|
|
8385
|
+
});
|
|
8386
|
+
return response.json();
|
|
8387
|
+
}
|
|
8388
|
+
};
|
|
8389
|
+
|
|
8390
|
+
// src/clients/razorpay.ts
|
|
8391
|
+
var RazorpayClient = class {
|
|
8392
|
+
config;
|
|
8393
|
+
constructor(config) {
|
|
8394
|
+
this.config = config;
|
|
8395
|
+
}
|
|
8396
|
+
getBaseUrl() {
|
|
8397
|
+
return "https://api.razorpay.com/v1";
|
|
8398
|
+
}
|
|
8399
|
+
buildHeaders() {
|
|
8400
|
+
const keyId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8401
|
+
const keySecret = this.config.apiKey || this.config.secretKey || "";
|
|
8402
|
+
return {
|
|
8403
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
8404
|
+
"Content-Type": "application/json"
|
|
8405
|
+
};
|
|
8406
|
+
}
|
|
8407
|
+
/** Ambil detail payment */
|
|
8408
|
+
async fetchPayment(paymentId) {
|
|
8409
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8410
|
+
method: "GET",
|
|
8411
|
+
headers: this.buildHeaders()
|
|
8412
|
+
});
|
|
8413
|
+
return response.json();
|
|
8414
|
+
}
|
|
8415
|
+
/** Capture authorized payment */
|
|
8416
|
+
async capturePayment(paymentId, amount, currency) {
|
|
8417
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/capture`, {
|
|
8418
|
+
method: "POST",
|
|
8419
|
+
headers: this.buildHeaders(),
|
|
8420
|
+
body: JSON.stringify({ amount, currency: currency || "INR" })
|
|
8421
|
+
});
|
|
8422
|
+
return response.json();
|
|
8423
|
+
}
|
|
8424
|
+
/** Buat refund untuk payment */
|
|
8425
|
+
async createRefund(paymentId, amount, notes) {
|
|
8426
|
+
const body = { notes };
|
|
8427
|
+
if (amount) body.amount = amount;
|
|
8428
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refund`, {
|
|
8429
|
+
method: "POST",
|
|
8430
|
+
headers: this.buildHeaders(),
|
|
8431
|
+
body: JSON.stringify(body)
|
|
8432
|
+
});
|
|
8433
|
+
return response.json();
|
|
8434
|
+
}
|
|
8435
|
+
/** Cek saldo akun Razorpay */
|
|
8436
|
+
async checkBalance() {
|
|
8437
|
+
const response = await fetch(`${this.getBaseUrl()}/balance`, {
|
|
8438
|
+
method: "GET",
|
|
8439
|
+
headers: this.buildHeaders()
|
|
8440
|
+
});
|
|
8441
|
+
return response.json();
|
|
8442
|
+
}
|
|
8443
|
+
/** Ambil daftar semua payment */
|
|
8444
|
+
async listPayments(from, to, count) {
|
|
8445
|
+
const params = new URLSearchParams();
|
|
8446
|
+
if (from) params.set("from", from.toString());
|
|
8447
|
+
if (to) params.set("to", to.toString());
|
|
8448
|
+
if (count) params.set("count", count.toString());
|
|
8449
|
+
const response = await fetch(`${this.getBaseUrl()}/payments?${params}`, {
|
|
8450
|
+
method: "GET",
|
|
8451
|
+
headers: this.buildHeaders()
|
|
8452
|
+
});
|
|
8453
|
+
return response.json();
|
|
8454
|
+
}
|
|
8455
|
+
};
|
|
8456
|
+
|
|
8457
|
+
// src/clients/square.ts
|
|
8458
|
+
var SquareClient = class {
|
|
8459
|
+
config;
|
|
8460
|
+
constructor(config) {
|
|
8461
|
+
this.config = config;
|
|
8462
|
+
}
|
|
8463
|
+
getBaseUrl() {
|
|
8464
|
+
return this.config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
8465
|
+
}
|
|
8466
|
+
buildHeaders() {
|
|
8467
|
+
return {
|
|
8468
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8469
|
+
"Content-Type": "application/json",
|
|
8470
|
+
"Square-Version": "2024-01-17"
|
|
8471
|
+
};
|
|
8472
|
+
}
|
|
8473
|
+
/** Ambil detail payment Square */
|
|
8474
|
+
async getPayment(paymentId) {
|
|
8475
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}`, {
|
|
8476
|
+
method: "GET",
|
|
8477
|
+
headers: this.buildHeaders()
|
|
8478
|
+
});
|
|
8479
|
+
return response.json();
|
|
8480
|
+
}
|
|
8481
|
+
/** Batalkan payment Square */
|
|
8482
|
+
async cancelPayment(paymentId) {
|
|
8483
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}/cancel`, {
|
|
8484
|
+
method: "POST",
|
|
8485
|
+
headers: this.buildHeaders(),
|
|
8486
|
+
body: "{}"
|
|
8487
|
+
});
|
|
8488
|
+
return response.json();
|
|
8489
|
+
}
|
|
8490
|
+
/** Refund payment Square */
|
|
8491
|
+
async refundPayment(paymentId, amount, currency, idempotencyKey, reason) {
|
|
8492
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/refunds`, {
|
|
8493
|
+
method: "POST",
|
|
8494
|
+
headers: this.buildHeaders(),
|
|
8495
|
+
body: JSON.stringify({
|
|
8496
|
+
idempotency_key: idempotencyKey,
|
|
8497
|
+
payment_id: paymentId,
|
|
8498
|
+
amount_money: { amount, currency },
|
|
8499
|
+
reason
|
|
8500
|
+
})
|
|
8501
|
+
});
|
|
8502
|
+
return response.json();
|
|
8503
|
+
}
|
|
8504
|
+
/** Ambil saldo location Square */
|
|
8505
|
+
async retrieveBalance(locationId) {
|
|
8506
|
+
const id = locationId || this.config.extra?.locationId || this.config.projectId || "";
|
|
8507
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations/${id}`, {
|
|
8508
|
+
method: "GET",
|
|
8509
|
+
headers: this.buildHeaders()
|
|
8510
|
+
});
|
|
8511
|
+
return response.json();
|
|
8512
|
+
}
|
|
8513
|
+
/** List semua locations merchant */
|
|
8514
|
+
async listLocations() {
|
|
8515
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations`, {
|
|
8516
|
+
method: "GET",
|
|
8517
|
+
headers: this.buildHeaders()
|
|
8518
|
+
});
|
|
8519
|
+
return response.json();
|
|
8520
|
+
}
|
|
8521
|
+
};
|
|
8522
|
+
|
|
8523
|
+
// src/clients/payu.ts
|
|
8524
|
+
var PayuClient = class {
|
|
8525
|
+
config;
|
|
8526
|
+
accessToken = null;
|
|
8527
|
+
constructor(config) {
|
|
8528
|
+
this.config = config;
|
|
8529
|
+
}
|
|
8530
|
+
getBaseUrl() {
|
|
8531
|
+
return this.config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
8532
|
+
}
|
|
8533
|
+
async getToken() {
|
|
8534
|
+
if (this.accessToken) return this.accessToken;
|
|
8535
|
+
const clientId = this.config.extra?.oauthClientId || this.config.clientKey || "";
|
|
8536
|
+
const clientSecret = this.config.extra?.oauthClientSecret || this.config.apiKey || this.config.secretKey || "";
|
|
8537
|
+
const response = await fetch(`${this.getBaseUrl()}/pl/standard/user/oauth/authorize`, {
|
|
8538
|
+
method: "POST",
|
|
8539
|
+
headers: { "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8540
|
+
body: "grant_type=client_credentials"
|
|
8541
|
+
});
|
|
8542
|
+
const data = await response.json();
|
|
8543
|
+
if (!data?.access_token) throw new Error("Failed to get PayU access token");
|
|
8544
|
+
this.accessToken = data.access_token;
|
|
8545
|
+
return this.accessToken;
|
|
8546
|
+
}
|
|
8547
|
+
/** Ambil detail order PayU */
|
|
8548
|
+
async getOrder(orderId) {
|
|
8549
|
+
const token = await this.getToken();
|
|
8550
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8551
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8552
|
+
});
|
|
8553
|
+
return response.json();
|
|
8554
|
+
}
|
|
8555
|
+
/** Batalkan order PayU */
|
|
8556
|
+
async cancelOrder(orderId) {
|
|
8557
|
+
const token = await this.getToken();
|
|
8558
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8559
|
+
method: "DELETE",
|
|
8560
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8561
|
+
});
|
|
8562
|
+
return response.json();
|
|
8563
|
+
}
|
|
8564
|
+
/** Refund order PayU */
|
|
8565
|
+
async refundOrder(orderId, amount, description) {
|
|
8566
|
+
const token = await this.getToken();
|
|
8567
|
+
const body = { refund: { description: description || "Refund" } };
|
|
8568
|
+
if (amount) body.refund.amount = amount;
|
|
8569
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}/refunds`, {
|
|
8570
|
+
method: "POST",
|
|
8571
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8572
|
+
body: JSON.stringify(body)
|
|
8573
|
+
});
|
|
8574
|
+
return response.json();
|
|
8575
|
+
}
|
|
8576
|
+
};
|
|
8577
|
+
|
|
8578
|
+
// src/clients/braintree.ts
|
|
8579
|
+
var BraintreeClient = class {
|
|
8580
|
+
config;
|
|
8581
|
+
constructor(config) {
|
|
8582
|
+
this.config = config;
|
|
8583
|
+
}
|
|
8584
|
+
getBaseUrl() {
|
|
8585
|
+
const merchantId = this.config.merchantCode || this.config.merchantId || "";
|
|
8586
|
+
const base = this.config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
8587
|
+
return `${base}/merchants/${merchantId}`;
|
|
8588
|
+
}
|
|
8589
|
+
buildHeaders() {
|
|
8590
|
+
const publicKey = this.config.clientKey || this.config.extra?.publicKey || "";
|
|
8591
|
+
const privateKey = this.config.apiKey || this.config.secretKey || "";
|
|
8592
|
+
return {
|
|
8593
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
8594
|
+
"Content-Type": "application/json",
|
|
8595
|
+
"Braintree-Version": "2019-01-01"
|
|
8596
|
+
};
|
|
8597
|
+
}
|
|
8598
|
+
/** Generate Client Token untuk frontend Drop-in UI */
|
|
8599
|
+
async getClientToken(customerId) {
|
|
8600
|
+
const body = {};
|
|
8601
|
+
if (customerId) body.client_token = { customer_id: customerId };
|
|
8602
|
+
const response = await fetch(`${this.getBaseUrl()}/client_token`, {
|
|
8603
|
+
method: "POST",
|
|
8604
|
+
headers: this.buildHeaders(),
|
|
8605
|
+
body: JSON.stringify(body)
|
|
8606
|
+
});
|
|
8607
|
+
const data = await response.json();
|
|
8608
|
+
return data.clientToken || "";
|
|
8609
|
+
}
|
|
8610
|
+
/** Ambil detail transaction */
|
|
8611
|
+
async findTransaction(transactionId) {
|
|
8612
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}`, {
|
|
8613
|
+
method: "GET",
|
|
8614
|
+
headers: this.buildHeaders()
|
|
8615
|
+
});
|
|
8616
|
+
return response.json();
|
|
8617
|
+
}
|
|
8618
|
+
/** Refund transaction Braintree */
|
|
8619
|
+
async refundTransaction(transactionId, amount) {
|
|
8620
|
+
const body = {};
|
|
8621
|
+
if (amount) body.transaction = { amount: (amount / 100).toFixed(2) };
|
|
8622
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/refund`, {
|
|
8623
|
+
method: "POST",
|
|
8624
|
+
headers: this.buildHeaders(),
|
|
8625
|
+
body: JSON.stringify(body)
|
|
8626
|
+
});
|
|
8627
|
+
return response.json();
|
|
8628
|
+
}
|
|
8629
|
+
/** Void (batalkan) transaction sebelum settlement */
|
|
8630
|
+
async voidTransaction(transactionId) {
|
|
8631
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/void`, {
|
|
8632
|
+
method: "PUT",
|
|
8633
|
+
headers: this.buildHeaders(),
|
|
8634
|
+
body: "{}"
|
|
8635
|
+
});
|
|
8636
|
+
return response.json();
|
|
8637
|
+
}
|
|
8638
|
+
};
|
|
8639
|
+
|
|
8640
|
+
// src/clients/twocheckout.ts
|
|
8641
|
+
var TwoCheckoutClient = class {
|
|
8642
|
+
config;
|
|
8643
|
+
constructor(config) {
|
|
8644
|
+
this.config = config;
|
|
8645
|
+
}
|
|
8646
|
+
getBaseUrl() {
|
|
8647
|
+
return this.config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
8648
|
+
}
|
|
8649
|
+
buildHeaders() {
|
|
8650
|
+
const merchantCode = this.config.merchantCode || this.config.merchantId || "";
|
|
8651
|
+
const secretKey = this.config.apiKey || this.config.secretKey || "";
|
|
8652
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
8653
|
+
return {
|
|
8654
|
+
"X-Avangate-Authentication": header,
|
|
8655
|
+
"Content-Type": "application/json",
|
|
8656
|
+
"Accept": "application/json"
|
|
8657
|
+
};
|
|
8658
|
+
}
|
|
8659
|
+
/** Ambil detail order 2Checkout berdasarkan Reference Number */
|
|
8660
|
+
async getOrder(refNo) {
|
|
8661
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}`, {
|
|
8662
|
+
method: "GET",
|
|
8663
|
+
headers: this.buildHeaders()
|
|
8664
|
+
});
|
|
8665
|
+
return response.json();
|
|
8666
|
+
}
|
|
8667
|
+
/** Refund order 2Checkout */
|
|
8668
|
+
async refundOrder(refNo, amount, comment) {
|
|
8669
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}/refund`, {
|
|
8670
|
+
method: "POST",
|
|
8671
|
+
headers: this.buildHeaders(),
|
|
8672
|
+
body: JSON.stringify({ amount, comment: comment || "Refund", reason: "NOT_SATISFIED" })
|
|
8673
|
+
});
|
|
8674
|
+
return response.json();
|
|
8675
|
+
}
|
|
8676
|
+
/** Ambil detail subscription */
|
|
8677
|
+
async getSubscription(subscriptionRef) {
|
|
8678
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/subscriptions/${subscriptionRef}`, {
|
|
8679
|
+
method: "GET",
|
|
8680
|
+
headers: this.buildHeaders()
|
|
8681
|
+
});
|
|
8682
|
+
return response.json();
|
|
8683
|
+
}
|
|
8684
|
+
/** List semua orders merchant */
|
|
8685
|
+
async listOrders(page, limit) {
|
|
8686
|
+
const params = new URLSearchParams({
|
|
8687
|
+
Pagination: JSON.stringify({ Page: page || 1, Limit: limit || 10 })
|
|
8688
|
+
});
|
|
8689
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders?${params}`, {
|
|
8690
|
+
method: "GET",
|
|
8691
|
+
headers: this.buildHeaders()
|
|
8692
|
+
});
|
|
8693
|
+
return response.json();
|
|
8694
|
+
}
|
|
8695
|
+
};
|
|
8696
|
+
|
|
6155
8697
|
// src/core/manager.ts
|
|
6156
8698
|
var PaymentManager = class {
|
|
6157
8699
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -6167,6 +8709,14 @@ var PaymentManager = class {
|
|
|
6167
8709
|
this.registerProvider(new NicepayProvider());
|
|
6168
8710
|
this.registerProvider(new OyProvider());
|
|
6169
8711
|
this.registerProvider(new StripeProvider());
|
|
8712
|
+
this.registerProvider(new PaypalProvider());
|
|
8713
|
+
this.registerProvider(new AdyenProvider());
|
|
8714
|
+
this.registerProvider(new CheckoutComProvider());
|
|
8715
|
+
this.registerProvider(new RazorpayProvider());
|
|
8716
|
+
this.registerProvider(new SquareProvider());
|
|
8717
|
+
this.registerProvider(new PayuProvider());
|
|
8718
|
+
this.registerProvider(new BraintreeProvider());
|
|
8719
|
+
this.registerProvider(new TwoCheckoutProvider());
|
|
6170
8720
|
}
|
|
6171
8721
|
registerProvider(provider) {
|
|
6172
8722
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -6178,6 +8728,7 @@ var PaymentManager = class {
|
|
|
6178
8728
|
}
|
|
6179
8729
|
return provider;
|
|
6180
8730
|
}
|
|
8731
|
+
// ─── Indonesian Provider Getters ──────────────────────────────────────────
|
|
6181
8732
|
getMidtransProvider() {
|
|
6182
8733
|
return this.getProvider("midtrans");
|
|
6183
8734
|
}
|
|
@@ -6238,12 +8789,62 @@ var PaymentManager = class {
|
|
|
6238
8789
|
getOyClient(config) {
|
|
6239
8790
|
return new OyClient(config);
|
|
6240
8791
|
}
|
|
8792
|
+
// ─── International Provider Getters ─────────────────────────────────────
|
|
6241
8793
|
getStripeProvider() {
|
|
6242
8794
|
return this.getProvider("stripe");
|
|
6243
8795
|
}
|
|
6244
8796
|
getStripeClient(config) {
|
|
6245
8797
|
return new StripeClient(config);
|
|
6246
8798
|
}
|
|
8799
|
+
getPaypalProvider() {
|
|
8800
|
+
return this.getProvider("paypal");
|
|
8801
|
+
}
|
|
8802
|
+
getPaypalClient(config) {
|
|
8803
|
+
return new PaypalClient(config);
|
|
8804
|
+
}
|
|
8805
|
+
getAdyenProvider() {
|
|
8806
|
+
return this.getProvider("adyen");
|
|
8807
|
+
}
|
|
8808
|
+
getAdyenClient(config) {
|
|
8809
|
+
return new AdyenClient(config);
|
|
8810
|
+
}
|
|
8811
|
+
getCheckoutComProvider() {
|
|
8812
|
+
return this.getProvider("checkoutcom");
|
|
8813
|
+
}
|
|
8814
|
+
getCheckoutComClient(config) {
|
|
8815
|
+
return new CheckoutComClient(config);
|
|
8816
|
+
}
|
|
8817
|
+
getRazorpayProvider() {
|
|
8818
|
+
return this.getProvider("razorpay");
|
|
8819
|
+
}
|
|
8820
|
+
getRazorpayClient(config) {
|
|
8821
|
+
return new RazorpayClient(config);
|
|
8822
|
+
}
|
|
8823
|
+
getSquareProvider() {
|
|
8824
|
+
return this.getProvider("square");
|
|
8825
|
+
}
|
|
8826
|
+
getSquareClient(config) {
|
|
8827
|
+
return new SquareClient(config);
|
|
8828
|
+
}
|
|
8829
|
+
getPayuProvider() {
|
|
8830
|
+
return this.getProvider("payu");
|
|
8831
|
+
}
|
|
8832
|
+
getPayuClient(config) {
|
|
8833
|
+
return new PayuClient(config);
|
|
8834
|
+
}
|
|
8835
|
+
getBraintreeProvider() {
|
|
8836
|
+
return this.getProvider("braintree");
|
|
8837
|
+
}
|
|
8838
|
+
getBraintreeClient(config) {
|
|
8839
|
+
return new BraintreeClient(config);
|
|
8840
|
+
}
|
|
8841
|
+
getTwoCheckoutProvider() {
|
|
8842
|
+
return this.getProvider("twocheckout");
|
|
8843
|
+
}
|
|
8844
|
+
getTwoCheckoutClient(config) {
|
|
8845
|
+
return new TwoCheckoutClient(config);
|
|
8846
|
+
}
|
|
8847
|
+
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
6247
8848
|
async createInvoice(providerName, params, config) {
|
|
6248
8849
|
const provider = this.getProvider(providerName);
|
|
6249
8850
|
return provider.createInvoice(params, config);
|
|
@@ -6303,6 +8904,22 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6303
8904
|
sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
|
|
6304
8905
|
} else if (env.STRIPE_SANDBOX !== void 0) {
|
|
6305
8906
|
sandbox = env.STRIPE_SANDBOX === "true" || env.STRIPE_SANDBOX === "1";
|
|
8907
|
+
} else if (env.PAYPAL_SANDBOX !== void 0) {
|
|
8908
|
+
sandbox = env.PAYPAL_SANDBOX === "true" || env.PAYPAL_SANDBOX === "1";
|
|
8909
|
+
} else if (env.ADYEN_SANDBOX !== void 0) {
|
|
8910
|
+
sandbox = env.ADYEN_SANDBOX === "true" || env.ADYEN_SANDBOX === "1";
|
|
8911
|
+
} else if (env.CHECKOUTCOM_SANDBOX !== void 0) {
|
|
8912
|
+
sandbox = env.CHECKOUTCOM_SANDBOX === "true" || env.CHECKOUTCOM_SANDBOX === "1";
|
|
8913
|
+
} else if (env.RAZORPAY_SANDBOX !== void 0) {
|
|
8914
|
+
sandbox = env.RAZORPAY_SANDBOX === "true" || env.RAZORPAY_SANDBOX === "1";
|
|
8915
|
+
} else if (env.SQUARE_SANDBOX !== void 0) {
|
|
8916
|
+
sandbox = env.SQUARE_SANDBOX === "true" || env.SQUARE_SANDBOX === "1";
|
|
8917
|
+
} else if (env.PAYU_SANDBOX !== void 0) {
|
|
8918
|
+
sandbox = env.PAYU_SANDBOX === "true" || env.PAYU_SANDBOX === "1";
|
|
8919
|
+
} else if (env.BRAINTREE_SANDBOX !== void 0) {
|
|
8920
|
+
sandbox = env.BRAINTREE_SANDBOX === "true" || env.BRAINTREE_SANDBOX === "1";
|
|
8921
|
+
} else if (env.TWOCHECKOUT_SANDBOX !== void 0) {
|
|
8922
|
+
sandbox = env.TWOCHECKOUT_SANDBOX === "true" || env.TWOCHECKOUT_SANDBOX === "1";
|
|
6306
8923
|
} else {
|
|
6307
8924
|
sandbox = env.NODE_ENV !== "production";
|
|
6308
8925
|
}
|
|
@@ -6330,6 +8947,22 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6330
8947
|
apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
6331
8948
|
} else if (provider === "stripe") {
|
|
6332
8949
|
apiKey = env.STRIPE_SECRET_KEY || env.STRIPE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8950
|
+
} else if (provider === "paypal") {
|
|
8951
|
+
apiKey = env.PAYPAL_CLIENT_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8952
|
+
} else if (provider === "adyen") {
|
|
8953
|
+
apiKey = env.ADYEN_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8954
|
+
} else if (provider === "checkoutcom") {
|
|
8955
|
+
apiKey = env.CHECKOUTCOM_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8956
|
+
} else if (provider === "razorpay") {
|
|
8957
|
+
apiKey = env.RAZORPAY_KEY_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8958
|
+
} else if (provider === "square") {
|
|
8959
|
+
apiKey = env.SQUARE_ACCESS_TOKEN || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8960
|
+
} else if (provider === "payu") {
|
|
8961
|
+
apiKey = env.PAYU_MD5_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8962
|
+
} else if (provider === "braintree") {
|
|
8963
|
+
apiKey = env.BRAINTREE_PRIVATE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8964
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
8965
|
+
apiKey = env.TWOCHECKOUT_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
6333
8966
|
} else {
|
|
6334
8967
|
apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
|
|
6335
8968
|
}
|
|
@@ -6367,26 +9000,63 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
6367
9000
|
} else if (provider === "stripe") {
|
|
6368
9001
|
clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
|
|
6369
9002
|
merchantCode = merchantCode || clientKey || "stripe";
|
|
9003
|
+
} else if (provider === "paypal") {
|
|
9004
|
+
clientKey = clientKey || env.PAYPAL_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
|
|
9005
|
+
merchantCode = merchantCode || env.PAYPAL_CLIENT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9006
|
+
} else if (provider === "adyen") {
|
|
9007
|
+
clientKey = clientKey || env.ADYEN_CLIENT_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9008
|
+
merchantCode = merchantCode || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_CODE;
|
|
9009
|
+
merchantId = merchantId || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_ID;
|
|
9010
|
+
} else if (provider === "checkoutcom") {
|
|
9011
|
+
clientKey = clientKey || env.CHECKOUTCOM_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9012
|
+
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE;
|
|
9013
|
+
} else if (provider === "razorpay") {
|
|
9014
|
+
clientKey = clientKey || env.RAZORPAY_KEY_ID || env.BUAYAR_CLIENT_KEY;
|
|
9015
|
+
merchantCode = merchantCode || env.RAZORPAY_KEY_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9016
|
+
} else if (provider === "square") {
|
|
9017
|
+
clientKey = clientKey || env.SQUARE_APPLICATION_ID || env.BUAYAR_CLIENT_KEY;
|
|
9018
|
+
merchantCode = merchantCode || env.SQUARE_APPLICATION_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9019
|
+
} else if (provider === "payu") {
|
|
9020
|
+
merchantCode = merchantCode || env.PAYU_POS_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9021
|
+
merchantId = merchantId || env.PAYU_POS_ID;
|
|
9022
|
+
} else if (provider === "braintree") {
|
|
9023
|
+
clientKey = clientKey || env.BRAINTREE_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
9024
|
+
merchantCode = merchantCode || env.BRAINTREE_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
9025
|
+
merchantId = merchantId || env.BRAINTREE_MERCHANT_ID;
|
|
9026
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
9027
|
+
merchantCode = merchantCode || env.TWOCHECKOUT_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE;
|
|
9028
|
+
merchantId = merchantId || env.TWOCHECKOUT_MERCHANT_CODE;
|
|
6370
9029
|
} else {
|
|
6371
9030
|
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
6372
9031
|
}
|
|
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;
|
|
9032
|
+
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID || env.SQUARE_LOCATION_ID;
|
|
9033
|
+
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;
|
|
9034
|
+
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY || env.BRAINTREE_PRIVATE_KEY;
|
|
9035
|
+
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 || 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
9036
|
const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
|
|
6378
9037
|
const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
|
|
6379
9038
|
const extra = {
|
|
6380
9039
|
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
6381
|
-
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
9040
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
6382
9041
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
6383
9042
|
userId: env.FASPAY_USER_ID,
|
|
6384
9043
|
iMid: env.NICEPAY_IMID,
|
|
6385
9044
|
username: env.OY_USERNAME,
|
|
9045
|
+
hmacKey: env.ADYEN_HMAC_KEY,
|
|
9046
|
+
liveUrlPrefix: env.ADYEN_LIVE_URL_PREFIX,
|
|
9047
|
+
webhookId: env.PAYPAL_WEBHOOK_ID,
|
|
9048
|
+
merchantAccount: env.ADYEN_MERCHANT_ACCOUNT,
|
|
9049
|
+
md5Key: env.PAYU_MD5_KEY,
|
|
9050
|
+
oauthClientId: env.PAYU_OAUTH_CLIENT_ID,
|
|
9051
|
+
oauthClientSecret: env.PAYU_OAUTH_CLIENT_SECRET,
|
|
9052
|
+
locationId: env.SQUARE_LOCATION_ID,
|
|
9053
|
+
webhookSignatureKey: env.SQUARE_WEBHOOK_SIGNATURE_KEY,
|
|
9054
|
+
publicKey: env.BRAINTREE_PUBLIC_KEY || env.ADYEN_CLIENT_KEY,
|
|
9055
|
+
secretWord: env.TWOCHECKOUT_SECRET_WORD,
|
|
6386
9056
|
...customConfig?.extra
|
|
6387
9057
|
};
|
|
6388
9058
|
return {
|
|
6389
|
-
provider: provider === "oyindonesia" ? "oy" : provider,
|
|
9059
|
+
provider: provider === "oyindonesia" ? "oy" : provider === "2checkout" ? "twocheckout" : provider,
|
|
6390
9060
|
apiKey: apiKey || "",
|
|
6391
9061
|
serverKey: apiKey || "",
|
|
6392
9062
|
secretKey: secretKey || apiKey || "",
|
|
@@ -6424,7 +9094,7 @@ var Buayar = class {
|
|
|
6424
9094
|
this.config = resolveConfigFromEnv({ ...this.config, ...config });
|
|
6425
9095
|
}
|
|
6426
9096
|
/**
|
|
6427
|
-
* Dapatkan nama provider aktif
|
|
9097
|
+
* Dapatkan nama provider aktif
|
|
6428
9098
|
*/
|
|
6429
9099
|
get provider() {
|
|
6430
9100
|
return this.config.provider || "midtrans";
|
|
@@ -6473,10 +9143,37 @@ var Buayar = class {
|
|
|
6473
9143
|
async verifyWebhook(payload, headers, configOverride) {
|
|
6474
9144
|
const mergedConfig = { ...this.config, ...configOverride };
|
|
6475
9145
|
if (headers) {
|
|
6476
|
-
const
|
|
6477
|
-
if (
|
|
9146
|
+
const stripeSig = headers["stripe-signature"] || headers["Stripe-Signature"];
|
|
9147
|
+
if (stripeSig) {
|
|
9148
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9149
|
+
mergedConfig.extra.signatureHeader = Array.isArray(stripeSig) ? stripeSig[0] : stripeSig;
|
|
9150
|
+
}
|
|
9151
|
+
const ckoSig = headers["cko-signature"] || headers["Cko-Signature"];
|
|
9152
|
+
if (ckoSig) {
|
|
9153
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9154
|
+
mergedConfig.extra.signatureHeader = Array.isArray(ckoSig) ? ckoSig[0] : ckoSig;
|
|
9155
|
+
}
|
|
9156
|
+
const rzpSig = headers["x-razorpay-signature"] || headers["X-Razorpay-Signature"];
|
|
9157
|
+
if (rzpSig) {
|
|
9158
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9159
|
+
mergedConfig.extra.signatureHeader = Array.isArray(rzpSig) ? rzpSig[0] : rzpSig;
|
|
9160
|
+
}
|
|
9161
|
+
const squareSig = headers["x-square-hmacsha256-signature"] || headers["x-square-signature"];
|
|
9162
|
+
if (squareSig) {
|
|
9163
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9164
|
+
mergedConfig.extra.signatureHeader = Array.isArray(squareSig) ? squareSig[0] : squareSig;
|
|
9165
|
+
}
|
|
9166
|
+
const payuSig = headers["openpayu-signature"] || headers["OpenPayU-Signature"];
|
|
9167
|
+
if (payuSig) {
|
|
9168
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9169
|
+
mergedConfig.extra.signatureHeader = Array.isArray(payuSig) ? payuSig[0] : payuSig;
|
|
9170
|
+
}
|
|
9171
|
+
const btSig = headers["bt_signature"];
|
|
9172
|
+
const btPayload = headers["bt_payload"];
|
|
9173
|
+
if (btSig && btPayload) {
|
|
6478
9174
|
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
6479
|
-
mergedConfig.extra.
|
|
9175
|
+
mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
|
|
9176
|
+
mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
|
|
6480
9177
|
}
|
|
6481
9178
|
}
|
|
6482
9179
|
let providerName = configOverride?.provider || this.provider;
|
|
@@ -6501,8 +9198,26 @@ var Buayar = class {
|
|
|
6501
9198
|
providerName = "prismalink";
|
|
6502
9199
|
} else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
|
|
6503
9200
|
providerName = "stripe";
|
|
9201
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9202
|
+
providerName = "razorpay";
|
|
6504
9203
|
} else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
|
|
6505
9204
|
providerName = "xendit";
|
|
9205
|
+
} else if (payload.event_type && payload.resource && (payload.event_type.startsWith("PAYMENT.") || payload.event_type.startsWith("CHECKOUT.ORDER."))) {
|
|
9206
|
+
providerName = "paypal";
|
|
9207
|
+
} else if (payload.notificationItems || payload.merchantAccountCode && payload.pspReference && payload.eventCode) {
|
|
9208
|
+
providerName = "adyen";
|
|
9209
|
+
} else if (payload.type && payload.data?._links && (payload.type.startsWith("payment_") || payload.type.startsWith("refund_"))) {
|
|
9210
|
+
providerName = "checkoutcom";
|
|
9211
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9212
|
+
providerName = "razorpay";
|
|
9213
|
+
} else if (payload.type && payload.data?.object?.status && payload.merchant_id) {
|
|
9214
|
+
providerName = "square";
|
|
9215
|
+
} else if (payload.order && payload.order?.status && payload.order?.extOrderId) {
|
|
9216
|
+
providerName = "payu";
|
|
9217
|
+
} else if (payload.kind && payload.subject?.transaction) {
|
|
9218
|
+
providerName = "braintree";
|
|
9219
|
+
} else if (payload.HASH && payload.REFNOEXT && payload.IPN_PID) {
|
|
9220
|
+
providerName = "twocheckout";
|
|
6506
9221
|
}
|
|
6507
9222
|
}
|
|
6508
9223
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
@@ -6510,77 +9225,74 @@ var Buayar = class {
|
|
|
6510
9225
|
async handleWebhook(payload, headers, configOverride) {
|
|
6511
9226
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
6512
9227
|
}
|
|
9228
|
+
// ─── Indonesian Provider Client Getters ───────────────────────────────────
|
|
6513
9229
|
getMidtransClient(configOverride) {
|
|
6514
|
-
return new MidtransClient({
|
|
6515
|
-
...this.config,
|
|
6516
|
-
...configOverride
|
|
6517
|
-
});
|
|
9230
|
+
return new MidtransClient({ ...this.config, ...configOverride });
|
|
6518
9231
|
}
|
|
6519
9232
|
getDuitkuClient(configOverride) {
|
|
6520
|
-
return new DuitkuClient({
|
|
6521
|
-
...this.config,
|
|
6522
|
-
...configOverride
|
|
6523
|
-
});
|
|
9233
|
+
return new DuitkuClient({ ...this.config, ...configOverride });
|
|
6524
9234
|
}
|
|
6525
9235
|
getIpaymuClient(configOverride) {
|
|
6526
|
-
return new IpaymuClient({
|
|
6527
|
-
...this.config,
|
|
6528
|
-
...configOverride
|
|
6529
|
-
});
|
|
9236
|
+
return new IpaymuClient({ ...this.config, ...configOverride });
|
|
6530
9237
|
}
|
|
6531
9238
|
getXenditClient(configOverride) {
|
|
6532
|
-
return new XenditClient({
|
|
6533
|
-
...this.config,
|
|
6534
|
-
...configOverride
|
|
6535
|
-
});
|
|
9239
|
+
return new XenditClient({ ...this.config, ...configOverride });
|
|
6536
9240
|
}
|
|
6537
9241
|
getDokuClient(configOverride) {
|
|
6538
|
-
return new DokuClient({
|
|
6539
|
-
...this.config,
|
|
6540
|
-
...configOverride
|
|
6541
|
-
});
|
|
9242
|
+
return new DokuClient({ ...this.config, ...configOverride });
|
|
6542
9243
|
}
|
|
6543
9244
|
getPrismalinkClient(configOverride) {
|
|
6544
|
-
return new PrismalinkClient({
|
|
6545
|
-
...this.config,
|
|
6546
|
-
...configOverride
|
|
6547
|
-
});
|
|
9245
|
+
return new PrismalinkClient({ ...this.config, ...configOverride });
|
|
6548
9246
|
}
|
|
6549
9247
|
getFaspayClient(configOverride) {
|
|
6550
|
-
return new FaspayClient({
|
|
6551
|
-
...this.config,
|
|
6552
|
-
...configOverride
|
|
6553
|
-
});
|
|
9248
|
+
return new FaspayClient({ ...this.config, ...configOverride });
|
|
6554
9249
|
}
|
|
6555
9250
|
getFinpayClient(configOverride) {
|
|
6556
|
-
return new FinpayClient({
|
|
6557
|
-
...this.config,
|
|
6558
|
-
...configOverride
|
|
6559
|
-
});
|
|
9251
|
+
return new FinpayClient({ ...this.config, ...configOverride });
|
|
6560
9252
|
}
|
|
6561
9253
|
getNicepayClient(configOverride) {
|
|
6562
|
-
return new NicepayClient({
|
|
6563
|
-
...this.config,
|
|
6564
|
-
...configOverride
|
|
6565
|
-
});
|
|
9254
|
+
return new NicepayClient({ ...this.config, ...configOverride });
|
|
6566
9255
|
}
|
|
6567
9256
|
getOyClient(configOverride) {
|
|
6568
|
-
return new OyClient({
|
|
6569
|
-
...this.config,
|
|
6570
|
-
...configOverride
|
|
6571
|
-
});
|
|
9257
|
+
return new OyClient({ ...this.config, ...configOverride });
|
|
6572
9258
|
}
|
|
9259
|
+
// ─── International Provider Client Getters ────────────────────────────────
|
|
6573
9260
|
getStripeClient(configOverride) {
|
|
6574
|
-
return new StripeClient({
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
});
|
|
9261
|
+
return new StripeClient({ ...this.config, ...configOverride });
|
|
9262
|
+
}
|
|
9263
|
+
getPaypalClient(configOverride) {
|
|
9264
|
+
return new PaypalClient({ ...this.config, ...configOverride });
|
|
9265
|
+
}
|
|
9266
|
+
getAdyenClient(configOverride) {
|
|
9267
|
+
return new AdyenClient({ ...this.config, ...configOverride });
|
|
9268
|
+
}
|
|
9269
|
+
getCheckoutComClient(configOverride) {
|
|
9270
|
+
return new CheckoutComClient({ ...this.config, ...configOverride });
|
|
9271
|
+
}
|
|
9272
|
+
getRazorpayClient(configOverride) {
|
|
9273
|
+
return new RazorpayClient({ ...this.config, ...configOverride });
|
|
9274
|
+
}
|
|
9275
|
+
getSquareClient(configOverride) {
|
|
9276
|
+
return new SquareClient({ ...this.config, ...configOverride });
|
|
9277
|
+
}
|
|
9278
|
+
getPayuClient(configOverride) {
|
|
9279
|
+
return new PayuClient({ ...this.config, ...configOverride });
|
|
9280
|
+
}
|
|
9281
|
+
getBraintreeClient(configOverride) {
|
|
9282
|
+
return new BraintreeClient({ ...this.config, ...configOverride });
|
|
9283
|
+
}
|
|
9284
|
+
getTwoCheckoutClient(configOverride) {
|
|
9285
|
+
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
6578
9286
|
}
|
|
6579
9287
|
};
|
|
6580
9288
|
var buayar = new Buayar();
|
|
6581
9289
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6582
9290
|
0 && (module.exports = {
|
|
9291
|
+
AdyenClient,
|
|
9292
|
+
AdyenProvider,
|
|
6583
9293
|
BasePaymentProvider,
|
|
9294
|
+
BraintreeClient,
|
|
9295
|
+
BraintreeProvider,
|
|
6584
9296
|
Buayar,
|
|
6585
9297
|
CANONICAL_TO_DOKU,
|
|
6586
9298
|
CANONICAL_TO_DUITKU,
|
|
@@ -6594,6 +9306,8 @@ var buayar = new Buayar();
|
|
|
6594
9306
|
CANONICAL_TO_STRIPE,
|
|
6595
9307
|
CANONICAL_TO_XENDIT,
|
|
6596
9308
|
CORE_API_METHODS,
|
|
9309
|
+
CheckoutComClient,
|
|
9310
|
+
CheckoutComProvider,
|
|
6597
9311
|
DUITKU_TO_CANONICAL,
|
|
6598
9312
|
DokuClient,
|
|
6599
9313
|
DokuProvider,
|
|
@@ -6614,14 +9328,29 @@ var buayar = new Buayar();
|
|
|
6614
9328
|
OyClient,
|
|
6615
9329
|
OyProvider,
|
|
6616
9330
|
PaymentManager,
|
|
9331
|
+
PaypalClient,
|
|
9332
|
+
PaypalProvider,
|
|
9333
|
+
PayuClient,
|
|
9334
|
+
PayuProvider,
|
|
6617
9335
|
PrismalinkClient,
|
|
6618
9336
|
PrismalinkProvider,
|
|
9337
|
+
RazorpayClient,
|
|
9338
|
+
RazorpayProvider,
|
|
9339
|
+
SquareClient,
|
|
9340
|
+
SquareProvider,
|
|
6619
9341
|
StripeClient,
|
|
6620
9342
|
StripeProvider,
|
|
9343
|
+
TwoCheckoutClient,
|
|
9344
|
+
TwoCheckoutProvider,
|
|
6621
9345
|
XenditClient,
|
|
6622
9346
|
XenditProvider,
|
|
6623
9347
|
buayar,
|
|
9348
|
+
buildBraintreeBasicAuth,
|
|
6624
9349
|
buildCoreChargePayload,
|
|
9350
|
+
buildPaypalBasicAuth,
|
|
9351
|
+
buildPayuBasicAuth,
|
|
9352
|
+
buildRazorpayBasicAuth,
|
|
9353
|
+
buildTwoCheckoutAuth,
|
|
6625
9354
|
formatNicepayTimestamp,
|
|
6626
9355
|
generateDokuHeaders,
|
|
6627
9356
|
generateFaspaySignature,
|
|
@@ -6641,6 +9370,7 @@ var buayar = new Buayar();
|
|
|
6641
9370
|
paymentManager,
|
|
6642
9371
|
resolveConfigFromEnv,
|
|
6643
9372
|
safeCompare,
|
|
9373
|
+
serializePaypalParams,
|
|
6644
9374
|
serializeStripeParams,
|
|
6645
9375
|
sha256,
|
|
6646
9376
|
sha512,
|
|
@@ -6655,6 +9385,9 @@ var buayar = new Buayar();
|
|
|
6655
9385
|
toPrismalinkPaymentMethod,
|
|
6656
9386
|
toStripePaymentMethod,
|
|
6657
9387
|
toXenditPaymentMethod,
|
|
9388
|
+
verifyAdyenWebhook,
|
|
9389
|
+
verifyBraintreeWebhook,
|
|
9390
|
+
verifyCheckoutComWebhook,
|
|
6658
9391
|
verifyDokuWebhookSignature,
|
|
6659
9392
|
verifyDuitkuCallbackSignature,
|
|
6660
9393
|
verifyFaspaySignature,
|
|
@@ -6662,7 +9395,12 @@ var buayar = new Buayar();
|
|
|
6662
9395
|
verifyIpaymuCallback,
|
|
6663
9396
|
verifyNicepayWebhook,
|
|
6664
9397
|
verifyOyWebhook,
|
|
9398
|
+
verifyPaypalWebhookSimple,
|
|
9399
|
+
verifyPayuWebhook,
|
|
6665
9400
|
verifyPrismalinkSignature,
|
|
9401
|
+
verifyRazorpayWebhook,
|
|
9402
|
+
verifySquareWebhook,
|
|
6666
9403
|
verifyStripeWebhook,
|
|
9404
|
+
verifyTwoCheckoutWebhook,
|
|
6667
9405
|
verifyXenditWebhookToken
|
|
6668
9406
|
});
|