From fcf6ef476ced0953e6faf88b7bbf9881923de4d5 Mon Sep 17 00:00:00 2001
From: Raphael Collet <rco@odoo.com>
Date: Thu, 31 Aug 2017 14:46:34 +0200
Subject: [PATCH] [FIX] fields: writing on a one2many with a domain should not
 remove all lines

Specifically, the command `(6, 0, ids)` should only unlink/detach the lines
that satisfy to the field's domain.

Test from #18440

opw-756983
---
 .../test_new_api/tests/test_new_fields.py     | 24 +++++++++++++++++++
 odoo/fields.py                                |  9 ++++---
 2 files changed, 28 insertions(+), 5 deletions(-)

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 9deaee1a5f0a..dc5b9936c7a1 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -697,6 +697,30 @@ class TestFields(common.TransactionCase):
         self.assertFalse(discussion.very_important_messages)
         self.assertFalse(message.exists())
 
+    def test_70_x2many_write(self):
+        discussion = self.env.ref('test_new_api.discussion_0')
+        Message = self.env['test_new_api.message']
+        # There must be 3 messages, 0 important
+        self.assertEqual(len(discussion.messages), 3)
+        self.assertEqual(len(discussion.important_messages), 0)
+        self.assertEqual(len(discussion.very_important_messages), 0)
+        discussion.important_messages = [(0, 0, {
+            'body': 'What is the answer?',
+            'important': True,
+        })]
+        # There must be 4 messages, 1 important
+        self.assertEqual(len(discussion.messages), 4)
+        self.assertEqual(len(discussion.important_messages), 1)
+        self.assertEqual(len(discussion.very_important_messages), 1)
+        discussion.very_important_messages |= Message.new({
+            'body': '42',
+            'important': True,
+        })
+        # There must be 5 messages, 2 important
+        self.assertEqual(len(discussion.messages), 5)
+        self.assertEqual(len(discussion.important_messages), 2)
+        self.assertEqual(len(discussion.very_important_messages), 2)
+
 
 class TestHtmlField(common.TransactionCase):
 
diff --git a/odoo/fields.py b/odoo/fields.py
index 60aefa9bc25d..50209746c10e 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -2205,14 +2205,13 @@ class One2many(_RelationalMulti):
                 elif act[0] == 6:
                     record = records[-1]
                     comodel.browse(act[2]).write({inverse: record.id})
-                    query = "SELECT id FROM %s WHERE %s=%%s AND id <> ALL(%%s)" % (comodel._table, inverse)
-                    comodel._cr.execute(query, (record.id, act[2] or [0]))
-                    lines = comodel.browse([row[0] for row in comodel._cr.fetchall()])
+                    domain = self.domain(records) if callable(self.domain) else self.domain
+                    domain = domain + [(inverse, 'in', records.ids), ('id', 'not in', act[2] or [0])]
                     inverse_field = comodel._fields[inverse]
                     if inverse_field.ondelete == 'cascade':
-                        lines.unlink()
+                        comodel.search(domain).unlink()
                     else:
-                        lines.write({inverse: False})
+                        comodel.search(domain).write({inverse: False})
 
 
 class Many2many(_RelationalMulti):
-- 
GitLab