[FIX] core: import of o2m with recursive xml declaration
Let's imagine this data
```xml
<record model="my.model" id="1">
<field name="name">parent</field>
<field name="children_ids">
<record model="my.model" id="1.1">
<field name="name">child</field>
</record>
</field>
</record>
```
Loading this data the first time, everything works fine.
But if we update it, this is what happens:
* load `my.model,1`: write on `name=parent` and `children_ids=None`
* load `my.model,1.1`: write on `name=child` and `parent_id=my.model,1`
The write on `children_ids=None` can unlink all the children if the
field is declared as `ondelete=cascade`
That will leade in all the records to be deleted and recreated, but
without keeping links with other documents.
For instance, when upgrading the `account` module, all the
`account.account.tag` are removed from `account.move.line` because when
the `account.tax.report.line` are updated, all the tags are deleted and
recreated.
closes odoo/odoo#82793
X-original-commit: de00316fa42173f3a5c394458bb4418e59e298cd
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: William André (wan) <wan@odoo.com>
Co-authored-by: rco-odoo <rco@odoo.com>
Co-authored-by: jva-odoo <jva@odoo.com>
Co-authored-by: william-andre <wan@odoo.com>
This commit is contained in:
@@ -7,6 +7,8 @@ class TestModel(models.Model):
|
||||
_name = 'test_convert.test_model'
|
||||
_description = "Test Convert Model"
|
||||
|
||||
usered_ids = fields.One2many('test_convert.usered', 'test_id')
|
||||
|
||||
@api.model
|
||||
def action_test_date(self, today_date):
|
||||
return True
|
||||
@@ -25,6 +27,7 @@ class Usered(models.Model):
|
||||
|
||||
name = fields.Char()
|
||||
user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
|
||||
test_id = fields.Many2one('test_convert.test_model')
|
||||
tz = fields.Char(default=lambda self: self.env.context.get('tz') or self.env.user.tz)
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -188,6 +188,37 @@ class TestEvalXML(common.TransactionCase):
|
||||
self.assertEqual(args, ())
|
||||
self.assertEqual(kwargs, {})
|
||||
|
||||
def test_o2m_sub_records(self):
|
||||
# patch the model's class with a proxy that copies the argument
|
||||
Model = self.registry['test_convert.test_model']
|
||||
call_args = []
|
||||
|
||||
def _load_records(self, data_list, update=False):
|
||||
call_args.append(data_list)
|
||||
# pylint: disable=bad-super-call
|
||||
return super(Model, self)._load_records(data_list, update=update)
|
||||
|
||||
self.patch(Model, '_load_records', _load_records)
|
||||
|
||||
# import a record with a subrecord
|
||||
xml = ET.fromstring("""
|
||||
<record id="test_convert.test_o2m_record" model="test_convert.test_model">
|
||||
<field name="usered_ids">
|
||||
<record id="test_convert.test_o2m_subrecord" model="test_convert.usered">
|
||||
<field name="name">subrecord</field>
|
||||
</record>
|
||||
</field>
|
||||
</record>
|
||||
""".strip())
|
||||
obj = xml_import(self.cr, 'test_convert', None, 'init')
|
||||
obj._tag_record(xml)
|
||||
|
||||
# check that field 'usered_ids' is not passed
|
||||
self.assertEqual(len(call_args), 1)
|
||||
for data in call_args[0]:
|
||||
self.assertNotIn('usered_ids', data['values'],
|
||||
"Unexpected value in O2M When loading XML with sub records")
|
||||
|
||||
@unittest.skip("not tested")
|
||||
def test_xml(self):
|
||||
pass
|
||||
|
||||
@@ -579,10 +579,12 @@ form: module.record_id""" % (xml_id,)
|
||||
elif field_type == 'boolean' and isinstance(f_val, str):
|
||||
f_val = str2bool(f_val)
|
||||
elif field_type == 'one2many':
|
||||
if isinstance(f_val, str):
|
||||
f_val = None
|
||||
for child in field.findall('./record'):
|
||||
sub_records.append((child, model._fields[f_name].inverse_name))
|
||||
if isinstance(f_val, str):
|
||||
# We do not want to write on the field since we will write
|
||||
# on the childrens' parents later
|
||||
continue
|
||||
res[f_name] = f_val
|
||||
if extra_vals:
|
||||
res.update(extra_vals)
|
||||
|
||||
Reference in New Issue
Block a user