v5.66.0 14 June 2026 Feature Fix

Invoice Correction: Payment Reversal, Void, and an Aged-Report Fix

Why This Matters

Mistakes happen on issued invoices. A payment gets recorded against the wrong one, or an invoice is raised that should never have existed. Until now an issued invoice had only three exits: payment, write-off, or cancellation while still a draft. There was no clean, audited way to undo a recorded payment or to retract an invoice raised in error.

This release adds two correction capabilities that keep the double-entry ledger correct and the audit trail intact, and it fixes a reporting defect found while building them. Together they are the first three steps of the invoice correction lifecycle. The credit note, which is the instrument for correcting VAT that has already been reported, follows in a later release.


Payment Reversal

  • Reverse a recorded payment A payment recorded in error can now be reversed, returning the invoice to sent with nothing paid. The reversal posts the exact inverse of the original receipt inside one atomic transaction, so the ledger is never left half-changed. The settlement relationship between status and amount paid is mechanically enforced as an invertible writer pair (AX-INV-002, Class M; proof anchor: an executable settlement-coherence test in CI plus the payment-bound database constraint, migration 071).

  • Reversal is its own endpoint Reversal is a dedicated action, not a status edit, so it cannot be triggered by accident through the ordinary status surface.


Void

  • Void an invoice raised in error An issued, unpaid invoice can now be voided. Voiding posts a full reversal of the original issue journal, so every affected account returns to zero and the trial balance is unchanged. The original issue document is never edited or deleted; immutability holds. Transitions are enforced at the database (migration 106), and the issue-journal provenance relationship is preserved (AX-INV-004, Class M; proof anchor: the deploy-time provenance sweep plus an executable void-journal reversal test in CI).

  • A paid invoice is voided by reversing the payment first Voiding applies only to an issued, unpaid invoice. A paid invoice cannot be voided directly; reverse the payment to return it to sent, then void. The lifecycle enforces this order rather than allowing a paid invoice to jump straight to voided.

VAT and voiding

  • Voiding does not adjust a VAT return, by design Void is for an invoice whose VAT has not been relied upon in a filed return. Its reversal is deliberately invisible to the VAT return, which continues to reflect the original invoice. To reverse VAT that has been or will be reported on a filed return, use a credit note, which is the correct in-period instrument and is coming in a later release.

  • An advisory at the point of action When you void an invoice that carried VAT, the status response now includes an advisory field restating that the void does not adjust any VAT return. This is an application-level safeguard, not an invariant; it exists so a clean-looking ledger is not mistaken for a corrected return.


Aged Reports Corrected

  • Written-off invoices no longer inflate aged debtors or aged creditors A written-off invoice that still carried an unpaid balance was previously counted as outstanding in the aged debtors and aged creditors reports, overstating both the totals and the ageing buckets. Written-off and voided invoices are now correctly excluded, so the reports show only genuinely outstanding balances. This affected reported figures only; the underlying ledger was always correct. The defect was found pre-launch while building the void capability, logged at High severity, and is recorded as resolved on the transparency page.

Operational Impact

  • Reversing a payment returns an invoice to sent with nothing paid, atomically, with the inverse receipt posted in the same transaction.
  • Voiding an issued, unpaid invoice nets every affected account to zero, the VAT control account included, leaving the trial balance unchanged.
  • Aged debtors and aged creditors now exclude written-off and voided invoices.
  • VAT returns are unchanged by a void and continue to reflect the original invoice; voiding a VAT-bearing invoice returns an advisory to that effect.
  • No change to existing payment, issue, write-off, or cancellation behaviour.

Versioning

The kernel axiom registry moved to v2.26 across this series.

  • AX-INV-002 was amended to record settlement consistency as an invertible writer pair rather than a single writer.
  • AX-INV-004 was amended for the new journal kind and gained a test-layer proof anchor for the void journal.

No new axiom was added and the count of mechanically-enforced invariants is unchanged; these are amendments and an added enforcement layer on an existing invariant.

No breaking API changes. The status endpoint gains voided as a public target and an optional advisory field on its response; the payment reversal endpoint is additive.


Files Changed

Backend:

  • Invoice correction lifecycle: the payment reversal action, the voided status target and its journal posting, and the supporting state-machine transitions (migration 106).
  • Reporting: aged debtors and aged creditors corrected to exclude written-off and voided invoices.
  • Kernel axiom registry: AX-INV-002 and AX-INV-004 amendments, registry to v2.26.

Frontend / Docs site:

  • API reference updated for the new voided status target, the advisory response field, and the payment reversal endpoint.

The next release in this series adds the credit note, the instrument that reverses VAT on a filed return by moving the figures forward into the current period rather than reaching back.