In this article
- 1. Define the migration scope before exporting data
- Make the compliance decision first
- 2. Build a migration register and preserve the audit trail
- Create External IDs before the first load
- 3. Clean master data and map it to Odoo
- Illustrative example: a multi-branch distributor
- 4. Configure Odoo before importing transactions
- 5. Reconcile opening balances before cutover
- Illustrative example: a Kenyan services group
- 6. Run a sandbox migration and user acceptance test
- 7. Execute cutover and protect the first month-end
- Frequently Asked Questions
- Should we migrate all historical Zoho invoices into Odoo?
- Can we use one Odoo tax configuration for several African countries?
- What is the most important Zoho data field to retain?
- When should we go live after the sandbox test?
A finance manager closes the month in Zoho, then discovers that customer balances, stock values and VAT control accounts will need to agree exactly on the first morning in Odoo. The technical import is rarely the point of failure. The pressure comes when the CFO needs signed opening figures, the tax team needs compliant invoices, and operations cannot stop billing.
A Zoho to Odoo migration needs a controlled cutover plan, not a bulk export. For organisations moving beyond Zoho, our migration to Odoo (from Pastel, QuickBooks, Sage, SAP) work starts with legal entities, tax obligations and the reports that must remain auditable after go-live.
As of October 2026, there is no single African tax or e-invoicing configuration. A group operating in Lusaka, Nairobi and Johannesburg needs separate company settings and country-specific compliance decisions in Odoo. This checklist sets out the order we recommend, based on Odoo 19 import and accounting guidance, plus current official tax authority requirements.
1. Define the migration scope before exporting data
Start with a written scope for each legal entity, not a list of Zoho modules.
For every country operation, document:
● Legal entity name, registration details, base currency and financial year.
● Tax registrations and tax IDs.
● Required invoice sequence and credit-note process.
● E-invoicing or fiscalisation obligation.
● Zoho applications in use, including Books, Inventory, CRM and Expense.
● Odoo apps required at go-live and processes that can wait for phase two.
Create a separate Odoo company for each jurisdiction. Each company needs its own chart of accounts, taxes, invoice numbering, currency, tax identifiers and compliance connector. A generic regional VAT template creates errors because VAT treatment, invoice evidence and electronic reporting rules differ by country.
Make the compliance decision first
Do not build invoicing screens before confirming the tax authority integration route. That is the step teams skip when they treat migration as an accounting project rather than an operational ERP implementation.
● Zambia: Businesses registered for listed taxes have no turnover threshold for Smart Invoice. An Odoo-based invoicing system must be integrated and approved through ZRA Smart Invoice using the Virtual Sales Data Controller route. The absence of a threshold matters because a smaller registered entity cannot assume it is outside the requirement.
● Zimbabwe: VAT operators must issue fiscal tax invoices through a device interfaced with ZIMRA FDMS. A non-compliant invoice cannot support a VAT input-tax or income-tax expense claim, so a normal PDF invoice is not sufficient evidence.
● Kenya: Every person in business must onboard eTIMS and issue electronic tax invoices. Automated Odoo billing requires OSCU or VSCU system-to-system integration and certification, according to KRA guidance.
● Nigeria: Large taxpayers with annual turnover of NGN 5 billion or more must use FIRS Merchant-Buyer e-invoicing. The requirement has applied from 1 August 2025 and includes real-time invoice generation, validation and transmission.
● South Africa: Configure standard VAT at 15%. SARS confirmed this rate on 25 February 2026, so remove any test configuration based on the withdrawn 15.5% or 16% proposals.
If an entity only needs statutory invoicing and core accounting, do not extend the first phase with every CRM customisation or reporting request. Those additions increase testing volume without improving the cutover control position.
2. Build a migration register and preserve the audit trail
List every data set in Zoho, its owner, its destination in Odoo and the decision for historical records. The migration register should be approved by Finance, Operations and IT before any production data is extracted.
At minimum, extract and archive:
1. Customers, suppliers and contact persons.
2. Products, services, units of measure and price lists.
3. Stock on hand and inventory valuation reports.
4. Chart of accounts, tax codes and journals.
5. Open receivables and payables.
6. Bank balances and bank reconciliation reports.
7. Attachments, audit reports and supporting documents required for review.
Keep the Zoho archive read-only and searchable. Migrating every historical invoice into Odoo usually costs more in cleansing and reconciliation than it returns in operational value. The better control is an auditable Zoho archive, controlled opening balances, and only unpaid customer invoices and supplier bills in the new ERP.
Odoo 19 supports CSV and XLSX imports. The important warning in the official Odoo import documentation is that imports are permanent. Load a tested copy into a sandbox first, then correct mappings before any production import.
Create External IDs before the first load
Export Zoho record IDs and turn them into stable External IDs. Use these IDs for customers, suppliers, products and related transactions.
External IDs allow updates without creating duplicates. They also preserve the links between a customer, the products it buys and its outstanding invoices. The most common data mistake we see in planning is dropping source IDs because a spreadsheet appears cleaner without them. It looks tidy until the second import creates duplicate contacts and invoices can no longer be connected to the correct master record.
3. Clean master data and map it to Odoo
Data cleansing is where Finance and Operations need to make decisions that no import tool can make for them. Mark inactive suppliers, duplicate customers, obsolete products and unused tax codes before they enter Odoo.
Use a mapping workbook with these columns:
| Zoho field | Odoo destination | Transformation | Owner | Test result | | Customer ID | External ID | Preserve source value | Finance | Pass or fail | | Tax code | Tax or fiscal position | Map by legal entity | Tax lead | Pass or fail | | Product SKU | Internal reference | Remove duplicates | Operations | Pass or fail | | Invoice date | Accounting date | Format as YYYY-MM-DD | Finance | Pass or fail | | Bank reference | Bank-import mapping | Confirm statement rule | Treasury | Pass or fail | Use ISO 8601 dates in CSV files, written as YYYY-MM-DD. Odoo 19 recommends this format because ambiguous dates such as 03/04/2026 can be interpreted differently by teams using different regional conventions.
Test decimal separators as well. A source export using commas for decimals can turn 1,500.00 into a different value from 1.500,00. This is not a cosmetic issue when the figures feed inventory valuation or tax returns.
Illustrative example: a multi-branch distributor
Take a distributor with four branches, 3,000 active products and monthly sales of about US$250,000. The project team initially planned to import five years of closed invoices because sales staff wanted customer history visible in one screen. After reviewing the requirement, they retained the closed invoice history in a controlled Zoho archive and imported customer master data, opening balances and unpaid invoices only.
That decision reduced the import file volume and made trial-balance reconciliation practical. The team would still need a documented archive-access procedure for auditors and credit control staff. If they were doing it again, they would agree that procedure before cleansing data, rather than during user acceptance testing.
4. Configure Odoo before importing transactions
Set up the destination environment before loading financial documents. Importing first and configuring taxes later is a direct route to invalid tax mapping and rework.
Configure and test:
● Company settings, users, access rights and approval roles.
● Chart of accounts and journals by legal entity.
● Taxes, fiscal positions and tax localisation rules.
● Invoice and credit-note sequences.
● Products, warehouses and valuation settings.
● Bank accounts and bank-import mapping.
● E-invoicing, Smart Invoice or fiscalisation connector where required.
Permissions deserve a formal test. A finance user who can amend a posted invoice, or an operations user who can access another entity’s records, creates an auditable control gap. Test the actual roles people will use at month-end, not only administrator access.
For Kenya, test the eTIMS workflow through the certified OSCU or VSCU integration before allowing automated invoices. For Zambia, confirm the ZRA Smart Invoice approval route before go-live. For Zimbabwe, test that the fiscal invoice is issued through the ZIMRA FDMS-connected process, rather than assuming an Odoo invoice layout proves compliance.
The official sources to retain in the project evidence pack are Odoo 19 documentation, ZRA Smart Invoice guidance, ZIMRA Public Notice 80 of 2024, KRA eTIMS guidance, FIRS Merchant-Buyer guidance and the SARS tax-rate confirmation. These materials provide the baseline, but the final configuration still depends on the entity’s registrations and transaction types.
5. Reconcile opening balances before cutover
A migration is ready for cutover only when the old and new control reports agree. Finance should sign the reconciliation, while IT confirms the data load and access controls.
Reconcile Zoho reports to signed source reports for:
8. Trial balance.
9. Aged debtors.
10. Aged creditors.
11. Inventory valuation.
12. Bank balance.
13. VAT or sales-tax control accounts.
Load opening balances and open items only after these reports agree. Odoo accounting guidance supports this controlled approach because unpaid invoices and bills need to retain their settlement status, while the opening journal carries the prior-period position.
Do not force a difference into a suspense account simply to meet a deadline. A suspense balance without an identified cause postpones the problem into the first close in Odoo, where it becomes harder to distinguish migration error from current-period activity.
Illustrative example: a Kenyan services group
Take a Kenyan services group with two legal entities and KES 18 million in open customer invoices. During the first test load, its aged-debtors total agreed to Zoho, but several invoices did not carry the correct customer reference because the Zoho IDs had not been retained as External IDs. The team stopped the load, rebuilt the customer mapping and reran the sandbox import.
The rework delayed testing by a week, but it prevented duplicate customer accounts and misapplied receipts after go-live. The group also tested eTIMS integration before billing resumed, because KRA requires electronic tax invoices and automated billing needs the certified system-to-system route. The better decision would have been to define the External ID rule in the scope workshop.
6. Run a sandbox migration and user acceptance test
A sandbox rehearsal should reproduce the cutover sequence from extract through reconciliation. It is not a demonstration of screens.
Test these controls in the sandbox:
● Duplicate detection for contacts, products and invoices.
● Date format and decimal separator handling.
● Tax mapping by company and customer scenario.
● User permissions and approval routing.
● Bank statement import and matching rules.
● Customer invoice, credit note and supplier bill workflows.
● Inventory opening quantities and valuation.
● E-invoice or fiscalisation transmission, response and exception handling.
Ask operational users to process normal work, then ask them to process exceptions. A credit controller should issue a credit note. A buyer should receive a partial supplier invoice. A cashier should resolve a failed bank match. The goal is to expose the point where the process stops, not to confirm that a clean invoice can be posted.
Capture every failure in a cutover issue log with an owner, decision and retest date. If a country integration has not passed its required test, do not go live in that entity. A partial rollout is preferable to issuing invoices that cannot support a customer VAT claim or your own tax reporting.
7. Execute cutover and protect the first month-end
Set a cutover date and define the final Zoho transaction date. Communicate it to sales, procurement, warehouse and finance teams so nobody creates transactions in both systems after the final extract.
Use this sequence:
14. Freeze agreed Zoho transactions and take final reports.
15. Reconcile the signed source position.
16. Load approved master data, opening journals and open items into Odoo.
17. Run post-load reconciliation reports.
18. Activate users and compliance integrations.
19. Process controlled live transactions.
20. Review daily exceptions until the first month-end close is complete.
Keep a small cutover command team available during the first reporting cycle. It should include Finance, IT, Operations and the Odoo implementation lead. Their role is to resolve exceptions using evidence, not to make unrecorded changes in production.
Frequently Asked Questions
Should we migrate all historical Zoho invoices into Odoo?
Usually, no. Retain an auditable, read-only Zoho archive and import controlled opening balances plus unpaid invoices and bills. Importing all history increases cleansing and testing effort, while closed documents rarely need operational processing in the new ERP.
Can we use one Odoo tax configuration for several African countries?
No. Configure each legal entity separately for its local chart of accounts, taxes, invoice sequences, currency, tax IDs and compliance connector. Zambia’s Smart Invoice, Zimbabwe’s FDMS, Kenya’s eTIMS and Nigeria’s Merchant-Buyer requirements are not interchangeable.
What is the most important Zoho data field to retain?
Retain the Zoho record ID as a stable Odoo External ID. It prevents duplicate imports and preserves relationships between customers, products and open transactions.
When should we go live after the sandbox test?
Go live only after the sandbox reconciliation matches signed Zoho reports, users have completed exception testing, and required tax or e-invoice integrations have passed their relevant tests. The calendar date should not override those controls.
A Zoho to Odoo migration should leave your group with cleaner data, a reconciled opening position and localised compliance controls that stand up to review. Request a Consultation with Serpa Africa to plan your migration to Odoo.