[FIX] util/records:Mark records noupdate
If particular xml don't have noupdate marked but parent data node have noupdate in that case from update_records_from_xml creating record as noupdate false which is causing issue in future upgrade because it going for delete. For preventing such case adding noupdate flag to record and inherit created record acccoring to this commit by that //data node or that xml node itself.
use case:
client db don't have the documents.document_internal_folder xmlid which is created when migrated to 18.0 from this script with noupdate false and because data node have noupdate true but particular xml don't have noupdate that is why it created as noupdate false and other inherit records also with noupdate and after migrating from onwards version related to that mail.alias records xml creating according to this
and later on version in 18.3 if related inherit model is changed but still some how use case of those records for preventing in that case.
before upgrade
timer_test_document_test=# select * from ir_model_data where name like '%document_internal_folder%'
;
id | create_uid | create_date | write_date | write_uid | res_id | noupdate | name | module | model
----+------------+-------------+------------+-----------+--------+----------+------+--------+-------
(0 rows)
before fix
timer_test_document_test=# select * from ir_model_data where name like '%document_internal_folder%'
;
id | create_uid | create_date | write_date | write_uid | res_id | noupdate | name | module | model
-------+------------+----------------------------+----------------------------+-----------+--------+----------+-------------------------------------+-----------+--------------------
39576 | | 2025-06-19 13:38:37.987267 | 2025-06-19 13:38:37.987267 | | 20 | f | document_internal_folder_mail_alias | documents | mail.alias
39577 | | 2025-06-19 13:38:37.987267 | 2025-06-19 13:38:37.987267 | | 20 | f | document_internal_folder | documents | documents.document
after fix
timer_test_document_test=# select * from ir_model_data where name like '%document_internal_folder%'
;
id | create_uid | create_date | write_date | write_uid | res_id | noupdate | name | module | model
-------+------------+----------------------------+----------------------------+-----------+--------+----------+-------------------------------------+-----------+--------------------
39576 | | 2025-06-19 13:41:40.343454 | 2025-06-19 13:41:40.343454 | | 20 | t | document_internal_folder_mail_alias | documents | mail.alias
39577 | | 2025-06-19 13:41:40.343454 | 2025-06-19 13:41:40.343454 | | 20 | t | document_internal_folder | documents | documents.document
Traceback (most recent call last):
File "/home/odoo/src/odoo/saas-18.3/odoo/service/server.py", line 1396, in preload_registries
registry = Registry.new(dbname, update_module=update_module, install_modules=config['init'], upgrade_modules=config['update'])
File "<decorator-gen-6>", line 2, in new
File "/home/odoo/src/odoo/saas-18.3/odoo/tools/func.py", line 83, in locked
return func(inst, *args, **kwargs)
File "/home/odoo/src/odoo/saas-18.3/odoo/orm/registry.py", line 167, in new
load_modules(
File "/home/odoo/src/odoo/saas-18.3/odoo/modules/loading.py", line 509, in load_modules
env['ir.model.data']._process_end(registry.updated_modules)
File "/tmp/tmp2ipekce9/migrations/base/0.0.0/pre-models-no-model-data-delete.py", line 108, in _process_end
return super(IrModelData, self)._process_end(modules)
File "/home/odoo/src/odoo/saas-18.3/odoo/addons/base/models/ir_model.py", line 2589, in _process_end
self._process_end_unlink_record(record)
File "/home/odoo/src/odoo/saas-18.3/addons/website/models/ir_model_data.py", line 35, in _process_end_unlink_record
return super()._process_end_unlink_record(record)
File "/home/odoo/src/odoo/saas-18.3/odoo/addons/base/models/ir_model.py", line 2518, in _process_end_unlink_record
record.unlink()
File "/home/odoo/src/odoo/saas-18.3/odoo/orm/models.py", line 3913, in unlink
cr.execute(SQL(
File "/home/odoo/src/odoo/saas-18.3/odoo/sql_db.py", line 422, in execute
self._obj.execute(query, params)
psycopg2.errors.ForeignKeyViolation: update or delete on table "mail_alias" violates foreign key constraint "documents_document_alias_id_fkey" on table "documents_document"
DETAIL: Key (id)=(40) is still referenced from table "documents_document".
upg-2987024 opw-4874805
I'm not sure we want this. We could call force_noupdate in the caller script. Or perhaps add a noupdate=(True/False/None) (None -> keep whatever is already there) to update_record_from_xml.
@KangOl wdyt?
upgradeci retry with always only documents
Indeed, it should not be automatically determined.
A noupdate:bool | None = None attribute can be added to the function.
Hello @aj-fuentes , @KangOl Thanks for your quick review. I have update patch so it will work only whenever new record will be created. your insight will be valuable and it will prevent blocking for future case also That's the main purpose of this fix
OK, I think I finally understand the initial problem.
We don't need this new noupdate=None argument.
The purpose of this function is to bypass the noupdate=1 flag in the XML declarations. So we need to force the record to be in noupdate when it is newly created.
diff --git src/util/records.py src/util/records.py
index 0ea524d..a7360aa 100644
--- src/util/records.py
+++ src/util/records.py
@@ -1108,7 +1108,8 @@ def __update_record_from_xml(
return
else:
# The xmlid doesn't already exists, nothing to reset
- reset_write_metadata = noupdate = reset_translations = False
+ reset_write_metadata = reset_translations = False
+ noupdate = True
fields = None
write_data = None
Then we have a second issue with the xmlids of the parent records in case of _inherits.
For this, I propose to change the force_noupdate function to directly handle that case.
Indeed @KangOl and @aj-fuentes , I was thinkin for the case where the record with noupdate False come for update_record_from_xml but that will never happen my bad and made fix according to that, anyway I have updated the patch and tested also.
Thanks
@sagu-odoo can you test with the last version?
@KangOl , here it's -> inherits instead of _inherit
so neeed to get inherits and mark them as noupdate
(Pdb) util.env(cr)['documents.document']._inherit
['mail.thread.cc', 'mail.activity.mixin', 'mail.alias.mixin']
(Pdb) util.env(cr)['documents.document']._inherits
{'mail.alias': 'alias_id'}
(Pdb)
Yes, this is filtered by the if inh.via: condition.
for the case I am testing for that it's not working. due to this,mail.alias is not directy inherited but it inherited from mail.alias.mixin and mail.alias.mixin is inherited in document.documents so it related to this mail.alias created record didn't marked as noupdate may be
during debugging that i found that mail_alias didn't yield here
> /home/odoo/odoo18/upgrade-util/src/util/inherit.py(106)direct_inherit_parents()
-> for inh in inhs:
(Pdb) n
> /home/odoo/odoo18/upgrade-util/src/util/inherit.py(107)direct_inherit_parents()
-> if inh.model == model and cmp_(inh):
(Pdb) parent
'mail.alias'
(Pdb) cmp_(inh)
True
(Pdb) inh.model == model
False
(Pdb) model
'documents.document'
(Pdb) inh.model
'mail.alias.mixin'
Ho! The usage of direct_inherit_parents is not enough.
Thanks for pointing it.
Hello @KangOl , I have tested with this new patch but here due to _cached decorator it not working because if model inherit is changed during upgrade those are not updated because it already in _result and changes regarding noupdate didn't reflected accordingly to that _inherits record because it never got that model in direct_inherits.
