diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 7017e17f177..ac10f1ee083 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -546,14 +546,22 @@ class ProductTemplate(models.Model): searched_ids = set(templates.ids) # some product.templates do not have product.products yet (dynamic variants configuration), # we need to add the base _name_search to the results - # FIXME awa: this is really not performant at all but after discussing with the team - # we don't see another way to do it - tmpl_without_variant = self.browse() - if not limit or len(searched_ids) < limit: - tmpl_with_variant_ids = self._search([('product_variant_ids.active', '=', True)]) - tmpl_without_variant = self.search([('id', 'not in', tmpl_with_variant_ids)]) - if tmpl_without_variant: - domain2 = expression.AND([domain, [('id', 'in', tmpl_without_variant.ids)]]) + tmpl_without_variant_ids = [] + # Useless if variants is not set up as no tmpl_without_variant_ids could exist. + if self.env.user.has_group('product.group_product_variant') and (not limit or len(searched_ids) < limit): + # The ORM has to be bypassed because it would require a NOT IN which is inefficient. + self.env['product.product'].flush_model(['product_tmpl_id', 'active']) + tmpl_without_variant_ids = self.env['product.template']._search([], order='id') + tmpl_without_variant_ids.add_where(""" + NOT EXISTS ( + SELECT product_tmpl_id + FROM product_product + WHERE product_product.active = true + AND product_template.id = product_product.product_tmpl_id + ) + """) + if tmpl_without_variant_ids: + domain2 = expression.AND([domain, [('id', 'in', tmpl_without_variant_ids)]]) searched_ids |= set(super()._name_search(name, domain2, operator, limit, order)) # re-apply product.template order + display_name diff --git a/addons/product/tests/test_name.py b/addons/product/tests/test_name.py index d2f643df036..d168118383c 100644 --- a/addons/product/tests/test_name.py +++ b/addons/product/tests/test_name.py @@ -29,3 +29,28 @@ class TestName(TransactionCase): res = self.env['product.template'].name_search(name='PTN', operator='not ilike') res_ids = [r[0] for r in res] self.assertNotIn(self.product.id, res_ids) + + def test_product_template_search_name_no_product_product(self): + color_attr = self.env['product.attribute'].create({'name': 'Color', 'create_variant': 'dynamic'}) + color_attr_value_r = self.env['product.attribute.value'].create({'name': 'Red', 'attribute_id': color_attr.id}) + color_attr_value_b = self.env['product.attribute.value'].create({'name': 'Blue', 'attribute_id': color_attr.id}) + template_dyn = self.env['product.template'].create({ + 'name': 'Test Dynamical', + 'attribute_line_ids': [(0, 0, { + 'attribute_id': color_attr.id, + 'value_ids': [(4, color_attr_value_r.id), (4, color_attr_value_b.id)], + })] + }) + product = self.env['product.product'].create({ + 'name': 'Dynamo Lamp', + 'default_code': 'Dynamo', + }) + self.assertTrue(template_dyn.has_dynamic_attributes()) + # Ensure that template_dyn hasn't any product_product + self.assertEqual(len(template_dyn.product_variant_ids), 0) + # Ensure that Dynam search return Dynamo and Test Dynamical as this + # last have no product_product + res = self.env['product.template'].name_search(name='Dynam', operator='ilike') + res_ids = [r[0] for r in res] + self.assertIn(template_dyn.id, res_ids) + self.assertIn(product.product_tmpl_id.id, res_ids)