[CLN] product: style pass on split files
closes odoo/odoo#113612 Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
@@ -12,14 +11,13 @@ class ProductAttribute(models.Model):
|
||||
# `_sort_key_attribute_value` in `product.template`
|
||||
_order = 'sequence, id'
|
||||
|
||||
name = fields.Char('Attribute', required=True, translate=True)
|
||||
value_ids = fields.One2many('product.attribute.value', 'attribute_id', 'Values', copy=True)
|
||||
sequence = fields.Integer('Sequence', help="Determine the display order", index=True)
|
||||
attribute_line_ids = fields.One2many('product.template.attribute.line', 'attribute_id', 'Lines')
|
||||
create_variant = fields.Selection([
|
||||
('always', 'Instantly'),
|
||||
('dynamic', 'Dynamically'),
|
||||
('no_variant', 'Never (option)')],
|
||||
name = fields.Char(string="Attribute", required=True, translate=True)
|
||||
create_variant = fields.Selection(
|
||||
selection=[
|
||||
('always', 'Instantly'),
|
||||
('dynamic', 'Dynamically'),
|
||||
('no_variant', 'Never (option)'),
|
||||
],
|
||||
default='always',
|
||||
string="Variants Creation Mode",
|
||||
help="""- Instantly: All possible variants are created as soon as the attribute and its values are added to a product.
|
||||
@@ -27,13 +25,33 @@ class ProductAttribute(models.Model):
|
||||
- Never: Variants are never created for the attribute.
|
||||
Note: the variants creation mode cannot be changed once the attribute is used on at least one product.""",
|
||||
required=True)
|
||||
display_type = fields.Selection(
|
||||
selection=[
|
||||
('radio', 'Radio'),
|
||||
('pills', 'Pills'),
|
||||
('select', 'Select'),
|
||||
('color', 'Color'),
|
||||
],
|
||||
default='radio',
|
||||
required=True,
|
||||
help="The display type used in the Product Configurator.")
|
||||
sequence = fields.Integer(string="Sequence", help="Determine the display order", index=True)
|
||||
|
||||
value_ids = fields.One2many(
|
||||
comodel_name='product.attribute.value',
|
||||
inverse_name='attribute_id',
|
||||
string="Values", copy=True)
|
||||
|
||||
attribute_line_ids = fields.One2many(
|
||||
comodel_name='product.template.attribute.line',
|
||||
inverse_name='attribute_id',
|
||||
string="Lines")
|
||||
product_tmpl_ids = fields.Many2many(
|
||||
comodel_name='product.template',
|
||||
string="Related Products",
|
||||
compute='_compute_products',
|
||||
store=True)
|
||||
number_related_products = fields.Integer(compute='_compute_number_related_products')
|
||||
product_tmpl_ids = fields.Many2many('product.template', string="Related Products", compute='_compute_products', store=True)
|
||||
display_type = fields.Selection([
|
||||
('radio', 'Radio'),
|
||||
('pills', 'Pills'),
|
||||
('select', 'Select'),
|
||||
('color', 'Color')], default='radio', required=True, help="The display type used in the Product Configurator.")
|
||||
|
||||
@api.depends('product_tmpl_ids')
|
||||
def _compute_number_related_products(self):
|
||||
@@ -59,12 +77,14 @@ class ProductAttribute(models.Model):
|
||||
if 'create_variant' in vals:
|
||||
for pa in self:
|
||||
if vals['create_variant'] != pa.create_variant and pa.number_related_products:
|
||||
raise UserError(
|
||||
_("You cannot change the Variants Creation Mode of the attribute %s because it is used on the following products:\n%s") %
|
||||
(pa.display_name, ", ".join(pa.product_tmpl_ids.mapped('display_name')))
|
||||
)
|
||||
raise UserError(_(
|
||||
"You cannot change the Variants Creation Mode of the attribute %(attribute)s"
|
||||
" because it is used on the following products:\n%(products)s",
|
||||
attribute=pa.display_name,
|
||||
products=", ".join(pa.product_tmpl_ids.mapped('display_name')),
|
||||
))
|
||||
invalidate = 'sequence' in vals and any(record.sequence != vals['sequence'] for record in self)
|
||||
res = super(ProductAttribute, self).write(vals)
|
||||
res = super().write(vals)
|
||||
if invalidate:
|
||||
# prefetched o2m have to be resequenced
|
||||
# (eg. product.template: attribute_line_ids)
|
||||
@@ -76,10 +96,12 @@ class ProductAttribute(models.Model):
|
||||
def _unlink_except_used_on_product(self):
|
||||
for pa in self:
|
||||
if pa.number_related_products:
|
||||
raise UserError(
|
||||
_("You cannot delete the attribute %s because it is used on the following products:\n%s") %
|
||||
(pa.display_name, ", ".join(pa.product_tmpl_ids.mapped('display_name')))
|
||||
)
|
||||
raise UserError(_(
|
||||
"You cannot delete the attribute %(attribute)s because it is used on the"
|
||||
" following products:\n%(products)s",
|
||||
attribute=pa.display_name,
|
||||
products=", ".join(pa.product_tmpl_ids.mapped('display_name')),
|
||||
))
|
||||
|
||||
def action_open_related_products(self):
|
||||
return {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProductAttributeCustomValue(models.Model):
|
||||
_name = "product.attribute.custom.value"
|
||||
_description = 'Product Attribute Custom Value'
|
||||
_name = 'product.attribute.custom.value'
|
||||
_description = "Product Attribute Custom Value"
|
||||
_order = 'custom_product_template_attribute_value_id, id'
|
||||
|
||||
name = fields.Char("Name", compute='_compute_name')
|
||||
custom_product_template_attribute_value_id = fields.Many2one('product.template.attribute.value', string="Attribute Value", required=True, ondelete='restrict')
|
||||
custom_value = fields.Char("Custom Value")
|
||||
name = fields.Char(string="Name", compute='_compute_name')
|
||||
custom_product_template_attribute_value_id = fields.Many2one(
|
||||
comodel_name='product.template.attribute.value',
|
||||
string="Attribute Value",
|
||||
required=True,
|
||||
ondelete='restrict')
|
||||
custom_value = fields.Char(string="Custom Value")
|
||||
|
||||
@api.depends('custom_product_template_attribute_value_id.name', 'custom_value')
|
||||
def _compute_name(self):
|
||||
|
||||
@@ -7,33 +7,47 @@ from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ProductAttributeValue(models.Model):
|
||||
_name = "product.attribute.value"
|
||||
_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'
|
||||
_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('product.attribute', string="Attribute", ondelete='cascade', required=True, index=True,
|
||||
help="The attribute cannot be changed once the value is used on at least one product.")
|
||||
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('product.template.attribute.line', string="Lines",
|
||||
relation='product_attribute_value_product_template_attribute_line_rel', copy=False)
|
||||
is_used_on_products = fields.Boolean('Used on Products', compute='_compute_is_used_on_products')
|
||||
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('Is custom value', help="Allow users to input custom values for this attribute value")
|
||||
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', readonly=True)
|
||||
color = fields.Integer('Color Index', default=_get_default_color)
|
||||
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.")
|
||||
('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')
|
||||
@@ -50,21 +64,23 @@ class ProductAttributeValue(models.Model):
|
||||
the attribute is already on each line so there is no need to repeat it
|
||||
on every value.
|
||||
"""
|
||||
if not self._context.get('show_attribute', True):
|
||||
return super(ProductAttributeValue, self).name_get()
|
||||
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 %s because it is used on the following products:%s") %
|
||||
(pav.display_name, ", ".join(pav.pav_attribute_line_ids.product_tmpl_id.mapped('display_name')))
|
||||
)
|
||||
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(ProductAttributeValue, self).write(values)
|
||||
res = super().write(values)
|
||||
if invalidate:
|
||||
# prefetched o2m have to be resequenced
|
||||
# (eg. product.template.attribute.line: value_ids)
|
||||
@@ -76,10 +92,11 @@ class ProductAttributeValue(models.Model):
|
||||
def _unlink_except_used_on_product(self):
|
||||
for pav in self:
|
||||
if pav.is_used_on_products:
|
||||
raise UserError(
|
||||
_("You cannot delete the value %s because it is used on the following products:\n%s") %
|
||||
(pav.display_name, ", ".join(pav.pav_attribute_line_ids.product_tmpl_id.mapped('display_name')))
|
||||
)
|
||||
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')
|
||||
|
||||
@@ -4,14 +4,23 @@ from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplateAttributeExclusion(models.Model):
|
||||
_name = "product.template.attribute.exclusion"
|
||||
_description = 'Product Template Attribute Exclusion'
|
||||
_name = 'product.template.attribute.exclusion'
|
||||
_description = "Product Template Attribute Exclusion"
|
||||
_order = 'product_tmpl_id, id'
|
||||
|
||||
product_template_attribute_value_id = fields.Many2one(
|
||||
'product.template.attribute.value', string="Attribute Value", ondelete='cascade', index=True)
|
||||
comodel_name='product.template.attribute.value',
|
||||
string="Attribute Value",
|
||||
ondelete='cascade',
|
||||
index=True)
|
||||
product_tmpl_id = fields.Many2one(
|
||||
'product.template', string='Product Template', ondelete='cascade', required=True, index=True)
|
||||
comodel_name='product.template',
|
||||
string="Product Template",
|
||||
ondelete='cascade',
|
||||
required=True,
|
||||
index=True)
|
||||
value_ids = fields.Many2many(
|
||||
'product.template.attribute.value', relation="product_attr_exclusion_value_ids_rel",
|
||||
string='Attribute Values', domain="[('product_tmpl_id', '=', product_tmpl_id), ('ptav_active', '=', True)]")
|
||||
comodel_name='product.template.attribute.value',
|
||||
relation='product_attr_exclusion_value_ids_rel',
|
||||
string="Attribute Values",
|
||||
domain="[('product_tmpl_id', '=', product_tmpl_id), ('ptav_active', '=', True)]")
|
||||
|
||||
@@ -2,25 +2,43 @@
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.fields import Command
|
||||
|
||||
|
||||
class ProductTemplateAttributeLine(models.Model):
|
||||
"""Attributes available on product.template with their selected values in a m2m.
|
||||
Used as a configuration model to generate the appropriate product.template.attribute.value"""
|
||||
|
||||
_name = "product.template.attribute.line"
|
||||
_name = 'product.template.attribute.line'
|
||||
_rec_name = 'attribute_id'
|
||||
_rec_names_search = ['attribute_id', 'value_ids']
|
||||
_description = 'Product Template Attribute Line'
|
||||
_description = "Product Template Attribute Line"
|
||||
_order = 'attribute_id, id'
|
||||
|
||||
active = fields.Boolean(default=True)
|
||||
product_tmpl_id = fields.Many2one('product.template', string="Product Template", ondelete='cascade', required=True, index=True)
|
||||
attribute_id = fields.Many2one('product.attribute', string="Attribute", ondelete='restrict', required=True, index=True)
|
||||
value_ids = fields.Many2many('product.attribute.value', string="Values", domain="[('attribute_id', '=', attribute_id)]",
|
||||
relation='product_attribute_value_product_template_attribute_line_rel', ondelete='restrict')
|
||||
value_count = fields.Integer(compute='_compute_value_count', store=True, readonly=True)
|
||||
product_template_value_ids = fields.One2many('product.template.attribute.value', 'attribute_line_id', string="Product Attribute Values")
|
||||
product_tmpl_id = fields.Many2one(
|
||||
comodel_name='product.template',
|
||||
string="Product Template",
|
||||
ondelete='cascade',
|
||||
required=True,
|
||||
index=True)
|
||||
attribute_id = fields.Many2one(
|
||||
comodel_name='product.attribute',
|
||||
string="Attribute",
|
||||
ondelete='restrict',
|
||||
required=True,
|
||||
index=True)
|
||||
value_ids = fields.Many2many(
|
||||
comodel_name='product.attribute.value',
|
||||
relation='product_attribute_value_product_template_attribute_line_rel',
|
||||
string="Values",
|
||||
domain="[('attribute_id', '=', attribute_id)]",
|
||||
ondelete='restrict')
|
||||
value_count = fields.Integer(compute='_compute_value_count', store=True)
|
||||
product_template_value_ids = fields.One2many(
|
||||
comodel_name='product.template.attribute.value',
|
||||
inverse_name='attribute_line_id',
|
||||
string="Product Attribute Values")
|
||||
|
||||
@api.depends('value_ids')
|
||||
def _compute_value_count(self):
|
||||
@@ -35,16 +53,20 @@ class ProductTemplateAttributeLine(models.Model):
|
||||
def _check_valid_values(self):
|
||||
for ptal in self:
|
||||
if ptal.active and not ptal.value_ids:
|
||||
raise ValidationError(
|
||||
_("The attribute %s must have at least one value for the product %s.") %
|
||||
(ptal.attribute_id.display_name, ptal.product_tmpl_id.display_name)
|
||||
)
|
||||
raise ValidationError(_(
|
||||
"The attribute %(attribute)s must have at least one value for the product %(product)s.",
|
||||
attribute=ptal.attribute_id.display_name,
|
||||
product=ptal.product_tmpl_id.display_name,
|
||||
))
|
||||
for pav in ptal.value_ids:
|
||||
if pav.attribute_id != ptal.attribute_id:
|
||||
raise ValidationError(
|
||||
_("On the product %s you cannot associate the value %s with the attribute %s because they do not match.") %
|
||||
(ptal.product_tmpl_id.display_name, pav.display_name, ptal.attribute_id.display_name)
|
||||
)
|
||||
raise ValidationError(_(
|
||||
"On the product %(product)s you cannot associate the value %(value)s"
|
||||
" with the attribute %(attribute)s because they do not match.",
|
||||
product=ptal.product_tmpl_id.display_name,
|
||||
value=pav.display_name,
|
||||
attribute=ptal.attribute_id.display_name,
|
||||
))
|
||||
return True
|
||||
|
||||
@api.model_create_multi
|
||||
@@ -79,7 +101,7 @@ class ProductTemplateAttributeLine(models.Model):
|
||||
activated_lines += archived_ptal
|
||||
else:
|
||||
create_values.append(value)
|
||||
res = activated_lines + super(ProductTemplateAttributeLine, self).create(create_values)
|
||||
res = activated_lines + super().create(create_values)
|
||||
res._update_product_template_attribute_values()
|
||||
return res
|
||||
|
||||
@@ -93,23 +115,29 @@ class ProductTemplateAttributeLine(models.Model):
|
||||
if 'product_tmpl_id' in values:
|
||||
for ptal in self:
|
||||
if ptal.product_tmpl_id.id != values['product_tmpl_id']:
|
||||
raise UserError(
|
||||
_("You cannot move the attribute %s from the product %s to the product %s.") %
|
||||
(ptal.attribute_id.display_name, ptal.product_tmpl_id.display_name, values['product_tmpl_id'])
|
||||
)
|
||||
raise UserError(_(
|
||||
"You cannot move the attribute %(attribute)s from the product"
|
||||
" %(product_src)s to the product %(product_dest)s.",
|
||||
attribute=ptal.attribute_id.display_name,
|
||||
product_src=ptal.product_tmpl_id.display_name,
|
||||
product_dest=values['product_tmpl_id'],
|
||||
))
|
||||
|
||||
if 'attribute_id' in values:
|
||||
for ptal in self:
|
||||
if ptal.attribute_id.id != values['attribute_id']:
|
||||
raise UserError(
|
||||
_("On the product %s you cannot transform the attribute %s into the attribute %s.") %
|
||||
(ptal.product_tmpl_id.display_name, ptal.attribute_id.display_name, values['attribute_id'])
|
||||
)
|
||||
raise UserError(_(
|
||||
"On the product %(product)s you cannot transform the attribute"
|
||||
" %(attribute_src)s into the attribute %(attribute_dest)s.",
|
||||
product=ptal.product_tmpl_id.display_name,
|
||||
attribute_src=ptal.attribute_id.display_name,
|
||||
attribute_dest=values['attribute_id'],
|
||||
))
|
||||
# Remove all values while archiving to make sure the line is clean if it
|
||||
# is ever activated again.
|
||||
if not values.get('active', True):
|
||||
values['value_ids'] = [(5, 0, 0)]
|
||||
res = super(ProductTemplateAttributeLine, self).write(values)
|
||||
values['value_ids'] = [Command.clear()]
|
||||
res = super().write(values)
|
||||
if 'active' in values:
|
||||
self.env.flush_all()
|
||||
self.env['product.template'].invalidate_model(['attribute_line_ids'])
|
||||
|
||||
@@ -4,13 +4,14 @@ from random import randint
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.fields import Command
|
||||
|
||||
|
||||
class ProductTemplateAttributeValue(models.Model):
|
||||
"""Materialized relationship between attribute values
|
||||
and product template generated by the product.template.attribute.line"""
|
||||
|
||||
_name = "product.template.attribute.value"
|
||||
_name = 'product.template.attribute.value'
|
||||
_description = "Product Template Attribute Value"
|
||||
_order = 'attribute_line_id, product_attribute_value_id, id'
|
||||
|
||||
@@ -19,51 +20,64 @@ class ProductTemplateAttributeValue(models.Model):
|
||||
|
||||
# Not just `active` because we always want to show the values except in
|
||||
# specific case, as opposed to `active_test`.
|
||||
ptav_active = fields.Boolean("Active", default=True)
|
||||
name = fields.Char('Value', related="product_attribute_value_id.name")
|
||||
ptav_active = fields.Boolean(string="Active", default=True)
|
||||
name = fields.Char(string="Value", related="product_attribute_value_id.name")
|
||||
|
||||
# defining fields: the product template attribute line and the product attribute value
|
||||
product_attribute_value_id = fields.Many2one(
|
||||
'product.attribute.value', string='Attribute Value',
|
||||
comodel_name='product.attribute.value',
|
||||
string="Attribute Value",
|
||||
required=True, ondelete='cascade', index=True)
|
||||
attribute_line_id = fields.Many2one(
|
||||
comodel_name='product.template.attribute.line',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
attribute_line_id = fields.Many2one('product.template.attribute.line', required=True, ondelete='cascade', index=True)
|
||||
# configuration fields: the price_extra and the exclusion rules
|
||||
price_extra = fields.Float(
|
||||
string="Value Price Extra",
|
||||
default=0.0,
|
||||
digits='Product Price',
|
||||
help="Extra price for the variant with this attribute value on sale price. eg. 200 price extra, 1000 + 200 = 1200.")
|
||||
help="Extra price for the variant with this attribute value on sale price."
|
||||
" eg. 200 price extra, 1000 + 200 = 1200.")
|
||||
currency_id = fields.Many2one(related='attribute_line_id.product_tmpl_id.currency_id')
|
||||
|
||||
exclude_for = fields.One2many(
|
||||
'product.template.attribute.exclusion',
|
||||
'product_template_attribute_value_id',
|
||||
comodel_name='product.template.attribute.exclusion',
|
||||
inverse_name='product_template_attribute_value_id',
|
||||
string="Exclude for",
|
||||
help="Make this attribute value not compatible with "
|
||||
"other values of the product or some attribute values of optional and accessory products.")
|
||||
|
||||
# related fields: product template and product attribute
|
||||
product_tmpl_id = fields.Many2one('product.template', string="Product Template", related='attribute_line_id.product_tmpl_id', store=True, index=True)
|
||||
attribute_id = fields.Many2one('product.attribute', string="Attribute", related='attribute_line_id.attribute_id', store=True, index=True)
|
||||
ptav_product_variant_ids = fields.Many2many('product.product', relation='product_variant_combination', string="Related Variants", readonly=True)
|
||||
product_tmpl_id = fields.Many2one(
|
||||
related='attribute_line_id.product_tmpl_id', store=True, index=True)
|
||||
attribute_id = fields.Many2one(
|
||||
related='attribute_line_id.attribute_id', store=True, index=True)
|
||||
ptav_product_variant_ids = fields.Many2many(
|
||||
comodel_name='product.product', relation='product_variant_combination',
|
||||
string="Related Variants", readonly=True)
|
||||
|
||||
html_color = fields.Char('HTML Color Index', related="product_attribute_value_id.html_color")
|
||||
is_custom = fields.Boolean('Is custom value', related="product_attribute_value_id.is_custom")
|
||||
display_type = fields.Selection(related='product_attribute_value_id.display_type', readonly=True)
|
||||
color = fields.Integer('Color', default=_get_default_color)
|
||||
html_color = fields.Char(string="HTML Color Index", related='product_attribute_value_id.html_color')
|
||||
is_custom = fields.Boolean(related='product_attribute_value_id.is_custom')
|
||||
display_type = fields.Selection(related='product_attribute_value_id.display_type')
|
||||
color = fields.Integer(string="Color", default=_get_default_color)
|
||||
|
||||
_sql_constraints = [
|
||||
('attribute_value_unique', 'unique(attribute_line_id, product_attribute_value_id)', "Each value should be defined only once per attribute per product."),
|
||||
('attribute_value_unique',
|
||||
'unique(attribute_line_id, product_attribute_value_id)',
|
||||
"Each value should be defined only once per attribute per product."),
|
||||
]
|
||||
|
||||
@api.constrains('attribute_line_id', 'product_attribute_value_id')
|
||||
def _check_valid_values(self):
|
||||
for ptav in self:
|
||||
if ptav.product_attribute_value_id not in ptav.attribute_line_id.value_ids:
|
||||
raise ValidationError(
|
||||
_("The value %s is not defined for the attribute %s on the product %s.") %
|
||||
(ptav.product_attribute_value_id.display_name, ptav.attribute_id.display_name, ptav.product_tmpl_id.display_name)
|
||||
)
|
||||
raise ValidationError(_(
|
||||
"The value %(value)s is not defined for the attribute %(attribute)s"
|
||||
" on the product %(product)s.",
|
||||
value=ptav.product_attribute_value_id.display_name,
|
||||
attribute=ptav.attribute_id.display_name,
|
||||
product=ptav.product_tmpl_id.display_name,
|
||||
))
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -71,7 +85,7 @@ class ProductTemplateAttributeValue(models.Model):
|
||||
# Force write on this relation from `product.product` to properly
|
||||
# trigger `_compute_combination_indices`.
|
||||
raise UserError(_("You cannot update related variants from the values. Please update related values from the variants."))
|
||||
return super(ProductTemplateAttributeValue, self).create(vals_list)
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, values):
|
||||
if 'ptav_product_variant_ids' in values:
|
||||
@@ -83,16 +97,18 @@ class ProductTemplateAttributeValue(models.Model):
|
||||
if pav_in_values or product_in_values:
|
||||
for ptav in self:
|
||||
if pav_in_values and ptav.product_attribute_value_id.id != values['product_attribute_value_id']:
|
||||
raise UserError(
|
||||
_("You cannot change the value of the value %s set on product %s.") %
|
||||
(ptav.display_name, ptav.product_tmpl_id.display_name)
|
||||
)
|
||||
raise UserError(_(
|
||||
"You cannot change the value of the value %(value)s set on product %(product)s.",
|
||||
value=ptav.display_name,
|
||||
product=ptav.product_tmpl_id.display_name,
|
||||
))
|
||||
if product_in_values and ptav.product_tmpl_id.id != values['product_tmpl_id']:
|
||||
raise UserError(
|
||||
_("You cannot change the product of the value %s set on product %s.") %
|
||||
(ptav.display_name, ptav.product_tmpl_id.display_name)
|
||||
)
|
||||
res = super(ProductTemplateAttributeValue, self).write(values)
|
||||
raise UserError(_(
|
||||
"You cannot change the product of the value %(value)s set on product %(product)s.",
|
||||
value=ptav.display_name,
|
||||
product=ptav.product_tmpl_id.display_name,
|
||||
))
|
||||
res = super().write(values)
|
||||
if 'exclude_for' in values:
|
||||
self.product_tmpl_id._create_variant_ids()
|
||||
return res
|
||||
@@ -112,7 +128,9 @@ class ProductTemplateAttributeValue(models.Model):
|
||||
# value (counting also the values that are archived).
|
||||
single_values = self.filtered(lambda ptav: len(ptav.attribute_line_id.product_template_value_ids) == 1)
|
||||
for ptav in single_values:
|
||||
ptav.ptav_product_variant_ids.write({'product_template_attribute_value_ids': [(3, ptav.id, 0)]})
|
||||
ptav.ptav_product_variant_ids.write({
|
||||
'product_template_attribute_value_ids': [Command.unlink(ptav.id)],
|
||||
})
|
||||
# Try to remove the variants before deleting to potentially remove some
|
||||
# blocking references.
|
||||
self.ptav_product_variant_ids._unlink_or_archive()
|
||||
|
||||
Reference in New Issue
Block a user