From fd910639da6784c8e4ae309b7a58f135f5ebe403 Mon Sep 17 00:00:00 2001 From: Laurent Smet Date: Thu, 10 Aug 2023 09:04:17 +0000 Subject: [PATCH] [FIX] account: Fix reconciliation with very tiny rate with one foreign currency Suppose a very tiny rate 1:10000. l1 is expressed in company currency and has an amount of -10. l2 is expressed in foreign currency and has 1000000 in company currency for 100 in foreign currency. The reconciliation is made in foreign currency but there is nothing left to reconcile after converting -10 to the foreign currency because -10 / 10000 = 0.0001 ~= 0.0 So no partial is created. After this fix, the reconciliation fallbacks to a reconciliation in company currency if there is nothing left to reconcile after applying the rate. closes odoo/odoo#132304 Issue: 128234 X-original-commit: 359710c7d51ee2b7510cae59cec5b728226a26c1 Signed-off-by: Brice Bartoletti (bib) Signed-off-by: Laurent Smet (las) --- addons/account/models/account_move_line.py | 10 ++++--- .../tests/test_account_move_reconcile.py | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/addons/account/models/account_move_line.py b/addons/account/models/account_move_line.py index 048294a04d0..14ba48c1c04 100644 --- a/addons/account/models/account_move_line.py +++ b/addons/account/models/account_move_line.py @@ -1659,10 +1659,12 @@ class AccountMoveLine(models.Model): and not has_zero_residual \ and counterpart_currency != company_currency: rate = get_odoo_rate(aml, counterpart_currency) - available_residual_per_currency[counterpart_currency] = { - 'residual': counterpart_currency.round(remaining_amount * rate), - 'rate': rate, - } + residual_in_foreign_curr = counterpart_currency.round(remaining_amount * rate) + if not counterpart_currency.is_zero(residual_in_foreign_curr): + available_residual_per_currency[counterpart_currency] = { + 'residual': residual_in_foreign_curr, + 'rate': rate, + } elif currency == counterpart_currency \ and currency != company_currency \ and not has_zero_residual_currency: diff --git a/addons/account/tests/test_account_move_reconcile.py b/addons/account/tests/test_account_move_reconcile.py index dc53d58eff6..6ba971ca8f7 100644 --- a/addons/account/tests/test_account_move_reconcile.py +++ b/addons/account/tests/test_account_move_reconcile.py @@ -40,6 +40,12 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_unit_label': 'Diamond', 'currency_subunit_label': 'Carbon', }, rate2016=6.0, rate2017=4.0) + cls.currency_data_3 = cls.setup_multi_currency_data(default_values={ + 'name': 'Sand', + 'symbol': 'S', + 'currency_unit_label': 'Sand', + 'currency_subunit_label': 'Sand', + }, rate2016=0.0001, rate2017=0.00001) # ==== Cash Basis Taxes setup ==== @@ -1150,6 +1156,30 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): {'amount_residual': 40.0, 'amount_residual_currency': 40.0, 'reconciled': False}, ]) + def test_reconcile_one_foreign_currency_fallback_company_currency(self): + comp_curr = self.company_data['currency'] + foreign_curr = self.currency_data_3['currency'] + + line_1 = self.create_line_for_reconciliation(-10.0, -10.0, comp_curr, '2017-01-01') + line_2 = self.create_line_for_reconciliation(1000000.0, 100.0, foreign_curr, '2017-01-01') + amls = line_1 + line_2 + + amls.reconcile() + partials = self._get_partials(amls) + + self.assertRecordValues(partials, [{ + 'amount': 10.0, + 'debit_amount_currency': 0.001, + 'credit_amount_currency': 10.0, + 'debit_move_id': line_2.id, + 'credit_move_id': line_1.id, + }]) + self.assertFalse(partials.exchange_move_id) + self.assertRecordValues(line_1 + line_2, [ + {'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True}, + {'amount_residual': 999990.0, 'amount_residual_currency': 99.999, 'reconciled': False}, + ]) + def test_reconcile_exchange_difference_on_partial_same_foreign_currency_debit_expense_full_payment(self): currency = self.currency_data['currency']