Avance Technologies

Odoo Implementation Guide · Updated October 2026

Odoo ERP Migration: Why Matching the Trial Balance Is Not Enough

The opening trial balance agrees with the old system to the fils, and the migration is declared done. Three weeks later a customer payment will not match its invoice and the stock report disagrees with the balance sheet. The totals were right. The detail behind them was not.

In short

A trial balance proves that each account carries the right total at the cutover date. Odoo works from the detail: open invoices and bills, stock quantities at cost, bank statement lines, foreign-currency documents at their original rates. A migration is ready to sign off when each control account agrees with its detail — receivables with open invoices less credit notes, payables with open bills less refunds, inventory with quantity times cost for each product — and the clearing accounts used for the import are back at nil. Odoo's own transition guide sets those checks as requirements, not as optional extras.

This guide covers moving into Odoo from another accounting system, such as Tally, QuickBooks, Sage or an older ERP. Avance Technologies implements Odoo from Dubai, including the data migration and the reconciliation that signs it off.

Key takeaways

  • A balanced, matching trial balance is the starting condition, not the finish line.
  • Receivables and payables come across as open documents, not as one balance per customer or supplier.
  • Odoo's method brings opening balances and open items through clearing accounts so they are not counted twice; a clearing account left with a balance is the clearest sign of a gap.
  • Foreign-currency documents need the historical rate for their own date, or their AED value drifts from the trial balance.
  • Opening stock should equal quantity times cost for each product, and the count should be tested on a copy first, because some valuation settings post it to the ledger as well.
  • The cleanest cutover is a year end or the end of a VAT return period; mid-period splits the return across two systems.

What a matching trial balance proves, and what it does not

A trial balance is a list of accounts with a closing figure against each. If the opening entry in Odoo reproduces those figures, the balance sheet on day one will look right. That is worth having, and it is the check most migrations stop at.

The trouble is that Odoo does not run on account totals. Receipts are matched to invoices, ageing is calculated from due dates, stock is valued from quantities and costs held per product, and bank reconciliation works line by line from a starting balance. A receivables total of AED 412,600 can be exactly right while the invoices behind it are incomplete, duplicated or in the wrong currency. Errors also offset: an invoice missed from one customer and an extra one included for another leave the total untouched.

Odoo's documentation for companies moving across from another system is direct about this. Before creating opening entries, it sets four conditions: receivable balances equal open customer invoices minus credit notes, payable balances equal open vendor bills minus refunds, inventory account balances equal the value of the stock counted, and the trial balance itself balances. Three of the four are about detail.

The reconciliation behind the trial balance

Each line of the trial balance that has a sub-ledger behind it needs its own check. These are the ones that most often carry a hidden difference.

Control accounts and the detail each one has to agree with
Trial balance lineMust agree withWhat goes wrong if it does not
Trade receivablesOpen invoices less open credit notes and unapplied receipts, by customerPayments cannot be matched, ageing and statements are wrong, follow-ups go to customers who have paid
Trade payablesOpen bills less refunds and advances paid, by supplierSuppliers get paid twice or not at all; the payables ageing cannot be trusted
InventoryQuantity times cost for each product, by locationMargins are wrong from the first sale; the stock report and the balance sheet disagree
Bank and cashThe bank ledger balance reconciled to the cutover bank statement, with outstanding cheques and deposits in transit identified separatelyBank reconciliation in Odoo starts from the wrong figure and does not close
Foreign-currency balancesEach open document in its own currency at its original rateExchange gains and losses on settlement are miscalculated
Post-dated chequesA cheque-by-cheque list at the cutover dateCustomer balances look settled or outstanding when they are neither
Fixed assetsThe asset register: cost, depreciation to date and remaining life per assetDepreciation restarts, stops or runs at the wrong rate after go-live
VAT accountsThe position on the last VAT return filed from the old system, plus any period not yet filedThe first VAT return from Odoo does not reconcile to the ledger

The right place to fix a difference is in the old system, before export. Correcting it in Odoo after import means the two systems no longer agree at the cutover date, and that is the one point where they need to.

A worked example: the trial balance that matched

A Sharjah trading company moves to Odoo at 30 September, the end of a VAT return period. The opening trial balance is imported, balances, and agrees with the old system line for line. Following Odoo's method, receivables and payables are routed through clearing accounts, and the open documents are imported against them. Three things then surface.

Receivables: the clearing account does not return to nil

Trial balance, trade receivables: AED 412,600 → AR clearing

Open invoices imported: AED 418,450 → AR clearing

Left in AR clearing: AED 5,850

The trial balance figure was correct. The difference is two receipts the old system held against customer accounts without matching them to invoices: a contractor's advance of AED 4,000 and an overpayment of AED 1,850. Imported invoice by invoice, without those two credits, the customers would have been chased for money they had already paid. Brought across as open credits, the clearing account closes.

Payables: one euro bill, converted at the wrong rate

Bill dated 15 July: EUR 40,000 at 4.0200 = AED 160,800 in the old system

Imported without a historical rate: EUR 40,000 at 4.2700 = AED 170,800

Difference left in AP clearing: AED 10,000

