From 5676d8121d97ba02596e5e3d78971d587fa9d3e7 Mon Sep 17 00:00:00 2001
From: Raphael Collet <rco@openerp.com>
Date: Fri, 6 May 2016 10:47:29 +0200
Subject: [PATCH] [FIX] fields: invalidate x2many fields with a domain

Invalidate the cache of a x2many field when any of the fields appearing in its
domain is modified.  Use the invalidation triggers mechanism for that purpose.
---
 openerp/addons/test_new_api/models.py                |  3 +++
 openerp/addons/test_new_api/tests/test_new_fields.py |  8 ++++++++
 openerp/fields.py                                    | 11 ++++++++++-
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/openerp/addons/test_new_api/models.py b/openerp/addons/test_new_api/models.py
index 50993d242773..2d6d17db541e 100644
--- a/openerp/addons/test_new_api/models.py
+++ b/openerp/addons/test_new_api/models.py
@@ -143,6 +143,8 @@ class Discussion(models.Model):
     participants = fields.Many2many('res.users')
     messages = fields.One2many('test_new_api.message', 'discussion')
     message_changes = fields.Integer(string='Message changes')
+    important_messages = fields.One2many('test_new_api.message', 'discussion',
+                                         domain=[('important', '=', True)])
 
     @api.onchange('moderator')
     def _onchange_moderator(self):
@@ -167,6 +169,7 @@ class Message(models.Model):
     author_partner = fields.Many2one(
         'res.partner', compute='_compute_author_partner',
         search='_search_author_partner')
+    important = fields.Boolean()
 
     @api.one
     @api.constrains('author', 'discussion')
diff --git a/openerp/addons/test_new_api/tests/test_new_fields.py b/openerp/addons/test_new_api/tests/test_new_fields.py
index 6ee9a4a664ee..16cb198c0050 100644
--- a/openerp/addons/test_new_api/tests/test_new_fields.py
+++ b/openerp/addons/test_new_api/tests/test_new_fields.py
@@ -448,6 +448,14 @@ class TestNewFields(common.TransactionCase):
             [('author_partner.name', '=', 'Demo User')])
         self.assertEqual(messages, self.env.ref('test_new_api.message_0_1'))
 
+    def test_60_x2many_domain(self):
+        """ test the cache consistency of a x2many field with a domain """
+        discussion = self.env.ref('test_new_api.discussion_0')
+        message = discussion.messages[0]
+        self.assertNotIn(message, discussion.important_messages)
+
+        message.important = True
+        self.assertIn(message, discussion.important_messages)
 
 
 class TestMagicFields(common.TransactionCase):
diff --git a/openerp/fields.py b/openerp/fields.py
index 94e15f1bac9a..e44caaf1f316 100644
--- a/openerp/fields.py
+++ b/openerp/fields.py
@@ -971,7 +971,7 @@ class Field(object):
         # invalidate the fields that depend on self, and prepare recomputation
         spec = [(self, records._ids)]
         for field, path in self._triggers:
-            if path and field.store:
+            if path and field.compute and field.store:
                 # don't move this line to function top, see log
                 env = records.env(user=SUPERUSER_ID, context={'active_test': False})
                 target = env[field.model_name].search([(path, 'in', records.ids)])
@@ -1723,6 +1723,15 @@ class _RelationalMulti(_Relational):
             for record in records:
                 record[self.name] = record[self.name].filtered(accessible)
 
+    def setup_triggers(self, env):
+        super(_RelationalMulti, self).setup_triggers(env)
+        # also invalidate self when fields appearing in the domain are modified
+        if isinstance(self.domain, list):
+            comodel = env[self.comodel_name]
+            for arg in self.domain:
+                if isinstance(arg, (tuple, list)) and isinstance(arg[0], basestring):
+                    self._setup_dependency([self.name], comodel, arg[0].split('.'))
+
 
 class One2many(_RelationalMulti):
     """ One2many field; the value of such a field is the recordset of all the
-- 
GitLab