From d9d2ef5b2731ba312e6274ea162caa2183d0ccbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
 <victor.martinez@tecnativa.com>
Date: Wed, 2 Nov 2022 08:52:09 +0100
Subject: [PATCH] [FIX] base_comment_template: Add models text field to prevent
 error from ir.model model

TT40209
---
 base_comment_template/__manifest__.py         |  2 +-
 .../i18n/base_comment_template.pot            |  9 ++++
 base_comment_template/i18n/es.po              | 29 ++++++----
 .../migrations/16.0.1.1.0/pre-migration.py    | 27 ++++++++++
 .../models/base_comment_template.py           | 53 ++++++++++++++++---
 .../models/comment_template.py                | 20 ++++---
 .../tests/test_base_comment_template.py       | 26 ++++++++-
 .../views/base_comment_template_view.xml      |  8 +--
 8 files changed, 142 insertions(+), 32 deletions(-)
 create mode 100644 base_comment_template/migrations/16.0.1.1.0/pre-migration.py

diff --git a/base_comment_template/__manifest__.py b/base_comment_template/__manifest__.py
index c6857151a..397f668c4 100644
--- a/base_comment_template/__manifest__.py
+++ b/base_comment_template/__manifest__.py
@@ -5,7 +5,7 @@
     "name": "Base Comments Templates",
     "summary": "Add conditional mako template to any report"
     "on models that inherits comment.template.",
-    "version": "16.0.1.0.0",
+    "version": "16.0.1.1.0",
     "category": "Reporting",
     "website": "https://github.com/OCA/reporting-engine",
     "author": "Camptocamp, Odoo Community Association (OCA)",
diff --git a/base_comment_template/i18n/base_comment_template.pot b/base_comment_template/i18n/base_comment_template.pot
index cfa90b75f..53df74568 100644
--- a/base_comment_template/i18n/base_comment_template.pot
+++ b/base_comment_template/i18n/base_comment_template.pot
@@ -6,6 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Odoo Server 16.0\n"
 "Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-11-03 08:01+0000\n"
+"PO-Revision-Date: 2022-11-03 08:01+0000\n"
 "Last-Translator: \n"
 "Language-Team: \n"
 "MIME-Version: 1.0\n"
@@ -196,6 +198,7 @@ msgstr ""
 
 #. module: base_comment_template
 #: model:ir.model,name:base_comment_template.model_ir_model
+#: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template__models
 msgid "Models"
 msgstr ""
 
@@ -256,6 +259,12 @@ msgstr ""
 msgid "Sequence"
 msgstr ""
 
+#. module: base_comment_template
+#: code:addons/base_comment_template/models/base_comment_template.py:0
+#, python-format
+msgid "Some model (%s) not found"
+msgstr ""
+
 #. module: base_comment_template
 #: model:ir.model.fields,help:base_comment_template.field_res_partner__base_comment_template_ids
 #: model:ir.model.fields,help:base_comment_template.field_res_users__base_comment_template_ids
diff --git a/base_comment_template/i18n/es.po b/base_comment_template/i18n/es.po
index fd21ae5a2..b6fd8b8fd 100644
--- a/base_comment_template/i18n/es.po
+++ b/base_comment_template/i18n/es.po
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Odoo Server 10.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-02-09 09:55+0000\n"
-"PO-Revision-Date: 2021-02-09 11:21+0100\n"
+"POT-Creation-Date: 2022-11-03 08:01+0000\n"
+"PO-Revision-Date: 2022-11-03 09:03+0100\n"
 "Last-Translator: Carlos <carlos.roca@tecnativa.com>\n"
 "Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
 "Language: es\n"
@@ -17,7 +17,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 2.0.6\n"
+"X-Generator: Poedit 3.0.1\n"
 
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.base_comment_template_preview_form
@@ -65,7 +65,7 @@ msgstr ""
 #. module: base_comment_template
 #: model:ir.model.fields.selection,name:base_comment_template.selection__base_comment_template__position__after_lines
 msgid "Bottom"
