feat: Add payment status endpoint with date filtering
Deploy Application / deploy (push) Successful in 31s
Details
Deploy Application / deploy (push) Successful in 31s
Details
This commit is contained in:
parent
2ad6c2759f
commit
766404ed8f
|
|
@ -438,3 +438,60 @@ export async function MidsuitPaymentV2(req: Request, res: Response) {
|
||||||
return res.status(200).json(result);
|
return res.status(200).json(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function paymentStatus(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { c_invoice_id, startdate, enddate } = req.query as any;
|
||||||
|
if (!c_invoice_id) {
|
||||||
|
return res.status(400).json({ error: "c_invoice_id is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const where: any = { c_invoice_id: Number(c_invoice_id) };
|
||||||
|
if (startdate || enddate) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await db.transactions_lines.findMany({
|
||||||
|
where: {
|
||||||
|
...where,
|
||||||
|
not: {
|
||||||
|
c_invoice_id: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: { transactions: true },
|
||||||
|
orderBy: { created_at: "desc" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = rows.map((r: any) => ({
|
||||||
|
id: r.id,
|
||||||
|
transaction_id: r.transaction_id,
|
||||||
|
amount: r.amount,
|
||||||
|
documentno: r.documentno,
|
||||||
|
c_invoice_id: r.c_invoice_id,
|
||||||
|
created_at: r.created_at,
|
||||||
|
tenant_id: r.tenant_id,
|
||||||
|
transaction_status: r.transactions ? r.transactions.status : null,
|
||||||
|
transaction_reference: r.transactions ? r.transactions.referenceNo : null,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res.json({ count: result.length, data: result });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("paymentStatus error", err);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: "internal_error",
|
||||||
|
detail: err instanceof Error ? err.message : String(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,6 @@ export async function getPoolForDbId(db_id: string) {
|
||||||
max: 10,
|
max: 10,
|
||||||
idleTimeoutMillis: 30000,
|
idleTimeoutMillis: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// poolCache.set(db_id, { pool, lastUsed: Date.now() });
|
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { pathToFileURL } from "url";
|
import { pathToFileURL } from "url";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
export async function callGate(opts: {
|
export async function callGate(opts: {
|
||||||
client: string;
|
client: string;
|
||||||
|
|
@ -12,49 +13,42 @@ export async function callGate(opts: {
|
||||||
|
|
||||||
// candidate paths to try (dev and prod)
|
// candidate paths to try (dev and prod)
|
||||||
const candidates = [
|
const candidates = [
|
||||||
// development / ts-node: src .ts
|
path.join(__dirname, "bank", client, `${action}.ts`),
|
||||||
// path.join(process.cwd(), "src", "lib", "bank", client, `${action}.ts`),
|
|
||||||
// // compiled production: dist .js
|
|
||||||
// path.join(process.cwd(), "dist", "lib", "bank", client, `${action}.js`),
|
|
||||||
// // relative to this file (useful when running from dist/lib)
|
|
||||||
// path.join(__dirname, "bank", client, `${action}.ts`),
|
|
||||||
path.join(__dirname, "bank", client, `${action}.js`),
|
path.join(__dirname, "bank", client, `${action}.js`),
|
||||||
// path.join(__dirname, "..", "lib", "bank", client, `${action}.js`),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let lastErr: any = null;
|
let lastErr: any = null;
|
||||||
|
let existsFile = null as any;
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
try {
|
try {
|
||||||
// prefer require when available (CommonJS build)
|
if (fs.existsSync(candidate)) {
|
||||||
// require expects a path without file://
|
existsFile = candidate;
|
||||||
// but dynamic import needs a file:// URL for absolute paths
|
break;
|
||||||
let mod: any;
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
mod = require(candidate);
|
|
||||||
} catch (reqErr) {
|
|
||||||
// try dynamic import with file:// URL
|
|
||||||
const url = pathToFileURL(candidate).href;
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
mod = await import(url);
|
|
||||||
}
|
}
|
||||||
|
} catch (ex) {}
|
||||||
if (!mod || typeof mod.default !== "function") {
|
}
|
||||||
throw new Error(
|
if (!existsFile) {
|
||||||
`handler at ${candidate} not found or default export not a function`
|
throw new Error(`handler not found for gate: ${client}/${action}`);
|
||||||
);
|
}
|
||||||
}
|
let mod: any;
|
||||||
|
try {
|
||||||
// call the handler with (user, session, data)
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
return await mod.default({ user, session, data });
|
mod = require(existsFile);
|
||||||
} catch (err) {
|
} catch (reqErr) {
|
||||||
lastErr = err;
|
// try dynamic import with file:// URL
|
||||||
// try next candidate
|
const url = pathToFileURL(existsFile).href;
|
||||||
continue;
|
// eslint-disable-next-line no-await-in-loop
|
||||||
}
|
mod = await import(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw lastErr || new Error("handler not found for gate");
|
if (!mod || typeof mod.default !== "function") {
|
||||||
|
throw new Error(
|
||||||
|
`handler at ${existsFile} not found or default export not a function`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the handler with (user, session, data)
|
||||||
|
return await mod.default({ user, session, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default callGate;
|
export default callGate;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ export const setRoutes = () => {
|
||||||
router.post("/api/transfer", authMiddleware, async (req, res) =>
|
router.post("/api/transfer", authMiddleware, async (req, res) =>
|
||||||
transferController.MidsuitPayment(req, res)
|
transferController.MidsuitPayment(req, res)
|
||||||
);
|
);
|
||||||
|
// Payment status lookup by c_invoice_id (optionally limit by startdate/enddate)
|
||||||
|
router.get("/api/va/status", authMiddleware, async (req, res) =>
|
||||||
|
transferController.paymentStatus(req, res)
|
||||||
|
);
|
||||||
// Signature generation for testing (uses PRIVATE_KEY_PATH file)
|
// Signature generation for testing (uses PRIVATE_KEY_PATH file)
|
||||||
router.post("/generate-signature", (req, res) =>
|
router.post("/generate-signature", (req, res) =>
|
||||||
signController.generateSignature(req, res)
|
signController.generateSignature(req, res)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue