Odoo migration acceptance: reconcile records and balances

Back
Kevin Riedl

12 min read · 5 Nov 2026
Last reviewed

Next
Made on your device, with no Instagram connection. We copy the post link for Instagram’s Link sticker.

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.

Baseline details that make a comparison reproducible
BoundaryRecord before testingFalse conclusion to prevent
PopulationCompanies, object types, state filters and intentional exclusions.Archived or draft records disappear from only one side.
TimeSnapshot timestamp, reporting period and time-zone interpretation.A later transaction looks like a migration defect or masks a missing earlier one.
Money and quantityCurrency, amount basis, units and approved rounding rules.Different units or currencies are added into a misleading total.
IdentityStable source keys and their target-record mapping.Two similarly named customers are treated as the same account.
Expected changesApproved 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.00

The 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.

Executed synthetic reconciliation cases on 5 November 2026
Fixture changeHeadline controlsObserved detailed findings
Unchanged baselineFive rows; company/currency totals match.No differences under the fixture’s comparison rules.
Offsetting amount errorsCounts and totals still match.Two amount differences, EUR +10.00 and EUR -10.00.
Delivered quantity changes from 6 to 10Counts and amounts still match.One quantity difference.
Customer reference and that customer’s company changeCounts and amounts still match.Two relationship-field differences.
Attachment identity changesCounts and amounts still match.One content-identity difference.
Draft state changes to the fixture’s sale stateCounts and amounts still match.One state difference.
A source order reference is replacedCounts and amounts still match.One missing identity and one unexpected identity.
Two records share one composite keyCounts and amounts still match.Duplicate key, missing identity and six field differences.
Target snapshot uses a different cutoffComparison 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.py

The 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.

Proposed control matrix to adapt to your Odoo scope
AreaEvidence to compareWho approves the business result?
Customers and productsStable identity, required attributes and intended relationships.The owner of the customer or product data.
Open ordersHeader and line references, amounts, current state and remaining work.Sales or purchasing process owner.
Partial fulfillmentOrdered, fulfilled and outstanding quantities in their approved units.Warehouse or service-delivery owner.
Receivables and payablesFinance-defined balances by account, company, currency and period; document-level exceptions.Authorized finance owner.
InventoryQuantity controls separately from valuation evidence, including relevant location or lot dimensions.Inventory owner, with finance approval for valuation.
Invoices and creditsDocument identity, state, amounts and the approved relation to settlement or corrections.Authorized finance owner.
AttachmentsCorrect document attached to the correct record and retrievable by the intended role.The process owner who depends on the document.
Access and integrationsPermitted 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.

How the CSV separates evidence from approval
Field groupWhat you enterRule
BaselineSnapshot, filters, company/currency scope and target build.Different populations require a documented adjustment before comparison.
ControlComparison method, expected value, unit and tolerance.Approve tolerances before looking at the result.
ExecutionActual value, variance, evidence reference and execution status.NOT_RUN stays distinct from a passed comparison.
ResolutionDefect, retest evidence and technical owner.A repaired import requires a new comparison of affected records.
ApprovalBusiness 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.

Odoo migration acceptance FAQ

Is an Odoo version upgrade the same acceptance task as importing another ERP’s history?
Both need evidence of the agreed target business outcome, but their transfer rules differ. An external-system import may split records, map identifiers or leave approved history in an archive. An Odoo upgrade may change views or custom-module behavior. State which path you are testing, then define the expected differences instead of assuming every source field must remain identical.
Can record counts approve opening balances?
No. Counts say how many records meet a filter; they do not establish their amounts, accounting basis or relationships. The finance owner must define the relevant accounts, currencies, periods and document states, inspect the reconciliation evidence and approve any adjustments. Keep that approval separate from the engineer’s record-count result and from a successful import message.
Must every monetary difference be zero?
Define the required precision and approved transformations before execution. Some comparisons should be exact; others may need an explicitly justified tolerance or reconciliation adjustment. Retain each variance and its reason. Do not net opposite document errors into a zero aggregate or invent a tolerance after seeing a failed result. The responsible business owner must accept the policy.
How should history intentionally left in an archive be handled?
Record the excluded population and the reason it remains outside the operational database. Establish who can retrieve it and how its documents connect to the records that moved. Test that retrieval with the intended roles. The migration acceptance record should preserve the approved history plan; it should not silently decide legal retention requirements or remove access to needed records.
How do you compare an attachment that was deliberately regenerated?
Choose the approved identity rule before comparing files. An unchanged original can be checked by content identity, while a regenerated document may need a semantic comparison of the required fields and its record association. Record the transformation and expected differences. A different byte hash alone does not establish corruption when regeneration was part of the approved scope.
Can the template be approved while checks remain NOT_RUN?
NOT_RUN means no execution evidence has been recorded for that check. It cannot be treated as a successful comparison. If the release policy permits a specific exception, retain the authorized decision and its consequence separately. Do not change the execution result to PASS merely because the project needs a signature or a planned release date.
Does the runnable fixture validate my Odoo database?
No. The fixture compares its own synthetic JSON records and reproduces nine named comparison cases. It does not connect to your database, inspect accounting reports or exercise real permissions and workflows. Use it to challenge your acceptance design, then adapt the proposed CSV and run the required checks on the actual source snapshot and target build.

Build the product, not just the backlog

If this article maps to a real product decision, Wavect can help you scope, build, harden, or lead the software work with senior founder-level judgment.

Useful service paths:

Inbox, without the noise

Follow the work that matters to you

Get a short email when we publish something new. Follow the whole blog or only the problems you care about.

What would you like to receive?
Choose your topics

Free, double opt-in, no tracking pixels.

Back
Kevin Riedl

12 min read · 5 Nov 2026
Last reviewed

Next

Get the next Delivery and QA field note

One concise email when we publish. No tracking pixels, and no inbox filler.

Free, double opt-in, no tracking pixels.