Back to blog
Engineering Notes 6 min read

Posting rules that make it through a real close

Five module blocks feeding one glowing conduit into a ledger slab carved with a T-account.

Every accounting system posts to the general ledger. The ones that get through a real month-end close have one auditable path for posting. They don't have a helper that each module calls in its own slightly different way.

One writer to the ledger

One function writes to the GL. Everything else (sales invoices, cash receipts, disbursements, journal vouchers) hands it a balanced set of lines and decides nothing. Once a second module is allowed to write its own entries, the two versions start to disagree. You find out three weeks later, when the trial balance is off by a few centavos.

What you get from that

  • Debits and credits get checked in one place only.
  • The fiscal period check runs once, so a closed period really is closed.
  • Reversals are symmetrical, since there's only one shape to reverse.
  • The audit trail comes for free. Nobody has to remember to add it.
If you can't point to the one function that writes to the ledger, you don't have a posting rule. You have a convention, and conventions drift.

Making the database enforce it

A convention that only lives in code review can't be enforced. Put the balance check where the database can refuse the write:

-- Refuse an unbalanced batch outright.
SELECT batch_id
FROM   gl_details
GROUP  BY batch_id
HAVING SUM(debit) <> SUM(credit);

Run that as a guard before the batch is committed, not as a report someone reads on the fifth working day. One gives you a rejected save. The other gives you a reconciliation.

All articles