diff --git a/script/odoo/migration/fix_migration_odoo130_to_odoo140.sql b/script/odoo/migration/fix_migration_odoo130_to_odoo140.sql new file mode 100644 index 0000000..cde9856 --- /dev/null +++ b/script/odoo/migration/fix_migration_odoo130_to_odoo140.sql @@ -0,0 +1,39 @@ +-- © 2021-2026 TechnoLibre (http://www.technolibre.ca) +-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +-- +-- Odoo 13.0 -> 14.0 : hand the « group_fiscal_year » security group over to +-- the module that owns it in 14.0. +-- +-- In 13.0 the group « Allow to define fiscal years of more or less than a +-- year » is declared by the core « account » module, so the database holds it +-- as account.group_fiscal_year. In 14.0 core account no longer declares it and +-- om_account_accountant (odoomates) does. During the upgrade that module finds +-- no XML id of its own, tries to CREATE the group, and hits: +-- +-- duplicate key value violates unique constraint "res_groups_name_uniq" +-- Key (category_id, name)=(9, Allow to define fiscal years ...) already exists +-- +-- Renaming the XML id makes Odoo UPDATE the existing row instead of creating a +-- duplicate. The record id is untouched, so any user assignment, access right +-- or record rule pointing at the group survives. +-- +-- Runs through psql, not the Odoo shell: at this point the database is still +-- 13.0 and loading it with the 14.0 registry is exactly what fails. + +UPDATE ir_model_data + SET module = 'om_account_accountant' + WHERE model = 'res.groups' + AND module = 'account' + AND name = 'group_fiscal_year' + -- Only when that module is actually part of this database. + AND EXISTS ( + SELECT 1 FROM ir_module_module + WHERE name = 'om_account_accountant' + AND state IN ('installed', 'to upgrade', 'to install') + ) + -- Idempotent: do nothing if the target XML id already exists. + AND NOT EXISTS ( + SELECT 1 FROM ir_model_data + WHERE module = 'om_account_accountant' + AND name = 'group_fiscal_year' + ); diff --git a/script/todo/todo_upgrade.py b/script/todo/todo_upgrade.py index b351903..cded711 100755 --- a/script/todo/todo_upgrade.py +++ b/script/todo/todo_upgrade.py @@ -1622,15 +1622,33 @@ class TodoUpgrade: if not lst_fix_migration_odoo[index]: print("") - file_path_fix_migration = os.path.join( - "script", - "odoo", - "migration", - f"fix_migration_odoo{(next_version-1)*10}_to_odoo{next_version*10}.py", + stem = os.path.join( + PATH_MIGRATION_GLOBAL, + f"fix_migration_odoo{(next_version - 1) * 10}" + f"_to_odoo{next_version * 10}", ) - if os.path.exists(file_path_fix_migration): + # Two flavours. « .sql » runs through psql: no Odoo registry, + # so it works on a database not yet migrated -- exactly when + # loading it with the TARGET version's code would fail. « .py » + # is piped into the Odoo shell when the ORM is really needed. + file_path_fix_migration = "" + cmd_fix_migration = "" + if os.path.exists(f"{stem}.sql"): + file_path_fix_migration = f"{stem}.sql" + cmd_fix_migration = ( + f"psql -v ON_ERROR_STOP=1 -d {database_name_upgrade}" + f" -f ./{file_path_fix_migration}" + ) + elif os.path.exists(f"{stem}.py"): + file_path_fix_migration = f"{stem}.py" + cmd_fix_migration = ( + f"cat ./{file_path_fix_migration} |" + f" ./odoo{next_version}.0/odoo/odoo-bin shell" + f" -d {database_name_upgrade}" + ) + if file_path_fix_migration: status, cmd_executed = self.todo_upgrade_execute( - f"cat ./{file_path_fix_migration} | ./odoo{next_version}.0/odoo/odoo-bin shell -d {database_name_upgrade}", + cmd_fix_migration, single_source_odoo=True, )