01The payment gateway doesn't get to say you paid
A bank transfer is someone claiming they paid, so an admin checks the proof before the invoice counts. A gateway callback that arrives through the participant's browser has the same shape: a claim, over a channel I don't control.
So both payment paths end in the same state, waiting for confirmation, and only an admin can move an invoice from there to paid. Every action also checks that the invoice is in a state the change is allowed from, so a repeated request is rejected instead of applied twice. Each change of status is saved as a history row, which is where the receipt email reads the payment date from.
To catch a payment the browser never reported, reopening an invoice makes the server ask Midtrans directly for that order's status.
// a gateway success only moves the invoice to WAITING_CONFIRMATION;// an admin's accept-payment is the only way to SUCCESSif (transactionExist.payment_status !== "PENDING") { return { error: "Action not allowed in current invoice status" };} transaction = await db.transaction.update({ where: { id: transaction_id }, data: { payment_status: "WAITING_CONFIRMATION", status_history: { create: { user: { connect: { id: user_id } }, newStatus: "WAITING_CONFIRMATION", oldStatus: transactionExist.payment_status }, }, },});Every payment waits for an admin to confirm it, so the receipt isn't instant.


