odoo/addons/product/models/product_attribute.py

113 lines
5.4 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError, ValidationError
class ProductAttribute(models.Model):
_name = "product.attribute"
_description = "Product Attribute"
_order = 'sequence, name'
name = fields.Char('Name', 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")
attribute_line_ids = fields.One2many('product.attribute.line', 'attribute_id', 'Lines')
create_variant = fields.Boolean(default=True, help="Check this if you want to create multiple variants for this attribute.")
class ProductAttributevalue(models.Model):
_name = "product.attribute.value"
_order = 'sequence'
name = fields.Char('Value', required=True, translate=True)
sequence = fields.Integer('Sequence', help="Determine the display order")
attribute_id = fields.Many2one('product.attribute', 'Attribute', ondelete='cascade', required=True)
product_ids = fields.Many2many('product.product', string='Variants', readonly=True)
price_extra = fields.Float(
'Attribute Price Extra', compute='_compute_price_extra', inverse='_set_price_extra',
default=0.0, digits=dp.get_precision('Product Price'),
help="Price Extra: Extra price for the variant with this attribute value on sale price. eg. 200 price extra, 1000 + 200 = 1200.")
price_ids = fields.One2many('product.attribute.price', 'value_id', 'Attribute Prices', readonly=True)
_sql_constraints = [
('value_company_uniq', 'unique (name,attribute_id)', 'This attribute value already exists !')
]
@api.one
def _compute_price_extra(self):
if self._context.get('active_id'):
price = self.price_ids.filtered(lambda price: price.product_tmpl_id.id == self._context['active_id'])
self.price_extra = price.price_extra
else:
self.price_extra = 0.0
def _set_price_extra(self):
if not self._context.get('active_id'):
return
AttributePrice = self.env['product.attribute.price']
prices = AttributePrice.search([('value_id', 'in', self.ids), ('product_tmpl_id', '=', self._context['active_id'])])
updated = prices.mapped('value_id')
if prices:
prices.write({'price_extra': self.price_extra})
else:
for value in self - updated:
AttributePrice.create({
'product_tmpl_id': self._context['active_id'],
'value_id': value.id,
'price_extra': self.price_extra,
})
@api.multi
def name_get(self):
if not self._context.get('show_attribute', True): # TDE FIXME: not used
return super(ProductAttributevalue, self).name_get()
return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self]
@api.multi
def unlink(self):
linked_products = self.env['product.product'].with_context(active_test=False).search([('attribute_value_ids', 'in', self.ids)])
if linked_products:
raise UserError(_('The operation cannot be completed:\nYou are trying to delete an attribute value with a reference on a product variant.'))
return super(ProductAttributevalue, self).unlink()
@api.multi
def _variant_name(self, variable_attributes):
return ", ".join([v.name for v in self.sorted(key=lambda r: r.attribute_id.name) if v.attribute_id in variable_attributes])
class ProductAttributePrice(models.Model):
_name = "product.attribute.price"
product_tmpl_id = fields.Many2one('product.template', 'Product Template', ondelete='cascade', required=True)
value_id = fields.Many2one('product.attribute.value', 'Product Attribute Value', ondelete='cascade', required=True)
price_extra = fields.Float('Price Extra', digits=dp.get_precision('Product Price'))
class ProductAttributeLine(models.Model):
_name = "product.attribute.line"
_rec_name = 'attribute_id'
product_tmpl_id = fields.Many2one('product.template', 'Product Template', ondelete='cascade', required=True)
attribute_id = fields.Many2one('product.attribute', 'Attribute', ondelete='restrict', required=True)
value_ids = fields.Many2many('product.attribute.value', string='Attribute Values')
@api.constrains('value_ids', 'attribute_id')
def _check_valid_attribute(self):
if any(line.value_ids > line.attribute_id.value_ids for line in self):
raise ValidationError(_('Error ! You cannot use this attribute with the following value.'))
return True
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
# TDE FIXME: currently overriding the domain; however as it includes a
# search on a m2o and one on a m2m, probably this will quickly become
# difficult to compute - check if performance optimization is required
if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
args = ['|', ('attribute_id', operator, name), ('value_ids', operator, name)]
return self.search(args, limit=limit).name_get()
return super(ProductAttributeLine, self).name_search(name=name, args=args, operator=operator, limit=limit)