[FIX] account: global tax rounding error management
Set Rounding Method to "Global rounding" Create a sale order having these line values: - Price Unit 54.45, tax 10% not included - Price Unit 600.00, tax 10% not included - Price Unit -500.00, tax 10% not included Tax total will be: Untaxed Amount 154.45 Taxes 15.44 Total 169.89 From the Sales Order create the Invoice Issue: Invoice tax totals will be Untaxed Amount 154.45 Taxes 15.45 Total 169.90 This occurs because when managing the rounding errors for global rounding the system 'force' a 1 cent difference on the negative line that do not need rounding Example: Line 1 - current diff: 0.0 - computed tax amount: 5.455 - tax amount + diff: 5.455, after rounding: 5.45 - stored diff for next line: -0.005 Line 2 - current diff: -0.005 - computed tax amount: 60.0 - tax amount + diff: 59.995, after rounding: 60.0 - stored diff for next line: -0.005 Line 3 - current diff: -0.005 - computed tax amount: -50.0 - tax amount + diff: -50.005, after rounding: -50.01 A solution is to not add the diff when the tax line is already rounded opw-3715229 closes odoo/odoo#156016 X-original-commit: bbca871841577203e44c98290ab0087ec94cf521 Signed-off-by: Laurent Smet (las) <las@odoo.com> Signed-off-by: Andrea Grazioso (agr) <agr@odoo.com> Co-authored-by: smetl <las@odoo.com>
This commit is contained in:
co-authored by
smetl
parent
cf1ead245c
commit
a73f06af8a
@@ -1210,27 +1210,55 @@ class AccountTax(models.Model):
|
||||
tax_details['group_tax_details'].append(tax_values)
|
||||
|
||||
if self.env.company.tax_calculation_rounding_method == 'round_globally':
|
||||
# Aggregate all amounts according the tax lines grouping key.
|
||||
comp_currency = self.env.company.currency_id
|
||||
amount_per_tax_repartition_line_id = defaultdict(lambda: {
|
||||
'delta_tax_amount': 0.0,
|
||||
'delta_tax_amount_currency': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'tax_values_list': [],
|
||||
})
|
||||
for base_line, to_update_vals, tax_values_list in to_process:
|
||||
currency = base_line['currency'] or self.env.company.currency_id
|
||||
comp_currency = self.env.company.currency_id
|
||||
currency = base_line['currency'] or comp_currency
|
||||
for tax_values in tax_values_list:
|
||||
grouping_key = frozendict(self._get_generation_dict_from_base_line(base_line, tax_values))
|
||||
|
||||
total_amounts = amount_per_tax_repartition_line_id[grouping_key]
|
||||
tax_amount_currency_with_delta = tax_values['tax_amount_currency'] \
|
||||
+ total_amounts['delta_tax_amount_currency']
|
||||
tax_amount_currency = currency.round(tax_amount_currency_with_delta)
|
||||
tax_amount_with_delta = tax_values['tax_amount'] \
|
||||
+ total_amounts['delta_tax_amount']
|
||||
tax_amount = comp_currency.round(tax_amount_with_delta)
|
||||
tax_values['tax_amount_currency'] = tax_amount_currency
|
||||
tax_values['tax_amount'] = tax_amount
|
||||
total_amounts['delta_tax_amount_currency'] = tax_amount_currency_with_delta - tax_amount_currency
|
||||
total_amounts['delta_tax_amount'] = tax_amount_with_delta - tax_amount
|
||||
total_amounts['tax_amount_currency'] += tax_values['tax_amount_currency']
|
||||
total_amounts['tax_amount'] += tax_values['tax_amount']
|
||||
total_amounts['tax_values_list'].append(tax_values)
|
||||
|
||||
# Round them like what the creation of tax lines would do.
|
||||
for key, values in amount_per_tax_repartition_line_id.items():
|
||||
currency = self.env['res.currency'].browse(key['currency_id']) or comp_currency
|
||||
values['tax_amount_rounded'] = comp_currency.round(values['tax_amount'])
|
||||
values['tax_amount_currency_rounded'] = currency.round(values['tax_amount_currency'])
|
||||
|
||||
# Dispatch the amount accross the tax values.
|
||||
for key, values in amount_per_tax_repartition_line_id.items():
|
||||
foreign_currency = self.env['res.currency'].browse(key['currency_id']) or comp_currency
|
||||
for currency, amount_field in ((comp_currency, 'tax_amount'), (foreign_currency, 'tax_amount_currency')):
|
||||
raw_value = values[amount_field]
|
||||
rounded_value = values[f'{amount_field}_rounded']
|
||||
diff = rounded_value - raw_value
|
||||
abs_diff = abs(diff)
|
||||
diff_sign = -1 if diff < 0 else 1
|
||||
tax_values_list = values['tax_values_list']
|
||||
nb_error = math.ceil(abs_diff / currency.rounding)
|
||||
nb_cents_per_tax_values = math.floor(nb_error / len(tax_values_list))
|
||||
nb_extra_cent = nb_error % len(tax_values_list)
|
||||
|
||||
for tax_values in tax_values_list:
|
||||
if not abs_diff:
|
||||
break
|
||||
|
||||
nb_amount_curr_cent = nb_cents_per_tax_values
|
||||
if nb_extra_cent:
|
||||
nb_amount_curr_cent += 1
|
||||
nb_extra_cent -= 1
|
||||
|
||||
# We can have more than one cent to distribute on a single tax_values.
|
||||
abs_delta_to_add = min(abs_diff, currency.rounding * nb_amount_curr_cent)
|
||||
tax_values[amount_field] += diff_sign * abs_delta_to_add
|
||||
abs_diff -= abs_delta_to_add
|
||||
|
||||
grouping_key_generator = grouping_key_generator or default_grouping_key_generator
|
||||
|
||||
|
||||
@@ -35,6 +35,12 @@ class TestTaxTotals(AccountTestInvoicingCommon):
|
||||
'sequence': 5
|
||||
})
|
||||
|
||||
cls.tax_10 = cls.env['account.tax'].create({
|
||||
'name': "tax_10a",
|
||||
'amount_type': 'percent',
|
||||
'amount': 10.0,
|
||||
})
|
||||
|
||||
cls.tax_16 = cls.env['account.tax'].create({
|
||||
'name': "tax_16",
|
||||
'amount_type': 'percent',
|
||||
@@ -733,6 +739,14 @@ class TestTaxTotals(AccountTestInvoicingCommon):
|
||||
run_case('round_per_line', lines, [16.60])
|
||||
run_case('round_globally', lines, [16.59])
|
||||
|
||||
lines = [
|
||||
(54.45, self.tax_10),
|
||||
(600, self.tax_10),
|
||||
(-500, self.tax_10),
|
||||
]
|
||||
run_case('round_per_line', lines, [15.45])
|
||||
run_case('round_globally', lines, [15.45])
|
||||
|
||||
def test_invoice_foreign_currency_tax_totals(self):
|
||||
self.env['res.currency.rate'].create({
|
||||
'name': '2018-01-01',
|
||||
|
||||
Reference in New Issue
Block a user