-msgstr ""
+msgstr "Abajo"
 
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.base_comment_template_preview_form
@@ -134,7 +134,7 @@ msgstr "Creado el"
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.base_comment_template_preview_form
 msgid "Discard"
-msgstr ""
+msgstr "Descartar"
 
 #. module: base_comment_template
 #: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template__display_name
@@ -201,10 +201,11 @@ msgstr "Última modificación el"
 #. module: base_comment_template
 #: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template_preview__model_id
 msgid "Model"
-msgstr ""
+msgstr "Modelo"
 
 #. module: base_comment_template
 #: model:ir.model,name:base_comment_template.model_ir_model
+#: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template__models
 msgid "Models"
 msgstr "Modelos"
 
@@ -223,7 +224,7 @@ msgstr "Nombre de la plantilla de comentario"
 #. module: base_comment_template
 #: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template_preview__no_record
 msgid "No Record"
-msgstr ""
+msgstr "Sin registro"
 
 #. module: base_comment_template
 #: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template__partner_ids
@@ -238,12 +239,12 @@ msgstr "Posición en el documento"
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.view_base_comment_template_form
 msgid "Preview"
-msgstr ""
+msgstr "Previsualizar"
 
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.base_comment_template_preview_form
 msgid "Preview of"
-msgstr ""
+msgstr "Previsualización de"
 
 #. module: base_comment_template
 #: model:ir.model.fields.selection,name:base_comment_template.selection__base_comment_template_preview__engine__qweb
@@ -263,7 +264,13 @@ msgstr ""
 #. module: base_comment_template
 #: model:ir.model.fields,field_description:base_comment_template.field_base_comment_template__sequence
 msgid "Sequence"
-msgstr ""
+msgstr "Secuencia"
+
+#. module: base_comment_template
+#: code:addons/base_comment_template/models/base_comment_template.py:0
+#, python-format
+msgid "Some model (%s) not found"
+msgstr "Algún modelo (%s) no se ha encontrado"
 
 #. module: base_comment_template
 #: model:ir.model.fields,help:base_comment_template.field_res_partner__base_comment_template_ids
@@ -349,4 +356,4 @@ msgstr ""
 #. module: base_comment_template
 #: model_terms:ir.ui.view,arch_db:base_comment_template.base_comment_template_preview_form
 msgid "record:"
-msgstr ""
+msgstr "registro:"
diff --git a/base_comment_template/migrations/16.0.1.1.0/pre-migration.py b/base_comment_template/migrations/16.0.1.1.0/pre-migration.py
new file mode 100644
index 000000000..89d9cbce4
--- /dev/null
+++ b/base_comment_template/migrations/16.0.1.1.0/pre-migration.py
@@ -0,0 +1,27 @@
+# Copyright 2022 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from openupgradelib import openupgrade
+
+from odoo.tools.sql import column_exists
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+    if not column_exists(env.cr, "base_comment_template", "models"):
+        openupgrade.logged_query(
+            env.cr,
+            "ALTER TABLE base_comment_template ADD COLUMN IF NOT EXISTS models text",
+        )
+        openupgrade.logged_query(
+            env.cr,
+            """
+            UPDATE base_comment_template template
+            SET models = (
+                SELECT string_agg(model.model, ',')
+                FROM base_comment_template_ir_model_rel AS rel
+                JOIN ir_model AS model ON rel.ir_model_id = model.id
+                WHERE rel.base_comment_template_id = template.id
+            )
+            """,
+        )
diff --git a/base_comment_template/models/base_comment_template.py b/base_comment_template/models/base_comment_template.py
index 66764ccc1..e2cce3a11 100644
--- a/base_comment_template/models/base_comment_template.py
+++ b/base_comment_template/models/base_comment_template.py
@@ -1,9 +1,10 @@
 # Copyright 2014 Guewen Baconnier (Camptocamp SA)
 # Copyright 2013-2014 Nicolas Bessi (Camptocamp SA)
 # Copyright 2020 NextERP Romania SRL
