[IMP] account: split _get_tax_included_unit_price_from_price util

separate the true computation of the tax value from the computation of the base unit price (uom & curr conversion, ...).

That way, the risks of unwanted side-effects is reduced when the base unit price is already computed (sale, website_sale).

Also allows preprocessing the taxes mapping, which doesn't have to be done multiple times when we compute different amounts for the same product/template.

original commit: bc79770d1e00cf86a46002d633afd8b32921610b

Part-of: odoo/odoo#160198
This commit is contained in:
Victor Feyens
2024-04-02 18:17:59 +00:00
parent 83594c6fde
commit b6688b1a47
2 changed files with 62 additions and 38 deletions
+56 -31
View File
@@ -149,9 +149,9 @@ class ProductProduct(models.Model):
return self.product_tmpl_id._get_product_accounts()
def _get_tax_included_unit_price(self, company, currency, document_date, document_type,
is_refund_document=False, product_uom=None, product_currency=None,
product_price_unit=None, product_taxes=None, fiscal_position=None
):
is_refund_document=False, product_uom=None, product_currency=None,
product_price_unit=None, product_taxes=None, fiscal_position=None
):
""" Helper to get the price unit from different models.
This is needed to compute the same unit price in different models (sale order, account move, etc.) with same parameters.
"""
@@ -187,34 +187,13 @@ class ProductProduct(models.Model):
# Apply fiscal position.
if product_taxes and fiscal_position:
product_taxes_after_fp = fiscal_position.map_tax(product_taxes)
flattened_taxes_after_fp = product_taxes_after_fp._origin.flatten_taxes_hierarchy()
flattened_taxes_before_fp = product_taxes._origin.flatten_taxes_hierarchy()
taxes_before_included = all(tax.price_include for tax in flattened_taxes_before_fp)
if set(product_taxes.ids) != set(product_taxes_after_fp.ids) and taxes_before_included:
taxes_res = flattened_taxes_before_fp.with_context(round=False, round_base=False).compute_all(
product_price_unit,
quantity=1.0,
currency=currency,
product=product,
is_refund=is_refund_document,
)
product_price_unit = taxes_res['total_excluded']
if any(tax.price_include for tax in flattened_taxes_after_fp):
taxes_res = flattened_taxes_after_fp.with_context(round=False, round_base=False).compute_all(
product_price_unit,
quantity=1.0,
currency=currency,
product=product,
is_refund=is_refund_document,
handle_price_include=False,
)
for tax_res in taxes_res['taxes']:
tax = self.env['account.tax'].browse(tax_res['id'])
if tax.price_include:
product_price_unit += tax_res['amount']
product_price_unit = self._get_tax_included_unit_price_from_price(
product_price_unit,
currency,
product_taxes,
fiscal_position=fiscal_position,
is_refund_document=is_refund_document,
)
# Apply currency rate.
if currency != product_currency:
@@ -222,6 +201,52 @@ class ProductProduct(models.Model):
return product_price_unit
@api.model # the product is optional for `compute_all`
def _get_tax_included_unit_price_from_price(
self, product_price_unit, currency, product_taxes,
fiscal_position=None,
product_taxes_after_fp=None,
is_refund_document=False,
):
if not product_taxes:
return product_price_unit
if product_taxes_after_fp is None:
if not fiscal_position:
return product_price_unit
product_taxes_after_fp = fiscal_position.map_tax(product_taxes)
flattened_taxes_after_fp = product_taxes_after_fp._origin.flatten_taxes_hierarchy()
flattened_taxes_before_fp = product_taxes._origin.flatten_taxes_hierarchy()
taxes_before_included = all(tax.price_include for tax in flattened_taxes_before_fp)
if set(product_taxes.ids) != set(product_taxes_after_fp.ids) and taxes_before_included:
taxes_res = flattened_taxes_before_fp.with_context(round=False, round_base=False).compute_all(
product_price_unit,
quantity=1.0,
currency=currency,
product=self,
is_refund=is_refund_document,
)
product_price_unit = taxes_res['total_excluded']
if any(tax.price_include for tax in flattened_taxes_after_fp):
taxes_res = flattened_taxes_after_fp.with_context(round=False, round_base=False).compute_all(
product_price_unit,
quantity=1.0,
currency=currency,
product=self,
is_refund=is_refund_document,
handle_price_include=False,
)
for tax_res in taxes_res['taxes']:
tax = self.env['account.tax'].browse(tax_res['id'])
if tax.price_include:
product_price_unit += tax_res['amount']
return product_price_unit
@api.depends('lst_price', 'product_tmpl_id', 'taxes_id')
def _compute_tax_string(self):
for record in self:
+6 -7
View File
@@ -471,14 +471,13 @@ class SaleOrderLine(models.Model):
else:
line = line.with_company(line.company_id)
price = line._get_display_price()
line.price_unit = line.product_id._get_tax_included_unit_price(
line.company_id or line.env.company,
line.order_id.currency_id,
line.order_id.date_order,
'sale',
line.price_unit = line.product_id._get_tax_included_unit_price_from_price(
price,
line.currency_id or line.order_id.currency_id,
product_taxes=line.product_id.taxes_id.filtered(
lambda tax: tax.company_id == line.env.company
),
fiscal_position=line.order_id.fiscal_position_id,
product_price_unit=price,
product_currency=line.currency_id
)
def _get_display_price(self):