import { randomUUID } from "node:crypto"; import { createTransaction, addTransactionEvent, toTransactionPayload } from "../store/transactionStore"; function makePartnerReference(requestId) { const clean = requestId.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 40); return `DYN-${clean || randomUUID().slice(0, 12)}`; } function makeDynamicQrPayload(input) { const amountMinor = Math.round(input.amount * 100); const encoded = Buffer.from(JSON.stringify({ type: "QRIS_DYNAMIC_MOCK", transaction_id: input.transactionId, partner_reference: input.partnerReference, amount_minor: amountMinor, currency: input.currency, expires_at: input.expiresAt })).toString("base64url"); return `QRIS-DYNAMIC-MOCK.${encoded}`; } export async function createDynamicQrTransaction(input) { const ttlSeconds = Math.min(Math.max(input.expires_in_seconds || 300, 60), 1800); const expiresAt = new Date(Date.now() + ttlSeconds * 1000).toISOString(); const partnerReference = makePartnerReference(input.request_id); const tx = await createTransaction({ merchant_id: input.merchant_id, outlet_id: input.outlet_id, terminal_id: input.terminal_id, device_id: input.device_id, partner_reference: partnerReference, amount: input.amount, currency: input.currency || "IDR", qr_mode: "dynamic", initiation_mode: input.initiation_mode || "dynamic_api", status: "awaiting_payment", expired_at: expiresAt }); const qrPayload = makeDynamicQrPayload({ transactionId: tx.id, partnerReference, amount: tx.amount, currency: tx.currency, expiresAt }); await addTransactionEvent({ transaction_id: tx.id, event_type: "DYNAMIC_QR_CREATED", source: "device", payload_json: { request_id: input.request_id, correlation_id: input.request_id, device_id: input.device_id, qr_payload: qrPayload, expires_at: expiresAt, transaction: toTransactionPayload(tx) } }); return { request_id: input.request_id, correlation_id: input.request_id, transaction_id: tx.id, transaction_code: tx.transaction_code, qr_type: "dynamic", qr_payload: qrPayload, expires_at: expiresAt, status: "awaiting_payment", partner_reference: partnerReference }; }