From 91bd2b8c387eef295be5429aeebaa43d72d2c7b5 Mon Sep 17 00:00:00 2001 From: Nicolas Galler Date: Tue, 29 Sep 2020 12:57:38 +0000 Subject: [PATCH] [FIX] account: avoid multiplying rounding error on unit price. Do not round the unit price when calculating the company currency price used to calculate the tax. This avoids rounding errors when the company currency amount has been calculated based on a converted (and rounded) unit price. Corrects a regression bug introduced in 13.0. The behavior has been corrected in 14.0 by a more extensive rework of the accounting module (commit id 419d4bbee04763367fef675a01dc73afa9758b2f among others). This fix seeks to correct the bug with minimal impact. In version 12.0, the tax amount was calculated strictly based on the total amount, which avoided compounding the rounding issue but had some other problems (see https://github.com/odoo/odoo/issues/35358). In version 14.0, the problem does not exist. This commit only includes the unit test. Current behavior before PR: For example: 20000 @ 2.82 with a rate of 1.1726 gives a tax amount in foreign currency of 11844, which is 10100 in company currency. But if the company currency amount is calculated based on a unit price of 2.4 (rounded converted amount of 2.82), the calculated tax amount will only be 10080 in company currency. Desired behavior after PR is merged: Tax amount is calculated based on the total amount in the foreign currency, not the amount based on the rounded unit price. opw-2340933 closes odoo/odoo#59365 X-original-commit: 14c86a020429dfc6b545b65b89cbc7e3828dc557 Signed-off-by: Nicolas Martinelli (nim) Signed-off-by: Nicolas Galler --- addons/account/tests/test_invoice_taxes.py | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/addons/account/tests/test_invoice_taxes.py b/addons/account/tests/test_invoice_taxes.py index 5bd600f1f1e..757cc1cefd2 100644 --- a/addons/account/tests/test_invoice_taxes.py +++ b/addons/account/tests/test_invoice_taxes.py @@ -432,3 +432,48 @@ class TestInvoiceTaxes(AccountTestInvoicingCommon): {'balance': -100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_pos.ids}, {'balance': 1100.0, 'tax_ids': [], 'tax_tag_ids': []}, ]) + + def test_tax_calculation_foreign_currency_large_quantity(self): + ''' Test: + Foreign currency with rate of 1.1726 and tax of 21% + price_unit | Quantity | Taxes + ------------------ + 2.82 | 20000 | 21% not incl + ''' + self.env['res.currency.rate'].search([]).unlink() + self.currency_usd_id = self.env.ref("base.USD") + self.currency_chf_id = self.env.ref("base.CHF") + # make sure that we have USD as base... + self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", + [self.currency_usd_id.id, self.env.company.id]) + self.env['res.currency.rate'].create({ + 'currency_id': self.currency_chf_id.id, + 'rate': 1.1726, + 'name': '2001-01-01'}) + invoice = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'partner_id': self.partner_a.id, + 'currency_id': self.currency_chf_id.id, + 'invoice_line_ids': [(0, 0, { + 'name': 'xxxx', + 'quantity': 20000, + 'price_unit': 2.82, + 'tax_ids': [(6, 0, self.percent_tax_1.ids)], + })] + }) + # don't post! Post will write() which will cause the amount to recalculate. + # but we want to make sure that the calculation is correct when it is made on + # the fly, from a user editing it in the web UI + # invoice.post() + # make sure the tax is calculated in the foreign currency correctly + self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [ + { + 'name': self.percent_tax_1.name, + # 20000 * 2.82 / 1.1726 + 'tax_base_amount': 48098.24, + 'price_unit': 11844, + # tax_base_amount * 21% + 'credit': 10100.63, + 'tax_ids': [] + }, + ])