[FIX] core: computed editable one2many field with a domain

Manually adding a line should not trigger the computation of the field,
just like modifying the line fields that occur in the field's domain.
In other words, the dependencies of the field should be limited to the
ones declared on field or its compute method.

closes odoo/odoo#71049

X-original-commit: 1c39814bd729cc08882f1545c7d88b0592e63f9a
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
Raphael Collet
2021-05-19 16:29:53 +00:00
parent 2df6a0ee81
commit 8ff079366d
4 changed files with 81 additions and 1 deletions
@@ -694,6 +694,40 @@ class ComputeUnassigned(models.Model):
record.bares = record.foo
class ComputeOne2many(models.Model):
_name = 'test_new_api.one2many'
_description = "A computed editable one2many field with a domain"
name = fields.Char()
line_ids = fields.One2many(
'test_new_api.one2many.line', 'container_id',
compute='_compute_line_ids', store=True, readonly=False,
domain=[('count', '>', 0)],
)
@api.depends('name')
def _compute_line_ids(self):
# increment counter of line with the same name, or create a new line
for record in self:
if not record.name:
continue
for line in record.line_ids:
if line.name == record.name:
line.count += 1
break
else:
record.line_ids = [(0, 0, {'name': record.name})]
class ComputeOne2manyLine(models.Model):
_name = 'test_new_api.one2many.line'
_description = "Line of a computed one2many"
name = fields.Char()
count = fields.Integer(default=1)
container_id = fields.Many2one('test_new_api.one2many', required=True)
class ModelBinary(models.Model):
_name = 'test_new_api.model_binary'
_description = 'Test Image field'
@@ -29,6 +29,8 @@ access_test_new_api_compute_onchange,access_test_new_api_compute_onchange,model_
access_test_new_api_compute_onchange_line,access_test_new_api_compute_onchange_line,model_test_new_api_compute_onchange_line,,1,1,1,1
access_test_new_api_compute_dynamic_depends,access_test_new_api_compute_dynamic_depends,model_test_new_api_compute_dynamic_depends,,1,1,1,1
access_test_new_api_compute_unassigned,access_test_new_api_compute_unassigned,model_test_new_api_compute_unassigned,,1,1,1,1
access_test_new_api_one2many,access_test_new_api_one2many,model_test_new_api_one2many,,1,1,1,1
access_test_new_api_one2many_line,access_test_new_api_one2many_line,model_test_new_api_one2many_line,,1,1,1,1
access_test_new_api_binary_svg,access_test_new_api_binary_svg,model_test_new_api_binary_svg,,1,1,1,1
access_test_new_api_monetary_base,access_test_new_api_monetary_base,model_test_new_api_monetary_base,,1,1,1,1
access_test_new_api_monetary_related,access_test_new_api_monetary_related,model_test_new_api_monetary_related,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
29 access_test_new_api_compute_onchange_line access_test_new_api_compute_onchange_line model_test_new_api_compute_onchange_line 1 1 1 1
30 access_test_new_api_compute_dynamic_depends access_test_new_api_compute_dynamic_depends model_test_new_api_compute_dynamic_depends 1 1 1 1
31 access_test_new_api_compute_unassigned access_test_new_api_compute_unassigned model_test_new_api_compute_unassigned 1 1 1 1
32 access_test_new_api_one2many access_test_new_api_one2many model_test_new_api_one2many 1 1 1 1
33 access_test_new_api_one2many_line access_test_new_api_one2many_line model_test_new_api_one2many_line 1 1 1 1
34 access_test_new_api_binary_svg access_test_new_api_binary_svg model_test_new_api_binary_svg 1 1 1 1
35 access_test_new_api_monetary_base access_test_new_api_monetary_base model_test_new_api_monetary_base 1 1 1 1
36 access_test_new_api_monetary_related access_test_new_api_monetary_related model_test_new_api_monetary_related 1 1 1 1
@@ -824,3 +824,47 @@ class TestComputeOnchange(common.TransactionCase):
]
result = record.onchange({'line_ids': line_ids}, 'line_ids', spec)
self.assertEqual(result, expected)
def test_computed_editable_one2many_domain(self):
""" Test a computed, editable one2many field with a domain. """
record = self.env['test_new_api.one2many'].create({'name': 'foo'})
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
])
# trigger recomputation by changing name
record.name = 'bar'
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
{'name': 'bar', 'count': 1},
])
# manually adding a line should not trigger recomputation
record.line_ids.create({'name': 'baz', 'container_id': record.id})
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
{'name': 'bar', 'count': 1},
{'name': 'baz', 'count': 1},
])
# changing the field in the domain should not trigger recomputation...
record.line_ids[-1].count = 2
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
{'name': 'bar', 'count': 1},
{'name': 'baz', 'count': 2},
])
# ...and may show cache inconsistencies
record.line_ids[-1].count = 0
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
{'name': 'bar', 'count': 1},
{'name': 'baz', 'count': 0},
])
record.flush()
record.invalidate_cache()
self.assertRecordValues(record.line_ids, [
{'name': 'foo', 'count': 1},
{'name': 'bar', 'count': 1},
])
+1 -1
View File
@@ -3237,7 +3237,7 @@ class _RelationalMulti(_Relational):
def get_depends(self, model):
depends, depends_context = super().get_depends(model)
if not self.related and isinstance(self.domain, list):
if not self.compute and isinstance(self.domain, list):
depends = unique(itertools.chain(depends, (
self.name + '.' + arg[0]
for arg in self.domain