diff --git a/product_template_multi_link/models/product_template.py b/product_template_multi_link/models/product_template.py index 7ef7ac37d9..6feb99a603 100644 --- a/product_template_multi_link/models/product_template.py +++ b/product_template_multi_link/models/product_template.py @@ -6,6 +6,7 @@ from odoo import _, api, fields, models from odoo.exceptions import AccessError +from odoo.osv import expression class ProductTemplate(models.Model): @@ -103,3 +104,38 @@ def get_links_by_code(self, code): return self.product_template_link_ids.filtered( lambda r: r.type_id.code == code and r.is_link_active ) + + @api.model + def _name_search( + self, name, args=None, operator="ilike", limit=100, name_get_uid=None + ): + # NOTE: Odoo limits the search on the name of templates as soon as + # the 'id' field is present in 'args' domain, and this 'id' criteria is + # set by the view on purpose to avoid a search on variants. + # Improve this search by looking also on template's default_code + # if there is only a domain on 'id'. + search_default_code = self.env.context.get("name_search_default_code") + if name and len(args or []) == 1 and args[0][0] == "id" and search_default_code: + args = expression.AND( + [ + args, + expression.OR( + [ + [("default_code", operator, name)], + [("product_variant_ids.default_code", operator, name)], + [(self._rec_name, operator, name)], + ] + ), + ] + ) + # Reset 'name' so base '_name_search' won't add '_rec_name' + # to 'args' (already added above). + # See 'odoo.models.BaseModel._name_search'. + name = "" + return super()._name_search( + name=name, + args=args, + operator=operator, + limit=limit, + name_get_uid=name_get_uid, + ) diff --git a/product_template_multi_link/tests/__init__.py b/product_template_multi_link/tests/__init__.py index 94bf0d972a..6680552b65 100644 --- a/product_template_multi_link/tests/__init__.py +++ b/product_template_multi_link/tests/__init__.py @@ -1,3 +1,4 @@ from . import test_product_template_link_type from . import test_product_template_link from . import test_product_template_linker +from . import test_product_template diff --git a/product_template_multi_link/tests/test_product_template.py b/product_template_multi_link/tests/test_product_template.py new file mode 100644 index 0000000000..6e15537997 --- /dev/null +++ b/product_template_multi_link/tests/test_product_template.py @@ -0,0 +1,114 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.tests.common import TransactionCase + + +class TestProductTemplate(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + tracking_disable=True, + # compatibility flag when you run tests on a db + # where `product_variant_multi_link` is installed. + _product_variant_link_bypass_check=True, + ) + ) + cls.product_template = cls.env["product.template"].create( + {"name": "PTL_name", "default_code": "PTL_default_code"} + ) + + def test_product_template_name_search_with_name(self): + # As soon as the value is matching the name of the template, it's working, + # with or without the domain on 'id' + product = self.env["product.template"].name_search("PTL_name") + self.assertTrue(product) + product = self.env["product.template"].name_search( + "PTL_name", args=[("id", "!=", 0)] + ) + self.assertTrue(product) + product = ( + self.env["product.template"] + .with_context(name_search_default_code=True) + .name_search("PTL_name", args=[("id", "!=", 0)]) + ) + self.assertTrue(product) + + def test_product_template_name_search_with_default_code(self): + product = self.env["product.template"].name_search("PTL_default_code") + self.assertTrue(product) + # Searching with the default_code => the template is not found + product = self.env["product.template"].name_search( + "PTL_default_code", args=[("id", "!=", 0)] + ) + self.assertFalse(product) + # Same but enable the search on default_code => the template is now found + product = ( + self.env["product.template"] + .with_context(name_search_default_code=True) + .name_search("PTL_default_code", args=[("id", "!=", 0)]) + ) + self.assertTrue(product) + + def test_product_template_multi_variants_name_search_with_default_code(self): + # Create variants + self.product_template.write( + { + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": self.env.ref( + "product.product_attribute_1" + ).id, + "value_ids": [ + ( + 6, + 0, + [ + self.env.ref( + "product.product_attribute_value_1" + ).id, + self.env.ref( + "product.product_attribute_value_2" + ).id, + ], + ) + ], + }, + ) + ], + } + ) + variant1, variant2 = self.product_template.product_variant_ids + variant1.default_code = "PV1_default_code" + variant2.default_code = "PV2_default_code" + # Odoo std behavior: search with template default code + product = self.env["product.template"].name_search("PTL_default_code") + self.assertFalse(product) + # Odoo std behavior: search with one of the variant default code + product = self.env["product.template"].name_search("PV1_default_code") + self.assertTrue(product) + # Searching with the default_code => the template is not found + product = self.env["product.template"].name_search( + "PTL_default_code", args=[("id", "!=", 0)] + ) + self.assertFalse(product) + # Same but enable the search on default_code => the template is still not found + product = ( + self.env["product.template"] + .with_context(name_search_default_code=True) + .name_search("PTL_default_code", args=[("id", "!=", 0)]) + ) + self.assertFalse(product) + # Same but with one of the variant default_code => the template is now found + product = ( + self.env["product.template"] + .with_context(name_search_default_code=True) + .name_search("PV1_default_code", args=[("id", "!=", 0)]) + ) + self.assertTrue(product) diff --git a/product_template_multi_link/views/product_template_link_view.xml b/product_template_multi_link/views/product_template_link_view.xml index 0bd28e7048..ce88b87a09 100644 --- a/product_template_multi_link/views/product_template_link_view.xml +++ b/product_template_multi_link/views/product_template_link_view.xml @@ -31,9 +31,17 @@ product.template.link - + - +