There is a shortcut almost every booking system takes. Rather than posting accounting entries, it stores transactions – a booking row, a payment row, a refund row – and produces financial reports by summing them at read time. Revenue is a query. The balance sheet is a view.
It works. It works for years, in fact, which is why the shortcut is so common. It stops working during an audit.
What breaks, and when
The problem is that a sum over transaction tables has no memory of intent. When a booking is amended, a payment partially refunded and a supplier bill raised against the same reference, the arithmetic still produces a number – it just produces a number nobody can explain. There is no entry saying this movement debited that account and credited this one, at this moment, because of this event.
An auditor does not ask what your revenue was. They ask you to show them how a specific figure was arrived at, and to demonstrate that the two sides of it agree. A transaction-sum architecture cannot answer that, because the answer was never recorded.
What a journal-based ledger actually requires
Every financial event posts a journal with at least two legs that must sum to zero. A booking does not just create a booking row – it posts revenue against a receivable. A payment moves the receivable to cash. A refund reverses with its own entry rather than editing the original. A supplier bill creates a payable.
Three consequences follow, and they are the reason this is worth the cost:
- The trial balance derives from the same records the operations team creates. There is one source of truth, not an operational system and a financial system that have to be reconciled.
- Nothing is edited in place. Corrections are new entries. The history of what the business believed at each point in time survives.
- Multi-currency becomes tractable. Each leg carries its currency and rate at posting time, so a later rate change does not silently rewrite last year’s revenue.
Retrofitting one
We did this on a live travel ERP handling Hajj and Umrah operations, and the trigger was not an audit – it was discovering that revenue journals were posting as zero across the entire system. A schema mismatch was silently discarding one leg of each entry. Every downstream report was internally consistent and wrong together, which is the worst failure mode available: nothing looked broken.
The sequence that worked:
- Start from the database, not the reports. Reproduce the failing write directly. Reports are a layer of interpretation over the defect and will mislead you.
- Fix the write before touching history. Backfilling into a still-broken schema means doing it twice.
- Rebuild history from source events – the booking, payment and refund records – rather than from the previous reports. Then reconcile the result against external evidence: bank statements and supplier invoices.
- Treat currency re-basing as a separate, reversible migration with a full backup and an account-level comparison of pre- and post-migration balances.
When the shortcut is fine
If the business genuinely does not need auditable financials – a single-currency operation with an external accountant doing the books from exports – a transaction-sum design is cheaper and there is no virtue in over-engineering it. The question worth asking honestly at design time is whether the business will ever need to prove a number to somebody who does not trust it. If the answer is yes, retrofitting later is several times the cost of building it right.