The payables total in the trial balance was right. The bill was converted at the rate the database held, not the rate the old books used, so its AED value moved. Left as it was, the exchange difference reported when the supplier is paid would be wrong by the same AED 10,000. The fix is the one Odoo's guide gives: create the historical rate for 15 July before importing the bill. Rates in this example are illustrative.

Stock: the count is AED 4,500 short of the ledger

Trial balance, inventory: AED 286,400

Opening count, quantity × cost per product: AED 281,900

Difference: AED 4,500

A shipment received in the old system on 29 September was still at the clearing agent's warehouse when the count was taken, so it was in the ledger and not on the count sheet. Neither figure was wrong; the scope was different. The goods belonged in the opening inventory, so they needed adding to the count. Imported as they stood, Odoo would have started with stock it cannot see, and the first month-end stock reconciliation would have begun with an unexplained difference.

In all three cases the trial balance matched. The clearing accounts and the per-product check did not, and those are what found the problems. This is why the clearing accounts are an additional sign-off control: the trial balance still has to agree with the old system, and the clearing accounts have to return to nil.

Stock: the line most likely to be counted twice

Odoo's guide brings opening inventory in as two things: the inventory accounts inside the opening trial balance, and a physical count imported through the inventory adjustment screen. Product costs have to be in place before the count is applied — Odoo's documentation singles out cost as particularly important for the opening inventory — and products tracked by lot or serial number need one line per lot or serial.

The point to test is whether applying the count also posts to the ledger in your configuration. Odoo's documentation for version 19 notes that with Anglo-Saxon accounting and perpetual (at invoicing) valuation, an inventory adjustment updates the valuation account in real time once the move is completed. If the count posts its own entry to the stock valuation account and the opening trial balance has already placed the inventory value there, stock is counted twice. Odoo's transition guide prescribes clearing accounts for receivables and payables but does not address this case for stock, so what follows is our recommendation rather than a documented procedure: route the inventory line of the trial balance through a clearing account as well, or set the count's counterpart account so the two cancel, and run the count for a handful of products on a copy of the database first to see which applies.

A separate case applies where the Odoo database was already in use before the accounting transition, through the Invoicing app or automated stock valuation. Odoo's guide covers that with the Invoicing Switch Threshold in the Accounting settings, which cancels the journal entries dated before the transition so the ledger starts clean. For how the stock report and the ledger relate after go-live, see our guide on Odoo inventory valuation and the general ledger.

Products costed on FIFO with stock bought at several prices need one more step. Odoo's documentation suggests setting the cost, importing the quantity held at that cost, and repeating for each cost layer, rather than loading a single averaged figure.

When to cut over

Odoo's documentation describes three options. The end of the financial year is the easiest, because the least data has to move. The end of a tax period is workable. The middle of a tax period is not recommended, because the return for that period then has to be assembled from two systems.

For a UAE business, that usually means cutting over at the end of a VAT return period, and at the year end where the project timetable allows it. The last return from the old system then covers a complete period, the first return from Odoo starts clean, and the VAT accounts in the opening trial balance can be agreed to a filed return.

Once the opening position is signed off, Odoo's lock dates are worth using. A lock date set to the last day kept in the old system prevents entries being posted into the pre-migration period by accident, while still allowing an administrator to make an exception if a genuine correction is needed.

What the trial balance does not contain

Some of what a business needs on day one has no line in the trial balance at all, so matching it cannot confirm any of it.

  • Open sales and purchase orders. Commitments not yet delivered or invoiced, including orders partly delivered or partly received, which need to come across in their current state.
  • Customer and supplier terms. Payment terms, credit limits and the default receivable and payable accounts on each contact, which Odoo applies by default to new invoices and bills.
  • Tax details on contacts. Customer TRNs and addresses, which belong on tax invoices now and carry more weight as structured e-invoicing approaches.
  • Product master data. Costs, units of measure, product categories and their valuation settings, which decide how future stock movements are valued.
  • Employee balances. Leave balances and the service history behind end-of-service accruals, which sit in HR records rather than the ledger. Our gratuity calculator shows what the accrual is built from.

A sign-off sequence that holds up

The order matters, because Odoo records depend on one another. The documentation is explicit that master data comes first, since an invoice needs its customer and a stock count needs its products.

  • Freeze the old system at the cutover date. Agree the date, stop posting into the period, and prepare the last VAT return for that period from the old system.
  • Export the trial balance and its detail at the same date. Aged receivables, aged payables, stock by product and location, bank reconciliations with uncleared items, foreign-currency open items, post-dated cheques and the asset register.
  • Reconcile each sub-ledger to its control account in the old system. Differences found here are fixed here, before anything moves.
  • Load master data first. Chart of accounts, taxes, product categories, products with costs, then contacts. Using the old system's record IDs as external IDs lets the open documents link back to the right contact and product.
  • Rehearse on a test database. Odoo recommends practising the transition in a test database first, and running in parallel with the old process if there is any doubt.
  • Import open items, the stock count and the trial balance through clearing accounts. Historical exchange rates go in before any foreign-currency document.
  • Close the clearing accounts. Each should return to nil. Once it does, Odoo's guide moves it off the balance sheet.
  • Compare the reports side by side. Aged receivables and payables by partner, stock valuation by product, and the bank position, against the same reports from the old system.
  • Lock the period and keep the old system readable. History stays where it is, read-only, for as long as it needs to be retained.

