In this piece
Odoo migration acceptance: reconcile records and balances
Five source orders become five target orders. The company totals match. In our local fixture, two of those orders still have the wrong amount. A migration can pass its headline controls while leaving the people who use the records with an incorrect result.
Accept an Odoo migration by comparing an agreed source snapshot with the intended target records, then running the business flows that depend on them. Check identity and relationships alongside amounts and states. Record each difference with its owner and retest evidence, and obtain the appropriate business approvals before treating the migration as complete.
Research checked: 5 November 2026. Product facts use official Odoo documentation sources. We executed nine synthetic JSON reconciliation cases with Python’s standard library. We did not migrate an Odoo database, inspect customer records or validate accounting reports. The downloadable acceptance CSV contains proposed checks with NOT_RUN status.
What does a successful Odoo migration have to prove?
A successful Odoo migration must produce the business records and operating behavior agreed for its scope. A database that starts or an import that reports success establishes only part of that evidence. Define who must be able to complete each required workflow, what records should result, and which historical information must remain retrievable.
First name the transfer. An upgrade from one Odoo version to another differs from importing another ERP’s history. The latter may require new mappings and deliberate exclusions; an upgrade may change application behavior or custom-module compatibility. Use an acceptance record that states the actual path instead of treating “migration” as one universal procedure.
Odoo’s upgrade guidance recommends testing the upgraded database across business flows and external integrations before moving production. Convert that requirement into evidence for your own operation: a partially fulfilled order needs a different check from a newly entered contact.
Separate technical execution from business approval. An engineer can establish that the tested comparison found no differences under its rules. The finance owner still decides whether the selected balance controls and documented adjustments support the accounting outcome. A warehouse owner must assess whether the remaining quantities represent work the team can complete.
Which baseline must you freeze before comparing data?
Freeze the source snapshot and comparison scope before calculating differences. Record the included companies, document states and reporting cutoff, together with the transformation rules approved for the target. Without those boundaries, a mismatch may describe different populations, while an apparent match may hide a filter that excluded the records you needed to inspect.
Keep the original exports or other approved source evidence alongside their extraction parameters. Preserve the target build identity and mapping revision. If source transactions continue after the snapshot, define how the final delta enters the cutover and how its results will be reconciled. Yesterday’s accepted export does not cover today’s receipts automatically.
| Boundary | Record before testing | False conclusion to prevent |
|---|---|---|
| Population | Companies, object types, state filters and intentional exclusions. | Archived or draft records disappear from only one side. |
| Time | Snapshot timestamp, reporting period and time-zone interpretation. | A later transaction looks like a migration defect or masks a missing earlier one. |
| Money and quantity | Currency, amount basis, units and approved rounding rules. | Different units or currencies are added into a misleading total. |
| Identity | Stable source keys and their target-record mapping. | Two similarly named customers are treated as the same account. |
| Expected changes | Approved transformations and the person who authorized them. | An unexplained difference is reclassified as intentional after the test fails. |
Retain a stable business reference even if target database IDs change. Odoo documents external IDs for rebuilding imported relationships. Your reconciliation should show which source record became which target record, including any approved split or merge.
Keep the checking logic independent of the transformation being checked. Reusing the import’s mistaken unit conversion in the expected-value calculation can make both sides agree. Derive a few reference cases directly from the approved business rule or original document, then compare them with the imported result.
Why can matching counts and totals still hide errors?
Matching counts and totals can hide errors because aggregate controls discard record identity. One missing record can be replaced by an unintended one, or opposite amount errors can cancel. Our executed fixture preserves five records and all company/currency totals while two order amounts differ. Keep aggregate controls, then compare the individual records that contribute to them.
The fixture contains orders for companies A and B, with EUR and USD amounts kept in separate groups. Company A’s two EUR orders should be EUR 100.00 and EUR 200.00. The faulty target holds EUR 110.00 and EUR 190.00:
Source company A / EUR: 100.00 + 200.00 = 300.00
Target company A / EUR: 110.00 + 190.00 = 300.00
Record differences: +10.00 and -10.00The zero aggregate variance does not approve either document. These are synthetic order-amount controls, not a trial balance. We used exact decimal comparisons under an illustrative zero-tolerance policy; no tax, exchange-rate or valuation calculation ran.
| Fixture change | Headline controls | Observed detailed findings |
|---|---|---|
| Unchanged baseline | Five rows; company/currency totals match. | No differences under the fixture’s comparison rules. |
| Offsetting amount errors | Counts and totals still match. | Two amount differences, EUR +10.00 and EUR -10.00. |
| Delivered quantity changes from 6 to 10 | Counts and amounts still match. | One quantity difference. |
| Customer reference and that customer’s company change | Counts and amounts still match. | Two relationship-field differences. |
| Attachment identity changes | Counts and amounts still match. | One content-identity difference. |
| Draft state changes to the fixture’s sale state | Counts and amounts still match. | One state difference. |
| A source order reference is replaced | Counts and amounts still match. | One missing identity and one unexpected identity. |
| Two records share one composite key | Counts and amounts still match. | Duplicate key, missing identity and six field differences. |
| Target snapshot uses a different cutoff | Comparison is rejected before totals are accepted. | Scope mismatch. |
All nine expected observations matched the local run. Download the runnable reconciliation model and recorded fixture results. Run the saved Python file with:
python3 reconcile-model.pyThe model compares named fields in JSON records. It does not exercise Odoo’s sales lines, journal entries or attachment storage. Its attachment values are identity labels standing in for verified content checks. The unchanged control case proves only that the comparator accepts its own specified baseline.
Which business records should the reconciliation cover?
Reconcile the records that carry the operating commitments in your migration scope. Check their identities and relationships before relying on sums. Then inspect amounts, remaining quantities and states under the appropriate company and currency. Add evidence that documents remain accessible and that the people who need them can continue the agreed work.
| Area | Evidence to compare | Who approves the business result? |
|---|---|---|
| Customers and products | Stable identity, required attributes and intended relationships. | The owner of the customer or product data. |
| Open orders | Header and line references, amounts, current state and remaining work. | Sales or purchasing process owner. |
| Partial fulfillment | Ordered, fulfilled and outstanding quantities in their approved units. | Warehouse or service-delivery owner. |
| Receivables and payables | Finance-defined balances by account, company, currency and period; document-level exceptions. | Authorized finance owner. |
| Inventory | Quantity controls separately from valuation evidence, including relevant location or lot dimensions. | Inventory owner, with finance approval for valuation. |
| Invoices and credits | Document identity, state, amounts and the approved relation to settlement or corrections. | Authorized finance owner. |
| Attachments | Correct document attached to the correct record and retrievable by the intended role. | The process owner who depends on the document. |
| Access and integrations | Permitted and denied operations, plus the final records after a controlled transfer. | Application owner and integration owner. |
A finance control needs an agreed accounting basis. Do not add currencies together, substitute invoice counts for balances, or assume that importing a draft document has posted an entry. Separate the technical comparison from the accounting review and retain the reports and adjustments the finance owner accepted.
For partial orders, inspect the remaining obligation. Ten ordered and six delivered leaves four to fulfill under the fixture’s simple rule. A migrated header showing ten delivered can remove that work from an operator’s queue even when the order amount is unchanged.
For permissions, use the separate Odoo 20 company-access test matrix. For the mapping that produced the target data, use independent validation of AI-assisted Odoo mappings. This acceptance record should link their evidence rather than compress every specialist check into one percentage.
What belongs in the migration acceptance CSV?
The migration acceptance CSV should connect each expected result to an observed result and its evidence, then record the responsible review separately. Include the baseline scope and target build so a later reader can reproduce the comparison. Keep unresolved differences visible with a defect reference and retest status; an empty actual value must never mean zero variance.
Download the proposed migration acceptance template. Its operational baselines start as TO_DEFINE, actual values remain empty, execution is NOT_RUN, and approval is PENDING. It contains no implied finance approval or live migration result.
| Field group | What you enter | Rule |
|---|---|---|
| Baseline | Snapshot, filters, company/currency scope and target build. | Different populations require a documented adjustment before comparison. |
| Control | Comparison method, expected value, unit and tolerance. | Approve tolerances before looking at the result. |
| Execution | Actual value, variance, evidence reference and execution status. | NOT_RUN stays distinct from a passed comparison. |
| Resolution | Defect, retest evidence and technical owner. | A repaired import requires a new comparison of affected records. |
| Approval | Business owner, approval decision and date. | A technical pass cannot fill the approver’s name automatically. |
For the fixture’s company A/EUR amount control, expected and actual both equal 300.00. That row can report a matching aggregate. The two document comparisons still fail and remain linked defects. Do not overwrite their variances with the aggregate zero.
When a transformation is intentional, record its expected effect and the authority behind it. “Accepted difference” should point to an approved rule or exception. It should not become a way to close a comparison that no one can explain.
How do you test the migrated workflow, not only its exports?
Test a migrated workflow by starting from a known transferred record, acting under its intended role, and inspecting the resulting business records. Use a protected environment with controlled external services. Include an exception the operators need to handle. Export comparisons establish stored values; a rehearsal establishes whether the team can continue the work under the new configuration.
For a partial order, locate the transferred record and its supporting document. Confirm that the authorized operator sees the expected outstanding quantity. Perform the agreed next step in the protected environment, then compare the new record and remaining obligation with the expected result. Retain the denied case for a role that must not perform that action.
Odoo’s neutralization documentation lists automatic and external features disabled in test databases. Check custom integration workers separately. A rehearsal needs controlled destinations even when the database is marked for testing.
The custom-upgrade process separates empty-database module checks from upgraded-data testing and rehearsal. Keep those evidence types distinct. A module that installs on an empty database has not demonstrated the treatment of your historical partial orders.
If the transfer depends on files instead of an API, the legacy ERP integration guide covers the delivery boundary. Include the actual import and its recovery path in the rehearsal, with a reference that connects the source file to the resulting target records.
How should late changes and unresolved differences affect release?
Bind release approval to the build and data scope that were tested. A late mapping change or a new source delta can invalidate part of the evidence. Identify the affected controls and rerun them before release. Keep unresolved differences with a named decision owner; their impact, not their age or ticket status, determines whether they block cutover.
Define the final delta procedure before the rehearsal. State when the baseline stops, who controls further source writes, and how changes after that point are identified. A final comparison should account for those changes explicitly rather than treating every new target record as unexplained.
For each remaining defect, record the affected process and possible business consequence. An authorized owner can decide whether an exception is acceptable under the agreed release policy. Retain the decision and its conditions. A general “looks good” message leaves the operator unable to tell whether a missing attachment or an incorrect remaining delivery was accepted knowingly.
After cutover, repeat the agreed controls against the production result and observe the next relevant operating step. A scheduled import or later fulfillment may expose a problem that an immediate login check cannot. The software release QA checklist provides the wider release-evidence framework.
What would we require before signing off?
We would require a trace from an agreed baseline through detailed comparison and workflow evidence to the appropriate business approvals. Begin with one critical process and expose every unresolved difference. Expand that method across the approved scope. A signed acceptance record should tell the next operator what was proved, on which build, and under which remaining conditions.
Wavect’s software quality assurance service is the commercial route for independent acceptance work. Bring the migration scope and one disputed result. The first useful review is whether the evidence can distinguish a correct business outcome from a migration that merely completed without an error.
