From dbd55e8fa5fb167eed76551a8ba922c61205e374 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Wed, 5 Feb 2025 16:35:47 +0100 Subject: [PATCH] [FIX] partner update from reconciliation widget We cant to avoid to change amounts on accounting entries during the reconciliation process. One of the goal is to avoid a following case : The statement line is created in a foreign currency journal, later, the rate is updated in Odoo. During reconciliation process, the partner is set on liquidity line, the accounting entries are synchronized and the balance changes. --- .../models/account_bank_statement_line.py | 83 +++++++++---------- .../tests/test_bank_account_reconcile.py | 12 +++ 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py index e29fb329..2b803262 100644 --- a/account_reconcile_oca/models/account_bank_statement_line.py +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -493,6 +493,8 @@ class AccountBankStatementLine(models.Model): line["kind"] if line["kind"] != "suspense" else "other" ) line.update(line_vals) + if line["kind"] == "liquidity": + self._update_move_partner() if self.manual_line_id and self.manual_line_id.id == line.get( "original_exchange_line_id" ): @@ -518,6 +520,11 @@ class AccountBankStatementLine(models.Model): ) self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + def _update_move_partner(self): + if self.partner_id == self.manual_partner_id: + return + self.partner_id = self.manual_partner_id + @api.depends("reconcile_data", "is_reconciled") def _compute_reconcile_data_info(self): for record in self: @@ -972,61 +979,48 @@ class AccountBankStatementLine(models.Model): )(self._prepare_reconcile_line_data(data["data"])) return result - def _synchronize_to_moves_custom(self, changed_fields): - """Similar process to what _synchronize_to_moves() method would do but without - the relative to all the changed_fields, we just need to update partner_id. - We precisely do not do an onchange of self.partner_id = self.manual_partner_id - to avoid making all those unnecessary changes, but we need to apply this - change to the account.move and the lines without side effects. - A change of manual_partner_id that has been reconciled should NOT change the - values of the account.move lines. + def _synchronize_to_moves(self, changed_fields): + """We want to avoid to change stuff (mainly amounts ) in accounting entries + when some changes happen in the reconciliation widget. The only change + (among the fields triggering the synchronization) possible from the + reconciliation widget is the partner_id field. + + So, in case of change on partner_id field we do not call super but make + only the required change (relative to partner) on accounting entries. + + And if something else changes, we then re-define reconcile_data_info to + make the data consistent (for example, if debit/credit has changed by + applying a different rate or even if there was a correction on statement + line amount). """ if self._context.get("skip_account_move_synchronization"): return - - # we actually check reconcile_data to find the partner of the liquidity lines - # because the written manual_partner_id is not always related to the liquidity - # line... - if not any(f_name in changed_fields for f_name in ("reconcile_data",)): - return - - for st_line in self.with_context(skip_account_move_synchronization=True): - data = st_line.reconcile_data_info.get("data", []) - partner_id = False - for line_data in data: - if line_data["kind"] == "liquidity": - partner_id = ( - line_data.get("partner_id") - and line_data.get("partner_id")[0] - or False - ) - break - if st_line.partner_id.id != partner_id: + if "partner_id" in changed_fields and not any( + field_name in changed_fields + for field_name in ( + "payment_ref", + "amount", + "amount_currency", + "foreign_currency_id", + "currency_id", + ) + ): + for st_line in self.with_context(skip_account_move_synchronization=True): ( liquidity_lines, suspense_lines, _other_lines, ) = st_line._seek_for_lines() - line_vals = {"partner_id": partner_id} + line_vals = {"partner_id": st_line.partner_id} line_ids_commands = [(1, liquidity_lines.id, line_vals)] if suspense_lines: line_ids_commands.append((1, suspense_lines.id, line_vals)) st_line_vals = {"line_ids": line_ids_commands} - if st_line.move_id.partner_id.id != partner_id: - st_line_vals["partner_id"] = partner_id + if st_line.move_id.partner_id != st_line.partner_id: + st_line_vals["partner_id"] = st_line.partner_id.id st_line.move_id.write(st_line_vals) - st_line.write({"partner_id": partner_id}) - - def _synchronize_to_moves(self, changed_fields): - """We take advantage of this method to call the custom method that does - specific things. Also, if something is changed, we will re-define - reconcile_data_info to make the data consistent (for example, if debit/credit - has changed by applying a different rate). - """ - super()._synchronize_to_moves(changed_fields=changed_fields) - self._synchronize_to_moves_custom(changed_fields) - if self._context.get("skip_account_move_synchronization"): - return + else: + super()._synchronize_to_moves(changed_fields=changed_fields) if not any( field_name in changed_fields @@ -1040,8 +1034,9 @@ class AccountBankStatementLine(models.Model): ) ): return - - for st_line in self.with_context(skip_account_move_synchronization=True): + # reset reconcile_data_info if amounts are not consistent anymore with the + # amounts of the accounting entries + for st_line in self: if st_line._check_reconcile_data_changed(): st_line.reconcile_data_info = st_line._default_reconcile_data() diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py index 83bab51a..3aeb2148 100644 --- a/account_reconcile_oca/tests/test_bank_account_reconcile.py +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -1352,6 +1352,7 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): "rate": 1.25, } ) + liquidity_lines, suspense_lines, other_lines = bank_stmt_line._seek_for_lines() with Form( bank_stmt_line, view="account_reconcile_oca.bank_statement_line_form_reconcile_view", @@ -1365,6 +1366,17 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): line["amount"], 83.33, ) + # check that adding a partner does not recompute the amounts on accounting + # entries, but is still synchronized with accounting entries + f.manual_reference = "account.move.line;%s" % liquidity_lines.id + f.manual_partner_id = inv1.partner_id + self.assertEqual(f.partner_id, inv1.partner_id) + self.assertEqual(liquidity_lines.debit, 83.33) + f.save() + # check liquidity line did not recompute debit with the new rate with + # partner change + self.assertEqual(liquidity_lines.debit, 83.33) + self.assertEqual(liquidity_lines.partner_id, inv1.partner_id) f.manual_reference = "account.move.line;%s" % line["id"] # simulate click on statement line, check amount does not recompute f.manual_partner_id = inv1.partner_id