diff --git a/document_page_tag/models/document_page_tag.py b/document_page_tag/models/document_page_tag.py index a1584e1b2cf..90f1cdb4b18 100644 --- a/document_page_tag/models/document_page_tag.py +++ b/document_page_tag/models/document_page_tag.py @@ -1,20 +1,53 @@ # Copyright 2015-2018 Therp BV # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError class DocumentPageTag(models.Model): _name = "document.page.tag" _description = "A keyword for document pages" + _parent_store = True name = fields.Char(required=True, translate=True) color = fields.Integer(string="Color Index") active = fields.Boolean(default=True) + parent_id = fields.Many2one( + "document.page.tag", string="Parent Tag", index=True, ondelete="restrict" + ) + child_ids = fields.One2many("document.page.tag", "parent_id", string="Child Tags") + parent_path = fields.Char(index=True) _sql_constraints = [ ("unique_name", "unique(name)", "Tags must be unique"), ] + @api.constrains("parent_id") + def _check_parent_id(self): + if self._has_cycle(): # pragma: no cover + raise ValidationError(_("You can not create recursive tags.")) + + def _get_hierarchy_name(self): + self.ensure_one() + names = [] + tag = self + while tag: + names.append(tag.name or "") + tag = tag.parent_id + return " / ".join(reversed(names)) + + @api.depends("parent_id") + def _compute_display_name(self): + for tag in self: + tag.display_name = tag._get_hierarchy_name() + + @api.model + def _search_display_name(self, operator, value): + domain = super()._search_display_name(operator, value) + if operator.endswith("like"): + return [("id", "child_of", self._search(list(domain)))] + return domain + @api.model_create_multi def create(self, vals_list): """Be nice when trying to create duplicates""" diff --git a/document_page_tag/tests/test_document_page_tag.py b/document_page_tag/tests/test_document_page_tag.py index 30d0d8fd5fb..951cfc5194e 100644 --- a/document_page_tag/tests/test_document_page_tag.py +++ b/document_page_tag/tests/test_document_page_tag.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from psycopg2 import IntegrityError +from odoo.exceptions import UserError from odoo.tests.common import TransactionCase from odoo.tools.misc import mute_logger @@ -20,3 +21,36 @@ def test_document_page_tag(self): testtag2 = self.env["document.page.tag"].create({"name": "test2"}) testtag2.write({"name": "test"}) testtag2.flush_model() + + def test_document_page_tag_recursion(self): + tag_a = self.env["document.page.tag"].create({"name": "tag a"}) + tag_b = self.env["document.page.tag"].create( + {"name": "tag b", "parent_id": tag_a.id} + ) + # native anti-recursion check from _parent_store + with self.assertRaises(UserError): + tag_a.parent_id = tag_b.id + + def test_document_page_tag_display_name_hierarchy(self): + tag_a = self.env["document.page.tag"].create({"name": "tag a"}) + tag_b = self.env["document.page.tag"].create( + {"name": "tag b", "parent_id": tag_a.id} + ) + self.assertEqual(tag_b.display_name, "tag a / tag b") + + def test_document_page_tag_search_display_name(self): + tag_a = self.env["document.page.tag"].create({"name": "tag a"}) + tag_b = self.env["document.page.tag"].create( + {"name": "tag b", "parent_id": tag_a.id} + ) + found = self.env["document.page.tag"].search( + [("display_name", "ilike", "tag a")] + ) + self.assertIn(tag_a, found) + self.assertIn(tag_b, found) + + def test_document_page_tag_search_display_name_exact(self): + # covers the non-"like" operator branch (no child_of expansion) + tag_a = self.env["document.page.tag"].create({"name": "tag a"}) + found = self.env["document.page.tag"].search([("display_name", "=", "tag a")]) + self.assertEqual(found, tag_a) diff --git a/document_page_tag/views/document_page_tag.xml b/document_page_tag/views/document_page_tag.xml index 84030347064..ff1982c6bad 100644 --- a/document_page_tag/views/document_page_tag.xml +++ b/document_page_tag/views/document_page_tag.xml @@ -12,6 +12,13 @@ /> + + + @@ -38,6 +45,7 @@ + @@ -49,8 +57,9 @@ document.page.tag.tree document.page.tag - + +