[FIX] *: pre-commit fixes
Due to latest copier template with all the checks.pull/654/head
parent
3f8a1a8ef9
commit
90ca34afc2
|
@ -155,8 +155,8 @@ class MassReconcileAdvanced(models.AbstractModel):
|
|||
mkey, mvalue = matcher
|
||||
omkey, omvalue = opposite_matcher
|
||||
assert mkey == omkey, _(
|
||||
"A matcher %(mkey)s is compared with a matcher %(omkey)s, the _matchers and "
|
||||
"_opposite_matchers are probably wrong"
|
||||
"A matcher %(mkey)s is compared with a matcher %(omkey)s, the _matchers "
|
||||
"and _opposite_matchers are probably wrong"
|
||||
) % {"mkey": mkey, "omkey": omkey}
|
||||
if not isinstance(mvalue, list | tuple):
|
||||
mvalue = (mvalue,)
|
||||
|
|
|
@ -63,12 +63,14 @@ class AccountBankStatementLine(models.Model):
|
|||
continue
|
||||
|
||||
# Find a partner having a name contained inside the statement line values.
|
||||
# Take care a partner could contain some special characters in its name that needs to be escaped.
|
||||
# Take care a partner could contain some special characters in its name that
|
||||
# needs to be escaped.
|
||||
sub_queries.append(
|
||||
rf"""
|
||||
{unaccent("%s")} ~* ('^' || (
|
||||
SELECT STRING_AGG(CONCAT('(?=.*\m', chunk[1], '\M)'), '')
|
||||
FROM regexp_matches({unaccent('partner.name')}, '\w{{3,}}', 'g') AS chunk
|
||||
FROM regexp_matches({unaccent('partner.name')}, '\w{{3,}}', 'g')
|
||||
AS chunk
|
||||
))
|
||||
"""
|
||||
)
|
||||
|
@ -100,7 +102,8 @@ class AccountBankStatementLine(models.Model):
|
|||
return self.env["res.partner"]
|
||||
|
||||
def _get_st_line_strings_for_matching(self, allowed_fields=None):
|
||||
"""Collect the strings that could be used on the statement line to perform some matching.
|
||||
"""Collect the strings that could be used on the statement line to perform some
|
||||
matching.
|
||||
:param allowed_fields: A explicit list of fields to consider.
|
||||
:return: A list of strings.
|
||||
"""
|
||||
|
|
|
@ -14,13 +14,14 @@ class AccountReconcileModel(models.Model):
|
|||
####################################################
|
||||
|
||||
def _apply_lines_for_bank_widget(self, residual_amount_currency, partner, st_line):
|
||||
"""Apply the reconciliation model lines to the statement line passed as parameter.
|
||||
:param residual_amount_currency: The open balance of the statement line in the bank reconciliation widget
|
||||
expressed in the statement line currency.
|
||||
:param partner: The partner set on the wizard.
|
||||
:param st_line: The statement line processed by the bank reconciliation widget.
|
||||
:return: A list of python dictionaries (one per reconcile model line) representing
|
||||
the journal items to be created by the current reconcile model.
|
||||
"""Apply the reconciliation model lines to the statement line passed as
|
||||
parameter.
|
||||
:param residual_amount_currency: The open balance of the statement line in the
|
||||
bank reconciliation widget expressed in the statement line currency.
|
||||
:param partner: The partner set on the wizard.
|
||||
:param st_line: The statement line processed by the bank reconciliation widget.
|
||||
:return: A list of python dictionaries (one per reconcile model line)
|
||||
representing the journal items to be created by the current reconcile model.
|
||||
"""
|
||||
self.ensure_one()
|
||||
currency = (
|
||||
|
@ -48,9 +49,11 @@ class AccountReconcileModel(models.Model):
|
|||
|
||||
def _get_taxes_move_lines_dict(self, tax, base_line_dict):
|
||||
"""Get move.lines dict (to be passed to the create()) corresponding to a tax.
|
||||
:param tax: An account.tax record.
|
||||
:param base_line_dict: A dict representing the move.line containing the base amount.
|
||||
:return: A list of dict representing move.lines to be created corresponding to the tax.
|
||||
:param tax: An account.tax record.
|
||||
:param base_line_dict: A dict representing the move.line containing the base
|
||||
amount.
|
||||
:return: A list of dict representing move.lines to be created corresponding to
|
||||
the tax.
|
||||
"""
|
||||
self.ensure_one()
|
||||
balance = base_line_dict["balance"]
|
||||
|
@ -103,9 +106,12 @@ class AccountReconcileModel(models.Model):
|
|||
return new_aml_dicts
|
||||
|
||||
def _get_write_off_move_lines_dict(self, residual_balance, partner_id):
|
||||
"""Get move.lines dict corresponding to the reconciliation model's write-off lines.
|
||||
:param residual_balance: The residual balance of the account on the manual reconciliation widget.
|
||||
:return: A list of dict representing move.lines to be created corresponding to the write-off lines.
|
||||
"""Get move.lines dict corresponding to the reconciliation model's write-off
|
||||
lines.
|
||||
:param residual_balance: The residual balance of the account on the manual
|
||||
reconciliation widget.
|
||||
:return: A list of dict representing move.lines to be created corresponding to
|
||||
the write-off lines.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
|
@ -153,8 +159,9 @@ class AccountReconcileModel(models.Model):
|
|||
if detected_fiscal_position:
|
||||
taxes = detected_fiscal_position.map_tax(taxes)
|
||||
writeoff_line["tax_ids"] += [Command.set(taxes.ids)]
|
||||
# Multiple taxes with force_tax_included results in wrong computation, so we
|
||||
# only allow to set the force_tax_included field if we have one tax selected
|
||||
# Multiple taxes with force_tax_included results in wrong computation,
|
||||
# so we only allow to set the force_tax_included field if we have one
|
||||
# tax selected
|
||||
if line.force_tax_included:
|
||||
taxes = taxes[0].with_context(force_price_include=True)
|
||||
tax_vals_list = self._get_taxes_move_lines_dict(taxes, writeoff_line)
|
||||
|
@ -172,15 +179,17 @@ class AccountReconcileModel(models.Model):
|
|||
def _apply_rules(self, st_line, partner):
|
||||
"""Apply criteria to get candidates for all reconciliation models.
|
||||
This function is called in enterprise by the reconciliation widget to match
|
||||
the statement line with the available candidates (using the reconciliation models).
|
||||
the statement line with the available candidates (using the reconciliation
|
||||
models).
|
||||
:param st_line: The statement line to match.
|
||||
:param partner: The partner to consider.
|
||||
:return: A dict mapping each statement line id with:
|
||||
* aml_ids: A list of account.move.line ids.
|
||||
* model: An account.reconcile.model record (optional).
|
||||
* status: 'reconciled' if the lines has been already reconciled, 'write_off' if the write-off
|
||||
must be applied on the statement line.
|
||||
* auto_reconcile: A flag indicating if the match is enough significant to auto reconcile the candidates.
|
||||
:return: A dict mapping each statement line id with:
|
||||
* aml_ids: A list of account.move.line ids.
|
||||
* model: An account.reconcile.model record (optional).
|
||||
* status: 'reconciled' if the lines has been already reconciled, 'write_off'
|
||||
if the write-off must be applied on the statement line.
|
||||
* auto_reconcile: A flag indicating if the match is enough significant to
|
||||
auto reconcile the candidates.
|
||||
"""
|
||||
available_models = self.filtered(
|
||||
lambda m: m.rule_type != "writeoff_button"
|
||||
|
@ -318,7 +327,8 @@ class AccountReconcileModel(models.Model):
|
|||
|
||||
def _get_invoice_matching_st_line_tokens(self, st_line):
|
||||
"""Parse the textual information from the statement line passed as parameter
|
||||
in order to extract from it the meaningful information in order to perform the matching.
|
||||
in order to extract from it the meaningful information in order to perform the
|
||||
matching.
|
||||
:param st_line: A statement line.
|
||||
:return: A list of tokens, each one being a string.
|
||||
"""
|
||||
|
@ -347,7 +357,8 @@ class AccountReconcileModel(models.Model):
|
|||
return tokens
|
||||
|
||||
def _get_invoice_matching_amls_candidates(self, st_line, partner):
|
||||
"""Returns the match candidates for the 'invoice_matching' rule, with respect to the provided parameters.
|
||||
"""Returns the match candidates for the 'invoice_matching' rule, with respect to
|
||||
the provided parameters.
|
||||
:param st_line: A statement line.
|
||||
:param partner: The partner associated to the statement line.
|
||||
"""
|
||||
|
@ -381,14 +392,17 @@ class AccountReconcileModel(models.Model):
|
|||
UNNEST(
|
||||
REGEXP_SPLIT_TO_ARRAY(
|
||||
SUBSTRING(
|
||||
REGEXP_REPLACE({table_alias}.{field}, '[^0-9\s]', '', 'g'),
|
||||
REGEXP_REPLACE(
|
||||
{table_alias}.{field}, '[^0-9\s]', '', 'g'
|
||||
),
|
||||
'\S(?:.*\S)*'
|
||||
),
|
||||
'\s+'
|
||||
)
|
||||
) AS token
|
||||
FROM {tables}
|
||||
JOIN account_move account_move_line__move_id ON account_move_line__move_id.id = account_move_line.move_id
|
||||
JOIN account_move account_move_line__move_id
|
||||
ON account_move_line__move_id.id = account_move_line.move_id
|
||||
WHERE {where_clause} AND {table_alias}.{field} IS NOT NULL
|
||||
"""
|
||||
)
|
||||
|
@ -432,11 +446,14 @@ class AccountReconcileModel(models.Model):
|
|||
}
|
||||
|
||||
def _get_invoice_matching_rules_map(self):
|
||||
"""Get a mapping <priority_order, rule> that could be overridden in others modules.
|
||||
"""Get a mapping <priority_order, rule> that could be overridden in others
|
||||
modules.
|
||||
:return: a mapping <priority_order, rule> where:
|
||||
* priority_order: Defines in which order the rules will be evaluated, the lowest comes first.
|
||||
This is extremely important since the algorithm stops when a rule returns some candidates.
|
||||
* rule: Method taking <st_line, partner> as parameters and returning the candidates journal items found.
|
||||
* priority_order: Defines in which order the rules will be evaluated, the
|
||||
lowest comes first. This is extremely important since the algorithm stops
|
||||
when a rule returns some candidates.
|
||||
* rule: Method taking <st_line, partner> as parameters and returning the
|
||||
candidates journal items found.
|
||||
"""
|
||||
rules_map = defaultdict(list)
|
||||
rules_map[10].append(self._get_invoice_matching_amls_candidates)
|
||||
|
@ -563,9 +580,11 @@ class AccountReconcileModel(models.Model):
|
|||
)
|
||||
> 0
|
||||
):
|
||||
# Here, we still have room for other candidates ; so we add the current one to the list we keep.
|
||||
# Then, we continue iterating, even if there is no room anymore, just in case one of the following candidates
|
||||
# is an exact match, which would then be preferred on the current candidates.
|
||||
# Here, we still have room for other candidates ; so we add the
|
||||
# current one to the list we keep. Then, we continue iterating, even
|
||||
# if there is no room anymore, just in case one of the following
|
||||
# candidates is an exact match, which would then be preferred on the
|
||||
# current candidates.
|
||||
kepts_amls_values_list.append(aml_values)
|
||||
sum_amount_residual_currency += aml_values[
|
||||
"amount_residual_currency"
|
||||
|
@ -580,7 +599,8 @@ class AccountReconcileModel(models.Model):
|
|||
else:
|
||||
return None, []
|
||||
|
||||
# Try to match a batch with the early payment feature. Only a perfect match is allowed.
|
||||
# Try to match a batch with the early payment feature. Only a perfect match is
|
||||
# allowed.
|
||||
match_type, kepts_amls_values_list = match_batch_amls(amls_with_epd_values_list)
|
||||
if match_type != "perfect":
|
||||
kepts_amls_values_list = []
|
||||
|
@ -603,15 +623,18 @@ class AccountReconcileModel(models.Model):
|
|||
def _check_rule_propositions(self, st_line, amls_values_list):
|
||||
"""Check restrictions that can't be handled for each move.line separately.
|
||||
Note: Only used by models having a type equals to 'invoice_matching'.
|
||||
:param st_line: The statement line.
|
||||
:param amls_values_list: The candidates account.move.line as a list of dict:
|
||||
* aml: The record.
|
||||
* amount_residual: The amount residual to consider.
|
||||
* amount_residual_currency: The amount residual in foreign currency to consider.
|
||||
:param st_line: The statement line.
|
||||
:param amls_values_list: The candidates account.move.line as a list of dict:
|
||||
* aml: The record.
|
||||
* amount_residual: The amount residual to consider.
|
||||
* amount_residual_currency: The amount residual in foreign currency to
|
||||
consider.
|
||||
:return: A string representing what to do with the candidates:
|
||||
* rejected: Reject candidates.
|
||||
* allow_write_off: Allow to generate the write-off from the reconcile model lines if specified.
|
||||
* allow_auto_reconcile: Allow to automatically reconcile entries if 'auto_validate' is enabled.
|
||||
* rejected: Reject candidates.
|
||||
* allow_write_off: Allow to generate the write-off from the reconcile model
|
||||
lines if specified.
|
||||
* allow_auto_reconcile: Allow to automatically reconcile entries if
|
||||
'auto_validate' is enabled.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
|
@ -637,8 +660,8 @@ class AccountReconcileModel(models.Model):
|
|||
if st_line_currency.is_zero(amount_curr_after_rec):
|
||||
return {"allow_auto_reconcile"}
|
||||
|
||||
# The payment amount is higher than the sum of invoices.
|
||||
# In that case, don't check the tolerance and don't try to generate any write-off.
|
||||
# The payment amount is higher than the sum of invoices. In that case, don't
|
||||
# check the tolerance and don't try to generate any write-off.
|
||||
if amount_curr_after_rec > 0.0:
|
||||
return {"allow_auto_reconcile"}
|
||||
|
||||
|
@ -646,8 +669,8 @@ class AccountReconcileModel(models.Model):
|
|||
if self.payment_tolerance_param == 0:
|
||||
return {"rejected"}
|
||||
|
||||
# If the tolerance is expressed as a fixed amount, check the residual payment amount doesn't exceed the
|
||||
# tolerance.
|
||||
# If the tolerance is expressed as a fixed amount, check the residual payment
|
||||
# amount doesn't exceed the tolerance.
|
||||
if (
|
||||
self.payment_tolerance_type == "fixed_amount"
|
||||
and -amount_curr_after_rec <= self.payment_tolerance_param
|
||||
|
|
|
@ -9,8 +9,8 @@ class TestAccountReconciliationCommon(AccountTestInvoicingCommon):
|
|||
|
||||
"""Tests for reconciliation (account.tax)
|
||||
|
||||
Test used to check that when doing a sale or purchase invoice in a different currency,
|
||||
the result will be balanced.
|
||||
Test used to check that when doing a sale or purchase invoice in a different
|
||||
currency, the result will be balanced.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -402,7 +402,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
},
|
||||
)
|
||||
|
||||
# Test matching with the partner name (reinitializing the statement line first)
|
||||
# Test matching with the partner name (resetting the statement line first)
|
||||
self.bank_line_1.write(
|
||||
{**st_line_initial_vals, st_line_field: self.partner_1.name}
|
||||
)
|
||||
|
@ -920,7 +920,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
)
|
||||
|
||||
def test_auto_reconcile_with_tax(self):
|
||||
"""Test auto reconciliation with a tax amount included in the bank statement line"""
|
||||
"""Test auto reconciliation with a tax amount included in the bank stat. line"""
|
||||
self.rule_1.write(
|
||||
{
|
||||
"auto_reconcile": True,
|
||||
|
@ -968,7 +968,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
)
|
||||
|
||||
def test_auto_reconcile_with_tax_fpos(self):
|
||||
"""Test the fiscal positions are applied by reconcile models when using taxes."""
|
||||
"""Test the fiscal positions are applied by reconcile models when using taxes"""
|
||||
self.rule_1.write(
|
||||
{
|
||||
"auto_reconcile": True,
|
||||
|
@ -1031,6 +1031,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
def test_reverted_move_matching(self):
|
||||
partner = self.partner_1
|
||||
AccountMove = self.env["account.move"]
|
||||
account = self.bank_journal.company_id.account_journal_payment_credit_account_id
|
||||
move = AccountMove.create(
|
||||
{
|
||||
"journal_id": self.bank_journal.id,
|
||||
|
@ -1049,7 +1050,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
0,
|
||||
0,
|
||||
{
|
||||
"account_id": self.bank_journal.company_id.account_journal_payment_credit_account_id.id,
|
||||
"account_id": account.id,
|
||||
"partner_id": partner.id,
|
||||
"name": "I'm gonna cut you into little pieces",
|
||||
"credit": 10,
|
||||
|
@ -1140,7 +1141,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
"line_ids": [(5, 0, 0)],
|
||||
"match_partner": False,
|
||||
"match_label": "contains",
|
||||
"match_label_param": "Tournicoti", # So that we only match what we want to test
|
||||
"match_label_param": "Tournicoti", # match what we want to test
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1165,7 +1166,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
{
|
||||
"match_partner": False,
|
||||
"match_label": "contains",
|
||||
"match_label_param": "doudlidou", # So that we only match what we want to test
|
||||
"match_label_param": "doudlidou", # match what we want to test
|
||||
"payment_tolerance_param": 10.0,
|
||||
"auto_reconcile": True,
|
||||
}
|
||||
|
@ -1219,7 +1220,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
self.bank_line_2.write({"partner_id": None})
|
||||
self.rule_1.write({"match_partner": False})
|
||||
|
||||
# bank_line_1 should match, as its communication contains the invoice's partner name
|
||||
# bank_line_1 should match, as its communic. contains the invoice's partner name
|
||||
self._check_statement_matching(
|
||||
self.rule_1,
|
||||
{
|
||||
|
@ -1246,13 +1247,13 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
)
|
||||
|
||||
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 GOL = 900 DAR and we want to match two journal
|
||||
items of:
|
||||
"""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
|
||||
GOL = 900 DAR and we want to match two journal items of:
|
||||
- 100 USD = 200 GOL (= 600 DAR from the statement line point of view)
|
||||
- 14 USD = 280 DAR
|
||||
Both journal items should be suggested to the user because they represents 98% of the statement line amount
|
||||
(DAR).
|
||||
Both journal items should be suggested to the user because they represents 98%
|
||||
of the statement line amount (DAR).
|
||||
"""
|
||||
partner = self.env["res.partner"].create({"name": "Bernard Perdant"})
|
||||
|
||||
|
@ -1280,9 +1281,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
}
|
||||
)
|
||||
|
||||
statement_line = self.env[
|
||||
"account.bank.statement.line"
|
||||
].create(
|
||||
statement_line = self.env["account.bank.statement.line"].create(
|
||||
{
|
||||
"journal_id": journal.id,
|
||||
"date": "2016-01-01",
|
||||
|
@ -1290,7 +1289,8 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
"partner_id": partner.id,
|
||||
"foreign_currency_id": self.currency_data_2["currency"].id,
|
||||
"amount": 300.0, # Rate is 3 GOL = 1 USD in 2016.
|
||||
"amount_currency": 900.0, # Rate is 10 DAR = 1 USD in 2016 but the rate used by the bank is 9:1.
|
||||
# Rate is 10 DAR = 1 USD in 2016 but the rate used by the bank is 9:1.
|
||||
"amount_currency": 900.0,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1447,10 +1447,11 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
|
|||
)
|
||||
|
||||
def test_no_amount_check_keep_first(self):
|
||||
"""In case the reconciliation model doesn't check the total amount of the candidates,
|
||||
we still don't want to suggest more than are necessary to match the statement.
|
||||
For example, if a statement line amounts to 250 and is to be matched with three invoices
|
||||
of 100, 200 and 300 (retrieved in this order), only 100 and 200 should be proposed.
|
||||
"""In case the reconciliation model doesn't check the total amount of the
|
||||
candidates, we still don't want to suggest more than are necessary to match the
|
||||
statement. For example, if a statement line amounts to 250 and is to be matched
|
||||
with three invoices of 100, 200 and 300 (retrieved in this order), only 100 and
|
||||
200 should be proposed.
|
||||
"""
|
||||
self.rule_1.allow_payment_tolerance = False
|
||||
self.bank_line_2.amount = 250
|
||||
|
|
|
@ -122,7 +122,6 @@ class AccountBankStatementLine(models.Model):
|
|||
or record.company_id.reconcile_aggregate
|
||||
)
|
||||
record.reconcile_aggregate = reconcile_aggregate
|
||||
print(record.date, reconcile_aggregate_map[reconcile_aggregate](record))
|
||||
record.aggregate_id, record.aggregate_name = reconcile_aggregate_map[
|
||||
reconcile_aggregate
|
||||
](record)
|
||||
|
@ -825,9 +824,10 @@ class AccountBankStatementLine(models.Model):
|
|||
],
|
||||
limit=1,
|
||||
)
|
||||
balance = previous_line_with_statement.statement_id.balance_end_real
|
||||
action["context"] = {
|
||||
"default_journal_id": self.journal_id.id,
|
||||
"default_balance_start": previous_line_with_statement.statement_id.balance_end_real,
|
||||
"default_balance_start": balance,
|
||||
"split_line_id": self.id,
|
||||
}
|
||||
return action
|
||||
|
|
|
@ -711,8 +711,8 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
|
||||
def test_widget_invoice_unselect(self):
|
||||
"""
|
||||
We want to test how selection and unselection of an account move lines is managed
|
||||
by the system.
|
||||
We want to test how selection and unselection of an account move lines is
|
||||
managed by the system.
|
||||
"""
|
||||
inv1 = self.create_invoice(
|
||||
currency_id=self.currency_euro_id, invoice_amount=100
|
||||
|
@ -786,7 +786,7 @@ class TestReconciliationWidget(TestAccountReconciliationCommon):
|
|||
f.manual_partner_id = inv1.partner_id
|
||||
self.assertEqual(f.partner_id, inv1.partner_id)
|
||||
bank_stmt_line.clean_reconcile()
|
||||
# As we have a set a partner, the cleaning should assign the invoice automatically
|
||||
# As we have set a partner, the cleaning should assign the invoice automatically
|
||||
self.assertTrue(bank_stmt_line.can_reconcile)
|
||||
|
||||
def test_widget_model_clean(self):
|
||||
|
|
Loading…
Reference in New Issue