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 08995bf9cce..b3dfd095f2a 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -513,6 +513,22 @@ class ComputeRecursive(models.Model): rec.display_name = rec.name +class ComputeRecursiveTree(models.Model): + _name = 'test_new_api.recursive.tree' + _description = 'Test New API Recursive with one2many field' + + name = fields.Char(required=True) + parent_id = fields.Many2one('test_new_api.recursive.tree', ondelete='cascade') + children_ids = fields.One2many('test_new_api.recursive.tree', 'parent_id') + display_name = fields.Char(compute='_compute_display_name', store=True) + + @api.depends('name', 'children_ids.display_name') + def _compute_display_name(self): + for rec in self: + children_names = rec.mapped('children_ids.display_name') + rec.display_name = '%s(%s)' % (rec.name, ', '.join(children_names)) + + class ComputeCascade(models.Model): _name = 'test_new_api.cascade' _description = 'Test New API Cascade' 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 946c10e27c4..b0e2a0b593b 100644 --- a/odoo/addons/test_new_api/security/ir.model.access.csv +++ b/odoo/addons/test_new_api/security/ir.model.access.csv @@ -22,6 +22,7 @@ access_test_new_api_compute_inverse,access_test_new_api_compute_inverse,model_te access_test_new_api_compute_readonly,access_test_new_api_compute_readonly,model_test_new_api_compute_readonly,,1,1,1,1 access_test_new_api_multi_compute_inverse,access_test_new_api_multi_compute_inverse,model_test_new_api_multi_compute_inverse,,1,1,1,1 access_test_new_api_recursive,access_test_new_api_recursive,model_test_new_api_recursive,,1,1,1,1 +access_test_new_api_recursive_tree,access_test_new_api_recursive_tree,model_test_new_api_recursive_tree,,1,1,1,1 access_test_new_api_cascade,access_test_new_api_cascade,model_test_new_api_cascade,,1,1,1,1 access_test_new_api_compute_readwrite,access_test_new_api_compute_readwrite,model_test_new_api_compute_readwrite,,1,1,1,1 access_test_new_api_compute_onchange,access_test_new_api_compute_onchange,model_test_new_api_compute_onchange,,1,1,1,1 diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index e0335c2f201..939bbd8621f 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -495,6 +495,14 @@ class TestFields(TransactionCaseWithUserDemo): b.unlink() self.assertEqual((a + b + c + d).exists(), a) + def test_12_recursive_tree(self): + foo = self.env['test_new_api.recursive.tree'].create({'name': 'foo'}) + self.assertEqual(foo.display_name, 'foo()') + bar = foo.create({'name': 'bar', 'parent_id': foo.id}) + self.assertEqual(foo.display_name, 'foo(bar())') + baz = foo.create({'name': 'baz', 'parent_id': bar.id}) + self.assertEqual(foo.display_name, 'foo(bar(baz()))') + def test_12_cascade(self): """ test computed field depending on computed field """ message = self.env.ref('test_new_api.message_0_0') diff --git a/odoo/models.py b/odoo/models.py index 2fdc0db37eb..8c6e9a65a50 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -5782,36 +5782,35 @@ Fields: tocompute = list(tocompute) # process what to compute - for field, records in tocompute: + for field, records, create in tocompute: records -= self.env.protected(field) if not records: continue - # Dont force the recomputation of compute fields which are - # not stored as this is not really necessary. - recursive = not create and field.recursive if field.compute and field.store: - if recursive: - marked_records = self.env.not_to_compute(field, records) + if field.recursive: + recursively_marked = self.env.not_to_compute(field, records) self.env.add_to_compute(field, records) else: - if recursive: - marked_records = records & self.env.cache.get_records(records, field) + # Dont force the recomputation of compute fields which are + # not stored as this is not really necessary. + if field.recursive: + recursively_marked = records & self.env.cache.get_records(records, field) self.env.cache.invalidate([(field, records._ids)]) # recursively trigger recomputation of field's dependents - if recursive: - marked_records.modified([field.name]) + if field.recursive: + recursively_marked.modified([field.name], create) def _modified_triggers(self, tree, create=False): """ Return an iterator traversing a tree of field triggers on ``self``, traversing backwards field dependencies along the way, and yielding - pairs ``(field, records)`` to recompute. + tuple ``(field, records, created)`` to recompute. """ if not self: return # first yield what to compute for field in tree.get(None, ()): - yield field, self + yield field, self, create # then traverse dependencies backwards, and proceed recursively for key, val in tree.items():