[IMP] sale,*: tooling for conversion of amounts to the SO currency

Harmonize currency conversion of unit prices:
* Make sure no rounding is applied during the conversion
(it'll be managed by the price_unit decimal precision
and the currency rounding will only be applied by the
monetary fields later in the computations).
* consistent parameters for the conversion (date,
company, currency).
* code simplification
* consistent behavior when the SO has no currency specified
...

Part-of: odoo/odoo#110833
This commit is contained in:
Victor Feyens
2023-02-03 05:09:05 +01:00
parent 6db4d6904e
commit f938f00877
7 changed files with 58 additions and 59 deletions
@@ -93,15 +93,12 @@ class SaleOrderLine(models.Model):
def _get_display_price(self):
if self.event_booth_pending_ids and self.event_id:
company = self.event_id.company_id or self.env.company
currency = company.currency_id
product = self.event_booth_pending_ids.booth_category_id.product_id
pricelist = product.product_tmpl_id._get_contextual_pricelist()
if pricelist.discount_policy == "with_discount":
total_price = sum([booth.booth_category_id.price_reduce for booth in self.event_booth_pending_ids])
else:
total_price = sum([booth.price for booth in self.event_booth_pending_ids])
return currency._convert(
total_price, self.order_id.currency_id,
self.order_id.company_id or self.env.company.id,
self.order_id.date_order or fields.Date.today())
return self._convert_to_sol_currency(total_price, company.currency_id)
return super()._get_display_price()
+1 -5
View File
@@ -173,14 +173,10 @@ class SaleOrderLine(models.Model):
uom=self.product_uom.id
)
company = event_ticket.company_id or self.env.company
currency = company.currency_id
pricelist = self.order_id.pricelist_id
if pricelist.discount_policy == "with_discount":
price = event_ticket.price_reduce
else:
price = event_ticket.price
return currency._convert(
price, self.order_id.currency_id,
self.order_id.company_id or self.env.company.id,
self.order_id.date_order or fields.Date.today())
return self._convert_to_sol_currency(price, company.currency_id)
return super()._get_display_price()
+25
View File
@@ -1149,3 +1149,28 @@ class SaleOrderLine(models.Model):
def _is_not_sellable_line(self):
# True if the line is a computed line (reward, delivery, ...) that user cannot add manually
return False
#=== TOOLING ===#
def _convert_to_sol_currency(self, amount, currency):
"""Convert the given amount from the given currency to the SO(L) currency.
:param float amount: the amount to convert
:param currency: currency in which the given amount is expressed
:type currency: `res.currency` record
:returns: converted amount
:rtype: float
"""
self.ensure_one()
to_currency = self.currency_id or self.order_id.currency_id
if currency and to_currency and currency != to_currency:
conversion_date = self.order_id.date_order or fields.Date.context_today(self)
company = self.company_id or self.order_id.company_id or self.env.company
return currency._convert(
from_amount=amount,
to_currency=to_currency,
company=company,
date=conversion_date,
round=False,
)
return amount
@@ -18,16 +18,8 @@ class SaleOrderLine(models.Model):
else:
product_cost = line.expense_id.untaxed_amount
from_currency = line.expense_id.currency_id
to_currency = line.currency_id or line.order_id.currency_id
line.purchase_price = line._convert_to_sol_currency(
product_cost,
line.expense_id.currency_id)
if to_currency and product_cost and from_currency != to_currency:
line.purchase_price = from_currency._convert(
from_amount=product_cost,
to_currency=to_currency,
company=line.company_id or self.env.company,
date=line.order_id.date_order or date_today,
round=False)
else:
line.purchase_price = product_cost
return super(SaleOrderLine, self - expense_lines)._compute_purchase_price()
+10 -28
View File
@@ -24,37 +24,19 @@ class SaleOrderLine(models.Model):
line.purchase_price = 0.0
continue
line = line.with_company(line.company_id)
product_cost = line.product_id.standard_price
line.purchase_price = line._convert_price(product_cost, line.product_id.uom_id)
# Convert the cost to the line UoM
product_cost = line.product_id.uom_id._compute_price(
line.product_id.standard_price,
line.product_uom,
)
line.purchase_price = line._convert_to_sol_currency(
product_cost,
line.product_id.cost_currency_id)
@api.depends('price_subtotal', 'product_uom_qty', 'purchase_price')
def _compute_margin(self):
for line in self:
line.margin = line.price_subtotal - (line.purchase_price * line.product_uom_qty)
line.margin_percent = line.price_subtotal and line.margin/line.price_subtotal
def _convert_price(self, product_cost, from_uom):
self.ensure_one()
if not product_cost:
# If the standard_price is 0
# Avoid unnecessary computations
# and currency conversions
if not self.purchase_price:
return product_cost
from_currency = self.product_id.cost_currency_id
to_cur = self.currency_id or self.order_id.currency_id
to_uom = self.product_uom
if to_uom and to_uom != from_uom:
product_cost = from_uom._compute_price(
product_cost,
to_uom,
)
return from_currency._convert(
from_amount=product_cost,
to_currency=to_cur,
company=self.company_id or self.env.company,
date=self.order_id.date_order or fields.Date.today(),
round=False,
) if to_cur and product_cost else product_cost
# The pricelist may not have been set, therefore no conversion
# is needed because we don't know the target currency..
@@ -19,11 +19,8 @@ class SaleOrderLine(models.Model):
if line.product_uom and line.product_uom != product.uom_id:
purch_price = product.uom_id._compute_price(purch_price, line.product_uom)
to_cur = line.currency_id or line.order_id.currency_id
line.purchase_price = product.cost_currency_id._convert(
from_amount=purch_price,
to_currency=to_cur,
company=line.company_id or self.env.company,
date=line.order_id.date_order or fields.Date.today(),
round=False,
) if to_cur and purch_price else purch_price
line.purchase_price = line._convert_to_sol_currency(
purch_price,
product.cost_currency_id,
)
return super(SaleOrderLine, lines_without_moves)._compute_purchase_price()
@@ -23,10 +23,20 @@ class SaleOrderLine(models.Model):
for line in timesheet_sols:
line = line.with_company(line.company_id)
product_cost = mapped_sol_timesheet_amount.get(line.id, line.product_id.standard_price)
if line.product_id.uom_id != line.company_id.project_time_mode_id and\
line.product_id.uom_id.category_id.id == line.company_id.project_time_mode_id.category_id.id:
if (
line.product_id.uom_id != line.company_id.project_time_mode_id
and line.product_id.uom_id.category_id.id == line.company_id.project_time_mode_id.category_id.id
):
product_cost = line.company_id.project_time_mode_id._compute_quantity(
product_cost,
line.product_id.uom_id
)
line.purchase_price = line._convert_price(product_cost, line.product_id.uom_id)
# Convert the cost to the line UoM
product_cost = line.product_id.uom_id._compute_price(
line.product_id.standard_price,
line.product_uom,
)
line.purchase_price = line._convert_to_sol_currency(
product_cost, line.product_id.cost_currency_id)