[FIX] account: Fix tax details with negative invoice lines

Before this commit:
Suppose invl1 of 1000.0 with 10.0% and invl2 of -100.0 with the same tax. A tax line of 90.0 is created.
If invl1 is created before invl2, the tax details is computing the tax amounts as:
invl1 tax amount = 1000/900 * 90 = 100 (OK)
invl2 tax amount = 90 - 100 = -10 (OK)
total tax amount = 100 - 10 = 90 (OK)
If invl2 is created before invl2:
invl1 tax amount = 100/900 * 90 = 10 (NOT OK)
invl2 tax amount = 90 - 10 = 80 (NOT OK)
total tax amount = 10 + 80 = 90 (OK)

closes odoo/odoo#85406

X-original-commit: bada85c7621b45970c88548c4d09b88b77c08e8e
Signed-off-by: Olivier Colson <oco@odoo.com>
Signed-off-by: Laurent Smet <las@odoo.com>
This commit is contained in:
Laurent Smet
2022-02-28 10:14:48 +00:00
parent 82bf20a700
commit aa856399db
2 changed files with 54 additions and 10 deletions
@@ -319,11 +319,11 @@ class AccountMoveLine(models.Model):
sub.src_line_id,
ROUND(
COALESCE(sub.total_tax_amount * ABS(sub.cumulated_base_amount) / ABS(NULLIF(sub.total_base_amount, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount) * sub.total_tax_amount * ABS(sub.cumulated_base_amount) / NULLIF(sub.total_base_amount, 0.0), 0.0),
sub.comp_curr_prec
)
- LAG(ROUND(
COALESCE(sub.total_tax_amount * ABS(sub.cumulated_base_amount) / ABS(NULLIF(sub.total_base_amount, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount) * sub.total_tax_amount * ABS(sub.cumulated_base_amount) / NULLIF(sub.total_base_amount, 0.0), 0.0),
sub.comp_curr_prec
), 1, 0.0)
OVER (
@@ -331,11 +331,11 @@ class AccountMoveLine(models.Model):
) AS base_amount,
ROUND(
COALESCE(sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / ABS(NULLIF(sub.total_base_amount_currency, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount_currency) * sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / NULLIF(sub.total_base_amount_currency, 0.0), 0.0),
sub.curr_prec
)
- LAG(ROUND(
COALESCE(sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / ABS(NULLIF(sub.total_base_amount_currency, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount_currency) * sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / NULLIF(sub.total_base_amount_currency, 0.0), 0.0),
sub.curr_prec
), 1, 0.0)
OVER (
@@ -459,11 +459,11 @@ class AccountMoveLine(models.Model):
sub.base_amount,
ROUND(
COALESCE(sub.total_tax_amount * ABS(sub.cumulated_base_amount) / ABS(NULLIF(sub.total_base_amount, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount) * sub.total_tax_amount * ABS(sub.cumulated_base_amount) / NULLIF(sub.total_base_amount, 0.0), 0.0),
sub.comp_curr_prec
)
- LAG(ROUND(
COALESCE(sub.total_tax_amount * ABS(sub.cumulated_base_amount) / ABS(NULLIF(sub.total_base_amount, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount) * sub.total_tax_amount * ABS(sub.cumulated_base_amount) / NULLIF(sub.total_base_amount, 0.0), 0.0),
sub.comp_curr_prec
), 1, 0.0)
OVER (
@@ -472,11 +472,11 @@ class AccountMoveLine(models.Model):
sub.base_amount_currency,
ROUND(
COALESCE(sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / ABS(NULLIF(sub.total_base_amount_currency, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount_currency) * sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / NULLIF(sub.total_base_amount_currency, 0.0), 0.0),
sub.curr_prec
)
- LAG(ROUND(
COALESCE(sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / ABS(NULLIF(sub.total_base_amount_currency, 0.0)), 0.0),
COALESCE(SIGN(sub.cumulated_base_amount_currency) * sub.total_tax_amount_currency * ABS(sub.cumulated_base_amount_currency) / NULLIF(sub.total_base_amount_currency, 0.0), 0.0),
sub.curr_prec
), 1, 0.0)
OVER (
@@ -17,8 +17,8 @@ class TestAccountTaxDetailsReport(AccountTestInvoicingCommon):
.sorted(lambda x: (x.move_id, x.tax_line_id, x.tax_ids, x.tax_repartition_line_id))
return base_lines, tax_lines
def _get_tax_details(self, fallback=False):
domain = [('company_id', '=', self.env.company.id)]
def _get_tax_details(self, fallback=False, extra_domain=None):
domain = [('company_id', '=', self.env.company.id)] + (extra_domain or [])
tax_details_query, tax_details_params = self.env['account.move.line']._get_query_tax_details_from_domain(domain, fallback=fallback)
self.cr.execute(tax_details_query, tax_details_params)
tax_details_res = self.cr.dictfetchall()
@@ -1252,3 +1252,47 @@ class TestAccountTaxDetailsReport(AccountTestInvoicingCommon):
],
)
self.assertTotalAmounts(invoice, tax_details)
def test_amounts_sign(self):
for tax_sign in (1, -1):
tax = self.env['account.tax'].create({
'name': "tax",
'amount_type': 'percent',
'amount': tax_sign * 10.0,
})
amounts_list = [
(-1000.0, 7000.0, -2000.0),
(1000.0, -7000.0, 2000.0),
(-1000.0, -7000.0, 2000.0),
(1000.0, 7000.0, -2000.0),
]
for amounts in amounts_list:
with self.subTest(tax_sign=tax_sign, amounts=amounts):
invoice = self.env['account.move'].create({
'move_type': 'in_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [
Command.create({
'name': 'line2',
'account_id': self.company_data['default_account_revenue'].id,
'price_unit': amount,
'tax_ids': [Command.set(tax.ids)],
})
for amount in amounts],
})
_base_lines, tax_lines = self._dispatch_move_lines(invoice)
tax_details = self._get_tax_details(extra_domain=[('move_id', '=', invoice.id)])
self.assertTaxDetailsValues(
tax_details,
[
{
'tax_line_id': tax_lines[0].id,
'base_amount': amount,
'tax_amount': tax_sign * amount * 0.1,
}
for amount in amounts],
)
self.assertTotalAmounts(invoice, tax_details)