Skip to content

Version migration

SECII

Moving a fleet of twenty-two custom modules from Odoo 16 to Odoo 19 — three major versions, APIs removed along the way, and a business role that had to be rescued from uninstallation.

Sector
Version migration
Scope
22 → 30 modules · 14 users
Duration
About 4 months
Role
Porting the custom modules and writing the data migration scripts
Odoo version
Odoo 16 → Odoo 19 (Enterprise)

The problem

An Odoo migration is not an update. Between version 16 and version 19, Odoo removed whole sections of its programming interface: the conditional syntax in views, the tag that declared a list, the method that gave a record its display name, the old JavaScript framework. A module that uses them does not degrade — it fails to load.

SECII's fleet held twenty-two custom modules, and one hundred and five occurrences of those vanished syntaxes in the view files alone. The most critical module — a salesperson filter on the general ledger and the aged balance — rested both on the old JavaScript framework and on a copy of the accounting report engine, long since out of sync with the standard.

And a trap waited further along: the "Salesperson" business role, with its group, its twenty-two access rules and its three record rules, belonged to a module due to be replaced. Uninstalling it would have erased the role by cascade, and with it an entire team's permissions.

The approach

The work started with a written audit before the first line of code: one sheet per module — what it does, what it contains, what breaks on v19, and a verdict. Migrate, rewrite, or drop. Out of that inventory came a five-layer running order, dictated by the dependencies between modules: the foundation first, reporting next, the modules depending on it after that, and the most tangled one last.

The first phase was deliberately conservative: one-for-one porting, no merging. A migration that refactors while it migrates leaves you unable to tell what broke. The consolidations spotted during the audit were recorded as deferred decisions, not carried out along the way.

Every module was installed on a throwaway database before going further — never on production, nor on its acceptance copy.

The solution

Twenty-two v16 modules became thirty on v19.

Nineteen kept their name and were adapted: removed view syntaxes fixed down to the last occurrence, deleted methods replaced, the salesperson filter's JavaScript widget rewritten in the modern framework.

Three were replaced by redesigned modules — electronic tax certification, expense tracking split in two, and above all the access rights module. The originals are kept unchanged in a holding folder rather than deleted.

Seven are entirely new: inter-company accounting mirror, partner dissociation, company selection shortcuts, out-of-stock sale blocking, price threshold, purchase down-payment link.

The data migration scripts are the invisible and most delicate part. The one that rescues the "Salesperson" role detaches the group and its rules from their originating module in direct SQL, outside the ORM, before that module is uninstalled — so they survive the deletion cascade. The role is then kept as-is rather than rebuilt in the new engine: remapping it would have handed administration rights over the tool to salespeople. A second script renames the tax certification module's technical identity and copies its per-company settings across, with credentials neutralised whenever production is cloned to acceptance.

The new rights engine is the project's functional gain. Where the old one defined a single role in static XML, the new one grants exceptions per user across five axes — the record, the field, the tab, the view and the button — each scopable to a company, and every change logged on the user's own record.

The result

The one hundred and five occurrences of removed syntax dropped to zero. The obsolete naming method is gone from the fleet. The JavaScript widget of the most at-risk module runs in the modern framework. The business role survived the replacement of its originating module, with no manual reassignment of permissions.

Along the way, the fleet's hygiene improved markedly: the licence, declared in four manifests out of ten on v16, is declared in nine out of ten on v19, and version numbers finally follow one convention. The v19 repository depends on no third-party module.

Stack

Odoo
Odoo 16 → Odoo 19 (Enterprise)
Modules
AccountingSalesPurchaseInventoryContactsHR
Tech
PythonSQLOWLJavaScript
Protocoles
REST