Both the correction path and the online-payment path rebuild paid_amount as the sum of non-reversed payment rows, then derive balance and status from it. Nothing increments or subtracts a stored figure.
Also called: invoice total doesn't match the payments · balance is wrong · self-healing totals
- 1recomputeInvoiceTotals sums live payments, computes balance = total − paid, and sets status.
- 2Status can fall as well as rise: an invoice whose only payment was reversed stops saying paid but drops to 'sent', not 'draft'.
- 3recordStripePayment recomputes the same way, so concurrent payments on different sessions cannot lose an update.
- 4Re-lining an invoice preserves paid_amount instead of resetting it to zero.
A stored paid total drifts. Subtract a reversal once and it is right, but if the figure was already wrong, or two corrections land together, it stays wrong forever and the invoice permanently disagrees with the payments listed on it. The amount paid is rebuilt from the payment rows that still count every time it is needed, which makes it self-correcting; a separate fault that reset the paid figure to zero when an invoice was edited in place — resurrecting a balance the customer had already settled — was closed with it.
- Stored totals permanently disagreeing with the payment list.
- In-place edits resurrecting a balance that had been paid.
- Concurrent payment writes overwriting each other.
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 →