From 71549030c7fcf4f34e0551ef1b4ccaebc6fe74ef Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Wed, 9 Sep 2020 15:31:06 +0000 Subject: [PATCH] [FIX] core: cache consistency of one2many field with computed inverse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consider a one2many field with a corresponding many2one field that is computed. After modifying the many2one field's dependencies, the cached value of the one2many field is inconsistent until the many2one field has been recomputed. Therefore, one has to force the computation of the many2one field before accessing the cached value of the one2many field. closes odoo/odoo#59034 X-original-commit: b9201ebdd65eaabab9257cf97c58410681783fa6 Signed-off-by: Xavier Dollé (xdo) Signed-off-by: Raphael Collet (rco) --- .../test_new_api/models/test_new_api.py | 20 +++++++++++++++++++ .../test_new_api/security/ir.model.access.csv | 2 ++ .../test_new_api/tests/test_one2many.py | 8 ++++++++ odoo/fields.py | 9 +++++++++ 4 files changed, 39 insertions(+) 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 47df3602baa..27af01e335b 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -1127,3 +1127,23 @@ class ShareCacheComputeLine(models.Model): parent_id = fields.Many2one('test_new_api.model_shared_cache_compute_parent') amount = fields.Integer() user_id = fields.Many2one('res.users', default= lambda self: self.env.user) # Note: There is an ir.rule about this. + + +class ComputeContainer(models.Model): + _name = _description = 'test_new_api.compute.container' + + name = fields.Char() + member_ids = fields.One2many('test_new_api.compute.member', 'container_id') + + +class ComputeMember(models.Model): + _name = _description = 'test_new_api.compute.member' + + name = fields.Char() + container_id = fields.Many2one('test_new_api.compute.container', compute='_compute_container', store=True) + + @api.depends('name') + def _compute_container(self): + container = self.env['test_new_api.compute.container'] + for member in self: + member.container_id = container.search([('name', '=', member.name)], limit=1) 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 466b014f213..71a309d5d1a 100644 --- a/odoo/addons/test_new_api/security/ir.model.access.csv +++ b/odoo/addons/test_new_api/security/ir.model.access.csv @@ -64,3 +64,5 @@ access_test_new_api_move,access_test_new_api_move,model_test_new_api_move,,1,1,1 access_test_new_api_move_line,access_test_new_api_move_line,model_test_new_api_move_line,,1,1,1,1 access_test_new_api_model_shared_cache_compute_parent,access_test_new_api.model_shared_cache_compute_parent,model_test_new_api_model_shared_cache_compute_parent,,1,1,1,1 access_test_new_api_model_shared_cache_compute_line,access_test_new_api.model_shared_cache_compute_line,model_test_new_api_model_shared_cache_compute_line,,1,1,1,1 +access_test_new_api_compute_container,access_test_new_api_compute_container,model_test_new_api_compute_container,,1,1,1,1 +access_test_new_api_compute_member,access_test_new_api_compute_member,model_test_new_api_compute_member,,1,1,1,1 diff --git a/odoo/addons/test_new_api/tests/test_one2many.py b/odoo/addons/test_new_api/tests/test_one2many.py index a2be1d9709e..f9d2be27190 100644 --- a/odoo/addons/test_new_api/tests/test_one2many.py +++ b/odoo/addons/test_new_api/tests/test_one2many.py @@ -247,3 +247,11 @@ class One2manyCase(TransactionCase): # delete parent, and check that recomputation ends parent.unlink() parent.flush() + + def test_compute_stored_many2one_one2many(self): + container = self.env['test_new_api.compute.container'].create({'name': 'Foo'}) + self.assertFalse(container.member_ids) + member = self.env['test_new_api.compute.member'].create({'name': 'Foo'}) + # at this point, member.container_id must be computed for member to + # appear in container.member_ids + self.assertEqual(container.member_ids, member) diff --git a/odoo/fields.py b/odoo/fields.py index f840585414f..7656b279004 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -3055,6 +3055,15 @@ class One2many(_RelationalMulti): domain = domain + [(inverse_field.model_field, '=', records._name)] return domain + def __get__(self, records, owner): + if records is not None and self.inverse_name is not None: + # force the computation of the inverse field to ensure that the + # cache value of self is consistent + inverse_field = records.pool[self.comodel_name]._fields[self.inverse_name] + if inverse_field.compute: + records.env[self.comodel_name].recompute([self.inverse_name]) + return super().__get__(records, owner) + def read(self, records): # retrieve the lines in the comodel context = {'active_test': False}