Skip to content

Commit

Permalink
[FIX] account: compute tax ordering
Browse files Browse the repository at this point in the history
**Issue Description**:
Currently, the order in which taxes are applied can vary based on the sequence they are entered in the invoice's Taxes field. This inconsistency arises when the tax list is not manually adjusted, leading to each tax having an identical sequence value. As a result, their hierarchy within the `flatten_taxes_hierarchy` function is determined by their input order rather than a defined sequence, causing unpredictable tax calculations.
https://github.com/odoo/odoo/blob/56666f8f7858fcbcce466d2240135b35509d2d96/addons/account/models/account_tax.py#L611-L632

A tax sequence should be explicitly defined, and in cases where sequences are identical, organization by tax ID should be enforced.

**Steps to Reproduce**:
1. Navigate to the `Account` or `Invoice` application.
2. Go to `Configuration > Taxes`.
3. Create a new tax with the advanced option `Affect Base of Subsequent Taxes` and specify an amount.
4. Generate a new invoice and add a line item priced at 100.
5. Apply taxes in the `Taxes` column in the following order: 15% followed by the newly created tax, and note the total amount.
6. Repeat step 5, but reverse the order of the taxes.
7. Observe that the total amounts differ between the two sequences.

**Proposed Solution**:
To ensure that taxes are applied consistently regardless of input order, we will modify the `flatten_taxes_hierarchy` function to add sorting by id. If the sequences are identical, the sorting will depend only on the id, otherwise it will be based on the sequence. This setting ensures a predictable and logical process for applying taxes.

opw-3691765

closes odoo#155414

X-original-commit: 9c2b421
Signed-off-by: Laurent Smet (las) <las@odoo.com>
Signed-off-by: Andrea Grazioso (agr) <agr@odoo.com>
  • Loading branch information
ilru-odoo authored and smetl committed Mar 1, 2024
1 parent 8ecf71f commit 516c471
Show file tree
Hide file tree
Showing 6 changed files with 11 additions and 4 deletions.
2 changes: 1 addition & 1 deletion addons/account/models/account_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def flatten_taxes_hierarchy(self, create_map=False):
# mapping each child tax to its parent group
all_taxes = self.env['account.tax']
groups_map = {}
for tax in self.sorted(key=lambda r: r.sequence):
for tax in self.sorted(key=lambda r: (r.sequence, r._origin.id)):
if tax.amount_type == 'group':
flattened_children = tax.children_tax_ids.flatten_taxes_hierarchy()
all_taxes += flattened_children
Expand Down
1 change: 1 addition & 0 deletions addons/account/tests/test_account_move_in_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def setUpClass(cls, chart_template_ref=None):
'amount_total': 1128.0,
}
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
(cls.tax_armageddon + cls.tax_armageddon.children_tax_ids).write({'type_tax_use': 'purchase'})

def setUp(self):
super(TestAccountMoveInInvoiceOnchanges, self).setUp()
Expand Down
1 change: 1 addition & 0 deletions addons/account/tests/test_account_move_in_refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def setUpClass(cls, chart_template_ref=None):
'amount_tax': 168.0,
'amount_total': 1128.0,
}
(cls.tax_armageddon + cls.tax_armageddon.children_tax_ids).write({'type_tax_use': 'purchase'})

def setUp(self):
super(TestAccountMoveInRefundOnchanges, self).setUp()
Expand Down
3 changes: 3 additions & 0 deletions addons/account/tests/test_invoice_tax_totals.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,15 @@ def test_tax_affect_base_2(self):
'amount': 10.0,
'tax_group_id': self.tax_group1.id,
'include_base_amount': True,
'sequence': 2,
})

tax_20 = self.env['account.tax'].create({
'name': "tax_20",
'amount_type': 'percent',
'amount': 20.0,
'tax_group_id': self.tax_group1.id,
'sequence': 2,
})

tax_30 = self.env['account.tax'].create({
Expand All @@ -325,6 +327,7 @@ def test_tax_affect_base_2(self):
'amount': 30.0,
'tax_group_id': self.tax_group2.id,
'include_base_amount': True,
'sequence': 1,
})

document = self._create_document_for_tax_totals_test([
Expand Down
5 changes: 3 additions & 2 deletions addons/account/tests/test_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,8 @@ def test_rounding_tax_included_round_per_line_02(self):
)

def test_rounding_tax_included_round_per_line_03(self):
''' Test the rounding of a 8% and 0% price included tax in an invoice having 8 * 15.55 as line.
''' Test the rounding of a 8% and 0% price included tax in an invoice having 8 * 15.55 as line
and a sequence that is solely dependent on the ID, as the tax sequence is identical.
The decimal precision is set to 2.
'''
self.tax_0_percent.company_id.currency_id.rounding = 0.01
Expand All @@ -877,8 +878,8 @@ def test_rounding_tax_included_round_per_line_03(self):
[
# base , amount
# -------------
(115.19, 9.21),
(115.19, 0.00),
(115.19, 9.21),
# -------------
],
res1
Expand Down
3 changes: 2 additions & 1 deletion addons/account_tax_python/tests/test_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ def test_tax_python_price_include(self):
res
)

res = (self.python_tax + self.python_tax).compute_all(130.0)
python_tax_2 = self.python_tax.copy()
res = (self.python_tax + python_tax_2).compute_all(130.0)
self._check_compute_all_results(
130, # 'total_included'
116.07, # 'total_excluded'
Expand Down

0 comments on commit 516c471

Please sign in to comment.