Merge PR #313 into 13.0

Signed-off-by simahawk
This commit is contained in:
OCA-git-bot
2021-09-15 06:01:26 +00:00
11 changed files with 260 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,15 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
{
"name": "Account Reconciliation Model Strict Match Amount",
"summary": "Restrict reconciliation propositions to matching amount parameter",
"version": "13.0.1.0.0",
"category": "Accounting",
"website": "https://github.com/OCA/account-reconcile",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": ["account"],
"data": ["views/account_reconcile_model.xml"],
}

View File

@@ -0,0 +1 @@
from . import account_reconcile_model

View File

@@ -0,0 +1,76 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import fields, models
class AccountReconcileModel(models.Model):
_inherit = "account.reconcile.model"
strict_match_total_amount = fields.Boolean(
string="Strict Amount Matching",
help="Avoid bypassing the Amount Matching parameter in case of a "
"statement line communication matching exactly existing entries.",
)
# flake8: noqa
def _get_select_communication_flag(self):
if not self.match_total_amount or not self.strict_match_total_amount:
return super()._get_select_communication_flag()
else:
return r"""
-- Determine a matching or not with the statement line communication using the aml.name, move.name or move.ref.
COALESCE(
(
aml.name IS NOT NULL
AND
substring(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*') != ''
AND
regexp_split_to_array(substring(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'),'\s+')
&& regexp_split_to_array(substring(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'), '\s+')
)
OR
regexp_split_to_array(substring(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'),'\s+')
&& regexp_split_to_array(substring(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'), '\s+')
OR
(
move.ref IS NOT NULL
AND
substring(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*') != ''
AND
regexp_split_to_array(substring(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'),'\s+')
&& regexp_split_to_array(substring(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g'), '\S(?:.*\S)*'), '\s+')
)
, FALSE)
AND
CASE
WHEN abs(st_line.amount) < abs(aml.balance) THEN abs(st_line.amount) / abs(aml.balance) * 100
WHEN abs(st_line.amount) > abs(aml.balance) THEN abs(aml.balance) / abs(st_line.amount) * 100
ELSE 100
END >= {match_total_amount_param} AS communication_flag
""".format(
match_total_amount_param=self.match_total_amount_param
)
def _get_select_payment_reference_flag(self):
if not self.match_total_amount or not self.strict_match_total_amount:
return super()._get_select_payment_reference_flag()
else:
return r"""
-- Determine a matching or not with the statement line communication using the move.invoice_payment_ref.
COALESCE
(
move.invoice_payment_ref IS NOT NULL
AND
regexp_replace(move.invoice_payment_ref, '\s+', '', 'g') = regexp_replace(st_line.name, '\s+', '', 'g')
, FALSE)
AND
CASE
WHEN abs(st_line.amount) < abs(aml.balance) THEN abs(st_line.amount) / abs(aml.balance) * 100
WHEN abs(st_line.amount) > abs(aml.balance) THEN abs(aml.balance) / abs(st_line.amount) * 100
ELSE 100
END >= {match_total_amount_param} AS payment_reference_flag
""".format(
match_total_amount_param=self.match_total_amount_param
)

View File

@@ -0,0 +1 @@
* Akim Juillerat <akim.juillerat@camptocamp.com>

View File

@@ -0,0 +1,4 @@
This module allows to cancel the bypassing of Amount Matching feature on
Reconciliation models "in case of a statement line communication matching
exactly existing entries", to ensure only statement lines matching the total
amount (or according to its percentage) will be reconciled automatically.

View File

@@ -0,0 +1 @@
from . import test_account_reconcile_model_strict_match_amount

View File

