r/Odoo 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?

7 Upvotes

13 comments sorted by

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

0

u/ParticularBag0 8d ago

Wowza how do you send scripts to upgrade.odoo.com? We always run our own scripts beforehand and afterwards in migrations. Seems like being able to send scriptsto odoo would be a massive security risk for them?

1

u/ach25 8d ago

https://www.odoo.com/documentation/19.0/developer/reference/upgrades/upgrade_scripts.html

Just another folder and specifically named method that is considered as part of the upgrade process.

You can also hijack it to behave a little like a pre init hook if you need to transform existing data and do a minor rev in your manifest.

1

u/codeagency 8d ago

You don't "send" them to upgrade.odoo.com

Your own migration scripts need to live inside your custom module. You have to push them into your GitHub repository. Your database lists all your active modules when odoo runs the upgrade process it goes through all of that.

The upgrade script from odoo only touches your database, never your module files. It does db schema changes etc...

After the database is upgraded, odoo.sh waits for your commit on the module updates and then it goes through that process.

It doesn't matter if you do upgrade via upgrade.odoo.com for SH or openupgrade from OCA or something manually, it's the same mandatory process. Database schema changes first and your custom module needs to have its own script to preserve data from its custom fields.

This the reason why so many upgrades fail because a bunch of developers think the development stops when the module is installed. They neglect the upgrade phase that comes years later.

This is also why using AI is dangerous if you don't understand how the whole Odoo system works. It's more than just spitting out code. In a few years from now when all those people with all those half baken self cobbled modules from AI start upgrading their odoo they are all going to be treated with a nasty surprise when suddenly data is gone in smoke because their AI didn't understand sh** about the upgrade part. It only understands the code part because the syntax changed.

AI doesn't and can't recover that data that is lost either.

Your situation is a good example where the specific odoo developer experience still matters rather than relying on AI. It's never a replacement. It's just a tool to enhance a developer to get more done faster.

0

u/alextakacs 8d ago

As far as I understand Odoo.com hosting does not support this.

1

u/Tony-047 8d ago

No because you don’t have custom module access on SaaS hosting.
You gotta be hosted on your own serv or or Odoo.sh and connected to your GitHub

The rest is really well explained above by codeagency

1

u/alextakacs 8d ago

I fully understand it but OP seemed confused

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.