-# Copyright 2021 Tecnativa - Víctor Martínez
+# Copyright 2021-2022 Tecnativa - Víctor Martínez
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-from odoo import fields, models
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
 
 
 class BaseCommentTemplate(models.Model):
@@ -51,17 +52,15 @@ class BaseCommentTemplate(models.Model):
         help="If set, the comment template will be available only for the selected "
         "partner.",
     )
+    models = fields.Text(required=True)
     model_ids = fields.Many2many(
         comodel_name="ir.model",
+        compute="_compute_model_ids",
+        compute_sudo=True,
         string="IR Model",
-        ondelete="cascade",
-        domain=[
-            ("is_comment_template", "=", True),
-            ("model", "!=", "comment.template"),
-        ],
-        required=True,
         help="This comment template will be available on this models. "
         "You can see here only models allowed to set the coment template.",
+        search="_search_model_ids",
     )
     domain = fields.Char(
         string="Filter Domain",
@@ -74,6 +73,37 @@ class BaseCommentTemplate(models.Model):
         required=True, default=10, help="The smaller number = The higher priority"
     )
 
+    def _get_ir_model_items(self, models):
+        return (
+            self.env["ir.model"]
+            .sudo()
+            .search(
+                [
+                    ("is_comment_template", "=", True),
+                    ("model", "!=", "comment.template"),
+                    ("model", "in", models),
+                ]
+            )
+        )
+
+    @api.depends("models")
+    def _compute_model_ids(self):
+        im_model = self.env["ir.model"]
+        for item in self:
+            models = im_model.browse()
+            if item.models:
+                models = self._get_ir_model_items(item.models.split(","))
+            item.model_ids = [(6, 0, models.ids)]
+
+    @api.constrains("models")
+    def check_models(self):
+        """Avoid non-existing or not allowed models (is_comment_template=True)"""
+        for item in self.filtered("models"):
+            models = item.models.split(",")
+            res = self._get_ir_model_items(item.models.split(","))
+            if not res or len(res) != len(models):
+                raise ValidationError(_("Some model (%s) not found") % item.models)
+
     def name_get(self):
         """Redefine the name_get method to show the template name with the position."""
         res = []
@@ -85,3 +115,10 @@ class BaseCommentTemplate(models.Model):
                 name += " (%s)" % ", ".join(item.model_ids.mapped("name"))
             res.append((item.id, name))
         return res
+
+    def _search_model_ids(self, operator, value):
+        # We cannot use model_ids.model in search() method to avoid access errors
+        allowed_items = (
+            self.sudo().search([]).filtered(lambda x: x.model_ids.model == value)
+        )
+        return [("id", "in", allowed_items.ids)]
diff --git a/base_comment_template/models/comment_template.py b/base_comment_template/models/comment_template.py
index b421eadc1..2e7f18407 100644
--- a/base_comment_template/models/comment_template.py
+++ b/base_comment_template/models/comment_template.py
@@ -1,9 +1,10 @@
 # Copyright 2014 Guewen Baconnier (Camptocamp SA)
 # Copyright 2013-2014 Nicolas Bessi (Camptocamp SA)
 # Copyright 2020 NextERP Romania SRL
-# Copyright 2021 Tecnativa - Víctor Martínez
+# Copyright 2021-2022 Tecnativa - Víctor Martínez
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 from odoo import api, fields, models
+from odoo.osv import expression
 from odoo.tools.safe_eval import safe_eval
 
 
@@ -20,23 +21,28 @@ class CommentTemplate(models.AbstractModel):
 
     comment_template_ids = fields.Many2many(
         compute="_compute_comment_template_ids",
+        compute_sudo=True,
         comodel_name="base.comment.template",
         string="Comment Template",
-        domain=lambda self: [("model_ids.model", "=", self._name)],
+        domain=lambda self: [("model_ids", "=", self._name)],
         store=True,
         readonly=False,
     )
 
     @api.depends(_comment_template_partner_field_name)
     def _compute_comment_template_ids(self):
+        template_model = self.env["base.comment.template"]
+        template_domain = template_model._search_model_ids("=", self._name)
         for record in self:
             partner = record[self._comment_template_partner_field_name]
             record.comment_template_ids = [(5,)]
