@crediblemark/buayar 0.2.0 → 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/README.md +12 -2
- package/dist/index.d.mts +383 -2
- package/dist/index.d.ts +383 -2
- package/dist/index.js +3772 -541
- package/dist/index.mjs +3736 -541
- 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,
|
|
@@ -41,8 +45,11 @@ __export(index_exports, {
|
|
|
41
45
|
CANONICAL_TO_NICEPAY: () => CANONICAL_TO_NICEPAY,
|
|
42
46
|
CANONICAL_TO_OY: () => CANONICAL_TO_OY,
|
|
43
47
|
CANONICAL_TO_PRISMALINK: () => CANONICAL_TO_PRISMALINK,
|
|
48
|
+
CANONICAL_TO_STRIPE: () => CANONICAL_TO_STRIPE,
|
|
44
49
|
CANONICAL_TO_XENDIT: () => CANONICAL_TO_XENDIT,
|
|
45
50
|
CORE_API_METHODS: () => CORE_API_METHODS,
|
|
51
|
+
CheckoutComClient: () => CheckoutComClient,
|
|
52
|
+
CheckoutComProvider: () => CheckoutComProvider,
|
|
46
53
|
DUITKU_TO_CANONICAL: () => DUITKU_TO_CANONICAL,
|
|
47
54
|
DokuClient: () => DokuClient,
|
|
48
55
|
DokuProvider: () => DokuProvider,
|
|
@@ -63,12 +70,29 @@ __export(index_exports, {
|
|
|
63
70
|
OyClient: () => OyClient,
|
|
64
71
|
OyProvider: () => OyProvider,
|
|
65
72
|
PaymentManager: () => PaymentManager,
|
|
73
|
+
PaypalClient: () => PaypalClient,
|
|
74
|
+
PaypalProvider: () => PaypalProvider,
|
|
75
|
+
PayuClient: () => PayuClient,
|
|
76
|
+
PayuProvider: () => PayuProvider,
|
|
66
77
|
PrismalinkClient: () => PrismalinkClient,
|
|
67
78
|
PrismalinkProvider: () => PrismalinkProvider,
|
|
79
|
+
RazorpayClient: () => RazorpayClient,
|
|
80
|
+
RazorpayProvider: () => RazorpayProvider,
|
|
81
|
+
SquareClient: () => SquareClient,
|
|
82
|
+
SquareProvider: () => SquareProvider,
|
|
83
|
+
StripeClient: () => StripeClient,
|
|
84
|
+
StripeProvider: () => StripeProvider,
|
|
85
|
+
TwoCheckoutClient: () => TwoCheckoutClient,
|
|
86
|
+
TwoCheckoutProvider: () => TwoCheckoutProvider,
|
|
68
87
|
XenditClient: () => XenditClient,
|
|
69
88
|
XenditProvider: () => XenditProvider,
|
|
70
89
|
buayar: () => buayar,
|
|
90
|
+
buildBraintreeBasicAuth: () => buildBraintreeBasicAuth,
|
|
71
91
|
buildCoreChargePayload: () => buildCoreChargePayload,
|
|
92
|
+
buildPaypalBasicAuth: () => buildPaypalBasicAuth,
|
|
93
|
+
buildPayuBasicAuth: () => buildPayuBasicAuth,
|
|
94
|
+
buildRazorpayBasicAuth: () => buildRazorpayBasicAuth,
|
|
95
|
+
buildTwoCheckoutAuth: () => buildTwoCheckoutAuth,
|
|
72
96
|
formatNicepayTimestamp: () => formatNicepayTimestamp,
|
|
73
97
|
generateDokuHeaders: () => generateDokuHeaders,
|
|
74
98
|
generateFaspaySignature: () => generateFaspaySignature,
|
|
@@ -88,6 +112,8 @@ __export(index_exports, {
|
|
|
88
112
|
paymentManager: () => paymentManager,
|
|
89
113
|
resolveConfigFromEnv: () => resolveConfigFromEnv,
|
|
90
114
|
safeCompare: () => safeCompare,
|
|
115
|
+
serializePaypalParams: () => serializePaypalParams,
|
|
116
|
+
serializeStripeParams: () => serializeStripeParams,
|
|
91
117
|
sha256: () => sha256,
|
|
92
118
|
sha512: () => sha512,
|
|
93
119
|
toCanonicalPaymentMethod: () => toCanonicalPaymentMethod,
|
|
@@ -99,7 +125,11 @@ __export(index_exports, {
|
|
|
99
125
|
toNicepayPaymentMethod: () => toNicepayPaymentMethod,
|
|
100
126
|
toOyPaymentMethod: () => toOyPaymentMethod,
|
|
101
127
|
toPrismalinkPaymentMethod: () => toPrismalinkPaymentMethod,
|
|
128
|
+
toStripePaymentMethod: () => toStripePaymentMethod,
|
|
102
129
|
toXenditPaymentMethod: () => toXenditPaymentMethod,
|
|
130
|
+
verifyAdyenWebhook: () => verifyAdyenWebhook,
|
|
131
|
+
verifyBraintreeWebhook: () => verifyBraintreeWebhook,
|
|
132
|
+
verifyCheckoutComWebhook: () => verifyCheckoutComWebhook,
|
|
103
133
|
verifyDokuWebhookSignature: () => verifyDokuWebhookSignature,
|
|
104
134
|
verifyDuitkuCallbackSignature: () => verifyDuitkuCallbackSignature,
|
|
105
135
|
verifyFaspaySignature: () => verifyFaspaySignature,
|
|
@@ -107,7 +137,13 @@ __export(index_exports, {
|
|
|
107
137
|
verifyIpaymuCallback: () => verifyIpaymuCallback,
|
|
108
138
|
verifyNicepayWebhook: () => verifyNicepayWebhook,
|
|
109
139
|
verifyOyWebhook: () => verifyOyWebhook,
|
|
140
|
+
verifyPaypalWebhookSimple: () => verifyPaypalWebhookSimple,
|
|
141
|
+
verifyPayuWebhook: () => verifyPayuWebhook,
|
|
110
142
|
verifyPrismalinkSignature: () => verifyPrismalinkSignature,
|
|
143
|
+
verifyRazorpayWebhook: () => verifyRazorpayWebhook,
|
|
144
|
+
verifySquareWebhook: () => verifySquareWebhook,
|
|
145
|
+
verifyStripeWebhook: () => verifyStripeWebhook,
|
|
146
|
+
verifyTwoCheckoutWebhook: () => verifyTwoCheckoutWebhook,
|
|
111
147
|
verifyXenditWebhookToken: () => verifyXenditWebhookToken
|
|
112
148
|
});
|
|
113
149
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -395,6 +431,17 @@ var CANONICAL_TO_OY = {
|
|
|
395
431
|
alfamart: { type: "cstore", channel: "alfamart" },
|
|
396
432
|
indomaret: { type: "cstore", channel: "indomaret" }
|
|
397
433
|
};
|
|
434
|
+
var CANONICAL_TO_STRIPE = {
|
|
435
|
+
credit_card: "card",
|
|
436
|
+
qris: "qris",
|
|
437
|
+
gopay_qris: "qris",
|
|
438
|
+
shopeepay_qris: "qris",
|
|
439
|
+
bca_va: "customer_balance",
|
|
440
|
+
mandiri_va: "customer_balance",
|
|
441
|
+
bni_va: "customer_balance",
|
|
442
|
+
bri_va: "customer_balance",
|
|
443
|
+
permata_va: "customer_balance"
|
|
444
|
+
};
|
|
398
445
|
function toDuitkuPaymentMethod(code) {
|
|
399
446
|
if (!code) return void 0;
|
|
400
447
|
const lower = code.toLowerCase().trim();
|
|
@@ -482,6 +529,14 @@ function toOyPaymentMethod(code) {
|
|
|
482
529
|
}
|
|
483
530
|
return void 0;
|
|
484
531
|
}
|
|
532
|
+
function toStripePaymentMethod(code) {
|
|
533
|
+
if (!code) return void 0;
|
|
534
|
+
const lower = code.toLowerCase().trim();
|
|
535
|
+
if (CANONICAL_TO_STRIPE[lower]) {
|
|
536
|
+
return CANONICAL_TO_STRIPE[lower];
|
|
537
|
+
}
|
|
538
|
+
return lower;
|
|
539
|
+
}
|
|
485
540
|
function toCanonicalPaymentMethod(provider, code) {
|
|
486
541
|
if (!code) return "";
|
|
487
542
|
const upper = code.toUpperCase().trim();
|
|
@@ -489,7 +544,7 @@ function toCanonicalPaymentMethod(provider, code) {
|
|
|
489
544
|
if (provider.toLowerCase() === "duitku" && DUITKU_TO_CANONICAL[upper]) {
|
|
490
545
|
return DUITKU_TO_CANONICAL[upper];
|
|
491
546
|
}
|
|
492
|
-
if (CANONICAL_TO_MIDTRANS[lower] || CANONICAL_TO_DUITKU[lower] || CANONICAL_TO_IPAYMU[lower] || CANONICAL_TO_XENDIT[lower] || CANONICAL_TO_DOKU[lower] || CANONICAL_TO_PRISMALINK[lower] || CANONICAL_TO_FASPAY[lower] || CANONICAL_TO_FINPAY[lower] || CANONICAL_TO_NICEPAY[lower] || CANONICAL_TO_OY[lower]) {
|
|
547
|
+
if (CANONICAL_TO_MIDTRANS[lower] || CANONICAL_TO_DUITKU[lower] || CANONICAL_TO_IPAYMU[lower] || CANONICAL_TO_XENDIT[lower] || CANONICAL_TO_DOKU[lower] || CANONICAL_TO_PRISMALINK[lower] || CANONICAL_TO_FASPAY[lower] || CANONICAL_TO_FINPAY[lower] || CANONICAL_TO_NICEPAY[lower] || CANONICAL_TO_OY[lower] || CANONICAL_TO_STRIPE[lower]) {
|
|
493
548
|
return lower;
|
|
494
549
|
}
|
|
495
550
|
return lower;
|
|
@@ -5000,225 +5055,2770 @@ var OyProvider = class extends BasePaymentProvider {
|
|
|
5000
5055
|
}
|
|
5001
5056
|
};
|
|
5002
5057
|
|
|
5003
|
-
// src/
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
}
|
|
5019
|
-
/**
|
|
5020
|
-
* Request helper generic dengan kalkulasi signature Duitku otomatis
|
|
5021
|
-
*/
|
|
5022
|
-
async request(method, endpoint, body = {}, options) {
|
|
5023
|
-
const baseUrl = options?.baseUrl === "api" ? this.getApiBaseUrl() : this.getPassportBaseUrl();
|
|
5024
|
-
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;
|
|
5025
|
-
const timestamp = Date.now().toString();
|
|
5026
|
-
const headerSignature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
5027
|
-
const headers = {
|
|
5028
|
-
"Content-Type": "application/json",
|
|
5029
|
-
"Accept": "application/json",
|
|
5030
|
-
"x-duitku-signature": headerSignature,
|
|
5031
|
-
"x-duitku-timestamp": timestamp,
|
|
5032
|
-
"x-duitku-merchantcode": this.merchantCode,
|
|
5033
|
-
...options?.customHeaders
|
|
5034
|
-
};
|
|
5035
|
-
const fetchOptions = {
|
|
5036
|
-
method,
|
|
5037
|
-
headers
|
|
5038
|
-
};
|
|
5039
|
-
if (method === "POST" && body) {
|
|
5040
|
-
fetchOptions.body = JSON.stringify(body);
|
|
5041
|
-
}
|
|
5042
|
-
const response = await fetch(url, fetchOptions);
|
|
5043
|
-
const text = await response.text();
|
|
5044
|
-
let data = null;
|
|
5045
|
-
try {
|
|
5046
|
-
data = JSON.parse(text);
|
|
5047
|
-
} catch (e) {
|
|
5058
|
+
// src/providers/stripe/signature.ts
|
|
5059
|
+
function serializeStripeParams(obj, prefix = "") {
|
|
5060
|
+
const pairs = [];
|
|
5061
|
+
if (obj === null || obj === void 0) {
|
|
5062
|
+
return "";
|
|
5063
|
+
}
|
|
5064
|
+
for (const key of Object.keys(obj)) {
|
|
5065
|
+
const val = obj[key];
|
|
5066
|
+
if (val === void 0 || val === null) continue;
|
|
5067
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
5068
|
+
if (typeof val === "object" && !(val instanceof Date)) {
|
|
5069
|
+
const nested = serializeStripeParams(val, fullKey);
|
|
5070
|
+
if (nested) pairs.push(nested);
|
|
5071
|
+
} else {
|
|
5072
|
+
pairs.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(val))}`);
|
|
5048
5073
|
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5074
|
+
}
|
|
5075
|
+
return pairs.join("&");
|
|
5076
|
+
}
|
|
5077
|
+
function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleranceSeconds = 300) {
|
|
5078
|
+
if (!signatureHeader || !webhookSecret) {
|
|
5079
|
+
return true;
|
|
5080
|
+
}
|
|
5081
|
+
const items = signatureHeader.split(",");
|
|
5082
|
+
let timestamp = "";
|
|
5083
|
+
const signatures = [];
|
|
5084
|
+
for (const item of items) {
|
|
5085
|
+
const [key, value] = item.trim().split("=");
|
|
5086
|
+
if (key === "t") {
|
|
5087
|
+
timestamp = value;
|
|
5088
|
+
} else if (key === "v1") {
|
|
5089
|
+
signatures.push(value);
|
|
5051
5090
|
}
|
|
5052
|
-
return data || text;
|
|
5053
5091
|
}
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
5057
|
-
*/
|
|
5058
|
-
async checkTransaction(merchantOrderId) {
|
|
5059
|
-
const { bodySignature } = getDuitkuStatusSignatures(
|
|
5060
|
-
this.merchantCode,
|
|
5061
|
-
merchantOrderId,
|
|
5062
|
-
this.apiKey
|
|
5063
|
-
);
|
|
5064
|
-
return this.request(
|
|
5065
|
-
"POST",
|
|
5066
|
-
"/api/merchant/transactionStatus",
|
|
5067
|
-
{
|
|
5068
|
-
merchantCode: this.merchantCode,
|
|
5069
|
-
merchantOrderId,
|
|
5070
|
-
signature: bodySignature
|
|
5071
|
-
},
|
|
5072
|
-
{ baseUrl: "api" }
|
|
5073
|
-
);
|
|
5092
|
+
if (!timestamp || signatures.length === 0) {
|
|
5093
|
+
return false;
|
|
5074
5094
|
}
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
signature
|
|
5087
|
-
});
|
|
5095
|
+
const payloadString = typeof rawPayload === "string" ? rawPayload : JSON.stringify(rawPayload);
|
|
5096
|
+
const signedPayload = `${timestamp}.${payloadString}`;
|
|
5097
|
+
const expectedSignature = hmacSha256(signedPayload, webhookSecret);
|
|
5098
|
+
return signatures.some((sig) => safeCompare(sig.toLowerCase(), expectedSignature.toLowerCase()));
|
|
5099
|
+
}
|
|
5100
|
+
|
|
5101
|
+
// src/providers/stripe/provider.ts
|
|
5102
|
+
var StripeProvider = class extends BasePaymentProvider {
|
|
5103
|
+
name = "stripe";
|
|
5104
|
+
getBaseUrl() {
|
|
5105
|
+
return "https://api.stripe.com/v1";
|
|
5088
5106
|
}
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
const
|
|
5095
|
-
const
|
|
5107
|
+
async createInvoice(params, config) {
|
|
5108
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5109
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5110
|
+
const integerAmount = Math.round(amount);
|
|
5111
|
+
const stripeMethod = toStripePaymentMethod(params.paymentMethod);
|
|
5112
|
+
const isDirect = !!params.paymentMethod;
|
|
5113
|
+
const baseUrl = this.getBaseUrl();
|
|
5114
|
+
const headers = {
|
|
5115
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
5116
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
5117
|
+
};
|
|
5096
5118
|
try {
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5119
|
+
if (isDirect) {
|
|
5120
|
+
const url = `${baseUrl}/payment_intents`;
|
|
5121
|
+
const payload = {
|
|
5122
|
+
amount: integerAmount,
|
|
5123
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
5124
|
+
description: productDetails,
|
|
5125
|
+
receipt_email: customer?.email,
|
|
5126
|
+
payment_method_types: [stripeMethod || "card"],
|
|
5127
|
+
metadata: {
|
|
5128
|
+
order_id: orderId,
|
|
5129
|
+
customer_name: customer?.name
|
|
5130
|
+
},
|
|
5131
|
+
...params.providerParams
|
|
5132
|
+
};
|
|
5133
|
+
const response = await fetch(url, {
|
|
5134
|
+
method: "POST",
|
|
5135
|
+
headers,
|
|
5136
|
+
body: serializeStripeParams(payload)
|
|
5137
|
+
});
|
|
5138
|
+
const text = await response.text();
|
|
5139
|
+
let data = null;
|
|
5140
|
+
try {
|
|
5141
|
+
data = JSON.parse(text);
|
|
5142
|
+
} catch (e) {
|
|
5143
|
+
}
|
|
5144
|
+
if (!response.ok || !data || data.error) {
|
|
5145
|
+
return {
|
|
5146
|
+
success: false,
|
|
5147
|
+
provider: "stripe",
|
|
5148
|
+
orderId,
|
|
5149
|
+
amount: integerAmount,
|
|
5150
|
+
rawResponse: data,
|
|
5151
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
return {
|
|
5155
|
+
success: true,
|
|
5156
|
+
provider: "stripe",
|
|
5157
|
+
orderId,
|
|
5158
|
+
amount: data.amount ? Number(data.amount) : integerAmount,
|
|
5159
|
+
reference: data.id,
|
|
5160
|
+
paymentCode: data.client_secret,
|
|
5161
|
+
rawResponse: data
|
|
5162
|
+
};
|
|
5163
|
+
} else {
|
|
5164
|
+
const url = `${baseUrl}/checkout/sessions`;
|
|
5165
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5166
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5167
|
+
const payload = {
|
|
5168
|
+
mode: "payment",
|
|
5169
|
+
client_reference_id: orderId,
|
|
5170
|
+
customer_email: customer?.email,
|
|
5171
|
+
line_items: [
|
|
5172
|
+
{
|
|
5173
|
+
price_data: {
|
|
5174
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
5175
|
+
product_data: {
|
|
5176
|
+
name: productDetails
|
|
5177
|
+
},
|
|
5178
|
+
unit_amount: integerAmount
|
|
5179
|
+
},
|
|
5180
|
+
quantity: 1
|
|
5181
|
+
}
|
|
5182
|
+
],
|
|
5183
|
+
metadata: {
|
|
5184
|
+
order_id: orderId
|
|
5185
|
+
},
|
|
5186
|
+
success_url: successUrl,
|
|
5187
|
+
cancel_url: cancelUrl,
|
|
5188
|
+
...params.providerParams
|
|
5189
|
+
};
|
|
5190
|
+
const response = await fetch(url, {
|
|
5191
|
+
method: "POST",
|
|
5192
|
+
headers,
|
|
5193
|
+
body: serializeStripeParams(payload)
|
|
5194
|
+
});
|
|
5195
|
+
const text = await response.text();
|
|
5196
|
+
let data = null;
|
|
5197
|
+
try {
|
|
5198
|
+
data = JSON.parse(text);
|
|
5199
|
+
} catch (e) {
|
|
5200
|
+
}
|
|
5201
|
+
if (!response.ok || !data || data.error) {
|
|
5202
|
+
return {
|
|
5203
|
+
success: false,
|
|
5204
|
+
provider: "stripe",
|
|
5205
|
+
orderId,
|
|
5206
|
+
amount: integerAmount,
|
|
5207
|
+
rawResponse: data,
|
|
5208
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5209
|
+
};
|
|
5210
|
+
}
|
|
5211
|
+
return {
|
|
5212
|
+
success: true,
|
|
5213
|
+
provider: "stripe",
|
|
5214
|
+
orderId: data.client_reference_id || orderId,
|
|
5215
|
+
amount: data.amount_total ? Number(data.amount_total) : integerAmount,
|
|
5216
|
+
reference: data.id,
|
|
5217
|
+
paymentUrl: data.url,
|
|
5218
|
+
rawResponse: data
|
|
5219
|
+
};
|
|
5220
|
+
}
|
|
5111
5221
|
} catch (e) {
|
|
5112
5222
|
return {
|
|
5113
5223
|
success: false,
|
|
5224
|
+
provider: "stripe",
|
|
5225
|
+
orderId,
|
|
5226
|
+
amount: integerAmount,
|
|
5114
5227
|
rawResponse: null,
|
|
5115
|
-
error: e.message || "Failed to
|
|
5228
|
+
error: e.message || "Failed to make request to Stripe API"
|
|
5116
5229
|
};
|
|
5117
5230
|
}
|
|
5118
5231
|
}
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
const
|
|
5124
|
-
const
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5232
|
+
async verifyCallback(body, config) {
|
|
5233
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
5234
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
5235
|
+
const isValid = verifyStripeWebhook(body, signatureHeader, webhookSecret);
|
|
5236
|
+
const eventType = body.type || "";
|
|
5237
|
+
const obj = body.data?.object || body;
|
|
5238
|
+
const orderId = obj.metadata?.order_id || obj.client_reference_id || obj.id || "";
|
|
5239
|
+
const amount = obj.amount_total || obj.amount || 0;
|
|
5240
|
+
const paymentStatus = (obj.payment_status || obj.status || "").toLowerCase();
|
|
5241
|
+
const isPaid = eventType === "checkout.session.completed" && (paymentStatus === "paid" || paymentStatus === "complete") || eventType === "payment_intent.succeeded" && paymentStatus === "succeeded" || eventType === "charge.succeeded" && (paymentStatus === "succeeded" || paymentStatus === "paid") || paymentStatus === "paid" || paymentStatus === "succeeded";
|
|
5242
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5243
|
+
const isExpired = paymentStatus === "expired" || eventType === "checkout.session.expired";
|
|
5244
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5245
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5246
|
+
return {
|
|
5247
|
+
isValid,
|
|
5248
|
+
provider: "stripe",
|
|
5249
|
+
orderId: String(orderId),
|
|
5250
|
+
amount: Number(amount) || 0,
|
|
5251
|
+
status,
|
|
5252
|
+
isPaid,
|
|
5253
|
+
isPending,
|
|
5254
|
+
isFailed,
|
|
5255
|
+
isExpired,
|
|
5256
|
+
statusCode: eventType || paymentStatus,
|
|
5257
|
+
rawPayload: body
|
|
5258
|
+
};
|
|
5259
|
+
}
|
|
5260
|
+
async getPaymentMethods(params, config) {
|
|
5261
|
+
const staticMethods = [
|
|
5128
5262
|
{
|
|
5129
|
-
|
|
5130
|
-
|
|
5263
|
+
paymentMethod: "credit_card",
|
|
5264
|
+
code: "credit_card",
|
|
5265
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, JCB, Amex)",
|
|
5266
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5267
|
+
totalFee: "2.9% + IDR 2,000",
|
|
5268
|
+
category: "Kartu Kredit"
|
|
5131
5269
|
},
|
|
5132
|
-
{ baseUrl: "api" }
|
|
5133
|
-
);
|
|
5134
|
-
}
|
|
5135
|
-
/**
|
|
5136
|
-
* Validasi nama pemilik rekening bank sebelum eksekusi transfer (Bank Account Inquiry)
|
|
5137
|
-
*/
|
|
5138
|
-
async inquiryBankAccount(bankCode, bankAccount) {
|
|
5139
|
-
const timestamp = Date.now().toString();
|
|
5140
|
-
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
5141
|
-
return this.request(
|
|
5142
|
-
"POST",
|
|
5143
|
-
"/api/disbursement/inquiry",
|
|
5144
5270
|
{
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5271
|
+
paymentMethod: "qris",
|
|
5272
|
+
code: "qris",
|
|
5273
|
+
paymentName: "QRIS (Indonesia)",
|
|
5274
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5275
|
+
totalFee: "0.7%",
|
|
5276
|
+
category: "QRIS"
|
|
5149
5277
|
},
|
|
5150
|
-
{
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5278
|
+
{
|
|
5279
|
+
paymentMethod: "bca_va",
|
|
5280
|
+
code: "bca_va",
|
|
5281
|
+
paymentName: "BCA Virtual Account (Bank Transfer)",
|
|
5282
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5283
|
+
totalFee: "IDR 4,000",
|
|
5284
|
+
category: "Virtual Account"
|
|
5285
|
+
},
|
|
5286
|
+
{
|
|
5287
|
+
paymentMethod: "mandiri_va",
|
|
5288
|
+
code: "mandiri_va",
|
|
5289
|
+
paymentName: "Mandiri Virtual Account (Bank Transfer)",
|
|
5290
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5291
|
+
totalFee: "IDR 4,000",
|
|
5292
|
+
category: "Virtual Account"
|
|
5293
|
+
},
|
|
5294
|
+
{
|
|
5295
|
+
paymentMethod: "bni_va",
|
|
5296
|
+
code: "bni_va",
|
|
5297
|
+
paymentName: "BNI Virtual Account (Bank Transfer)",
|
|
5298
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5299
|
+
totalFee: "IDR 4,000",
|
|
5300
|
+
category: "Virtual Account"
|
|
5301
|
+
},
|
|
5302
|
+
{
|
|
5303
|
+
paymentMethod: "bri_va",
|
|
5304
|
+
code: "bri_va",
|
|
5305
|
+
paymentName: "BRI Virtual Account (Bank Transfer)",
|
|
5306
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5307
|
+
totalFee: "IDR 4,000",
|
|
5308
|
+
category: "Virtual Account"
|
|
5309
|
+
},
|
|
5310
|
+
{
|
|
5311
|
+
paymentMethod: "permata_va",
|
|
5312
|
+
code: "permata_va",
|
|
5313
|
+
paymentName: "Permata Virtual Account (Bank Transfer)",
|
|
5314
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5315
|
+
totalFee: "IDR 4,000",
|
|
5316
|
+
category: "Virtual Account"
|
|
5317
|
+
}
|
|
5318
|
+
];
|
|
5319
|
+
const categories = {};
|
|
5320
|
+
for (const item of staticMethods) {
|
|
5321
|
+
if (!categories[item.category]) {
|
|
5322
|
+
categories[item.category] = [];
|
|
5323
|
+
}
|
|
5324
|
+
categories[item.category].push(item);
|
|
5325
|
+
}
|
|
5326
|
+
return {
|
|
5327
|
+
success: true,
|
|
5328
|
+
provider: "stripe",
|
|
5329
|
+
methods: staticMethods,
|
|
5330
|
+
categories,
|
|
5331
|
+
rawResponse: staticMethods
|
|
5332
|
+
};
|
|
5333
|
+
}
|
|
5334
|
+
async checkTransaction(params, config) {
|
|
5335
|
+
const { merchantOrderId } = params;
|
|
5336
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5337
|
+
const baseUrl = this.getBaseUrl();
|
|
5338
|
+
let endpoint = `/checkout/sessions/${encodeURIComponent(merchantOrderId)}`;
|
|
5339
|
+
if (merchantOrderId.startsWith("pi_")) {
|
|
5340
|
+
endpoint = `/payment_intents/${encodeURIComponent(merchantOrderId)}`;
|
|
5341
|
+
}
|
|
5342
|
+
const url = `${baseUrl}${endpoint}`;
|
|
5343
|
+
const headers = {
|
|
5344
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
5345
|
+
"Accept": "application/json"
|
|
5346
|
+
};
|
|
5347
|
+
try {
|
|
5348
|
+
const response = await fetch(url, {
|
|
5349
|
+
method: "GET",
|
|
5350
|
+
headers
|
|
5351
|
+
});
|
|
5352
|
+
const text = await response.text();
|
|
5353
|
+
let data = null;
|
|
5354
|
+
try {
|
|
5355
|
+
data = JSON.parse(text);
|
|
5356
|
+
} catch (e) {
|
|
5357
|
+
}
|
|
5358
|
+
if (!response.ok || !data || data.error) {
|
|
5359
|
+
return {
|
|
5360
|
+
success: false,
|
|
5361
|
+
provider: "stripe",
|
|
5362
|
+
orderId: merchantOrderId,
|
|
5363
|
+
reference: "",
|
|
5364
|
+
amount: 0,
|
|
5365
|
+
statusCode: response.status.toString(),
|
|
5366
|
+
status: "failed",
|
|
5367
|
+
isPaid: false,
|
|
5368
|
+
isPending: false,
|
|
5369
|
+
isFailed: true,
|
|
5370
|
+
isExpired: false,
|
|
5371
|
+
statusMessage: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5372
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5373
|
+
rawResponse: data
|
|
5374
|
+
};
|
|
5375
|
+
}
|
|
5376
|
+
const paymentStatus = (data.payment_status || data.status || "").toLowerCase();
|
|
5377
|
+
const isPaid = paymentStatus === "paid" || paymentStatus === "succeeded" || paymentStatus === "complete";
|
|
5378
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5379
|
+
const isExpired = paymentStatus === "expired";
|
|
5380
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5381
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5382
|
+
return {
|
|
5383
|
+
success: true,
|
|
5384
|
+
provider: "stripe",
|
|
5385
|
+
orderId: data.metadata?.order_id || data.client_reference_id || data.id || merchantOrderId,
|
|
5386
|
+
reference: data.id || "",
|
|
5387
|
+
amount: data.amount_total ? Number(data.amount_total) : data.amount ? Number(data.amount) : 0,
|
|
5388
|
+
statusCode: paymentStatus,
|
|
5389
|
+
status,
|
|
5390
|
+
isPaid,
|
|
5391
|
+
isPending,
|
|
5392
|
+
isFailed,
|
|
5393
|
+
isExpired,
|
|
5394
|
+
statusMessage: paymentStatus,
|
|
5395
|
+
paymentType: data.payment_method_types?.[0] || "card",
|
|
5396
|
+
transactionTime: data.created ? new Date(data.created * 1e3) : void 0,
|
|
5397
|
+
rawResponse: data
|
|
5398
|
+
};
|
|
5399
|
+
} catch (e) {
|
|
5400
|
+
return {
|
|
5401
|
+
success: false,
|
|
5402
|
+
provider: "stripe",
|
|
5403
|
+
orderId: merchantOrderId,
|
|
5404
|
+
reference: "",
|
|
5405
|
+
amount: 0,
|
|
5406
|
+
statusCode: "ERROR",
|
|
5407
|
+
status: "failed",
|
|
5408
|
+
isPaid: false,
|
|
5409
|
+
isPending: false,
|
|
5410
|
+
isFailed: true,
|
|
5411
|
+
isExpired: false,
|
|
5412
|
+
statusMessage: e.message || "Failed to check transaction status in Stripe",
|
|
5413
|
+
error: e.message || "Failed to check transaction status in Stripe",
|
|
5414
|
+
rawResponse: null
|
|
5415
|
+
};
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
};
|
|
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
|
+
|
|
7405
|
+
// src/clients/duitku.ts
|
|
7406
|
+
var DuitkuClient = class {
|
|
7407
|
+
merchantCode;
|
|
7408
|
+
apiKey;
|
|
7409
|
+
sandbox;
|
|
7410
|
+
constructor(config) {
|
|
7411
|
+
this.merchantCode = config.merchantCode || "";
|
|
7412
|
+
this.apiKey = config.apiKey || config.serverKey || "";
|
|
7413
|
+
this.sandbox = !!config.sandbox;
|
|
7414
|
+
}
|
|
7415
|
+
getPassportBaseUrl() {
|
|
7416
|
+
return this.sandbox ? "https://sandbox.duitku.com/webapi" : "https://passport.duitku.com/webapi";
|
|
7417
|
+
}
|
|
7418
|
+
getApiBaseUrl() {
|
|
7419
|
+
return this.sandbox ? "https://api-sandbox.duitku.com" : "https://api-prod.duitku.com";
|
|
7420
|
+
}
|
|
7421
|
+
/**
|
|
7422
|
+
* Request helper generic dengan kalkulasi signature Duitku otomatis
|
|
7423
|
+
*/
|
|
7424
|
+
async request(method, endpoint, body = {}, options) {
|
|
7425
|
+
const baseUrl = options?.baseUrl === "api" ? this.getApiBaseUrl() : this.getPassportBaseUrl();
|
|
7426
|
+
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;
|
|
7427
|
+
const timestamp = Date.now().toString();
|
|
7428
|
+
const headerSignature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7429
|
+
const headers = {
|
|
7430
|
+
"Content-Type": "application/json",
|
|
7431
|
+
"Accept": "application/json",
|
|
7432
|
+
"x-duitku-signature": headerSignature,
|
|
7433
|
+
"x-duitku-timestamp": timestamp,
|
|
7434
|
+
"x-duitku-merchantcode": this.merchantCode,
|
|
7435
|
+
...options?.customHeaders
|
|
7436
|
+
};
|
|
7437
|
+
const fetchOptions = {
|
|
7438
|
+
method,
|
|
7439
|
+
headers
|
|
7440
|
+
};
|
|
7441
|
+
if (method === "POST" && body) {
|
|
7442
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7443
|
+
}
|
|
7444
|
+
const response = await fetch(url, fetchOptions);
|
|
7445
|
+
const text = await response.text();
|
|
7446
|
+
let data = null;
|
|
7447
|
+
try {
|
|
7448
|
+
data = JSON.parse(text);
|
|
7449
|
+
} catch (e) {
|
|
7450
|
+
}
|
|
7451
|
+
if (!response.ok) {
|
|
7452
|
+
throw new Error(data?.Message || data?.statusMessage || data?.responseMessage || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7453
|
+
}
|
|
7454
|
+
return data || text;
|
|
7455
|
+
}
|
|
7456
|
+
// ─── TRANSACTIONS & PAYMENT METHODS ──────────────────────────────────────────
|
|
7457
|
+
/**
|
|
7458
|
+
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
7459
|
+
*/
|
|
7460
|
+
async checkTransaction(merchantOrderId) {
|
|
7461
|
+
const { bodySignature } = getDuitkuStatusSignatures(
|
|
7462
|
+
this.merchantCode,
|
|
7463
|
+
merchantOrderId,
|
|
7464
|
+
this.apiKey
|
|
7465
|
+
);
|
|
7466
|
+
return this.request(
|
|
7467
|
+
"POST",
|
|
7468
|
+
"/api/merchant/transactionStatus",
|
|
7469
|
+
{
|
|
7470
|
+
merchantCode: this.merchantCode,
|
|
7471
|
+
merchantOrderId,
|
|
7472
|
+
signature: bodySignature
|
|
7473
|
+
},
|
|
7474
|
+
{ baseUrl: "api" }
|
|
7475
|
+
);
|
|
7476
|
+
}
|
|
7477
|
+
/**
|
|
7478
|
+
* Ambil daftar channel pembayaran aktif dan kalkulasi fee dinamis
|
|
7479
|
+
*/
|
|
7480
|
+
async getPaymentMethods(amount = 1e4) {
|
|
7481
|
+
const integerAmount = Math.round(amount);
|
|
7482
|
+
const datetime = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
7483
|
+
const signature = getDuitkuPaymentMethodsSignature(this.merchantCode, integerAmount, datetime, this.apiKey);
|
|
7484
|
+
return this.request("POST", "/api/merchant/paymentmethod/getpaymentmethod", {
|
|
7485
|
+
merchantcode: this.merchantCode,
|
|
7486
|
+
amount: integerAmount,
|
|
7487
|
+
datetime,
|
|
7488
|
+
signature
|
|
7489
|
+
});
|
|
7490
|
+
}
|
|
7491
|
+
// ─── DISBURSEMENT & BALANCE INQUIRY ──────────────────────────────────────────
|
|
7492
|
+
/**
|
|
7493
|
+
* Cek saldo merchant (Balance Inquiry)
|
|
7494
|
+
*/
|
|
7495
|
+
async checkBalance() {
|
|
7496
|
+
const timestamp = Date.now().toString();
|
|
7497
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7498
|
+
try {
|
|
7499
|
+
const data = await this.request(
|
|
7500
|
+
"POST",
|
|
7501
|
+
"/api/merchant/checkBalance",
|
|
7502
|
+
{
|
|
7503
|
+
merchantCode: this.merchantCode,
|
|
7504
|
+
signature
|
|
7505
|
+
},
|
|
7506
|
+
{ baseUrl: "api" }
|
|
7507
|
+
);
|
|
7508
|
+
return {
|
|
7509
|
+
success: data.responseCode === "00" || data.statusCode === "00",
|
|
7510
|
+
balance: data.balance ? Number(data.balance) : void 0,
|
|
7511
|
+
rawResponse: data
|
|
7512
|
+
};
|
|
7513
|
+
} catch (e) {
|
|
7514
|
+
return {
|
|
7515
|
+
success: false,
|
|
7516
|
+
rawResponse: null,
|
|
7517
|
+
error: e.message || "Failed to check Duitku merchant balance"
|
|
7518
|
+
};
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
/**
|
|
7522
|
+
* Mengambil daftar bank yang didukung untuk transfer / penarikan dana
|
|
7523
|
+
*/
|
|
7524
|
+
async listBanks() {
|
|
7525
|
+
const timestamp = Date.now().toString();
|
|
7526
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7527
|
+
return this.request(
|
|
7528
|
+
"POST",
|
|
7529
|
+
"/api/disbursement/listBank",
|
|
7530
|
+
{
|
|
7531
|
+
merchantCode: this.merchantCode,
|
|
7532
|
+
signature
|
|
7533
|
+
},
|
|
7534
|
+
{ baseUrl: "api" }
|
|
7535
|
+
);
|
|
7536
|
+
}
|
|
7537
|
+
/**
|
|
7538
|
+
* Validasi nama pemilik rekening bank sebelum eksekusi transfer (Bank Account Inquiry)
|
|
7539
|
+
*/
|
|
7540
|
+
async inquiryBankAccount(bankCode, bankAccount) {
|
|
7541
|
+
const timestamp = Date.now().toString();
|
|
7542
|
+
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
7543
|
+
return this.request(
|
|
7544
|
+
"POST",
|
|
7545
|
+
"/api/disbursement/inquiry",
|
|
7546
|
+
{
|
|
7547
|
+
merchantCode: this.merchantCode,
|
|
7548
|
+
bankCode,
|
|
7549
|
+
bankAccount,
|
|
7550
|
+
signature
|
|
7551
|
+
},
|
|
7552
|
+
{ baseUrl: "api" }
|
|
7553
|
+
);
|
|
7554
|
+
}
|
|
7555
|
+
/**
|
|
7556
|
+
* Eksekusi transfer dana / payout (Disbursement Transfer)
|
|
7557
|
+
*/
|
|
7558
|
+
async disburse(params) {
|
|
7559
|
+
const integerAmount = Math.round(params.amount);
|
|
7560
|
+
const signature = sha256(
|
|
7561
|
+
this.merchantCode + params.merchantOrderId + params.bankCode + params.bankAccount + integerAmount.toString() + this.apiKey
|
|
7562
|
+
);
|
|
7563
|
+
const payload = {
|
|
7564
|
+
merchantCode: this.merchantCode,
|
|
7565
|
+
merchantOrderId: params.merchantOrderId,
|
|
7566
|
+
bankCode: params.bankCode,
|
|
7567
|
+
bankAccount: params.bankAccount,
|
|
7568
|
+
amount: integerAmount,
|
|
7569
|
+
purpose: params.purpose,
|
|
7570
|
+
senderName: params.senderName || "",
|
|
7571
|
+
senderPhone: params.senderPhone || "",
|
|
7572
|
+
callbackUrl: params.callbackUrl || "",
|
|
5171
7573
|
signature
|
|
5172
7574
|
};
|
|
5173
|
-
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
7575
|
+
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
7576
|
+
}
|
|
7577
|
+
/**
|
|
7578
|
+
* Cek status disbursement berdasarkan merchant order ID
|
|
7579
|
+
*/
|
|
7580
|
+
async checkDisbursementStatus(merchantOrderId) {
|
|
7581
|
+
const signature = sha256(this.merchantCode + merchantOrderId + this.apiKey);
|
|
7582
|
+
return this.request(
|
|
7583
|
+
"POST",
|
|
7584
|
+
"/api/disbursement/checkStatus",
|
|
7585
|
+
{
|
|
7586
|
+
merchantCode: this.merchantCode,
|
|
7587
|
+
merchantOrderId,
|
|
7588
|
+
signature
|
|
7589
|
+
},
|
|
7590
|
+
{ baseUrl: "api" }
|
|
7591
|
+
);
|
|
7592
|
+
}
|
|
7593
|
+
};
|
|
7594
|
+
|
|
7595
|
+
// src/clients/ipaymu.ts
|
|
7596
|
+
var IpaymuClient = class {
|
|
7597
|
+
va;
|
|
7598
|
+
apiKey;
|
|
7599
|
+
sandbox;
|
|
7600
|
+
constructor(config) {
|
|
7601
|
+
this.va = config.merchantCode || config.merchantId || "";
|
|
7602
|
+
this.apiKey = config.apiKey || config.serverKey || "";
|
|
7603
|
+
this.sandbox = !!config.sandbox;
|
|
7604
|
+
}
|
|
7605
|
+
getBaseUrl() {
|
|
7606
|
+
return this.sandbox ? "https://sandbox.ipaymu.com/api/v2" : "https://my.ipaymu.com/api/v2";
|
|
7607
|
+
}
|
|
7608
|
+
/**
|
|
7609
|
+
* Helper request bertanda tangan iPaymu v2
|
|
7610
|
+
*/
|
|
7611
|
+
async request(method, endpoint, body) {
|
|
7612
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7613
|
+
const { signature, timestamp } = generateIpaymuSignature(method, this.va, this.apiKey, body);
|
|
7614
|
+
const headers = {
|
|
7615
|
+
"Content-Type": "application/json",
|
|
7616
|
+
"Accept": "application/json",
|
|
7617
|
+
"va": this.va,
|
|
7618
|
+
"signature": signature,
|
|
7619
|
+
"timestamp": timestamp
|
|
7620
|
+
};
|
|
7621
|
+
const fetchOptions = {
|
|
7622
|
+
method,
|
|
7623
|
+
headers
|
|
7624
|
+
};
|
|
7625
|
+
if (method === "POST" && body) {
|
|
7626
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7627
|
+
}
|
|
7628
|
+
const response = await fetch(url, fetchOptions);
|
|
7629
|
+
const text = await response.text();
|
|
7630
|
+
let data = null;
|
|
7631
|
+
try {
|
|
7632
|
+
data = JSON.parse(text);
|
|
7633
|
+
} catch (e) {
|
|
7634
|
+
}
|
|
7635
|
+
if (!response.ok) {
|
|
7636
|
+
throw new Error(data?.Message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7637
|
+
}
|
|
7638
|
+
return data;
|
|
7639
|
+
}
|
|
7640
|
+
/**
|
|
7641
|
+
* Cek saldo merchant iPaymu
|
|
7642
|
+
*/
|
|
7643
|
+
async checkBalance() {
|
|
7644
|
+
try {
|
|
7645
|
+
const payload = { account: this.va };
|
|
7646
|
+
const data = await this.request("POST", "/balance", payload);
|
|
7647
|
+
const success = data.Status === 200 || data.status === 200;
|
|
7648
|
+
const balance = data.Data?.MerchantBalance ? Number(data.Data.MerchantBalance) : void 0;
|
|
7649
|
+
return {
|
|
7650
|
+
success,
|
|
7651
|
+
balance,
|
|
7652
|
+
rawResponse: data
|
|
7653
|
+
};
|
|
7654
|
+
} catch (e) {
|
|
7655
|
+
return {
|
|
7656
|
+
success: false,
|
|
7657
|
+
rawResponse: null,
|
|
7658
|
+
error: e.message || "Failed to check iPaymu balance"
|
|
7659
|
+
};
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
/**
|
|
7663
|
+
* Cek detail transaksi iPaymu
|
|
7664
|
+
*/
|
|
7665
|
+
async checkTransaction(transactionId) {
|
|
7666
|
+
return this.request("POST", "/transaction", { transactionId });
|
|
7667
|
+
}
|
|
7668
|
+
};
|
|
7669
|
+
|
|
7670
|
+
// src/clients/xendit.ts
|
|
7671
|
+
var XenditClient = class {
|
|
7672
|
+
apiKey;
|
|
7673
|
+
constructor(config) {
|
|
7674
|
+
this.apiKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
7675
|
+
}
|
|
7676
|
+
getBaseUrl() {
|
|
7677
|
+
return "https://api.xendit.co";
|
|
7678
|
+
}
|
|
7679
|
+
/**
|
|
7680
|
+
* HTTP Request helper bertanda tangan Basic Auth Xendit
|
|
7681
|
+
*/
|
|
7682
|
+
async request(method, endpoint, body) {
|
|
7683
|
+
const url = endpoint.startsWith("http") ? endpoint : `${this.getBaseUrl()}${endpoint}`;
|
|
7684
|
+
const authHeader = getXenditAuthHeader(this.apiKey);
|
|
7685
|
+
const headers = {
|
|
7686
|
+
"Content-Type": "application/json",
|
|
7687
|
+
"Accept": "application/json",
|
|
7688
|
+
"Authorization": authHeader
|
|
7689
|
+
};
|
|
7690
|
+
const fetchOptions = {
|
|
7691
|
+
method,
|
|
7692
|
+
headers
|
|
7693
|
+
};
|
|
7694
|
+
if ((method === "POST" || method === "PATCH") && body) {
|
|
7695
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7696
|
+
}
|
|
7697
|
+
const response = await fetch(url, fetchOptions);
|
|
7698
|
+
const text = await response.text();
|
|
7699
|
+
let data = null;
|
|
7700
|
+
try {
|
|
7701
|
+
data = JSON.parse(text);
|
|
7702
|
+
} catch (e) {
|
|
7703
|
+
}
|
|
7704
|
+
if (!response.ok) {
|
|
7705
|
+
throw new Error(data?.message || data?.error_code || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7706
|
+
}
|
|
7707
|
+
return data;
|
|
7708
|
+
}
|
|
7709
|
+
/**
|
|
7710
|
+
* Cek Saldo Merchant Xendit
|
|
7711
|
+
*/
|
|
7712
|
+
async checkBalance(accountType = "CASH") {
|
|
7713
|
+
try {
|
|
7714
|
+
const data = await this.request("GET", `/balance?account_type=${accountType}`);
|
|
7715
|
+
return {
|
|
7716
|
+
success: data.balance !== void 0,
|
|
7717
|
+
balance: data.balance !== void 0 ? Number(data.balance) : void 0,
|
|
7718
|
+
rawResponse: data
|
|
7719
|
+
};
|
|
7720
|
+
} catch (e) {
|
|
7721
|
+
return {
|
|
7722
|
+
success: false,
|
|
7723
|
+
rawResponse: null,
|
|
7724
|
+
error: e.message || "Failed to check Xendit balance"
|
|
7725
|
+
};
|
|
7726
|
+
}
|
|
7727
|
+
}
|
|
7728
|
+
/**
|
|
7729
|
+
* Memaksa sebuah invoice kadaluwarsa (Expire Invoice)
|
|
7730
|
+
*/
|
|
7731
|
+
async expireInvoice(invoiceId) {
|
|
7732
|
+
return this.request("POST", `/invoices/${invoiceId}/expire!`);
|
|
7733
|
+
}
|
|
7734
|
+
/**
|
|
7735
|
+
* Eksekusi transfer dana / disbursement
|
|
7736
|
+
*/
|
|
7737
|
+
async createDisbursement(params) {
|
|
7738
|
+
return this.request("POST", "/disbursements", {
|
|
7739
|
+
external_id: params.externalId,
|
|
7740
|
+
bank_code: params.bankCode,
|
|
7741
|
+
account_holder_name: params.accountHolderName,
|
|
7742
|
+
account_number: params.accountNumber,
|
|
7743
|
+
description: params.description,
|
|
7744
|
+
amount: Math.round(params.amount)
|
|
7745
|
+
});
|
|
7746
|
+
}
|
|
7747
|
+
};
|
|
7748
|
+
|
|
7749
|
+
// src/clients/doku.ts
|
|
7750
|
+
var DokuClient = class {
|
|
7751
|
+
clientId;
|
|
7752
|
+
secretKey;
|
|
7753
|
+
sandbox;
|
|
7754
|
+
constructor(config) {
|
|
7755
|
+
this.clientId = config.merchantCode || config.clientId || config.clientKey || "";
|
|
7756
|
+
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
7757
|
+
this.sandbox = !!config.sandbox;
|
|
7758
|
+
}
|
|
7759
|
+
getBaseUrl() {
|
|
7760
|
+
return this.sandbox ? "https://api-sandbox.doku.com" : "https://api.doku.com";
|
|
7761
|
+
}
|
|
7762
|
+
/**
|
|
7763
|
+
* Helper request bertanda tangan DOKU Jokul v2
|
|
7764
|
+
*/
|
|
7765
|
+
async request(method, endpoint, body) {
|
|
7766
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7767
|
+
const headers = generateDokuHeaders(this.clientId, this.secretKey, endpoint, body);
|
|
7768
|
+
const fetchOptions = {
|
|
7769
|
+
method,
|
|
7770
|
+
headers: {
|
|
7771
|
+
"Content-Type": "application/json",
|
|
7772
|
+
...headers
|
|
7773
|
+
}
|
|
7774
|
+
};
|
|
7775
|
+
if (method === "POST" && body) {
|
|
7776
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7777
|
+
}
|
|
7778
|
+
const response = await fetch(url, fetchOptions);
|
|
7779
|
+
const text = await response.text();
|
|
7780
|
+
let data = null;
|
|
7781
|
+
try {
|
|
7782
|
+
data = JSON.parse(text);
|
|
7783
|
+
} catch (e) {
|
|
7784
|
+
}
|
|
7785
|
+
if (!response.ok) {
|
|
7786
|
+
throw new Error(data?.error?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7787
|
+
}
|
|
7788
|
+
return data;
|
|
5174
7789
|
}
|
|
5175
7790
|
/**
|
|
5176
|
-
* Cek status
|
|
7791
|
+
* Cek status transaksi pesanan di DOKU
|
|
5177
7792
|
*/
|
|
5178
|
-
async
|
|
5179
|
-
|
|
5180
|
-
return this.request(
|
|
5181
|
-
"POST",
|
|
5182
|
-
"/api/disbursement/checkStatus",
|
|
5183
|
-
{
|
|
5184
|
-
merchantCode: this.merchantCode,
|
|
5185
|
-
merchantOrderId,
|
|
5186
|
-
signature
|
|
5187
|
-
},
|
|
5188
|
-
{ baseUrl: "api" }
|
|
5189
|
-
);
|
|
7793
|
+
async checkTransaction(invoiceNumber) {
|
|
7794
|
+
return this.request("GET", `/orders/v1/status/${invoiceNumber}`);
|
|
5190
7795
|
}
|
|
5191
7796
|
};
|
|
5192
7797
|
|
|
5193
|
-
// src/clients/
|
|
5194
|
-
var
|
|
5195
|
-
|
|
5196
|
-
|
|
7798
|
+
// src/clients/prismalink.ts
|
|
7799
|
+
var PrismalinkClient = class {
|
|
7800
|
+
merchantId;
|
|
7801
|
+
secretKey;
|
|
5197
7802
|
sandbox;
|
|
5198
7803
|
constructor(config) {
|
|
5199
|
-
this.
|
|
5200
|
-
this.
|
|
7804
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7805
|
+
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
5201
7806
|
this.sandbox = !!config.sandbox;
|
|
5202
7807
|
}
|
|
5203
7808
|
getBaseUrl() {
|
|
5204
|
-
return this.sandbox ? "https://sandbox.
|
|
7809
|
+
return this.sandbox ? "https://sandbox-api.prismalink.co.id" : "https://api.prismalink.co.id";
|
|
5205
7810
|
}
|
|
5206
7811
|
/**
|
|
5207
|
-
* Helper
|
|
7812
|
+
* Helper HTTP Request ke API PrismaLink
|
|
5208
7813
|
*/
|
|
5209
7814
|
async request(method, endpoint, body) {
|
|
5210
7815
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
5211
|
-
const { signature, timestamp } = generateIpaymuSignature(method, this.va, this.apiKey, body);
|
|
5212
|
-
const headers = {
|
|
5213
|
-
"Content-Type": "application/json",
|
|
5214
|
-
"Accept": "application/json",
|
|
5215
|
-
"va": this.va,
|
|
5216
|
-
"signature": signature,
|
|
5217
|
-
"timestamp": timestamp
|
|
5218
|
-
};
|
|
5219
7816
|
const fetchOptions = {
|
|
5220
7817
|
method,
|
|
5221
|
-
headers
|
|
7818
|
+
headers: {
|
|
7819
|
+
"Content-Type": "application/json",
|
|
7820
|
+
"Accept": "application/json"
|
|
7821
|
+
}
|
|
5222
7822
|
};
|
|
5223
7823
|
if (method === "POST" && body) {
|
|
5224
7824
|
fetchOptions.body = JSON.stringify(body);
|
|
@@ -5231,68 +7831,165 @@ var IpaymuClient = class {
|
|
|
5231
7831
|
} catch (e) {
|
|
5232
7832
|
}
|
|
5233
7833
|
if (!response.ok) {
|
|
5234
|
-
throw new Error(data?.
|
|
7834
|
+
throw new Error(data?.message || data?.response_message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5235
7835
|
}
|
|
5236
7836
|
return data;
|
|
5237
7837
|
}
|
|
5238
7838
|
/**
|
|
5239
|
-
* Cek
|
|
7839
|
+
* Cek status transaksi pesanan di PrismaLink
|
|
5240
7840
|
*/
|
|
5241
|
-
async
|
|
7841
|
+
async checkTransaction(orderId) {
|
|
7842
|
+
const signature = generatePrismalinkSignature(this.merchantId, orderId, 0, this.secretKey);
|
|
7843
|
+
return this.request("POST", "/api/v1/payment/status", {
|
|
7844
|
+
merchant_id: this.merchantId,
|
|
7845
|
+
order_id: orderId,
|
|
7846
|
+
signature
|
|
7847
|
+
});
|
|
7848
|
+
}
|
|
7849
|
+
};
|
|
7850
|
+
|
|
7851
|
+
// src/clients/faspay.ts
|
|
7852
|
+
var FaspayClient = class {
|
|
7853
|
+
merchantId;
|
|
7854
|
+
userId;
|
|
7855
|
+
password;
|
|
7856
|
+
sandbox;
|
|
7857
|
+
constructor(config) {
|
|
7858
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7859
|
+
this.userId = config.clientKey || config.userId || config.extra?.userId || this.merchantId;
|
|
7860
|
+
this.password = config.apiKey || config.password || config.serverKey || config.secretKey || "";
|
|
7861
|
+
this.sandbox = !!config.sandbox;
|
|
7862
|
+
}
|
|
7863
|
+
getBaseUrl() {
|
|
7864
|
+
return this.sandbox ? "https://sandbox.faspay.co.id" : "https://web.faspay.co.id";
|
|
7865
|
+
}
|
|
7866
|
+
/**
|
|
7867
|
+
* Helper HTTP Request ke endpoint Faspay
|
|
7868
|
+
*/
|
|
7869
|
+
async request(endpoint, payload) {
|
|
7870
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7871
|
+
const response = await fetch(url, {
|
|
7872
|
+
method: "POST",
|
|
7873
|
+
headers: {
|
|
7874
|
+
"Content-Type": "application/json",
|
|
7875
|
+
"Accept": "application/json"
|
|
7876
|
+
},
|
|
7877
|
+
body: JSON.stringify(payload)
|
|
7878
|
+
});
|
|
7879
|
+
const text = await response.text();
|
|
7880
|
+
let data = null;
|
|
5242
7881
|
try {
|
|
5243
|
-
|
|
5244
|
-
const data = await this.request("POST", "/balance", payload);
|
|
5245
|
-
const success = data.Status === 200 || data.status === 200;
|
|
5246
|
-
const balance = data.Data?.MerchantBalance ? Number(data.Data.MerchantBalance) : void 0;
|
|
5247
|
-
return {
|
|
5248
|
-
success,
|
|
5249
|
-
balance,
|
|
5250
|
-
rawResponse: data
|
|
5251
|
-
};
|
|
7882
|
+
data = JSON.parse(text);
|
|
5252
7883
|
} catch (e) {
|
|
5253
|
-
return {
|
|
5254
|
-
success: false,
|
|
5255
|
-
rawResponse: null,
|
|
5256
|
-
error: e.message || "Failed to check iPaymu balance"
|
|
5257
|
-
};
|
|
5258
7884
|
}
|
|
7885
|
+
if (!response.ok) {
|
|
7886
|
+
throw new Error(data?.response_desc || data?.response_message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7887
|
+
}
|
|
7888
|
+
return data;
|
|
5259
7889
|
}
|
|
5260
7890
|
/**
|
|
5261
|
-
* Cek
|
|
7891
|
+
* Cek status pembayaran tagihan Faspay
|
|
5262
7892
|
*/
|
|
5263
|
-
async checkTransaction(
|
|
5264
|
-
|
|
7893
|
+
async checkTransaction(billNo) {
|
|
7894
|
+
const signature = generateFaspaySignature(this.userId, this.password, billNo);
|
|
7895
|
+
return this.request("/cvr/100004/10", {
|
|
7896
|
+
request: "Inquiry Payment Status",
|
|
7897
|
+
merchant_id: this.merchantId,
|
|
7898
|
+
bill_no: billNo,
|
|
7899
|
+
signature
|
|
7900
|
+
});
|
|
7901
|
+
}
|
|
7902
|
+
/**
|
|
7903
|
+
* Batalkan tagihan pembayaran Faspay
|
|
7904
|
+
*/
|
|
7905
|
+
async cancelTransaction(billNo, paymentChannel) {
|
|
7906
|
+
const signature = generateFaspaySignature(this.userId, this.password, billNo);
|
|
7907
|
+
return this.request("/cvr/100005/10", {
|
|
7908
|
+
request: "Cancel Transaction",
|
|
7909
|
+
merchant_id: this.merchantId,
|
|
7910
|
+
bill_no: billNo,
|
|
7911
|
+
payment_channel: paymentChannel,
|
|
7912
|
+
signature
|
|
7913
|
+
});
|
|
5265
7914
|
}
|
|
5266
7915
|
};
|
|
5267
7916
|
|
|
5268
|
-
// src/clients/
|
|
5269
|
-
var
|
|
5270
|
-
|
|
7917
|
+
// src/clients/finpay.ts
|
|
7918
|
+
var FinpayClient = class {
|
|
7919
|
+
merchantId;
|
|
7920
|
+
merchantKey;
|
|
7921
|
+
sandbox;
|
|
5271
7922
|
constructor(config) {
|
|
5272
|
-
this.
|
|
7923
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7924
|
+
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
7925
|
+
this.sandbox = !!config.sandbox;
|
|
5273
7926
|
}
|
|
5274
7927
|
getBaseUrl() {
|
|
5275
|
-
return "https://
|
|
7928
|
+
return this.sandbox ? "https://sandbox.finpay.co.id" : "https://api.finpay.id";
|
|
5276
7929
|
}
|
|
5277
7930
|
/**
|
|
5278
|
-
* HTTP Request
|
|
7931
|
+
* Helper HTTP Request ke Finpay API
|
|
5279
7932
|
*/
|
|
5280
|
-
async request(
|
|
5281
|
-
const url =
|
|
5282
|
-
const
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
7933
|
+
async request(endpoint, payload) {
|
|
7934
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7935
|
+
const response = await fetch(url, {
|
|
7936
|
+
method: "POST",
|
|
7937
|
+
headers: {
|
|
7938
|
+
"Content-Type": "application/json",
|
|
7939
|
+
"Accept": "application/json"
|
|
7940
|
+
},
|
|
7941
|
+
body: JSON.stringify(payload)
|
|
7942
|
+
});
|
|
7943
|
+
const text = await response.text();
|
|
7944
|
+
let data = null;
|
|
7945
|
+
try {
|
|
7946
|
+
data = JSON.parse(text);
|
|
7947
|
+
} catch (e) {
|
|
5294
7948
|
}
|
|
5295
|
-
|
|
7949
|
+
if (!response.ok) {
|
|
7950
|
+
throw new Error(data?.response_desc || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7951
|
+
}
|
|
7952
|
+
return data;
|
|
7953
|
+
}
|
|
7954
|
+
/**
|
|
7955
|
+
* Cek status transaksi pembayaran Finpay
|
|
7956
|
+
*/
|
|
7957
|
+
async checkTransaction(orderId) {
|
|
7958
|
+
const signature = generateFinpaySignature(this.merchantId, orderId, 0, this.merchantKey);
|
|
7959
|
+
return this.request("/pg/payment/status", {
|
|
7960
|
+
merchant_id: this.merchantId,
|
|
7961
|
+
order_id: orderId,
|
|
7962
|
+
signature
|
|
7963
|
+
});
|
|
7964
|
+
}
|
|
7965
|
+
};
|
|
7966
|
+
|
|
7967
|
+
// src/clients/nicepay.ts
|
|
7968
|
+
var NicepayClient = class {
|
|
7969
|
+
iMid;
|
|
7970
|
+
merchantKey;
|
|
7971
|
+
sandbox;
|
|
7972
|
+
constructor(config) {
|
|
7973
|
+
this.iMid = config.merchantCode || config.merchantId || config.iMid || "";
|
|
7974
|
+
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
7975
|
+
this.sandbox = !!config.sandbox;
|
|
7976
|
+
}
|
|
7977
|
+
getBaseUrl() {
|
|
7978
|
+
return this.sandbox ? "https://dev.nicepay.co.id/nicepay" : "https://www.nicepay.co.id/nicepay";
|
|
7979
|
+
}
|
|
7980
|
+
/**
|
|
7981
|
+
* Helper HTTP Request ke Nicepay API
|
|
7982
|
+
*/
|
|
7983
|
+
async request(endpoint, payload) {
|
|
7984
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7985
|
+
const response = await fetch(url, {
|
|
7986
|
+
method: "POST",
|
|
7987
|
+
headers: {
|
|
7988
|
+
"Content-Type": "application/json",
|
|
7989
|
+
"Accept": "application/json"
|
|
7990
|
+
},
|
|
7991
|
+
body: JSON.stringify(payload)
|
|
7992
|
+
});
|
|
5296
7993
|
const text = await response.text();
|
|
5297
7994
|
let data = null;
|
|
5298
7995
|
try {
|
|
@@ -5300,75 +7997,64 @@ var XenditClient = class {
|
|
|
5300
7997
|
} catch (e) {
|
|
5301
7998
|
}
|
|
5302
7999
|
if (!response.ok) {
|
|
5303
|
-
throw new Error(data?.
|
|
8000
|
+
throw new Error(data?.resultMsg || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5304
8001
|
}
|
|
5305
8002
|
return data;
|
|
5306
8003
|
}
|
|
5307
8004
|
/**
|
|
5308
|
-
* Cek
|
|
5309
|
-
*/
|
|
5310
|
-
async checkBalance(accountType = "CASH") {
|
|
5311
|
-
try {
|
|
5312
|
-
const data = await this.request("GET", `/balance?account_type=${accountType}`);
|
|
5313
|
-
return {
|
|
5314
|
-
success: data.balance !== void 0,
|
|
5315
|
-
balance: data.balance !== void 0 ? Number(data.balance) : void 0,
|
|
5316
|
-
rawResponse: data
|
|
5317
|
-
};
|
|
5318
|
-
} catch (e) {
|
|
5319
|
-
return {
|
|
5320
|
-
success: false,
|
|
5321
|
-
rawResponse: null,
|
|
5322
|
-
error: e.message || "Failed to check Xendit balance"
|
|
5323
|
-
};
|
|
5324
|
-
}
|
|
5325
|
-
}
|
|
5326
|
-
/**
|
|
5327
|
-
* Memaksa sebuah invoice kadaluwarsa (Expire Invoice)
|
|
8005
|
+
* Cek status transaksi pembayaran di Nicepay
|
|
5328
8006
|
*/
|
|
5329
|
-
async
|
|
5330
|
-
|
|
8007
|
+
async checkTransaction(referenceNo, amount = 0) {
|
|
8008
|
+
const timeStamp = formatNicepayTimestamp();
|
|
8009
|
+
const merchantToken = generateNicepayToken(timeStamp, this.iMid, referenceNo, amount, this.merchantKey);
|
|
8010
|
+
return this.request("/api/oneStepTransInquiry.do", {
|
|
8011
|
+
timeStamp,
|
|
8012
|
+
iMid: this.iMid,
|
|
8013
|
+
referenceNo,
|
|
8014
|
+
amt: String(amount),
|
|
8015
|
+
merchantToken
|
|
8016
|
+
});
|
|
5331
8017
|
}
|
|
5332
8018
|
/**
|
|
5333
|
-
*
|
|
8019
|
+
* Batalkan transaksi di Nicepay
|
|
5334
8020
|
*/
|
|
5335
|
-
async
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
8021
|
+
async cancelTransaction(tXid, payMethod, cancelMsg = "User Cancel") {
|
|
8022
|
+
const timeStamp = formatNicepayTimestamp();
|
|
8023
|
+
const merchantToken = sha256(`${timeStamp}${this.iMid}${tXid}0${this.merchantKey}`);
|
|
8024
|
+
return this.request("/api/oneStepTransCancel.do", {
|
|
8025
|
+
timeStamp,
|
|
8026
|
+
iMid: this.iMid,
|
|
8027
|
+
tXid,
|
|
8028
|
+
payMethod,
|
|
8029
|
+
cancelType: "1",
|
|
8030
|
+
cancelMsg,
|
|
8031
|
+
merchantToken
|
|
5343
8032
|
});
|
|
5344
8033
|
}
|
|
5345
8034
|
};
|
|
5346
8035
|
|
|
5347
|
-
// src/clients/
|
|
5348
|
-
var
|
|
5349
|
-
|
|
5350
|
-
|
|
8036
|
+
// src/clients/oy.ts
|
|
8037
|
+
var OyClient = class {
|
|
8038
|
+
username;
|
|
8039
|
+
apiKey;
|
|
5351
8040
|
sandbox;
|
|
5352
8041
|
constructor(config) {
|
|
5353
|
-
this.
|
|
5354
|
-
this.
|
|
8042
|
+
this.username = config.clientKey || config.username || config.merchantCode || "";
|
|
8043
|
+
this.apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5355
8044
|
this.sandbox = !!config.sandbox;
|
|
5356
8045
|
}
|
|
5357
8046
|
getBaseUrl() {
|
|
5358
|
-
return this.sandbox ? "https://api-
|
|
8047
|
+
return this.sandbox ? "https://api-stg.oyindonesia.com/api" : "https://api.oyindonesia.com/api";
|
|
5359
8048
|
}
|
|
5360
8049
|
/**
|
|
5361
|
-
* Helper
|
|
8050
|
+
* Helper HTTP Request ke OY! Bisnis API
|
|
5362
8051
|
*/
|
|
5363
8052
|
async request(method, endpoint, body) {
|
|
5364
8053
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
5365
|
-
const headers =
|
|
8054
|
+
const headers = generateOyHeaders(this.username, this.apiKey);
|
|
5366
8055
|
const fetchOptions = {
|
|
5367
8056
|
method,
|
|
5368
|
-
headers
|
|
5369
|
-
"Content-Type": "application/json",
|
|
5370
|
-
...headers
|
|
5371
|
-
}
|
|
8057
|
+
headers
|
|
5372
8058
|
};
|
|
5373
8059
|
if (method === "POST" && body) {
|
|
5374
8060
|
fetchOptions.body = JSON.stringify(body);
|
|
@@ -5381,45 +8067,61 @@ var DokuClient = class {
|
|
|
5381
8067
|
} catch (e) {
|
|
5382
8068
|
}
|
|
5383
8069
|
if (!response.ok) {
|
|
5384
|
-
throw new Error(data?.
|
|
8070
|
+
throw new Error(data?.status?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5385
8071
|
}
|
|
5386
8072
|
return data;
|
|
5387
8073
|
}
|
|
5388
8074
|
/**
|
|
5389
|
-
* Cek status transaksi
|
|
8075
|
+
* Cek status transaksi pembayaran
|
|
5390
8076
|
*/
|
|
5391
|
-
async checkTransaction(
|
|
5392
|
-
return this.request("GET", `/
|
|
8077
|
+
async checkTransaction(partnerTxId) {
|
|
8078
|
+
return this.request("GET", `/payment-checkout/status?partner_tx_id=${encodeURIComponent(partnerTxId)}&send_callback=false`);
|
|
8079
|
+
}
|
|
8080
|
+
/**
|
|
8081
|
+
* Cek saldo akun OY! Bisnis
|
|
8082
|
+
*/
|
|
8083
|
+
async checkBalance() {
|
|
8084
|
+
return this.request("GET", "/balance");
|
|
8085
|
+
}
|
|
8086
|
+
/**
|
|
8087
|
+
* Kirim dana / Transfer uang (Disbursement / Remittance)
|
|
8088
|
+
*/
|
|
8089
|
+
async remit(params) {
|
|
8090
|
+
return this.request("POST", "/remit", {
|
|
8091
|
+
recipient_bank: params.recipientBank,
|
|
8092
|
+
recipient_account: params.recipientAccount,
|
|
8093
|
+
amount: params.amount,
|
|
8094
|
+
note: params.note || "Disbursement",
|
|
8095
|
+
partner_trx_id: params.partnerTrxId
|
|
8096
|
+
});
|
|
5393
8097
|
}
|
|
5394
8098
|
};
|
|
5395
8099
|
|
|
5396
|
-
// src/clients/
|
|
5397
|
-
var
|
|
5398
|
-
merchantId;
|
|
8100
|
+
// src/clients/stripe.ts
|
|
8101
|
+
var StripeClient = class {
|
|
5399
8102
|
secretKey;
|
|
5400
|
-
sandbox;
|
|
5401
8103
|
constructor(config) {
|
|
5402
|
-
this.
|
|
5403
|
-
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
5404
|
-
this.sandbox = !!config.sandbox;
|
|
8104
|
+
this.secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5405
8105
|
}
|
|
5406
8106
|
getBaseUrl() {
|
|
5407
|
-
return
|
|
8107
|
+
return "https://api.stripe.com/v1";
|
|
5408
8108
|
}
|
|
5409
8109
|
/**
|
|
5410
|
-
* Helper HTTP Request ke API
|
|
8110
|
+
* Helper HTTP Request ke Stripe API
|
|
5411
8111
|
*/
|
|
5412
8112
|
async request(method, endpoint, body) {
|
|
5413
8113
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
8114
|
+
const headers = {
|
|
8115
|
+
"Authorization": `Bearer ${this.secretKey}`,
|
|
8116
|
+
"Accept": "application/json"
|
|
8117
|
+
};
|
|
5414
8118
|
const fetchOptions = {
|
|
5415
8119
|
method,
|
|
5416
|
-
headers
|
|
5417
|
-
"Content-Type": "application/json",
|
|
5418
|
-
"Accept": "application/json"
|
|
5419
|
-
}
|
|
8120
|
+
headers
|
|
5420
8121
|
};
|
|
5421
8122
|
if (method === "POST" && body) {
|
|
5422
|
-
|
|
8123
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
8124
|
+
fetchOptions.body = serializeStripeParams(body);
|
|
5423
8125
|
}
|
|
5424
8126
|
const response = await fetch(url, fetchOptions);
|
|
5425
8127
|
const text = await response.text();
|
|
@@ -5428,270 +8130,567 @@ var PrismalinkClient = class {
|
|
|
5428
8130
|
data = JSON.parse(text);
|
|
5429
8131
|
} catch (e) {
|
|
5430
8132
|
}
|
|
5431
|
-
if (!response.ok) {
|
|
5432
|
-
throw new Error(data?.message ||
|
|
8133
|
+
if (!response.ok || data?.error) {
|
|
8134
|
+
throw new Error(data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5433
8135
|
}
|
|
5434
8136
|
return data;
|
|
5435
8137
|
}
|
|
5436
8138
|
/**
|
|
5437
|
-
*
|
|
8139
|
+
* Ambil detail Checkout Session
|
|
5438
8140
|
*/
|
|
5439
|
-
async
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
8141
|
+
async retrieveCheckoutSession(sessionId) {
|
|
8142
|
+
return this.request("GET", `/checkout/sessions/${encodeURIComponent(sessionId)}`);
|
|
8143
|
+
}
|
|
8144
|
+
/**
|
|
8145
|
+
* Ambil detail Payment Intent
|
|
8146
|
+
*/
|
|
8147
|
+
async retrievePaymentIntent(paymentIntentId) {
|
|
8148
|
+
return this.request("GET", `/payment_intents/${encodeURIComponent(paymentIntentId)}`);
|
|
8149
|
+
}
|
|
8150
|
+
/**
|
|
8151
|
+
* Cek saldo akun Stripe (Balance)
|
|
8152
|
+
*/
|
|
8153
|
+
async checkBalance() {
|
|
8154
|
+
return this.request("GET", "/balance");
|
|
8155
|
+
}
|
|
8156
|
+
/**
|
|
8157
|
+
* Buat refund dana
|
|
8158
|
+
*/
|
|
8159
|
+
async createRefund(paymentIntentId, amount) {
|
|
8160
|
+
const payload = {
|
|
8161
|
+
payment_intent: paymentIntentId
|
|
8162
|
+
};
|
|
8163
|
+
if (amount) {
|
|
8164
|
+
payload.amount = Math.round(amount);
|
|
8165
|
+
}
|
|
8166
|
+
return this.request("POST", "/refunds", payload);
|
|
5446
8167
|
}
|
|
5447
8168
|
};
|
|
5448
8169
|
|
|
5449
|
-
// src/clients/
|
|
5450
|
-
var
|
|
5451
|
-
|
|
5452
|
-
userId;
|
|
5453
|
-
password;
|
|
5454
|
-
sandbox;
|
|
8170
|
+
// src/clients/paypal.ts
|
|
8171
|
+
var PaypalClient = class {
|
|
8172
|
+
config;
|
|
5455
8173
|
constructor(config) {
|
|
5456
|
-
this.
|
|
5457
|
-
this.userId = config.clientKey || config.userId || config.extra?.userId || this.merchantId;
|
|
5458
|
-
this.password = config.apiKey || config.password || config.serverKey || config.secretKey || "";
|
|
5459
|
-
this.sandbox = !!config.sandbox;
|
|
8174
|
+
this.config = config;
|
|
5460
8175
|
}
|
|
5461
8176
|
getBaseUrl() {
|
|
5462
|
-
return this.sandbox ? "https://sandbox.
|
|
8177
|
+
return this.config.sandbox !== false ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
5463
8178
|
}
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
const
|
|
5469
|
-
const response = await fetch(url, {
|
|
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`, {
|
|
5470
8184
|
method: "POST",
|
|
5471
|
-
headers: {
|
|
5472
|
-
|
|
5473
|
-
"Accept": "application/json"
|
|
5474
|
-
},
|
|
5475
|
-
body: JSON.stringify(payload)
|
|
8185
|
+
headers: { "Authorization": `Basic ${auth}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8186
|
+
body: "grant_type=client_credentials"
|
|
5476
8187
|
});
|
|
5477
|
-
const
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
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";
|
|
5482
8217
|
}
|
|
5483
|
-
|
|
5484
|
-
|
|
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`;
|
|
5485
8265
|
}
|
|
5486
|
-
return
|
|
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();
|
|
5487
8423
|
}
|
|
5488
|
-
/**
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
const
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
bill_no: billNo,
|
|
5497
|
-
signature
|
|
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)
|
|
5498
8432
|
});
|
|
8433
|
+
return response.json();
|
|
5499
8434
|
}
|
|
5500
|
-
/**
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
return this.request("/cvr/100005/10", {
|
|
5506
|
-
request: "Cancel Transaction",
|
|
5507
|
-
merchant_id: this.merchantId,
|
|
5508
|
-
bill_no: billNo,
|
|
5509
|
-
payment_channel: paymentChannel,
|
|
5510
|
-
signature
|
|
8435
|
+
/** Cek saldo akun Razorpay */
|
|
8436
|
+
async checkBalance() {
|
|
8437
|
+
const response = await fetch(`${this.getBaseUrl()}/balance`, {
|
|
8438
|
+
method: "GET",
|
|
8439
|
+
headers: this.buildHeaders()
|
|
5511
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();
|
|
5512
8454
|
}
|
|
5513
8455
|
};
|
|
5514
8456
|
|
|
5515
|
-
// src/clients/
|
|
5516
|
-
var
|
|
5517
|
-
|
|
5518
|
-
merchantKey;
|
|
5519
|
-
sandbox;
|
|
8457
|
+
// src/clients/square.ts
|
|
8458
|
+
var SquareClient = class {
|
|
8459
|
+
config;
|
|
5520
8460
|
constructor(config) {
|
|
5521
|
-
this.
|
|
5522
|
-
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
5523
|
-
this.sandbox = !!config.sandbox;
|
|
8461
|
+
this.config = config;
|
|
5524
8462
|
}
|
|
5525
8463
|
getBaseUrl() {
|
|
5526
|
-
return this.sandbox ? "https://
|
|
8464
|
+
return this.config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
5527
8465
|
}
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
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`, {
|
|
5534
8484
|
method: "POST",
|
|
5535
|
-
headers:
|
|
5536
|
-
|
|
5537
|
-
"Accept": "application/json"
|
|
5538
|
-
},
|
|
5539
|
-
body: JSON.stringify(payload)
|
|
8485
|
+
headers: this.buildHeaders(),
|
|
8486
|
+
body: "{}"
|
|
5540
8487
|
});
|
|
5541
|
-
|
|
5542
|
-
let data = null;
|
|
5543
|
-
try {
|
|
5544
|
-
data = JSON.parse(text);
|
|
5545
|
-
} catch (e) {
|
|
5546
|
-
}
|
|
5547
|
-
if (!response.ok) {
|
|
5548
|
-
throw new Error(data?.response_desc || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5549
|
-
}
|
|
5550
|
-
return data;
|
|
8488
|
+
return response.json();
|
|
5551
8489
|
}
|
|
5552
|
-
/**
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
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
|
+
})
|
|
5561
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();
|
|
5562
8520
|
}
|
|
5563
8521
|
};
|
|
5564
8522
|
|
|
5565
|
-
// src/clients/
|
|
5566
|
-
var
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
sandbox;
|
|
8523
|
+
// src/clients/payu.ts
|
|
8524
|
+
var PayuClient = class {
|
|
8525
|
+
config;
|
|
8526
|
+
accessToken = null;
|
|
5570
8527
|
constructor(config) {
|
|
5571
|
-
this.
|
|
5572
|
-
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
5573
|
-
this.sandbox = !!config.sandbox;
|
|
8528
|
+
this.config = config;
|
|
5574
8529
|
}
|
|
5575
8530
|
getBaseUrl() {
|
|
5576
|
-
return this.sandbox ? "https://
|
|
8531
|
+
return this.config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
5577
8532
|
}
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
const
|
|
5583
|
-
const response = await fetch(url, {
|
|
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`, {
|
|
5584
8538
|
method: "POST",
|
|
5585
|
-
headers: {
|
|
5586
|
-
|
|
5587
|
-
"Accept": "application/json"
|
|
5588
|
-
},
|
|
5589
|
-
body: JSON.stringify(payload)
|
|
8539
|
+
headers: { "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8540
|
+
body: "grant_type=client_credentials"
|
|
5590
8541
|
});
|
|
5591
|
-
const
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
}
|
|
5600
|
-
|
|
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();
|
|
5601
8575
|
}
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
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)
|
|
5614
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();
|
|
5615
8617
|
}
|
|
5616
|
-
/**
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
const
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
iMid: this.iMid,
|
|
5625
|
-
tXid,
|
|
5626
|
-
payMethod,
|
|
5627
|
-
cancelType: "1",
|
|
5628
|
-
cancelMsg,
|
|
5629
|
-
merchantToken
|
|
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)
|
|
5630
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();
|
|
5631
8637
|
}
|
|
5632
8638
|
};
|
|
5633
8639
|
|
|
5634
|
-
// src/clients/
|
|
5635
|
-
var
|
|
5636
|
-
|
|
5637
|
-
apiKey;
|
|
5638
|
-
sandbox;
|
|
8640
|
+
// src/clients/twocheckout.ts
|
|
8641
|
+
var TwoCheckoutClient = class {
|
|
8642
|
+
config;
|
|
5639
8643
|
constructor(config) {
|
|
5640
|
-
this.
|
|
5641
|
-
this.apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5642
|
-
this.sandbox = !!config.sandbox;
|
|
8644
|
+
this.config = config;
|
|
5643
8645
|
}
|
|
5644
8646
|
getBaseUrl() {
|
|
5645
|
-
return this.sandbox ? "https://api
|
|
8647
|
+
return this.config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
5646
8648
|
}
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
headers
|
|
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"
|
|
5656
8657
|
};
|
|
5657
|
-
if (method === "POST" && body) {
|
|
5658
|
-
fetchOptions.body = JSON.stringify(body);
|
|
5659
|
-
}
|
|
5660
|
-
const response = await fetch(url, fetchOptions);
|
|
5661
|
-
const text = await response.text();
|
|
5662
|
-
let data = null;
|
|
5663
|
-
try {
|
|
5664
|
-
data = JSON.parse(text);
|
|
5665
|
-
} catch (e) {
|
|
5666
|
-
}
|
|
5667
|
-
if (!response.ok) {
|
|
5668
|
-
throw new Error(data?.status?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5669
|
-
}
|
|
5670
|
-
return data;
|
|
5671
8658
|
}
|
|
5672
|
-
/**
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
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();
|
|
5677
8666
|
}
|
|
5678
|
-
/**
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
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();
|
|
5683
8675
|
}
|
|
5684
|
-
/**
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
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()
|
|
5694
8692
|
});
|
|
8693
|
+
return response.json();
|
|
5695
8694
|
}
|
|
5696
8695
|
};
|
|
5697
8696
|
|
|
@@ -5709,6 +8708,15 @@ var PaymentManager = class {
|
|
|
5709
8708
|
this.registerProvider(new FinpayProvider());
|
|
5710
8709
|
this.registerProvider(new NicepayProvider());
|
|
5711
8710
|
this.registerProvider(new OyProvider());
|
|
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());
|
|
5712
8720
|
}
|
|
5713
8721
|
registerProvider(provider) {
|
|
5714
8722
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -5720,6 +8728,7 @@ var PaymentManager = class {
|
|
|
5720
8728
|
}
|
|
5721
8729
|
return provider;
|
|
5722
8730
|
}
|
|
8731
|
+
// ─── Indonesian Provider Getters ──────────────────────────────────────────
|
|
5723
8732
|
getMidtransProvider() {
|
|
5724
8733
|
return this.getProvider("midtrans");
|
|
5725
8734
|
}
|
|
@@ -5780,6 +8789,62 @@ var PaymentManager = class {
|
|
|
5780
8789
|
getOyClient(config) {
|
|
5781
8790
|
return new OyClient(config);
|
|
5782
8791
|
}
|
|
8792
|
+
// ─── International Provider Getters ─────────────────────────────────────
|
|
8793
|
+
getStripeProvider() {
|
|
8794
|
+
return this.getProvider("stripe");
|
|
8795
|
+
}
|
|
8796
|
+
getStripeClient(config) {
|
|
8797
|
+
return new StripeClient(config);
|
|
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 ──────────────────────────────────────────────────
|
|
5783
8848
|
async createInvoice(providerName, params, config) {
|
|
5784
8849
|
const provider = this.getProvider(providerName);
|
|
5785
8850
|
return provider.createInvoice(params, config);
|
|
@@ -5837,6 +8902,24 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5837
8902
|
sandbox = env.NICEPAY_SANDBOX === "true" || env.NICEPAY_SANDBOX === "1";
|
|
5838
8903
|
} else if (env.OY_SANDBOX !== void 0) {
|
|
5839
8904
|
sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
|
|
8905
|
+
} else if (env.STRIPE_SANDBOX !== void 0) {
|
|
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";
|
|
5840
8923
|
} else {
|
|
5841
8924
|
sandbox = env.NODE_ENV !== "production";
|
|
5842
8925
|
}
|
|
@@ -5862,6 +8945,24 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5862
8945
|
apiKey = env.NICEPAY_KEY || env.NICEPAY_MERCHANT_KEY || env.NICEPAY_SECRET_KEY || env.NICEPAY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
5863
8946
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5864
8947
|
apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8948
|
+
} else if (provider === "stripe") {
|
|
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;
|
|
5865
8966
|
} else {
|
|
5866
8967
|
apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
|
|
5867
8968
|
}
|
|
@@ -5896,25 +8997,66 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5896
8997
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5897
8998
|
merchantCode = merchantCode || env.OY_USERNAME || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5898
8999
|
clientKey = clientKey || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
|
|
9000
|
+
} else if (provider === "stripe") {
|
|
9001
|
+
clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
|
|
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;
|
|
5899
9029
|
} else {
|
|
5900
9030
|
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5901
9031
|
}
|
|
5902
|
-
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID;
|
|
5903
|
-
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY;
|
|
5904
|
-
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY;
|
|
5905
|
-
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;
|
|
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;
|
|
5906
9036
|
const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
|
|
5907
9037
|
const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
|
|
5908
9038
|
const extra = {
|
|
5909
9039
|
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
9040
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
5910
9041
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
5911
9042
|
userId: env.FASPAY_USER_ID,
|
|
5912
9043
|
iMid: env.NICEPAY_IMID,
|
|
5913
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,
|
|
5914
9056
|
...customConfig?.extra
|
|
5915
9057
|
};
|
|
5916
9058
|
return {
|
|
5917
|
-
provider: provider === "oyindonesia" ? "oy" : provider,
|
|
9059
|
+
provider: provider === "oyindonesia" ? "oy" : provider === "2checkout" ? "twocheckout" : provider,
|
|
5918
9060
|
apiKey: apiKey || "",
|
|
5919
9061
|
serverKey: apiKey || "",
|
|
5920
9062
|
secretKey: secretKey || apiKey || "",
|
|
@@ -5952,7 +9094,7 @@ var Buayar = class {
|
|
|
5952
9094
|
this.config = resolveConfigFromEnv({ ...this.config, ...config });
|
|
5953
9095
|
}
|
|
5954
9096
|
/**
|
|
5955
|
-
* Dapatkan nama provider aktif
|
|
9097
|
+
* Dapatkan nama provider aktif
|
|
5956
9098
|
*/
|
|
5957
9099
|
get provider() {
|
|
5958
9100
|
return this.config.provider || "midtrans";
|
|
@@ -6000,6 +9142,40 @@ var Buayar = class {
|
|
|
6000
9142
|
*/
|
|
6001
9143
|
async verifyWebhook(payload, headers, configOverride) {
|
|
6002
9144
|
const mergedConfig = { ...this.config, ...configOverride };
|
|
9145
|
+
if (headers) {
|
|
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) {
|
|
9174
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9175
|
+
mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
|
|
9176
|
+
mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
6003
9179
|
let providerName = configOverride?.provider || this.provider;
|
|
6004
9180
|
if (payload) {
|
|
6005
9181
|
if (payload.signature_key && payload.transaction_status) {
|
|
@@ -6020,8 +9196,28 @@ var Buayar = class {
|
|
|
6020
9196
|
providerName = "oy";
|
|
6021
9197
|
} else if (payload.merchant_id && payload.order_id && payload.signature) {
|
|
6022
9198
|
providerName = "prismalink";
|
|
9199
|
+
} else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
|
|
9200
|
+
providerName = "stripe";
|
|
9201
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9202
|
+
providerName = "razorpay";
|
|
6023
9203
|
} else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
|
|
6024
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";
|
|
6025
9221
|
}
|
|
6026
9222
|
}
|
|
6027
9223
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
@@ -6029,71 +9225,74 @@ var Buayar = class {
|
|
|
6029
9225
|
async handleWebhook(payload, headers, configOverride) {
|
|
6030
9226
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
6031
9227
|
}
|
|
9228
|
+
// ─── Indonesian Provider Client Getters ───────────────────────────────────
|
|
6032
9229
|
getMidtransClient(configOverride) {
|
|
6033
|
-
return new MidtransClient({
|
|
6034
|
-
...this.config,
|
|
6035
|
-
...configOverride
|
|
6036
|
-
});
|
|
9230
|
+
return new MidtransClient({ ...this.config, ...configOverride });
|
|
6037
9231
|
}
|
|
6038
9232
|
getDuitkuClient(configOverride) {
|
|
6039
|
-
return new DuitkuClient({
|
|
6040
|
-
...this.config,
|
|
6041
|
-
...configOverride
|
|
6042
|
-
});
|
|
9233
|
+
return new DuitkuClient({ ...this.config, ...configOverride });
|
|
6043
9234
|
}
|
|
6044
9235
|
getIpaymuClient(configOverride) {
|
|
6045
|
-
return new IpaymuClient({
|
|
6046
|
-
...this.config,
|
|
6047
|
-
...configOverride
|
|
6048
|
-
});
|
|
9236
|
+
return new IpaymuClient({ ...this.config, ...configOverride });
|
|
6049
9237
|
}
|
|
6050
9238
|
getXenditClient(configOverride) {
|
|
6051
|
-
return new XenditClient({
|
|
6052
|
-
...this.config,
|
|
6053
|
-
...configOverride
|
|
6054
|
-
});
|
|
9239
|
+
return new XenditClient({ ...this.config, ...configOverride });
|
|
6055
9240
|
}
|
|
6056
9241
|
getDokuClient(configOverride) {
|
|
6057
|
-
return new DokuClient({
|
|
6058
|
-
...this.config,
|
|
6059
|
-
...configOverride
|
|
6060
|
-
});
|
|
9242
|
+
return new DokuClient({ ...this.config, ...configOverride });
|
|
6061
9243
|
}
|
|
6062
9244
|
getPrismalinkClient(configOverride) {
|
|
6063
|
-
return new PrismalinkClient({
|
|
6064
|
-
...this.config,
|
|
6065
|
-
...configOverride
|
|
6066
|
-
});
|
|
9245
|
+
return new PrismalinkClient({ ...this.config, ...configOverride });
|
|
6067
9246
|
}
|
|
6068
9247
|
getFaspayClient(configOverride) {
|
|
6069
|
-
return new FaspayClient({
|
|
6070
|
-
...this.config,
|
|
6071
|
-
...configOverride
|
|
6072
|
-
});
|
|
9248
|
+
return new FaspayClient({ ...this.config, ...configOverride });
|
|
6073
9249
|
}
|
|
6074
9250
|
getFinpayClient(configOverride) {
|
|
6075
|
-
return new FinpayClient({
|
|
6076
|
-
...this.config,
|
|
6077
|
-
...configOverride
|
|
6078
|
-
});
|
|
9251
|
+
return new FinpayClient({ ...this.config, ...configOverride });
|
|
6079
9252
|
}
|
|
6080
9253
|
getNicepayClient(configOverride) {
|
|
6081
|
-
return new NicepayClient({
|
|
6082
|
-
...this.config,
|
|
6083
|
-
...configOverride
|
|
6084
|
-
});
|
|
9254
|
+
return new NicepayClient({ ...this.config, ...configOverride });
|
|
6085
9255
|
}
|
|
6086
9256
|
getOyClient(configOverride) {
|
|
6087
|
-
return new OyClient({
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
9257
|
+
return new OyClient({ ...this.config, ...configOverride });
|
|
9258
|
+
}
|
|
9259
|
+
// ─── International Provider Client Getters ────────────────────────────────
|
|
9260
|
+
getStripeClient(configOverride) {
|
|
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 });
|
|
6091
9286
|
}
|
|
6092
9287
|
};
|
|
6093
9288
|
var buayar = new Buayar();
|
|
6094
9289
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6095
9290
|
0 && (module.exports = {
|
|
9291
|
+
AdyenClient,
|
|
9292
|
+
AdyenProvider,
|
|
6096
9293
|
BasePaymentProvider,
|
|
9294
|
+
BraintreeClient,
|
|
9295
|
+
BraintreeProvider,
|
|
6097
9296
|
Buayar,
|
|
6098
9297
|
CANONICAL_TO_DOKU,
|
|
6099
9298
|
CANONICAL_TO_DUITKU,
|
|
@@ -6104,8 +9303,11 @@ var buayar = new Buayar();
|
|
|
6104
9303
|
CANONICAL_TO_NICEPAY,
|
|
6105
9304
|
CANONICAL_TO_OY,
|
|
6106
9305
|
CANONICAL_TO_PRISMALINK,
|
|
9306
|
+
CANONICAL_TO_STRIPE,
|
|
6107
9307
|
CANONICAL_TO_XENDIT,
|
|
6108
9308
|
CORE_API_METHODS,
|
|
9309
|
+
CheckoutComClient,
|
|
9310
|
+
CheckoutComProvider,
|
|
6109
9311
|
DUITKU_TO_CANONICAL,
|
|
6110
9312
|
DokuClient,
|
|
6111
9313
|
DokuProvider,
|
|
@@ -6126,12 +9328,29 @@ var buayar = new Buayar();
|
|
|
6126
9328
|
OyClient,
|
|
6127
9329
|
OyProvider,
|
|
6128
9330
|
PaymentManager,
|
|
9331
|
+
PaypalClient,
|
|
9332
|
+
PaypalProvider,
|
|
9333
|
+
PayuClient,
|
|
9334
|
+
PayuProvider,
|
|
6129
9335
|
PrismalinkClient,
|
|
6130
9336
|
PrismalinkProvider,
|
|
9337
|
+
RazorpayClient,
|
|
9338
|
+
RazorpayProvider,
|
|
9339
|
+
SquareClient,
|
|
9340
|
+
SquareProvider,
|
|
9341
|
+
StripeClient,
|
|
9342
|
+
StripeProvider,
|
|
9343
|
+
TwoCheckoutClient,
|
|
9344
|
+
TwoCheckoutProvider,
|
|
6131
9345
|
XenditClient,
|
|
6132
9346
|
XenditProvider,
|
|
6133
9347
|
buayar,
|
|
9348
|
+
buildBraintreeBasicAuth,
|
|
6134
9349
|
buildCoreChargePayload,
|
|
9350
|
+
buildPaypalBasicAuth,
|
|
9351
|
+
buildPayuBasicAuth,
|
|
9352
|
+
buildRazorpayBasicAuth,
|
|
9353
|
+
buildTwoCheckoutAuth,
|
|
6135
9354
|
formatNicepayTimestamp,
|
|
6136
9355
|
generateDokuHeaders,
|
|
6137
9356
|
generateFaspaySignature,
|
|
@@ -6151,6 +9370,8 @@ var buayar = new Buayar();
|
|
|
6151
9370
|
paymentManager,
|
|
6152
9371
|
resolveConfigFromEnv,
|
|
6153
9372
|
safeCompare,
|
|
9373
|
+
serializePaypalParams,
|
|
9374
|
+
serializeStripeParams,
|
|
6154
9375
|
sha256,
|
|
6155
9376
|
sha512,
|
|
6156
9377
|
toCanonicalPaymentMethod,
|
|
@@ -6162,7 +9383,11 @@ var buayar = new Buayar();
|
|
|
6162
9383
|
toNicepayPaymentMethod,
|
|
6163
9384
|
toOyPaymentMethod,
|
|
6164
9385
|
toPrismalinkPaymentMethod,
|
|
9386
|
+
toStripePaymentMethod,
|
|
6165
9387
|
toXenditPaymentMethod,
|
|
9388
|
+
verifyAdyenWebhook,
|
|
9389
|
+
verifyBraintreeWebhook,
|
|
9390
|
+
verifyCheckoutComWebhook,
|
|
6166
9391
|
verifyDokuWebhookSignature,
|
|
6167
9392
|
verifyDuitkuCallbackSignature,
|
|
6168
9393
|
verifyFaspaySignature,
|
|
@@ -6170,6 +9395,12 @@ var buayar = new Buayar();
|
|
|
6170
9395
|
verifyIpaymuCallback,
|
|
6171
9396
|
verifyNicepayWebhook,
|
|
6172
9397
|
verifyOyWebhook,
|
|
9398
|
+
verifyPaypalWebhookSimple,
|
|
9399
|
+
verifyPayuWebhook,
|
|
6173
9400
|
verifyPrismalinkSignature,
|
|
9401
|
+
verifyRazorpayWebhook,
|
|
9402
|
+
verifySquareWebhook,
|
|
9403
|
+
verifyStripeWebhook,
|
|
9404
|
+
verifyTwoCheckoutWebhook,
|
|
6174
9405
|
verifyXenditWebhookToken
|
|
6175
9406
|
});
|