103 lines
4.3 KiB
Python
103 lines
4.3 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from random import randint
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class ProductAttributeValue(models.Model):
|
|
_name = 'product.attribute.value'
|
|
# if you change this _order, keep it in sync with the method
|
|
# `_sort_key_variant` in `product.template'
|
|
_order = 'attribute_id, sequence, id'
|
|
_description = "Attribute Value"
|
|
|
|
def _get_default_color(self):
|
|
return randint(1, 11)
|
|
|
|
name = fields.Char(string="Value", required=True, translate=True)
|
|
sequence = fields.Integer(string="Sequence", help="Determine the display order", index=True)
|
|
attribute_id = fields.Many2one(
|
|
comodel_name='product.attribute',
|
|
string="Attribute",
|
|
help="The attribute cannot be changed once the value is used on at least one product.",
|
|
ondelete='cascade',
|
|
required=True,
|
|
index=True)
|
|
|
|
pav_attribute_line_ids = fields.Many2many(
|
|
comodel_name='product.template.attribute.line',
|
|
relation='product_attribute_value_product_template_attribute_line_rel',
|
|
string="Lines",
|
|
copy=False)
|
|
is_used_on_products = fields.Boolean(
|
|
string="Used on Products", compute='_compute_is_used_on_products')
|
|
|
|
is_custom = fields.Boolean(
|
|
string="Is custom value",
|
|
help="Allow users to input custom values for this attribute value")
|
|
html_color = fields.Char(
|
|
string="Color",
|
|
help="Here you can set a specific HTML color index (e.g. #ff0000)"
|
|
" to display the color if the attribute type is 'Color'.")
|
|
display_type = fields.Selection(related='attribute_id.display_type')
|
|
color = fields.Integer(string="Color Index", default=_get_default_color)
|
|
|
|
_sql_constraints = [
|
|
('value_company_uniq',
|
|
'unique (name, attribute_id)',
|
|
"You cannot create two values with the same name for the same attribute.")
|
|
]
|
|
|
|
@api.depends('pav_attribute_line_ids')
|
|
def _compute_is_used_on_products(self):
|
|
for pav in self:
|
|
pav.is_used_on_products = bool(pav.pav_attribute_line_ids)
|
|
|
|
def name_get(self):
|
|
"""Override because in general the name of the value is confusing if it
|
|
is displayed without the name of the corresponding attribute.
|
|
Eg. on product list & kanban views, on BOM form view
|
|
|
|
However during variant set up (on the product template form) the name of
|
|
the attribute is already on each line so there is no need to repeat it
|
|
on every value.
|
|
"""
|
|
if not self.env.context.get('show_attribute', True):
|
|
return super().name_get()
|
|
return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self]
|
|
|
|
def write(self, values):
|
|
if 'attribute_id' in values:
|
|
for pav in self:
|
|
if pav.attribute_id.id != values['attribute_id'] and pav.is_used_on_products:
|
|
raise UserError(_(
|
|
"You cannot change the attribute of the value %(value)s because it is used"
|
|
" on the following products: %(products)s",
|
|
value=pav.display_name,
|
|
products=", ".join(pav.pav_attribute_line_ids.product_tmpl_id.mapped('display_name')),
|
|
))
|
|
|
|
invalidate = 'sequence' in values and any(record.sequence != values['sequence'] for record in self)
|
|
res = super().write(values)
|
|
if invalidate:
|
|
# prefetched o2m have to be resequenced
|
|
# (eg. product.template.attribute.line: value_ids)
|
|
self.env.flush_all()
|
|
self.env.invalidate_all()
|
|
return res
|
|
|
|
@api.ondelete(at_uninstall=False)
|
|
def _unlink_except_used_on_product(self):
|
|
for pav in self:
|
|
if pav.is_used_on_products:
|
|
raise UserError(_(
|
|
"You cannot delete the value %(value)s because it is used on the following products:\n%(products)s",
|
|
value=pav.display_name,
|
|
products=", ".join(pav.pav_attribute_line_ids.product_tmpl_id.mapped('display_name')),
|
|
))
|
|
|
|
def _without_no_variant_attributes(self):
|
|
return self.filtered(lambda pav: pav.attribute_id.create_variant != 'no_variant')
|