From 995f6fbb86af448cd8cb76f1b115d1de7b16fecb Mon Sep 17 00:00:00 2001 From: oco-odoo Date: Mon, 3 May 2021 15:15:43 +0000 Subject: [PATCH] [FIX] account: reconciliation models: fix priorities when matching amls from payments Since the payment refactoring, the structured reference of a payment is stored in its ref field, not payment_reference like for invoices. This caused payments never to be matched with highest priorities, as payment_reference_flag was always false, and only communication_flag could match. To reproduce: - Have a reconcile model with match_total_amount=False. - Create a statement line with communication a1b2c3 for 1000 - Create 3 payments: > 500, with memo a1b2c3 > 500, with memo a1b2c3 (so, the same one) > 500, with memo d1e2f3 - Open the reconciliation widget for your statement line ===> The 3 payments are matched, while only the two first ones should have been, as they were exact matches for the communication, and should hence have received higher priority. closes odoo/odoo#70394 X-original-commit: b5800c9d2088df2bb9c4fbe0fed91c7ef24299c5 Signed-off-by: Laurent Smet Signed-off-by: oco-odoo --- .../account/models/account_reconcile_model.py | 7 ++-- .../test_reconciliation_matching_rules.py | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index bb56bcf0517..4b866bcbbb6 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -612,6 +612,7 @@ class AccountReconcileModel(models.Model): LEFT JOIN account_move move ON move.id = aml.move_id AND move.state = 'posted' LEFT JOIN account_account account ON account.id = aml.account_id LEFT JOIN res_partner aml_partner ON aml.partner_id = aml_partner.id + LEFT JOIN account_payment payment ON payment.move_id = move.id WHERE aml.company_id = st_line_move.company_id AND move.state = 'posted' @@ -725,9 +726,11 @@ class AccountReconcileModel(models.Model): st_ref_list += ['st_line_move.ref'] if not st_ref_list: return "FALSE" - return r'''(move.payment_reference IS NOT NULL AND ({}))'''.format( + + # payment_reference is not used on account.move for payments; ref is used instead + return r'''((move.payment_reference IS NOT NULL OR (payment.id IS NOT NULL AND move.ref IS NOT NULL)) AND ({}))'''.format( ' OR '.join( - rf"regexp_replace(move.payment_reference, '\s+', '', 'g') = regexp_replace({st_ref}, '\s+', '', 'g')" + rf"regexp_replace(CASE WHEN payment.id IS NULL THEN move.payment_reference ELSE move.ref END, '\s+', '', 'g') = regexp_replace({st_ref}, '\s+', '', 'g')" for st_ref in st_ref_list ) ) diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index b7718ff0f7b..e3be048b114 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -919,3 +919,39 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off', 'partner': self.bank_line_1.partner_id}, self.bank_line_2.id: {'aml_ids': [self.invoice_line_2.id], 'model': second_inv_matching_rule, 'partner': self.bank_line_2.partner_id} }, statements=self.bank_st) + + def test_payment_similar_communications(self): + def create_payment_line(amount, memo, partner): + payment = self.env['account.payment'].create({ + 'amount': amount, + 'payment_type': 'inbound', + 'partner_type': 'customer', + 'partner_id': partner.id, + 'ref': memo, + 'destination_account_id': self.company_data['default_account_receivable'].id, + }) + payment.action_post() + + return payment.line_ids.filtered(lambda x: x.account_id.user_type_id.type not in {'receivable', 'payable'}) + + payment_partner = self.env['res.partner'].create({ + 'name': "Bernard Gagnant", + }) + + self.rule_1.match_partner_ids = [(6, 0, payment_partner.ids)] + + pmt_line_1 = create_payment_line(500, 'a1b2c3', payment_partner) + pmt_line_2 = create_payment_line(500, 'a1b2c3', payment_partner) + create_payment_line(500, 'd1e2f3', payment_partner) + + self.bank_line_1.write({ + 'amount': 1000, + 'payment_ref': 'a1b2c3', + 'partner_id': payment_partner.id, + }) + self.bank_line_2.unlink() + self.rule_1.match_total_amount = False + + self._check_statement_matching(self.rule_1, { + self.bank_line_1.id: {'aml_ids': (pmt_line_1 + pmt_line_2).ids, 'model': self.rule_1, 'partner': payment_partner}, + }, statements=self.bank_line_1.statement_id)