[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 <smetl@users.noreply.github.com>
Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com>
This commit is contained in:
oco-odoo
2021-05-06 15:17:32 +00:00
parent 255c63ff26
commit 995f6fbb86
2 changed files with 41 additions and 2 deletions
@@ -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
)
)
@@ -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)