This is an illustrative project pattern — a composite scenario built from how legacy-version migrations actually go wrong, and how we structure them so they don’t. It is not a named client and no figures below are attributed to a real engagement. It exists to show the shape of the work and the standard we hold ourselves to.
The pattern this represents: a distribution business running a heavily customised Odoo install several major versions back — old enough that the legacy surcharge has kicked in, new enough that nobody wants to touch it in case it breaks.
Community edition, several major releases behind current. OCA module support for that version has already lapsed, so security patches have effectively stopped.
A bespoke tiered-discount engine on the sales order, built years ago by a since-departed freelancer. Nobody left in-house can read the code, let alone port it.
Full accounting history — invoices, credit notes, reconciled bank statements — sitting in that database. A botched migration doesn’t just break a feature, it breaks an audit trail.
A courier API for shipment tracking and a bank-feed connector, both wired against internal APIs that shift meaningfully between major Odoo versions.
Orders come in on weekdays, warehouse picks run daily. A migration that takes production offline mid-week isn’t survivable — it has to happen in a window nobody notices.
A previous in-place upgrade attempt (done without staging) had already corrupted a batch of stock moves. The business wanted proof of reversibility before agreeing to try again.
The same five-step shape we use on every version jump — the only variable is how many version increments it takes to get there.
Every custom module and every third-party dependency checked line-by-line against the target version’s API. The tiered-discount engine gets flagged early — that’s the module most likely to need a rewrite, not a port.
Target version stood up on its own server, restored from a production snapshot, modules installed alongside it. Production keeps running untouched while staging gets built and tested in the background.
Every table in staging reconciled against production — invoice counts, ledger balances, stock quantities, partner records. Anything that doesn’t match gets investigated and resolved before anyone signs off on a cutover date.
Production frozen Friday evening, final data sync run, DNS/routing flipped to the new instance, smoke tests run against real workflows — sales order, invoice, stock move, bank reconciliation — before Monday users ever log in. A tested rollback path sits ready the whole time.
Real usage always surfaces something staging didn’t — an edge case in the discount engine, a courier webhook retry that behaves differently. Bug-watch included for a month so those get fixed fast, not queued.
Where the old code still expresses the business logic correctly, we repackage it for the new API rather than rewriting the business rules from scratch — the discount tiers stay the discount tiers, they just run on current Odoo.
The audit tells you exactly what migrates clean and what needs rework — before you commit to a date or a quote. Fixed scope, tested rollback, no in-place gamble.