Retroactive Accounting Migration
If a tenant has been running on Fexl Lite since before the accounting layer landed — or imported their data from a different POS — their journal_entries table starts empty even though the invoices, expenses, inventory_transactions, and customer_payments tables are full. The Trial Balance is empty. The P&L shows zeros. The Balance Sheet has no Cash & Equivalents number to draw on. The Retroactive Migration is the one-button fix: it walks the historical operational tables and posts the journal entries that should have been written at the time.
When you need it
Run the migration if:
- The Trial Balance shows the empty-state hint “Run the retroactive migration from Settings → Accounting to populate journal entries.”
- The P&L shows zero revenue / zero COGS even though the Invoices page lists hundreds of completed invoices.
- A tenant was upgraded from a pre-accounting build of Fexl Lite (before v1.6.0).
- A tenant imported data from another system into the operational tables without populating
journal_entries.
If you started on a recent Fexl Lite version with a fresh tenant, you don’t need this — the chokepoint that posts JEs has been firing on every flow since day one of your usage, and the books are already complete.
What the migration does
Per tenant, the migration walks each operational table in chronological order and posts the JE that the matching flow would have posted at the time:
- Invoices (non-cancelled, non-comp) — for each invoice, posts the standard cash + revenue + COGS + inventory pattern. Backdates the JE to the invoice’s date.
- Refunds — posts the reverse-revenue + cash-out + re-ingress JE for every completed return.
- Expenses — posts DR
6xxx/ CR1010-xxx(or1300for prepaid) for every expense row. For prepaid expenses, the recognition schedule is replayed too — everyrecognized=truerow gets its DR6xxx/ CR1300JE posted at the schedule’smonth. - Restocks — for every PO receive and manual restock, posts DR
1200/ CR2010(or1010-xxxif cash-paid). - Customer payments — debt settlements (DR
1010-xxx/ CR1100), credit usage (DR2100/ CR1100), credit withdrawals (DR2100/ CR1010-xxx). - Cash drawer transactions — every cash-in, cash-out, and transfer that already has a row in
cash_drawer_transactions.
Comp invoices are deliberately skipped — they have no JE by design, and the migration honours that.
Idempotency
How to run it
Open Settings → Accounting
In the desktop or web app, Settings → Accounting. The Retroactive Migration card is on this page.
Read the warning, then click Run
The card shows a warning that this writes new rows to journal_entries for the entire history — clicking through is an explicit acknowledgement. The button is permission-gated to accounting:migrate; sales-agent roles don’t see it.
Wait for the progress dialog
A progress dialog shows per-table progress: “Invoices: 1,247 / 1,500”, “Expenses: 320 / 320”, etc. Larger tenants take a few minutes; smaller ones complete in seconds.
Verify with the Trial Balance
Once the dialog closes, open the Trial Balance. The chip at the top should read Balanced. Run a P&L for a wide date range and confirm revenue, COGS, and expense numbers are now non-zero and match what the invoices, products, and expenses pages have shown all along.
What can go wrong, and the recovery path
What the migration does not do
- It does not invent missing data. If an invoice was deleted from the operational table, no JE will be posted for it. The migration walks what’s there.
- It does not validate amounts upstream. If
invoices.totaldoesn’t equalΣ items.subtotal − discounts + VAT + shipping, the migration uses what’s on the invoice header, even if the items don’t tie. Fix data shape problems before running. - It does not split bonus-vs-sold COGS retroactively if
is_bonuswasn’t tracked at the time — older imports may post all COGS to5010even for items that should have hit5020. That’s a reporting limitation, not a migration bug. - It does not run on cancelled records. Cancelled invoices are skipped — they wouldn’t have posted a JE the first time around either.