From d00fdb9310f7033f30c08768653b0a52d99bd53a Mon Sep 17 00:00:00 2001 From: "Guillaume (guva)" Date: Thu, 21 Apr 2022 10:08:14 +0000 Subject: [PATCH] [FIX] account: reconciliation on reversed move MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, we make sure that all lines are fully reconciled when reversing a move. Steps to reproduce: - Create a Journal Entry, with eg a line with 300$ debit/credit and two others lines to make the journal entry fully balanced - Then reverse the move -> Only one line is marked as fully reconciled, the other one is marked as partially reconciled. This is because each line was passed in the reconcile method with all the counterpart lines, even those which didn't belong to it. Therefore, all the firsts lines was marked as partially reconciled until the last one, which passed with the only counterpart line left. With this commit, we group the lines and counterpart lines by account, and reconcile them. opw-2810392 closes odoo/odoo#90928 X-original-commit: 0a03d029f93f6c0f31f6617c00943aa2dfcd937b Signed-off-by: William André (wan) Signed-off-by: Guillaume Vanleynseele --- addons/account/models/account_move.py | 17 ++---- .../tests/test_account_move_reconcile.py | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 56ac0b9af69..ec00bb99a97 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -2643,17 +2643,12 @@ class AccountMove(models.Model): if cancel: reverse_moves.with_context(move_reverse_cancel=cancel)._post(soft=False) for move, reverse_move in zip(self, reverse_moves): - lines = move.line_ids.filtered( - lambda x: (x.account_id.reconcile or x.account_id.internal_type == 'liquidity') - and not x.reconciled - ) - for line in lines: - counterpart_lines = reverse_move.line_ids.filtered( - lambda x: x.account_id == line.account_id - and x.currency_id == line.currency_id - and not x.reconciled - ) - (line + counterpart_lines).with_context(move_reverse_cancel=cancel).reconcile() + group = defaultdict(list) + for line in move.line_ids + reverse_move.line_ids: + group[(line.account_id, line.currency_id)].append(line.id) + for (account, dummy), line_ids in group.items(): + if account.reconcile or account.internal_type == 'liquidity': + self.env['account.move.line'].browse(line_ids).reconcile() return reverse_moves diff --git a/addons/account/tests/test_account_move_reconcile.py b/addons/account/tests/test_account_move_reconcile.py index a459ffcaaa1..a5053d6657a 100644 --- a/addons/account/tests/test_account_move_reconcile.py +++ b/addons/account/tests/test_account_move_reconcile.py @@ -1631,6 +1631,63 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): {'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True}, ]) + def test_reverse_with_multiple_lines(self): + """ + Test if all lines from a reversed entry are fully reconciled + """ + move = self.env['account.move'].create({ + 'move_type': 'entry', + 'line_ids': [ + (0, 0, { + 'debit': 1200.0, + 'credit': 0.0, + 'amount_currency': 3600.0, + 'account_id': self.company_data['default_account_receivable'].id, + }), + (0, 0, { + 'debit': 0.0, + 'credit': 200.0, + 'account_id': self.company_data['default_account_payable'].id, + }), + (0, 0, { + 'debit': 0.0, + 'credit': 400.0, + 'account_id': self.company_data['default_account_payable'].id, + }), + (0, 0, { + 'debit': 0.0, + 'credit': 600.0, + 'account_id': self.company_data['default_account_payable'].id, + }), + ], + }) + + move.action_post() + + lines_to_reconcile = move.line_ids.filtered(lambda x: (x.account_id.reconcile or x.account_id.internal_type == 'liquidity') and not x.reconciled) + + self.assertRecordValues(lines_to_reconcile, [ + {'debit': 1200.0, 'credit': 0.0, 'reconciled': False}, + {'debit': 0.0, 'credit': 200.0, 'reconciled': False}, + {'debit': 0.0, 'credit': 400.0, 'reconciled': False}, + {'debit': 0.0, 'credit': 600.0, 'reconciled': False}, + ]) + + reversed_move = move._reverse_moves(cancel=True) + + reversed_lines = reversed_move.line_ids.filtered(lambda x: ( + x.account_id.reconcile or x.account_id.internal_type == 'liquidity' + )) + + self.assertRecordValues(reversed_lines, [ + {'debit': 0.0, 'credit': 1200.0, 'reconciled': True}, + {'debit': 200.0, 'credit': 0.0, 'reconciled': True}, + {'debit': 400.0, 'credit': 0.0, 'reconciled': True}, + {'debit': 600.0, 'credit': 0.0, 'reconciled': True}, + ]) + + self.assertTrue(all([line.full_reconcile_id for line in reversed_lines])) + def test_reconcile_special_mexican_workflow_1(self): comp_curr = self.company_data['currency'] foreign_curr = self.env['res.currency'].create({