[ADD] migration quality: explain ir_property and tracking values
ir_property never empties, it GROWS — 211 rows in 12, 457 in 17 — then vanishes in 18. Its fields are jsonb columns there, verified on res_partner.property_payment_term_id. mail_tracking_value is a REAL loss, not a rename: `field` goes from varchar to a foreign key in 14, and what would not resolve was deleted. 1528 of the 2336 belonged to the removed agile module; 706 more survived under a new name. New kind "pruned" so the report cannot call a living table retired. --- FR --- ir_property ne se vide jamais, elle GROSSIT — 211 lignes en 12, 457 en 17 — puis disparaît en 18. Ses champs y sont des colonnes jsonb, vérifié sur res_partner.property_payment_term_id. mail_tracking_value est une VRAIE perte, pas un renommage : `field` passe de varchar à clé étrangère en 14, et ce qui ne se résolvait pas a été supprimé. 1528 des 2336 venaient du module agile retiré ; 706 autres ont survécu sous un autre nom. Nouveau genre « pruned » pour que le rapport ne déclare pas retirée une table bien vivante. Assisted-by: Claude Opus 5
This commit is contained in:
parent
4103e13800
commit
d2f70f6535
3 changed files with 103 additions and 6 deletions
|
|
@ -471,6 +471,18 @@ SEMANTIC_MAP = (
|
|||
"kind": "retired",
|
||||
"why": "translations moved into jsonb columns",
|
||||
},
|
||||
# Vérifiée palier par palier : la table ne se vide jamais, elle GROSSIT
|
||||
# (211 en 12 → 457 en 17) puis disparaît d'un coup en 18. Les champs
|
||||
# qu'elle portait sont des colonnes jsonb en 18 — vérifié sur
|
||||
# res_partner.property_payment_term_id et
|
||||
# product_template.property_account_income_id.
|
||||
{
|
||||
"since": 18,
|
||||
"table": "ir_property",
|
||||
"into": None,
|
||||
"kind": "retired",
|
||||
"why": "company-dependent values moved into jsonb columns",
|
||||
},
|
||||
{
|
||||
"since": 17,
|
||||
"table": "account_tax_template",
|
||||
|
|
@ -537,6 +549,23 @@ SEMANTIC_MAP = (
|
|||
"kind": "merged",
|
||||
"why": "inventory adjustments became quants",
|
||||
},
|
||||
# Élagages : la table demeure, ces lignes non. À distinguer d'une
|
||||
# fusion — ici les enregistrements ne continuent NULLE PART.
|
||||
#
|
||||
# Vérifié : en 13 `field` est un varchar (le nom du champ), en 14 c'est
|
||||
# une clé étrangère vers ir_model_fields. En 14 aucune ligne n'a de
|
||||
# champ nul ni de clé cassée : ce qui ne se résolvait pas a été
|
||||
# supprimé. Sur les 2336 disparues, 1528 portaient des champs du module
|
||||
# agile retiré (priority_id 761, agile_enabled 711, story_points 54,
|
||||
# resolution_id 2) ; 706 autres ont SURVÉCU sous un nouveau nom
|
||||
# (account.move.type → move_type, 651).
|
||||
{
|
||||
"since": 14,
|
||||
"table": "mail_tracking_value",
|
||||
"into": None,
|
||||
"kind": "pruned",
|
||||
"why": "tracking of fields that ceased to exist",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -812,7 +841,7 @@ def render_compare(diff, colour, limit=8):
|
|||
if connues:
|
||||
lignes.append(
|
||||
f" {paint('▽', 'dim', colour)} {len(connues)}"
|
||||
f" {t('table(s) Odoo moved or retired')} :"
|
||||
f" {t('table(s) explained by an Odoo change')} :"
|
||||
)
|
||||
for table, avant, apres, connu in connues[:limit]:
|
||||
if connu["into"]:
|
||||
|
|
@ -826,6 +855,13 @@ def render_compare(diff, colour, limit=8):
|
|||
else paint(t("but it gained nothing"), "fail", colour)
|
||||
)
|
||||
ou = f"→ {connu['into']} ({accueil})"
|
||||
elif connu["kind"] == "pruned":
|
||||
# La table est TOUJOURS là : dire « retirée » serait
|
||||
# faux, et cette perte-ci est réelle — les lignes ne
|
||||
# continuent nulle part. Le mot doit le laisser voir.
|
||||
ou = paint(
|
||||
t("rows dropped, the table remains"), "warn", colour
|
||||
)
|
||||
else:
|
||||
ou = t("retired from the database")
|
||||
lignes.append(f" {table:<40} {avant:>8} → {apres} {ou}")
|
||||
|
|
|
|||
|
|
@ -5787,9 +5787,13 @@ TRANSLATIONS = {
|
|||
"fr": "table(s) ont perdu des lignes, sans explication",
|
||||
"en": "table(s) lost rows, unexplained",
|
||||
},
|
||||
"table(s) Odoo moved or retired": {
|
||||
"fr": "table(s) qu'Odoo a déplacées ou retirées",
|
||||
"en": "table(s) Odoo moved or retired",
|
||||
"table(s) explained by an Odoo change": {
|
||||
"fr": "table(s) expliquées par un changement d'Odoo",
|
||||
"en": "table(s) explained by an Odoo change",
|
||||
},
|
||||
"rows dropped, the table remains": {
|
||||
"fr": "lignes supprimées, la table demeure",
|
||||
"en": "rows dropped, the table remains",
|
||||
},
|
||||
"retired from the database": {
|
||||
"fr": "retirée de la base",
|
||||
|
|
|
|||
|
|
@ -331,7 +331,10 @@ class TestTheSemanticMap(Base):
|
|||
snapshot(odoo="18.0", table={}),
|
||||
)
|
||||
texte = "\n".join(quality.render_compare(diff, colour=False))
|
||||
self.assertLess(texte.index("unexplained"), texte.index("moved or"))
|
||||
self.assertLess(
|
||||
texte.index(todo_i18n.t("table(s) lost rows, unexplained")),
|
||||
texte.index(todo_i18n.t("table(s) explained by an Odoo change")),
|
||||
)
|
||||
|
||||
def test_needaction_became_notifications_in_15(self):
|
||||
"""Vérifiée palier par palier, pas déduite d'un nom qui se ressemble.
|
||||
|
|
@ -376,7 +379,61 @@ class TestTheSemanticMap(Base):
|
|||
for cle in ("since", "table", "into", "kind", "why"):
|
||||
self.assertIn(cle, entree, entree)
|
||||
self.assertTrue(entree["why"], entree)
|
||||
self.assertIn(entree["kind"], ("merged", "renamed", "retired"))
|
||||
self.assertIn(
|
||||
entree["kind"], ("merged", "renamed", "retired", "pruned")
|
||||
)
|
||||
|
||||
def test_a_pruned_entry_never_claims_a_destination(self):
|
||||
# « pruned » dit que les lignes ne continuent NULLE PART. Lui donner
|
||||
# un « into » ferait passer une perte réelle pour une fusion.
|
||||
for entree in quality.SEMANTIC_MAP:
|
||||
if entree["kind"] == "pruned":
|
||||
self.assertIsNone(entree["into"], entree)
|
||||
|
||||
def test_properties_became_jsonb_columns_in_18(self):
|
||||
"""La table ne se vide pas : elle GROSSIT, puis disparaît d'un coup.
|
||||
|
||||
211 lignes en 12, 457 en 17, table absente en 18. Les champs
|
||||
qu'elle portait sont des colonnes jsonb en 18 — vérifié sur
|
||||
res_partner.property_payment_term_id.
|
||||
"""
|
||||
diff = self.perte("ir_property", 457, 0, version="18.0")
|
||||
connu = diff["rows_lost"][0][3]
|
||||
self.assertIsNotNone(connu)
|
||||
self.assertEqual(connu["kind"], "retired")
|
||||
self.assertIsNone(connu["into"])
|
||||
|
||||
def test_properties_are_not_explained_at_the_17_bump(self):
|
||||
# En 17 la table est à son maximum (457). Dater l'entrée plus tôt
|
||||
# ferait passer pour attendue une perte qui ne l'est pas.
|
||||
diff = self.perte("ir_property", 273, 100, version="17.0")
|
||||
self.assertIsNone(diff["rows_lost"][0][3])
|
||||
|
||||
def test_tracking_values_were_pruned_in_14(self):
|
||||
"""Le champ suivi passe de varchar à clé étrangère au palier 14.
|
||||
|
||||
En 14 aucune ligne n'a de clé nulle ni cassée : ce qui ne se
|
||||
résolvait pas a été supprimé. La table SURVIT — 13833 lignes — donc
|
||||
l'explication ne doit pas prétendre qu'elle a disparu.
|
||||
"""
|
||||
diff = self.perte("mail_tracking_value", 16169, 13833, version="14.0")
|
||||
table, avant, apres, connu = diff["rows_lost"][0]
|
||||
self.assertEqual((avant, apres), (16169, 13833))
|
||||
self.assertIsNotNone(connu)
|
||||
self.assertEqual(connu["kind"], "pruned")
|
||||
|
||||
def test_tracking_values_are_not_explained_at_the_13_bump(self):
|
||||
# 16167 en 12, 16169 en 13 : rien n'a encore été élagué.
|
||||
diff = self.perte("mail_tracking_value", 16167, 10000, version="13.0")
|
||||
self.assertIsNone(diff["rows_lost"][0][3])
|
||||
|
||||
def test_a_pruned_loss_is_not_rendered_as_retired(self):
|
||||
# « retirée de la base » serait faux : la table est toujours là.
|
||||
diff = self.perte("mail_tracking_value", 16169, 13833, version="14.0")
|
||||
texte = "\n".join(quality.render_compare(diff, False, 8))
|
||||
self.assertIn("mail_tracking_value", texte)
|
||||
self.assertNotIn(todo_i18n.t("retired from the database"), texte)
|
||||
self.assertIn(todo_i18n.t("rows dropped, the table remains"), texte)
|
||||
|
||||
def test_the_column_counts_only_what_needs_an_answer(self):
|
||||
# Afficher 81 quand 14 sont des refontes voulues ferait fuir le
|
||||
|
|
|
|||
Loading…
Reference in a new issue