[FIX] account,point_of_sale: Fix computation of GST group of taxes in india

Configure the group of taxes 5% GST to be price_included and apply it on 295.
Both children taxes must have the exact same amount.
However, this is not the case. In this example, we get 7.02 for one tax (correct) but 7.20 for the other.
This is because both taxes are "include_base_amount".

opw-3758458

closes odoo/odoo#160541

X-original-commit: ce28edbaae5a9af0a8c6e1f2addf4285ec56e9e1
Signed-off-by: Claire Bretton (clbr) <clbr@odoo.com>
Signed-off-by: Laurent Smet (las) <las@odoo.com>
This commit is contained in:
Laurent Smet
2024-04-05 12:18:18 +00:00
parent b4985308b4
commit 89c9396cc3
4 changed files with 64 additions and 34 deletions
+17 -8
View File
@@ -757,11 +757,14 @@ class AccountTax(models.Model):
# For the indian case, when facing two percent price-included taxes having the same percentage,
# both need to produce the same tax amounts. To do that, the tax amount of those taxes are computed
# directly during the first traveling in reversed order.
total_percentage = sum(tax_factor for _i, tax_factor in incl_tax_amounts['percent_taxes'])
total_tax_amount = 0.0
for i, tax_factor in incl_tax_amounts['percent_taxes']:
tax_amount = float_round(base * tax_factor / (100 + total_percentage), precision_rounding=prec)
tax_amount = float_round(base * tax_factor / (100 + percent_amount), precision_rounding=prec)
total_tax_amount += tax_amount
cached_tax_amounts[i] = tax_amount
fixed_amount += tax_amount
for i, tax_factor in incl_tax_amounts['percent_taxes']:
cached_base_amounts[i] = base - total_tax_amount
percent_amount = 0.0
incl_tax_amounts.update({
@@ -822,7 +825,9 @@ class AccountTax(models.Model):
'fixed_amount': 0.0,
}
# Store the tax amounts we compute while searching for the total_excluded
cached_base_amounts = {}
cached_tax_amounts = {}
is_base_affected = True
if handle_price_include:
for tax in reversed(taxes):
tax_repartition_lines = (
@@ -832,7 +837,7 @@ class AccountTax(models.Model):
).filtered(lambda x: x.repartition_type == "tax")
sum_repartition_factor = sum(tax_repartition_lines.mapped("factor"))
if tax.include_base_amount:
if tax.include_base_amount and is_base_affected:
base = recompute_base(base, incl_tax_amounts)
store_included_tax_total = True
if self._context.get('force_price_include', tax.price_include):
@@ -844,7 +849,8 @@ class AccountTax(models.Model):
incl_tax_amounts['fixed_amount'] = abs(quantity) * tax.amount * sum_repartition_factor * abs(fixed_multiplicator)
else:
# tax.amount_type == other (python)
tax_amount = tax._compute_amount(base, sign * price_unit, quantity, product, partner, fixed_multiplicator) * sum_repartition_factor
tax_amount = tax._compute_amount(base, sign * price_unit, quantity, product, partner, fixed_multiplicator)
tax_amount = float_round(tax_amount, precision_rounding=prec)
incl_tax_amounts['fixed_amount'] += tax_amount
# Avoid unecessary re-computation
cached_tax_amounts[i] = tax_amount
@@ -857,6 +863,7 @@ class AccountTax(models.Model):
total_included_checkpoints[i] = base
store_included_tax_total = False
i -= 1
is_base_affected = tax.is_base_affected
total_excluded = recompute_base(base, incl_tax_amounts)
if self._context.get('round_base', True):
@@ -881,7 +888,9 @@ class AccountTax(models.Model):
for tax in taxes:
price_include = self._context.get('force_price_include', tax.price_include)
if price_include or tax.is_base_affected:
if price_include and i in cached_base_amounts:
tax_base_amount = cached_base_amounts[i]
elif price_include or tax.is_base_affected:
tax_base_amount = base
else:
tax_base_amount = total_excluded
@@ -890,12 +899,12 @@ class AccountTax(models.Model):
sum_repartition_factor = sum(tax_repartition_lines.mapped('factor'))
#compute the tax_amount
if not skip_checkpoint and price_include and total_included_checkpoints.get(i) is not None and sum_repartition_factor != 0:
if price_include and i in cached_tax_amounts:
tax_amount = cached_tax_amounts[i]
elif not skip_checkpoint and price_include and total_included_checkpoints.get(i) is not None and sum_repartition_factor != 0:
# We know the total to reach for that tax, so we make a substraction to avoid any rounding issues
tax_amount = total_included_checkpoints[i] - (base + cumulated_tax_included_amount)
cumulated_tax_included_amount = 0
elif price_include and i in cached_tax_amounts:
tax_amount = cached_tax_amounts[i]
else:
tax_amount = tax.with_context(force_price_include=False)._compute_amount(
tax_base_amount, sign * price_unit, quantity, product, partner, fixed_multiplicator)
+23 -3
View File
@@ -217,7 +217,7 @@ class TestTax(TestTaxCommon):
)
def test_tax_group_percent(self):
res = self.group_tax_percent.with_context({'force_price_include':True}).compute_all(100.0)
res = self.group_tax_percent.with_context({'force_price_include': True}).compute_all(100.0)
self._check_compute_all_results(
100, # 'total_included'
83.33, # 'total_excluded'
@@ -232,10 +232,11 @@ class TestTax(TestTaxCommon):
)
self.env.company.country_id = self.env.ref('base.in')
res = self.group_tax_percent.with_context({'force_price_include':True}).compute_all(100.0)
self.group_tax_percent.children_tax_ids.price_include = True
res = self.group_tax_percent.compute_all(100.0)
self._check_compute_all_results(
100, # 'total_included'
83.34, # 'total_excluded'
83.34, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
@@ -246,6 +247,25 @@ class TestTax(TestTaxCommon):
res
)
self.group_tax_percent.children_tax_ids.write({
'amount': 2.5,
'include_base_amount': True,
'is_base_affected': False,
})
res = self.group_tax_percent.compute_all(295.0)
self._check_compute_all_results(
295.0, # 'total_included'
280.96, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
(280.96, 7.02), # | 1 | 10% | |
(280.96, 7.02), # | 2 | 10% | |
# ---------------------------------------------------
],
res
)
def test_tax_percent_division(self):
self.division_tax.price_include = True
self.division_tax.include_base_amount = True
+5 -5
View File
@@ -20,7 +20,7 @@ class TestTaxPython(TestTaxCommon):
def test_tax_python_basic(self):
res = self.python_tax.compute_all(130.0)
self._check_compute_all_results(
136.96, # 'total_included'
136.96, # 'total_included'
130.0, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
@@ -49,13 +49,13 @@ class TestTaxPython(TestTaxCommon):
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'
130, # 'total_included'
116.08, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
(116.07, 6.96), # | 1 | 6% | t |
(116.07, 6.97), # | 1 | 6% | t |
(116.08, 6.96), # | 1 | 6% | t |
(116.08, 6.96), # | 1 | 6% | t |
# ---------------------------------------------------
],
res
@@ -1531,14 +1531,16 @@ export class PosStore extends Reactive {
}
if (company.country && company.country.code === "IN") {
for (const [i, tax_factor] of incl_tax_amounts.percent_taxes) {
const tax_amount = round_pr(
(base_amount * tax_factor) / (100 + percent_amount),
currency_rounding
);
let total_tax_amount = 0.0;
for(const [i, tax_factor] of incl_tax_amounts.percent_taxes){
const tax_amount = round_pr(base_amount * tax_factor / (100 + percent_amount), currency_rounding);
total_tax_amount += tax_amount;
cached_tax_amounts[i] = tax_amount;
fixed_amount += tax_amount;
}
for (const [i,] of incl_tax_amounts.percent_taxes) {
cached_base_amounts[i] = base - total_tax_amount;
}
percent_amount = 0.0;
}
@@ -1574,9 +1576,11 @@ export class PosStore extends Reactive {
};
var cached_tax_amounts = {};
var cached_base_amounts = {};
let is_base_affected = true;
if (handle_price_include) {
taxes.reverse().forEach(function (tax) {
if (tax.include_base_amount) {
if (tax.include_base_amount && is_base_affected) {
base = recompute_base(base, incl_tax_amounts);
store_included_tax_total = true;
}
@@ -1605,6 +1609,7 @@ export class PosStore extends Reactive {
}
}
i -= 1;
is_base_affected = tax.is_base_affected;
});
}
@@ -1624,24 +1629,20 @@ export class PosStore extends Reactive {
i = 0;
var cumulated_tax_included_amount = 0;
taxes.reverse().forEach(function (tax) {
if (tax.price_include || tax.is_base_affected) {
if (tax.price_include && i in cached_base_amounts) {
var tax_base_amount = cached_base_amounts[i];
} else if (tax.price_include || tax.is_base_affected) {
var tax_base_amount = base;
} else {
tax_base_amount = total_excluded;
}
if (
!skip_checkpoint &&
tax.price_include &&
total_included_checkpoints[i] !== undefined &&
tax.sum_repartition_factor != 0
) {
var tax_amount =
total_included_checkpoints[i] - (base + cumulated_tax_included_amount);
cumulated_tax_included_amount = 0;
} else if (tax.price_include && cached_tax_amounts.hasOwnProperty(i)) {
if (tax.price_include && cached_tax_amounts.hasOwnProperty(i)) {
var tax_amount = cached_tax_amounts[i];
} else {
} else if (!skip_checkpoint && tax.price_include && total_included_checkpoints[i] !== undefined) {
var tax_amount = total_included_checkpoints[i] - (base + cumulated_tax_included_amount);
cumulated_tax_included_amount = 0;
}else{
var tax_amount = self._compute_all(tax, tax_base_amount, quantity, true);
}