[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
This commit is contained in:
committed by
Yannick Tivisse
parent
244e4cae03
commit
5b64d252d2
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)]
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Product Tags -->
|
||||
<record id="product_tag_form_view" model="ir.ui.view">
|
||||
<field name="name">product.tag.form</field>
|
||||
<field name="model">product.tag</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Product Tag">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="product_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_tag_tree_view" model="ir.ui.view">
|
||||
<field name="name">product.tag.tree</field>
|
||||
<field name="model">product.tag</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Tags">
|
||||
<field name="name"/>
|
||||
<field name="color" widget="color_picker"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_tag_action" model="ir.actions.act_window">
|
||||
<field name="name">Product Tags</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.tag</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" eval="False"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Define a new tag
|
||||
</p><p>
|
||||
Tags are used to search product for a given theme.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -15,6 +15,7 @@
|
||||
<field name="priority" widget="priority" optional="show" nolabel="1"/>
|
||||
<field name="name" string="Product Name"/>
|
||||
<field name="default_code" optional="show"/>
|
||||
<field name="product_tag_ids" widget="many2many_tags" options="{'color_field': 'color'}" optional="show"/>
|
||||
<field name="barcode" optional="hide" attrs="{'readonly': [('product_variant_count', '>', 1)]}"/>
|
||||
<field name="company_id" options="{'no_create_edit': True}"
|
||||
groups="base.group_multi_company" optional="hide"/>
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<field name="categ_id" string="Product Category"/>
|
||||
<field name="product_tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_edit_color': 1}"/>
|
||||
<field name="company_id" groups="base.group_multi_company"
|
||||
options="{'no_create': True}"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
@@ -289,6 +290,12 @@
|
||||
context="{'tree_view_ref':'product.product_packaging_tree_view2'}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group name="tags" string="Tags">
|
||||
<field name="product_tag_ids" string="Product Template Tags" widget="many2many_tags" readonly="1" options="{'no_open': True, 'color_field': 'color'}"/>
|
||||
<field name="additional_product_tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_edit_color': 1}"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
@@ -335,6 +342,7 @@
|
||||
<field name="lst_price" optional="show" string="Sales Price"/>
|
||||
<field name="standard_price" optional="show"/>
|
||||
<field name="categ_id" optional="hide"/>
|
||||
<field name="product_tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_edit_color': 1}" optional="hide"/>
|
||||
<field name="type" optional="hide" readonly="1"/>
|
||||
<field name="uom_id" options="{'no_open': True, 'no_create': True}" groups="uom.group_uom" optional="show" readonly="1"/>
|
||||
<field name="product_tmpl_id" invisible="1" readonly="1"/>
|
||||
@@ -373,6 +381,12 @@
|
||||
<xpath expr="//div[hasclass('oe_title')]" position="inside">
|
||||
<field name="product_template_variant_value_ids" widget="many2many_tags" readonly="1" groups="product.group_product_variant"/>
|
||||
</xpath>
|
||||
<field name="product_tag_ids" position="attributes">
|
||||
<attribute name="options">{'no_open': true}</attribute>
|
||||
</field>
|
||||
<field name="product_tag_ids" position="after">
|
||||
<field name="additional_product_tag_ids" options="{'color_field': 'color', 'no_edit_color': 1}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user