A reversal marks the payment row reversed with a reason and a name, excludes it from paid_amount, and re-derives the invoice's balance and status from the surviving rows. The row is never deleted — a deletion would make money silently vanish from a reconciled month.
Also called: entered the cheque twice · wrong payment amount · cheque bounced · undo a payment · payment on wrong invoice
- 1The route checks the payment belongs to the caller's org before touching it, and refuses a second reversal.
- 2reversed_at, reversal_reason and reversed_by are stamped on the payment row.
- 3recomputeInvoiceTotals sums only non-reversed payments, writes paid_amount and balance, and lets the status fall.
- 4The open viewer re-reads both the invoice and the payment list rather than patching its local copy.
A single cheque was recorded twice against one invoice, eight seconds apart, leaving $20,410.12 paid on a $10,205.06 bill while the balance on screen still read zero. Voiding the invoice would not have touched the payment. A payment can now be reversed with a reason, and the invoice's paid total is rebuilt from the payments that still count rather than by subtracting the reversal — subtraction is correct exactly once, and the row that started all this held a figure no correct arithmetic ever produced.
- Double-entered payments leaving an invoice permanently overpaid.
- A bounced cheque leaving an invoice marked paid.
- Stored totals that no arithmetic can reproduce.
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →