From 5b64d252d219f314934809031c4efaf1f8255f1e Mon Sep 17 00:00:00 2001 From: Thibault Libioulle Date: Thu, 4 Nov 2021 16:08:25 +0000 Subject: [PATCH] [IMP] product: add product tag model This commit adds the product tag model. Purpose ======= The product tags allows to easily tag given types of product independently from their category, following their product range, their seasonal collection, their theme, etc Specification ============= A product template takes tags that are valid for all their variants. In order to add granularity, product variants can also take additionnal tags. A field is defined on product variants to allow searching on both product template and product variant tags. task-2675384 Part-of: odoo/odoo#79296 --- addons/product/__manifest__.py | 1 + addons/product/models/__init__.py | 1 + addons/product/models/product.py | 13 +++++ addons/product/models/product_tag.py | 37 +++++++++++++++ addons/product/models/product_template.py | 2 + addons/product/security/ir.model.access.csv | 2 + addons/product/views/product_tag_views.xml | 47 +++++++++++++++++++ .../product/views/product_template_views.xml | 1 + addons/product/views/product_views.xml | 14 ++++++ 9 files changed, 118 insertions(+) create mode 100644 addons/product/models/product_tag.py create mode 100644 addons/product/views/product_tag_views.xml diff --git a/addons/product/__manifest__.py b/addons/product/__manifest__.py index 9e2e25721ca..19b7ef041c4 100644 --- a/addons/product/__manifest__.py +++ b/addons/product/__manifest__.py @@ -36,6 +36,7 @@ Print product labels with barcode. 'views/product_views.xml', 'views/product_template_views.xml', 'views/product_pricelist_views.xml', + 'views/product_tag_views.xml', 'views/res_partner_views.xml', 'report/product_reports.xml', 'report/product_product_templates.xml', diff --git a/addons/product/models/__init__.py b/addons/product/models/__init__.py index 8d4b6f309c5..617913cc420 100644 --- a/addons/product/models/__init__.py +++ b/addons/product/models/__init__.py @@ -14,6 +14,7 @@ from . import product from . import product_attribute from . import product_pricelist +from . import product_tag from . import res_company from . import res_currency from . import res_partner diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 32f652316e9..e0801ce4967 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -122,6 +122,9 @@ class ProductProduct(models.Model): 'product.packaging', 'product_id', 'Product Packages', help="Gives the different ways to package the same product.") + additional_product_tag_ids = fields.Many2many('product.tag', 'product_tag_product_product_rel') + all_product_tag_ids = fields.Many2many('product.tag', compute='_compute_all_product_tag_ids', search='_search_all_product_tag_ids') + # all image fields are base64 encoded and PIL-supported # all image_variant fields are technical and should not be displayed to the user @@ -295,6 +298,16 @@ class ProductProduct(models.Model): '&', ('product_id', '=', product.id), ('applied_on', '=', '0_product_variant')] product.pricelist_item_count = self.env['product.pricelist.item'].search_count(domain) + @api.depends('product_tag_ids', 'additional_product_tag_ids') + def _compute_all_product_tag_ids(self): + for product in self: + product.all_product_tag_ids = product.product_tag_ids | product.additional_product_tag_ids + + def _search_all_product_tag_ids(self, operator, operand): + if operator in expression.NEGATIVE_TERM_OPERATORS: + return [('product_tag_ids', operator, operand), ('additional_product_tag_ids', operator, operand)] + return ['|', ('product_tag_ids', operator, operand), ('additional_product_tag_ids', operator, operand)] + @api.onchange('uom_id') def _onchange_uom_id(self): if self.uom_id: diff --git a/addons/product/models/product_tag.py b/addons/product/models/product_tag.py new file mode 100644 index 00000000000..d37123bc0a5 --- /dev/null +++ b/addons/product/models/product_tag.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from random import randint + +from odoo import api, fields, models +from odoo.osv import expression + +class ProductTag(models.Model): + _name = 'product.tag' + _description = 'Product Tag' + + def _get_default_color(self): + return randint(1, 11) + + name = fields.Char('Tag Name', required=True, translate=True) + color = fields.Integer('Color', default=_get_default_color) + + product_template_ids = fields.Many2many('product.template', 'product_tag_product_template_rel') + product_product_ids = fields.Many2many('product.product', 'product_tag_product_product_rel') + product_ids = fields.Many2many( + 'product.product', string='All Product Variants using this Tag', + compute='_compute_product_ids', search='_search_product_ids' + ) + + _sql_constraints = [ + ('name_uniq', 'unique (name)', "Tag name already exists !"), + ] + + @api.depends('product_template_ids', 'product_product_ids') + def _compute_product_ids(self): + for tag in self: + tag.product_ids = tag.product_template_ids.product_variant_ids | tag.product_product_ids + + def _search_product_ids(self, operator, operand): + if operator in expression.NEGATIVE_TERM_OPERATORS: + return [('product_template_ids.product_variant_ids', operator, operand), ('product_product_ids', operator, operand)] + return ['|', ('product_template_ids.product_variant_ids', operator, operand), ('product_product_ids', operator, operand)] diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index afb86b64baa..4c4b831e362 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -140,6 +140,8 @@ class ProductTemplate(models.Model): ('1', 'Favorite'), ], default='0', string="Favorite") + product_tag_ids = fields.Many2many('product.tag', 'product_tag_product_template_rel', string='Product Tags') + def _compute_item_count(self): for template in self: # Pricelist item count counts the rules applicable on current template or on its variants. diff --git a/addons/product/security/ir.model.access.csv b/addons/product/security/ir.model.access.csv index 275b5510210..dd5a40f86fd 100644 --- a/addons/product/security/ir.model.access.csv +++ b/addons/product/security/ir.model.access.csv @@ -13,6 +13,7 @@ access_product_attribute_custom_value_user,product.attribute.custom value manage access_product_product_attribute,product.template.attribute value,model_product_template_attribute_value,base.group_user,1,0,0,0 access_product_template_attribute_exclusion,product..template.attribute exclusion,model_product_template_attribute_exclusion,base.group_user,1,0,0,0 access_product_template_attribute_line,product.template.attribute line,model_product_template_attribute_line,base.group_user,1,0,0,0 +access_product_tag_user,product.tag.user,model_product_tag,base.group_user,1,0,0,0 access_product_category_manager,product.category.manager,model_product_category,base.group_system,1,1,1,1 access_product_template_manager,product.template.manager,model_product_template,base.group_system,1,1,1,1 access_product_packaging_manager,product.packaging.manager,model_product_packaging,base.group_system,1,1,1,1 @@ -27,3 +28,4 @@ access_product_product_attribute_manager,product.template.attribute value manage access_product_template_attribute_exclusion_manager,product.template.attribute exclusion manager,model_product_template_attribute_exclusion,base.group_system,1,1,1,1 access_product_template_attribute_line_manager,product.template.attribute line manager,model_product_template_attribute_line,base.group_system,1,1,1,1 access_product_label_layout_user,product.label.layout.user,model_product_label_layout,base.group_system,1,1,1,1 +access_product_tag_manager,product.tag.manager,model_product_tag,base.group_system,1,1,1,1 diff --git a/addons/product/views/product_tag_views.xml b/addons/product/views/product_tag_views.xml new file mode 100644 index 00000000000..84fd3d76028 --- /dev/null +++ b/addons/product/views/product_tag_views.xml @@ -0,0 +1,47 @@ + + + + + product.tag.form + product.tag + +
+ + + + + + + + + + + +
+
+
+ + product.tag.tree + product.tag + + + + + + + + + Product Tags + ir.actions.act_window + product.tag + tree,form + + +

+ Define a new tag +

+ Tags are used to search product for a given theme. +

+
+
+
diff --git a/addons/product/views/product_template_views.xml b/addons/product/views/product_template_views.xml index 60947ea1aa5..bf2bbf875d4 100644 --- a/addons/product/views/product_template_views.xml +++ b/addons/product/views/product_template_views.xml @@ -15,6 +15,7 @@ + diff --git a/addons/product/views/product_views.xml b/addons/product/views/product_views.xml index 592b4a45012..f9e2975ee81 100644 --- a/addons/product/views/product_views.xml +++ b/addons/product/views/product_views.xml @@ -87,6 +87,7 @@ + @@ -289,6 +290,12 @@ context="{'tree_view_ref':'product.product_packaging_tree_view2'}"/> + + + + + + @@ -335,6 +342,7 @@ + @@ -373,6 +381,12 @@ + + {'no_open': true} + + + +