Implement phase 1 completion and phase 2 dynamic QR
This commit is contained in:
33
dist/routes/integrations.js
vendored
33
dist/routes/integrations.js
vendored
@ -6,6 +6,7 @@ import { readIdempotency, writeIdempotency } from "../shared/idempotency/idempot
|
||||
import { addTransactionEvent, findTransactionByPartnerReference, getTransactionEvents, updateTransactionStatus } from "../shared/store/transactionStore";
|
||||
import { emitTransactionPaid } from "../shared/events/transactionEvents";
|
||||
import { env } from "../config/env";
|
||||
import { createAuditLog } from "../shared/store/auditLogStore";
|
||||
const router = Router();
|
||||
function parsePaymentStatus(rawStatus) {
|
||||
const normalized = String(rawStatus || "").toLowerCase();
|
||||
@ -79,6 +80,20 @@ function buildCallbackResponse(req, transactionId, eventId, note, reason) {
|
||||
function writeCallbackResult(idempotencyKey, response, transactionId) {
|
||||
writeIdempotency("callback.processing", idempotencyKey, { response, transaction_id: transactionId }, env.IDEMPOTENCY_TTL_MS);
|
||||
}
|
||||
async function auditWebhookAction(req, payload) {
|
||||
await createAuditLog({
|
||||
actor_type: "webhook",
|
||||
actor_id: "qris_partner",
|
||||
action: payload.action,
|
||||
entity_type: "transaction",
|
||||
entity_id: payload.entity_id,
|
||||
before_json: payload.before_json,
|
||||
after_json: payload.after_json,
|
||||
source_ip: req.ip,
|
||||
request_id: req.requestId,
|
||||
trace_id: req.traceId
|
||||
});
|
||||
}
|
||||
async function makeResponseEventId(txId, fallbackTag) {
|
||||
const events = await getTransactionEvents(txId);
|
||||
return events.at(-1)?.id || `${fallbackTag}_${Date.now()}`;
|
||||
@ -172,6 +187,12 @@ router.post("/qris/callback", async (req, res, next) => {
|
||||
throw error;
|
||||
}
|
||||
if (!wasPaid) {
|
||||
await auditWebhookAction(req, {
|
||||
action: "transaction.mark_paid",
|
||||
entity_id: updated.id,
|
||||
before_json: tx,
|
||||
after_json: updated
|
||||
});
|
||||
emitTransactionPaid({
|
||||
transaction_id: updated.id,
|
||||
merchant_id: updated.merchant_id,
|
||||
@ -216,6 +237,12 @@ router.post("/qris/callback", async (req, res, next) => {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
await auditWebhookAction(req, {
|
||||
action: "transaction.mark_expired",
|
||||
entity_id: updated.id,
|
||||
before_json: tx,
|
||||
after_json: updated
|
||||
});
|
||||
const response = buildCallbackResponse(req, updated.id, await makeResponseEventId(updated.id, "tx_event"));
|
||||
writeCallbackResult(idempotencyKey, response, updated.id);
|
||||
return res.json(successResponse(req, response));
|
||||
@ -235,6 +262,12 @@ router.post("/qris/callback", async (req, res, next) => {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
await auditWebhookAction(req, {
|
||||
action: "transaction.mark_failed",
|
||||
entity_id: updated.id,
|
||||
before_json: tx,
|
||||
after_json: updated
|
||||
});
|
||||
const response = buildCallbackResponse(req, updated.id, await makeResponseEventId(updated.id, "tx_event"), undefined, parsed.status.reason);
|
||||
writeCallbackResult(idempotencyKey, response, updated.id);
|
||||
return res.json(successResponse(req, response));
|
||||
|
||||
Reference in New Issue
Block a user