← DArnTech services

darnbooks · QuickBooks Desktop → ERPNext · migration proof · 2026-08-21

The Penny-Exact Proof

A complete company — 1,191 transactions over two fiscal years — was placed into real QuickBooks Desktop, extracted through QuickBooks' own API, and loaded into ERPNext. At every step, an independent checker compared the books. They match to the penny, everywhere.

TRIAL BALANCE337,670.12Dr = Cr, all four systems
1,191 transactions 1,828 line items 386 payments w/ applications 44 ledger accounts 0 differences at the gate
Scope, stated plainly: the company is synthetic — generated data built to exercise real migration hazards (partial payments, credit memos, owner draws, sales tax, near-duplicate vendor names). No client data was used, and this page claims exactly what it shows: one company, moved once, verified three ways. Payroll is out of scope by design — it routes to a payroll service, and the books receive the journal entry.

How the proof is built

One rule makes the whole thing checkable: every system must describe the books in the same neutral format — a normalized JSON schema where money is a decimal string, never a float. The generator writes it, the QuickBooks extractor writes it, the ERPNext reader writes it. The parity checker only ever compares two of those files; it doesn't know or care where they came from.

Generator QuickBooks Normalized ERPNext v15 seed 42, deterministic Desktop Enterprise 24 JSON snapshot fresh company canonical JSON real install, real books money = decimal string chart from extraction IIF lists+txns qbXML payments qbXML 17.0 extract raw XML archived REST import provenance-tagged reader: books back out as the same JSON CHECK 1 — parity: canonical vs. what QuickBooks holds . CHECK 2 — rebuild TB recomputed from raw txns CHECK 3 — parity: ERPNext read-back vs. the extract
The three checks are independent: check 1 proves QuickBooks holds the intended books, check 2 proves the extracted transactions alone are sufficient to rebuild the trial balance, and check 3 proves ERPNext ends up holding the same books it was given. Any single-cent error anywhere fails a gate — that failure mode is itself tested.

The three checks, with their actual output

CHECK 1 · PASS

QuickBooks holds the intended books

The generator's canonical file says what the books should be. After importing into a fresh QuickBooks company and extracting back out over qbXML, the two snapshots are compared: trial balance per account, AR and AP agings per customer and vendor, and every entity count.

$ python3 tools/parity_check.py --named-deltas artifacts/seed42/expected-deltas-qbd.json \
    artifacts/extract-20260821T183504Z.json artifacts/seed42/synthetic-company.json
  ~ named delta (accepted): counts.accounts: A=44 vs B=37   # QBD pre-creates 7 accounts
  ~ named delta (accepted): counts.terms: A=7 vs B=3        # QBD pre-creates standard terms
RESULT: PASS - snapshots match on all compared fields (2 named delta(s) accepted).

The two "named deltas" are QuickBooks' own furniture — accounts and payment terms it creates in every new company. They are declared in a file, matched exactly, and the check fails if they don't appear. Nothing is waved through silently.

CHECK 2 · PENNY-EXACT

The extraction is complete enough to rebuild the books

This is the strongest evidence that nothing was lost in extraction: taking only the extracted transactions and re-deriving every posting from first principles (debits, credits, tax lines, payment applications, fiscal-year close), the rebuilt trial balance equals QuickBooks' own report on every account.

$ python3 tools/recompute_tb.py artifacts/extract-20260821T183504Z.json
  QBD TB total       : 337670.12 Dr / 337670.12 Cr
  recomputed TB total: 337670.12 Dr / 337670.12 Cr
  accounts compared 36: matched 36, mismatched 0 (0 unexplained by declared gaps)
RESULT: PENNY-EXACT — recomputed TB matches QuickBooks on every account.
CHECK 3 · PASS, ZERO DELTAS

ERPNext ends up with the same books

The extract is loaded into a fresh ERPNext company over REST — chart of accounts from the extraction (never a template), every document tagged back to its QuickBooks transaction ID. A separate reader pulls the books out of ERPNext as the same normalized JSON, and the checker compares it against the extract. The reader also fails loudly if any untagged ledger entry exists — nothing may post outside the migration.

$ python3 tools/parity_check.py erpnext-snapshot-extract.json artifacts/extract-20260821T183504Z.json
  Compared: trialBalance, arAging, apAging, counts
RESULT: PASS - snapshots match on all compared fields.

Same books, two systems

The trial balance as each system reports it, captured live from the running installs.

QUICKBOOKS DESKTOP ENTERPRISE 24 · Trial Balance, all dates
QuickBooks Desktop Trial Balance report for Acme Sign & Service as of July 31, 2026, listing all 37 accounts with a double-underlined total of 337,670.12 in both the debit and credit columns.
ERPNEXT v15 · Trial Balance, fiscal 2026 view of the migrated company
ERPNext Trial Balance report for the migrated company Acme Sign & Service, fiscal year 2026, showing closing balances identical to the QuickBooks report: Checking 38,562.92, Accounts Receivable 42,084.52, Accounts Payable 24,352.27, Sales Tax Payable 729.68.

The two systems present the report differently — ERPNext shows opening/period/closing per fiscal year, QuickBooks a point-in-time balance — but the closing figures are the same numbers, cent for cent. The row-by-row, full-window comparison is what the checker does mechanically in Check 3.

Why you can trust the checker

Chain of evidence

Every check above writes a file: the canonical books, the raw QuickBooks XML, each comparison report. They live in a private repository. Read the artifacts with me on a call, and I'll re-run any gate you pick.

What the proof surfaced along the way

The value of doing this against real QuickBooks rather than on paper: the live install pushed back, and each finding is now encoded in the tools.

Sage 50, held to the same penny

Sage stopped selling Sage 50 licenses you keep on January 1, 2023, so its owners now rent it on Sage's schedule. We wrote the same 1,191-transaction company into Sage 50's documented export format: nine CSV files, laid out the way Sage's own documentation specifies. A separate reader rebuilt the whole books from those files alone. They match to the penny.

To show the gate can fail, we changed one cent on one row of the sales file — an 890.00 line became 889.99. The checker found seven differences, including a paid-up customer who suddenly showed a one-cent credit.

Not proven yet: we haven't exported from a live Sage 50 install and run that file through. Until we do, that step is mapped, not proven.

Have books to move?

This proof is the method we bring to your company file. Scope depends on your books, so it starts with a conversation, not a quote form.

Book a 30-min call All services →