erplibre/script/odoo/migration/fix_migration_odoo170_to_odoo180.sql
Mathieu Benoit d2832f5c60 [FIX] migration 17→18 : retirer la vue morte account_root
Odoo 17 créait une vue SQL pour account.root ; en 18 le modèle porte
_auto = False et _table_query = '0' : son nom n'entre plus dans aucune
requête, et le contrôle des tables manquantes ignore ces modèles.

Elle n'est pas seulement morte, elle est FAUSSE : bâtie sur la colonne code que
l'ORM 18 n'écrit plus, elle rend trop peu de racines. Elle est aussi l'unique
épingle des deux colonnes héritées où database_cleanup échoue, d'où ce retrait
avant le chargement en 18 ; aucun DROP COLUMN, OpenUpgrade les lit encore.

Sur base jetable, l'ordre est rejouable et laisse intactes une vue d'une
autre forme, une vue dont dépend un objet, une table homonyme.

--- EN ---

Odoo 17 created a SQL view for account.root; in 18 the model carries
_auto = False and _table_query = '0': its name no longer enters any query,
and the missing-table check ignores such models.

It is not merely dead, it is WRONG: built on the code column the 18 ORM no
longer writes, it returns too few roots. It is also the sole pin holding the
two legacy columns database_cleanup fails on, hence its removal before the
load into 18; no DROP COLUMN, OpenUpgrade still reads them afterwards.

On a throwaway database the statement replays cleanly and leaves alone a
view of another shape, a view something depends on, a table of that name.

Assisted-by: Claude Opus 5
(cherry picked from commit b50e2308cbdd1efdfa914497062919eab1bbd329)
2026-08-29 02:11:04 -04:00

118 lines
4.8 KiB
SQL

-- © 2021-2026 TechnoLibre (http://www.technolibre.ca)
-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
--
-- Correctifs à appliquer AVANT qu'OpenUpgrade ne migre vers Odoo 18.
--
-- En SQL et non en Python : ce fichier tourne sur une base encore en
-- 17, que le code de la 18 ne saurait pas charger.
-- forum_tag_rel : la colonne qui pointe vers forum.post s'appelait
-- `forum_id` — un nom trompeur, elle ne désignait pas un forum. La 18 la
-- nomme `forum_post_id`.
--
-- OpenUpgrade le DÉCLARE dans son analyse :
-- website_forum / forum.post / tag_ids (many2many)
-- : column1 is now 'forum_post_id' ('forum_id') [forum_tag_rel]
-- mais `website_forum/18.0.1.2/` ne contient aucun script : rien ne
-- l'applique. Le chargement casse alors sur
-- column "forum_post_id" referenced in foreign key constraint does not exist
-- et la base reste à moitié migrée.
--
-- Les deux conditions rendent l'ordre rejouable : rien à faire si la
-- table n'existe pas (website_forum non installé) ni si le renommage a
-- déjà eu lieu.
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'forum_tag_rel' AND column_name = 'forum_id'
) AND NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'forum_tag_rel' AND column_name = 'forum_post_id'
) THEN
ALTER TABLE forum_tag_rel RENAME COLUMN forum_id TO forum_post_id;
RAISE NOTICE 'forum_tag_rel.forum_id renommee en forum_post_id';
END IF;
END $$;
-- account_root : une VUE SQL qu'Odoo 17 créait pour le modèle
-- `account.root` (son init() bâtissait la vue sur account_account.code),
-- et que la 18 a orphelinée sans la retirer. En 18 le modèle porte
-- `_auto = False` et `_table_query = '0'` : son nom n'entre plus dans
-- aucune requête, et registry.py exclut ces modèles du contrôle des
-- tables manquantes — Odoo ne la recréera donc jamais.
--
-- Elle n'est pas seulement morte, elle est FAUSSE : bâtie sur la colonne
-- `code` que l'ORM 18 n'écrit plus, elle rendait 14 racines là où la
-- donnée vivante (code_store) en portait 31. Un objet du schéma public
-- qui répond faux, sans avertir, à qui l'interroge à la main ou par un
-- outil décisionnel.
--
-- Elle est AUSSI l'unique épingle de deux colonnes héritées :
-- database_cleanup a purgé 110 colonnes orphelines au palier 18 et n'a
-- échoué que sur account_account.code et .company_id, dont elle dépend.
-- On retire donc l'obstacle ICI, et l'outil déjà en place finit sa passe
-- APRÈS le chargement en 18.
--
-- On ne supprime SURTOUT PAS les colonnes ici : le post-migration
-- d'OpenUpgrade les lit encore pour remplir code_store et company_ids,
-- et il tourne après ce fichier.
DO $$
DECLARE
oid_vue oid;
oid_table oid;
nb_dependants int;
BEGIN
SELECT c.oid INTO oid_vue
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public'
AND c.relname = 'account_root'
AND c.relkind = 'v';
IF oid_vue IS NULL THEN
-- Ni vue, ni base sans le module account : rien à faire. C'est
-- aussi ce qui rend l'ordre rejouable après un premier passage.
RETURN;
END IF;
oid_table := to_regclass('public.account_account');
IF oid_table IS NULL THEN
RAISE NOTICE 'account_root sans account_account : laissee en place';
RETURN;
END IF;
-- La vue morte est CELLE QUI LIT account_account.code. Le contrôle
-- est structurel et non textuel : si une version future d'Odoo
-- recree un account_root d'une autre forme, on n'y touche pas.
IF NOT EXISTS (
SELECT 1
FROM pg_depend d
JOIN pg_rewrite r ON r.oid = d.objid
JOIN pg_attribute a ON a.attrelid = d.refobjid
AND a.attnum = d.refobjsubid
WHERE r.ev_class = oid_vue
AND d.refobjid = oid_table
AND a.attname = 'code'
) THEN
RAISE NOTICE 'account_root ne lit pas account_account.code : laissee en place';
RETURN;
END IF;
-- Rien ne doit en dependre. Le jour ou quelque chose en dependrait,
-- APPRENDRE plutot que detruire : on le dit et on passe. Jamais de
-- CASCADE, et jamais d echec — ce fichier tourne sous ON_ERROR_STOP.
SELECT count(DISTINCT ev.oid) INTO nb_dependants
FROM pg_depend d
JOIN pg_rewrite r ON r.oid = d.objid
JOIN pg_class ev ON ev.oid = r.ev_class
WHERE d.refobjid = oid_vue
AND ev.oid <> oid_vue;
IF nb_dependants > 0 THEN
RAISE NOTICE 'account_root : % objet(s) en dependent, laissee en place',
nb_dependants;
RETURN;
END IF;
DROP VIEW public.account_root;
RAISE NOTICE 'vue morte account_root supprimee (Odoo 18 ne la recree pas)';
END $$;