504 lines
15 KiB
TypeScript
504 lines
15 KiB
TypeScript
import { Request, Response } from "express";
|
|
import getTokenAuth from "../lib/getTokenAuth";
|
|
import { getUserFromToken } from "../middleware/auth";
|
|
import { get, isEmpty } from "lodash";
|
|
import db from "../db";
|
|
import { v7 } from "uuid";
|
|
import { formatTimestamp } from "../lib/formatTimestamp";
|
|
import { formatMoney } from "../lib/bank/mandiri/getInvoiceVirtualAccount";
|
|
import callGate from "../lib/gate";
|
|
import { getParameter } from "../lib/getParameter";
|
|
import { dbQueryClient } from "../lib/dbQueryClient";
|
|
import sequence from "../lib/sequence";
|
|
|
|
export async function inquiry(req: Request, res: Response) {
|
|
try {
|
|
const { version } = req.params;
|
|
if (version === "v1.0") {
|
|
const body = req.body || {};
|
|
const requiredBody = [
|
|
"partnerServiceId",
|
|
"customerNo",
|
|
"virtualAccountNo",
|
|
"trxDateInit",
|
|
"inquiryRequestId",
|
|
];
|
|
for (const f of requiredBody) {
|
|
if (body[f] === undefined || body[f] === null) {
|
|
return res.status(400).json({ error: `missing body field ${f}` });
|
|
}
|
|
}
|
|
await db.activity_logs.create({
|
|
data: {
|
|
action: "GET",
|
|
status: "SUCCESS",
|
|
message: "Get Parameter User PartnerServiceId",
|
|
},
|
|
});
|
|
const parameters = await db.parameters.findFirst({
|
|
where: {
|
|
param_key: "partnerServiceId",
|
|
param_value: get(body, "partnerServiceId"),
|
|
},
|
|
});
|
|
const user = await db.users.findFirst({
|
|
where: { user_id: parameters?.user_id },
|
|
include: {
|
|
database: true,
|
|
banks: true,
|
|
parameters: true,
|
|
tenants: true,
|
|
},
|
|
});
|
|
await db.activity_logs.create({
|
|
data: {
|
|
action: "GET",
|
|
status: "SUCCESS",
|
|
message: "Get User",
|
|
},
|
|
});
|
|
const result = await callGate({
|
|
client: "mandiri",
|
|
action: "getInvoiceVirtualAccount",
|
|
data: { ...body },
|
|
user: user,
|
|
});
|
|
return res.status(200).json({
|
|
responseCode: "2002400",
|
|
responseMessage: "Successful",
|
|
virtualAccountData: result,
|
|
});
|
|
} else {
|
|
return res.status(400).json({ error: "unsupported version" });
|
|
}
|
|
} catch (err) {
|
|
const message: any = get(err, "message", "internal_error");
|
|
if (
|
|
message === "No outstanding amount found for the given Virtual Account No"
|
|
) {
|
|
return res.status(404).json({
|
|
responseCode: "4042412",
|
|
responseMessage: "Invalid Bill not found",
|
|
});
|
|
} else if (
|
|
message === "C_BPartner_ID not found for the given Virtual Account No"
|
|
) {
|
|
return res.status(404).json({
|
|
responseCode: "4042401",
|
|
responseMessage: "Virtual Account not found",
|
|
});
|
|
} else if (message === "User database information is missing") {
|
|
return res.status(500).json({
|
|
responseCode: "5002401",
|
|
responseMessage: "Internal Server Error",
|
|
});
|
|
}
|
|
console.error("transfer inquiry error:", err);
|
|
return res.status(500).json({
|
|
responseCode: "5002401",
|
|
responseMessage: "Internal Server Error",
|
|
});
|
|
}
|
|
}
|
|
|
|
export async function MidsuitPayment(req: Request, res: Response) {
|
|
const data = req.body || {};
|
|
const timestamp = formatTimestamp();
|
|
let token = await getTokenAuth(req);
|
|
let user = null as any;
|
|
if (!token) {
|
|
const authClient = req.header("Authorization-Client") || "";
|
|
user = await db.users.findFirst({
|
|
where: {
|
|
token_access: authClient,
|
|
},
|
|
include: {
|
|
tenants: true,
|
|
database: true,
|
|
banks: true,
|
|
parameters: true,
|
|
},
|
|
});
|
|
} else {
|
|
const userToken = await getUserFromToken(token);
|
|
user = get(userToken, "user");
|
|
}
|
|
if (!user) {
|
|
return res.status(401).json({ error: "invalid token" });
|
|
}
|
|
if (!get(user, "database")) {
|
|
return res.status(400).json({ error: "user has no database assigned" });
|
|
}
|
|
if (get(data, "amount") <= 0) {
|
|
return res.status(400).json({ error: "invalid amount" });
|
|
}
|
|
if (
|
|
isEmpty(get(data, "originatorBankCode")) ||
|
|
isEmpty(get(data, "beneficiaryBankCode"))
|
|
) {
|
|
return res.status(400).json({ error: "invalid bank code" });
|
|
}
|
|
const bankFrom = await db.banks.findFirst({
|
|
where: { code: String(get(data, "originatorBankCode")) },
|
|
});
|
|
if (!bankFrom) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "unsupported originator bank code midsuit" });
|
|
}
|
|
const bankTo = await db.banks.findFirst({
|
|
where: { code: String(get(data, "beneficiaryBankCode")) },
|
|
});
|
|
if (!bankTo) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "unsupported beneficiary bank code midsuit" });
|
|
}
|
|
const bankCodeUser = String(get(data, "originatorBankCode"));
|
|
if (isEmpty(bankCodeUser)) {
|
|
return res.status(400).json({ error: "user has no bank assigned" });
|
|
}
|
|
const partnerReferenceNo = v7();
|
|
const external_id = await sequence("midsuit_payment_external_id");
|
|
let requestBody: any = {
|
|
partnerReferenceNo: partnerReferenceNo,
|
|
amount: {
|
|
value: formatMoney(get(data, "amount")),
|
|
currency: "IDR",
|
|
},
|
|
beneficiaryAccountNo: get(data, "beneficiaryAccountNo"),
|
|
beneficiaryEmail: get(data, "beneficiaryEmail"),
|
|
currency: "IDR",
|
|
customerReference: get(data, "documentno"),
|
|
// feeType: "BEN", BIAYA ADMIN
|
|
remark: get(data, "documentno"),
|
|
sourceAccountNo: get(data, "sourceAccountNo"),
|
|
transactionDate: timestamp,
|
|
originatorInfos: [
|
|
{
|
|
originatorCustomerNo: get(data, "originatorCustomerNo"),
|
|
originatorCustomerName: get(data, "originatorCustomerName"),
|
|
originatorBankCode: bankCodeUser,
|
|
},
|
|
],
|
|
};
|
|
let isRTKGS = get(data, "amount") >= 100000000;
|
|
if (isRTKGS || get(data, "beneficiaryBankCode") !== bankCodeUser) {
|
|
requestBody = {
|
|
...requestBody,
|
|
beneficiaryAccountName: get(data, "beneficiaryAccountName"),
|
|
beneficiaryBankCode: get(data, "beneficiaryBankCode"),
|
|
beneficiaryCustomerResidence: "1",
|
|
beneficiaryCustomerType: get(data, "beneficiaryCustomerType", "1"),
|
|
senderCustomerResidence: "1",
|
|
senderCustomerType: get(data, "beneficiaryCustomerType", "2"),
|
|
};
|
|
}
|
|
const transaction = await db.transactions.create({
|
|
data: {
|
|
db_id: user.db_id,
|
|
user_id: user.user_id,
|
|
documentno: get(data, "documentno"),
|
|
tenant_id: user.tenant_id,
|
|
bank_id: get(bankTo, "bank_id") as any,
|
|
bankto_id: get(bankFrom, "bank_id") as any,
|
|
external_id: external_id,
|
|
partnerReferenceNo: partnerReferenceNo,
|
|
amount: get(data, "amount"),
|
|
description: `Payment for ${get(data, "documentno")}`,
|
|
status: "DRAFT",
|
|
beneficiaryAccountName: get(data, "beneficiaryAccountName"),
|
|
beneficiaryAccountNo: get(data, "beneficiaryAccountNo"),
|
|
sourceAccountNo: get(data, "sourceAccountNo"),
|
|
originatorCustomerName: get(data, "originatorCustomerName"),
|
|
originatorCustomerNo: get(data, "originatorCustomerNo"),
|
|
method: isRTKGS
|
|
? "RTGS"
|
|
: get(data, "beneficiaryBankCode") !== bankCodeUser
|
|
? "SKN"
|
|
: "Inhouse",
|
|
},
|
|
});
|
|
await db.transactions_lines.create({
|
|
data: {
|
|
transaction_id: transaction.id,
|
|
documentno: get(data, "documentno"),
|
|
amount: get(data, "amount"),
|
|
description: `Payment for ${get(data, "documentno")}`,
|
|
tenant_id: user.tenant_id,
|
|
line_no: 1,
|
|
},
|
|
});
|
|
if (isRTKGS) {
|
|
// method RTGS
|
|
const result = await callGate({
|
|
action: "TransferRTGS",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: getParameter(user, "external_id"),
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
await db.transactions.update({
|
|
where: { id: transaction.id },
|
|
data: {
|
|
status: "COMPLETED",
|
|
referenceNo: get(result, "referenceNo"),
|
|
trxDateTime: get(result, "timestamp")
|
|
? new Date(get(result, "timestamp"))
|
|
: null,
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
} else if (get(data, "beneficiaryBankCode") !== bankCodeUser) {
|
|
// method SKN
|
|
const result = await callGate({
|
|
action: "TransferSKN",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: external_id,
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
await db.transactions.update({
|
|
where: { id: transaction.id },
|
|
data: {
|
|
status: "COMPLETED",
|
|
referenceNo: get(result, "referenceNo"),
|
|
trxDateTime: get(result, "timestamp")
|
|
? new Date(get(result, "timestamp"))
|
|
: null,
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
} else if (get(data, "beneficiaryBankCode") === bankCodeUser) {
|
|
// method Inhouse
|
|
const result = await callGate({
|
|
action: "TransferInhouse",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: external_id,
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
await db.transactions.update({
|
|
where: { id: transaction.id },
|
|
data: {
|
|
status: "COMPLETED",
|
|
referenceNo: get(result, "referenceNo"),
|
|
trxDateTime: get(result, "timestamp")
|
|
? new Date(get(result, "timestamp"))
|
|
: null,
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
}
|
|
}
|
|
export async function MidsuitPaymentV2(req: Request, res: Response) {
|
|
const data = req.body || {};
|
|
const timestamp = formatTimestamp();
|
|
let token = await getTokenAuth(req);
|
|
let user = null as any;
|
|
if (!token) {
|
|
const authClient = req.header("Authorization-Client") || "";
|
|
user = await db.users.findFirst({
|
|
where: {
|
|
token_access: authClient,
|
|
},
|
|
include: {
|
|
tenants: true,
|
|
database: true,
|
|
banks: true,
|
|
parameters: true,
|
|
},
|
|
});
|
|
} else {
|
|
const userToken = await getUserFromToken(token);
|
|
user = get(userToken, "user");
|
|
}
|
|
if (!user) {
|
|
return res.status(401).json({ error: "invalid token" });
|
|
}
|
|
if (!get(user, "database")) {
|
|
return res.status(400).json({ error: "user has no database assigned" });
|
|
}
|
|
const result = await dbQueryClient({
|
|
name: get(user, "database.name") || "",
|
|
action: "first",
|
|
query: `
|
|
select * from c_payment where c_payment_id = ${get(
|
|
data,
|
|
"c_payment_id",
|
|
0
|
|
)}`,
|
|
});
|
|
if (!result) {
|
|
return res.status(404).json({ error: "payment not found" });
|
|
}
|
|
if (get(data, "amount") != get(result, "payamt")) {
|
|
return res.status(400).json({ error: "amount mismatch" });
|
|
}
|
|
if (get(data, "amount") <= 0) {
|
|
return res.status(400).json({ error: "invalid amount" });
|
|
}
|
|
if (isEmpty(get(data, "bank_code"))) {
|
|
return res.status(400).json({ error: "invalid bank code" });
|
|
}
|
|
const bankCode = await db.bank_code.findFirst({
|
|
where: { code: String(get(data, "bank_code")) },
|
|
});
|
|
if (!bankCode) {
|
|
return res.status(400).json({ error: "unsupported bank code midsuit" });
|
|
}
|
|
const bankCodeUser = String(get(user, "banks.code"));
|
|
if (isEmpty(bankCodeUser)) {
|
|
return res.status(400).json({ error: "user has no bank assigned" });
|
|
}
|
|
const partnerReferenceNo = v7();
|
|
let requestBody: any = {
|
|
partnerReferenceNo: partnerReferenceNo,
|
|
amount: {
|
|
value: formatMoney(get(data, "amount")),
|
|
currency: "IDR",
|
|
},
|
|
beneficiaryAccountNo: get(data, "accountno"),
|
|
beneficiaryEmail: get(data, "email"),
|
|
currency: "IDR",
|
|
customerReference:
|
|
get(data, "customerReference") || get(result, "documentno"),
|
|
// feeType: "BEN", BIAYA ADMIN
|
|
remark: get(result, "documentno"),
|
|
sourceAccountNo: getParameter(user, "sourceaccountno"),
|
|
transactionDate: timestamp,
|
|
originatorInfos: [
|
|
{
|
|
originatorCustomerNo: getParameter(user, "originatorCustomerNo"),
|
|
originatorCustomerName: getParameter(user, "originatorCustomerName"),
|
|
originatorBankCode: bankCodeUser,
|
|
},
|
|
],
|
|
};
|
|
let isRTKGS = get(data, "amount") >= 100000000;
|
|
if (isRTKGS || bankCode.code !== bankCodeUser) {
|
|
requestBody = {
|
|
...requestBody,
|
|
beneficiaryAccountName: get(data, "accountname"),
|
|
beneficiaryBankCode: get(bankCode, "code"),
|
|
beneficiaryCustomerResidence: "1",
|
|
beneficiaryCustomerType: "1",
|
|
senderCustomerResidence: "1",
|
|
senderCustomerType: "2",
|
|
};
|
|
}
|
|
|
|
if (isRTKGS) {
|
|
// method RTGS
|
|
const result = await callGate({
|
|
action: "TransferRTGS",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: getParameter(user, "external_id"),
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
} else if (bankCode.code !== bankCodeUser) {
|
|
// method SKN
|
|
const result = await callGate({
|
|
action: "TransferSKN",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: getParameter(user, "external_id"),
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
} else if (bankCode.code === bankCodeUser) {
|
|
// method Inhouse
|
|
const result = await callGate({
|
|
action: "TransferInhouse",
|
|
client: "mandiri",
|
|
data: {
|
|
clientbank_id: get(user, "clientbank_id"),
|
|
requestBody,
|
|
external_id: getParameter(user, "external_id"),
|
|
channel_id: getParameter(user, "channel_id"),
|
|
},
|
|
});
|
|
return res.status(200).json(result);
|
|
}
|
|
}
|
|
|
|
export async function paymentStatus(req: Request, res: Response) {
|
|
try {
|
|
const { c_invoice_id, startdate, enddate } = req.body as any;
|
|
|
|
const where: any = {};
|
|
if (startdate || enddate) {
|
|
if (!startdate || !enddate) {
|
|
return res.status(400).json({
|
|
error: "startdate and enddate are required when filtering by date",
|
|
});
|
|
}
|
|
where.created_at = {} as any;
|
|
if (startdate) {
|
|
const s = new Date(String(startdate));
|
|
where.created_at.gte = s;
|
|
}
|
|
if (enddate) {
|
|
const e = new Date(String(enddate));
|
|
// include the whole end day by setting to end of day if time not provided
|
|
if (!String(enddate).includes("T")) {
|
|
e.setHours(23, 59, 59, 999);
|
|
}
|
|
where.created_at.lte = e;
|
|
}
|
|
}
|
|
if (c_invoice_id) {
|
|
where.c_invoice_id = Number(c_invoice_id);
|
|
}
|
|
|
|
const rows = await db.transactions_lines.findMany({
|
|
where: {
|
|
...where,
|
|
AND: [
|
|
{
|
|
NOT: {
|
|
c_invoice_id: null,
|
|
},
|
|
},
|
|
{
|
|
transactions: {
|
|
status: "COMPLETED",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
include: { transactions: true },
|
|
orderBy: { created_at: "desc" },
|
|
});
|
|
if (rows.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ responseCode: "404", responseMessage: "no payment found" });
|
|
}
|
|
return res.json({ count: rows.length, data: rows });
|
|
} catch (err) {
|
|
console.error("paymentStatus error", err);
|
|
return res.status(500).json({
|
|
error: "internal_error",
|
|
detail: err instanceof Error ? err.message : String(err),
|
|
});
|
|
}
|
|
}
|