From bf6e1d23a0727d7637c2c4c26179670370ab4a85 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Tue, 8 Oct 2024 12:44:09 +0200 Subject: [PATCH] [FIX] account_reconcile_oca : foreign currency reconcile with late currency rate It is possible that the statement line in foreign currency is created before the rate of the day is updated in Odoo. In this case we need to take the real rate of the statement line to comput the exchange rate --- .../models/account_bank_statement_line.py | 15 +++- .../tests/test_bank_account_reconcile.py | 72 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py index 248d935e..bb06175b 100644 --- a/account_reconcile_oca/models/account_bank_statement_line.py +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -8,6 +8,7 @@ from dateutil.relativedelta import relativedelta from odoo import Command, _, api, fields, models, tools from odoo.exceptions import UserError +from odoo.fields import first from odoo.tools import float_is_zero @@ -402,7 +403,11 @@ class AccountBankStatementLine(models.Model): @api.onchange("manual_amount_in_currency") def _onchange_manual_amount_in_currency(self): - if self.manual_line_id.exists() and self.manual_line_id: + if ( + self.manual_line_id.exists() + and self.manual_line_id + and self.manual_kind != "liquidity" + ): self.manual_amount = self.manual_in_currency_id._convert( self.manual_amount_in_currency, self.company_id.currency_id, @@ -1046,7 +1051,7 @@ class AccountBankStatementLine(models.Model): return reconcile_auxiliary_id, new_vals def _get_exchange_rate_amount(self, amount, currency_amount, currency, line): - if self.foreign_currency_id: + if self.foreign_currency_id == currency: # take real rate of statement line to compute the exchange rate gain/loss real_rate = self.amount / self.amount_currency to_amount_journal_currency = currency_amount * real_rate @@ -1057,6 +1062,12 @@ class AccountBankStatementLine(models.Model): self.date, ) to_amount = self.company_id.currency_id.round(to_amount_company_currency) + elif self.currency_id == currency and not self.foreign_currency_id: + liquidity_lines, _suspense_lines, _other_lines = self._seek_for_lines() + real_rate = ( + first(liquidity_lines).balance / first(liquidity_lines).amount_currency + ) + to_amount = self.company_id.currency_id.round(currency_amount * real_rate) else: to_amount = currency._convert( currency_amount, diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py index 59b485c7..fe7c9b95 100644 --- a/account_reconcile_oca/tests/test_bank_account_reconcile.py +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -1250,3 +1250,75 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): .account_type, "liability_payable", ) + + def test_invoice_foreign_currency_late_change_of_rate(self): + # Test we can reconcile lines in foreign currency even if the rate was updated + # late in odoo, meaning the statement line was created and the rate was updated + # in odoo after that. + self.env["res.currency.rate"].create( + { + "currency_id": self.env.ref("base.USD").id, + "name": time.strftime("%Y-07-14"), + "rate": 1.15, + } + ) + self.env["res.currency.rate"].create( + { + "currency_id": self.env.ref("base.USD").id, + "name": time.strftime("%Y-07-15"), + "rate": 1.2, + } + ) + inv1 = self._create_invoice( + currency_id=self.currency_usd_id, + invoice_amount=100, + date_invoice=time.strftime("%Y-07-14"), + auto_validate=True, + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "journal_id": self.bank_journal_usd.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_usd.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-16"), + } + ) + # rate of 07-16 is create after the statement line, meaning the rate of the + # statement line is the one of the 07-15 + self.env["res.currency.rate"].create( + { + "currency_id": self.env.ref("base.USD").id, + "name": time.strftime("%Y-07-16"), + "rate": 1.25, + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + line = f.reconcile_data_info["data"][0] + self.assertEqual( + line["currency_amount"], + 100, + ) + self.assertEqual( + line["amount"], + 83.33, + ) + f.manual_reference = "account.move.line;%s" % line["id"] + # simulate click on statement line, check amount does not recompute + self.assertEqual(f.manual_amount, 83.33) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda l: l.account_id.account_type == "asset_receivable" + ) + self.assertEqual(3, len(f.reconcile_data_info["data"])) + self.assertTrue(f.can_reconcile) + self.assertEqual(f.reconcile_data_info["data"][-1]["amount"], 3.63)