A unique index over (invoice_id, lowercased trimmed reference, amount) on live payment rows. Two real cheques never share a number, so a reference is a hard identity. Payments with no reference — cash, 'other' — are deliberately not constrained, because the same customer paying the same round sum twice is ordinary.
Also called: entered the payment twice · same cheque number · double payment entry · overpaid invoice
- 1recordPayment surfaces Postgres 23505 as a duplicate rather than a generic failure.
- 2The message names the cheque and the amount and states it was not added again.
- 3Reversed rows are excluded from the index so a payment can be backed out and re-entered correctly.
- 4The entry form stays open with the explanation, because closing it would look like the entry went through.
The same cheque was recorded twice against one invoice eight seconds apart, leaving $20,410.12 taken on a $10,205.06 bill while the balance still read zero, so nothing on screen looked wrong. Recording a payment that matches one already on the invoice now stops and shows the one it matched, with the option to confirm it is genuinely a second payment. It never offers to try again, because inviting a retry is exactly how the first duplicate got in.
- Double-entered cheques inflating an invoice's paid amount.
- A 'try again' message causing the exact second entry that creates the problem.
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 →