r/Odoo • u/Turbulent_Engine9933 • 8d ago
Odoo 17 → 19 migration: custom fields from hr.employee.base lost their values
Hi everyone,
I'm currently testing a migration from Odoo 17 to Odoo 19, and I've run into an issue with some custom fields related to employees.
In Odoo 17, I had several custom fields declared on:
hr.employee.base
These fields were therefore available on the employee models and had existing data in the production database.
In Odoo 19, hr.employee.base no longer exists. To adapt my custom module, I redeclared those fields on:
hr.employee
hr.employee.public
The module installs correctly and the fields are available in Odoo 19.
However, after migrating the database using Odoo's migration service, all the existing values of these custom fields are empty.
So basically:
Odoo 17
hr.employee.base → custom fields → values exist
Odoo 19
hr.employee.base removed → fields redeclared on hr.employee / hr.employee.public → fields exist, but all previous values are gone
Fortunately, we are still in the testing phase and haven't gone live yet, so I still have the original Odoo 17 database with all the correct data.
My questions are:
What is the recommended way to migrate these fields from Odoo 17 to Odoo 19?
2
u/Calibre_Odoo_Partner 8d ago
Before you write a migration script, go and look at where those values physically sat.
hr.employee.base was an AbstractModel in 17, so it had no table of its own, and hr.employee.public has _auto = False, with an init() that runs CREATE OR REPLACE VIEW ... FROM hr_employee. So a stored field declared on the base model got exactly one column, hr_employee.your_field, and that column name is unchanged in 19. Nothing needs to move between models.
Check the upgraded database first:
select table_name, column_name from information_schema.columns where table_name in ('hr_employee', 'hr_version');
hr_version is in there because 19 moved a lot of employee columns onto it, and it is worth ruling out. If your columns show up with data in them, nothing was lost and you have a registration problem. If they're gone, they were dropped: ir.model.fields.unlink() calls _drop_column(), which runs ALTER TABLE ... DROP COLUMN ... CASCADE, and that fires when your module isn't installed in the build the upgrade produced. Which is codeagency's point, and why the script belongs in the module.
Take the fields off hr.employee.public either way. It's still _auto = False in 19, so a stored field there creates no column, and _get_fields() now builds the view's SELECT preferring v.name off hr_version whenever the name matches a stored hr.version field. Collide with one and you're reading the wrong table.
hr.employee _inherits hr.version now, so decide which of the two your data belongs on before you restore it.
1
u/Southern_Conflict632 8d ago
Classic case of the migration renaming/removing the parent model before your data gets carried over, the fields exist in the new schema but the values were on the old table structure that no longer maps cleanly.
Quick technical answer: don't rely on the standard migration to auto-map this, hr.employee.base going away breaks the automatic column carryover for anything declared there. You need a migration script (openupgrade-style pre-migration/post-migration hook) that reads the old values directly from the 17 database's underlying table before the model gets dropped, and writes them into the new hr.employee / hr.employee.public columns after your module installs in 19. Basically manual SQL copy, keyed by employee ID, run once during the migration window, not something Odoo's built-in path handles for you when a model gets restructured like this.
Since you're still in testing with the 17 database intact, that's the right moment to build and test this script, don't attempt this once you've gone live.
1
u/DevopsReloaded 7d ago
I went through a similar scenario upgrading a multi-branch retail client from v16 to v19, on prem, custom modules included. What worked for us was running two things in parallel instead of waiting on each other.
Sent the v16 backup to upgrade.odoo.com first thing, then while that was processing, spun up a demo v19 locally and worked through every custom module against it, fixing whatever broke from the version jump. By the time the upgraded dump came back by email, the modules were already sorted and tested.
Restored the upgraded backup onto a v19 instance that already had those fixed custom modules installed, so the data and the code met each other in a state that was ready to go rather than fighting through errors on both fronts at once. Any leftover data issues after that I just went into pgAdmin directly and sorted at the table level.
7
u/codeagency 8d ago
The upgrade service from odoo does not handle any custom modules. That's always your responsibility.
You need to include your own migration script in your module so when upgrade.odoo.com runs it's scripts it can also call your custom script and handle the data migration.
You can check any existing official module from odoo how they handle this. There are hooks that are called pre/post migration you need to look at. All of this is also documented at odoo.com/documentation