@@ -0,0 +1,130 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo.addons.account.tests.test_reconciliation_matching_rules import (
TestReconciliationMatchingRules,
)
class TestAccountReconcileModelStrictMatchAmount(TestReconciliationMatchingRules):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.partner_3 = cls.env["res.partner"].create({"name": "partner_3"})
cls.partner_4 = cls.env["res.partner"].create({"name": "partner_4"})
cls.partner_5 = cls.env["res.partner"].create({"name": "partner_5"})
cls.partner_6 = cls.env["res.partner"].create({"name": "partner_6"})
cls.invoice_line_5 = cls._create_invoice_line(150, cls.partner_3, "out_invoice")
cls.invoice_line_5.ref = "ABC001XYZ"
cls.invoice_line_6 = cls._create_invoice_line(300, cls.partner_4, "out_invoice")
cls.invoice_line_6.name = "ABC002XYZ"
cls.invoice_line_7 = cls._create_invoice_line(450, cls.partner_5, "out_invoice")
cls.invoice_line_7.move_id.ref = "ABC003XYZ"
cls.invoice_line_8 = cls._create_invoice_line(600, cls.partner_6, "out_invoice")
cls.invoice_line_8.move_id.invoice_payment_ref = "ABC004XYZ"
cls.bank_st_2 = cls.env["account.bank.statement"].create(
{
"name": "test bank journal 2",
"journal_id": cls.company_data["default_journal_bank"].id,
}
)
cls.bank_line_3 = cls.env["account.bank.statement.line"].create(
{
"statement_id": cls.bank_st_2.id,
"name": "ABC001XYZ",
"partner_id": cls.partner_3.id,
"amount": 135,
"sequence": 1,
}
)
cls.bank_line_4 = cls.env["account.bank.statement.line"].create(
{
"statement_id": cls.bank_st_2.id,
"name": "ABC002XYZ",
"partner_id": cls.partner_4.id,
"amount": 270,
"sequence": 2,
}
)
cls.bank_line_5 = cls.env["account.bank.statement.line"].create(
{
"statement_id": cls.bank_st_2.id,
"name": "ABC003XYZ",
"partner_id": cls.partner_5.id,
"amount": 405,
"sequence": 3,
}
)
cls.bank_line_6 = cls.env["account.bank.statement.line"].create(
{
"statement_id": cls.bank_st_2.id,
"name": "ABC004XYZ",
"partner_id": cls.partner_6.id,
"amount": 540,
"sequence": 4,
}
)
def test_auto_reconcile_strict_match_100(self):
my_rule = self.env["account.reconcile.model"].create(
{
"name": "Strict Invoice matching amount 100%",
"rule_type": "invoice_matching",
"auto_reconcile": True,
"match_nature": "both",
"match_same_currency": True,
"match_total_amount": True,
"match_total_amount_param": 100.0,
"strict_match_total_amount": True,
}
)
self._check_statement_matching(
my_rule,
{
self.bank_line_3.id: {"aml_ids": []},
self.bank_line_4.id: {"aml_ids": []},
self.bank_line_5.id: {"aml_ids": []},
self.bank_line_6.id: {"aml_ids": []},
},
statements=self.bank_st_2,
)
def test_auto_reconcile_strict_match_90(self):
my_rule = self.env["account.reconcile.model"].create(
{
"name": "Strict Invoice matching amount 90%",
"rule_type": "invoice_matching",
"auto_reconcile": True,
"match_nature": "both",
"match_same_currency": True,
"match_total_amount": True,
"match_total_amount_param": 90.0,
"strict_match_total_amount": True,
}
)
self._check_statement_matching(
my_rule,
{
self.bank_line_3.id: {
"aml_ids": [self.invoice_line_5.id],
"model": my_rule,
"status": "reconciled",
},
self.bank_line_4.id: {
"aml_ids": [self.invoice_line_6.id],
"model": my_rule,
"status": "reconciled",
},
self.bank_line_5.id: {
"aml_ids": [self.invoice_line_7.id],
"model": my_rule,
"status": "reconciled",
},
self.bank_line_6.id: {
"aml_ids": [self.invoice_line_8.id],
"model": my_rule,
"status": "reconciled",
},
},
statements=self.bank_st_2,
)

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_account_reconcile_model_form" model="ir.ui.view">
<field name="name">account.reconcile.model.form</field>
<field name="model">account.reconcile.model</field>
<field name="inherit_id" ref="account.view_account_reconcile_model_form" />
<field name="arch" type="xml">
<xpath expr="//div[field[@name='match_total_amount']]" position="after">
<field
name="strict_match_total_amount"
attrs="{'invisible': ['|', ('rule_type', '!=', 'invoice_matching'), ('match_total_amount', '=', False)]}"
/>
</xpath>
<xpath
expr="//div[field[@name='match_total_amount']]/div[hasclass('text-muted')]"
position="attributes"
>
<attribute
name="attrs"
>{'invisible': ['|', '|', ('rule_type', '!=', 'invoice_matching'), ('match_total_amount', '=', False), ('strict_match_total_amount', '=', True)]}</attribute>
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
../../../../account_reconcile_model_strict_match_amount

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)