Settings saved via set_param() have no ir_model_data; the noupdate config XML then collides on UNIQUE(key) during -u. Pre-migrate links existing params to their XML external id (value-preserving) so upgrades are robust. Found on the Entech clone-verify; affects prod (35 params vs 32 xmlids). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
#
|
|
# Defensive pre-migration: re-link orphaned fusion_clock config-parameter
|
|
# external IDs.
|
|
#
|
|
# Booleans/floats saved through the Settings UI go in via set_param(), which
|
|
# creates the ir_config_parameter row WITHOUT an ir_model_data external id. If a
|
|
# param later also appears in the noupdate data/ir_config_parameter_data.xml,
|
|
# a plain `-u` can't match it by external id, treats it as new, and the INSERT
|
|
# trips the UNIQUE(key) constraint -> "Failed to load registry".
|
|
#
|
|
# This runs BEFORE the data files load: for every config record in the XML whose
|
|
# param already exists but whose external id is missing, we create the external
|
|
# id pointing at the existing param. The noupdate load then matches + skips it,
|
|
# so the existing (possibly customised) value is preserved.
|
|
|
|
import logging
|
|
import os
|
|
|
|
from lxml import etree
|
|
|
|
from odoo.modules.module import get_module_path
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def migrate(cr, version):
|
|
module_path = get_module_path('fusion_clock')
|
|
if not module_path:
|
|
return
|
|
xml_path = os.path.join(module_path, 'data', 'ir_config_parameter_data.xml')
|
|
if not os.path.exists(xml_path):
|
|
return
|
|
|
|
tree = etree.parse(xml_path)
|
|
fixed = 0
|
|
for rec in tree.findall('.//record[@model="ir.config_parameter"]'):
|
|
xmlid = rec.get('id')
|
|
key_node = rec.find('./field[@name="key"]')
|
|
if not xmlid or key_node is None or not (key_node.text or '').strip():
|
|
continue
|
|
key = key_node.text.strip()
|
|
|
|
cr.execute("SELECT id FROM ir_config_parameter WHERE key = %s", (key,))
|
|
param = cr.fetchone()
|
|
if not param:
|
|
continue # not set yet -> the noupdate load will create it cleanly
|
|
|
|
cr.execute(
|
|
"SELECT id FROM ir_model_data WHERE module = 'fusion_clock' AND name = %s",
|
|
(xmlid,))
|
|
if cr.fetchone():
|
|
continue # already linked
|
|
|
|
cr.execute("""
|
|
INSERT INTO ir_model_data (module, name, model, res_id, noupdate, create_date, write_date)
|
|
VALUES ('fusion_clock', %s, 'ir.config_parameter', %s, true, now(), now())
|
|
""", (xmlid, param[0]))
|
|
fixed += 1
|
|
|
|
if fixed:
|
|
_logger.info(
|
|
"Fusion Clock: re-linked %s orphaned config-parameter external id(s).", fixed)
|