← All articles

Blog

Migrating to Odoo from QuickBooks, Xero, Excel or a Legacy ERP

A practical data migration playbook for moving to Odoo from QuickBooks, Xero, spreadsheets or an old ERP: what to bring over, what to leave, and how to validate.

7 min read
  • bottom
  • odoo

The short answer: most Odoo migrations go wrong because teams try to move everything. The approach that works is to migrate master data (customers, vendors, products, chart of accounts), opening balances at a clean cut-off date, and open items (unpaid invoices, open orders, stock on hand). Leave full transaction history in the old system, or in an archive, as read-only reference.

The source system matters less than you would expect. QuickBooks, Xero, a spreadsheet and a 15-year-old ERP all end up as the same set of files that Odoo imports. What changes is how clean those files are.

Step 1: Decide what actually moves

Before touching a file, sort your data into three buckets.

BucketExamplesUsual approach
Master dataContacts, products, price lists, chart of accounts, taxes, bills of materialsClean and import
Balances and open itemsTrial balance at cut-off, unpaid customer invoices, unpaid vendor bills, open sales and purchase orders, stock quantitiesImport as of one date
HistoryClosed invoices, old orders, old journal entries, email threadsKeep in the old system or an export; migrate only if there is a clear reporting need

Every extra year of history you import is more mapping, more validation and more things that can quietly go wrong. Auditors and tax authorities generally care that you can retrieve old records, not that they live inside the new system. Confirm the retention rules in your country with your accountant.

Step 2: Choose a cut-off date

For finance data, pick a clean boundary, typically the end of a month, quarter or fiscal year. Balances are posted as of that date, and everything after it is entered in Odoo directly.

A year-end cut-off is easiest because the old books are closed and the trial balance is final. A mid-year cut-off is workable, but expect to also bring across year-to-date figures if management reports need them.

Step 3: Map before you import

Mapping is where most of the effort sits, and it is a business task as much as a technical one.

  • Chart of accounts. Do not copy the old chart blindly. Start from the Odoo chart for your country, then map each legacy account to it. Retiring unused or duplicate accounts is a good reason to migrate in the first place.
  • Taxes. Map every tax code you use (sales tax, VAT, reverse charge, exempt) to the matching Odoo tax. Wrong tax mapping is hard to spot until a return is due.
  • Partners. Customers and vendors often live in separate tables or as free text. Deduplicate them first, and decide how you will identify a partner uniquely (a reference code, a VAT number, an email).
  • Products and units. Standardize units of measure, SKUs and categories. Spreadsheets tend to hide inconsistent names here.
  • Currencies. List every currency in use and agree how foreign-currency open items are revalued at the cut-off.

Step 4: Understand how Odoo imports data

Odoo’s official documentation covers the mechanics. The points that matter most for a migration:

  • Odoo imports from .xlsx or .csv files on most business objects.
  • Keep the External ID column. A unique External ID per record lets you re-import a corrected file without creating duplicates, and it is how related records (an invoice and its partner, for example) are linked.
  • Odoo guesses a column’s field type from the first rows, so some columns may map wrongly or not at all. Check the mapping on the test screen, and use Test before Import.
  • Large files can time out. The documentation recommends splitting them into smaller batches.
  • Imports are permanent and cannot be undone. You can find affected records afterwards with the created-on or last-modified filters, but a bad import means cleanup work.

That last point is the reason to do every migration at least twice: once into a throwaway test database, then again for real.

Step 5: Load opening balances and open items

For the accounting side, the pattern described by Odoo’s community and partners is consistent, though the exact screens differ by version and apps installed, so confirm against the documentation for your release.

  1. Post the balance sheet balances as of the cut-off date, typically as an opening journal entry.
  2. Load receivables and payables per partner, so you can match payments to specific invoices later. A community thread describes entering open items invoice by invoice if you want to pay them invoice by invoice.
  3. Use a temporary balancing (waiting) account for the offset, and check that it ends at zero. One forum discussion shows what happens when an opening entry does not balance: Odoo rejects the import with a “not balanced” error, which is why each file needs its own balancing line.
  4. Keep these in separate, individually balanced files (general ledger, customers, vendors) rather than one giant file.

These forum threads are community material, not official procedure. Treat them as a pattern to test, not a guarantee.

Source-specific notes

QuickBooks. Export the trial balance, customer and vendor lists, and the aged receivables and payables reports as of the cut-off. The chart of accounts usually needs the most remapping, because QuickBooks users tend to accumulate sub-accounts over time.

Xero. The same logic applies: trial balance, contacts, and aged receivables and payables. Xero tracking categories need a deliberate decision, since Odoo handles analytic dimensions differently (analytic accounts and plans).

Excel or Google Sheets. The risk is not the format but the discipline. Spreadsheets contain merged cells, mixed date formats, blank rows with meaning and the same customer typed five ways. Budget real time for cleaning before you map anything.

Legacy or on-premise ERP. Expect unusual data models, custom fields and encodings. Extract through database queries or reports, not screen exports, and involve whoever knows why a given field exists. Stock valuation and bills of materials are the two areas where legacy ERPs most often hide surprises.

Step 6: Validate, then run in parallel

Validation is the step teams skip when schedules slip, and it is the one that protects you.

  • Trial balance: Odoo’s trial balance at the cut-off must match the final legacy trial balance, account by account.
  • Sub-ledgers: Aged receivables and payables in Odoo must match the legacy aged reports in total and per partner.
  • Inventory: Quantities and valuation must match a physical or system count on the cut-off date.
  • Record counts: Compare counts of partners, products and open orders against the source files.
  • Spot checks: Have the people who use the data daily check 20 or 30 records each. They find problems totals do not.

If you can, run both systems for one accounting period and compare the reports before turning off the old one. It costs extra effort for a month, and it is far cheaper than finding a discrepancy at year-end.

A realistic sequence

  1. Scope and cut-off date agreed.
  2. Mapping workbook for accounts, taxes, partners and products signed off.
  3. Trial import into a test database; fix and repeat until clean.
  4. User acceptance testing on migrated data.
  5. Final extract at the cut-off, final import, validation checks.
  6. Go live, then reconcile at the first month-end.

Timelines depend on data quality and scope, so be wary of anyone who quotes a fixed duration before seeing your files.

Common mistakes

  • Importing years of history “just in case”.
  • Skipping the test database and importing straight into production.
  • Mapping the chart of accounts last, after other data already depends on it.
  • No named owner on the business side for data sign-off.
  • Treating validation as a formality.

Next step

If you are weighing a move to Odoo and want a second opinion on scope, data quality or cut-off timing, we are happy to talk it through, no charge and no obligation. Get in touch with Teknologia Solutions and bring a sample of your data if you have one.


Sources: Odoo documentation, Export and import data (19.0); Odoo community forum, importing receivables and payables from a legacy system; Odoo community forum, opening balances import process. Forum posts are community material and may not reflect your Odoo version. Please verify procedures against the official documentation for your release, and confirm accounting and record-retention requirements with your accountant.