-            templates = self.env["base.comment.template"].search(
-                [
-                    ("id", "in", partner.base_comment_template_ids.ids),
-                    ("model_ids.model", "=", self._name),
-                ]
+            templates = template_model.search(
+                expression.AND(
+                    [
+                        [("id", "in", partner.base_comment_template_ids.ids)],
+                        template_domain,
+                    ]
+                )
             )
             for template in templates:
                 domain = safe_eval(template.domain)
diff --git a/base_comment_template/tests/test_base_comment_template.py b/base_comment_template/tests/test_base_comment_template.py
index 359aee55a..7ad31cdc7 100644
--- a/base_comment_template/tests/test_base_comment_template.py
+++ b/base_comment_template/tests/test_base_comment_template.py
@@ -2,6 +2,7 @@
 # Copyright 2021 Tecnativa - Víctor Martínez
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 from odoo import Command
+from odoo.exceptions import ValidationError
 from odoo.tests import common
 from odoo.tools.misc import mute_logger
 
@@ -25,7 +26,7 @@ class TestCommentTemplate(common.TransactionCase):
             {
                 "name": "Top template",
                 "text": "Text before lines",
-                "model_ids": [(6, 0, cls.user_obj.ids)],
+                "models": cls.user_obj.model,
                 "company_id": cls.company.id,
             }
         )
@@ -34,7 +35,7 @@ class TestCommentTemplate(common.TransactionCase):
                 "name": "Bottom template",
                 "position": "after_lines",
                 "text": "Text after lines",
-                "model_ids": [(6, 0, cls.user_obj.ids)],
+                "models": cls.user_obj.model,
                 "company_id": cls.company.id,
             }
         )
@@ -48,6 +49,27 @@ class TestCommentTemplate(common.TransactionCase):
         teardown_test_model(cls.env, ResUsers)
         return super(TestCommentTemplate, cls).tearDownClass()
 
+    def test_template_model_ids(self):
+        self.assertIn(
+            self.user_obj.model, self.before_template_id.mapped("model_ids.model")
+        )
+        self.assertEqual(len(self.before_template_id.model_ids), 1)
+        self.assertIn(
+            self.user_obj.model, self.after_template_id.mapped("model_ids.model")
+        )
+        self.assertEqual(len(self.after_template_id.model_ids), 1)
+
+    def test_template_models_constrains(self):
+        with self.assertRaises(ValidationError):
+            self.env["base.comment.template"].create(
+                {
+                    "name": "Custom template",
+                    "text": "Text",
+                    "models": "incorrect.model",
+                    "company_id": self.company.id,
+                }
+            )
+
     def test_template_name_get(self):
         self.assertEqual(
             self.before_template_id.display_name,
diff --git a/base_comment_template/views/base_comment_template_view.xml b/base_comment_template/views/base_comment_template_view.xml
index 6def84549..04bb4e6ad 100644
--- a/base_comment_template/views/base_comment_template_view.xml
+++ b/base_comment_template/views/base_comment_template_view.xml
@@ -10,7 +10,8 @@
                 <field name="position" />
                 <field name="company_id" groups="base.group_multi_company" />
                 <field name="partner_ids" />
-                <field name="model_ids" />
+                <field name="models" />
+                <field name="model_ids" groups="base.group_erp_manager" />
                 <field name="domain" />
             </tree>
         </field>
@@ -24,7 +25,8 @@
                 <field name="position" />
                 <field name="company_id" groups="base.group_multi_company" />
                 <field name="partner_ids" />
-                <field name="model_ids" />
+                <field name="models" />
+                <field name="model_ids" groups="base.group_erp_manager" />
                 <field name="domain" />
                 <field name="sequence" />
             </search>
@@ -67,7 +69,7 @@
                                 groups="base.group_multi_company"
                             />
                             <field name="domain" />
-                            <field name="model_ids" widget="many2many_tags" />
+                            <field name="models" />
                             <field name="partner_ids" widget="many2many_tags" />
                         </group>
                     </group>