Adjustment notes
Sub-ledger 6 was introduced by migration0008; the current issuance authority is migration 0068_adjustment_note_proposals.
The idea
A supplier reduces a bill. A customer is credited for a return. A quantity was wrong. In a mutable system you edit the document. In GreatBook the original bill or invoice is never edited; a note references it and changes its derived due. This is the clearest place where immutability and derived balances pay off together. Becausedue is derived rather than stored, a note does not have to reach into the original and change a number.
It adds a row, and the derivation accounts for it.
Every new note is staged for a second person
AdjustmentNoteProposalService.propose derives the full note plan and stores it without posting.
The proposal names its target obligation, credit/debit direction, source discrepancy basis and reference, exact decimal amounts, currency, proposer, reason, request key, and content fingerprint.
Approval requires a different named person.
The service normalizes identities before comparing them, so case, surrounding whitespace, or the email form cannot turn one person into two.
Agent, service, placeholder, and same-person approvers are refused.
The approval and note issue happen in one transaction.
approved is therefore not a durable resting state: either the note, immutable journal, proposal attribution, and native links all commit, or the approval rolls back with the failed post.
The original bill or invoice remains unchanged.
Migration 0068 repeats the load-bearing rules in the database:
- an approved or posted proposal must name a decider distinct from its proposer;
- a staged proposal has no decider and every decided proposal does;
- every proposal carries both a discrepancy basis and the specific source reference;
- amounts are non-negative and
total = amount_pretax + vat_amount; - historical notes are not backfilled with invented issuer or proposal evidence.
The four shapes
Notice that every shape moves the VAT leg too.
A credit note that reduces a bill also reduces the recoverable input VAT, so the VAT register and the
133 position stay tied.
A note that touches a stock account also posts a matching stock movement, so the costing sub-ledger stays consistent with what was actually returned.
What a note may not do
Three checks constrain a note against the document it adjusts:
Plus
ADJ-CATALOG (the direction and target type are in the catalog), ADJ-ORPHAN (no note against a document that does not exist), ADJ-AMOUNT (amount matches quantity times price) and ADJ-STOCK-COUNTERLEG (a stock-touching note posted its movement).
Two explainable balances report the net adjustment impact on AP and on AR.
Where it is enforced
The test that would fail if it broke
backend/tests/test_adjustments.py covers all four shapes and the constraint checks, and ties to the v12 worked data: a credit note moves a bill’s due to 2,805,000 with the original document frozen, and a note against an invoice produces a negative due of 100 where the customer overpaid.
backend/tests/test_adjustment_note_authority.py covers distinct-human approval, exact plan re-derivation, stale state, database constraints, replay, atomicity, and deliberately null historical attribution.
A negative due is a legitimate outcome, not a bug: it is an overpayment.
The check surface reports it rather than clamping it to zero, because clamping loses the fact that money is owed back.
Adjustment notes are not adjusting entries
Two similarly-named things, and they are different.What goes wrong without it
Editing the original is the alternative, and it breaks three things at once: the hash chain, the audit trail, and any downstream artifact that already quoted the old figure. The softer failure is a “correction” booked as a fresh unrelated entry. It nets to the right total and nothing links it to what it corrected, so the supplier statement reconciliation shows one bill you disagree about and one credit you cannot explain.Related
- Immutability and the hash chain - why the original is frozen
- Nothing stored that can be derived - why a note can change
duewithout touching it - Settlement, rails and the AP/AR spine - the obligations notes adjust
- VN VAT and statutory tax - the VAT leg every note carries