diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index d0f705c32ae..2b5f60b724f 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -634,30 +634,42 @@ class AccountReconcileModel(models.Model): if partner: st_line_subquery += r" AND aml.partner_id = %s" % partner.id else: - st_line_subquery += r""" - AND - ( - substring(REGEXP_REPLACE(st_line.payment_ref, '[^0-9\s]', '', 'g'), '\S(?:.*\S)*') != '' - AND - ( - (""" + self._get_select_communication_flag() + """) - OR - (""" + self._get_select_payment_reference_flag() + """) - ) - ) - OR - ( - /* We also match statement lines without partners with amls - whose partner's name's parts (splitting on space) are all present - within the payment_ref, in any order, with any characters between them. */ + st_line_fields_consideration = [ + (self.match_text_location_label, 'st_line.payment_ref'), + (self.match_text_location_note, 'st_line_move.narration'), + (self.match_text_location_reference, 'st_line_move.ref'), + ] - aml_partner.name IS NOT NULL - AND """ + unaccent("st_line.payment_ref") + r""" ~* ('^' || ( - SELECT string_agg(concat('(?=.*\m', chunk[1], '\M)'), '') - FROM regexp_matches(""" + unaccent("aml_partner.name") + r""", '\w{3,}', 'g') AS chunk - )) - ) - """ + no_partner_query = " OR ".join([ + r""" + ( + substring(REGEXP_REPLACE(""" + sql_field + r""", '[^0-9\s]', '', 'g'), '\S(?:.*\S)*') != '' + AND + ( + (""" + self._get_select_communication_flag() + r""") + OR + (""" + self._get_select_payment_reference_flag() + r""") + ) + ) + OR + ( + /* We also match statement lines without partners with amls + whose partner's name's parts (splitting on space) are all present + within the payment_ref, in any order, with any characters between them. */ + + aml_partner.name IS NOT NULL + AND """ + unaccent(sql_field) + r""" ~* ('^' || ( + SELECT string_agg(concat('(?=.*\m', chunk[1], '\M)'), '') + FROM regexp_matches(""" + unaccent("aml_partner.name") + r""", '\w{3,}', 'g') AS chunk + )) + ) + """ + for consider_field, sql_field in st_line_fields_consideration + if consider_field + ]) + + if no_partner_query: + st_line_subquery += " AND " + no_partner_query st_lines_queries.append(r"st_line.id = %s AND (%s)" % (st_line.id, st_line_subquery)) diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index 4d32c31591b..d5c429b05b9 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -298,6 +298,51 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): self.bank_line_5.id: {'aml_ids': [self.invoice_line_6.id], 'model': self.rule_1, 'partner': self.bank_line_5.partner_id}, }, statements=self.bank_st_2) + def test_matching_fields_match_text_location_no_partner(self): + self.bank_line_2.unlink() # One line is enough for this test + self.bank_line_1.partner_id = None + + self.partner_1.name = "Bernard Gagnant" + + self.rule_1.write({ + 'match_partner': False, + 'match_partner_ids': [(5, 0, 0)], + 'line_ids': [(5, 0, 0)], + }) + + st_line_initial_vals = {'ref': None, 'payment_ref': 'nothing', 'narration': None} + recmod_initial_vals = {'match_text_location_label': False, 'match_text_location_note': False, 'match_text_location_reference': False} + + rec_mod_options_to_fields = { + 'match_text_location_label': 'payment_ref', + 'match_text_location_note': 'narration', + 'match_text_location_reference': 'ref', + } + + for rec_mod_field, st_line_field in rec_mod_options_to_fields.items(): + self.rule_1.write({**recmod_initial_vals, rec_mod_field: True}) + # Fully reinitialize the statement line + self.bank_line_1.write(st_line_initial_vals) + + # Nothing should match + self._check_statement_matching(self.rule_1, { + self.bank_line_1.id: {'aml_ids': []}, + }, statements=self.bank_st) + + # Test matching with the invoice ref + self.bank_line_1.write({st_line_field: self.invoice_line_1.move_id.payment_reference}) + + self._check_statement_matching(self.rule_1, { + self.bank_line_1.id: {'aml_ids': self.invoice_line_1.ids, 'model': self.rule_1, 'partner': self.env['res.partner']}, + }, statements=self.bank_st) + + # Test matching with the partner name (reinitializing the statement line first) + self.bank_line_1.write({**st_line_initial_vals, st_line_field: self.partner_1.name}) + + self._check_statement_matching(self.rule_1, { + self.bank_line_1.id: {'aml_ids': self.invoice_line_1.ids, 'model': self.rule_1, 'partner': self.env['res.partner']}, + }, statements=self.bank_st) + def test_matching_fields_match_journal_ids(self): self.rule_1.match_journal_ids |= self.cash_st.journal_id self._check_statement_matching(self.rule_1, {