@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.mjs
CHANGED
|
@@ -281,6 +281,17 @@ var CANONICAL_TO_OY = {
|
|
|
281
281
|
alfamart: { type: "cstore", channel: "alfamart" },
|
|
282
282
|
indomaret: { type: "cstore", channel: "indomaret" }
|
|
283
283
|
};
|
|
284
|
+
var CANONICAL_TO_STRIPE = {
|
|
285
|
+
credit_card: "card",
|
|
286
|
+
qris: "qris",
|
|
287
|
+
gopay_qris: "qris",
|
|
288
|
+
shopeepay_qris: "qris",
|
|
289
|
+
bca_va: "customer_balance",
|
|
290
|
+
mandiri_va: "customer_balance",
|
|
291
|
+
bni_va: "customer_balance",
|
|
292
|
+
bri_va: "customer_balance",
|
|
293
|
+
permata_va: "customer_balance"
|
|
294
|
+
};
|
|
284
295
|
function toDuitkuPaymentMethod(code) {
|
|
285
296
|
if (!code) return void 0;
|
|
286
297
|
const lower = code.toLowerCase().trim();
|
|
@@ -368,6 +379,14 @@ function toOyPaymentMethod(code) {
|
|
|
368
379
|
}
|
|
369
380
|
return void 0;
|
|
370
381
|
}
|
|
382
|
+
function toStripePaymentMethod(code) {
|
|
383
|
+
if (!code) return void 0;
|
|
384
|
+
const lower = code.toLowerCase().trim();
|
|
385
|
+
if (CANONICAL_TO_STRIPE[lower]) {
|
|
386
|
+
return CANONICAL_TO_STRIPE[lower];
|
|
387
|
+
}
|
|
388
|
+
return lower;
|
|
389
|
+
}
|
|
371
390
|
function toCanonicalPaymentMethod(provider, code) {
|
|
372
391
|
if (!code) return "";
|
|
373
392
|
const upper = code.toUpperCase().trim();
|
|
@@ -375,7 +394,7 @@ function toCanonicalPaymentMethod(provider, code) {
|
|
|
375
394
|
if (provider.toLowerCase() === "duitku" && DUITKU_TO_CANONICAL[upper]) {
|
|
376
395
|
return DUITKU_TO_CANONICAL[upper];
|
|
377
396
|
}
|
|
378
|
-
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]) {
|
|
397
|
+
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]) {
|
|
379
398
|
return lower;
|
|
380
399
|
}
|
|
381
400
|
return lower;
|
|
@@ -4886,225 +4905,2770 @@ var OyProvider = class extends BasePaymentProvider {
|
|
|
4886
4905
|
}
|
|
4887
4906
|
};
|
|
4888
4907
|
|
|
4889
|
-
// src/
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
}
|
|
4905
|
-
/**
|
|
4906
|
-
* Request helper generic dengan kalkulasi signature Duitku otomatis
|
|
4907
|
-
*/
|
|
4908
|
-
async request(method, endpoint, body = {}, options) {
|
|
4909
|
-
const baseUrl = options?.baseUrl === "api" ? this.getApiBaseUrl() : this.getPassportBaseUrl();
|
|
4910
|
-
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;
|
|
4911
|
-
const timestamp = Date.now().toString();
|
|
4912
|
-
const headerSignature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
4913
|
-
const headers = {
|
|
4914
|
-
"Content-Type": "application/json",
|
|
4915
|
-
"Accept": "application/json",
|
|
4916
|
-
"x-duitku-signature": headerSignature,
|
|
4917
|
-
"x-duitku-timestamp": timestamp,
|
|
4918
|
-
"x-duitku-merchantcode": this.merchantCode,
|
|
4919
|
-
...options?.customHeaders
|
|
4920
|
-
};
|
|
4921
|
-
const fetchOptions = {
|
|
4922
|
-
method,
|
|
4923
|
-
headers
|
|
4924
|
-
};
|
|
4925
|
-
if (method === "POST" && body) {
|
|
4926
|
-
fetchOptions.body = JSON.stringify(body);
|
|
4927
|
-
}
|
|
4928
|
-
const response = await fetch(url, fetchOptions);
|
|
4929
|
-
const text = await response.text();
|
|
4930
|
-
let data = null;
|
|
4931
|
-
try {
|
|
4932
|
-
data = JSON.parse(text);
|
|
4933
|
-
} catch (e) {
|
|
4908
|
+
// src/providers/stripe/signature.ts
|
|
4909
|
+
function serializeStripeParams(obj, prefix = "") {
|
|
4910
|
+
const pairs = [];
|
|
4911
|
+
if (obj === null || obj === void 0) {
|
|
4912
|
+
return "";
|
|
4913
|
+
}
|
|
4914
|
+
for (const key of Object.keys(obj)) {
|
|
4915
|
+
const val = obj[key];
|
|
4916
|
+
if (val === void 0 || val === null) continue;
|
|
4917
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
4918
|
+
if (typeof val === "object" && !(val instanceof Date)) {
|
|
4919
|
+
const nested = serializeStripeParams(val, fullKey);
|
|
4920
|
+
if (nested) pairs.push(nested);
|
|
4921
|
+
} else {
|
|
4922
|
+
pairs.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(val))}`);
|
|
4934
4923
|
}
|
|
4935
|
-
|
|
4936
|
-
|
|
4924
|
+
}
|
|
4925
|
+
return pairs.join("&");
|
|
4926
|
+
}
|
|
4927
|
+
function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleranceSeconds = 300) {
|
|
4928
|
+
if (!signatureHeader || !webhookSecret) {
|
|
4929
|
+
return true;
|
|
4930
|
+
}
|
|
4931
|
+
const items = signatureHeader.split(",");
|
|
4932
|
+
let timestamp = "";
|
|
4933
|
+
const signatures = [];
|
|
4934
|
+
for (const item of items) {
|
|
4935
|
+
const [key, value] = item.trim().split("=");
|
|
4936
|
+
if (key === "t") {
|
|
4937
|
+
timestamp = value;
|
|
4938
|
+
} else if (key === "v1") {
|
|
4939
|
+
signatures.push(value);
|
|
4937
4940
|
}
|
|
4938
|
-
return data || text;
|
|
4939
4941
|
}
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
4943
|
-
*/
|
|
4944
|
-
async checkTransaction(merchantOrderId) {
|
|
4945
|
-
const { bodySignature } = getDuitkuStatusSignatures(
|
|
4946
|
-
this.merchantCode,
|
|
4947
|
-
merchantOrderId,
|
|
4948
|
-
this.apiKey
|
|
4949
|
-
);
|
|
4950
|
-
return this.request(
|
|
4951
|
-
"POST",
|
|
4952
|
-
"/api/merchant/transactionStatus",
|
|
4953
|
-
{
|
|
4954
|
-
merchantCode: this.merchantCode,
|
|
4955
|
-
merchantOrderId,
|
|
4956
|
-
signature: bodySignature
|
|
4957
|
-
},
|
|
4958
|
-
{ baseUrl: "api" }
|
|
4959
|
-
);
|
|
4942
|
+
if (!timestamp || signatures.length === 0) {
|
|
4943
|
+
return false;
|
|
4960
4944
|
}
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
signature
|
|
4973
|
-
});
|
|
4945
|
+
const payloadString = typeof rawPayload === "string" ? rawPayload : JSON.stringify(rawPayload);
|
|
4946
|
+
const signedPayload = `${timestamp}.${payloadString}`;
|
|
4947
|
+
const expectedSignature = hmacSha256(signedPayload, webhookSecret);
|
|
4948
|
+
return signatures.some((sig) => safeCompare(sig.toLowerCase(), expectedSignature.toLowerCase()));
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// src/providers/stripe/provider.ts
|
|
4952
|
+
var StripeProvider = class extends BasePaymentProvider {
|
|
4953
|
+
name = "stripe";
|
|
4954
|
+
getBaseUrl() {
|
|
4955
|
+
return "https://api.stripe.com/v1";
|
|
4974
4956
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
const
|
|
4981
|
-
const
|
|
4957
|
+
async createInvoice(params, config) {
|
|
4958
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
4959
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
4960
|
+
const integerAmount = Math.round(amount);
|
|
4961
|
+
const stripeMethod = toStripePaymentMethod(params.paymentMethod);
|
|
4962
|
+
const isDirect = !!params.paymentMethod;
|
|
4963
|
+
const baseUrl = this.getBaseUrl();
|
|
4964
|
+
const headers = {
|
|
4965
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
4966
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
4967
|
+
};
|
|
4982
4968
|
try {
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4969
|
+
if (isDirect) {
|
|
4970
|
+
const url = `${baseUrl}/payment_intents`;
|
|
4971
|
+
const payload = {
|
|
4972
|
+
amount: integerAmount,
|
|
4973
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
4974
|
+
description: productDetails,
|
|
4975
|
+
receipt_email: customer?.email,
|
|
4976
|
+
payment_method_types: [stripeMethod || "card"],
|
|
4977
|
+
metadata: {
|
|
4978
|
+
order_id: orderId,
|
|
4979
|
+
customer_name: customer?.name
|
|
4980
|
+
},
|
|
4981
|
+
...params.providerParams
|
|
4982
|
+
};
|
|
4983
|
+
const response = await fetch(url, {
|
|
4984
|
+
method: "POST",
|
|
4985
|
+
headers,
|
|
4986
|
+
body: serializeStripeParams(payload)
|
|
4987
|
+
});
|
|
4988
|
+
const text = await response.text();
|
|
4989
|
+
let data = null;
|
|
4990
|
+
try {
|
|
4991
|
+
data = JSON.parse(text);
|
|
4992
|
+
} catch (e) {
|
|
4993
|
+
}
|
|
4994
|
+
if (!response.ok || !data || data.error) {
|
|
4995
|
+
return {
|
|
4996
|
+
success: false,
|
|
4997
|
+
provider: "stripe",
|
|
4998
|
+
orderId,
|
|
4999
|
+
amount: integerAmount,
|
|
5000
|
+
rawResponse: data,
|
|
5001
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
5004
|
+
return {
|
|
5005
|
+
success: true,
|
|
5006
|
+
provider: "stripe",
|
|
5007
|
+
orderId,
|
|
5008
|
+
amount: data.amount ? Number(data.amount) : integerAmount,
|
|
5009
|
+
reference: data.id,
|
|
5010
|
+
paymentCode: data.client_secret,
|
|
5011
|
+
rawResponse: data
|
|
5012
|
+
};
|
|
5013
|
+
} else {
|
|
5014
|
+
const url = `${baseUrl}/checkout/sessions`;
|
|
5015
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5016
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5017
|
+
const payload = {
|
|
5018
|
+
mode: "payment",
|
|
5019
|
+
client_reference_id: orderId,
|
|
5020
|
+
customer_email: customer?.email,
|
|
5021
|
+
line_items: [
|
|
5022
|
+
{
|
|
5023
|
+
price_data: {
|
|
5024
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
5025
|
+
product_data: {
|
|
5026
|
+
name: productDetails
|
|
5027
|
+
},
|
|
5028
|
+
unit_amount: integerAmount
|
|
5029
|
+
},
|
|
5030
|
+
quantity: 1
|
|
5031
|
+
}
|
|
5032
|
+
],
|
|
5033
|
+
metadata: {
|
|
5034
|
+
order_id: orderId
|
|
5035
|
+
},
|
|
5036
|
+
success_url: successUrl,
|
|
5037
|
+
cancel_url: cancelUrl,
|
|
5038
|
+
...params.providerParams
|
|
5039
|
+
};
|
|
5040
|
+
const response = await fetch(url, {
|
|
5041
|
+
method: "POST",
|
|
5042
|
+
headers,
|
|
5043
|
+
body: serializeStripeParams(payload)
|
|
5044
|
+
});
|
|
5045
|
+
const text = await response.text();
|
|
5046
|
+
let data = null;
|
|
5047
|
+
try {
|
|
5048
|
+
data = JSON.parse(text);
|
|
5049
|
+
} catch (e) {
|
|
5050
|
+
}
|
|
5051
|
+
if (!response.ok || !data || data.error) {
|
|
5052
|
+
return {
|
|
5053
|
+
success: false,
|
|
5054
|
+
provider: "stripe",
|
|
5055
|
+
orderId,
|
|
5056
|
+
amount: integerAmount,
|
|
5057
|
+
rawResponse: data,
|
|
5058
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
return {
|
|
5062
|
+
success: true,
|
|
5063
|
+
provider: "stripe",
|
|
5064
|
+
orderId: data.client_reference_id || orderId,
|
|
5065
|
+
amount: data.amount_total ? Number(data.amount_total) : integerAmount,
|
|
5066
|
+
reference: data.id,
|
|
5067
|
+
paymentUrl: data.url,
|
|
5068
|
+
rawResponse: data
|
|
5069
|
+
};
|
|
5070
|
+
}
|
|
4997
5071
|
} catch (e) {
|
|
4998
5072
|
return {
|
|
4999
5073
|
success: false,
|
|
5074
|
+
provider: "stripe",
|
|
5075
|
+
orderId,
|
|
5076
|
+
amount: integerAmount,
|
|
5000
5077
|
rawResponse: null,
|
|
5001
|
-
error: e.message || "Failed to
|
|
5078
|
+
error: e.message || "Failed to make request to Stripe API"
|
|
5002
5079
|
};
|
|
5003
5080
|
}
|
|
5004
5081
|
}
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
const
|
|
5010
|
-
const
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5082
|
+
async verifyCallback(body, config) {
|
|
5083
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
5084
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
5085
|
+
const isValid = verifyStripeWebhook(body, signatureHeader, webhookSecret);
|
|
5086
|
+
const eventType = body.type || "";
|
|
5087
|
+
const obj = body.data?.object || body;
|
|
5088
|
+
const orderId = obj.metadata?.order_id || obj.client_reference_id || obj.id || "";
|
|
5089
|
+
const amount = obj.amount_total || obj.amount || 0;
|
|
5090
|
+
const paymentStatus = (obj.payment_status || obj.status || "").toLowerCase();
|
|
5091
|
+
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";
|
|
5092
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5093
|
+
const isExpired = paymentStatus === "expired" || eventType === "checkout.session.expired";
|
|
5094
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5095
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5096
|
+
return {
|
|
5097
|
+
isValid,
|
|
5098
|
+
provider: "stripe",
|
|
5099
|
+
orderId: String(orderId),
|
|
5100
|
+
amount: Number(amount) || 0,
|
|
5101
|
+
status,
|
|
5102
|
+
isPaid,
|
|
5103
|
+
isPending,
|
|
5104
|
+
isFailed,
|
|
5105
|
+
isExpired,
|
|
5106
|
+
statusCode: eventType || paymentStatus,
|
|
5107
|
+
rawPayload: body
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
5110
|
+
async getPaymentMethods(params, config) {
|
|
5111
|
+
const staticMethods = [
|
|
5014
5112
|
{
|
|
5015
|
-
|
|
5016
|
-
|
|
5113
|
+
paymentMethod: "credit_card",
|
|
5114
|
+
code: "credit_card",
|
|
5115
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, JCB, Amex)",
|
|
5116
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5117
|
+
totalFee: "2.9% + IDR 2,000",
|
|
5118
|
+
category: "Kartu Kredit"
|
|
5017
5119
|
},
|
|
5018
|
-
{ baseUrl: "api" }
|
|
5019
|
-
);
|
|
5020
|
-
}
|
|
5021
|
-
/**
|
|
5022
|
-
* Validasi nama pemilik rekening bank sebelum eksekusi transfer (Bank Account Inquiry)
|
|
5023
|
-
*/
|
|
5024
|
-
async inquiryBankAccount(bankCode, bankAccount) {
|
|
5025
|
-
const timestamp = Date.now().toString();
|
|
5026
|
-
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
5027
|
-
return this.request(
|
|
5028
|
-
"POST",
|
|
5029
|
-
"/api/disbursement/inquiry",
|
|
5030
5120
|
{
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5121
|
+
paymentMethod: "qris",
|
|
5122
|
+
code: "qris",
|
|
5123
|
+
paymentName: "QRIS (Indonesia)",
|
|
5124
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5125
|
+
totalFee: "0.7%",
|
|
5126
|
+
category: "QRIS"
|
|
5035
5127
|
},
|
|
5036
|
-
{
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5128
|
+
{
|
|
5129
|
+
paymentMethod: "bca_va",
|
|
5130
|
+
code: "bca_va",
|
|
5131
|
+
paymentName: "BCA Virtual Account (Bank Transfer)",
|
|
5132
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5133
|
+
totalFee: "IDR 4,000",
|
|
5134
|
+
category: "Virtual Account"
|
|
5135
|
+
},
|
|
5136
|
+
{
|
|
5137
|
+
paymentMethod: "mandiri_va",
|
|
5138
|
+
code: "mandiri_va",
|
|
5139
|
+
paymentName: "Mandiri Virtual Account (Bank Transfer)",
|
|
5140
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5141
|
+
totalFee: "IDR 4,000",
|
|
5142
|
+
category: "Virtual Account"
|
|
5143
|
+
},
|
|
5144
|
+
{
|
|
5145
|
+
paymentMethod: "bni_va",
|
|
5146
|
+
code: "bni_va",
|
|
5147
|
+
paymentName: "BNI Virtual Account (Bank Transfer)",
|
|
5148
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5149
|
+
totalFee: "IDR 4,000",
|
|
5150
|
+
category: "Virtual Account"
|
|
5151
|
+
},
|
|
5152
|
+
{
|
|
5153
|
+
paymentMethod: "bri_va",
|
|
5154
|
+
code: "bri_va",
|
|
5155
|
+
paymentName: "BRI Virtual Account (Bank Transfer)",
|
|
5156
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5157
|
+
totalFee: "IDR 4,000",
|
|
5158
|
+
category: "Virtual Account"
|
|
5159
|
+
},
|
|
5160
|
+
{
|
|
5161
|
+
paymentMethod: "permata_va",
|
|
5162
|
+
code: "permata_va",
|
|
5163
|
+
paymentName: "Permata Virtual Account (Bank Transfer)",
|
|
5164
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5165
|
+
totalFee: "IDR 4,000",
|
|
5166
|
+
category: "Virtual Account"
|
|
5167
|
+
}
|
|
5168
|
+
];
|
|
5169
|
+
const categories = {};
|
|
5170
|
+
for (const item of staticMethods) {
|
|
5171
|
+
if (!categories[item.category]) {
|
|
5172
|
+
categories[item.category] = [];
|
|
5173
|
+
}
|
|
5174
|
+
categories[item.category].push(item);
|
|
5175
|
+
}
|
|
5176
|
+
return {
|
|
5177
|
+
success: true,
|
|
5178
|
+
provider: "stripe",
|
|
5179
|
+
methods: staticMethods,
|
|
5180
|
+
categories,
|
|
5181
|
+
rawResponse: staticMethods
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
async checkTransaction(params, config) {
|
|
5185
|
+
const { merchantOrderId } = params;
|
|
5186
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5187
|
+
const baseUrl = this.getBaseUrl();
|
|
5188
|
+
let endpoint = `/checkout/sessions/${encodeURIComponent(merchantOrderId)}`;
|
|
5189
|
+
if (merchantOrderId.startsWith("pi_")) {
|
|
5190
|
+
endpoint = `/payment_intents/${encodeURIComponent(merchantOrderId)}`;
|
|
5191
|
+
}
|
|
5192
|
+
const url = `${baseUrl}${endpoint}`;
|
|
5193
|
+
const headers = {
|
|
5194
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
5195
|
+
"Accept": "application/json"
|
|
5196
|
+
};
|
|
5197
|
+
try {
|
|
5198
|
+
const response = await fetch(url, {
|
|
5199
|
+
method: "GET",
|
|
5200
|
+
headers
|
|
5201
|
+
});
|
|
5202
|
+
const text = await response.text();
|
|
5203
|
+
let data = null;
|
|
5204
|
+
try {
|
|
5205
|
+
data = JSON.parse(text);
|
|
5206
|
+
} catch (e) {
|
|
5207
|
+
}
|
|
5208
|
+
if (!response.ok || !data || data.error) {
|
|
5209
|
+
return {
|
|
5210
|
+
success: false,
|
|
5211
|
+
provider: "stripe",
|
|
5212
|
+
orderId: merchantOrderId,
|
|
5213
|
+
reference: "",
|
|
5214
|
+
amount: 0,
|
|
5215
|
+
statusCode: response.status.toString(),
|
|
5216
|
+
status: "failed",
|
|
5217
|
+
isPaid: false,
|
|
5218
|
+
isPending: false,
|
|
5219
|
+
isFailed: true,
|
|
5220
|
+
isExpired: false,
|
|
5221
|
+
statusMessage: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5222
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5223
|
+
rawResponse: data
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
const paymentStatus = (data.payment_status || data.status || "").toLowerCase();
|
|
5227
|
+
const isPaid = paymentStatus === "paid" || paymentStatus === "succeeded" || paymentStatus === "complete";
|
|
5228
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5229
|
+
const isExpired = paymentStatus === "expired";
|
|
5230
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5231
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5232
|
+
return {
|
|
5233
|
+
success: true,
|
|
5234
|
+
provider: "stripe",
|
|
5235
|
+
orderId: data.metadata?.order_id || data.client_reference_id || data.id || merchantOrderId,
|
|
5236
|
+
reference: data.id || "",
|
|
5237
|
+
amount: data.amount_total ? Number(data.amount_total) : data.amount ? Number(data.amount) : 0,
|
|
5238
|
+
statusCode: paymentStatus,
|
|
5239
|
+
status,
|
|
5240
|
+
isPaid,
|
|
5241
|
+
isPending,
|
|
5242
|
+
isFailed,
|
|
5243
|
+
isExpired,
|
|
5244
|
+
statusMessage: paymentStatus,
|
|
5245
|
+
paymentType: data.payment_method_types?.[0] || "card",
|
|
5246
|
+
transactionTime: data.created ? new Date(data.created * 1e3) : void 0,
|
|
5247
|
+
rawResponse: data
|
|
5248
|
+
};
|
|
5249
|
+
} catch (e) {
|
|
5250
|
+
return {
|
|
5251
|
+
success: false,
|
|
5252
|
+
provider: "stripe",
|
|
5253
|
+
orderId: merchantOrderId,
|
|
5254
|
+
reference: "",
|
|
5255
|
+
amount: 0,
|
|
5256
|
+
statusCode: "ERROR",
|
|
5257
|
+
status: "failed",
|
|
5258
|
+
isPaid: false,
|
|
5259
|
+
isPending: false,
|
|
5260
|
+
isFailed: true,
|
|
5261
|
+
isExpired: false,
|
|
5262
|
+
statusMessage: e.message || "Failed to check transaction status in Stripe",
|
|
5263
|
+
error: e.message || "Failed to check transaction status in Stripe",
|
|
5264
|
+
rawResponse: null
|
|
5265
|
+
};
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
};
|
|
5269
|
+
|
|
5270
|
+
// src/providers/paypal/signature.ts
|
|
5271
|
+
function buildPaypalBasicAuth(clientId, clientSecret) {
|
|
5272
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
5273
|
+
}
|
|
5274
|
+
function verifyPaypalWebhookSimple(transmissionId, timestamp, webhookId, body, transmissionSig, certUrl) {
|
|
5275
|
+
return !!(transmissionId && timestamp && webhookId && transmissionSig && certUrl);
|
|
5276
|
+
}
|
|
5277
|
+
function serializePaypalParams(obj) {
|
|
5278
|
+
return Object.entries(obj).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
|
|
5279
|
+
}
|
|
5280
|
+
|
|
5281
|
+
// src/providers/paypal/provider.ts
|
|
5282
|
+
var PaypalProvider = class extends BasePaymentProvider {
|
|
5283
|
+
name = "paypal";
|
|
5284
|
+
getSandbox(config) {
|
|
5285
|
+
return config.sandbox !== false;
|
|
5286
|
+
}
|
|
5287
|
+
getBaseUrl(config) {
|
|
5288
|
+
return this.getSandbox(config) ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
5289
|
+
}
|
|
5290
|
+
/** OAuth2 Client Credentials — dapatkan access token */
|
|
5291
|
+
async getAccessToken(config) {
|
|
5292
|
+
const clientId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
5293
|
+
const clientSecret = config.apiKey || config.secretKey || "";
|
|
5294
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
5295
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5296
|
+
const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
|
|
5297
|
+
method: "POST",
|
|
5298
|
+
headers: {
|
|
5299
|
+
"Authorization": `Basic ${auth}`,
|
|
5300
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
5301
|
+
},
|
|
5302
|
+
body: "grant_type=client_credentials"
|
|
5303
|
+
});
|
|
5304
|
+
const text = await response.text();
|
|
5305
|
+
let data = null;
|
|
5306
|
+
try {
|
|
5307
|
+
data = JSON.parse(text);
|
|
5308
|
+
} catch (e) {
|
|
5309
|
+
}
|
|
5310
|
+
if (!response.ok || !data?.access_token) {
|
|
5311
|
+
throw new Error(data?.error_description || `Failed to get PayPal access token: ${response.status}`);
|
|
5312
|
+
}
|
|
5313
|
+
return data.access_token;
|
|
5314
|
+
}
|
|
5315
|
+
async createInvoice(params, config) {
|
|
5316
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
5317
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5318
|
+
let accessToken;
|
|
5319
|
+
try {
|
|
5320
|
+
accessToken = await this.getAccessToken(config);
|
|
5321
|
+
} catch (e) {
|
|
5322
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5323
|
+
}
|
|
5324
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5325
|
+
const amountFormatted = (amount / 100).toFixed(2);
|
|
5326
|
+
const isDirect = !!params.paymentMethod;
|
|
5327
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5328
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5329
|
+
const body = {
|
|
5330
|
+
intent: isDirect ? "CAPTURE" : "CAPTURE",
|
|
5331
|
+
purchase_units: [
|
|
5332
|
+
{
|
|
5333
|
+
reference_id: orderId,
|
|
5334
|
+
description: productDetails,
|
|
5335
|
+
amount: {
|
|
5336
|
+
currency_code: currency,
|
|
5337
|
+
value: amountFormatted
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
],
|
|
5341
|
+
application_context: {
|
|
5342
|
+
return_url: successUrl,
|
|
5343
|
+
cancel_url: cancelUrl,
|
|
5344
|
+
brand_name: productDetails,
|
|
5345
|
+
user_action: "PAY_NOW"
|
|
5346
|
+
}
|
|
5347
|
+
};
|
|
5348
|
+
if (isDirect) {
|
|
5349
|
+
body.application_context.shipping_preference = "NO_SHIPPING";
|
|
5350
|
+
}
|
|
5351
|
+
if (callbackUrl || config.callbackUrl) {
|
|
5352
|
+
}
|
|
5353
|
+
try {
|
|
5354
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders`, {
|
|
5355
|
+
method: "POST",
|
|
5356
|
+
headers: {
|
|
5357
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5358
|
+
"Content-Type": "application/json",
|
|
5359
|
+
"PayPal-Request-Id": orderId,
|
|
5360
|
+
"Prefer": "return=representation"
|
|
5361
|
+
},
|
|
5362
|
+
body: JSON.stringify(body)
|
|
5363
|
+
});
|
|
5364
|
+
const text = await response.text();
|
|
5365
|
+
let data = null;
|
|
5366
|
+
try {
|
|
5367
|
+
data = JSON.parse(text);
|
|
5368
|
+
} catch (e) {
|
|
5369
|
+
}
|
|
5370
|
+
if (!response.ok || !data || data.name) {
|
|
5371
|
+
return {
|
|
5372
|
+
success: false,
|
|
5373
|
+
provider: "paypal",
|
|
5374
|
+
orderId,
|
|
5375
|
+
amount,
|
|
5376
|
+
rawResponse: data,
|
|
5377
|
+
error: data?.message || `HTTP error! Status: ${response.status}`
|
|
5378
|
+
};
|
|
5379
|
+
}
|
|
5380
|
+
const approveLink = data.links?.find((l) => l.rel === "approve" || l.rel === "payer-action");
|
|
5381
|
+
const paymentUrl = approveLink?.href || "";
|
|
5382
|
+
return {
|
|
5383
|
+
success: true,
|
|
5384
|
+
provider: "paypal",
|
|
5385
|
+
orderId,
|
|
5386
|
+
amount,
|
|
5387
|
+
reference: data.id,
|
|
5388
|
+
paymentUrl,
|
|
5389
|
+
rawResponse: data
|
|
5390
|
+
};
|
|
5391
|
+
} catch (e) {
|
|
5392
|
+
return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
async verifyCallback(body, config) {
|
|
5396
|
+
const eventType = body?.event_type || body?.event_name || "";
|
|
5397
|
+
const resource = body?.resource || {};
|
|
5398
|
+
const orderId = resource.reference_id || resource.purchase_units?.[0]?.reference_id || resource.supplementary_data?.related_ids?.order_id || resource.id || "";
|
|
5399
|
+
const amount = Number(resource.amount?.value || resource.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5400
|
+
const statusRaw = (resource.status || "").toUpperCase();
|
|
5401
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "PAYMENT.CAPTURE.COMPLETED";
|
|
5402
|
+
const isPending = statusRaw === "PENDING" || eventType === "PAYMENT.CAPTURE.PENDING";
|
|
5403
|
+
const isExpired = statusRaw === "EXPIRED" || eventType === "CHECKOUT.ORDER.EXPIRED";
|
|
5404
|
+
const isFailed = !isPaid && !isPending && !isExpired && (statusRaw === "DENIED" || statusRaw === "FAILED" || eventType.includes("FAILED") || eventType.includes("DENIED"));
|
|
5405
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5406
|
+
return {
|
|
5407
|
+
isValid: true,
|
|
5408
|
+
// Full cert-chain validation deferred to PayPal's verify API
|
|
5409
|
+
provider: "paypal",
|
|
5410
|
+
orderId: String(orderId),
|
|
5411
|
+
amount,
|
|
5412
|
+
status,
|
|
5413
|
+
isPaid,
|
|
5414
|
+
isPending,
|
|
5415
|
+
isFailed,
|
|
5416
|
+
isExpired,
|
|
5417
|
+
statusCode: eventType,
|
|
5418
|
+
rawPayload: body
|
|
5419
|
+
};
|
|
5420
|
+
}
|
|
5421
|
+
async getPaymentMethods(params, config) {
|
|
5422
|
+
const methods = [
|
|
5423
|
+
{
|
|
5424
|
+
paymentMethod: "credit_card",
|
|
5425
|
+
code: "card",
|
|
5426
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)",
|
|
5427
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5428
|
+
totalFee: "3.49% + fixed fee",
|
|
5429
|
+
category: "Kartu Kredit"
|
|
5430
|
+
},
|
|
5431
|
+
{
|
|
5432
|
+
paymentMethod: "paypal",
|
|
5433
|
+
code: "paypal",
|
|
5434
|
+
paymentName: "PayPal Balance / PayPal Checkout",
|
|
5435
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5436
|
+
totalFee: "3.49% + fixed fee",
|
|
5437
|
+
category: "E-Wallet"
|
|
5438
|
+
},
|
|
5439
|
+
{
|
|
5440
|
+
paymentMethod: "paylater",
|
|
5441
|
+
code: "pay_later",
|
|
5442
|
+
paymentName: "PayPal Pay Later / Buy Now Pay Later",
|
|
5443
|
+
paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
|
|
5444
|
+
totalFee: "3.49% + fixed fee",
|
|
5445
|
+
category: "Paylater / Cicilan"
|
|
5446
|
+
}
|
|
5447
|
+
];
|
|
5448
|
+
const categories = {};
|
|
5449
|
+
for (const item of methods) {
|
|
5450
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5451
|
+
categories[item.category].push(item);
|
|
5452
|
+
}
|
|
5453
|
+
return { success: true, provider: "paypal", methods, categories, rawResponse: methods };
|
|
5454
|
+
}
|
|
5455
|
+
async checkTransaction(params, config) {
|
|
5456
|
+
const { merchantOrderId } = params;
|
|
5457
|
+
let accessToken;
|
|
5458
|
+
try {
|
|
5459
|
+
accessToken = await this.getAccessToken(config);
|
|
5460
|
+
} catch (e) {
|
|
5461
|
+
return {
|
|
5462
|
+
success: false,
|
|
5463
|
+
provider: "paypal",
|
|
5464
|
+
orderId: merchantOrderId,
|
|
5465
|
+
reference: "",
|
|
5466
|
+
amount: 0,
|
|
5467
|
+
statusCode: "AUTH_ERROR",
|
|
5468
|
+
status: "failed",
|
|
5469
|
+
isPaid: false,
|
|
5470
|
+
isPending: false,
|
|
5471
|
+
isFailed: true,
|
|
5472
|
+
isExpired: false,
|
|
5473
|
+
statusMessage: e.message,
|
|
5474
|
+
error: e.message,
|
|
5475
|
+
rawResponse: null
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5479
|
+
try {
|
|
5480
|
+
const response = await fetch(`${baseUrl}/v2/checkout/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
5481
|
+
method: "GET",
|
|
5482
|
+
headers: {
|
|
5483
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
5484
|
+
"Content-Type": "application/json"
|
|
5485
|
+
}
|
|
5486
|
+
});
|
|
5487
|
+
const text = await response.text();
|
|
5488
|
+
let data = null;
|
|
5489
|
+
try {
|
|
5490
|
+
data = JSON.parse(text);
|
|
5491
|
+
} catch (e) {
|
|
5492
|
+
}
|
|
5493
|
+
if (!response.ok || !data || data.name) {
|
|
5494
|
+
return {
|
|
5495
|
+
success: false,
|
|
5496
|
+
provider: "paypal",
|
|
5497
|
+
orderId: merchantOrderId,
|
|
5498
|
+
reference: "",
|
|
5499
|
+
amount: 0,
|
|
5500
|
+
statusCode: response.status.toString(),
|
|
5501
|
+
status: "failed",
|
|
5502
|
+
isPaid: false,
|
|
5503
|
+
isPending: false,
|
|
5504
|
+
isFailed: true,
|
|
5505
|
+
isExpired: false,
|
|
5506
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5507
|
+
error: data?.message,
|
|
5508
|
+
rawResponse: data
|
|
5509
|
+
};
|
|
5510
|
+
}
|
|
5511
|
+
const statusRaw = (data.status || "").toUpperCase();
|
|
5512
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
5513
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED" || statusRaw === "CREATED";
|
|
5514
|
+
const isExpired = statusRaw === "VOIDED";
|
|
5515
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5516
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5517
|
+
const amountValue = Number(data.purchase_units?.[0]?.amount?.value || 0) * 100;
|
|
5518
|
+
return {
|
|
5519
|
+
success: true,
|
|
5520
|
+
provider: "paypal",
|
|
5521
|
+
orderId: data.purchase_units?.[0]?.reference_id || merchantOrderId,
|
|
5522
|
+
reference: data.id || merchantOrderId,
|
|
5523
|
+
amount: amountValue,
|
|
5524
|
+
statusCode: statusRaw,
|
|
5525
|
+
status,
|
|
5526
|
+
isPaid,
|
|
5527
|
+
isPending,
|
|
5528
|
+
isFailed,
|
|
5529
|
+
isExpired,
|
|
5530
|
+
statusMessage: statusRaw,
|
|
5531
|
+
transactionTime: data.create_time ? new Date(data.create_time) : void 0,
|
|
5532
|
+
rawResponse: data
|
|
5533
|
+
};
|
|
5534
|
+
} catch (e) {
|
|
5535
|
+
return {
|
|
5536
|
+
success: false,
|
|
5537
|
+
provider: "paypal",
|
|
5538
|
+
orderId: merchantOrderId,
|
|
5539
|
+
reference: "",
|
|
5540
|
+
amount: 0,
|
|
5541
|
+
statusCode: "ERROR",
|
|
5542
|
+
status: "failed",
|
|
5543
|
+
isPaid: false,
|
|
5544
|
+
isPending: false,
|
|
5545
|
+
isFailed: true,
|
|
5546
|
+
isExpired: false,
|
|
5547
|
+
statusMessage: e.message,
|
|
5548
|
+
error: e.message,
|
|
5549
|
+
rawResponse: null
|
|
5550
|
+
};
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
};
|
|
5554
|
+
|
|
5555
|
+
// src/providers/adyen/signature.ts
|
|
5556
|
+
import { createHmac } from "crypto";
|
|
5557
|
+
function verifyAdyenWebhook(notificationItem, hmacKey) {
|
|
5558
|
+
if (!hmacKey || !notificationItem) return false;
|
|
5559
|
+
try {
|
|
5560
|
+
const amount = notificationItem.amount || {};
|
|
5561
|
+
const fields = [
|
|
5562
|
+
notificationItem.pspReference || "",
|
|
5563
|
+
notificationItem.originalReference || "",
|
|
5564
|
+
notificationItem.merchantAccountCode || "",
|
|
5565
|
+
notificationItem.merchantReference || "",
|
|
5566
|
+
String(amount.value || ""),
|
|
5567
|
+
amount.currency || "",
|
|
5568
|
+
notificationItem.eventCode || "",
|
|
5569
|
+
notificationItem.success || ""
|
|
5570
|
+
];
|
|
5571
|
+
const signedData = fields.join(":");
|
|
5572
|
+
const keyBytes = Buffer.from(hmacKey, "hex");
|
|
5573
|
+
const expected = createHmac("sha256", keyBytes).update(signedData, "utf8").digest("base64");
|
|
5574
|
+
return expected === notificationItem.additionalData?.hmacSignature;
|
|
5575
|
+
} catch {
|
|
5576
|
+
return false;
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5580
|
+
// src/providers/adyen/provider.ts
|
|
5581
|
+
var AdyenProvider = class extends BasePaymentProvider {
|
|
5582
|
+
name = "adyen";
|
|
5583
|
+
getBaseUrl(config) {
|
|
5584
|
+
if (!config.sandbox) {
|
|
5585
|
+
const prefix = config.extra?.liveUrlPrefix || config.projectId || "";
|
|
5586
|
+
if (prefix) {
|
|
5587
|
+
return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
return "https://checkout-test.adyen.com";
|
|
5591
|
+
}
|
|
5592
|
+
async createInvoice(params, config) {
|
|
5593
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5594
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5595
|
+
const merchantAccount = config.merchantCode || config.merchantId || config.extra?.merchantAccount || "";
|
|
5596
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5597
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5598
|
+
const isDirect = !!params.paymentMethod;
|
|
5599
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5600
|
+
try {
|
|
5601
|
+
if (isDirect) {
|
|
5602
|
+
const url = `${baseUrl}/v68/payments`;
|
|
5603
|
+
const body = {
|
|
5604
|
+
merchantAccount,
|
|
5605
|
+
reference: orderId,
|
|
5606
|
+
amount: { value: amount, currency },
|
|
5607
|
+
returnUrl: successUrl,
|
|
5608
|
+
shopperEmail: customer?.email,
|
|
5609
|
+
shopperName: customer?.name ? { firstName: customer.name.split(" ")[0], lastName: customer.name.split(" ").slice(1).join(" ") || "-" } : void 0,
|
|
5610
|
+
shopperReference: customer?.email || orderId,
|
|
5611
|
+
additionalData: { allow3DS2: true },
|
|
5612
|
+
metadata: { order_id: orderId },
|
|
5613
|
+
...params.providerParams
|
|
5614
|
+
};
|
|
5615
|
+
const response = await fetch(url, {
|
|
5616
|
+
method: "POST",
|
|
5617
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5618
|
+
body: JSON.stringify(body)
|
|
5619
|
+
});
|
|
5620
|
+
const text = await response.text();
|
|
5621
|
+
let data = null;
|
|
5622
|
+
try {
|
|
5623
|
+
data = JSON.parse(text);
|
|
5624
|
+
} catch (e) {
|
|
5625
|
+
}
|
|
5626
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5627
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5628
|
+
}
|
|
5629
|
+
const isPaid = data.resultCode === "Authorised";
|
|
5630
|
+
const isPending = data.resultCode === "Pending" || data.resultCode === "RedirectShopper" || data.resultCode === "IdentifyShopper" || data.resultCode === "ChallengeShopper";
|
|
5631
|
+
return {
|
|
5632
|
+
success: true,
|
|
5633
|
+
provider: "adyen",
|
|
5634
|
+
orderId,
|
|
5635
|
+
amount,
|
|
5636
|
+
reference: data.pspReference || data.merchantReference,
|
|
5637
|
+
paymentUrl: data.action?.url || data.redirect?.url || void 0,
|
|
5638
|
+
rawResponse: data
|
|
5639
|
+
};
|
|
5640
|
+
} else {
|
|
5641
|
+
const url = `${baseUrl}/v68/sessions`;
|
|
5642
|
+
const body = {
|
|
5643
|
+
merchantAccount,
|
|
5644
|
+
reference: orderId,
|
|
5645
|
+
amount: { value: amount, currency },
|
|
5646
|
+
returnUrl: successUrl,
|
|
5647
|
+
countryCode: config.extra?.countryCode || "US",
|
|
5648
|
+
shopperLocale: config.extra?.shopperLocale || "en-US",
|
|
5649
|
+
shopperEmail: customer?.email,
|
|
5650
|
+
shopperReference: customer?.email || orderId,
|
|
5651
|
+
metadata: { order_id: orderId },
|
|
5652
|
+
...params.providerParams
|
|
5653
|
+
};
|
|
5654
|
+
const response = await fetch(url, {
|
|
5655
|
+
method: "POST",
|
|
5656
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
|
|
5657
|
+
body: JSON.stringify(body)
|
|
5658
|
+
});
|
|
5659
|
+
const text = await response.text();
|
|
5660
|
+
let data = null;
|
|
5661
|
+
try {
|
|
5662
|
+
data = JSON.parse(text);
|
|
5663
|
+
} catch (e) {
|
|
5664
|
+
}
|
|
5665
|
+
if (!response.ok || !data || data.status >= 400) {
|
|
5666
|
+
return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
5667
|
+
}
|
|
5668
|
+
return {
|
|
5669
|
+
success: true,
|
|
5670
|
+
provider: "adyen",
|
|
5671
|
+
orderId,
|
|
5672
|
+
amount,
|
|
5673
|
+
reference: data.id,
|
|
5674
|
+
paymentUrl: data.url,
|
|
5675
|
+
paymentCode: data.sessionData,
|
|
5676
|
+
rawResponse: data
|
|
5677
|
+
};
|
|
5678
|
+
}
|
|
5679
|
+
} catch (e) {
|
|
5680
|
+
return { success: false, provider: "adyen", orderId, amount, error: e.message, rawResponse: null };
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
async verifyCallback(body, config) {
|
|
5684
|
+
const hmacKey = config.extra?.hmacKey || config.secretKey || "";
|
|
5685
|
+
const notificationItems = body?.notificationItems || [body];
|
|
5686
|
+
const item = notificationItems[0]?.NotificationRequestItem || notificationItems[0] || body;
|
|
5687
|
+
const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : true;
|
|
5688
|
+
const eventCode = (item.eventCode || "").toUpperCase();
|
|
5689
|
+
const success = item.success === "true" || item.success === true;
|
|
5690
|
+
const orderId = item.merchantReference || item.pspReference || "";
|
|
5691
|
+
const amount = item.amount?.value ? Number(item.amount.value) : 0;
|
|
5692
|
+
const isPaid = eventCode === "AUTHORISATION" && success;
|
|
5693
|
+
const isPending = eventCode === "PENDING" || eventCode === "OFFER_CLOSED";
|
|
5694
|
+
const isExpired = eventCode === "EXPIRED" || eventCode === "CANCEL";
|
|
5695
|
+
const isFailed = !isPaid && !isPending && !isExpired && (!success || eventCode === "REFUSAL");
|
|
5696
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5697
|
+
return {
|
|
5698
|
+
isValid,
|
|
5699
|
+
provider: "adyen",
|
|
5700
|
+
orderId: String(orderId),
|
|
5701
|
+
amount,
|
|
5702
|
+
status,
|
|
5703
|
+
isPaid,
|
|
5704
|
+
isPending,
|
|
5705
|
+
isFailed,
|
|
5706
|
+
isExpired,
|
|
5707
|
+
statusCode: eventCode,
|
|
5708
|
+
rawPayload: body
|
|
5709
|
+
};
|
|
5710
|
+
}
|
|
5711
|
+
async getPaymentMethods(params, config) {
|
|
5712
|
+
const methods = [
|
|
5713
|
+
{ 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" },
|
|
5714
|
+
{ 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" },
|
|
5715
|
+
{ 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" },
|
|
5716
|
+
{ 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" },
|
|
5717
|
+
{ 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" },
|
|
5718
|
+
{ 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" },
|
|
5719
|
+
{ 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" }
|
|
5720
|
+
];
|
|
5721
|
+
const categories = {};
|
|
5722
|
+
for (const item of methods) {
|
|
5723
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5724
|
+
categories[item.category].push(item);
|
|
5725
|
+
}
|
|
5726
|
+
return { success: true, provider: "adyen", methods, categories, rawResponse: methods };
|
|
5727
|
+
}
|
|
5728
|
+
async checkTransaction(params, config) {
|
|
5729
|
+
const { merchantOrderId } = params;
|
|
5730
|
+
const apiKey = config.apiKey || config.secretKey || "";
|
|
5731
|
+
const merchantAccount = config.merchantCode || config.merchantId || "";
|
|
5732
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5733
|
+
try {
|
|
5734
|
+
const response = await fetch(`${baseUrl}/v68/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
5735
|
+
method: "GET",
|
|
5736
|
+
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" }
|
|
5737
|
+
});
|
|
5738
|
+
const text = await response.text();
|
|
5739
|
+
let data = null;
|
|
5740
|
+
try {
|
|
5741
|
+
data = JSON.parse(text);
|
|
5742
|
+
} catch (e) {
|
|
5743
|
+
}
|
|
5744
|
+
if (!response.ok || !data) {
|
|
5745
|
+
return {
|
|
5746
|
+
success: false,
|
|
5747
|
+
provider: "adyen",
|
|
5748
|
+
orderId: merchantOrderId,
|
|
5749
|
+
reference: "",
|
|
5750
|
+
amount: 0,
|
|
5751
|
+
statusCode: response.status.toString(),
|
|
5752
|
+
status: "failed",
|
|
5753
|
+
isPaid: false,
|
|
5754
|
+
isPending: false,
|
|
5755
|
+
isFailed: true,
|
|
5756
|
+
isExpired: false,
|
|
5757
|
+
statusMessage: data?.message || "HTTP Error",
|
|
5758
|
+
error: data?.message,
|
|
5759
|
+
rawResponse: data
|
|
5760
|
+
};
|
|
5761
|
+
}
|
|
5762
|
+
const resultCode = (data.resultCode || data.status || "").toUpperCase();
|
|
5763
|
+
const isPaid = resultCode === "AUTHORISED" || resultCode === "SETTLED";
|
|
5764
|
+
const isPending = resultCode === "PENDING" || resultCode === "RECEIVED" || resultCode === "REDIRECTSHOPPER";
|
|
5765
|
+
const isExpired = resultCode === "EXPIRED" || resultCode === "CANCELLED";
|
|
5766
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5767
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5768
|
+
return {
|
|
5769
|
+
success: true,
|
|
5770
|
+
provider: "adyen",
|
|
5771
|
+
orderId: data.merchantReference || merchantOrderId,
|
|
5772
|
+
reference: data.pspReference || merchantOrderId,
|
|
5773
|
+
amount: data.amount?.value ? Number(data.amount.value) : 0,
|
|
5774
|
+
statusCode: resultCode,
|
|
5775
|
+
status,
|
|
5776
|
+
isPaid,
|
|
5777
|
+
isPending,
|
|
5778
|
+
isFailed,
|
|
5779
|
+
isExpired,
|
|
5780
|
+
statusMessage: resultCode,
|
|
5781
|
+
rawResponse: data
|
|
5782
|
+
};
|
|
5783
|
+
} catch (e) {
|
|
5784
|
+
return {
|
|
5785
|
+
success: false,
|
|
5786
|
+
provider: "adyen",
|
|
5787
|
+
orderId: merchantOrderId,
|
|
5788
|
+
reference: "",
|
|
5789
|
+
amount: 0,
|
|
5790
|
+
statusCode: "ERROR",
|
|
5791
|
+
status: "failed",
|
|
5792
|
+
isPaid: false,
|
|
5793
|
+
isPending: false,
|
|
5794
|
+
isFailed: true,
|
|
5795
|
+
isExpired: false,
|
|
5796
|
+
statusMessage: e.message,
|
|
5797
|
+
error: e.message,
|
|
5798
|
+
rawResponse: null
|
|
5799
|
+
};
|
|
5800
|
+
}
|
|
5801
|
+
}
|
|
5802
|
+
};
|
|
5803
|
+
|
|
5804
|
+
// src/providers/checkoutcom/signature.ts
|
|
5805
|
+
import { createHmac as createHmac2 } from "crypto";
|
|
5806
|
+
function verifyCheckoutComWebhook(body, signatureHeader, secret) {
|
|
5807
|
+
if (!secret || !signatureHeader || !body) return false;
|
|
5808
|
+
try {
|
|
5809
|
+
const expected = createHmac2("sha256", secret).update(body, "utf8").digest("hex");
|
|
5810
|
+
const provided = signatureHeader.replace(/^sha256=/, "");
|
|
5811
|
+
return expected === provided;
|
|
5812
|
+
} catch {
|
|
5813
|
+
return false;
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
|
|
5817
|
+
// src/providers/checkoutcom/provider.ts
|
|
5818
|
+
var CheckoutComProvider = class extends BasePaymentProvider {
|
|
5819
|
+
name = "checkoutcom";
|
|
5820
|
+
getBaseUrl(config) {
|
|
5821
|
+
return config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
5822
|
+
}
|
|
5823
|
+
async createInvoice(params, config) {
|
|
5824
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
5825
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
5826
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
5827
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5828
|
+
const isDirect = !!params.paymentMethod;
|
|
5829
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5830
|
+
try {
|
|
5831
|
+
if (isDirect) {
|
|
5832
|
+
const url = `${baseUrl}/payments`;
|
|
5833
|
+
const body = {
|
|
5834
|
+
amount,
|
|
5835
|
+
currency,
|
|
5836
|
+
reference: orderId,
|
|
5837
|
+
description: productDetails,
|
|
5838
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
5839
|
+
success_url: successUrl,
|
|
5840
|
+
failure_url: successUrl,
|
|
5841
|
+
metadata: { order_id: orderId },
|
|
5842
|
+
...params.providerParams
|
|
5843
|
+
};
|
|
5844
|
+
const response = await fetch(url, {
|
|
5845
|
+
method: "POST",
|
|
5846
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
5847
|
+
body: JSON.stringify(body)
|
|
5848
|
+
});
|
|
5849
|
+
const text = await response.text();
|
|
5850
|
+
let data = null;
|
|
5851
|
+
try {
|
|
5852
|
+
data = JSON.parse(text);
|
|
5853
|
+
} catch (e) {
|
|
5854
|
+
}
|
|
5855
|
+
if (!response.ok || !data || data.error_codes) {
|
|
5856
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
5857
|
+
}
|
|
5858
|
+
return {
|
|
5859
|
+
success: true,
|
|
5860
|
+
provider: "checkoutcom",
|
|
5861
|
+
orderId,
|
|
5862
|
+
amount: data.amount || amount,
|
|
5863
|
+
reference: data.id,
|
|
5864
|
+
paymentUrl: data._links?.redirect?.href,
|
|
5865
|
+
rawResponse: data
|
|
5866
|
+
};
|
|
5867
|
+
} else {
|
|
5868
|
+
const url = `${baseUrl}/payment-links`;
|
|
5869
|
+
const body = {
|
|
5870
|
+
amount,
|
|
5871
|
+
currency,
|
|
5872
|
+
reference: orderId,
|
|
5873
|
+
description: productDetails,
|
|
5874
|
+
customer: { email: customer?.email, name: customer?.name },
|
|
5875
|
+
return_url: successUrl,
|
|
5876
|
+
metadata: { order_id: orderId },
|
|
5877
|
+
...params.providerParams
|
|
5878
|
+
};
|
|
5879
|
+
const response = await fetch(url, {
|
|
5880
|
+
method: "POST",
|
|
5881
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
|
|
5882
|
+
body: JSON.stringify(body)
|
|
5883
|
+
});
|
|
5884
|
+
const text = await response.text();
|
|
5885
|
+
let data = null;
|
|
5886
|
+
try {
|
|
5887
|
+
data = JSON.parse(text);
|
|
5888
|
+
} catch (e) {
|
|
5889
|
+
}
|
|
5890
|
+
if (!response.ok || !data || data.error_codes) {
|
|
5891
|
+
return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
|
|
5892
|
+
}
|
|
5893
|
+
return {
|
|
5894
|
+
success: true,
|
|
5895
|
+
provider: "checkoutcom",
|
|
5896
|
+
orderId,
|
|
5897
|
+
amount,
|
|
5898
|
+
reference: data.id,
|
|
5899
|
+
paymentUrl: data._links?.redirect?.href || data.reference,
|
|
5900
|
+
rawResponse: data
|
|
5901
|
+
};
|
|
5902
|
+
}
|
|
5903
|
+
} catch (e) {
|
|
5904
|
+
return { success: false, provider: "checkoutcom", orderId, amount, error: e.message, rawResponse: null };
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
async verifyCallback(body, config) {
|
|
5908
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
5909
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
5910
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
5911
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
5912
|
+
const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : true;
|
|
5913
|
+
const eventType = parsedBody?.type || "";
|
|
5914
|
+
const data = parsedBody?.data || parsedBody;
|
|
5915
|
+
const orderId = data?.reference || data?.metadata?.order_id || data?.id || "";
|
|
5916
|
+
const amount = Number(data?.amount || 0);
|
|
5917
|
+
const isPaid = eventType === "payment_approved" || eventType === "payment_captured" || data?.approved === true;
|
|
5918
|
+
const isPending = eventType === "payment_pending" || eventType === "payment_voided";
|
|
5919
|
+
const isExpired = eventType === "payment_expired";
|
|
5920
|
+
const isFailed = eventType === "payment_declined" || eventType === "payment_capture_declined";
|
|
5921
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5922
|
+
return {
|
|
5923
|
+
isValid,
|
|
5924
|
+
provider: "checkoutcom",
|
|
5925
|
+
orderId: String(orderId),
|
|
5926
|
+
amount,
|
|
5927
|
+
status,
|
|
5928
|
+
isPaid,
|
|
5929
|
+
isPending,
|
|
5930
|
+
isFailed,
|
|
5931
|
+
isExpired,
|
|
5932
|
+
statusCode: eventType,
|
|
5933
|
+
rawPayload: parsedBody
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
async getPaymentMethods(params, config) {
|
|
5937
|
+
const methods = [
|
|
5938
|
+
{ 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" },
|
|
5939
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
5940
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
5941
|
+
{ paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
5942
|
+
{ paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" },
|
|
5943
|
+
{ paymentMethod: "sofort", code: "sofort", paymentName: "Sofort / SEPA", paymentImage: "https://checkout.com/favicon.ico", totalFee: "0.8% + \u20AC0.25", category: "Virtual Account" }
|
|
5944
|
+
];
|
|
5945
|
+
const categories = {};
|
|
5946
|
+
for (const item of methods) {
|
|
5947
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
5948
|
+
categories[item.category].push(item);
|
|
5949
|
+
}
|
|
5950
|
+
return { success: true, provider: "checkoutcom", methods, categories, rawResponse: methods };
|
|
5951
|
+
}
|
|
5952
|
+
async checkTransaction(params, config) {
|
|
5953
|
+
const { merchantOrderId } = params;
|
|
5954
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
5955
|
+
const baseUrl = this.getBaseUrl(config);
|
|
5956
|
+
try {
|
|
5957
|
+
const response = await fetch(`${baseUrl}/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
5958
|
+
method: "GET",
|
|
5959
|
+
headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" }
|
|
5960
|
+
});
|
|
5961
|
+
const text = await response.text();
|
|
5962
|
+
let data = null;
|
|
5963
|
+
try {
|
|
5964
|
+
data = JSON.parse(text);
|
|
5965
|
+
} catch (e) {
|
|
5966
|
+
}
|
|
5967
|
+
if (!response.ok || !data) {
|
|
5968
|
+
return {
|
|
5969
|
+
success: false,
|
|
5970
|
+
provider: "checkoutcom",
|
|
5971
|
+
orderId: merchantOrderId,
|
|
5972
|
+
reference: "",
|
|
5973
|
+
amount: 0,
|
|
5974
|
+
statusCode: response.status.toString(),
|
|
5975
|
+
status: "failed",
|
|
5976
|
+
isPaid: false,
|
|
5977
|
+
isPending: false,
|
|
5978
|
+
isFailed: true,
|
|
5979
|
+
isExpired: false,
|
|
5980
|
+
statusMessage: "HTTP Error",
|
|
5981
|
+
rawResponse: data
|
|
5982
|
+
};
|
|
5983
|
+
}
|
|
5984
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
5985
|
+
const isPaid = statusRaw === "authorized" || statusRaw === "captured";
|
|
5986
|
+
const isPending = statusRaw === "pending" || statusRaw === "card_verified";
|
|
5987
|
+
const isExpired = statusRaw === "expired" || statusRaw === "voided";
|
|
5988
|
+
const isFailed = statusRaw === "declined" || statusRaw === "failed";
|
|
5989
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5990
|
+
return {
|
|
5991
|
+
success: true,
|
|
5992
|
+
provider: "checkoutcom",
|
|
5993
|
+
orderId: data.reference || merchantOrderId,
|
|
5994
|
+
reference: data.id || merchantOrderId,
|
|
5995
|
+
amount: Number(data.amount || 0),
|
|
5996
|
+
statusCode: statusRaw,
|
|
5997
|
+
status,
|
|
5998
|
+
isPaid,
|
|
5999
|
+
isPending,
|
|
6000
|
+
isFailed,
|
|
6001
|
+
isExpired,
|
|
6002
|
+
statusMessage: statusRaw,
|
|
6003
|
+
paymentType: data.payment_type || "card",
|
|
6004
|
+
transactionTime: data.requested_on ? new Date(data.requested_on) : void 0,
|
|
6005
|
+
rawResponse: data
|
|
6006
|
+
};
|
|
6007
|
+
} catch (e) {
|
|
6008
|
+
return {
|
|
6009
|
+
success: false,
|
|
6010
|
+
provider: "checkoutcom",
|
|
6011
|
+
orderId: merchantOrderId,
|
|
6012
|
+
reference: "",
|
|
6013
|
+
amount: 0,
|
|
6014
|
+
statusCode: "ERROR",
|
|
6015
|
+
status: "failed",
|
|
6016
|
+
isPaid: false,
|
|
6017
|
+
isPending: false,
|
|
6018
|
+
isFailed: true,
|
|
6019
|
+
isExpired: false,
|
|
6020
|
+
statusMessage: e.message,
|
|
6021
|
+
error: e.message,
|
|
6022
|
+
rawResponse: null
|
|
6023
|
+
};
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
};
|
|
6027
|
+
|
|
6028
|
+
// src/providers/razorpay/signature.ts
|
|
6029
|
+
import { createHmac as createHmac3 } from "crypto";
|
|
6030
|
+
function verifyRazorpayWebhook(rawBody, signature, webhookSecret) {
|
|
6031
|
+
if (!webhookSecret || !signature || !rawBody) return false;
|
|
6032
|
+
try {
|
|
6033
|
+
const expected = createHmac3("sha256", webhookSecret).update(rawBody).digest("hex");
|
|
6034
|
+
return expected === signature;
|
|
6035
|
+
} catch {
|
|
6036
|
+
return false;
|
|
6037
|
+
}
|
|
6038
|
+
}
|
|
6039
|
+
function buildRazorpayBasicAuth(keyId, keySecret) {
|
|
6040
|
+
return Buffer.from(`${keyId}:${keySecret}`).toString("base64");
|
|
6041
|
+
}
|
|
6042
|
+
|
|
6043
|
+
// src/providers/razorpay/provider.ts
|
|
6044
|
+
var RazorpayProvider = class extends BasePaymentProvider {
|
|
6045
|
+
name = "razorpay";
|
|
6046
|
+
getBaseUrl() {
|
|
6047
|
+
return "https://api.razorpay.com/v1";
|
|
6048
|
+
}
|
|
6049
|
+
buildHeaders(config) {
|
|
6050
|
+
const keyId = config.clientKey || config.merchantCode || config.merchantId || "";
|
|
6051
|
+
const keySecret = config.apiKey || config.secretKey || "";
|
|
6052
|
+
return {
|
|
6053
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
6054
|
+
"Content-Type": "application/json"
|
|
6055
|
+
};
|
|
6056
|
+
}
|
|
6057
|
+
async createInvoice(params, config) {
|
|
6058
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6059
|
+
const currency = (params.currency || "INR").toUpperCase();
|
|
6060
|
+
const baseUrl = this.getBaseUrl();
|
|
6061
|
+
const headers = this.buildHeaders(config);
|
|
6062
|
+
const isDirect = !!params.paymentMethod;
|
|
6063
|
+
try {
|
|
6064
|
+
if (isDirect) {
|
|
6065
|
+
const body = {
|
|
6066
|
+
amount,
|
|
6067
|
+
currency,
|
|
6068
|
+
receipt: orderId,
|
|
6069
|
+
notes: { order_id: orderId, product: productDetails },
|
|
6070
|
+
...params.providerParams
|
|
6071
|
+
};
|
|
6072
|
+
const response = await fetch(`${baseUrl}/orders`, {
|
|
6073
|
+
method: "POST",
|
|
6074
|
+
headers,
|
|
6075
|
+
body: JSON.stringify(body)
|
|
6076
|
+
});
|
|
6077
|
+
const text = await response.text();
|
|
6078
|
+
let data = null;
|
|
6079
|
+
try {
|
|
6080
|
+
data = JSON.parse(text);
|
|
6081
|
+
} catch (e) {
|
|
6082
|
+
}
|
|
6083
|
+
if (!response.ok || !data || data.error) {
|
|
6084
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6085
|
+
}
|
|
6086
|
+
return {
|
|
6087
|
+
success: true,
|
|
6088
|
+
provider: "razorpay",
|
|
6089
|
+
orderId,
|
|
6090
|
+
amount: data.amount || amount,
|
|
6091
|
+
reference: data.id,
|
|
6092
|
+
paymentCode: data.id,
|
|
6093
|
+
rawResponse: data
|
|
6094
|
+
};
|
|
6095
|
+
} else {
|
|
6096
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6097
|
+
const body = {
|
|
6098
|
+
amount,
|
|
6099
|
+
currency,
|
|
6100
|
+
description: productDetails,
|
|
6101
|
+
reference_id: orderId,
|
|
6102
|
+
customer: { name: customer?.name, email: customer?.email, contact: customer?.phone || "" },
|
|
6103
|
+
notify: { sms: false, email: !!customer?.email },
|
|
6104
|
+
reminder_enable: false,
|
|
6105
|
+
callback_url: callbackUrl || config.callbackUrl || successUrl,
|
|
6106
|
+
callback_method: "get",
|
|
6107
|
+
notes: { order_id: orderId },
|
|
6108
|
+
...params.providerParams
|
|
6109
|
+
};
|
|
6110
|
+
const response = await fetch(`${baseUrl}/payment_links`, {
|
|
6111
|
+
method: "POST",
|
|
6112
|
+
headers,
|
|
6113
|
+
body: JSON.stringify(body)
|
|
6114
|
+
});
|
|
6115
|
+
const text = await response.text();
|
|
6116
|
+
let data = null;
|
|
6117
|
+
try {
|
|
6118
|
+
data = JSON.parse(text);
|
|
6119
|
+
} catch (e) {
|
|
6120
|
+
}
|
|
6121
|
+
if (!response.ok || !data || data.error) {
|
|
6122
|
+
return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
|
|
6123
|
+
}
|
|
6124
|
+
return {
|
|
6125
|
+
success: true,
|
|
6126
|
+
provider: "razorpay",
|
|
6127
|
+
orderId,
|
|
6128
|
+
amount: data.amount || amount,
|
|
6129
|
+
reference: data.id,
|
|
6130
|
+
paymentUrl: data.short_url,
|
|
6131
|
+
rawResponse: data
|
|
6132
|
+
};
|
|
6133
|
+
}
|
|
6134
|
+
} catch (e) {
|
|
6135
|
+
return { success: false, provider: "razorpay", orderId, amount, error: e.message, rawResponse: null };
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
async verifyCallback(body, config) {
|
|
6139
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
6140
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6141
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6142
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6143
|
+
const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : true;
|
|
6144
|
+
const eventType = parsedBody?.event || "";
|
|
6145
|
+
const payload = parsedBody?.payload;
|
|
6146
|
+
const paymentEntity = payload?.payment?.entity || payload?.payment_link?.entity || parsedBody;
|
|
6147
|
+
const orderId = paymentEntity?.notes?.order_id || paymentEntity?.order_id || paymentEntity?.reference_id || paymentEntity?.id || "";
|
|
6148
|
+
const amount = Number(paymentEntity?.amount || 0);
|
|
6149
|
+
const statusRaw = (paymentEntity?.status || "").toLowerCase();
|
|
6150
|
+
const isPaid = eventType === "payment.captured" || eventType === "payment_link.paid" || statusRaw === "captured";
|
|
6151
|
+
const isPending = eventType === "payment.authorized" || statusRaw === "authorized" || statusRaw === "created";
|
|
6152
|
+
const isExpired = eventType === "payment_link.expired" || statusRaw === "expired";
|
|
6153
|
+
const isFailed = eventType === "payment.failed" || statusRaw === "failed";
|
|
6154
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6155
|
+
return {
|
|
6156
|
+
isValid,
|
|
6157
|
+
provider: "razorpay",
|
|
6158
|
+
orderId: String(orderId),
|
|
6159
|
+
amount,
|
|
6160
|
+
status,
|
|
6161
|
+
isPaid,
|
|
6162
|
+
isPending,
|
|
6163
|
+
isFailed,
|
|
6164
|
+
isExpired,
|
|
6165
|
+
statusCode: eventType || statusRaw,
|
|
6166
|
+
rawPayload: parsedBody
|
|
6167
|
+
};
|
|
6168
|
+
}
|
|
6169
|
+
async getPaymentMethods(params, config) {
|
|
6170
|
+
const methods = [
|
|
6171
|
+
{ paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "2% + GST", category: "Kartu Kredit" },
|
|
6172
|
+
{ paymentMethod: "upi", code: "upi", paymentName: "UPI (GPay, PhonePe, Paytm)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Free", category: "QRIS" },
|
|
6173
|
+
{ paymentMethod: "netbanking", code: "netbanking", paymentName: "Net Banking (50+ banks)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "\u20B910", category: "Virtual Account" },
|
|
6174
|
+
{ paymentMethod: "wallet", code: "wallet", paymentName: "Wallets (Paytm, PhonePe, etc.)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
|
|
6175
|
+
{ paymentMethod: "emi", code: "emi", paymentName: "EMI (Card / Cardless)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Bank charge", category: "Paylater / Cicilan" }
|
|
6176
|
+
];
|
|
6177
|
+
const categories = {};
|
|
6178
|
+
for (const item of methods) {
|
|
6179
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6180
|
+
categories[item.category].push(item);
|
|
6181
|
+
}
|
|
6182
|
+
return { success: true, provider: "razorpay", methods, categories, rawResponse: methods };
|
|
6183
|
+
}
|
|
6184
|
+
async checkTransaction(params, config) {
|
|
6185
|
+
const { merchantOrderId } = params;
|
|
6186
|
+
const baseUrl = this.getBaseUrl();
|
|
6187
|
+
const headers = this.buildHeaders(config);
|
|
6188
|
+
try {
|
|
6189
|
+
const endpoint = merchantOrderId.startsWith("plink_") ? `/payment_links/${encodeURIComponent(merchantOrderId)}` : `/payments/${encodeURIComponent(merchantOrderId)}`;
|
|
6190
|
+
const response = await fetch(`${baseUrl}${endpoint}`, { method: "GET", headers });
|
|
6191
|
+
const text = await response.text();
|
|
6192
|
+
let data = null;
|
|
6193
|
+
try {
|
|
6194
|
+
data = JSON.parse(text);
|
|
6195
|
+
} catch (e) {
|
|
6196
|
+
}
|
|
6197
|
+
if (!response.ok || !data || data.error) {
|
|
6198
|
+
return {
|
|
6199
|
+
success: false,
|
|
6200
|
+
provider: "razorpay",
|
|
6201
|
+
orderId: merchantOrderId,
|
|
6202
|
+
reference: "",
|
|
6203
|
+
amount: 0,
|
|
6204
|
+
statusCode: response.status.toString(),
|
|
6205
|
+
status: "failed",
|
|
6206
|
+
isPaid: false,
|
|
6207
|
+
isPending: false,
|
|
6208
|
+
isFailed: true,
|
|
6209
|
+
isExpired: false,
|
|
6210
|
+
statusMessage: data?.error?.description || "HTTP Error",
|
|
6211
|
+
rawResponse: data
|
|
6212
|
+
};
|
|
6213
|
+
}
|
|
6214
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
6215
|
+
const isPaid = statusRaw === "captured" || statusRaw === "paid";
|
|
6216
|
+
const isPending = statusRaw === "authorized" || statusRaw === "created";
|
|
6217
|
+
const isExpired = statusRaw === "expired";
|
|
6218
|
+
const isFailed = statusRaw === "failed";
|
|
6219
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6220
|
+
return {
|
|
6221
|
+
success: true,
|
|
6222
|
+
provider: "razorpay",
|
|
6223
|
+
orderId: data.notes?.order_id || data.reference_id || merchantOrderId,
|
|
6224
|
+
reference: data.id || merchantOrderId,
|
|
6225
|
+
amount: Number(data.amount || 0),
|
|
6226
|
+
statusCode: statusRaw,
|
|
6227
|
+
status,
|
|
6228
|
+
isPaid,
|
|
6229
|
+
isPending,
|
|
6230
|
+
isFailed,
|
|
6231
|
+
isExpired,
|
|
6232
|
+
statusMessage: statusRaw,
|
|
6233
|
+
paymentType: data.method || "card",
|
|
6234
|
+
transactionTime: data.created_at ? new Date(data.created_at * 1e3) : void 0,
|
|
6235
|
+
rawResponse: data
|
|
6236
|
+
};
|
|
6237
|
+
} catch (e) {
|
|
6238
|
+
return {
|
|
6239
|
+
success: false,
|
|
6240
|
+
provider: "razorpay",
|
|
6241
|
+
orderId: merchantOrderId,
|
|
6242
|
+
reference: "",
|
|
6243
|
+
amount: 0,
|
|
6244
|
+
statusCode: "ERROR",
|
|
6245
|
+
status: "failed",
|
|
6246
|
+
isPaid: false,
|
|
6247
|
+
isPending: false,
|
|
6248
|
+
isFailed: true,
|
|
6249
|
+
isExpired: false,
|
|
6250
|
+
statusMessage: e.message,
|
|
6251
|
+
error: e.message,
|
|
6252
|
+
rawResponse: null
|
|
6253
|
+
};
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
};
|
|
6257
|
+
|
|
6258
|
+
// src/providers/square/signature.ts
|
|
6259
|
+
import { createHmac as createHmac4 } from "crypto";
|
|
6260
|
+
function verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) {
|
|
6261
|
+
if (!signatureKey || !signatureHeader || !rawBody) return false;
|
|
6262
|
+
try {
|
|
6263
|
+
const payload = notificationUrl + rawBody;
|
|
6264
|
+
const expected = createHmac4("sha256", signatureKey).update(payload).digest("base64");
|
|
6265
|
+
return expected === signatureHeader;
|
|
6266
|
+
} catch {
|
|
6267
|
+
return false;
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6270
|
+
|
|
6271
|
+
// src/providers/square/provider.ts
|
|
6272
|
+
var SquareProvider = class extends BasePaymentProvider {
|
|
6273
|
+
name = "square";
|
|
6274
|
+
getBaseUrl(config) {
|
|
6275
|
+
return config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
6276
|
+
}
|
|
6277
|
+
buildHeaders(config) {
|
|
6278
|
+
return {
|
|
6279
|
+
"Authorization": `Bearer ${config.apiKey || config.secretKey || ""}`,
|
|
6280
|
+
"Content-Type": "application/json",
|
|
6281
|
+
"Square-Version": "2024-01-17"
|
|
6282
|
+
};
|
|
6283
|
+
}
|
|
6284
|
+
async createInvoice(params, config) {
|
|
6285
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
6286
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6287
|
+
const locationId = config.extra?.locationId || config.projectId || "";
|
|
6288
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6289
|
+
const headers = this.buildHeaders(config);
|
|
6290
|
+
const isDirect = !!params.paymentMethod;
|
|
6291
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6292
|
+
try {
|
|
6293
|
+
if (isDirect) {
|
|
6294
|
+
const sourceId = params.providerParams?.sourceId || params.providerParams?.nonce || "cnon:card-nonce-ok";
|
|
6295
|
+
const body = {
|
|
6296
|
+
idempotency_key: orderId,
|
|
6297
|
+
source_id: sourceId,
|
|
6298
|
+
amount_money: { amount, currency },
|
|
6299
|
+
reference_id: orderId,
|
|
6300
|
+
note: productDetails,
|
|
6301
|
+
buyer_email_address: customer?.email,
|
|
6302
|
+
...params.providerParams
|
|
6303
|
+
};
|
|
6304
|
+
const response = await fetch(`${baseUrl}/v2/payments`, {
|
|
6305
|
+
method: "POST",
|
|
6306
|
+
headers,
|
|
6307
|
+
body: JSON.stringify(body)
|
|
6308
|
+
});
|
|
6309
|
+
const text = await response.text();
|
|
6310
|
+
let data = null;
|
|
6311
|
+
try {
|
|
6312
|
+
data = JSON.parse(text);
|
|
6313
|
+
} catch (e) {
|
|
6314
|
+
}
|
|
6315
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6316
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6317
|
+
}
|
|
6318
|
+
const payment = data.payment || data;
|
|
6319
|
+
return {
|
|
6320
|
+
success: true,
|
|
6321
|
+
provider: "square",
|
|
6322
|
+
orderId,
|
|
6323
|
+
amount: payment.amount_money?.amount || amount,
|
|
6324
|
+
reference: payment.id,
|
|
6325
|
+
rawResponse: data
|
|
6326
|
+
};
|
|
6327
|
+
} else {
|
|
6328
|
+
const body = {
|
|
6329
|
+
idempotency_key: orderId,
|
|
6330
|
+
order: {
|
|
6331
|
+
location_id: locationId,
|
|
6332
|
+
reference_id: orderId,
|
|
6333
|
+
line_items: [
|
|
6334
|
+
{
|
|
6335
|
+
name: productDetails,
|
|
6336
|
+
quantity: "1",
|
|
6337
|
+
base_price_money: { amount, currency }
|
|
6338
|
+
}
|
|
6339
|
+
]
|
|
6340
|
+
},
|
|
6341
|
+
checkout_options: {
|
|
6342
|
+
redirect_url: successUrl,
|
|
6343
|
+
ask_for_shipping_address: false
|
|
6344
|
+
},
|
|
6345
|
+
pre_populated_data: {
|
|
6346
|
+
buyer_email: customer?.email
|
|
6347
|
+
},
|
|
6348
|
+
...params.providerParams
|
|
6349
|
+
};
|
|
6350
|
+
const response = await fetch(`${baseUrl}/v2/online-checkout/payment-links`, {
|
|
6351
|
+
method: "POST",
|
|
6352
|
+
headers,
|
|
6353
|
+
body: JSON.stringify(body)
|
|
6354
|
+
});
|
|
6355
|
+
const text = await response.text();
|
|
6356
|
+
let data = null;
|
|
6357
|
+
try {
|
|
6358
|
+
data = JSON.parse(text);
|
|
6359
|
+
} catch (e) {
|
|
6360
|
+
}
|
|
6361
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6362
|
+
return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
|
|
6363
|
+
}
|
|
6364
|
+
const link = data.payment_link || data;
|
|
6365
|
+
return {
|
|
6366
|
+
success: true,
|
|
6367
|
+
provider: "square",
|
|
6368
|
+
orderId,
|
|
6369
|
+
amount,
|
|
6370
|
+
reference: link.id,
|
|
6371
|
+
paymentUrl: link.url,
|
|
6372
|
+
rawResponse: data
|
|
6373
|
+
};
|
|
6374
|
+
}
|
|
6375
|
+
} catch (e) {
|
|
6376
|
+
return { success: false, provider: "square", orderId, amount, error: e.message, rawResponse: null };
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6379
|
+
async verifyCallback(body, config) {
|
|
6380
|
+
const signatureKey = config.extra?.webhookSignatureKey || config.secretKey || "";
|
|
6381
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6382
|
+
const notificationUrl = config.callbackUrl || config.extra?.notificationUrl || "";
|
|
6383
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6384
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6385
|
+
const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : true;
|
|
6386
|
+
const eventType = parsedBody?.type || "";
|
|
6387
|
+
const data = parsedBody?.data?.object || parsedBody?.data || parsedBody;
|
|
6388
|
+
const payment = data?.payment || data;
|
|
6389
|
+
const orderId = payment?.reference_id || payment?.order_id || payment?.id || "";
|
|
6390
|
+
const amount = Number(payment?.amount_money?.amount || 0);
|
|
6391
|
+
const statusRaw = (payment?.status || "").toUpperCase();
|
|
6392
|
+
const isPaid = statusRaw === "COMPLETED" || eventType === "payment.completed";
|
|
6393
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6394
|
+
const isFailed = statusRaw === "FAILED" || statusRaw === "CANCELED";
|
|
6395
|
+
const isExpired = eventType === "payment.expired";
|
|
6396
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6397
|
+
return {
|
|
6398
|
+
isValid,
|
|
6399
|
+
provider: "square",
|
|
6400
|
+
orderId: String(orderId),
|
|
6401
|
+
amount,
|
|
6402
|
+
status,
|
|
6403
|
+
isPaid,
|
|
6404
|
+
isPending,
|
|
6405
|
+
isFailed,
|
|
6406
|
+
isExpired,
|
|
6407
|
+
statusCode: eventType || statusRaw,
|
|
6408
|
+
rawPayload: parsedBody
|
|
6409
|
+
};
|
|
6410
|
+
}
|
|
6411
|
+
async getPaymentMethods(params, config) {
|
|
6412
|
+
const methods = [
|
|
6413
|
+
{ 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" },
|
|
6414
|
+
{ paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6415
|
+
{ paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6416
|
+
{ paymentMethod: "cash_app", code: "cashapp", paymentName: "Cash App Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
|
|
6417
|
+
{ paymentMethod: "afterpay", code: "afterpay", paymentName: "Afterpay / Clearpay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "6% + $0.30", category: "Paylater / Cicilan" }
|
|
6418
|
+
];
|
|
6419
|
+
const categories = {};
|
|
6420
|
+
for (const item of methods) {
|
|
6421
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6422
|
+
categories[item.category].push(item);
|
|
6423
|
+
}
|
|
6424
|
+
return { success: true, provider: "square", methods, categories, rawResponse: methods };
|
|
6425
|
+
}
|
|
6426
|
+
async checkTransaction(params, config) {
|
|
6427
|
+
const { merchantOrderId } = params;
|
|
6428
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6429
|
+
const headers = this.buildHeaders(config);
|
|
6430
|
+
try {
|
|
6431
|
+
const response = await fetch(`${baseUrl}/v2/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
6432
|
+
method: "GET",
|
|
6433
|
+
headers
|
|
6434
|
+
});
|
|
6435
|
+
const text = await response.text();
|
|
6436
|
+
let data = null;
|
|
6437
|
+
try {
|
|
6438
|
+
data = JSON.parse(text);
|
|
6439
|
+
} catch (e) {
|
|
6440
|
+
}
|
|
6441
|
+
if (!response.ok || !data || data.errors?.length) {
|
|
6442
|
+
return {
|
|
6443
|
+
success: false,
|
|
6444
|
+
provider: "square",
|
|
6445
|
+
orderId: merchantOrderId,
|
|
6446
|
+
reference: "",
|
|
6447
|
+
amount: 0,
|
|
6448
|
+
statusCode: response.status.toString(),
|
|
6449
|
+
status: "failed",
|
|
6450
|
+
isPaid: false,
|
|
6451
|
+
isPending: false,
|
|
6452
|
+
isFailed: true,
|
|
6453
|
+
isExpired: false,
|
|
6454
|
+
statusMessage: data?.errors?.[0]?.detail || "HTTP Error",
|
|
6455
|
+
rawResponse: data
|
|
6456
|
+
};
|
|
6457
|
+
}
|
|
6458
|
+
const payment = data.payment || data;
|
|
6459
|
+
const statusRaw = (payment.status || "").toUpperCase();
|
|
6460
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6461
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
|
|
6462
|
+
const isExpired = statusRaw === "CANCELED";
|
|
6463
|
+
const isFailed = statusRaw === "FAILED";
|
|
6464
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6465
|
+
return {
|
|
6466
|
+
success: true,
|
|
6467
|
+
provider: "square",
|
|
6468
|
+
orderId: payment.reference_id || merchantOrderId,
|
|
6469
|
+
reference: payment.id || merchantOrderId,
|
|
6470
|
+
amount: Number(payment.amount_money?.amount || 0),
|
|
6471
|
+
statusCode: statusRaw,
|
|
6472
|
+
status,
|
|
6473
|
+
isPaid,
|
|
6474
|
+
isPending,
|
|
6475
|
+
isFailed,
|
|
6476
|
+
isExpired,
|
|
6477
|
+
statusMessage: statusRaw,
|
|
6478
|
+
paymentType: payment.source_type || "card",
|
|
6479
|
+
transactionTime: payment.created_at ? new Date(payment.created_at) : void 0,
|
|
6480
|
+
rawResponse: data
|
|
6481
|
+
};
|
|
6482
|
+
} catch (e) {
|
|
6483
|
+
return {
|
|
6484
|
+
success: false,
|
|
6485
|
+
provider: "square",
|
|
6486
|
+
orderId: merchantOrderId,
|
|
6487
|
+
reference: "",
|
|
6488
|
+
amount: 0,
|
|
6489
|
+
statusCode: "ERROR",
|
|
6490
|
+
status: "failed",
|
|
6491
|
+
isPaid: false,
|
|
6492
|
+
isPending: false,
|
|
6493
|
+
isFailed: true,
|
|
6494
|
+
isExpired: false,
|
|
6495
|
+
statusMessage: e.message,
|
|
6496
|
+
error: e.message,
|
|
6497
|
+
rawResponse: null
|
|
6498
|
+
};
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
};
|
|
6502
|
+
|
|
6503
|
+
// src/providers/payu/signature.ts
|
|
6504
|
+
import { createHash } from "crypto";
|
|
6505
|
+
function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
|
|
6506
|
+
if (!md5Key || !signatureHeader || !rawBody) return false;
|
|
6507
|
+
try {
|
|
6508
|
+
const parts = {};
|
|
6509
|
+
for (const part of signatureHeader.split(";")) {
|
|
6510
|
+
const [k, v] = part.split("=");
|
|
6511
|
+
if (k && v) parts[k.trim()] = v.trim();
|
|
6512
|
+
}
|
|
6513
|
+
const providedSig = parts["signature"];
|
|
6514
|
+
const algorithm = (parts["algorithm"] || "MD5").toUpperCase();
|
|
6515
|
+
if (algorithm === "MD5") {
|
|
6516
|
+
const expected = createHash("md5").update(rawBody + md5Key).digest("hex");
|
|
6517
|
+
return expected === providedSig;
|
|
6518
|
+
} else if (algorithm === "SHA-256") {
|
|
6519
|
+
const expected = createHash("sha256").update(rawBody + md5Key).digest("hex");
|
|
6520
|
+
return expected === providedSig;
|
|
6521
|
+
}
|
|
6522
|
+
return false;
|
|
6523
|
+
} catch {
|
|
6524
|
+
return false;
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
function buildPayuBasicAuth(clientId, clientSecret) {
|
|
6528
|
+
return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
6529
|
+
}
|
|
6530
|
+
|
|
6531
|
+
// src/providers/payu/provider.ts
|
|
6532
|
+
var PayuProvider = class extends BasePaymentProvider {
|
|
6533
|
+
name = "payu";
|
|
6534
|
+
getBaseUrl(config) {
|
|
6535
|
+
return config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
6536
|
+
}
|
|
6537
|
+
/** OAuth2 Bearer Token untuk PayU */
|
|
6538
|
+
async getAccessToken(config) {
|
|
6539
|
+
const clientId = config.extra?.oauthClientId || config.clientKey || "";
|
|
6540
|
+
const clientSecret = config.extra?.oauthClientSecret || config.apiKey || config.secretKey || "";
|
|
6541
|
+
if (!clientId || !clientSecret) {
|
|
6542
|
+
return "";
|
|
6543
|
+
}
|
|
6544
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6545
|
+
const response = await fetch(`${baseUrl}/pl/standard/user/oauth/authorize`, {
|
|
6546
|
+
method: "POST",
|
|
6547
|
+
headers: {
|
|
6548
|
+
"Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`,
|
|
6549
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
6550
|
+
},
|
|
6551
|
+
body: "grant_type=client_credentials"
|
|
6552
|
+
});
|
|
6553
|
+
const text = await response.text();
|
|
6554
|
+
let data = null;
|
|
6555
|
+
try {
|
|
6556
|
+
data = JSON.parse(text);
|
|
6557
|
+
} catch (e) {
|
|
6558
|
+
}
|
|
6559
|
+
if (!response.ok || !data?.access_token) {
|
|
6560
|
+
throw new Error(data?.error_description || `Failed to get PayU access token: ${response.status}`);
|
|
6561
|
+
}
|
|
6562
|
+
return data.access_token;
|
|
6563
|
+
}
|
|
6564
|
+
async createInvoice(params, config) {
|
|
6565
|
+
const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
|
|
6566
|
+
const currency = (params.currency || "PLN").toUpperCase();
|
|
6567
|
+
const posId = config.merchantCode || config.merchantId || config.extra?.posId || "";
|
|
6568
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6569
|
+
let accessToken;
|
|
6570
|
+
try {
|
|
6571
|
+
accessToken = await this.getAccessToken(config);
|
|
6572
|
+
} catch (e) {
|
|
6573
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6574
|
+
}
|
|
6575
|
+
const isDirect = !!params.paymentMethod;
|
|
6576
|
+
const continueUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
6577
|
+
const notifyUrl = callbackUrl || config.callbackUrl || "";
|
|
6578
|
+
const body = {
|
|
6579
|
+
notifyUrl,
|
|
6580
|
+
customerIp: params.providerParams?.customerIp || "127.0.0.1",
|
|
6581
|
+
merchantPosId: posId,
|
|
6582
|
+
description: productDetails,
|
|
6583
|
+
currencyCode: currency,
|
|
6584
|
+
totalAmount: amount.toString(),
|
|
6585
|
+
extOrderId: orderId,
|
|
6586
|
+
continueUrl,
|
|
6587
|
+
buyer: {
|
|
6588
|
+
email: customer?.email,
|
|
6589
|
+
firstName: customer?.name?.split(" ")[0],
|
|
6590
|
+
lastName: customer?.name?.split(" ").slice(1).join(" ") || "-",
|
|
6591
|
+
phone: customer?.phone,
|
|
6592
|
+
language: "en"
|
|
6593
|
+
},
|
|
6594
|
+
products: [
|
|
6595
|
+
{ name: productDetails, unitPrice: amount.toString(), quantity: "1" }
|
|
6596
|
+
],
|
|
6597
|
+
...params.providerParams
|
|
6598
|
+
};
|
|
6599
|
+
if (isDirect && params.paymentMethod) {
|
|
6600
|
+
body.payMethods = {
|
|
6601
|
+
payMethod: {
|
|
6602
|
+
type: "PBL",
|
|
6603
|
+
value: params.paymentMethod
|
|
6604
|
+
// e.g. "blik", "c" (card), "ap" (Apple Pay)
|
|
6605
|
+
}
|
|
6606
|
+
};
|
|
6607
|
+
}
|
|
6608
|
+
try {
|
|
6609
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders`, {
|
|
6610
|
+
method: "POST",
|
|
6611
|
+
headers: {
|
|
6612
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
6613
|
+
"Content-Type": "application/json"
|
|
6614
|
+
},
|
|
6615
|
+
body: JSON.stringify(body),
|
|
6616
|
+
redirect: "manual"
|
|
6617
|
+
// PayU responds with 302
|
|
6618
|
+
});
|
|
6619
|
+
const text = await response.text();
|
|
6620
|
+
let data = null;
|
|
6621
|
+
try {
|
|
6622
|
+
data = JSON.parse(text);
|
|
6623
|
+
} catch (e) {
|
|
6624
|
+
}
|
|
6625
|
+
if (response.status === 302 || response.headers.get("location")) {
|
|
6626
|
+
const location = response.headers.get("location") || "";
|
|
6627
|
+
return {
|
|
6628
|
+
success: true,
|
|
6629
|
+
provider: "payu",
|
|
6630
|
+
orderId,
|
|
6631
|
+
amount,
|
|
6632
|
+
reference: data?.orderId || orderId,
|
|
6633
|
+
paymentUrl: location,
|
|
6634
|
+
rawResponse: data
|
|
6635
|
+
};
|
|
6636
|
+
}
|
|
6637
|
+
if (!response.ok || !data || data.status?.statusCode === "ERROR") {
|
|
6638
|
+
return { success: false, provider: "payu", orderId, amount, rawResponse: data, error: data?.status?.statusDesc || `HTTP ${response.status}` };
|
|
6639
|
+
}
|
|
6640
|
+
return {
|
|
6641
|
+
success: true,
|
|
6642
|
+
provider: "payu",
|
|
6643
|
+
orderId,
|
|
6644
|
+
amount,
|
|
6645
|
+
reference: data.orderId || orderId,
|
|
6646
|
+
paymentUrl: data.redirectUri,
|
|
6647
|
+
rawResponse: data
|
|
6648
|
+
};
|
|
6649
|
+
} catch (e) {
|
|
6650
|
+
return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
|
|
6651
|
+
}
|
|
6652
|
+
}
|
|
6653
|
+
async verifyCallback(body, config) {
|
|
6654
|
+
const md5Key = config.extra?.md5Key || config.apiKey || config.secretKey || "";
|
|
6655
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
6656
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
6657
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6658
|
+
const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : true;
|
|
6659
|
+
const order = parsedBody?.order || parsedBody;
|
|
6660
|
+
const orderId = order.extOrderId || order.orderId || "";
|
|
6661
|
+
const amount = Number(order.totalAmount || 0);
|
|
6662
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6663
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6664
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6665
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6666
|
+
const isExpired = false;
|
|
6667
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6668
|
+
return {
|
|
6669
|
+
isValid,
|
|
6670
|
+
provider: "payu",
|
|
6671
|
+
orderId: String(orderId),
|
|
6672
|
+
amount,
|
|
6673
|
+
status,
|
|
6674
|
+
isPaid,
|
|
6675
|
+
isPending,
|
|
6676
|
+
isFailed,
|
|
6677
|
+
isExpired,
|
|
6678
|
+
statusCode: statusRaw,
|
|
6679
|
+
rawPayload: parsedBody
|
|
6680
|
+
};
|
|
6681
|
+
}
|
|
6682
|
+
async getPaymentMethods(params, config) {
|
|
6683
|
+
const methods = [
|
|
6684
|
+
{ paymentMethod: "credit_card", code: "c", paymentName: "Credit / Debit Card", paymentImage: "https://payu.com/favicon.ico", totalFee: "1.5%+", category: "Kartu Kredit" },
|
|
6685
|
+
{ paymentMethod: "blik", code: "blik", paymentName: "BLIK (Poland)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "E-Wallet" },
|
|
6686
|
+
{ paymentMethod: "apple_pay", code: "ap", paymentName: "Apple Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6687
|
+
{ paymentMethod: "google_pay", code: "gp", paymentName: "Google Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
|
|
6688
|
+
{ paymentMethod: "bank_transfer", code: "t", paymentName: "Online Bank Transfer (50+ banks)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
6689
|
+
{ paymentMethod: "installment", code: "ai", paymentName: "Installments (PayU)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Bank rate", category: "Paylater / Cicilan" }
|
|
6690
|
+
];
|
|
6691
|
+
const categories = {};
|
|
6692
|
+
for (const item of methods) {
|
|
6693
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6694
|
+
categories[item.category].push(item);
|
|
6695
|
+
}
|
|
6696
|
+
return { success: true, provider: "payu", methods, categories, rawResponse: methods };
|
|
6697
|
+
}
|
|
6698
|
+
async checkTransaction(params, config) {
|
|
6699
|
+
const { merchantOrderId } = params;
|
|
6700
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6701
|
+
let accessToken;
|
|
6702
|
+
try {
|
|
6703
|
+
accessToken = await this.getAccessToken(config);
|
|
6704
|
+
} catch (e) {
|
|
6705
|
+
return {
|
|
6706
|
+
success: false,
|
|
6707
|
+
provider: "payu",
|
|
6708
|
+
orderId: merchantOrderId,
|
|
6709
|
+
reference: "",
|
|
6710
|
+
amount: 0,
|
|
6711
|
+
statusCode: "AUTH_ERROR",
|
|
6712
|
+
status: "failed",
|
|
6713
|
+
isPaid: false,
|
|
6714
|
+
isPending: false,
|
|
6715
|
+
isFailed: true,
|
|
6716
|
+
isExpired: false,
|
|
6717
|
+
statusMessage: e.message,
|
|
6718
|
+
error: e.message,
|
|
6719
|
+
rawResponse: null
|
|
6720
|
+
};
|
|
6721
|
+
}
|
|
6722
|
+
try {
|
|
6723
|
+
const response = await fetch(`${baseUrl}/api/v2_1/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
6724
|
+
method: "GET",
|
|
6725
|
+
headers: { "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/json" }
|
|
6726
|
+
});
|
|
6727
|
+
const text = await response.text();
|
|
6728
|
+
let data = null;
|
|
6729
|
+
try {
|
|
6730
|
+
data = JSON.parse(text);
|
|
6731
|
+
} catch (e) {
|
|
6732
|
+
}
|
|
6733
|
+
if (!response.ok || !data) {
|
|
6734
|
+
return {
|
|
6735
|
+
success: false,
|
|
6736
|
+
provider: "payu",
|
|
6737
|
+
orderId: merchantOrderId,
|
|
6738
|
+
reference: "",
|
|
6739
|
+
amount: 0,
|
|
6740
|
+
statusCode: response.status.toString(),
|
|
6741
|
+
status: "failed",
|
|
6742
|
+
isPaid: false,
|
|
6743
|
+
isPending: false,
|
|
6744
|
+
isFailed: true,
|
|
6745
|
+
isExpired: false,
|
|
6746
|
+
statusMessage: "HTTP Error",
|
|
6747
|
+
rawResponse: data
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6750
|
+
const order = data.orders?.[0] || data;
|
|
6751
|
+
const statusRaw = (order.status || "").toUpperCase();
|
|
6752
|
+
const isPaid = statusRaw === "COMPLETED";
|
|
6753
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
|
|
6754
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
|
|
6755
|
+
const isExpired = false;
|
|
6756
|
+
const status = isPaid ? "paid" : isPending ? "pending" : "failed";
|
|
6757
|
+
return {
|
|
6758
|
+
success: true,
|
|
6759
|
+
provider: "payu",
|
|
6760
|
+
orderId: order.extOrderId || merchantOrderId,
|
|
6761
|
+
reference: order.orderId || merchantOrderId,
|
|
6762
|
+
amount: Number(order.totalAmount || 0),
|
|
6763
|
+
statusCode: statusRaw,
|
|
6764
|
+
status,
|
|
6765
|
+
isPaid,
|
|
6766
|
+
isPending,
|
|
6767
|
+
isFailed,
|
|
6768
|
+
isExpired,
|
|
6769
|
+
statusMessage: statusRaw,
|
|
6770
|
+
transactionTime: order.orderCreateDate ? new Date(order.orderCreateDate) : void 0,
|
|
6771
|
+
rawResponse: data
|
|
6772
|
+
};
|
|
6773
|
+
} catch (e) {
|
|
6774
|
+
return {
|
|
6775
|
+
success: false,
|
|
6776
|
+
provider: "payu",
|
|
6777
|
+
orderId: merchantOrderId,
|
|
6778
|
+
reference: "",
|
|
6779
|
+
amount: 0,
|
|
6780
|
+
statusCode: "ERROR",
|
|
6781
|
+
status: "failed",
|
|
6782
|
+
isPaid: false,
|
|
6783
|
+
isPending: false,
|
|
6784
|
+
isFailed: true,
|
|
6785
|
+
isExpired: false,
|
|
6786
|
+
statusMessage: e.message,
|
|
6787
|
+
error: e.message,
|
|
6788
|
+
rawResponse: null
|
|
6789
|
+
};
|
|
6790
|
+
}
|
|
6791
|
+
}
|
|
6792
|
+
};
|
|
6793
|
+
|
|
6794
|
+
// src/providers/braintree/signature.ts
|
|
6795
|
+
import { createHash as createHash2, createHmac as createHmac6 } from "crypto";
|
|
6796
|
+
function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
|
|
6797
|
+
if (!privateKey || !btSignature || !btPayload) return false;
|
|
6798
|
+
try {
|
|
6799
|
+
const parts = btSignature.split("|");
|
|
6800
|
+
if (parts.length < 2) return false;
|
|
6801
|
+
const providedHmac = parts[1];
|
|
6802
|
+
const payload = Buffer.from(btPayload, "base64").toString("utf8");
|
|
6803
|
+
const secretHash = createHash2("sha1").update(privateKey).digest("hex");
|
|
6804
|
+
const expected = createHmac6("sha1", secretHash).update(payload).digest("hex");
|
|
6805
|
+
return expected === providedHmac;
|
|
6806
|
+
} catch {
|
|
6807
|
+
return false;
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
function buildBraintreeBasicAuth(publicKey, privateKey) {
|
|
6811
|
+
return Buffer.from(`${publicKey}:${privateKey}`).toString("base64");
|
|
6812
|
+
}
|
|
6813
|
+
|
|
6814
|
+
// src/providers/braintree/provider.ts
|
|
6815
|
+
var BraintreeProvider = class extends BasePaymentProvider {
|
|
6816
|
+
name = "braintree";
|
|
6817
|
+
getBaseUrl(config) {
|
|
6818
|
+
const merchantId = config.merchantCode || config.merchantId || "";
|
|
6819
|
+
const base = config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
6820
|
+
return `${base}/merchants/${merchantId}`;
|
|
6821
|
+
}
|
|
6822
|
+
buildHeaders(config) {
|
|
6823
|
+
const publicKey = config.clientKey || config.extra?.publicKey || "";
|
|
6824
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
6825
|
+
return {
|
|
6826
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
6827
|
+
"Content-Type": "application/json",
|
|
6828
|
+
"Braintree-Version": "2019-01-01"
|
|
6829
|
+
};
|
|
6830
|
+
}
|
|
6831
|
+
async createInvoice(params, config) {
|
|
6832
|
+
const { orderId, amount, productDetails, customer } = params;
|
|
6833
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
6834
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6835
|
+
const headers = this.buildHeaders(config);
|
|
6836
|
+
const isDirect = !!params.paymentMethod;
|
|
6837
|
+
try {
|
|
6838
|
+
if (isDirect) {
|
|
6839
|
+
const paymentMethodNonce = params.providerParams?.nonce || params.providerParams?.paymentMethodNonce || "fake-valid-nonce";
|
|
6840
|
+
const body = {
|
|
6841
|
+
transaction: {
|
|
6842
|
+
amount: (amount / 100).toFixed(2),
|
|
6843
|
+
payment_method_nonce: paymentMethodNonce,
|
|
6844
|
+
order_id: orderId,
|
|
6845
|
+
currency_iso_code: currency,
|
|
6846
|
+
options: { submit_for_settlement: true },
|
|
6847
|
+
customer: { first_name: customer?.name, email: customer?.email },
|
|
6848
|
+
custom_fields: { order_id: orderId },
|
|
6849
|
+
...params.providerParams
|
|
6850
|
+
}
|
|
6851
|
+
};
|
|
6852
|
+
const response = await fetch(`${baseUrl}/transactions`, {
|
|
6853
|
+
method: "POST",
|
|
6854
|
+
headers,
|
|
6855
|
+
body: JSON.stringify(body)
|
|
6856
|
+
});
|
|
6857
|
+
const text = await response.text();
|
|
6858
|
+
let data = null;
|
|
6859
|
+
try {
|
|
6860
|
+
data = JSON.parse(text);
|
|
6861
|
+
} catch (e) {
|
|
6862
|
+
}
|
|
6863
|
+
if (!response.ok || data?.apiErrorResponse) {
|
|
6864
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.apiErrorResponse?.message || `HTTP ${response.status}` };
|
|
6865
|
+
}
|
|
6866
|
+
const tx = data?.transaction || data;
|
|
6867
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
6868
|
+
return {
|
|
6869
|
+
success: statusRaw === "submitted_for_settlement" || statusRaw === "settling" || statusRaw === "settled",
|
|
6870
|
+
provider: "braintree",
|
|
6871
|
+
orderId,
|
|
6872
|
+
amount: Math.round(Number(tx.amount || amount / 100) * 100),
|
|
6873
|
+
reference: tx.id,
|
|
6874
|
+
rawResponse: data
|
|
6875
|
+
};
|
|
6876
|
+
} else {
|
|
6877
|
+
const body = { client_token: { customer_id: customer?.email || orderId } };
|
|
6878
|
+
const response = await fetch(`${baseUrl}/client_token`, {
|
|
6879
|
+
method: "POST",
|
|
6880
|
+
headers,
|
|
6881
|
+
body: JSON.stringify(body)
|
|
6882
|
+
});
|
|
6883
|
+
const text = await response.text();
|
|
6884
|
+
let data = null;
|
|
6885
|
+
try {
|
|
6886
|
+
data = JSON.parse(text);
|
|
6887
|
+
} catch (e) {
|
|
6888
|
+
}
|
|
6889
|
+
if (!response.ok || !data?.clientToken) {
|
|
6890
|
+
return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
6891
|
+
}
|
|
6892
|
+
return {
|
|
6893
|
+
success: true,
|
|
6894
|
+
provider: "braintree",
|
|
6895
|
+
orderId,
|
|
6896
|
+
amount,
|
|
6897
|
+
reference: orderId,
|
|
6898
|
+
paymentCode: data.clientToken,
|
|
6899
|
+
// Frontend uses this token for Drop-in UI
|
|
6900
|
+
rawResponse: data
|
|
6901
|
+
};
|
|
6902
|
+
}
|
|
6903
|
+
} catch (e) {
|
|
6904
|
+
return { success: false, provider: "braintree", orderId, amount, error: e.message, rawResponse: null };
|
|
6905
|
+
}
|
|
6906
|
+
}
|
|
6907
|
+
async verifyCallback(body, config) {
|
|
6908
|
+
const privateKey = config.apiKey || config.secretKey || "";
|
|
6909
|
+
const btSignature = config.extra?.btSignature || "";
|
|
6910
|
+
const btPayload = config.extra?.btPayload || "";
|
|
6911
|
+
const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : true;
|
|
6912
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
6913
|
+
const subject = parsedBody?.subject || parsedBody;
|
|
6914
|
+
const transaction = subject?.transaction || subject?.disbursement || parsedBody;
|
|
6915
|
+
const kind = parsedBody?.kind || parsedBody?.event || "";
|
|
6916
|
+
const orderId = transaction?.orderId || transaction?.order_id || transaction?.id || "";
|
|
6917
|
+
const amount = Math.round(Number(transaction?.amount || 0) * 100);
|
|
6918
|
+
const statusRaw = (transaction?.status || "").toLowerCase();
|
|
6919
|
+
const isPaid = kind === "transaction_settled" || kind === "transaction_disbursed" || statusRaw === "settled";
|
|
6920
|
+
const isPending = kind === "transaction_settlement_declined" || statusRaw === "submitted_for_settlement" || statusRaw === "settling";
|
|
6921
|
+
const isFailed = kind === "transaction_failed" || statusRaw === "failed" || statusRaw === "voided";
|
|
6922
|
+
const isExpired = statusRaw === "expired";
|
|
6923
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6924
|
+
return {
|
|
6925
|
+
isValid,
|
|
6926
|
+
provider: "braintree",
|
|
6927
|
+
orderId: String(orderId),
|
|
6928
|
+
amount,
|
|
6929
|
+
status,
|
|
6930
|
+
isPaid,
|
|
6931
|
+
isPending,
|
|
6932
|
+
isFailed,
|
|
6933
|
+
isExpired,
|
|
6934
|
+
statusCode: kind || statusRaw,
|
|
6935
|
+
rawPayload: parsedBody
|
|
6936
|
+
};
|
|
6937
|
+
}
|
|
6938
|
+
async getPaymentMethods(params, config) {
|
|
6939
|
+
const methods = [
|
|
6940
|
+
{ 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" },
|
|
6941
|
+
{ paymentMethod: "paypal", code: "PayPalAccount", paymentName: "PayPal (via Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "3.49% + fixed", category: "E-Wallet" },
|
|
6942
|
+
{ paymentMethod: "apple_pay", code: "ApplePayCard", paymentName: "Apple Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
6943
|
+
{ paymentMethod: "google_pay", code: "AndroidPayCard", paymentName: "Google Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
|
|
6944
|
+
{ paymentMethod: "venmo", code: "VenmoAccount", paymentName: "Venmo (US only)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "1.9% + $0.10", category: "E-Wallet" }
|
|
6945
|
+
];
|
|
6946
|
+
const categories = {};
|
|
6947
|
+
for (const item of methods) {
|
|
6948
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
6949
|
+
categories[item.category].push(item);
|
|
6950
|
+
}
|
|
6951
|
+
return { success: true, provider: "braintree", methods, categories, rawResponse: methods };
|
|
6952
|
+
}
|
|
6953
|
+
async checkTransaction(params, config) {
|
|
6954
|
+
const { merchantOrderId } = params;
|
|
6955
|
+
const baseUrl = this.getBaseUrl(config);
|
|
6956
|
+
const headers = this.buildHeaders(config);
|
|
6957
|
+
try {
|
|
6958
|
+
const response = await fetch(`${baseUrl}/transactions/${encodeURIComponent(merchantOrderId)}`, {
|
|
6959
|
+
method: "GET",
|
|
6960
|
+
headers
|
|
6961
|
+
});
|
|
6962
|
+
const text = await response.text();
|
|
6963
|
+
let data = null;
|
|
6964
|
+
try {
|
|
6965
|
+
data = JSON.parse(text);
|
|
6966
|
+
} catch (e) {
|
|
6967
|
+
}
|
|
6968
|
+
if (!response.ok || !data) {
|
|
6969
|
+
return {
|
|
6970
|
+
success: false,
|
|
6971
|
+
provider: "braintree",
|
|
6972
|
+
orderId: merchantOrderId,
|
|
6973
|
+
reference: "",
|
|
6974
|
+
amount: 0,
|
|
6975
|
+
statusCode: response.status.toString(),
|
|
6976
|
+
status: "failed",
|
|
6977
|
+
isPaid: false,
|
|
6978
|
+
isPending: false,
|
|
6979
|
+
isFailed: true,
|
|
6980
|
+
isExpired: false,
|
|
6981
|
+
statusMessage: "HTTP Error",
|
|
6982
|
+
rawResponse: data
|
|
6983
|
+
};
|
|
6984
|
+
}
|
|
6985
|
+
const tx = data.transaction || data;
|
|
6986
|
+
const statusRaw = (tx.status || "").toLowerCase();
|
|
6987
|
+
const isPaid = statusRaw === "settled" || statusRaw === "settling";
|
|
6988
|
+
const isPending = statusRaw === "submitted_for_settlement" || statusRaw === "authorized";
|
|
6989
|
+
const isExpired = statusRaw === "expired";
|
|
6990
|
+
const isFailed = statusRaw === "failed" || statusRaw === "voided";
|
|
6991
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
6992
|
+
return {
|
|
6993
|
+
success: true,
|
|
6994
|
+
provider: "braintree",
|
|
6995
|
+
orderId: tx.orderId || merchantOrderId,
|
|
6996
|
+
reference: tx.id || merchantOrderId,
|
|
6997
|
+
amount: Math.round(Number(tx.amount || 0) * 100),
|
|
6998
|
+
statusCode: statusRaw,
|
|
6999
|
+
status,
|
|
7000
|
+
isPaid,
|
|
7001
|
+
isPending,
|
|
7002
|
+
isFailed,
|
|
7003
|
+
isExpired,
|
|
7004
|
+
statusMessage: statusRaw,
|
|
7005
|
+
paymentType: tx.paymentInstrumentType || "card",
|
|
7006
|
+
transactionTime: tx.createdAt ? new Date(tx.createdAt) : void 0,
|
|
7007
|
+
rawResponse: data
|
|
7008
|
+
};
|
|
7009
|
+
} catch (e) {
|
|
7010
|
+
return {
|
|
7011
|
+
success: false,
|
|
7012
|
+
provider: "braintree",
|
|
7013
|
+
orderId: merchantOrderId,
|
|
7014
|
+
reference: "",
|
|
7015
|
+
amount: 0,
|
|
7016
|
+
statusCode: "ERROR",
|
|
7017
|
+
status: "failed",
|
|
7018
|
+
isPaid: false,
|
|
7019
|
+
isPending: false,
|
|
7020
|
+
isFailed: true,
|
|
7021
|
+
isExpired: false,
|
|
7022
|
+
statusMessage: e.message,
|
|
7023
|
+
error: e.message,
|
|
7024
|
+
rawResponse: null
|
|
7025
|
+
};
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
7028
|
+
};
|
|
7029
|
+
|
|
7030
|
+
// src/providers/twocheckout/signature.ts
|
|
7031
|
+
import { createHash as createHash3, createHmac as createHmac7 } from "crypto";
|
|
7032
|
+
function buildTwoCheckoutAuth(merchantCode, secretKey) {
|
|
7033
|
+
const date = Math.floor(Date.now() / 1e3).toString();
|
|
7034
|
+
const raw = merchantCode + date;
|
|
7035
|
+
const hmac = createHmac7("sha256", secretKey).update(raw).digest("hex");
|
|
7036
|
+
const header = `code="${merchantCode}" date="${date}" hash="${hmac}"`;
|
|
7037
|
+
return { header, date };
|
|
7038
|
+
}
|
|
7039
|
+
function verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) {
|
|
7040
|
+
if (!secretWord || !providedHash) return false;
|
|
7041
|
+
try {
|
|
7042
|
+
const raw = secretWord + saleId + productId + invoiceId;
|
|
7043
|
+
const expected = createHash3("md5").update(raw).digest("hex").toUpperCase();
|
|
7044
|
+
return expected === (providedHash || "").toUpperCase();
|
|
7045
|
+
} catch {
|
|
7046
|
+
return false;
|
|
7047
|
+
}
|
|
7048
|
+
}
|
|
7049
|
+
|
|
7050
|
+
// src/providers/twocheckout/provider.ts
|
|
7051
|
+
var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
7052
|
+
name = "twocheckout";
|
|
7053
|
+
getBaseUrl(config) {
|
|
7054
|
+
return config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
7055
|
+
}
|
|
7056
|
+
buildHeaders(config) {
|
|
7057
|
+
const merchantCode = config.merchantCode || config.merchantId || "";
|
|
7058
|
+
const secretKey = config.apiKey || config.secretKey || "";
|
|
7059
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
7060
|
+
return {
|
|
7061
|
+
"X-Avangate-Authentication": header,
|
|
7062
|
+
"Content-Type": "application/json",
|
|
7063
|
+
"Accept": "application/json"
|
|
7064
|
+
};
|
|
7065
|
+
}
|
|
7066
|
+
async createInvoice(params, config) {
|
|
7067
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
7068
|
+
const currency = (params.currency || "USD").toUpperCase();
|
|
7069
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7070
|
+
const headers = this.buildHeaders(config);
|
|
7071
|
+
const isDirect = !!params.paymentMethod;
|
|
7072
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
7073
|
+
const body = {
|
|
7074
|
+
Currency: currency,
|
|
7075
|
+
Language: "en",
|
|
7076
|
+
Country: config.extra?.country || "US",
|
|
7077
|
+
CustomerIP: params.providerParams?.customerIp || "127.0.0.1",
|
|
7078
|
+
Source: "API",
|
|
7079
|
+
MerchantReference: orderId,
|
|
7080
|
+
Items: [
|
|
7081
|
+
{
|
|
7082
|
+
Name: productDetails,
|
|
7083
|
+
Quantity: 1,
|
|
7084
|
+
Price: { Amount: (amount / 100).toFixed(2), Type: "CUSTOM" },
|
|
7085
|
+
Type: "PRODUCT",
|
|
7086
|
+
IsDynamic: true,
|
|
7087
|
+
Tangible: false
|
|
7088
|
+
}
|
|
7089
|
+
],
|
|
7090
|
+
BillingDetails: {
|
|
7091
|
+
FirstName: customer?.name?.split(" ")[0] || "Customer",
|
|
7092
|
+
LastName: customer?.name?.split(" ").slice(1).join(" ") || "Name",
|
|
7093
|
+
Email: customer?.email,
|
|
7094
|
+
Country: config.extra?.country || "US",
|
|
7095
|
+
Address1: config.extra?.address || "N/A",
|
|
7096
|
+
City: config.extra?.city || "N/A",
|
|
7097
|
+
State: config.extra?.state || "",
|
|
7098
|
+
Zip: config.extra?.zip || "00000"
|
|
7099
|
+
},
|
|
7100
|
+
...params.providerParams
|
|
7101
|
+
};
|
|
7102
|
+
if (!isDirect) {
|
|
7103
|
+
body.PaymentDetails = { Type: "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7104
|
+
} else {
|
|
7105
|
+
body.PaymentDetails = { Type: params.paymentMethod === "paypal" ? "PAYPAL" : "EES_TOKEN_PAYMENT", Currency: currency };
|
|
7106
|
+
}
|
|
7107
|
+
try {
|
|
7108
|
+
const response = await fetch(`${baseUrl}/6.0/orders`, {
|
|
7109
|
+
method: "POST",
|
|
7110
|
+
headers,
|
|
7111
|
+
body: JSON.stringify(body)
|
|
7112
|
+
});
|
|
7113
|
+
const text = await response.text();
|
|
7114
|
+
let data = null;
|
|
7115
|
+
try {
|
|
7116
|
+
data = JSON.parse(text);
|
|
7117
|
+
} catch (e) {
|
|
7118
|
+
}
|
|
7119
|
+
if (!response.ok || !data || data.error_code) {
|
|
7120
|
+
return { success: false, provider: "twocheckout", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
|
|
7121
|
+
}
|
|
7122
|
+
const paymentUrl = data.PaymentDetails?.PaymentMethod?.RedirectURL || data.PaymentDetails?.PaymentMethod?.Href || `${successUrl}?ref=${data.RefNo}`;
|
|
7123
|
+
return {
|
|
7124
|
+
success: true,
|
|
7125
|
+
provider: "twocheckout",
|
|
7126
|
+
orderId,
|
|
7127
|
+
amount,
|
|
7128
|
+
reference: data.RefNo || data.OrderNo?.toString(),
|
|
7129
|
+
paymentUrl,
|
|
7130
|
+
rawResponse: data
|
|
7131
|
+
};
|
|
7132
|
+
} catch (e) {
|
|
7133
|
+
return { success: false, provider: "twocheckout", orderId, amount, error: e.message, rawResponse: null };
|
|
7134
|
+
}
|
|
7135
|
+
}
|
|
7136
|
+
async verifyCallback(body, config) {
|
|
7137
|
+
const secretWord = config.extra?.secretWord || config.apiKey || "";
|
|
7138
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
7139
|
+
const saleId = parsedBody?.SALE_ID || parsedBody?.sale_id || "";
|
|
7140
|
+
const productId = parsedBody?.IPN_PID?.[0] || parsedBody?.product_id || "";
|
|
7141
|
+
const invoiceId = parsedBody?.IPN_PNAME?.[0] || parsedBody?.invoice_id || "";
|
|
7142
|
+
const providedHash = parsedBody?.HASH || parsedBody?.hash || "";
|
|
7143
|
+
const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : true;
|
|
7144
|
+
const orderId = parsedBody?.REFNOEXT || parsedBody?.ext_ref_no || parsedBody?.SALE_ID || "";
|
|
7145
|
+
const amount = Math.round(Number(parsedBody?.IPN_TOTAL_GENERAL || parsedBody?.total || 0) * 100);
|
|
7146
|
+
const statusRaw = (parsedBody?.ORDERSTATUS || parsedBody?.order_status || "").toUpperCase();
|
|
7147
|
+
const isPaid = statusRaw === "COMPLETE" || statusRaw === "COMPLETE_MANUAL";
|
|
7148
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7149
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND" || statusRaw === "FRAUD";
|
|
7150
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7151
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7152
|
+
return {
|
|
7153
|
+
isValid,
|
|
7154
|
+
provider: "twocheckout",
|
|
7155
|
+
orderId: String(orderId),
|
|
7156
|
+
amount,
|
|
7157
|
+
status,
|
|
7158
|
+
isPaid,
|
|
7159
|
+
isPending,
|
|
7160
|
+
isFailed,
|
|
7161
|
+
isExpired,
|
|
7162
|
+
statusCode: statusRaw,
|
|
7163
|
+
rawPayload: parsedBody
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
async getPaymentMethods(params, config) {
|
|
7167
|
+
const methods = [
|
|
7168
|
+
{ 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" },
|
|
7169
|
+
{ paymentMethod: "paypal", code: "PAYPAL", paymentName: "PayPal", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "E-Wallet" },
|
|
7170
|
+
{ paymentMethod: "wire_transfer", code: "WIRE", paymentName: "Wire Transfer / Bank Transfer", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
|
|
7171
|
+
{ paymentMethod: "paylater", code: "PAY_LATER", paymentName: "Buy Now Pay Later (Klarna)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" }
|
|
7172
|
+
];
|
|
7173
|
+
const categories = {};
|
|
7174
|
+
for (const item of methods) {
|
|
7175
|
+
if (!categories[item.category]) categories[item.category] = [];
|
|
7176
|
+
categories[item.category].push(item);
|
|
7177
|
+
}
|
|
7178
|
+
return { success: true, provider: "twocheckout", methods, categories, rawResponse: methods };
|
|
7179
|
+
}
|
|
7180
|
+
async checkTransaction(params, config) {
|
|
7181
|
+
const { merchantOrderId } = params;
|
|
7182
|
+
const baseUrl = this.getBaseUrl(config);
|
|
7183
|
+
const headers = this.buildHeaders(config);
|
|
7184
|
+
try {
|
|
7185
|
+
const response = await fetch(`${baseUrl}/6.0/orders/${encodeURIComponent(merchantOrderId)}`, {
|
|
7186
|
+
method: "GET",
|
|
7187
|
+
headers
|
|
7188
|
+
});
|
|
7189
|
+
const text = await response.text();
|
|
7190
|
+
let data = null;
|
|
7191
|
+
try {
|
|
7192
|
+
data = JSON.parse(text);
|
|
7193
|
+
} catch (e) {
|
|
7194
|
+
}
|
|
7195
|
+
if (!response.ok || !data || data.error_code) {
|
|
7196
|
+
return {
|
|
7197
|
+
success: false,
|
|
7198
|
+
provider: "twocheckout",
|
|
7199
|
+
orderId: merchantOrderId,
|
|
7200
|
+
reference: "",
|
|
7201
|
+
amount: 0,
|
|
7202
|
+
statusCode: response.status.toString(),
|
|
7203
|
+
status: "failed",
|
|
7204
|
+
isPaid: false,
|
|
7205
|
+
isPending: false,
|
|
7206
|
+
isFailed: true,
|
|
7207
|
+
isExpired: false,
|
|
7208
|
+
statusMessage: data?.message || "HTTP Error",
|
|
7209
|
+
rawResponse: data
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
7212
|
+
const statusRaw = (data.Status || "").toUpperCase();
|
|
7213
|
+
const isPaid = statusRaw === "COMPLETE";
|
|
7214
|
+
const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
|
|
7215
|
+
const isExpired = statusRaw === "EXPIRED";
|
|
7216
|
+
const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND";
|
|
7217
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
7218
|
+
return {
|
|
7219
|
+
success: true,
|
|
7220
|
+
provider: "twocheckout",
|
|
7221
|
+
orderId: data.ExternalReference || merchantOrderId,
|
|
7222
|
+
reference: data.RefNo?.toString() || merchantOrderId,
|
|
7223
|
+
amount: Math.round(Number(data.GrossAmount || 0) * 100),
|
|
7224
|
+
statusCode: statusRaw,
|
|
7225
|
+
status,
|
|
7226
|
+
isPaid,
|
|
7227
|
+
isPending,
|
|
7228
|
+
isFailed,
|
|
7229
|
+
isExpired,
|
|
7230
|
+
statusMessage: statusRaw,
|
|
7231
|
+
transactionTime: data.OrderDate ? new Date(data.OrderDate) : void 0,
|
|
7232
|
+
rawResponse: data
|
|
7233
|
+
};
|
|
7234
|
+
} catch (e) {
|
|
7235
|
+
return {
|
|
7236
|
+
success: false,
|
|
7237
|
+
provider: "twocheckout",
|
|
7238
|
+
orderId: merchantOrderId,
|
|
7239
|
+
reference: "",
|
|
7240
|
+
amount: 0,
|
|
7241
|
+
statusCode: "ERROR",
|
|
7242
|
+
status: "failed",
|
|
7243
|
+
isPaid: false,
|
|
7244
|
+
isPending: false,
|
|
7245
|
+
isFailed: true,
|
|
7246
|
+
isExpired: false,
|
|
7247
|
+
statusMessage: e.message,
|
|
7248
|
+
error: e.message,
|
|
7249
|
+
rawResponse: null
|
|
7250
|
+
};
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
};
|
|
7254
|
+
|
|
7255
|
+
// src/clients/duitku.ts
|
|
7256
|
+
var DuitkuClient = class {
|
|
7257
|
+
merchantCode;
|
|
7258
|
+
apiKey;
|
|
7259
|
+
sandbox;
|
|
7260
|
+
constructor(config) {
|
|
7261
|
+
this.merchantCode = config.merchantCode || "";
|
|
7262
|
+
this.apiKey = config.apiKey || config.serverKey || "";
|
|
7263
|
+
this.sandbox = !!config.sandbox;
|
|
7264
|
+
}
|
|
7265
|
+
getPassportBaseUrl() {
|
|
7266
|
+
return this.sandbox ? "https://sandbox.duitku.com/webapi" : "https://passport.duitku.com/webapi";
|
|
7267
|
+
}
|
|
7268
|
+
getApiBaseUrl() {
|
|
7269
|
+
return this.sandbox ? "https://api-sandbox.duitku.com" : "https://api-prod.duitku.com";
|
|
7270
|
+
}
|
|
7271
|
+
/**
|
|
7272
|
+
* Request helper generic dengan kalkulasi signature Duitku otomatis
|
|
7273
|
+
*/
|
|
7274
|
+
async request(method, endpoint, body = {}, options) {
|
|
7275
|
+
const baseUrl = options?.baseUrl === "api" ? this.getApiBaseUrl() : this.getPassportBaseUrl();
|
|
7276
|
+
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;
|
|
7277
|
+
const timestamp = Date.now().toString();
|
|
7278
|
+
const headerSignature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7279
|
+
const headers = {
|
|
7280
|
+
"Content-Type": "application/json",
|
|
7281
|
+
"Accept": "application/json",
|
|
7282
|
+
"x-duitku-signature": headerSignature,
|
|
7283
|
+
"x-duitku-timestamp": timestamp,
|
|
7284
|
+
"x-duitku-merchantcode": this.merchantCode,
|
|
7285
|
+
...options?.customHeaders
|
|
7286
|
+
};
|
|
7287
|
+
const fetchOptions = {
|
|
7288
|
+
method,
|
|
7289
|
+
headers
|
|
7290
|
+
};
|
|
7291
|
+
if (method === "POST" && body) {
|
|
7292
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7293
|
+
}
|
|
7294
|
+
const response = await fetch(url, fetchOptions);
|
|
7295
|
+
const text = await response.text();
|
|
7296
|
+
let data = null;
|
|
7297
|
+
try {
|
|
7298
|
+
data = JSON.parse(text);
|
|
7299
|
+
} catch (e) {
|
|
7300
|
+
}
|
|
7301
|
+
if (!response.ok) {
|
|
7302
|
+
throw new Error(data?.Message || data?.statusMessage || data?.responseMessage || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7303
|
+
}
|
|
7304
|
+
return data || text;
|
|
7305
|
+
}
|
|
7306
|
+
// ─── TRANSACTIONS & PAYMENT METHODS ──────────────────────────────────────────
|
|
7307
|
+
/**
|
|
7308
|
+
* Cek status transaksi pembayaran berdasarkan merchant order ID
|
|
7309
|
+
*/
|
|
7310
|
+
async checkTransaction(merchantOrderId) {
|
|
7311
|
+
const { bodySignature } = getDuitkuStatusSignatures(
|
|
7312
|
+
this.merchantCode,
|
|
7313
|
+
merchantOrderId,
|
|
7314
|
+
this.apiKey
|
|
7315
|
+
);
|
|
7316
|
+
return this.request(
|
|
7317
|
+
"POST",
|
|
7318
|
+
"/api/merchant/transactionStatus",
|
|
7319
|
+
{
|
|
7320
|
+
merchantCode: this.merchantCode,
|
|
7321
|
+
merchantOrderId,
|
|
7322
|
+
signature: bodySignature
|
|
7323
|
+
},
|
|
7324
|
+
{ baseUrl: "api" }
|
|
7325
|
+
);
|
|
7326
|
+
}
|
|
7327
|
+
/**
|
|
7328
|
+
* Ambil daftar channel pembayaran aktif dan kalkulasi fee dinamis
|
|
7329
|
+
*/
|
|
7330
|
+
async getPaymentMethods(amount = 1e4) {
|
|
7331
|
+
const integerAmount = Math.round(amount);
|
|
7332
|
+
const datetime = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
7333
|
+
const signature = getDuitkuPaymentMethodsSignature(this.merchantCode, integerAmount, datetime, this.apiKey);
|
|
7334
|
+
return this.request("POST", "/api/merchant/paymentmethod/getpaymentmethod", {
|
|
7335
|
+
merchantcode: this.merchantCode,
|
|
7336
|
+
amount: integerAmount,
|
|
7337
|
+
datetime,
|
|
7338
|
+
signature
|
|
7339
|
+
});
|
|
7340
|
+
}
|
|
7341
|
+
// ─── DISBURSEMENT & BALANCE INQUIRY ──────────────────────────────────────────
|
|
7342
|
+
/**
|
|
7343
|
+
* Cek saldo merchant (Balance Inquiry)
|
|
7344
|
+
*/
|
|
7345
|
+
async checkBalance() {
|
|
7346
|
+
const timestamp = Date.now().toString();
|
|
7347
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7348
|
+
try {
|
|
7349
|
+
const data = await this.request(
|
|
7350
|
+
"POST",
|
|
7351
|
+
"/api/merchant/checkBalance",
|
|
7352
|
+
{
|
|
7353
|
+
merchantCode: this.merchantCode,
|
|
7354
|
+
signature
|
|
7355
|
+
},
|
|
7356
|
+
{ baseUrl: "api" }
|
|
7357
|
+
);
|
|
7358
|
+
return {
|
|
7359
|
+
success: data.responseCode === "00" || data.statusCode === "00",
|
|
7360
|
+
balance: data.balance ? Number(data.balance) : void 0,
|
|
7361
|
+
rawResponse: data
|
|
7362
|
+
};
|
|
7363
|
+
} catch (e) {
|
|
7364
|
+
return {
|
|
7365
|
+
success: false,
|
|
7366
|
+
rawResponse: null,
|
|
7367
|
+
error: e.message || "Failed to check Duitku merchant balance"
|
|
7368
|
+
};
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
/**
|
|
7372
|
+
* Mengambil daftar bank yang didukung untuk transfer / penarikan dana
|
|
7373
|
+
*/
|
|
7374
|
+
async listBanks() {
|
|
7375
|
+
const timestamp = Date.now().toString();
|
|
7376
|
+
const signature = sha256(this.merchantCode + timestamp + this.apiKey);
|
|
7377
|
+
return this.request(
|
|
7378
|
+
"POST",
|
|
7379
|
+
"/api/disbursement/listBank",
|
|
7380
|
+
{
|
|
7381
|
+
merchantCode: this.merchantCode,
|
|
7382
|
+
signature
|
|
7383
|
+
},
|
|
7384
|
+
{ baseUrl: "api" }
|
|
7385
|
+
);
|
|
7386
|
+
}
|
|
7387
|
+
/**
|
|
7388
|
+
* Validasi nama pemilik rekening bank sebelum eksekusi transfer (Bank Account Inquiry)
|
|
7389
|
+
*/
|
|
7390
|
+
async inquiryBankAccount(bankCode, bankAccount) {
|
|
7391
|
+
const timestamp = Date.now().toString();
|
|
7392
|
+
const signature = sha256(this.merchantCode + bankCode + bankAccount + this.apiKey);
|
|
7393
|
+
return this.request(
|
|
7394
|
+
"POST",
|
|
7395
|
+
"/api/disbursement/inquiry",
|
|
7396
|
+
{
|
|
7397
|
+
merchantCode: this.merchantCode,
|
|
7398
|
+
bankCode,
|
|
7399
|
+
bankAccount,
|
|
7400
|
+
signature
|
|
7401
|
+
},
|
|
7402
|
+
{ baseUrl: "api" }
|
|
7403
|
+
);
|
|
7404
|
+
}
|
|
7405
|
+
/**
|
|
7406
|
+
* Eksekusi transfer dana / payout (Disbursement Transfer)
|
|
7407
|
+
*/
|
|
7408
|
+
async disburse(params) {
|
|
7409
|
+
const integerAmount = Math.round(params.amount);
|
|
7410
|
+
const signature = sha256(
|
|
7411
|
+
this.merchantCode + params.merchantOrderId + params.bankCode + params.bankAccount + integerAmount.toString() + this.apiKey
|
|
7412
|
+
);
|
|
7413
|
+
const payload = {
|
|
7414
|
+
merchantCode: this.merchantCode,
|
|
7415
|
+
merchantOrderId: params.merchantOrderId,
|
|
7416
|
+
bankCode: params.bankCode,
|
|
7417
|
+
bankAccount: params.bankAccount,
|
|
7418
|
+
amount: integerAmount,
|
|
7419
|
+
purpose: params.purpose,
|
|
7420
|
+
senderName: params.senderName || "",
|
|
7421
|
+
senderPhone: params.senderPhone || "",
|
|
7422
|
+
callbackUrl: params.callbackUrl || "",
|
|
5057
7423
|
signature
|
|
5058
7424
|
};
|
|
5059
|
-
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
7425
|
+
return this.request("POST", "/api/disbursement/transfer", payload, { baseUrl: "api" });
|
|
7426
|
+
}
|
|
7427
|
+
/**
|
|
7428
|
+
* Cek status disbursement berdasarkan merchant order ID
|
|
7429
|
+
*/
|
|
7430
|
+
async checkDisbursementStatus(merchantOrderId) {
|
|
7431
|
+
const signature = sha256(this.merchantCode + merchantOrderId + this.apiKey);
|
|
7432
|
+
return this.request(
|
|
7433
|
+
"POST",
|
|
7434
|
+
"/api/disbursement/checkStatus",
|
|
7435
|
+
{
|
|
7436
|
+
merchantCode: this.merchantCode,
|
|
7437
|
+
merchantOrderId,
|
|
7438
|
+
signature
|
|
7439
|
+
},
|
|
7440
|
+
{ baseUrl: "api" }
|
|
7441
|
+
);
|
|
7442
|
+
}
|
|
7443
|
+
};
|
|
7444
|
+
|
|
7445
|
+
// src/clients/ipaymu.ts
|
|
7446
|
+
var IpaymuClient = class {
|
|
7447
|
+
va;
|
|
7448
|
+
apiKey;
|
|
7449
|
+
sandbox;
|
|
7450
|
+
constructor(config) {
|
|
7451
|
+
this.va = config.merchantCode || config.merchantId || "";
|
|
7452
|
+
this.apiKey = config.apiKey || config.serverKey || "";
|
|
7453
|
+
this.sandbox = !!config.sandbox;
|
|
7454
|
+
}
|
|
7455
|
+
getBaseUrl() {
|
|
7456
|
+
return this.sandbox ? "https://sandbox.ipaymu.com/api/v2" : "https://my.ipaymu.com/api/v2";
|
|
7457
|
+
}
|
|
7458
|
+
/**
|
|
7459
|
+
* Helper request bertanda tangan iPaymu v2
|
|
7460
|
+
*/
|
|
7461
|
+
async request(method, endpoint, body) {
|
|
7462
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7463
|
+
const { signature, timestamp } = generateIpaymuSignature(method, this.va, this.apiKey, body);
|
|
7464
|
+
const headers = {
|
|
7465
|
+
"Content-Type": "application/json",
|
|
7466
|
+
"Accept": "application/json",
|
|
7467
|
+
"va": this.va,
|
|
7468
|
+
"signature": signature,
|
|
7469
|
+
"timestamp": timestamp
|
|
7470
|
+
};
|
|
7471
|
+
const fetchOptions = {
|
|
7472
|
+
method,
|
|
7473
|
+
headers
|
|
7474
|
+
};
|
|
7475
|
+
if (method === "POST" && body) {
|
|
7476
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7477
|
+
}
|
|
7478
|
+
const response = await fetch(url, fetchOptions);
|
|
7479
|
+
const text = await response.text();
|
|
7480
|
+
let data = null;
|
|
7481
|
+
try {
|
|
7482
|
+
data = JSON.parse(text);
|
|
7483
|
+
} catch (e) {
|
|
7484
|
+
}
|
|
7485
|
+
if (!response.ok) {
|
|
7486
|
+
throw new Error(data?.Message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7487
|
+
}
|
|
7488
|
+
return data;
|
|
7489
|
+
}
|
|
7490
|
+
/**
|
|
7491
|
+
* Cek saldo merchant iPaymu
|
|
7492
|
+
*/
|
|
7493
|
+
async checkBalance() {
|
|
7494
|
+
try {
|
|
7495
|
+
const payload = { account: this.va };
|
|
7496
|
+
const data = await this.request("POST", "/balance", payload);
|
|
7497
|
+
const success = data.Status === 200 || data.status === 200;
|
|
7498
|
+
const balance = data.Data?.MerchantBalance ? Number(data.Data.MerchantBalance) : void 0;
|
|
7499
|
+
return {
|
|
7500
|
+
success,
|
|
7501
|
+
balance,
|
|
7502
|
+
rawResponse: data
|
|
7503
|
+
};
|
|
7504
|
+
} catch (e) {
|
|
7505
|
+
return {
|
|
7506
|
+
success: false,
|
|
7507
|
+
rawResponse: null,
|
|
7508
|
+
error: e.message || "Failed to check iPaymu balance"
|
|
7509
|
+
};
|
|
7510
|
+
}
|
|
7511
|
+
}
|
|
7512
|
+
/**
|
|
7513
|
+
* Cek detail transaksi iPaymu
|
|
7514
|
+
*/
|
|
7515
|
+
async checkTransaction(transactionId) {
|
|
7516
|
+
return this.request("POST", "/transaction", { transactionId });
|
|
7517
|
+
}
|
|
7518
|
+
};
|
|
7519
|
+
|
|
7520
|
+
// src/clients/xendit.ts
|
|
7521
|
+
var XenditClient = class {
|
|
7522
|
+
apiKey;
|
|
7523
|
+
constructor(config) {
|
|
7524
|
+
this.apiKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
7525
|
+
}
|
|
7526
|
+
getBaseUrl() {
|
|
7527
|
+
return "https://api.xendit.co";
|
|
7528
|
+
}
|
|
7529
|
+
/**
|
|
7530
|
+
* HTTP Request helper bertanda tangan Basic Auth Xendit
|
|
7531
|
+
*/
|
|
7532
|
+
async request(method, endpoint, body) {
|
|
7533
|
+
const url = endpoint.startsWith("http") ? endpoint : `${this.getBaseUrl()}${endpoint}`;
|
|
7534
|
+
const authHeader = getXenditAuthHeader(this.apiKey);
|
|
7535
|
+
const headers = {
|
|
7536
|
+
"Content-Type": "application/json",
|
|
7537
|
+
"Accept": "application/json",
|
|
7538
|
+
"Authorization": authHeader
|
|
7539
|
+
};
|
|
7540
|
+
const fetchOptions = {
|
|
7541
|
+
method,
|
|
7542
|
+
headers
|
|
7543
|
+
};
|
|
7544
|
+
if ((method === "POST" || method === "PATCH") && body) {
|
|
7545
|
+
fetchOptions.body = JSON.stringify(body);
|
|
7546
|
+
}
|
|
7547
|
+
const response = await fetch(url, fetchOptions);
|
|
7548
|
+
const text = await response.text();
|
|
7549
|
+
let data = null;
|
|
7550
|
+
try {
|
|
7551
|
+
data = JSON.parse(text);
|
|
7552
|
+
} catch (e) {
|
|
7553
|
+
}
|
|
7554
|
+
if (!response.ok) {
|
|
7555
|
+
throw new Error(data?.message || data?.error_code || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7556
|
+
}
|
|
7557
|
+
return data;
|
|
7558
|
+
}
|
|
7559
|
+
/**
|
|
7560
|
+
* Cek Saldo Merchant Xendit
|
|
7561
|
+
*/
|
|
7562
|
+
async checkBalance(accountType = "CASH") {
|
|
7563
|
+
try {
|
|
7564
|
+
const data = await this.request("GET", `/balance?account_type=${accountType}`);
|
|
7565
|
+
return {
|
|
7566
|
+
success: data.balance !== void 0,
|
|
7567
|
+
balance: data.balance !== void 0 ? Number(data.balance) : void 0,
|
|
7568
|
+
rawResponse: data
|
|
7569
|
+
};
|
|
7570
|
+
} catch (e) {
|
|
7571
|
+
return {
|
|
7572
|
+
success: false,
|
|
7573
|
+
rawResponse: null,
|
|
7574
|
+
error: e.message || "Failed to check Xendit balance"
|
|
7575
|
+
};
|
|
7576
|
+
}
|
|
7577
|
+
}
|
|
7578
|
+
/**
|
|
7579
|
+
* Memaksa sebuah invoice kadaluwarsa (Expire Invoice)
|
|
7580
|
+
*/
|
|
7581
|
+
async expireInvoice(invoiceId) {
|
|
7582
|
+
return this.request("POST", `/invoices/${invoiceId}/expire!`);
|
|
7583
|
+
}
|
|
7584
|
+
/**
|
|
7585
|
+
* Eksekusi transfer dana / disbursement
|
|
7586
|
+
*/
|
|
7587
|
+
async createDisbursement(params) {
|
|
7588
|
+
return this.request("POST", "/disbursements", {
|
|
7589
|
+
external_id: params.externalId,
|
|
7590
|
+
bank_code: params.bankCode,
|
|
7591
|
+
account_holder_name: params.accountHolderName,
|
|
7592
|
+
account_number: params.accountNumber,
|
|
7593
|
+
description: params.description,
|
|
7594
|
+
amount: Math.round(params.amount)
|
|
7595
|
+
});
|
|
7596
|
+
}
|
|
7597
|
+
};
|
|
7598
|
+
|
|
7599
|
+
// src/clients/doku.ts
|
|
7600
|
+
var DokuClient = class {
|
|
7601
|
+
clientId;
|
|
7602
|
+
secretKey;
|
|
7603
|
+
sandbox;
|
|
7604
|
+
constructor(config) {
|
|
7605
|
+
this.clientId = config.merchantCode || config.clientId || config.clientKey || "";
|
|
7606
|
+
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
7607
|
+
this.sandbox = !!config.sandbox;
|
|
7608
|
+
}
|
|
7609
|
+
getBaseUrl() {
|
|
7610
|
+
return this.sandbox ? "https://api-sandbox.doku.com" : "https://api.doku.com";
|
|
7611
|
+
}
|
|
7612
|
+
/**
|
|
7613
|
+
* Helper request bertanda tangan DOKU Jokul v2
|
|
7614
|
+
*/
|
|
7615
|
+
async request(method, endpoint, body) {
|
|
7616
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7617
|
+
const headers = generateDokuHeaders(this.clientId, this.secretKey, endpoint, body);
|
|
7618
|
+
const fetchOptions = {
|
|
7619
|
+
method,
|
|
7620
|
+
headers: {
|
|
7621
|
+
"Content-Type": "application/json",
|
|
7622
|
+
...headers
|
|
7623
|
+
}
|
|
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?.error?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7637
|
+
}
|
|
7638
|
+
return data;
|
|
5060
7639
|
}
|
|
5061
7640
|
/**
|
|
5062
|
-
* Cek status
|
|
7641
|
+
* Cek status transaksi pesanan di DOKU
|
|
5063
7642
|
*/
|
|
5064
|
-
async
|
|
5065
|
-
|
|
5066
|
-
return this.request(
|
|
5067
|
-
"POST",
|
|
5068
|
-
"/api/disbursement/checkStatus",
|
|
5069
|
-
{
|
|
5070
|
-
merchantCode: this.merchantCode,
|
|
5071
|
-
merchantOrderId,
|
|
5072
|
-
signature
|
|
5073
|
-
},
|
|
5074
|
-
{ baseUrl: "api" }
|
|
5075
|
-
);
|
|
7643
|
+
async checkTransaction(invoiceNumber) {
|
|
7644
|
+
return this.request("GET", `/orders/v1/status/${invoiceNumber}`);
|
|
5076
7645
|
}
|
|
5077
7646
|
};
|
|
5078
7647
|
|
|
5079
|
-
// src/clients/
|
|
5080
|
-
var
|
|
5081
|
-
|
|
5082
|
-
|
|
7648
|
+
// src/clients/prismalink.ts
|
|
7649
|
+
var PrismalinkClient = class {
|
|
7650
|
+
merchantId;
|
|
7651
|
+
secretKey;
|
|
5083
7652
|
sandbox;
|
|
5084
7653
|
constructor(config) {
|
|
5085
|
-
this.
|
|
5086
|
-
this.
|
|
7654
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7655
|
+
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
5087
7656
|
this.sandbox = !!config.sandbox;
|
|
5088
7657
|
}
|
|
5089
7658
|
getBaseUrl() {
|
|
5090
|
-
return this.sandbox ? "https://sandbox.
|
|
7659
|
+
return this.sandbox ? "https://sandbox-api.prismalink.co.id" : "https://api.prismalink.co.id";
|
|
5091
7660
|
}
|
|
5092
7661
|
/**
|
|
5093
|
-
* Helper
|
|
7662
|
+
* Helper HTTP Request ke API PrismaLink
|
|
5094
7663
|
*/
|
|
5095
7664
|
async request(method, endpoint, body) {
|
|
5096
7665
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
5097
|
-
const { signature, timestamp } = generateIpaymuSignature(method, this.va, this.apiKey, body);
|
|
5098
|
-
const headers = {
|
|
5099
|
-
"Content-Type": "application/json",
|
|
5100
|
-
"Accept": "application/json",
|
|
5101
|
-
"va": this.va,
|
|
5102
|
-
"signature": signature,
|
|
5103
|
-
"timestamp": timestamp
|
|
5104
|
-
};
|
|
5105
7666
|
const fetchOptions = {
|
|
5106
7667
|
method,
|
|
5107
|
-
headers
|
|
7668
|
+
headers: {
|
|
7669
|
+
"Content-Type": "application/json",
|
|
7670
|
+
"Accept": "application/json"
|
|
7671
|
+
}
|
|
5108
7672
|
};
|
|
5109
7673
|
if (method === "POST" && body) {
|
|
5110
7674
|
fetchOptions.body = JSON.stringify(body);
|
|
@@ -5117,68 +7681,165 @@ var IpaymuClient = class {
|
|
|
5117
7681
|
} catch (e) {
|
|
5118
7682
|
}
|
|
5119
7683
|
if (!response.ok) {
|
|
5120
|
-
throw new Error(data?.
|
|
7684
|
+
throw new Error(data?.message || data?.response_message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5121
7685
|
}
|
|
5122
7686
|
return data;
|
|
5123
7687
|
}
|
|
5124
7688
|
/**
|
|
5125
|
-
* Cek
|
|
7689
|
+
* Cek status transaksi pesanan di PrismaLink
|
|
5126
7690
|
*/
|
|
5127
|
-
async
|
|
7691
|
+
async checkTransaction(orderId) {
|
|
7692
|
+
const signature = generatePrismalinkSignature(this.merchantId, orderId, 0, this.secretKey);
|
|
7693
|
+
return this.request("POST", "/api/v1/payment/status", {
|
|
7694
|
+
merchant_id: this.merchantId,
|
|
7695
|
+
order_id: orderId,
|
|
7696
|
+
signature
|
|
7697
|
+
});
|
|
7698
|
+
}
|
|
7699
|
+
};
|
|
7700
|
+
|
|
7701
|
+
// src/clients/faspay.ts
|
|
7702
|
+
var FaspayClient = class {
|
|
7703
|
+
merchantId;
|
|
7704
|
+
userId;
|
|
7705
|
+
password;
|
|
7706
|
+
sandbox;
|
|
7707
|
+
constructor(config) {
|
|
7708
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7709
|
+
this.userId = config.clientKey || config.userId || config.extra?.userId || this.merchantId;
|
|
7710
|
+
this.password = config.apiKey || config.password || config.serverKey || config.secretKey || "";
|
|
7711
|
+
this.sandbox = !!config.sandbox;
|
|
7712
|
+
}
|
|
7713
|
+
getBaseUrl() {
|
|
7714
|
+
return this.sandbox ? "https://sandbox.faspay.co.id" : "https://web.faspay.co.id";
|
|
7715
|
+
}
|
|
7716
|
+
/**
|
|
7717
|
+
* Helper HTTP Request ke endpoint Faspay
|
|
7718
|
+
*/
|
|
7719
|
+
async request(endpoint, payload) {
|
|
7720
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7721
|
+
const response = await fetch(url, {
|
|
7722
|
+
method: "POST",
|
|
7723
|
+
headers: {
|
|
7724
|
+
"Content-Type": "application/json",
|
|
7725
|
+
"Accept": "application/json"
|
|
7726
|
+
},
|
|
7727
|
+
body: JSON.stringify(payload)
|
|
7728
|
+
});
|
|
7729
|
+
const text = await response.text();
|
|
7730
|
+
let data = null;
|
|
5128
7731
|
try {
|
|
5129
|
-
|
|
5130
|
-
const data = await this.request("POST", "/balance", payload);
|
|
5131
|
-
const success = data.Status === 200 || data.status === 200;
|
|
5132
|
-
const balance = data.Data?.MerchantBalance ? Number(data.Data.MerchantBalance) : void 0;
|
|
5133
|
-
return {
|
|
5134
|
-
success,
|
|
5135
|
-
balance,
|
|
5136
|
-
rawResponse: data
|
|
5137
|
-
};
|
|
7732
|
+
data = JSON.parse(text);
|
|
5138
7733
|
} catch (e) {
|
|
5139
|
-
return {
|
|
5140
|
-
success: false,
|
|
5141
|
-
rawResponse: null,
|
|
5142
|
-
error: e.message || "Failed to check iPaymu balance"
|
|
5143
|
-
};
|
|
5144
7734
|
}
|
|
7735
|
+
if (!response.ok) {
|
|
7736
|
+
throw new Error(data?.response_desc || data?.response_message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7737
|
+
}
|
|
7738
|
+
return data;
|
|
5145
7739
|
}
|
|
5146
7740
|
/**
|
|
5147
|
-
* Cek
|
|
7741
|
+
* Cek status pembayaran tagihan Faspay
|
|
5148
7742
|
*/
|
|
5149
|
-
async checkTransaction(
|
|
5150
|
-
|
|
7743
|
+
async checkTransaction(billNo) {
|
|
7744
|
+
const signature = generateFaspaySignature(this.userId, this.password, billNo);
|
|
7745
|
+
return this.request("/cvr/100004/10", {
|
|
7746
|
+
request: "Inquiry Payment Status",
|
|
7747
|
+
merchant_id: this.merchantId,
|
|
7748
|
+
bill_no: billNo,
|
|
7749
|
+
signature
|
|
7750
|
+
});
|
|
7751
|
+
}
|
|
7752
|
+
/**
|
|
7753
|
+
* Batalkan tagihan pembayaran Faspay
|
|
7754
|
+
*/
|
|
7755
|
+
async cancelTransaction(billNo, paymentChannel) {
|
|
7756
|
+
const signature = generateFaspaySignature(this.userId, this.password, billNo);
|
|
7757
|
+
return this.request("/cvr/100005/10", {
|
|
7758
|
+
request: "Cancel Transaction",
|
|
7759
|
+
merchant_id: this.merchantId,
|
|
7760
|
+
bill_no: billNo,
|
|
7761
|
+
payment_channel: paymentChannel,
|
|
7762
|
+
signature
|
|
7763
|
+
});
|
|
5151
7764
|
}
|
|
5152
7765
|
};
|
|
5153
7766
|
|
|
5154
|
-
// src/clients/
|
|
5155
|
-
var
|
|
5156
|
-
|
|
7767
|
+
// src/clients/finpay.ts
|
|
7768
|
+
var FinpayClient = class {
|
|
7769
|
+
merchantId;
|
|
7770
|
+
merchantKey;
|
|
7771
|
+
sandbox;
|
|
5157
7772
|
constructor(config) {
|
|
5158
|
-
this.
|
|
7773
|
+
this.merchantId = config.merchantCode || config.merchantId || "";
|
|
7774
|
+
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
7775
|
+
this.sandbox = !!config.sandbox;
|
|
5159
7776
|
}
|
|
5160
7777
|
getBaseUrl() {
|
|
5161
|
-
return "https://
|
|
7778
|
+
return this.sandbox ? "https://sandbox.finpay.co.id" : "https://api.finpay.id";
|
|
5162
7779
|
}
|
|
5163
7780
|
/**
|
|
5164
|
-
* HTTP Request
|
|
7781
|
+
* Helper HTTP Request ke Finpay API
|
|
5165
7782
|
*/
|
|
5166
|
-
async request(
|
|
5167
|
-
const url =
|
|
5168
|
-
const
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
7783
|
+
async request(endpoint, payload) {
|
|
7784
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7785
|
+
const response = await fetch(url, {
|
|
7786
|
+
method: "POST",
|
|
7787
|
+
headers: {
|
|
7788
|
+
"Content-Type": "application/json",
|
|
7789
|
+
"Accept": "application/json"
|
|
7790
|
+
},
|
|
7791
|
+
body: JSON.stringify(payload)
|
|
7792
|
+
});
|
|
7793
|
+
const text = await response.text();
|
|
7794
|
+
let data = null;
|
|
7795
|
+
try {
|
|
7796
|
+
data = JSON.parse(text);
|
|
7797
|
+
} catch (e) {
|
|
5180
7798
|
}
|
|
5181
|
-
|
|
7799
|
+
if (!response.ok) {
|
|
7800
|
+
throw new Error(data?.response_desc || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
7801
|
+
}
|
|
7802
|
+
return data;
|
|
7803
|
+
}
|
|
7804
|
+
/**
|
|
7805
|
+
* Cek status transaksi pembayaran Finpay
|
|
7806
|
+
*/
|
|
7807
|
+
async checkTransaction(orderId) {
|
|
7808
|
+
const signature = generateFinpaySignature(this.merchantId, orderId, 0, this.merchantKey);
|
|
7809
|
+
return this.request("/pg/payment/status", {
|
|
7810
|
+
merchant_id: this.merchantId,
|
|
7811
|
+
order_id: orderId,
|
|
7812
|
+
signature
|
|
7813
|
+
});
|
|
7814
|
+
}
|
|
7815
|
+
};
|
|
7816
|
+
|
|
7817
|
+
// src/clients/nicepay.ts
|
|
7818
|
+
var NicepayClient = class {
|
|
7819
|
+
iMid;
|
|
7820
|
+
merchantKey;
|
|
7821
|
+
sandbox;
|
|
7822
|
+
constructor(config) {
|
|
7823
|
+
this.iMid = config.merchantCode || config.merchantId || config.iMid || "";
|
|
7824
|
+
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
7825
|
+
this.sandbox = !!config.sandbox;
|
|
7826
|
+
}
|
|
7827
|
+
getBaseUrl() {
|
|
7828
|
+
return this.sandbox ? "https://dev.nicepay.co.id/nicepay" : "https://www.nicepay.co.id/nicepay";
|
|
7829
|
+
}
|
|
7830
|
+
/**
|
|
7831
|
+
* Helper HTTP Request ke Nicepay API
|
|
7832
|
+
*/
|
|
7833
|
+
async request(endpoint, payload) {
|
|
7834
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7835
|
+
const response = await fetch(url, {
|
|
7836
|
+
method: "POST",
|
|
7837
|
+
headers: {
|
|
7838
|
+
"Content-Type": "application/json",
|
|
7839
|
+
"Accept": "application/json"
|
|
7840
|
+
},
|
|
7841
|
+
body: JSON.stringify(payload)
|
|
7842
|
+
});
|
|
5182
7843
|
const text = await response.text();
|
|
5183
7844
|
let data = null;
|
|
5184
7845
|
try {
|
|
@@ -5186,75 +7847,64 @@ var XenditClient = class {
|
|
|
5186
7847
|
} catch (e) {
|
|
5187
7848
|
}
|
|
5188
7849
|
if (!response.ok) {
|
|
5189
|
-
throw new Error(data?.
|
|
7850
|
+
throw new Error(data?.resultMsg || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5190
7851
|
}
|
|
5191
7852
|
return data;
|
|
5192
7853
|
}
|
|
5193
7854
|
/**
|
|
5194
|
-
* Cek
|
|
5195
|
-
*/
|
|
5196
|
-
async checkBalance(accountType = "CASH") {
|
|
5197
|
-
try {
|
|
5198
|
-
const data = await this.request("GET", `/balance?account_type=${accountType}`);
|
|
5199
|
-
return {
|
|
5200
|
-
success: data.balance !== void 0,
|
|
5201
|
-
balance: data.balance !== void 0 ? Number(data.balance) : void 0,
|
|
5202
|
-
rawResponse: data
|
|
5203
|
-
};
|
|
5204
|
-
} catch (e) {
|
|
5205
|
-
return {
|
|
5206
|
-
success: false,
|
|
5207
|
-
rawResponse: null,
|
|
5208
|
-
error: e.message || "Failed to check Xendit balance"
|
|
5209
|
-
};
|
|
5210
|
-
}
|
|
5211
|
-
}
|
|
5212
|
-
/**
|
|
5213
|
-
* Memaksa sebuah invoice kadaluwarsa (Expire Invoice)
|
|
7855
|
+
* Cek status transaksi pembayaran di Nicepay
|
|
5214
7856
|
*/
|
|
5215
|
-
async
|
|
5216
|
-
|
|
7857
|
+
async checkTransaction(referenceNo, amount = 0) {
|
|
7858
|
+
const timeStamp = formatNicepayTimestamp();
|
|
7859
|
+
const merchantToken = generateNicepayToken(timeStamp, this.iMid, referenceNo, amount, this.merchantKey);
|
|
7860
|
+
return this.request("/api/oneStepTransInquiry.do", {
|
|
7861
|
+
timeStamp,
|
|
7862
|
+
iMid: this.iMid,
|
|
7863
|
+
referenceNo,
|
|
7864
|
+
amt: String(amount),
|
|
7865
|
+
merchantToken
|
|
7866
|
+
});
|
|
5217
7867
|
}
|
|
5218
7868
|
/**
|
|
5219
|
-
*
|
|
7869
|
+
* Batalkan transaksi di Nicepay
|
|
5220
7870
|
*/
|
|
5221
|
-
async
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
7871
|
+
async cancelTransaction(tXid, payMethod, cancelMsg = "User Cancel") {
|
|
7872
|
+
const timeStamp = formatNicepayTimestamp();
|
|
7873
|
+
const merchantToken = sha256(`${timeStamp}${this.iMid}${tXid}0${this.merchantKey}`);
|
|
7874
|
+
return this.request("/api/oneStepTransCancel.do", {
|
|
7875
|
+
timeStamp,
|
|
7876
|
+
iMid: this.iMid,
|
|
7877
|
+
tXid,
|
|
7878
|
+
payMethod,
|
|
7879
|
+
cancelType: "1",
|
|
7880
|
+
cancelMsg,
|
|
7881
|
+
merchantToken
|
|
5229
7882
|
});
|
|
5230
7883
|
}
|
|
5231
7884
|
};
|
|
5232
7885
|
|
|
5233
|
-
// src/clients/
|
|
5234
|
-
var
|
|
5235
|
-
|
|
5236
|
-
|
|
7886
|
+
// src/clients/oy.ts
|
|
7887
|
+
var OyClient = class {
|
|
7888
|
+
username;
|
|
7889
|
+
apiKey;
|
|
5237
7890
|
sandbox;
|
|
5238
7891
|
constructor(config) {
|
|
5239
|
-
this.
|
|
5240
|
-
this.
|
|
7892
|
+
this.username = config.clientKey || config.username || config.merchantCode || "";
|
|
7893
|
+
this.apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5241
7894
|
this.sandbox = !!config.sandbox;
|
|
5242
7895
|
}
|
|
5243
7896
|
getBaseUrl() {
|
|
5244
|
-
return this.sandbox ? "https://api-
|
|
7897
|
+
return this.sandbox ? "https://api-stg.oyindonesia.com/api" : "https://api.oyindonesia.com/api";
|
|
5245
7898
|
}
|
|
5246
7899
|
/**
|
|
5247
|
-
* Helper
|
|
7900
|
+
* Helper HTTP Request ke OY! Bisnis API
|
|
5248
7901
|
*/
|
|
5249
7902
|
async request(method, endpoint, body) {
|
|
5250
7903
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
5251
|
-
const headers =
|
|
7904
|
+
const headers = generateOyHeaders(this.username, this.apiKey);
|
|
5252
7905
|
const fetchOptions = {
|
|
5253
7906
|
method,
|
|
5254
|
-
headers
|
|
5255
|
-
"Content-Type": "application/json",
|
|
5256
|
-
...headers
|
|
5257
|
-
}
|
|
7907
|
+
headers
|
|
5258
7908
|
};
|
|
5259
7909
|
if (method === "POST" && body) {
|
|
5260
7910
|
fetchOptions.body = JSON.stringify(body);
|
|
@@ -5267,45 +7917,61 @@ var DokuClient = class {
|
|
|
5267
7917
|
} catch (e) {
|
|
5268
7918
|
}
|
|
5269
7919
|
if (!response.ok) {
|
|
5270
|
-
throw new Error(data?.
|
|
7920
|
+
throw new Error(data?.status?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5271
7921
|
}
|
|
5272
7922
|
return data;
|
|
5273
7923
|
}
|
|
5274
7924
|
/**
|
|
5275
|
-
* Cek status transaksi
|
|
7925
|
+
* Cek status transaksi pembayaran
|
|
5276
7926
|
*/
|
|
5277
|
-
async checkTransaction(
|
|
5278
|
-
return this.request("GET", `/
|
|
7927
|
+
async checkTransaction(partnerTxId) {
|
|
7928
|
+
return this.request("GET", `/payment-checkout/status?partner_tx_id=${encodeURIComponent(partnerTxId)}&send_callback=false`);
|
|
7929
|
+
}
|
|
7930
|
+
/**
|
|
7931
|
+
* Cek saldo akun OY! Bisnis
|
|
7932
|
+
*/
|
|
7933
|
+
async checkBalance() {
|
|
7934
|
+
return this.request("GET", "/balance");
|
|
7935
|
+
}
|
|
7936
|
+
/**
|
|
7937
|
+
* Kirim dana / Transfer uang (Disbursement / Remittance)
|
|
7938
|
+
*/
|
|
7939
|
+
async remit(params) {
|
|
7940
|
+
return this.request("POST", "/remit", {
|
|
7941
|
+
recipient_bank: params.recipientBank,
|
|
7942
|
+
recipient_account: params.recipientAccount,
|
|
7943
|
+
amount: params.amount,
|
|
7944
|
+
note: params.note || "Disbursement",
|
|
7945
|
+
partner_trx_id: params.partnerTrxId
|
|
7946
|
+
});
|
|
5279
7947
|
}
|
|
5280
7948
|
};
|
|
5281
7949
|
|
|
5282
|
-
// src/clients/
|
|
5283
|
-
var
|
|
5284
|
-
merchantId;
|
|
7950
|
+
// src/clients/stripe.ts
|
|
7951
|
+
var StripeClient = class {
|
|
5285
7952
|
secretKey;
|
|
5286
|
-
sandbox;
|
|
5287
7953
|
constructor(config) {
|
|
5288
|
-
this.
|
|
5289
|
-
this.secretKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
5290
|
-
this.sandbox = !!config.sandbox;
|
|
7954
|
+
this.secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5291
7955
|
}
|
|
5292
7956
|
getBaseUrl() {
|
|
5293
|
-
return
|
|
7957
|
+
return "https://api.stripe.com/v1";
|
|
5294
7958
|
}
|
|
5295
7959
|
/**
|
|
5296
|
-
* Helper HTTP Request ke API
|
|
7960
|
+
* Helper HTTP Request ke Stripe API
|
|
5297
7961
|
*/
|
|
5298
7962
|
async request(method, endpoint, body) {
|
|
5299
7963
|
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
7964
|
+
const headers = {
|
|
7965
|
+
"Authorization": `Bearer ${this.secretKey}`,
|
|
7966
|
+
"Accept": "application/json"
|
|
7967
|
+
};
|
|
5300
7968
|
const fetchOptions = {
|
|
5301
7969
|
method,
|
|
5302
|
-
headers
|
|
5303
|
-
"Content-Type": "application/json",
|
|
5304
|
-
"Accept": "application/json"
|
|
5305
|
-
}
|
|
7970
|
+
headers
|
|
5306
7971
|
};
|
|
5307
7972
|
if (method === "POST" && body) {
|
|
5308
|
-
|
|
7973
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
7974
|
+
fetchOptions.body = serializeStripeParams(body);
|
|
5309
7975
|
}
|
|
5310
7976
|
const response = await fetch(url, fetchOptions);
|
|
5311
7977
|
const text = await response.text();
|
|
@@ -5314,270 +7980,567 @@ var PrismalinkClient = class {
|
|
|
5314
7980
|
data = JSON.parse(text);
|
|
5315
7981
|
} catch (e) {
|
|
5316
7982
|
}
|
|
5317
|
-
if (!response.ok) {
|
|
5318
|
-
throw new Error(data?.message ||
|
|
7983
|
+
if (!response.ok || data?.error) {
|
|
7984
|
+
throw new Error(data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5319
7985
|
}
|
|
5320
7986
|
return data;
|
|
5321
7987
|
}
|
|
5322
7988
|
/**
|
|
5323
|
-
*
|
|
7989
|
+
* Ambil detail Checkout Session
|
|
5324
7990
|
*/
|
|
5325
|
-
async
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
7991
|
+
async retrieveCheckoutSession(sessionId) {
|
|
7992
|
+
return this.request("GET", `/checkout/sessions/${encodeURIComponent(sessionId)}`);
|
|
7993
|
+
}
|
|
7994
|
+
/**
|
|
7995
|
+
* Ambil detail Payment Intent
|
|
7996
|
+
*/
|
|
7997
|
+
async retrievePaymentIntent(paymentIntentId) {
|
|
7998
|
+
return this.request("GET", `/payment_intents/${encodeURIComponent(paymentIntentId)}`);
|
|
7999
|
+
}
|
|
8000
|
+
/**
|
|
8001
|
+
* Cek saldo akun Stripe (Balance)
|
|
8002
|
+
*/
|
|
8003
|
+
async checkBalance() {
|
|
8004
|
+
return this.request("GET", "/balance");
|
|
8005
|
+
}
|
|
8006
|
+
/**
|
|
8007
|
+
* Buat refund dana
|
|
8008
|
+
*/
|
|
8009
|
+
async createRefund(paymentIntentId, amount) {
|
|
8010
|
+
const payload = {
|
|
8011
|
+
payment_intent: paymentIntentId
|
|
8012
|
+
};
|
|
8013
|
+
if (amount) {
|
|
8014
|
+
payload.amount = Math.round(amount);
|
|
8015
|
+
}
|
|
8016
|
+
return this.request("POST", "/refunds", payload);
|
|
5332
8017
|
}
|
|
5333
8018
|
};
|
|
5334
8019
|
|
|
5335
|
-
// src/clients/
|
|
5336
|
-
var
|
|
5337
|
-
|
|
5338
|
-
userId;
|
|
5339
|
-
password;
|
|
5340
|
-
sandbox;
|
|
8020
|
+
// src/clients/paypal.ts
|
|
8021
|
+
var PaypalClient = class {
|
|
8022
|
+
config;
|
|
5341
8023
|
constructor(config) {
|
|
5342
|
-
this.
|
|
5343
|
-
this.userId = config.clientKey || config.userId || config.extra?.userId || this.merchantId;
|
|
5344
|
-
this.password = config.apiKey || config.password || config.serverKey || config.secretKey || "";
|
|
5345
|
-
this.sandbox = !!config.sandbox;
|
|
8024
|
+
this.config = config;
|
|
5346
8025
|
}
|
|
5347
8026
|
getBaseUrl() {
|
|
5348
|
-
return this.sandbox ? "https://sandbox.
|
|
8027
|
+
return this.config.sandbox !== false ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
|
|
5349
8028
|
}
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
const
|
|
5355
|
-
const response = await fetch(url, {
|
|
8029
|
+
async getAccessToken() {
|
|
8030
|
+
const clientId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8031
|
+
const clientSecret = this.config.apiKey || this.config.secretKey || "";
|
|
8032
|
+
const auth = buildPaypalBasicAuth(clientId, clientSecret);
|
|
8033
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/oauth2/token`, {
|
|
5356
8034
|
method: "POST",
|
|
5357
|
-
headers: {
|
|
5358
|
-
|
|
5359
|
-
"Accept": "application/json"
|
|
5360
|
-
},
|
|
5361
|
-
body: JSON.stringify(payload)
|
|
8035
|
+
headers: { "Authorization": `Basic ${auth}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8036
|
+
body: "grant_type=client_credentials"
|
|
5362
8037
|
});
|
|
5363
|
-
const
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
8038
|
+
const data = await response.json();
|
|
8039
|
+
if (!data?.access_token) throw new Error(data?.error_description || "Failed to get PayPal access token");
|
|
8040
|
+
return data.access_token;
|
|
8041
|
+
}
|
|
8042
|
+
/** Ambil detail order PayPal berdasarkan Order ID */
|
|
8043
|
+
async getOrder(orderId) {
|
|
8044
|
+
const token = await this.getAccessToken();
|
|
8045
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}`, {
|
|
8046
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8047
|
+
});
|
|
8048
|
+
return response.json();
|
|
8049
|
+
}
|
|
8050
|
+
/** Capture order PayPal (mengeksekusi pembayaran yang sudah diapprove buyer) */
|
|
8051
|
+
async captureOrder(orderId) {
|
|
8052
|
+
const token = await this.getAccessToken();
|
|
8053
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}/capture`, {
|
|
8054
|
+
method: "POST",
|
|
8055
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8056
|
+
body: "{}"
|
|
8057
|
+
});
|
|
8058
|
+
return response.json();
|
|
8059
|
+
}
|
|
8060
|
+
/** Refund capture PayPal */
|
|
8061
|
+
async refundCapture(captureId, amount, currency) {
|
|
8062
|
+
const token = await this.getAccessToken();
|
|
8063
|
+
const body = {};
|
|
8064
|
+
if (amount && currency) {
|
|
8065
|
+
body.amount = { value: (amount / 100).toFixed(2), currency_code: currency };
|
|
8066
|
+
body.note_to_payer = "Refund";
|
|
5368
8067
|
}
|
|
5369
|
-
|
|
5370
|
-
|
|
8068
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/captures/${captureId}/refund`, {
|
|
8069
|
+
method: "POST",
|
|
8070
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8071
|
+
body: JSON.stringify(body)
|
|
8072
|
+
});
|
|
8073
|
+
return response.json();
|
|
8074
|
+
}
|
|
8075
|
+
/** Cek saldo akun PayPal merchant (hanya tersedia di account via Seller REST API) */
|
|
8076
|
+
async checkBalance() {
|
|
8077
|
+
const token = await this.getAccessToken();
|
|
8078
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/reporting/balances`, {
|
|
8079
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8080
|
+
});
|
|
8081
|
+
return response.json();
|
|
8082
|
+
}
|
|
8083
|
+
/** Verifikasi webhook via PayPal Webhook Verification API */
|
|
8084
|
+
async verifyWebhookSignature(webhookId, body, headers) {
|
|
8085
|
+
const token = await this.getAccessToken();
|
|
8086
|
+
const verifyBody = {
|
|
8087
|
+
auth_algo: headers["paypal-auth-algo"],
|
|
8088
|
+
cert_url: headers["paypal-cert-url"],
|
|
8089
|
+
transmission_id: headers["paypal-transmission-id"],
|
|
8090
|
+
transmission_sig: headers["paypal-transmission-sig"],
|
|
8091
|
+
transmission_time: headers["paypal-transmission-time"],
|
|
8092
|
+
webhook_id: webhookId,
|
|
8093
|
+
webhook_event: typeof body === "string" ? JSON.parse(body) : body
|
|
8094
|
+
};
|
|
8095
|
+
const response = await fetch(`${this.getBaseUrl()}/v1/notifications/verify-webhook-signature`, {
|
|
8096
|
+
method: "POST",
|
|
8097
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8098
|
+
body: JSON.stringify(verifyBody)
|
|
8099
|
+
});
|
|
8100
|
+
const data = await response.json();
|
|
8101
|
+
return data?.verification_status === "SUCCESS";
|
|
8102
|
+
}
|
|
8103
|
+
};
|
|
8104
|
+
|
|
8105
|
+
// src/clients/adyen.ts
|
|
8106
|
+
var AdyenClient = class {
|
|
8107
|
+
config;
|
|
8108
|
+
constructor(config) {
|
|
8109
|
+
this.config = config;
|
|
8110
|
+
}
|
|
8111
|
+
getBaseUrl() {
|
|
8112
|
+
if (this.config.sandbox === false) {
|
|
8113
|
+
const prefix = this.config.extra?.liveUrlPrefix || this.config.projectId || "";
|
|
8114
|
+
if (prefix) return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
|
|
5371
8115
|
}
|
|
5372
|
-
return
|
|
8116
|
+
return "https://checkout-test.adyen.com";
|
|
8117
|
+
}
|
|
8118
|
+
buildHeaders() {
|
|
8119
|
+
return {
|
|
8120
|
+
"X-API-Key": this.config.apiKey || this.config.secretKey || "",
|
|
8121
|
+
"Content-Type": "application/json"
|
|
8122
|
+
};
|
|
8123
|
+
}
|
|
8124
|
+
/** Ambil detail payment berdasarkan PSP Reference */
|
|
8125
|
+
async getPaymentDetails(pspReference) {
|
|
8126
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}`, {
|
|
8127
|
+
method: "GET",
|
|
8128
|
+
headers: this.buildHeaders()
|
|
8129
|
+
});
|
|
8130
|
+
return response.json();
|
|
8131
|
+
}
|
|
8132
|
+
/** Batalkan payment (sebelum capture) */
|
|
8133
|
+
async cancelPayment(pspReference, merchantAccount) {
|
|
8134
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8135
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/cancels`, {
|
|
8136
|
+
method: "POST",
|
|
8137
|
+
headers: this.buildHeaders(),
|
|
8138
|
+
body: JSON.stringify({ merchantAccount: account })
|
|
8139
|
+
});
|
|
8140
|
+
return response.json();
|
|
8141
|
+
}
|
|
8142
|
+
/** Refund payment yang sudah di-capture */
|
|
8143
|
+
async refundPayment(pspReference, amount, currency, merchantAccount) {
|
|
8144
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8145
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/refunds`, {
|
|
8146
|
+
method: "POST",
|
|
8147
|
+
headers: this.buildHeaders(),
|
|
8148
|
+
body: JSON.stringify({
|
|
8149
|
+
merchantAccount: account,
|
|
8150
|
+
amount: { value: amount, currency }
|
|
8151
|
+
})
|
|
8152
|
+
});
|
|
8153
|
+
return response.json();
|
|
8154
|
+
}
|
|
8155
|
+
/** Capture authorized payment */
|
|
8156
|
+
async capturePayment(pspReference, amount, currency, merchantAccount) {
|
|
8157
|
+
const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
|
|
8158
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/captures`, {
|
|
8159
|
+
method: "POST",
|
|
8160
|
+
headers: this.buildHeaders(),
|
|
8161
|
+
body: JSON.stringify({
|
|
8162
|
+
merchantAccount: account,
|
|
8163
|
+
amount: { value: amount, currency }
|
|
8164
|
+
})
|
|
8165
|
+
});
|
|
8166
|
+
return response.json();
|
|
8167
|
+
}
|
|
8168
|
+
/** Ambil daftar payment methods yang tersedia */
|
|
8169
|
+
async getAvailablePaymentMethods(merchantAccount, countryCode, currency, amount) {
|
|
8170
|
+
const response = await fetch(`${this.getBaseUrl()}/v68/paymentMethods`, {
|
|
8171
|
+
method: "POST",
|
|
8172
|
+
headers: this.buildHeaders(),
|
|
8173
|
+
body: JSON.stringify({ merchantAccount, countryCode, channel: "Web", amount: { value: amount, currency } })
|
|
8174
|
+
});
|
|
8175
|
+
return response.json();
|
|
8176
|
+
}
|
|
8177
|
+
};
|
|
8178
|
+
|
|
8179
|
+
// src/clients/checkoutcom.ts
|
|
8180
|
+
var CheckoutComClient = class {
|
|
8181
|
+
config;
|
|
8182
|
+
constructor(config) {
|
|
8183
|
+
this.config = config;
|
|
8184
|
+
}
|
|
8185
|
+
getBaseUrl() {
|
|
8186
|
+
return this.config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
|
|
8187
|
+
}
|
|
8188
|
+
buildHeaders() {
|
|
8189
|
+
return {
|
|
8190
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8191
|
+
"Content-Type": "application/json"
|
|
8192
|
+
};
|
|
8193
|
+
}
|
|
8194
|
+
/** Ambil detail payment berdasarkan Payment ID */
|
|
8195
|
+
async getPaymentDetails(paymentId) {
|
|
8196
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8197
|
+
method: "GET",
|
|
8198
|
+
headers: this.buildHeaders()
|
|
8199
|
+
});
|
|
8200
|
+
return response.json();
|
|
8201
|
+
}
|
|
8202
|
+
/** Void (batalkan) payment yang belum di-capture */
|
|
8203
|
+
async voidPayment(paymentId, reference) {
|
|
8204
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/voids`, {
|
|
8205
|
+
method: "POST",
|
|
8206
|
+
headers: this.buildHeaders(),
|
|
8207
|
+
body: JSON.stringify({ reference })
|
|
8208
|
+
});
|
|
8209
|
+
return response.json();
|
|
8210
|
+
}
|
|
8211
|
+
/** Refund payment yang sudah di-capture */
|
|
8212
|
+
async refundPayment(paymentId, amount, reference) {
|
|
8213
|
+
const body = { reference };
|
|
8214
|
+
if (amount) body.amount = amount;
|
|
8215
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refunds`, {
|
|
8216
|
+
method: "POST",
|
|
8217
|
+
headers: this.buildHeaders(),
|
|
8218
|
+
body: JSON.stringify(body)
|
|
8219
|
+
});
|
|
8220
|
+
return response.json();
|
|
8221
|
+
}
|
|
8222
|
+
/** Cek saldo merchant di Checkout.com */
|
|
8223
|
+
async checkBalance() {
|
|
8224
|
+
const response = await fetch(`${this.getBaseUrl()}/balances`, {
|
|
8225
|
+
method: "GET",
|
|
8226
|
+
headers: this.buildHeaders()
|
|
8227
|
+
});
|
|
8228
|
+
return response.json();
|
|
8229
|
+
}
|
|
8230
|
+
/** Ambil daftar payment links */
|
|
8231
|
+
async listPaymentLinks() {
|
|
8232
|
+
const response = await fetch(`${this.getBaseUrl()}/payment-links`, {
|
|
8233
|
+
method: "GET",
|
|
8234
|
+
headers: this.buildHeaders()
|
|
8235
|
+
});
|
|
8236
|
+
return response.json();
|
|
8237
|
+
}
|
|
8238
|
+
};
|
|
8239
|
+
|
|
8240
|
+
// src/clients/razorpay.ts
|
|
8241
|
+
var RazorpayClient = class {
|
|
8242
|
+
config;
|
|
8243
|
+
constructor(config) {
|
|
8244
|
+
this.config = config;
|
|
8245
|
+
}
|
|
8246
|
+
getBaseUrl() {
|
|
8247
|
+
return "https://api.razorpay.com/v1";
|
|
8248
|
+
}
|
|
8249
|
+
buildHeaders() {
|
|
8250
|
+
const keyId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
|
|
8251
|
+
const keySecret = this.config.apiKey || this.config.secretKey || "";
|
|
8252
|
+
return {
|
|
8253
|
+
"Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
|
|
8254
|
+
"Content-Type": "application/json"
|
|
8255
|
+
};
|
|
8256
|
+
}
|
|
8257
|
+
/** Ambil detail payment */
|
|
8258
|
+
async fetchPayment(paymentId) {
|
|
8259
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
|
|
8260
|
+
method: "GET",
|
|
8261
|
+
headers: this.buildHeaders()
|
|
8262
|
+
});
|
|
8263
|
+
return response.json();
|
|
8264
|
+
}
|
|
8265
|
+
/** Capture authorized payment */
|
|
8266
|
+
async capturePayment(paymentId, amount, currency) {
|
|
8267
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/capture`, {
|
|
8268
|
+
method: "POST",
|
|
8269
|
+
headers: this.buildHeaders(),
|
|
8270
|
+
body: JSON.stringify({ amount, currency: currency || "INR" })
|
|
8271
|
+
});
|
|
8272
|
+
return response.json();
|
|
5373
8273
|
}
|
|
5374
|
-
/**
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
const
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
bill_no: billNo,
|
|
5383
|
-
signature
|
|
8274
|
+
/** Buat refund untuk payment */
|
|
8275
|
+
async createRefund(paymentId, amount, notes) {
|
|
8276
|
+
const body = { notes };
|
|
8277
|
+
if (amount) body.amount = amount;
|
|
8278
|
+
const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refund`, {
|
|
8279
|
+
method: "POST",
|
|
8280
|
+
headers: this.buildHeaders(),
|
|
8281
|
+
body: JSON.stringify(body)
|
|
5384
8282
|
});
|
|
8283
|
+
return response.json();
|
|
5385
8284
|
}
|
|
5386
|
-
/**
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
return this.request("/cvr/100005/10", {
|
|
5392
|
-
request: "Cancel Transaction",
|
|
5393
|
-
merchant_id: this.merchantId,
|
|
5394
|
-
bill_no: billNo,
|
|
5395
|
-
payment_channel: paymentChannel,
|
|
5396
|
-
signature
|
|
8285
|
+
/** Cek saldo akun Razorpay */
|
|
8286
|
+
async checkBalance() {
|
|
8287
|
+
const response = await fetch(`${this.getBaseUrl()}/balance`, {
|
|
8288
|
+
method: "GET",
|
|
8289
|
+
headers: this.buildHeaders()
|
|
5397
8290
|
});
|
|
8291
|
+
return response.json();
|
|
8292
|
+
}
|
|
8293
|
+
/** Ambil daftar semua payment */
|
|
8294
|
+
async listPayments(from, to, count) {
|
|
8295
|
+
const params = new URLSearchParams();
|
|
8296
|
+
if (from) params.set("from", from.toString());
|
|
8297
|
+
if (to) params.set("to", to.toString());
|
|
8298
|
+
if (count) params.set("count", count.toString());
|
|
8299
|
+
const response = await fetch(`${this.getBaseUrl()}/payments?${params}`, {
|
|
8300
|
+
method: "GET",
|
|
8301
|
+
headers: this.buildHeaders()
|
|
8302
|
+
});
|
|
8303
|
+
return response.json();
|
|
5398
8304
|
}
|
|
5399
8305
|
};
|
|
5400
8306
|
|
|
5401
|
-
// src/clients/
|
|
5402
|
-
var
|
|
5403
|
-
|
|
5404
|
-
merchantKey;
|
|
5405
|
-
sandbox;
|
|
8307
|
+
// src/clients/square.ts
|
|
8308
|
+
var SquareClient = class {
|
|
8309
|
+
config;
|
|
5406
8310
|
constructor(config) {
|
|
5407
|
-
this.
|
|
5408
|
-
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
5409
|
-
this.sandbox = !!config.sandbox;
|
|
8311
|
+
this.config = config;
|
|
5410
8312
|
}
|
|
5411
8313
|
getBaseUrl() {
|
|
5412
|
-
return this.sandbox ? "https://
|
|
8314
|
+
return this.config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
|
|
5413
8315
|
}
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
8316
|
+
buildHeaders() {
|
|
8317
|
+
return {
|
|
8318
|
+
"Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
|
|
8319
|
+
"Content-Type": "application/json",
|
|
8320
|
+
"Square-Version": "2024-01-17"
|
|
8321
|
+
};
|
|
8322
|
+
}
|
|
8323
|
+
/** Ambil detail payment Square */
|
|
8324
|
+
async getPayment(paymentId) {
|
|
8325
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}`, {
|
|
8326
|
+
method: "GET",
|
|
8327
|
+
headers: this.buildHeaders()
|
|
8328
|
+
});
|
|
8329
|
+
return response.json();
|
|
8330
|
+
}
|
|
8331
|
+
/** Batalkan payment Square */
|
|
8332
|
+
async cancelPayment(paymentId) {
|
|
8333
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}/cancel`, {
|
|
5420
8334
|
method: "POST",
|
|
5421
|
-
headers:
|
|
5422
|
-
|
|
5423
|
-
"Accept": "application/json"
|
|
5424
|
-
},
|
|
5425
|
-
body: JSON.stringify(payload)
|
|
8335
|
+
headers: this.buildHeaders(),
|
|
8336
|
+
body: "{}"
|
|
5426
8337
|
});
|
|
5427
|
-
|
|
5428
|
-
let data = null;
|
|
5429
|
-
try {
|
|
5430
|
-
data = JSON.parse(text);
|
|
5431
|
-
} catch (e) {
|
|
5432
|
-
}
|
|
5433
|
-
if (!response.ok) {
|
|
5434
|
-
throw new Error(data?.response_desc || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5435
|
-
}
|
|
5436
|
-
return data;
|
|
8338
|
+
return response.json();
|
|
5437
8339
|
}
|
|
5438
|
-
/**
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
8340
|
+
/** Refund payment Square */
|
|
8341
|
+
async refundPayment(paymentId, amount, currency, idempotencyKey, reason) {
|
|
8342
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/refunds`, {
|
|
8343
|
+
method: "POST",
|
|
8344
|
+
headers: this.buildHeaders(),
|
|
8345
|
+
body: JSON.stringify({
|
|
8346
|
+
idempotency_key: idempotencyKey,
|
|
8347
|
+
payment_id: paymentId,
|
|
8348
|
+
amount_money: { amount, currency },
|
|
8349
|
+
reason
|
|
8350
|
+
})
|
|
5447
8351
|
});
|
|
8352
|
+
return response.json();
|
|
8353
|
+
}
|
|
8354
|
+
/** Ambil saldo location Square */
|
|
8355
|
+
async retrieveBalance(locationId) {
|
|
8356
|
+
const id = locationId || this.config.extra?.locationId || this.config.projectId || "";
|
|
8357
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations/${id}`, {
|
|
8358
|
+
method: "GET",
|
|
8359
|
+
headers: this.buildHeaders()
|
|
8360
|
+
});
|
|
8361
|
+
return response.json();
|
|
8362
|
+
}
|
|
8363
|
+
/** List semua locations merchant */
|
|
8364
|
+
async listLocations() {
|
|
8365
|
+
const response = await fetch(`${this.getBaseUrl()}/v2/locations`, {
|
|
8366
|
+
method: "GET",
|
|
8367
|
+
headers: this.buildHeaders()
|
|
8368
|
+
});
|
|
8369
|
+
return response.json();
|
|
5448
8370
|
}
|
|
5449
8371
|
};
|
|
5450
8372
|
|
|
5451
|
-
// src/clients/
|
|
5452
|
-
var
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
sandbox;
|
|
8373
|
+
// src/clients/payu.ts
|
|
8374
|
+
var PayuClient = class {
|
|
8375
|
+
config;
|
|
8376
|
+
accessToken = null;
|
|
5456
8377
|
constructor(config) {
|
|
5457
|
-
this.
|
|
5458
|
-
this.merchantKey = config.apiKey || config.merchantKey || config.serverKey || config.secretKey || "";
|
|
5459
|
-
this.sandbox = !!config.sandbox;
|
|
8378
|
+
this.config = config;
|
|
5460
8379
|
}
|
|
5461
8380
|
getBaseUrl() {
|
|
5462
|
-
return this.sandbox ? "https://
|
|
8381
|
+
return this.config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
|
|
5463
8382
|
}
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
const
|
|
5469
|
-
const response = await fetch(url, {
|
|
8383
|
+
async getToken() {
|
|
8384
|
+
if (this.accessToken) return this.accessToken;
|
|
8385
|
+
const clientId = this.config.extra?.oauthClientId || this.config.clientKey || "";
|
|
8386
|
+
const clientSecret = this.config.extra?.oauthClientSecret || this.config.apiKey || this.config.secretKey || "";
|
|
8387
|
+
const response = await fetch(`${this.getBaseUrl()}/pl/standard/user/oauth/authorize`, {
|
|
5470
8388
|
method: "POST",
|
|
5471
|
-
headers: {
|
|
5472
|
-
|
|
5473
|
-
"Accept": "application/json"
|
|
5474
|
-
},
|
|
5475
|
-
body: JSON.stringify(payload)
|
|
8389
|
+
headers: { "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`, "Content-Type": "application/x-www-form-urlencoded" },
|
|
8390
|
+
body: "grant_type=client_credentials"
|
|
5476
8391
|
});
|
|
5477
|
-
const
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
}
|
|
5486
|
-
|
|
8392
|
+
const data = await response.json();
|
|
8393
|
+
if (!data?.access_token) throw new Error("Failed to get PayU access token");
|
|
8394
|
+
this.accessToken = data.access_token;
|
|
8395
|
+
return this.accessToken;
|
|
8396
|
+
}
|
|
8397
|
+
/** Ambil detail order PayU */
|
|
8398
|
+
async getOrder(orderId) {
|
|
8399
|
+
const token = await this.getToken();
|
|
8400
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8401
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8402
|
+
});
|
|
8403
|
+
return response.json();
|
|
8404
|
+
}
|
|
8405
|
+
/** Batalkan order PayU */
|
|
8406
|
+
async cancelOrder(orderId) {
|
|
8407
|
+
const token = await this.getToken();
|
|
8408
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
|
|
8409
|
+
method: "DELETE",
|
|
8410
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
|
|
8411
|
+
});
|
|
8412
|
+
return response.json();
|
|
8413
|
+
}
|
|
8414
|
+
/** Refund order PayU */
|
|
8415
|
+
async refundOrder(orderId, amount, description) {
|
|
8416
|
+
const token = await this.getToken();
|
|
8417
|
+
const body = { refund: { description: description || "Refund" } };
|
|
8418
|
+
if (amount) body.refund.amount = amount;
|
|
8419
|
+
const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}/refunds`, {
|
|
8420
|
+
method: "POST",
|
|
8421
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
8422
|
+
body: JSON.stringify(body)
|
|
8423
|
+
});
|
|
8424
|
+
return response.json();
|
|
5487
8425
|
}
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
8426
|
+
};
|
|
8427
|
+
|
|
8428
|
+
// src/clients/braintree.ts
|
|
8429
|
+
var BraintreeClient = class {
|
|
8430
|
+
config;
|
|
8431
|
+
constructor(config) {
|
|
8432
|
+
this.config = config;
|
|
8433
|
+
}
|
|
8434
|
+
getBaseUrl() {
|
|
8435
|
+
const merchantId = this.config.merchantCode || this.config.merchantId || "";
|
|
8436
|
+
const base = this.config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
|
|
8437
|
+
return `${base}/merchants/${merchantId}`;
|
|
8438
|
+
}
|
|
8439
|
+
buildHeaders() {
|
|
8440
|
+
const publicKey = this.config.clientKey || this.config.extra?.publicKey || "";
|
|
8441
|
+
const privateKey = this.config.apiKey || this.config.secretKey || "";
|
|
8442
|
+
return {
|
|
8443
|
+
"Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
|
|
8444
|
+
"Content-Type": "application/json",
|
|
8445
|
+
"Braintree-Version": "2019-01-01"
|
|
8446
|
+
};
|
|
8447
|
+
}
|
|
8448
|
+
/** Generate Client Token untuk frontend Drop-in UI */
|
|
8449
|
+
async getClientToken(customerId) {
|
|
8450
|
+
const body = {};
|
|
8451
|
+
if (customerId) body.client_token = { customer_id: customerId };
|
|
8452
|
+
const response = await fetch(`${this.getBaseUrl()}/client_token`, {
|
|
8453
|
+
method: "POST",
|
|
8454
|
+
headers: this.buildHeaders(),
|
|
8455
|
+
body: JSON.stringify(body)
|
|
5500
8456
|
});
|
|
8457
|
+
const data = await response.json();
|
|
8458
|
+
return data.clientToken || "";
|
|
8459
|
+
}
|
|
8460
|
+
/** Ambil detail transaction */
|
|
8461
|
+
async findTransaction(transactionId) {
|
|
8462
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}`, {
|
|
8463
|
+
method: "GET",
|
|
8464
|
+
headers: this.buildHeaders()
|
|
8465
|
+
});
|
|
8466
|
+
return response.json();
|
|
5501
8467
|
}
|
|
5502
|
-
/**
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
const
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
iMid: this.iMid,
|
|
5511
|
-
tXid,
|
|
5512
|
-
payMethod,
|
|
5513
|
-
cancelType: "1",
|
|
5514
|
-
cancelMsg,
|
|
5515
|
-
merchantToken
|
|
8468
|
+
/** Refund transaction Braintree */
|
|
8469
|
+
async refundTransaction(transactionId, amount) {
|
|
8470
|
+
const body = {};
|
|
8471
|
+
if (amount) body.transaction = { amount: (amount / 100).toFixed(2) };
|
|
8472
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/refund`, {
|
|
8473
|
+
method: "POST",
|
|
8474
|
+
headers: this.buildHeaders(),
|
|
8475
|
+
body: JSON.stringify(body)
|
|
5516
8476
|
});
|
|
8477
|
+
return response.json();
|
|
8478
|
+
}
|
|
8479
|
+
/** Void (batalkan) transaction sebelum settlement */
|
|
8480
|
+
async voidTransaction(transactionId) {
|
|
8481
|
+
const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/void`, {
|
|
8482
|
+
method: "PUT",
|
|
8483
|
+
headers: this.buildHeaders(),
|
|
8484
|
+
body: "{}"
|
|
8485
|
+
});
|
|
8486
|
+
return response.json();
|
|
5517
8487
|
}
|
|
5518
8488
|
};
|
|
5519
8489
|
|
|
5520
|
-
// src/clients/
|
|
5521
|
-
var
|
|
5522
|
-
|
|
5523
|
-
apiKey;
|
|
5524
|
-
sandbox;
|
|
8490
|
+
// src/clients/twocheckout.ts
|
|
8491
|
+
var TwoCheckoutClient = class {
|
|
8492
|
+
config;
|
|
5525
8493
|
constructor(config) {
|
|
5526
|
-
this.
|
|
5527
|
-
this.apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5528
|
-
this.sandbox = !!config.sandbox;
|
|
8494
|
+
this.config = config;
|
|
5529
8495
|
}
|
|
5530
8496
|
getBaseUrl() {
|
|
5531
|
-
return this.sandbox ? "https://api
|
|
8497
|
+
return this.config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
|
|
5532
8498
|
}
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
headers
|
|
8499
|
+
buildHeaders() {
|
|
8500
|
+
const merchantCode = this.config.merchantCode || this.config.merchantId || "";
|
|
8501
|
+
const secretKey = this.config.apiKey || this.config.secretKey || "";
|
|
8502
|
+
const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
|
|
8503
|
+
return {
|
|
8504
|
+
"X-Avangate-Authentication": header,
|
|
8505
|
+
"Content-Type": "application/json",
|
|
8506
|
+
"Accept": "application/json"
|
|
5542
8507
|
};
|
|
5543
|
-
if (method === "POST" && body) {
|
|
5544
|
-
fetchOptions.body = JSON.stringify(body);
|
|
5545
|
-
}
|
|
5546
|
-
const response = await fetch(url, fetchOptions);
|
|
5547
|
-
const text = await response.text();
|
|
5548
|
-
let data = null;
|
|
5549
|
-
try {
|
|
5550
|
-
data = JSON.parse(text);
|
|
5551
|
-
} catch (e) {
|
|
5552
|
-
}
|
|
5553
|
-
if (!response.ok) {
|
|
5554
|
-
throw new Error(data?.status?.message || data?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
5555
|
-
}
|
|
5556
|
-
return data;
|
|
5557
8508
|
}
|
|
5558
|
-
/**
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
8509
|
+
/** Ambil detail order 2Checkout berdasarkan Reference Number */
|
|
8510
|
+
async getOrder(refNo) {
|
|
8511
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}`, {
|
|
8512
|
+
method: "GET",
|
|
8513
|
+
headers: this.buildHeaders()
|
|
8514
|
+
});
|
|
8515
|
+
return response.json();
|
|
5563
8516
|
}
|
|
5564
|
-
/**
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
8517
|
+
/** Refund order 2Checkout */
|
|
8518
|
+
async refundOrder(refNo, amount, comment) {
|
|
8519
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}/refund`, {
|
|
8520
|
+
method: "POST",
|
|
8521
|
+
headers: this.buildHeaders(),
|
|
8522
|
+
body: JSON.stringify({ amount, comment: comment || "Refund", reason: "NOT_SATISFIED" })
|
|
8523
|
+
});
|
|
8524
|
+
return response.json();
|
|
5569
8525
|
}
|
|
5570
|
-
/**
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
8526
|
+
/** Ambil detail subscription */
|
|
8527
|
+
async getSubscription(subscriptionRef) {
|
|
8528
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/subscriptions/${subscriptionRef}`, {
|
|
8529
|
+
method: "GET",
|
|
8530
|
+
headers: this.buildHeaders()
|
|
8531
|
+
});
|
|
8532
|
+
return response.json();
|
|
8533
|
+
}
|
|
8534
|
+
/** List semua orders merchant */
|
|
8535
|
+
async listOrders(page, limit) {
|
|
8536
|
+
const params = new URLSearchParams({
|
|
8537
|
+
Pagination: JSON.stringify({ Page: page || 1, Limit: limit || 10 })
|
|
8538
|
+
});
|
|
8539
|
+
const response = await fetch(`${this.getBaseUrl()}/6.0/orders?${params}`, {
|
|
8540
|
+
method: "GET",
|
|
8541
|
+
headers: this.buildHeaders()
|
|
5580
8542
|
});
|
|
8543
|
+
return response.json();
|
|
5581
8544
|
}
|
|
5582
8545
|
};
|
|
5583
8546
|
|
|
@@ -5595,6 +8558,15 @@ var PaymentManager = class {
|
|
|
5595
8558
|
this.registerProvider(new FinpayProvider());
|
|
5596
8559
|
this.registerProvider(new NicepayProvider());
|
|
5597
8560
|
this.registerProvider(new OyProvider());
|
|
8561
|
+
this.registerProvider(new StripeProvider());
|
|
8562
|
+
this.registerProvider(new PaypalProvider());
|
|
8563
|
+
this.registerProvider(new AdyenProvider());
|
|
8564
|
+
this.registerProvider(new CheckoutComProvider());
|
|
8565
|
+
this.registerProvider(new RazorpayProvider());
|
|
8566
|
+
this.registerProvider(new SquareProvider());
|
|
8567
|
+
this.registerProvider(new PayuProvider());
|
|
8568
|
+
this.registerProvider(new BraintreeProvider());
|
|
8569
|
+
this.registerProvider(new TwoCheckoutProvider());
|
|
5598
8570
|
}
|
|
5599
8571
|
registerProvider(provider) {
|
|
5600
8572
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -5606,6 +8578,7 @@ var PaymentManager = class {
|
|
|
5606
8578
|
}
|
|
5607
8579
|
return provider;
|
|
5608
8580
|
}
|
|
8581
|
+
// ─── Indonesian Provider Getters ──────────────────────────────────────────
|
|
5609
8582
|
getMidtransProvider() {
|
|
5610
8583
|
return this.getProvider("midtrans");
|
|
5611
8584
|
}
|
|
@@ -5666,6 +8639,62 @@ var PaymentManager = class {
|
|
|
5666
8639
|
getOyClient(config) {
|
|
5667
8640
|
return new OyClient(config);
|
|
5668
8641
|
}
|
|
8642
|
+
// ─── International Provider Getters ─────────────────────────────────────
|
|
8643
|
+
getStripeProvider() {
|
|
8644
|
+
return this.getProvider("stripe");
|
|
8645
|
+
}
|
|
8646
|
+
getStripeClient(config) {
|
|
8647
|
+
return new StripeClient(config);
|
|
8648
|
+
}
|
|
8649
|
+
getPaypalProvider() {
|
|
8650
|
+
return this.getProvider("paypal");
|
|
8651
|
+
}
|
|
8652
|
+
getPaypalClient(config) {
|
|
8653
|
+
return new PaypalClient(config);
|
|
8654
|
+
}
|
|
8655
|
+
getAdyenProvider() {
|
|
8656
|
+
return this.getProvider("adyen");
|
|
8657
|
+
}
|
|
8658
|
+
getAdyenClient(config) {
|
|
8659
|
+
return new AdyenClient(config);
|
|
8660
|
+
}
|
|
8661
|
+
getCheckoutComProvider() {
|
|
8662
|
+
return this.getProvider("checkoutcom");
|
|
8663
|
+
}
|
|
8664
|
+
getCheckoutComClient(config) {
|
|
8665
|
+
return new CheckoutComClient(config);
|
|
8666
|
+
}
|
|
8667
|
+
getRazorpayProvider() {
|
|
8668
|
+
return this.getProvider("razorpay");
|
|
8669
|
+
}
|
|
8670
|
+
getRazorpayClient(config) {
|
|
8671
|
+
return new RazorpayClient(config);
|
|
8672
|
+
}
|
|
8673
|
+
getSquareProvider() {
|
|
8674
|
+
return this.getProvider("square");
|
|
8675
|
+
}
|
|
8676
|
+
getSquareClient(config) {
|
|
8677
|
+
return new SquareClient(config);
|
|
8678
|
+
}
|
|
8679
|
+
getPayuProvider() {
|
|
8680
|
+
return this.getProvider("payu");
|
|
8681
|
+
}
|
|
8682
|
+
getPayuClient(config) {
|
|
8683
|
+
return new PayuClient(config);
|
|
8684
|
+
}
|
|
8685
|
+
getBraintreeProvider() {
|
|
8686
|
+
return this.getProvider("braintree");
|
|
8687
|
+
}
|
|
8688
|
+
getBraintreeClient(config) {
|
|
8689
|
+
return new BraintreeClient(config);
|
|
8690
|
+
}
|
|
8691
|
+
getTwoCheckoutProvider() {
|
|
8692
|
+
return this.getProvider("twocheckout");
|
|
8693
|
+
}
|
|
8694
|
+
getTwoCheckoutClient(config) {
|
|
8695
|
+
return new TwoCheckoutClient(config);
|
|
8696
|
+
}
|
|
8697
|
+
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
5669
8698
|
async createInvoice(providerName, params, config) {
|
|
5670
8699
|
const provider = this.getProvider(providerName);
|
|
5671
8700
|
return provider.createInvoice(params, config);
|
|
@@ -5723,6 +8752,24 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5723
8752
|
sandbox = env.NICEPAY_SANDBOX === "true" || env.NICEPAY_SANDBOX === "1";
|
|
5724
8753
|
} else if (env.OY_SANDBOX !== void 0) {
|
|
5725
8754
|
sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
|
|
8755
|
+
} else if (env.STRIPE_SANDBOX !== void 0) {
|
|
8756
|
+
sandbox = env.STRIPE_SANDBOX === "true" || env.STRIPE_SANDBOX === "1";
|
|
8757
|
+
} else if (env.PAYPAL_SANDBOX !== void 0) {
|
|
8758
|
+
sandbox = env.PAYPAL_SANDBOX === "true" || env.PAYPAL_SANDBOX === "1";
|
|
8759
|
+
} else if (env.ADYEN_SANDBOX !== void 0) {
|
|
8760
|
+
sandbox = env.ADYEN_SANDBOX === "true" || env.ADYEN_SANDBOX === "1";
|
|
8761
|
+
} else if (env.CHECKOUTCOM_SANDBOX !== void 0) {
|
|
8762
|
+
sandbox = env.CHECKOUTCOM_SANDBOX === "true" || env.CHECKOUTCOM_SANDBOX === "1";
|
|
8763
|
+
} else if (env.RAZORPAY_SANDBOX !== void 0) {
|
|
8764
|
+
sandbox = env.RAZORPAY_SANDBOX === "true" || env.RAZORPAY_SANDBOX === "1";
|
|
8765
|
+
} else if (env.SQUARE_SANDBOX !== void 0) {
|
|
8766
|
+
sandbox = env.SQUARE_SANDBOX === "true" || env.SQUARE_SANDBOX === "1";
|
|
8767
|
+
} else if (env.PAYU_SANDBOX !== void 0) {
|
|
8768
|
+
sandbox = env.PAYU_SANDBOX === "true" || env.PAYU_SANDBOX === "1";
|
|
8769
|
+
} else if (env.BRAINTREE_SANDBOX !== void 0) {
|
|
8770
|
+
sandbox = env.BRAINTREE_SANDBOX === "true" || env.BRAINTREE_SANDBOX === "1";
|
|
8771
|
+
} else if (env.TWOCHECKOUT_SANDBOX !== void 0) {
|
|
8772
|
+
sandbox = env.TWOCHECKOUT_SANDBOX === "true" || env.TWOCHECKOUT_SANDBOX === "1";
|
|
5726
8773
|
} else {
|
|
5727
8774
|
sandbox = env.NODE_ENV !== "production";
|
|
5728
8775
|
}
|
|
@@ -5748,6 +8795,24 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5748
8795
|
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;
|
|
5749
8796
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5750
8797
|
apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8798
|
+
} else if (provider === "stripe") {
|
|
8799
|
+
apiKey = env.STRIPE_SECRET_KEY || env.STRIPE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8800
|
+
} else if (provider === "paypal") {
|
|
8801
|
+
apiKey = env.PAYPAL_CLIENT_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8802
|
+
} else if (provider === "adyen") {
|
|
8803
|
+
apiKey = env.ADYEN_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8804
|
+
} else if (provider === "checkoutcom") {
|
|
8805
|
+
apiKey = env.CHECKOUTCOM_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8806
|
+
} else if (provider === "razorpay") {
|
|
8807
|
+
apiKey = env.RAZORPAY_KEY_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8808
|
+
} else if (provider === "square") {
|
|
8809
|
+
apiKey = env.SQUARE_ACCESS_TOKEN || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8810
|
+
} else if (provider === "payu") {
|
|
8811
|
+
apiKey = env.PAYU_MD5_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8812
|
+
} else if (provider === "braintree") {
|
|
8813
|
+
apiKey = env.BRAINTREE_PRIVATE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
8814
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
8815
|
+
apiKey = env.TWOCHECKOUT_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
5751
8816
|
} else {
|
|
5752
8817
|
apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
|
|
5753
8818
|
}
|
|
@@ -5782,25 +8847,66 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5782
8847
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5783
8848
|
merchantCode = merchantCode || env.OY_USERNAME || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5784
8849
|
clientKey = clientKey || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
|
|
8850
|
+
} else if (provider === "stripe") {
|
|
8851
|
+
clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
|
|
8852
|
+
merchantCode = merchantCode || clientKey || "stripe";
|
|
8853
|
+
} else if (provider === "paypal") {
|
|
8854
|
+
clientKey = clientKey || env.PAYPAL_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
|
|
8855
|
+
merchantCode = merchantCode || env.PAYPAL_CLIENT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
8856
|
+
} else if (provider === "adyen") {
|
|
8857
|
+
clientKey = clientKey || env.ADYEN_CLIENT_KEY || env.BUAYAR_CLIENT_KEY;
|
|
8858
|
+
merchantCode = merchantCode || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_CODE;
|
|
8859
|
+
merchantId = merchantId || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_ID;
|
|
8860
|
+
} else if (provider === "checkoutcom") {
|
|
8861
|
+
clientKey = clientKey || env.CHECKOUTCOM_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
8862
|
+
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE;
|
|
8863
|
+
} else if (provider === "razorpay") {
|
|
8864
|
+
clientKey = clientKey || env.RAZORPAY_KEY_ID || env.BUAYAR_CLIENT_KEY;
|
|
8865
|
+
merchantCode = merchantCode || env.RAZORPAY_KEY_ID || env.BUAYAR_MERCHANT_CODE;
|
|
8866
|
+
} else if (provider === "square") {
|
|
8867
|
+
clientKey = clientKey || env.SQUARE_APPLICATION_ID || env.BUAYAR_CLIENT_KEY;
|
|
8868
|
+
merchantCode = merchantCode || env.SQUARE_APPLICATION_ID || env.BUAYAR_MERCHANT_CODE;
|
|
8869
|
+
} else if (provider === "payu") {
|
|
8870
|
+
merchantCode = merchantCode || env.PAYU_POS_ID || env.BUAYAR_MERCHANT_CODE;
|
|
8871
|
+
merchantId = merchantId || env.PAYU_POS_ID;
|
|
8872
|
+
} else if (provider === "braintree") {
|
|
8873
|
+
clientKey = clientKey || env.BRAINTREE_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
|
|
8874
|
+
merchantCode = merchantCode || env.BRAINTREE_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE;
|
|
8875
|
+
merchantId = merchantId || env.BRAINTREE_MERCHANT_ID;
|
|
8876
|
+
} else if (provider === "twocheckout" || provider === "2checkout") {
|
|
8877
|
+
merchantCode = merchantCode || env.TWOCHECKOUT_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE;
|
|
8878
|
+
merchantId = merchantId || env.TWOCHECKOUT_MERCHANT_CODE;
|
|
5785
8879
|
} else {
|
|
5786
8880
|
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5787
8881
|
}
|
|
5788
|
-
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID;
|
|
5789
|
-
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY;
|
|
5790
|
-
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY;
|
|
5791
|
-
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;
|
|
8882
|
+
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID || env.SQUARE_LOCATION_ID;
|
|
8883
|
+
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;
|
|
8884
|
+
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY || env.BRAINTREE_PRIVATE_KEY;
|
|
8885
|
+
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;
|
|
5792
8886
|
const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
|
|
5793
8887
|
const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
|
|
5794
8888
|
const extra = {
|
|
5795
8889
|
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
8890
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
5796
8891
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
5797
8892
|
userId: env.FASPAY_USER_ID,
|
|
5798
8893
|
iMid: env.NICEPAY_IMID,
|
|
5799
8894
|
username: env.OY_USERNAME,
|
|
8895
|
+
hmacKey: env.ADYEN_HMAC_KEY,
|
|
8896
|
+
liveUrlPrefix: env.ADYEN_LIVE_URL_PREFIX,
|
|
8897
|
+
webhookId: env.PAYPAL_WEBHOOK_ID,
|
|
8898
|
+
merchantAccount: env.ADYEN_MERCHANT_ACCOUNT,
|
|
8899
|
+
md5Key: env.PAYU_MD5_KEY,
|
|
8900
|
+
oauthClientId: env.PAYU_OAUTH_CLIENT_ID,
|
|
8901
|
+
oauthClientSecret: env.PAYU_OAUTH_CLIENT_SECRET,
|
|
8902
|
+
locationId: env.SQUARE_LOCATION_ID,
|
|
8903
|
+
webhookSignatureKey: env.SQUARE_WEBHOOK_SIGNATURE_KEY,
|
|
8904
|
+
publicKey: env.BRAINTREE_PUBLIC_KEY || env.ADYEN_CLIENT_KEY,
|
|
8905
|
+
secretWord: env.TWOCHECKOUT_SECRET_WORD,
|
|
5800
8906
|
...customConfig?.extra
|
|
5801
8907
|
};
|
|
5802
8908
|
return {
|
|
5803
|
-
provider: provider === "oyindonesia" ? "oy" : provider,
|
|
8909
|
+
provider: provider === "oyindonesia" ? "oy" : provider === "2checkout" ? "twocheckout" : provider,
|
|
5804
8910
|
apiKey: apiKey || "",
|
|
5805
8911
|
serverKey: apiKey || "",
|
|
5806
8912
|
secretKey: secretKey || apiKey || "",
|
|
@@ -5838,7 +8944,7 @@ var Buayar = class {
|
|
|
5838
8944
|
this.config = resolveConfigFromEnv({ ...this.config, ...config });
|
|
5839
8945
|
}
|
|
5840
8946
|
/**
|
|
5841
|
-
* Dapatkan nama provider aktif
|
|
8947
|
+
* Dapatkan nama provider aktif
|
|
5842
8948
|
*/
|
|
5843
8949
|
get provider() {
|
|
5844
8950
|
return this.config.provider || "midtrans";
|
|
@@ -5886,6 +8992,40 @@ var Buayar = class {
|
|
|
5886
8992
|
*/
|
|
5887
8993
|
async verifyWebhook(payload, headers, configOverride) {
|
|
5888
8994
|
const mergedConfig = { ...this.config, ...configOverride };
|
|
8995
|
+
if (headers) {
|
|
8996
|
+
const stripeSig = headers["stripe-signature"] || headers["Stripe-Signature"];
|
|
8997
|
+
if (stripeSig) {
|
|
8998
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
8999
|
+
mergedConfig.extra.signatureHeader = Array.isArray(stripeSig) ? stripeSig[0] : stripeSig;
|
|
9000
|
+
}
|
|
9001
|
+
const ckoSig = headers["cko-signature"] || headers["Cko-Signature"];
|
|
9002
|
+
if (ckoSig) {
|
|
9003
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9004
|
+
mergedConfig.extra.signatureHeader = Array.isArray(ckoSig) ? ckoSig[0] : ckoSig;
|
|
9005
|
+
}
|
|
9006
|
+
const rzpSig = headers["x-razorpay-signature"] || headers["X-Razorpay-Signature"];
|
|
9007
|
+
if (rzpSig) {
|
|
9008
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9009
|
+
mergedConfig.extra.signatureHeader = Array.isArray(rzpSig) ? rzpSig[0] : rzpSig;
|
|
9010
|
+
}
|
|
9011
|
+
const squareSig = headers["x-square-hmacsha256-signature"] || headers["x-square-signature"];
|
|
9012
|
+
if (squareSig) {
|
|
9013
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9014
|
+
mergedConfig.extra.signatureHeader = Array.isArray(squareSig) ? squareSig[0] : squareSig;
|
|
9015
|
+
}
|
|
9016
|
+
const payuSig = headers["openpayu-signature"] || headers["OpenPayU-Signature"];
|
|
9017
|
+
if (payuSig) {
|
|
9018
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9019
|
+
mergedConfig.extra.signatureHeader = Array.isArray(payuSig) ? payuSig[0] : payuSig;
|
|
9020
|
+
}
|
|
9021
|
+
const btSig = headers["bt_signature"];
|
|
9022
|
+
const btPayload = headers["bt_payload"];
|
|
9023
|
+
if (btSig && btPayload) {
|
|
9024
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
9025
|
+
mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
|
|
9026
|
+
mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
5889
9029
|
let providerName = configOverride?.provider || this.provider;
|
|
5890
9030
|
if (payload) {
|
|
5891
9031
|
if (payload.signature_key && payload.transaction_status) {
|
|
@@ -5906,8 +9046,28 @@ var Buayar = class {
|
|
|
5906
9046
|
providerName = "oy";
|
|
5907
9047
|
} else if (payload.merchant_id && payload.order_id && payload.signature) {
|
|
5908
9048
|
providerName = "prismalink";
|
|
9049
|
+
} else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
|
|
9050
|
+
providerName = "stripe";
|
|
9051
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9052
|
+
providerName = "razorpay";
|
|
5909
9053
|
} else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
|
|
5910
9054
|
providerName = "xendit";
|
|
9055
|
+
} else if (payload.event_type && payload.resource && (payload.event_type.startsWith("PAYMENT.") || payload.event_type.startsWith("CHECKOUT.ORDER."))) {
|
|
9056
|
+
providerName = "paypal";
|
|
9057
|
+
} else if (payload.notificationItems || payload.merchantAccountCode && payload.pspReference && payload.eventCode) {
|
|
9058
|
+
providerName = "adyen";
|
|
9059
|
+
} else if (payload.type && payload.data?._links && (payload.type.startsWith("payment_") || payload.type.startsWith("refund_"))) {
|
|
9060
|
+
providerName = "checkoutcom";
|
|
9061
|
+
} else if (payload.event && payload.payload?.payment?.entity) {
|
|
9062
|
+
providerName = "razorpay";
|
|
9063
|
+
} else if (payload.type && payload.data?.object?.status && payload.merchant_id) {
|
|
9064
|
+
providerName = "square";
|
|
9065
|
+
} else if (payload.order && payload.order?.status && payload.order?.extOrderId) {
|
|
9066
|
+
providerName = "payu";
|
|
9067
|
+
} else if (payload.kind && payload.subject?.transaction) {
|
|
9068
|
+
providerName = "braintree";
|
|
9069
|
+
} else if (payload.HASH && payload.REFNOEXT && payload.IPN_PID) {
|
|
9070
|
+
providerName = "twocheckout";
|
|
5911
9071
|
}
|
|
5912
9072
|
}
|
|
5913
9073
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
@@ -5915,70 +9075,73 @@ var Buayar = class {
|
|
|
5915
9075
|
async handleWebhook(payload, headers, configOverride) {
|
|
5916
9076
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
5917
9077
|
}
|
|
9078
|
+
// ─── Indonesian Provider Client Getters ───────────────────────────────────
|
|
5918
9079
|
getMidtransClient(configOverride) {
|
|
5919
|
-
return new MidtransClient({
|
|
5920
|
-
...this.config,
|
|
5921
|
-
...configOverride
|
|
5922
|
-
});
|
|
9080
|
+
return new MidtransClient({ ...this.config, ...configOverride });
|
|
5923
9081
|
}
|
|
5924
9082
|
getDuitkuClient(configOverride) {
|
|
5925
|
-
return new DuitkuClient({
|
|
5926
|
-
...this.config,
|
|
5927
|
-
...configOverride
|
|
5928
|
-
});
|
|
9083
|
+
return new DuitkuClient({ ...this.config, ...configOverride });
|
|
5929
9084
|
}
|
|
5930
9085
|
getIpaymuClient(configOverride) {
|
|
5931
|
-
return new IpaymuClient({
|
|
5932
|
-
...this.config,
|
|
5933
|
-
...configOverride
|
|
5934
|
-
});
|
|
9086
|
+
return new IpaymuClient({ ...this.config, ...configOverride });
|
|
5935
9087
|
}
|
|
5936
9088
|
getXenditClient(configOverride) {
|
|
5937
|
-
return new XenditClient({
|
|
5938
|
-
...this.config,
|
|
5939
|
-
...configOverride
|
|
5940
|
-
});
|
|
9089
|
+
return new XenditClient({ ...this.config, ...configOverride });
|
|
5941
9090
|
}
|
|
5942
9091
|
getDokuClient(configOverride) {
|
|
5943
|
-
return new DokuClient({
|
|
5944
|
-
...this.config,
|
|
5945
|
-
...configOverride
|
|
5946
|
-
});
|
|
9092
|
+
return new DokuClient({ ...this.config, ...configOverride });
|
|
5947
9093
|
}
|
|
5948
9094
|
getPrismalinkClient(configOverride) {
|
|
5949
|
-
return new PrismalinkClient({
|
|
5950
|
-
...this.config,
|
|
5951
|
-
...configOverride
|
|
5952
|
-
});
|
|
9095
|
+
return new PrismalinkClient({ ...this.config, ...configOverride });
|
|
5953
9096
|
}
|
|
5954
9097
|
getFaspayClient(configOverride) {
|
|
5955
|
-
return new FaspayClient({
|
|
5956
|
-
...this.config,
|
|
5957
|
-
...configOverride
|
|
5958
|
-
});
|
|
9098
|
+
return new FaspayClient({ ...this.config, ...configOverride });
|
|
5959
9099
|
}
|
|
5960
9100
|
getFinpayClient(configOverride) {
|
|
5961
|
-
return new FinpayClient({
|
|
5962
|
-
...this.config,
|
|
5963
|
-
...configOverride
|
|
5964
|
-
});
|
|
9101
|
+
return new FinpayClient({ ...this.config, ...configOverride });
|
|
5965
9102
|
}
|
|
5966
9103
|
getNicepayClient(configOverride) {
|
|
5967
|
-
return new NicepayClient({
|
|
5968
|
-
...this.config,
|
|
5969
|
-
...configOverride
|
|
5970
|
-
});
|
|
9104
|
+
return new NicepayClient({ ...this.config, ...configOverride });
|
|
5971
9105
|
}
|
|
5972
9106
|
getOyClient(configOverride) {
|
|
5973
|
-
return new OyClient({
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
9107
|
+
return new OyClient({ ...this.config, ...configOverride });
|
|
9108
|
+
}
|
|
9109
|
+
// ─── International Provider Client Getters ────────────────────────────────
|
|
9110
|
+
getStripeClient(configOverride) {
|
|
9111
|
+
return new StripeClient({ ...this.config, ...configOverride });
|
|
9112
|
+
}
|
|
9113
|
+
getPaypalClient(configOverride) {
|
|
9114
|
+
return new PaypalClient({ ...this.config, ...configOverride });
|
|
9115
|
+
}
|
|
9116
|
+
getAdyenClient(configOverride) {
|
|
9117
|
+
return new AdyenClient({ ...this.config, ...configOverride });
|
|
9118
|
+
}
|
|
9119
|
+
getCheckoutComClient(configOverride) {
|
|
9120
|
+
return new CheckoutComClient({ ...this.config, ...configOverride });
|
|
9121
|
+
}
|
|
9122
|
+
getRazorpayClient(configOverride) {
|
|
9123
|
+
return new RazorpayClient({ ...this.config, ...configOverride });
|
|
9124
|
+
}
|
|
9125
|
+
getSquareClient(configOverride) {
|
|
9126
|
+
return new SquareClient({ ...this.config, ...configOverride });
|
|
9127
|
+
}
|
|
9128
|
+
getPayuClient(configOverride) {
|
|
9129
|
+
return new PayuClient({ ...this.config, ...configOverride });
|
|
9130
|
+
}
|
|
9131
|
+
getBraintreeClient(configOverride) {
|
|
9132
|
+
return new BraintreeClient({ ...this.config, ...configOverride });
|
|
9133
|
+
}
|
|
9134
|
+
getTwoCheckoutClient(configOverride) {
|
|
9135
|
+
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
5977
9136
|
}
|
|
5978
9137
|
};
|
|
5979
9138
|
var buayar = new Buayar();
|
|
5980
9139
|
export {
|
|
9140
|
+
AdyenClient,
|
|
9141
|
+
AdyenProvider,
|
|
5981
9142
|
BasePaymentProvider,
|
|
9143
|
+
BraintreeClient,
|
|
9144
|
+
BraintreeProvider,
|
|
5982
9145
|
Buayar,
|
|
5983
9146
|
CANONICAL_TO_DOKU,
|
|
5984
9147
|
CANONICAL_TO_DUITKU,
|
|
@@ -5989,8 +9152,11 @@ export {
|
|
|
5989
9152
|
CANONICAL_TO_NICEPAY,
|
|
5990
9153
|
CANONICAL_TO_OY,
|
|
5991
9154
|
CANONICAL_TO_PRISMALINK,
|
|
9155
|
+
CANONICAL_TO_STRIPE,
|
|
5992
9156
|
CANONICAL_TO_XENDIT,
|
|
5993
9157
|
CORE_API_METHODS,
|
|
9158
|
+
CheckoutComClient,
|
|
9159
|
+
CheckoutComProvider,
|
|
5994
9160
|
DUITKU_TO_CANONICAL,
|
|
5995
9161
|
DokuClient,
|
|
5996
9162
|
DokuProvider,
|
|
@@ -6011,12 +9177,29 @@ export {
|
|
|
6011
9177
|
OyClient,
|
|
6012
9178
|
OyProvider,
|
|
6013
9179
|
PaymentManager,
|
|
9180
|
+
PaypalClient,
|
|
9181
|
+
PaypalProvider,
|
|
9182
|
+
PayuClient,
|
|
9183
|
+
PayuProvider,
|
|
6014
9184
|
PrismalinkClient,
|
|
6015
9185
|
PrismalinkProvider,
|
|
9186
|
+
RazorpayClient,
|
|
9187
|
+
RazorpayProvider,
|
|
9188
|
+
SquareClient,
|
|
9189
|
+
SquareProvider,
|
|
9190
|
+
StripeClient,
|
|
9191
|
+
StripeProvider,
|
|
9192
|
+
TwoCheckoutClient,
|
|
9193
|
+
TwoCheckoutProvider,
|
|
6016
9194
|
XenditClient,
|
|
6017
9195
|
XenditProvider,
|
|
6018
9196
|
buayar,
|
|
9197
|
+
buildBraintreeBasicAuth,
|
|
6019
9198
|
buildCoreChargePayload,
|
|
9199
|
+
buildPaypalBasicAuth,
|
|
9200
|
+
buildPayuBasicAuth,
|
|
9201
|
+
buildRazorpayBasicAuth,
|
|
9202
|
+
buildTwoCheckoutAuth,
|
|
6020
9203
|
formatNicepayTimestamp,
|
|
6021
9204
|
generateDokuHeaders,
|
|
6022
9205
|
generateFaspaySignature,
|
|
@@ -6036,6 +9219,8 @@ export {
|
|
|
6036
9219
|
paymentManager,
|
|
6037
9220
|
resolveConfigFromEnv,
|
|
6038
9221
|
safeCompare,
|
|
9222
|
+
serializePaypalParams,
|
|
9223
|
+
serializeStripeParams,
|
|
6039
9224
|
sha256,
|
|
6040
9225
|
sha512,
|
|
6041
9226
|
toCanonicalPaymentMethod,
|
|
@@ -6047,7 +9232,11 @@ export {
|
|
|
6047
9232
|
toNicepayPaymentMethod,
|
|
6048
9233
|
toOyPaymentMethod,
|
|
6049
9234
|
toPrismalinkPaymentMethod,
|
|
9235
|
+
toStripePaymentMethod,
|
|
6050
9236
|
toXenditPaymentMethod,
|
|
9237
|
+
verifyAdyenWebhook,
|
|
9238
|
+
verifyBraintreeWebhook,
|
|
9239
|
+
verifyCheckoutComWebhook,
|
|
6051
9240
|
verifyDokuWebhookSignature,
|
|
6052
9241
|
verifyDuitkuCallbackSignature,
|
|
6053
9242
|
verifyFaspaySignature,
|
|
@@ -6055,6 +9244,12 @@ export {
|
|
|
6055
9244
|
verifyIpaymuCallback,
|
|
6056
9245
|
verifyNicepayWebhook,
|
|
6057
9246
|
verifyOyWebhook,
|
|
9247
|
+
verifyPaypalWebhookSimple,
|
|
9248
|
+
verifyPayuWebhook,
|
|
6058
9249
|
verifyPrismalinkSignature,
|
|
9250
|
+
verifyRazorpayWebhook,
|
|
9251
|
+
verifySquareWebhook,
|
|
9252
|
+
verifyStripeWebhook,
|
|
9253
|
+
verifyTwoCheckoutWebhook,
|
|
6059
9254
|
verifyXenditWebhookToken
|
|
6060
9255
|
};
|