From 8ff079366d21b71f2a8867b469b337cb3c89018c Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 12 May 2021 14:02:33 +0000 Subject: [PATCH] [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) --- .../test_new_api/models/test_new_api.py | 34 ++++++++++++++ .../test_new_api/security/ir.model.access.csv | 2 + .../test_new_api/tests/test_onchange.py | 44 +++++++++++++++++++ odoo/fields.py | 2 +- 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py index 9849eb876b2..dbf4a1a6c7f 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -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' diff --git a/odoo/addons/test_new_api/security/ir.model.access.csv b/odoo/addons/test_new_api/security/ir.model.access.csv index e3dff81114b..75ce10cd7f2 100644 --- a/odoo/addons/test_new_api/security/ir.model.access.csv +++ b/odoo/addons/test_new_api/security/ir.model.access.csv @@ -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 diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index 57526d83fb3..2164f191a2f 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -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}, + ]) diff --git a/odoo/fields.py b/odoo/fields.py index 77c43d14b74..664c49e50ab 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -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