diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 51b5088ad71..be3edf6acc1 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -385,26 +385,45 @@ class AccountReconcileModel(models.Model): liquidity_lines, suspense_lines, other_lines = st_line._seek_for_lines() if st_line.to_check: - residual_balance = -liquidity_lines.balance + st_line_residual = -liquidity_lines.balance elif suspense_lines.account_id.reconcile: - residual_balance = sum(suspense_lines.mapped('amount_residual')) + st_line_residual = sum(suspense_lines.mapped('amount_residual')) else: - residual_balance = sum(suspense_lines.mapped('balance')) + st_line_residual = sum(suspense_lines.mapped('balance')) partner = partner or st_line.partner_id - lines_vals_list = [{'id': aml_id} for aml_id in aml_ids] + + lines_vals_list = [] + amls = self.env['account.move.line'].browse(aml_ids) + st_line_residual_before = st_line_residual + aml_total_residual = 0 + for aml in amls: + aml_total_residual += aml.amount_residual + + if aml.balance * st_line_residual > 0: + # Meaning they have the same signs, so they can't be reconciled together + assigned_balance = -aml.amount_residual + else: + assigned_balance = min(-aml.amount_residual, st_line_residual, key=abs) + st_line_residual -= assigned_balance + + lines_vals_list.append({ + 'id': aml.id, + 'balance': assigned_balance, + 'currency_id': st_line.move_id.company_id.currency_id.id, + }) + + write_off_amount = max(aml_total_residual, -st_line_residual_before, key=abs) + st_line_residual_before + st_line_residual + reconciliation_overview, open_balance_vals = st_line._prepare_reconciliation(lines_vals_list) - for reconciliation_vals in reconciliation_overview: - residual_balance -= reconciliation_vals['line_vals']['debit'] - reconciliation_vals['line_vals']['credit'] - - writeoff_vals_list = self._get_write_off_move_lines_dict(st_line, residual_balance) + writeoff_vals_list = self._get_write_off_move_lines_dict(st_line, write_off_amount) for line_vals in writeoff_vals_list: - residual_balance -= st_line.company_currency_id.round(line_vals['balance']) + st_line_residual -= st_line.company_currency_id.round(line_vals['balance']) # Check we have enough information to create an open balance. - if not st_line.company_currency_id.is_zero(residual_balance): + if not st_line.company_currency_id.is_zero(st_line_residual): if st_line.amount > 0: open_balance_account = partner.property_account_receivable_id else: diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index 5ec74054b85..ef471961a03 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -447,6 +447,27 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): {'partner_id': self.partner_2.id, 'debit': 1000.0, 'credit': 0.0}, ]) + def test_larger_invoice_auto_reconcile(self): + ''' Test auto reconciliation with an invoice with larger amount than the statement line's.''' + self.bank_line_1.amount = 40 + self.invoice_line_1.move_id.payment_reference = self.bank_line_1.payment_ref + + self.rule_1.sequence = 2 + self.rule_1.auto_reconcile = True + + self._check_statement_matching(self.rule_1, { + self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'reconciled', 'partner': self.bank_line_1.partner_id}, + self.bank_line_2.id: {'aml_ids': []}, + }, statements=self.bank_st) + + # Check first line has been well reconciled. + self.assertRecordValues(self.bank_line_1.line_ids, [ + {'partner_id': self.partner_1.id, 'debit': 40.0, 'credit': 0.0}, + {'partner_id': self.partner_1.id, 'debit': 0.0, 'credit': 40.0}, + ]) + + self.assertEqual(self.invoice_line_1.amount_residual, 60.0, "The invoice should have been partially reconciled") + def test_auto_reconcile_with_tax(self): ''' Test auto reconciliation with a tax amount included in the bank statement line''' self.rule_1.write({