From 19b7692ee8a0239b1b2c5a0e14b0938d57788dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Thu, 22 Apr 2021 18:04:48 +0200 Subject: [PATCH] [IMP] base_comment_template: Refactor code and convert to Many2Many --- .../migrations/13.0.1.0.0/pre-migration.py | 22 +++ .../migrations/13.0.2.0.0/pre-migration.py | 12 ++ .../migrations/14.0.1.0.0/pre-migration.py | 26 --- base_comment_template/models/__init__.py | 1 + .../models/base_comment_template.py | 151 +++--------------- .../models/comment_template.py | 45 ++++++ base_comment_template/models/res_partner.py | 11 +- .../tests/test_base_comment_template.py | 151 ++++-------------- .../views/base_comment_template_view.xml | 6 +- .../views/res_partner_view.xml | 19 ++- 10 files changed, 167 insertions(+), 277 deletions(-) create mode 100644 base_comment_template/migrations/13.0.1.0.0/pre-migration.py create mode 100644 base_comment_template/migrations/13.0.2.0.0/pre-migration.py delete mode 100644 base_comment_template/migrations/14.0.1.0.0/pre-migration.py create mode 100644 base_comment_template/models/comment_template.py diff --git a/base_comment_template/migrations/13.0.1.0.0/pre-migration.py b/base_comment_template/migrations/13.0.1.0.0/pre-migration.py new file mode 100644 index 00000000..edac6891 --- /dev/null +++ b/base_comment_template/migrations/13.0.1.0.0/pre-migration.py @@ -0,0 +1,22 @@ +# Copyright 2020 NextERP Romania SRL +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + # Not tested + openupgrade.logged_query( + env.cr, + """ + INSERT INTO base_comment_template_res_partner_rel + (res_partner_id, base_comment_template_id) + SELECT SPLIT_PART(ip.res_id, ',', 2)::int AS res_partner_id, + SPLIT_PART(ip.value_reference, ',', 2)::int AS base_comment_template_id + FROM ir_property ip + JOIN ir_model_fields imf ON ip.fields_id = imf.id + WHERE imf.name = 'property_comment_template_id' + AND imf.model = 'res.partner' + """, + ) diff --git a/base_comment_template/migrations/13.0.2.0.0/pre-migration.py b/base_comment_template/migrations/13.0.2.0.0/pre-migration.py new file mode 100644 index 00000000..a80f06fc --- /dev/null +++ b/base_comment_template/migrations/13.0.2.0.0/pre-migration.py @@ -0,0 +1,12 @@ +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openupgradelib import openupgrade # pylint: disable=W7936 + +field_renames = [ + ("base.comment.template", "base_comment_template", "priority", "sequence"), +] + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.rename_fields(env, field_renames) diff --git a/base_comment_template/migrations/14.0.1.0.0/pre-migration.py b/base_comment_template/migrations/14.0.1.0.0/pre-migration.py deleted file mode 100644 index fd5a0c1c..00000000 --- a/base_comment_template/migrations/14.0.1.0.0/pre-migration.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2020 NextERP Romania SRL -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - # Not tested - properties = env["ir.property"].search( - [ - ( - "fields_id", - "=", - env.ref("base.field_res_partner_property_comment_template_id").id, - ) - ] - ) - if properties: - for template in properties.mapped("value_reference"): - template_id = template.value_reference.split(",")[-1] - if template_id: - template = env["base.comment.template"].browse(template_id) - part_prop = properties.filtered(lambda p: p.value_reference == template) - template.partner_ids = [ - (prop["res_id"] or "").split(",")[-1] for prop in part_prop - ] diff --git a/base_comment_template/models/__init__.py b/base_comment_template/models/__init__.py index 4d140780..d695c580 100644 --- a/base_comment_template/models/__init__.py +++ b/base_comment_template/models/__init__.py @@ -1,3 +1,4 @@ from . import base_comment_template +from . import comment_template from . import res_partner from . import ir_model diff --git a/base_comment_template/models/base_comment_template.py b/base_comment_template/models/base_comment_template.py index 721e4e0f..92d86807 100644 --- a/base_comment_template/models/base_comment_template.py +++ b/base_comment_template/models/base_comment_template.py @@ -1,76 +1,9 @@ # 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 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from lxml import etree - -from odoo import _, api, fields, models -from odoo.exceptions import ValidationError -from odoo.tools.safe_eval import safe_eval - - -class CommentTemplate(models.AbstractModel): - _name = "comment.template" - _description = ( - "base.comment.template to put header and footer " - "in reports based on created comment templates" - ) - - def get_comment_template_records( - self, position="before_lines", company_id=False, partner_id=False - ): - self.ensure_one() - if not company_id: - company_id = self.env.company.id - present_model_id = self.env["ir.model"].search([("model", "=", self._name)]) - default_dom = [ - ("model_ids", "in", present_model_id.id), - ("position", "=", position), - ] - lang = False - if partner_id and "partner_id" in self._fields: - default_dom += [ - "|", - ("partner_ids", "=", False), - ("partner_ids", "in", partner_id), - ] - lang = self.env["res.partner"].browse(partner_id).lang - if company_id and "company_id" in self._fields: - if partner_id and "partner_id" in self._fields: - default_dom.insert(-3, "&") - default_dom += [ - "|", - ("company_id", "=", company_id), - ("company_id", "=", False), - ] - templates = self.env["base.comment.template"].search( - default_dom, order="priority" - ) - if lang: - templates = templates.with_context({"lang": lang}) - return templates - - def get_comment_template( - self, position="before_lines", company_id=False, partner_id=False - ): - """ Method that is called from report xml and is returning the - position template as a html if exists - """ - self.ensure_one() - templates = self.get_comment_template_records( - position=position, company_id=company_id, partner_id=partner_id - ) - template = False - if templates: - for templ in templates: - if self in self.search(safe_eval(templ.domain or "[]")): - template = templ - break - if not template: - return "" - return self.env["mail.template"]._render_template( - template.text, self._name, self.id, post_process=True - ) +from odoo import fields, models class BaseCommentTemplate(models.Model): @@ -78,11 +11,12 @@ class BaseCommentTemplate(models.Model): _name = "base.comment.template" _description = "Comments Template" + _order = "sequence,id" active = fields.Boolean(default=True) position = fields.Selection( string="Position on document", - selection=[("before_lines", "Before lines"), ("after_lines", "After lines")], + selection=[("before_lines", "Top"), ("after_lines", "Bottom")], required=True, default="before_lines", help="This field allows to select the position of the comment on reports.", @@ -101,7 +35,7 @@ class BaseCommentTemplate(models.Model): help="This is the text template that will be inserted into reports.", ) company_id = fields.Many2one( - "res.company", + comodel_name="res.company", string="Company", ondelete="cascade", index=True, @@ -110,79 +44,46 @@ class BaseCommentTemplate(models.Model): ) partner_ids = fields.Many2many( comodel_name="res.partner", + relation="base_comment_template_res_partner_rel", + column1="res_partner_id", + column2="base_comment_template_id", string="Partner", - ondelete="cascade", + readonly=True, help="If set, the comment template will be available only for the selected " "partner.", ) - model_ids = fields.Many2many( comodel_name="ir.model", 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.", ) - domain = fields.Char( - "Filter Domain", + string="Filter Domain", required=True, default="[]", help="This comment template will be available only for objects " "that satisfy the condition", ) - - priority = fields.Integer( - default=10, copy=False, help="the highest priority = the smallest number", + sequence = fields.Integer( + required=True, default=10, help="The smaller number = The higher priority" ) - @api.constrains("domain", "priority", "model_ids", "position") - def _check_partners_in_company_id(self): - templates = self.search([]) - for record in self: - other_template_same_models_and_priority = templates.filtered( - lambda t: t.priority == record.priority - and set(record.model_ids).intersection(record.model_ids) - and t.domain == record.domain - and t.position == record.position - and t.id != record.id + def name_get(self): + """Redefine the name_get method to show the template name with the position. + """ + res = [] + for item in self: + name = "{} ({})".format( + item.name, dict(self._fields["position"].selection).get(item.position) ) - if other_template_same_models_and_priority: - raise ValidationError( - _( - "There are other records with same models, priority, " - "domain and position." - ) - ) - - @api.model - def fields_view_get( - self, view_id=None, view_type="form", toolbar=False, submenu=False - ): - # modify the form view of base_commnent_template - # Add domain on model_id to get only models that have a report set - # and those whom have inherited this model - res = super().fields_view_get( - view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu - ) - if view_type == "form": - doc = etree.XML(res["arch"]) - for node in doc.xpath("//field[@name='model_ids']"): - report_models = self.env["ir.actions.report"].search([]).mapped("model") - model_ids = ( - self.env["ir.model"] - .search( - [ - ("model", "in", report_models), - ("is_comment_template", "=", True), - "!", - ("name", "=like", "ir.%"), - ] - ) - .ids - ) - model_filter = "[('id','in'," + str(model_ids) + ")]" - node.set("domain", model_filter) - res["arch"] = etree.tostring(doc, encoding="unicode") + if self.env.context.get("comment_template_model_display"): + name += " (%s)" % ", ".join(item.model_ids.mapped("name")) + res.append((item.id, name)) return res diff --git a/base_comment_template/models/comment_template.py b/base_comment_template/models/comment_template.py new file mode 100644 index 00000000..465e6ddc --- /dev/null +++ b/base_comment_template/models/comment_template.py @@ -0,0 +1,45 @@ +# 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 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models +from odoo.tools.safe_eval import safe_eval + + +class CommentTemplate(models.AbstractModel): + _name = "comment.template" + _description = ( + "base.comment.template to put header and footer " + "in reports based on created comment templates" + ) + # This field allows to set any given field that determines the source partner for + # the comment templates downstream. + # E.g.: other models where the partner field is called customer_id. + _comment_template_partner_field_name = "partner_id" + + comment_template_ids = fields.Many2many( + compute="_compute_comment_template_ids", + comodel_name="base.comment.template", + string="Comment Template", + domain=lambda self: [("model_ids.model", "=", self._name)], + store=True, + readonly=False, + ) + + @api.depends(_comment_template_partner_field_name) + def _compute_comment_template_ids(self): + 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), + ] + ) + for template in templates: + if not template.domain or self in self.search( + safe_eval(template.domain) + ): + record.comment_template_ids = [(4, template.id)] diff --git a/base_comment_template/models/res_partner.py b/base_comment_template/models/res_partner.py index 0f612496..9d9b1c60 100644 --- a/base_comment_template/models/res_partner.py +++ b/base_comment_template/models/res_partner.py @@ -1,7 +1,8 @@ # Copyright 2020 NextERP Romania SRL +# Copyright 2021 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 class ResPartner(models.Model): @@ -9,6 +10,14 @@ class ResPartner(models.Model): base_comment_template_ids = fields.Many2many( comodel_name="base.comment.template", + relation="base_comment_template_res_partner_rel", + column1="base_comment_template_id", + column2="res_partner_id", string="Comment Templates", help="Specific partner comments that can be included in reports", ) + + @api.model + def _commercial_fields(self): + """Add comment templates to commercial fields""" + return super()._commercial_fields() + ["base_comment_template_ids"] diff --git a/base_comment_template/tests/test_base_comment_template.py b/base_comment_template/tests/test_base_comment_template.py index acf0fd76..c191546e 100644 --- a/base_comment_template/tests/test_base_comment_template.py +++ b/base_comment_template/tests/test_base_comment_template.py @@ -1,8 +1,6 @@ # Copyright 2020 NextERP Romania SRL # Copyright 2021 Tecnativa - Víctor Martínez # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from lxml import etree - from odoo.tests import common from .fake_models import ResUsers, setup_test_model, teardown_test_model @@ -25,147 +23,68 @@ class TestCommentTemplate(common.SavepointCase): cls.company = cls.env["res.company"].create({"name": "Test company"}) cls.before_template_id = cls.env["base.comment.template"].create( { - "name": "before_lines", + "name": "Top template", "text": "Text before lines", "model_ids": [(6, 0, cls.user_obj.ids)], - "priority": 5, - "company_id": cls.main_company.id, + "company_id": cls.company.id, } ) cls.after_template_id = cls.env["base.comment.template"].create( { - "name": "after_lines", + "name": "Bottom template", "position": "after_lines", "text": "Text after lines", "model_ids": [(6, 0, cls.user_obj.ids)], - "priority": 6, - "company_id": cls.main_company.id, + "company_id": cls.company.id, } ) + cls.user.partner_id.base_comment_template_ids = [ + (4, cls.before_template_id.id), + (4, cls.after_template_id.id), + ] @classmethod def tearDownClass(cls): teardown_test_model(cls.env, ResUsers) super(TestCommentTemplate, cls).tearDownClass() + def test_template_name_get(self): + self.assertEqual( + self.before_template_id.display_name, "Top template (Top)", + ) + self.assertEqual( + self.after_template_id.display_name, "Bottom template (Bottom)", + ) + def test_general_template(self): + # Need to force _compute because only trigger when partner_id have changed + self.user._compute_comment_template_ids() # Check getting default comment template - templ = self.user.get_comment_template("before_lines") - self.assertEqual(templ, "Text before lines") - templ = self.user.get_comment_template("after_lines") - self.assertEqual(templ, "Text after lines") - - def test_company_general_template(self): - # Check getting default comment template company - self.before_template_id.company_id = self.company - templ = self.user.get_comment_template("before_lines") - self.assertEqual(templ, "") - templ = self.user.get_comment_template( - "before_lines", company_id=self.company.id - ) - self.assertEqual(templ, "Text before lines") - templ = self.user.get_comment_template("after_lines") - self.assertEqual(templ, "Text after lines") + self.assertTrue(self.before_template_id in self.user.comment_template_ids) + self.assertTrue(self.after_template_id in self.user.comment_template_ids) def test_partner_template(self): - # Check getting the comment template if partner is set - self.before_template_id.partner_ids = self.partner2_id.ids - templ = self.user.get_comment_template( - "before_lines", partner_id=self.partner2_id.id + self.partner2_id.base_comment_template_ids = [ + (4, self.before_template_id.id), + (4, self.after_template_id.id), + ] + self.assertTrue( + self.before_template_id in self.partner2_id.base_comment_template_ids ) - self.assertEqual(templ, "Text before lines") - templ = self.user.get_comment_template( - "before_lines", partner_id=self.partner_id.id + self.assertTrue( + self.after_template_id in self.partner2_id.base_comment_template_ids ) - self.assertEqual(templ, "") - templ = self.user.get_comment_template("after_lines") - self.assertEqual(templ, "Text after lines") def test_partner_template_domain(self): # Check getting the comment template if domain is set - self.before_template_id.partner_ids = self.partner2_id.ids + self.partner2_id.base_comment_template_ids = [ + (4, self.before_template_id.id), + (4, self.after_template_id.id), + ] self.before_template_id.domain = "[('id', 'in', %s)]" % self.user.ids - templ = self.user.get_comment_template( - "before_lines", partner_id=self.partner2_id.id - ) - self.assertEqual(templ, "Text before lines") - templ = self.user2.get_comment_template( - "before_lines", partner_id=self.partner_id.id - ) - self.assertEqual(templ, "") - - def test_company_partner_template_domain(self): - # Check getting the comment template with company and if domain is set - self.before_template_id.company_id = self.company - templ = self.user.get_comment_template("before_lines") - self.assertEqual(templ, "") - templ = self.user.get_comment_template( - "before_lines", company_id=self.company.id - ) - self.assertEqual(templ, "Text before lines") - self.before_template_id.partner_ids = self.partner2_id.ids - self.before_template_id.domain = "[('id', 'in', %s)]" % self.user.ids - templ = self.user.get_comment_template( - "before_lines", partner_id=self.partner2_id.id - ) - self.assertEqual(templ, "") - self.before_template_id.company_id = self.env.user.company_id - templ = self.user.get_comment_template( - "before_lines", partner_id=self.partner2_id.id - ) - self.assertEqual(templ, "Text before lines") - templ = self.user2.get_comment_template( - "before_lines", partner_id=self.partner2_id.id - ) - self.assertEqual(templ, "") - - def test_priority(self): - # Check setting default template will change previous record default - new_template = self.env["base.comment.template"].create( - { - "name": "before_lines", - "text": "Text before lines 1", - "model_ids": [(6, 0, self.user_obj.ids)], - "priority": 2, - } - ) - - self.assertEqual(new_template.text, "Text before lines 1") - - def test_check_partners_in_company_id(self): - """ should rise any error because exist the same model, - domain, position and priority""" - with self.assertRaises(Exception) as context: - self.before_template_id_2 = self.env["base.comment.template"].create( - { - "name": "before_lines", - "text": "Text before lines", - "model_ids": [(6, 0, self.user_obj.ids)], - "priority": 5, - } - ) self.assertTrue( - "There are other records with same models, priority, domain and position." - == context.exception.args[0] + self.before_template_id in self.partner2_id.base_comment_template_ids ) - - # should not rise any error - self.before_template_id_3 = self.env["base.comment.template"].create( - { - "name": "before_lines", - "text": "Text before lines", - "model_ids": [(6, 0, self.user_obj.ids)], - "priority": 55, - } + self.assertTrue( + self.before_template_id not in self.partner_id.base_comment_template_ids ) - - def test_fields_view_get( - self, view_id=None, view_type="form", toolbar=False, submenu=False - ): - bf_tmp_form_view = self.before_template_id.fields_view_get() - if view_type == "form": - doc = etree.XML(bf_tmp_form_view["arch"]) - model_ids = doc.xpath("//field[@name='model_ids']") - domain = model_ids[0].attrib["domain"] - # if domain exist means that the filtering is done and the function is ok - self.assertTrue(domain != "") diff --git a/base_comment_template/views/base_comment_template_view.xml b/base_comment_template/views/base_comment_template_view.xml index ab5b9732..79b4979a 100644 --- a/base_comment_template/views/base_comment_template_view.xml +++ b/base_comment_template/views/base_comment_template_view.xml @@ -5,13 +5,13 @@ base.comment.template + - @@ -26,7 +26,7 @@ - + @@ -58,9 +58,9 @@ name="company_id" groups="base.group_multi_company" /> + - diff --git a/base_comment_template/views/res_partner_view.xml b/base_comment_template/views/res_partner_view.xml index 74b19e52..d1fd4c7c 100644 --- a/base_comment_template/views/res_partner_view.xml +++ b/base_comment_template/views/res_partner_view.xml @@ -6,14 +6,21 @@ + context="{'comment_template_model_display': True}" + > + + + + + + + +