[IMP] product,sale: harmonize/clarify contextual keys for extra prices
Clarify the uses and impacts of current_attributes_price_extra and no_variant_attributes_price_extra context keys. Group the key specification and usage. Provide a clear API shared by templates and variants. Part-of: odoo/odoo#113234
This commit is contained in:
@@ -620,6 +620,31 @@ class ProductProduct(models.Model):
|
||||
res |= seller
|
||||
return res.sorted('price')[:1]
|
||||
|
||||
def _get_product_price_context(self, combination):
|
||||
self.ensure_one()
|
||||
res = {}
|
||||
|
||||
# It is possible that a no_variant attribute is still in a variant if
|
||||
# the type of the attribute has been changed after creation.
|
||||
no_variant_attributes_price_extra = [
|
||||
ptav.price_extra for ptav in combination.filtered(
|
||||
lambda ptav:
|
||||
ptav.price_extra
|
||||
and ptav.product_tmpl_id == self.product_tmpl_id
|
||||
and ptav not in self.product_template_attribute_value_ids
|
||||
)
|
||||
]
|
||||
if no_variant_attributes_price_extra:
|
||||
res['no_variant_attributes_price_extra'] = tuple(no_variant_attributes_price_extra)
|
||||
|
||||
return res
|
||||
|
||||
def _get_attributes_extra_price(self):
|
||||
self.ensure_one()
|
||||
|
||||
return self.price_extra + sum(
|
||||
self.env.context.get('no_variant_attributes_price_extra', []))
|
||||
|
||||
def price_compute(self, price_type, uom=None, currency=None, company=None, date=False):
|
||||
company = company or self.env.company
|
||||
date = date or fields.Date.context_today(self)
|
||||
@@ -637,14 +662,8 @@ class ProductProduct(models.Model):
|
||||
price_currency = product.currency_id
|
||||
if price_type == 'standard_price':
|
||||
price_currency = product.cost_currency_id
|
||||
|
||||
if price_type == 'list_price':
|
||||
price += product.price_extra
|
||||
# we need to add the price from the attributes that do not generate variants
|
||||
# (see field product.attribute create_variant)
|
||||
if self._context.get('no_variant_attributes_price_extra'):
|
||||
# we have a list of price_extra that comes from the attribute values, we need to sum all that
|
||||
price += sum(self._context.get('no_variant_attributes_price_extra'))
|
||||
elif price_type == 'list_price':
|
||||
price += product._get_attributes_extra_price()
|
||||
|
||||
if uom:
|
||||
price = product.uom_id._compute_price(price, uom)
|
||||
|
||||
@@ -562,6 +562,27 @@ class ProductTemplate(models.Model):
|
||||
},
|
||||
}
|
||||
|
||||
def _get_product_price_context(self, combination):
|
||||
self.ensure_one()
|
||||
res = {}
|
||||
|
||||
current_attributes_price_extra = [
|
||||
ptav.price_extra for ptav in combination.filtered(
|
||||
lambda ptav:
|
||||
ptav.price_extra
|
||||
and ptav.product_tmpl_id == self
|
||||
)
|
||||
]
|
||||
if current_attributes_price_extra:
|
||||
res['current_attributes_price_extra'] = tuple(current_attributes_price_extra)
|
||||
|
||||
return res
|
||||
|
||||
def _get_attributes_extra_price(self):
|
||||
self.ensure_one()
|
||||
|
||||
return sum(self.env.context.get('current_attributes_price_extra', []))
|
||||
|
||||
def price_compute(self, price_type, uom=None, currency=None, company=None, date=False):
|
||||
company = company or self.env.company
|
||||
date = date or fields.Date.context_today(self)
|
||||
@@ -579,12 +600,8 @@ class ProductTemplate(models.Model):
|
||||
price_currency = template.currency_id
|
||||
if price_type == 'standard_price':
|
||||
price_currency = template.cost_currency_id
|
||||
|
||||
# yes, there can be attribute values for product template if it's not a variant YET
|
||||
# (see field product.attribute create_variant)
|
||||
if price_type == 'list_price' and self._context.get('current_attributes_price_extra'):
|
||||
# we have a list of price_extra that comes from the attribute values, we need to sum all that
|
||||
price += sum(self._context.get('current_attributes_price_extra'))
|
||||
elif price_type == 'list_price':
|
||||
price += template._get_attributes_extra_price()
|
||||
|
||||
if uom:
|
||||
price = template.uom_id._compute_price(price, uom)
|
||||
|
||||
@@ -209,8 +209,6 @@ class ProductTemplate(models.Model):
|
||||
discount applied (price < list_price), else False
|
||||
"""
|
||||
self.ensure_one()
|
||||
# get the name before the change of context to benefit from prefetch
|
||||
display_name = self.display_name
|
||||
|
||||
quantity = self.env.context.get('quantity', add_qty)
|
||||
product_template = self
|
||||
@@ -230,38 +228,25 @@ class ProductTemplate(models.Model):
|
||||
product = product_template._get_variant_for_combination(combination)
|
||||
|
||||
if product:
|
||||
# We need to add the price_extra for the attributes that are not
|
||||
# in the variant, typically those of type no_variant, but it is
|
||||
# possible that a no_variant attribute is still in a variant if
|
||||
# the type of the attribute has been changed after creation.
|
||||
no_variant_attributes_price_extra = [
|
||||
ptav.price_extra for ptav in combination.filtered(
|
||||
lambda ptav:
|
||||
ptav.price_extra and
|
||||
ptav not in product.product_template_attribute_value_ids
|
||||
)
|
||||
]
|
||||
if no_variant_attributes_price_extra:
|
||||
product = product.with_context(
|
||||
no_variant_attributes_price_extra=tuple(no_variant_attributes_price_extra)
|
||||
)
|
||||
list_price = product.price_compute('list_price')[product.id]
|
||||
price = pricelist._get_product_price(product, quantity)
|
||||
display_image = bool(product.image_128)
|
||||
display_name = product.display_name
|
||||
price_extra = (product.price_extra or 0.0) + (sum(no_variant_attributes_price_extra) or 0.0)
|
||||
else:
|
||||
current_attributes_price_extra = [v.price_extra or 0.0 for v in combination]
|
||||
product_template = product_template.with_context(current_attributes_price_extra=current_attributes_price_extra)
|
||||
price_extra = sum(current_attributes_price_extra)
|
||||
list_price = product_template.price_compute('list_price')[product_template.id]
|
||||
price = pricelist._get_product_price(product_template, quantity)
|
||||
display_image = bool(product_template.image_128)
|
||||
display_name = product_template.display_name
|
||||
|
||||
combination_name = combination._get_combination_name()
|
||||
if combination_name:
|
||||
display_name = "%s (%s)" % (display_name, combination_name)
|
||||
|
||||
product_or_template = product or self
|
||||
|
||||
price_context = product_or_template._get_product_price_context(combination)
|
||||
product_or_template = product_or_template.with_context(**price_context)
|
||||
|
||||
list_price = product_or_template.price_compute('list_price')[product_or_template.id]
|
||||
price_extra = product_or_template._get_attributes_extra_price()
|
||||
price = pricelist._get_product_price(product_or_template, quantity)
|
||||
|
||||
currency = pricelist.currency_id or self.env.company.currency_id
|
||||
if currency != product_template.currency_id:
|
||||
list_price = product_template.currency_id._convert(
|
||||
|
||||
@@ -489,21 +489,9 @@ class SaleOrderLine(models.Model):
|
||||
:rtype: dict
|
||||
"""
|
||||
self.ensure_one()
|
||||
res = {}
|
||||
|
||||
# It is possible that a no_variant attribute is still in a variant if
|
||||
# the type of the attribute has been changed after creation.
|
||||
no_variant_attributes_price_extra = [
|
||||
ptav.price_extra for ptav in self.product_no_variant_attribute_value_ids.filtered(
|
||||
lambda ptav:
|
||||
ptav.price_extra and
|
||||
ptav not in self.product_id.product_template_attribute_value_ids
|
||||
)
|
||||
]
|
||||
if no_variant_attributes_price_extra:
|
||||
res['no_variant_attributes_price_extra'] = tuple(no_variant_attributes_price_extra)
|
||||
|
||||
return res
|
||||
return self.product_id._get_product_price_context(
|
||||
self.product_no_variant_attribute_value_ids,
|
||||
)
|
||||
|
||||
def _get_pricelist_price_before_discount(self):
|
||||
"""Compute the price used as base for the pricelist price computation.
|
||||
|
||||
Reference in New Issue
Block a user