Skip to content

Unpost / Repost Manual Journal Entries — is_posted made real

Date: 2026-06-27 Status: shipped Audit finding: #31LedgerEntry.is_posted was never False, so the ~dozen is_posted.is_(True) report filters were vacuous and the draft/post concept the column modelled didn't exist.

Problem / motivation

Every ledger entry was born is_posted = True and nothing ever set it False, so reports filtering on posted entries filtered nothing and there was no way to exclude an erroneous manual journal entry from the books short of deleting it.

What shipped

The lowest-risk way to make is_posted meaningful (chosen over a full draft workflow or dropping the column):

  • unpostLedgerEntry(entryId) — excludes a manual journal entry from the posted ledger and therefore from every report (the is_posted.is_(True) filters now do real work). The entry is retained, not deleted.
  • postLedgerEntry(entryId) — restores a previously-unposted manual entry (re-checking the accounting period is open).
  • Guard: only manual entries (no source_type) can be unposted/posted. A source-linked entry (invoice, payment, credit, …) raises a ValidationError — it must be reversed instead, so a document's accounting effect is never silently dropped.
  • Audit trail: both operations are recorded on the tamper-evident ledger audit chain — POSTED on repost and a new UNPOSTED operation on unpost.

Files

Data model / GraphQL surface

  • No DB migration. LedgerAuditOperation gains an appended UNPOSTED member (stable integer value — no reindex of existing rows; it's an IntEnum stored as a smallint).
  • New mutations postLedgerEntry / unpostLedgerEntry (additive).

Frontend impact

  • A manual journal entry can now be unposted (hidden from reports) and reposted.
  • Attempting to unpost a source-linked entry returns a validation error directing the user to reverse it instead.

Future additions

  • Create-as-draft: create_manual_journal_entry still posts immediately; a future option could create manual entries as drafts (is_posted = False) for review before posting.