From 83c583b494b72689efe8700a98cf3d831b5f7b24 Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Thu, 23 Dec 2021 12:43:00 +0100 Subject: [PATCH] [IMP] product: do not fallback on context values in price_compute This adds too much indeterminism in price computation logic. Furthermore, remaining calls to price_compute provide the parameter when needed. --- addons/product/models/product.py | 37 ++++++++++------------ addons/product/models/product_pricelist.py | 6 ---- addons/product/models/product_template.py | 32 +++++++++---------- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index de11cb95312..59296f01aa2 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -623,44 +623,41 @@ class ProductProduct(models.Model): res |= seller return res.sorted('price')[:1] - def price_compute(self, price_type, uom=False, currency=False, company=None, date=False): - # TDE FIXME: delegate to template or not ? fields are reencoded here ... - # compatibility about context keys used a bit everywhere in the code - if not uom and self._context.get('uom'): - uom = self.env['uom.uom'].browse(self._context['uom']) - if not currency and self._context.get('currency'): - currency = self.env['res.currency'].browse(self._context['currency']) + 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) - products = self + self = self.with_company(company) if price_type == 'standard_price': # standard_price field can only be seen by users in base.group_user # Thus, in order to compute the sale price from the cost for users not in this group # We fetch the standard price as the superuser - products = self.with_company(company).sudo() - if not company: - company = self.env.company - - date = date or fields.Date.context_today(self) + self = self.sudo() prices = dict.fromkeys(self.ids, 0.0) - for product in products: - prices[product.id] = product[price_type] or 0.0 + for product in self: + price = product[price_type] or 0.0 + price_currency = product.currency_id + if price_type == 'standard_price': + price_currency = product.cost_currency_id + if price_type == 'list_price': - prices[product.id] += product.price_extra + 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 - prices[product.id] += sum(self._context.get('no_variant_attributes_price_extra')) + price += sum(self._context.get('no_variant_attributes_price_extra')) if uom: - prices[product.id] = product.uom_id._compute_price(prices[product.id], uom) + price = product.uom_id._compute_price(price, uom) # Convert from current user company currency to asked one # This is right cause a field cannot be in more than one currency if currency: - prices[product.id] = product.currency_id._convert( - prices[product.id], currency, company, date) + price = price_currency._convert(price, currency, company, date) + + prices[product.id] = price return prices diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 91af22df74e..ba2bfb4229c 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -168,12 +168,6 @@ class Pricelist(models.Model): # Fetch all rules potentially matching specified products/templates/categories and date rules = self._get_applicable_rules(date, product_tmpl_ids, product_ids, category_ids) - if 'currency' in products.env.context: - # Remove currency from product context to avoid any - # side-effect currency conversion in price_compute calls - # since we manage currency conversion without the context fallbacks - product = products.with_context(currency=False) - results = {} for product in products: suitable_rule = self.env['product.pricelist.item'] diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 3d2aaa5076f..08ab88a3d04 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -549,41 +549,39 @@ class ProductTemplate(models.Model): }, } - def price_compute(self, price_type, uom=False, currency=False, company=None, date=False): - # TDE FIXME: delegate to template or not ? fields are reencoded here ... - # compatibility about context keys used a bit everywhere in the code - if not uom and self._context.get('uom'): - uom = self.env['uom.uom'].browse(self._context['uom']) - if not currency and self._context.get('currency'): - currency = self.env['res.currency'].browse(self._context['currency']) + 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) - templates = self + self = self.with_company(company) if price_type == 'standard_price': # standard_price field can only be seen by users in base.group_user # Thus, in order to compute the sale price from the cost for users not in this group # We fetch the standard price as the superuser - templates = self.with_company(company).sudo() - if not company: - company = self.env.company - date = date or fields.Date.context_today(self) + self = self.sudo() prices = dict.fromkeys(self.ids, 0.0) - for template in templates: - prices[template.id] = template[price_type] or 0.0 + for template in self: + price = template[price_type] or 0.0 + 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 - prices[template.id] += sum(self._context.get('current_attributes_price_extra')) + price += sum(self._context.get('current_attributes_price_extra')) if uom: - prices[template.id] = template.uom_id._compute_price(prices[template.id], uom) + price = template.uom_id._compute_price(price, uom) # Convert from current user company currency to asked one # This is right cause a field cannot be in more than one currency if currency: - prices[template.id] = template.currency_id._convert(prices[template.id], currency, company, date) + price = price_currency._convert(price, currency, company, date) + prices[template.id] = price return prices def _create_variant_ids(self):