[FIX] account_reconcile_model_oca: Fix matching rules with no partner
The orm doesn't match monetary amounts using the related currency.
It means, -208.73 != 208.730000000000002.
Let's match the amount using an sql query instead.
Related to ae848e9981
pull/819/head
parent
0510276a36
commit
13f438d320
|
@ -380,15 +380,16 @@ class AccountReconcileModel(models.Model):
|
|||
:param st_line: A statement line.
|
||||
:param partner: The partner associated to the statement line.
|
||||
"""
|
||||
|
||||
def get_order_by_clause(alias=None):
|
||||
direction = "DESC" if self.matching_order == "new_first" else "ASC"
|
||||
dotted_alias = f"{alias}." if alias else ""
|
||||
return f"{dotted_alias}date_maturity {direction}, {dotted_alias}date {direction}, {dotted_alias}id {direction}" # noqa: E501
|
||||
|
||||
assert self.rule_type == "invoice_matching"
|
||||
self.env["account.move"].flush_model()
|
||||
self.env["account.move.line"].flush_model()
|
||||
|
||||
if self.matching_order == "new_first":
|
||||
order_by = "sub.date_maturity DESC, sub.date DESC, sub.id DESC"
|
||||
else:
|
||||
order_by = "sub.date_maturity ASC, sub.date ASC, sub.id ASC"
|
||||
|
||||
aml_domain = self._get_invoice_matching_amls_domain(st_line, partner)
|
||||
query = self.env["account.move.line"]._where_calc(aml_domain)
|
||||
from_string, from_params = query.from_clause
|
||||
|
@ -456,6 +457,7 @@ class AccountReconcileModel(models.Model):
|
|||
all_params += where_params
|
||||
|
||||
if sub_queries:
|
||||
order_by = get_order_by_clause(alias="sub")
|
||||
self._cr.execute(
|
||||
"""
|
||||
SELECT
|
||||
|
@ -480,14 +482,43 @@ class AccountReconcileModel(models.Model):
|
|||
"amls": self.env["account.move.line"].browse(candidate_ids),
|
||||
}
|
||||
|
||||
# Search without any matching based on textual information.
|
||||
if partner:
|
||||
if self.matching_order == "new_first":
|
||||
order = "date_maturity DESC, date DESC, id DESC"
|
||||
if not partner:
|
||||
st_line_currency = (
|
||||
st_line.foreign_currency_id
|
||||
or st_line.journal_id.currency_id
|
||||
or st_line.company_currency_id
|
||||
)
|
||||
if st_line_currency == self.company_id.currency_id:
|
||||
aml_amount_field = "amount_residual"
|
||||
else:
|
||||
order = "date_maturity ASC, date ASC, id ASC"
|
||||
aml_amount_field = "amount_residual_currency"
|
||||
|
||||
amls = self.env["account.move.line"].search(aml_domain, order=order)
|
||||
order_by = get_order_by_clause(alias="account_move_line")
|
||||
self._cr.execute(
|
||||
f"""
|
||||
SELECT account_move_line.id
|
||||
FROM {from_clause}
|
||||
WHERE
|
||||
{where_clause}
|
||||
AND account_move_line.currency_id = %s
|
||||
AND ROUND(account_move_line.{aml_amount_field}, %s) = ROUND(%s, %s)
|
||||
ORDER BY {order_by}
|
||||
""", # noqa: E501
|
||||
where_params
|
||||
+ [
|
||||
st_line_currency.id,
|
||||
st_line_currency.decimal_places,
|
||||
-st_line.amount_residual,
|
||||
st_line_currency.decimal_places,
|
||||
],
|
||||
)
|
||||
amls = self.env["account.move.line"].browse(
|
||||
[row[0] for row in self._cr.fetchall()]
|
||||
)
|
||||
else:
|
||||
amls = self.env["account.move.line"].search(
|
||||
aml_domain, order=get_order_by_clause()
|
||||
)
|
||||
if amls:
|
||||
return {
|
||||
"allow_auto_reconcile": False,
|
||||
|
|
|
@ -1095,40 +1095,6 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
# Matching is back thanks to "coincoin".
|
||||
self.assertEqual(st_line._retrieve_partner(), self.partner_1)
|
||||
|
||||
def test_partner_name_in_communication(self):
|
||||
self.invoice_line_1.partner_id.write({"name": "Archibald Haddock"})
|
||||
self.bank_line_1.write(
|
||||
{"partner_id": None, "payment_ref": "1234//HADDOCK-Archibald"}
|
||||
)
|
||||
self.bank_line_2.write({"partner_id": None})
|
||||
self.rule_1.write({"match_partner": False})
|
||||
|
||||
# bank_line_1 should match, as its communic. contains the invoice's partner name
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1},
|
||||
self.bank_line_2: {},
|
||||
},
|
||||
)
|
||||
|
||||
def test_partner_name_with_regexp_chars(self):
|
||||
self.invoice_line_1.partner_id.write({"name": "Archibald + Haddock"})
|
||||
self.bank_line_1.write(
|
||||
{"partner_id": None, "payment_ref": "1234//HADDOCK+Archibald"}
|
||||
)
|
||||
self.bank_line_2.write({"partner_id": None})
|
||||
self.rule_1.write({"match_partner": False})
|
||||
|
||||
# The query should still work
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1},
|
||||
self.bank_line_2: {},
|
||||
},
|
||||
)
|
||||
|
||||
def test_match_multi_currencies(self):
|
||||
"""Ensure the matching of candidates is made using the right statement line
|
||||
currency. In this test, the value of the statement line is 100 USD = 300
|
||||
|
@ -1540,3 +1506,70 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
rule._apply_rules(st_line, None),
|
||||
{"amls": term_lines, "model": rule},
|
||||
)
|
||||
|
||||
@freeze_time("2019-01-01")
|
||||
def test_matching_exact_amount_no_partner(self):
|
||||
"""In case the reconciliation model can't match via text or partner matching
|
||||
we do a last check to find amls with the exact amount.
|
||||
"""
|
||||
self.rule_1.write(
|
||||
{
|
||||
"match_text_location_label": False,
|
||||
"match_partner": False,
|
||||
"match_partner_ids": [Command.clear()],
|
||||
}
|
||||
)
|
||||
self.bank_line_1.partner_id = None
|
||||
self.bank_line_1.payment_ref = False
|
||||
|
||||
with self.subTest(test="single_currency"):
|
||||
st_line = self._create_st_line(
|
||||
amount=100, payment_ref=None, partner_id=None
|
||||
)
|
||||
invl = self._create_invoice_line(100, self.partner_1, "out_invoice")
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
st_line: {
|
||||
"amls": invl,
|
||||
"model": self.rule_1,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
with self.subTest(test="rounding"):
|
||||
st_line = self._create_st_line(
|
||||
amount=-208.73, payment_ref=None, partner_id=None
|
||||
)
|
||||
invl = self._create_invoice_line(208.73, self.partner_1, "in_invoice")
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
st_line: {
|
||||
"amls": invl,
|
||||
"model": self.rule_1,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
with self.subTest(test="multi_currencies"):
|
||||
foreign_curr = self.other_currency
|
||||
invl = self._create_invoice_line(
|
||||
300, self.partner_1, "out_invoice", currency=foreign_curr
|
||||
)
|
||||
st_line = self._create_st_line(
|
||||
amount=15.0,
|
||||
foreign_currency_id=foreign_curr.id,
|
||||
amount_currency=300.0,
|
||||
payment_ref=None,
|
||||
partner_id=None,
|
||||
)
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
st_line: {
|
||||
"amls": invl,
|
||||
"model": self.rule_1,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue