diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index 90242c5f343..8358d4f8665 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -385,7 +385,7 @@ class AccountTax(models.Model): # precision when we round the tax amount for each line (we use # the 'Account' decimal precision + 5), and that way it's like # rounding after the sum of the tax amounts of each line - prec = currency.decimal_places + prec = currency.rounding # In some cases, it is necessary to force/prevent the rounding of the tax and the total # amounts. For example, in SO/PO line, we don't want to round the price unit at the @@ -396,7 +396,7 @@ class AccountTax(models.Model): round_tax = bool(self.env.context['round']) if not round_tax: - prec += 5 + prec *= 1e-5 # 4) Iterate the taxes in the reversed sequence order to retrieve the initial base of the computation. # tax | base | amount | @@ -525,8 +525,8 @@ class AccountTax(models.Model): base, sign * price_unit, quantity, product, partner) # Round the tax_amount multiplied by the computed repartition lines factor. - tax_amount = round(tax_amount, prec) - factorized_tax_amount = round(tax_amount * sum_repartition_factor, prec) + tax_amount = round(tax_amount, precision_rounding=prec) + factorized_tax_amount = round(tax_amount * sum_repartition_factor, precision_rounding=prec) if price_include and not total_included_checkpoints.get(i): cumulated_tax_included_amount += factorized_tax_amount @@ -548,10 +548,10 @@ class AccountTax(models.Model): # The factorized_tax_amount will be 0.06 (200% x 0.03). However, each line taken independently will compute # 50% * 0.03 = 0.01 with rounding. It means there is 0.06 - 0.04 = 0.02 as total_rounding_error to dispatch # in lines as 2 x 0.01. - repartition_line_amounts = [round(tax_amount * line.factor, prec) for line in tax_repartition_lines] - total_rounding_error = round(factorized_tax_amount - sum(repartition_line_amounts), prec) + repartition_line_amounts = [round(tax_amount * line.factor, precision_rounding=prec) for line in tax_repartition_lines] + total_rounding_error = round(factorized_tax_amount - sum(repartition_line_amounts), precision_rounding=prec) nber_rounding_steps = int(abs(total_rounding_error / currency.rounding)) - rounding_error = round(nber_rounding_steps and total_rounding_error / nber_rounding_steps or 0.0, prec) + rounding_error = round(nber_rounding_steps and total_rounding_error / nber_rounding_steps or 0.0, precision_rounding=prec) for repartition_line, line_amount in zip(tax_repartition_lines, repartition_line_amounts): @@ -563,7 +563,7 @@ class AccountTax(models.Model): 'id': tax.id, 'name': partner and tax.with_context(lang=partner.lang).name or tax.name, 'amount': sign * line_amount, - 'base': round(sign * base, prec), + 'base': round(sign * base, precision_rounding=prec), 'sequence': tax.sequence, 'account_id': tax.cash_basis_transition_account_id.id if tax.tax_exigibility == 'on_payment' else repartition_line.account_id.id, 'analytic': tax.analytic, diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py index 1964d626c96..532ca7eb0c3 100644 --- a/addons/account/tests/test_tax.py +++ b/addons/account/tests/test_tax.py @@ -130,6 +130,12 @@ class TestTaxCommon(AccountTestInvoicingCommon): 'amount': 0, }) + cls.tax_5_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({ + 'name': "test_5_percent", + 'amount_type': 'percent', + 'amount': 5, + }) + cls.tax_8_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({ 'name': "test_8_percent", 'amount_type': 'percent', @@ -878,6 +884,53 @@ class TestTax(TestTaxCommon): res2 ) + def test_rounding_tax_included_round_per_line_04(self): + ''' Test the rounding of a 5% price included tax. + The decimal precision is set to 0.05. + ''' + self.tax_5_percent.price_include = True + self.tax_5_percent.company_id.currency_id.rounding = 0.05 + self.tax_5_percent.company_id.tax_calculation_rounding_method = 'round_per_line' + + res1 = self.tax_5_percent.compute_all(5) + self._check_compute_all_results( + 5, # 'total_included' + 4.75, # 'total_excluded' + [ + # base , amount + # --------------- + (4.75, 0.25), + # --------------- + ], + res1 + ) + + res2 = self.tax_5_percent.compute_all(10) + self._check_compute_all_results( + 10, # 'total_included' + 9.5, # 'total_excluded' + [ + # base , amount + # --------------- + (9.5, 0.5), + # --------------- + ], + res2 + ) + + res3 = self.tax_5_percent.compute_all(50) + self._check_compute_all_results( + 50, # 'total_included' + 47.6, # 'total_excluded' + [ + # base , amount + # --------------- + (47.6, 2.4), + # --------------- + ], + res3 + ) + def test_rounding_tax_included_round_globally_01(self): ''' Test the rounding of a 19% price included tax in an invoice having 27000 and 10920 as lines. The decimal precision is set to zero. @@ -945,3 +998,50 @@ class TestTax(TestTaxCommon): ], res2 ) + + def test_rounding_tax_included_round_globally_03(self): + ''' Test the rounding of a 5% price included tax. + The decimal precision is set to 0.05. + ''' + self.tax_5_percent.price_include = True + self.tax_5_percent.company_id.currency_id.rounding = 0.05 + self.tax_5_percent.company_id.tax_calculation_rounding_method = 'round_globally' + + res1 = self.tax_5_percent.compute_all(5) + self._check_compute_all_results( + 5, # 'total_included' + 4.75, # 'total_excluded' + [ + # base , amount + # --------------- + (4.75, 0.25), + # --------------- + ], + res1 + ) + + res2 = self.tax_5_percent.compute_all(10) + self._check_compute_all_results( + 10, # 'total_included' + 9.5, # 'total_excluded' + [ + # base , amount + # --------------- + (9.50, 0.50), + # --------------- + ], + res2 + ) + + res3 = self.tax_5_percent.compute_all(50) + self._check_compute_all_results( + 50, # 'total_included' + 47.6, # 'total_excluded' + [ + # base , amount + # --------------- + (47.60, 2.40), + # --------------- + ], + res3 + )