diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index 4962daa027e..c1a1d024c2c 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -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) diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py index 44406de8734..63c11259766 100644 --- a/addons/account/tests/test_tax.py +++ b/addons/account/tests/test_tax.py @@ -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 diff --git a/addons/account_tax_python/tests/test_tax.py b/addons/account_tax_python/tests/test_tax.py index 947e8503cdb..5341eef9ed5 100644 --- a/addons/account_tax_python/tests/test_tax.py +++ b/addons/account_tax_python/tests/test_tax.py @@ -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 diff --git a/addons/point_of_sale/static/src/app/store/pos_store.js b/addons/point_of_sale/static/src/app/store/pos_store.js index 645cfbe4193..2ec36f39a30 100644 --- a/addons/point_of_sale/static/src/app/store/pos_store.js +++ b/addons/point_of_sale/static/src/app/store/pos_store.js @@ -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); }