diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py index a94c4f037..350714cdb 100644 --- a/account_reconcile_oca/models/account_bank_statement_line.py +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -9,7 +9,7 @@ from odoo import Command, _, api, fields, models from odoo.exceptions import UserError from odoo.fields import first -from odoo.tools import float_is_zero +from odoo.tools import float_compare, float_is_zero class AccountBankStatementLine(models.Model): @@ -340,6 +340,28 @@ def _check_line_changed(self, line): or self.analytic_distribution != line.get("analytic_distribution", False) ) + def _check_reconcile_data_changed(self): + self.ensure_one() + data = self.reconcile_data_info.get("data", []) + liquidity_lines, _suspense_lines, _other_lines = self._seek_for_lines() + move_amount_cur = sum(liquidity_lines.mapped("amount_currency")) + move_credit = sum(liquidity_lines.mapped("credit")) + move_debit = sum(liquidity_lines.mapped("debit")) + stmt_amount_curr = stmt_debit = stmt_credit = 0.0 + for line_data in data: + if line_data["kind"] != "liquidity": + continue + stmt_amount_curr += line_data["currency_amount"] + stmt_debit += line_data["debit"] + stmt_credit += line_data["credit"] + prec = self.currency_id.rounding + return ( + float_compare(move_amount_cur, move_amount_cur, precision_rounding=prec) + != 0 + or float_compare(move_credit, stmt_credit, precision_rounding=prec) != 0 + or float_compare(move_debit, stmt_debit, precision_rounding=prec) != 0 + ) + def _get_manual_delete_vals(self): return { "manual_reference": False, @@ -953,6 +975,68 @@ def create(self, mvals): )(self._prepare_reconcile_line_data(data["data"])) return result + 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 + 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": 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 != st_line.partner_id: + st_line_vals["partner_id"] = st_line.partner_id.id + st_line.move_id.write(st_line_vals) + else: + super()._synchronize_to_moves(changed_fields=changed_fields) + + if not any( + field_name in changed_fields + for field_name in ( + "payment_ref", + "amount", + "amount_currency", + "foreign_currency_id", + "currency_id", + "partner_id", + ) + ): + return + # 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() + def _prepare_reconcile_line_data(self, lines): new_lines = [] reverse_lines = {} diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py index 4d2bdaf4a..a161c3e8f 100644 --- a/account_reconcile_oca/tests/test_bank_account_reconcile.py +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -892,6 +892,7 @@ def test_widget_invoice_change_partner(self): self.assertFalse(f.partner_id) f.manual_reference = "account.move.line;%s" % liquidity_lines.id f.manual_partner_id = inv1.partner_id + f.save() self.assertEqual(f.partner_id, inv1.partner_id) bank_stmt_line.clean_reconcile() # As we have a set a partner, the cleaning should assign the invoice automatically @@ -1296,6 +1297,7 @@ def test_invoice_foreign_currency_late_change_of_rate(self): "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", @@ -1309,6 +1311,17 @@ def test_invoice_foreign_currency_late_change_of_rate(self): 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