What this guide does not cover

  • Upgrading from one Odoo version to another, which is a database upgrade with its own testing rather than a migration from a different system.
  • Migrating full transaction history, which is rarely worth the reconciliation effort it creates.
  • Payroll history and the tax treatment of any balance — those are questions for your auditor or tax adviser.
  • Screen-by-screen configuration, which varies by version; the reconciliation logic matters more than the menu path.

Talk to our Odoo team in Dubai → We migrate UAE and GCC businesses into Odoo from Tally, QuickBooks, Microsoft Dynamics and other systems, with the reconciliation that shows the opening position is right before the old system is switched off.

Frequently asked questions

Is a matching trial balance enough to sign off an Odoo migration?

No. It shows that each account carries the right total at the cutover date, which is necessary but says nothing about the detail Odoo works from. Receivables have to agree with the open invoices and credit notes behind them, payables with the open bills, inventory with quantity times cost for each product, and bank balances with the statement position including uncleared items. Odoo's own transition guide sets these as requirements before the opening entries are created. A migration is ready to sign off when each control account agrees with its detail and the clearing accounts used for the import are back at nil.

Why does Odoo use clearing accounts for opening balances?

To stop receivables and payables being counted twice. The opening trial balance carries the receivables total, and the open invoices imported to support it carry the same amount again. Odoo's documentation gives the example of a receivables balance of 1,000 appearing as 2,000 when both are created without adjustment. Routing the trial balance line and the imported invoices through a clearing account lets the two cancel. A clearing account that does not return to nil is the most useful signal the migration produces, because it means the detail and the total disagree.

Should we import our full transaction history into Odoo?

Usually not. Bringing in balances and open items keeps the migration small enough to reconcile properly, and Odoo's guidance is built around exactly that: opening balances, open invoices and bills, an opening stock count and bank starting balances. History is better kept in the old system, set to read-only and retained for as long as your record-keeping obligations require. Where specific history is needed in Odoo, such as a year of sales by customer for reporting, it can be brought in as a separate, deliberate exercise.

When is the best time to switch to Odoo?

Odoo's documentation describes three options. The end of the financial year is the easiest, because it minimises what has to be transferred. The end of a tax period is workable. Mid-period is not recommended, because the VAT return for that period would have to be prepared from two systems. For a UAE business that usually means aligning the cutover with the end of a VAT return period, and preferably with the year end where the timetable allows.

How are foreign-currency invoices and bills brought into Odoo?

Each one in its original currency, with the exchange rate the old system used on its date. Odoo's guidance is to create a historical exchange rate for the date of each foreign-currency invoice or bill before importing it. If that step is skipped, the document is converted at whatever rate the database holds for that date, its AED value no longer matches the payables or receivables line in the trial balance, and the exchange difference reported when it is eventually paid is wrong.

How is opening stock brought into Odoo?

Product costs are set first, then the counted quantities are imported through the physical inventory screen and applied with an opening-inventory reason and a counting date. Before that, quantity times cost for each product should add up to the inventory accounts in the opening trial balance. One point to test on a copy of the database: depending on the valuation settings, applying the count can post its own entry to the stock valuation account. Where it does, the two entries have to be set up to cancel, for example by routing the inventory line of the trial balance through a clearing account, or stock is counted twice. Odoo's transition guide does not cover this for stock, so it is a test to run rather than a documented step.

What happens to post-dated cheques at cutover?

They are open items with a future date, so they need to come across as a list, not as a balance. Received cheques not yet deposited, and issued cheques not yet presented, each affect what the bank and the customer or supplier balances will look like after go-live. How they are recorded in Odoo depends on the configuration chosen, but the reconciliation is the same: the list at the cutover date should agree with the balance carried for it, cheque by cheque.

Can we raise a credit note against an invoice migrated from the old system?

Yes, but it needs care. Odoo recommends importing open invoices with only the amount due, rather than their individual lines, to avoid tax accounts being affected twice. That means a migrated invoice carries no VAT line of its own. A credit note issued against it later will not pick up the original VAT treatment automatically, so the tax on the credit note has to be set deliberately. It is worth deciding how this is handled before the first one is needed.

Written by the Avance Technologies team in Dubai, from implementing Odoo for UAE businesses. The transition steps described here follow Odoo's published documentation for version 19, including its guidance on opening entries, clearing accounts and lock dates; features and menu names change between releases, so confirm against the version you run. Figures in the examples are illustrative. This is guidance on how the software behaves, not accounting or tax advice — the treatment of balances and the timing of the cutover belong with your auditor or tax adviser. Reviewed October 2026.

Planning a move to Odoo?

Tell us which system you are moving from and roughly how many open invoices, products and currencies are involved, and we will tell you where the reconciliation effort is likely to sit.

CallWhatsAppDemo