[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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user