[FIX] models: make inverse of x2many fields work

This commit is contained in:
Raphael Collet
2019-10-07 13:42:52 +00:00
parent db1c909f33
commit 400efc4d40
4 changed files with 49 additions and 1 deletions
@@ -1,5 +1,6 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_test_unit,access_test_unit,model_test_unit,,1,1,1,1
access_test_unit_line,access_test_unit_line,model_test_unit_line,,1,1,1,1
access_test_box,access_test_box,model_test_box,,1,1,1,1
access_test_pallet,access_test_pallet,model_test_pallet,,1,1,1,1
access_test_another_unit,access_test_another_unit,model_test_another_unit,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_unit access_test_unit model_test_unit 1 1 1 1
3 access_test_unit_line access_test_unit_line model_test_unit_line 1 1 1 1
4 access_test_box access_test_box model_test_box 1 1 1 1
5 access_test_pallet access_test_pallet model_test_pallet 1 1 1 1
6 access_test_another_unit access_test_another_unit model_test_another_unit 1 1 1 1
+9
View File
@@ -11,6 +11,7 @@ class Unit(models.Model):
name = fields.Char('Name', required=True)
state = fields.Selection([('a', 'A'), ('b', 'B')], string='State')
surname = fields.Char(compute='_compute_surname')
line_ids = fields.One2many('test.unit.line', 'unit_id')
@api.depends('name')
def _compute_surname(self):
@@ -18,6 +19,14 @@ class Unit(models.Model):
unit.surname = unit.name or ''
class UnitLine(models.Model):
_name = 'test.unit.line'
_description = 'Test Unit Line'
name = fields.Char('Name', required=True)
unit_id = fields.Many2one('test.unit', required=True)
# We want to _inherits from the parent model and we add some fields
# in the child object
class Box(models.Model):
@@ -28,6 +28,26 @@ class test_inherits(common.TransactionCase):
pallet.write({'name': 'C'})
self.assertEqual(pallet.name, 'C')
def test_write_4_one2many(self):
""" Check that we can write on an inherited one2many field. """
box = self.env.ref('test_inherits.box_a')
box.write({'line_ids': [(0, 0, {'name': 'Line 1'})]})
self.assertTrue(all(box.line_ids._ids))
self.assertEqual(box.line_ids.mapped('name'), ['Line 1'])
self.assertEqual(box.line_ids, box.unit_id.line_ids)
box.flush()
box.invalidate_cache(['line_ids'])
box.write({'line_ids': [(0, 0, {'name': 'Line 2'})]})
self.assertTrue(all(box.line_ids._ids))
self.assertEqual(box.line_ids.mapped('name'), ['Line 1', 'Line 2'])
self.assertEqual(box.line_ids, box.unit_id.line_ids)
box.flush()
box.invalidate_cache(['line_ids'])
box.write({'line_ids': [(1, box.line_ids[0].id, {'name': 'First line'})]})
self.assertTrue(all(box.line_ids._ids))
self.assertEqual(box.line_ids.mapped('name'), ['First line', 'Line 2'])
self.assertEqual(box.line_ids, box.unit_id.line_ids)
def test_ir_model_data_inherits(self):
""" Check the existence of the correct ir.model.data """
IrModelData = self.env['ir.model.data']
+19 -1
View File
@@ -3396,6 +3396,14 @@ Record ids: %(records)s
for fname in vals:
field = self._fields[fname]
if field.inverse:
if field.type in ('one2many', 'many2many'):
# The written value is a list of commands that must applied
# on the field's current value. Because the field is
# protected while being written, the field's current value
# will not be computed and default to an empty recordset. So
# make sure the field's value is in cache before writing, in
# order to avoid an inconsistent update.
self[fname]
determine_inverses[field.inverse].append(field)
# DLE P150: `test_cancel_propagation`, `test_manufacturing_3_steps`, `test_manufacturing_flow`
# TODO: check whether still necessary
@@ -3403,7 +3411,17 @@ Record ids: %(records)s
if field.relational or self._field_inverses[field]:
relational_names.append(fname)
if field.compute and not field.readonly:
protected.update(self._field_computed.get(field, [field]))
if field.store or field.type not in ('one2many', 'many2many'):
# Protect the field from being recomputed while being
# inversed. In the case of non-stored x2many fields, the
# field's value may contain unexpeced new records (created
# by command 0). Those new records are necessary for
# inversing the field, but should no longer appear if the
# field is recomputed afterwards. Not protecting the field
# will automatically invalidate the field from the cache,
# forcing its value to be recomputed once dependencies are
# up-to-date.
protected.update(self._field_computed.get(field, [field]))
if fname == 'company_id' or (field.relational and field.check_company):
check_company = True