[IMP] partner_statement: Allow to exclude accounts
This commit is contained in:
committed by
Miquel Raïch
parent
965ea7d6ff
commit
795f9c60fe
@@ -52,6 +52,9 @@ class ActivityStatement(models.AbstractModel):
|
|||||||
return title
|
return title
|
||||||
|
|
||||||
def _initial_balance_sql_q1(self, partners, date_start, account_type):
|
def _initial_balance_sql_q1(self, partners, date_start, account_type):
|
||||||
|
excluded_accounts_ids = tuple(
|
||||||
|
self.env.context.get("excluded_accounts_ids", [])
|
||||||
|
) or (-1,)
|
||||||
return str(
|
return str(
|
||||||
self._cr.mogrify(
|
self._cr.mogrify(
|
||||||
"""
|
"""
|
||||||
@@ -84,6 +87,7 @@ class ActivityStatement(models.AbstractModel):
|
|||||||
WHERE l2.date < %(date_start)s
|
WHERE l2.date < %(date_start)s
|
||||||
) as pc ON pc.credit_move_id = l.id
|
) as pc ON pc.credit_move_id = l.id
|
||||||
WHERE l.partner_id IN %(partners)s
|
WHERE l.partner_id IN %(partners)s
|
||||||
|
AND aa.id not in %(excluded_accounts_ids)s
|
||||||
AND l.date < %(date_start)s AND not l.blocked
|
AND l.date < %(date_start)s AND not l.blocked
|
||||||
AND m.state IN ('posted')
|
AND m.state IN ('posted')
|
||||||
AND aa.account_type = %(account_type)s
|
AND aa.account_type = %(account_type)s
|
||||||
@@ -156,6 +160,9 @@ class ActivityStatement(models.AbstractModel):
|
|||||||
def _display_activity_lines_sql_q1(
|
def _display_activity_lines_sql_q1(
|
||||||
self, partners, date_start, date_end, account_type
|
self, partners, date_start, date_end, account_type
|
||||||
):
|
):
|
||||||
|
excluded_accounts_ids = tuple(
|
||||||
|
self.env.context.get("excluded_accounts_ids", [])
|
||||||
|
) or (-1,)
|
||||||
payment_ref = _("Payment")
|
payment_ref = _("Payment")
|
||||||
return str(
|
return str(
|
||||||
self._cr.mogrify(
|
self._cr.mogrify(
|
||||||
@@ -191,6 +198,7 @@ class ActivityStatement(models.AbstractModel):
|
|||||||
JOIN account_move m ON (l.move_id = m.id)
|
JOIN account_move m ON (l.move_id = m.id)
|
||||||
JOIN account_journal aj ON (l.journal_id = aj.id)
|
JOIN account_journal aj ON (l.journal_id = aj.id)
|
||||||
WHERE l.partner_id IN %(partners)s
|
WHERE l.partner_id IN %(partners)s
|
||||||
|
AND aa.id not in %(excluded_accounts_ids)s
|
||||||
AND %(date_start)s <= l.date
|
AND %(date_start)s <= l.date
|
||||||
AND l.date <= %(date_end)s
|
AND l.date <= %(date_end)s
|
||||||
AND m.state IN ('posted')
|
AND m.state IN ('posted')
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class OutstandingStatement(models.AbstractModel):
|
|||||||
|
|
||||||
def _display_outstanding_lines_sql_q1(self, partners, date_end, account_type):
|
def _display_outstanding_lines_sql_q1(self, partners, date_end, account_type):
|
||||||
partners = tuple(partners)
|
partners = tuple(partners)
|
||||||
|
excluded_accounts_ids = tuple(
|
||||||
|
self.env.context.get("excluded_accounts_ids", [])
|
||||||
|
) or (-1,)
|
||||||
return str(
|
return str(
|
||||||
self._cr.mogrify(
|
self._cr.mogrify(
|
||||||
"""
|
"""
|
||||||
@@ -71,6 +74,7 @@ class OutstandingStatement(models.AbstractModel):
|
|||||||
WHERE l2.date <= %(date_end)s
|
WHERE l2.date <= %(date_end)s
|
||||||
) as pc ON pc.credit_move_id = l.id
|
) as pc ON pc.credit_move_id = l.id
|
||||||
WHERE l.partner_id IN %(partners)s
|
WHERE l.partner_id IN %(partners)s
|
||||||
|
AND aa.id not in %(excluded_accounts_ids)s
|
||||||
AND (
|
AND (
|
||||||
(pd.id IS NOT NULL AND
|
(pd.id IS NOT NULL AND
|
||||||
pd.max_date <= %(date_end)s) OR
|
pd.max_date <= %(date_end)s) OR
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ class ReportStatementCommon(models.AbstractModel):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _show_buckets_sql_q1(self, partners, date_end, account_type):
|
def _show_buckets_sql_q1(self, partners, date_end, account_type):
|
||||||
|
excluded_accounts_ids = tuple(
|
||||||
|
self.env.context.get("excluded_accounts_ids", [])
|
||||||
|
) or (-1,)
|
||||||
return str(
|
return str(
|
||||||
self._cr.mogrify(
|
self._cr.mogrify(
|
||||||
"""
|
"""
|
||||||
@@ -91,18 +94,18 @@ class ReportStatementCommon(models.AbstractModel):
|
|||||||
WHERE l2.date <= %(date_end)s
|
WHERE l2.date <= %(date_end)s
|
||||||
) as pc ON pc.credit_move_id = l.id
|
) as pc ON pc.credit_move_id = l.id
|
||||||
WHERE l.partner_id IN %(partners)s
|
WHERE l.partner_id IN %(partners)s
|
||||||
AND (
|
AND aa.id not in %(excluded_accounts_ids)s
|
||||||
(pd.id IS NOT NULL AND
|
AND (
|
||||||
pd.max_date <= %(date_end)s) OR
|
(pd.id IS NOT NULL AND
|
||||||
(pc.id IS NOT NULL AND
|
pd.max_date <= %(date_end)s) OR
|
||||||
pc.max_date <= %(date_end)s) OR
|
(pc.id IS NOT NULL AND
|
||||||
(pd.id IS NULL AND pc.id IS NULL)
|
pc.max_date <= %(date_end)s) OR
|
||||||
) AND l.date <= %(date_end)s AND not l.blocked
|
(pd.id IS NULL AND pc.id IS NULL)
|
||||||
AND m.state IN ('posted')
|
) AND l.date <= %(date_end)s AND not l.blocked
|
||||||
AND aa.account_type = %(account_type)s
|
AND m.state IN ('posted')
|
||||||
|
AND aa.account_type = %(account_type)s
|
||||||
GROUP BY l.partner_id, l.currency_id, l.date, l.date_maturity,
|
GROUP BY l.partner_id, l.currency_id, l.date, l.date_maturity,
|
||||||
l.amount_currency, l.balance, l.move_id,
|
l.amount_currency, l.balance, l.move_id, l.company_id, l.id
|
||||||
l.company_id, l.id
|
|
||||||
""",
|
""",
|
||||||
locals(),
|
locals(),
|
||||||
),
|
),
|
||||||
@@ -358,6 +361,11 @@ class ReportStatementCommon(models.AbstractModel):
|
|||||||
if isinstance(date_end, str):
|
if isinstance(date_end, str):
|
||||||
date_end = datetime.strptime(date_end, DEFAULT_SERVER_DATE_FORMAT).date()
|
date_end = datetime.strptime(date_end, DEFAULT_SERVER_DATE_FORMAT).date()
|
||||||
account_type = data["account_type"]
|
account_type = data["account_type"]
|
||||||
|
excluded_accounts_ids = data["excluded_accounts_ids"]
|
||||||
|
if excluded_accounts_ids:
|
||||||
|
self = self.with_context(
|
||||||
|
excluded_accounts_ids=excluded_accounts_ids,
|
||||||
|
)
|
||||||
aging_type = data["aging_type"]
|
aging_type = data["aging_type"]
|
||||||
is_activity = data.get("is_activity")
|
is_activity = data.get("is_activity")
|
||||||
is_detailed = data.get("is_detailed")
|
is_detailed = data.get("is_detailed")
|
||||||
@@ -583,6 +591,7 @@ class ReportStatementCommon(models.AbstractModel):
|
|||||||
"company": self.env["res.company"].browse(company_id),
|
"company": self.env["res.company"].browse(company_id),
|
||||||
"Currencies": currencies,
|
"Currencies": currencies,
|
||||||
"account_type": account_type,
|
"account_type": account_type,
|
||||||
|
"excluded_accounts_ids": excluded_accounts_ids,
|
||||||
"is_detailed": is_detailed,
|
"is_detailed": is_detailed,
|
||||||
"bucket_labels": bucket_labels,
|
"bucket_labels": bucket_labels,
|
||||||
"get_inv_addr": self._get_invoice_address,
|
"get_inv_addr": self._get_invoice_address,
|
||||||
|
|||||||
@@ -92,3 +92,59 @@ class TestOutstandingStatement(TransactionCase):
|
|||||||
self.assertIn(
|
self.assertIn(
|
||||||
"bucket_labels", report, "There was an error while compiling the report."
|
"bucket_labels", report, "There was an error while compiling the report."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_exclude_accounts(self):
|
||||||
|
"""Accounts can be excluded with a code selector."""
|
||||||
|
# Arrange
|
||||||
|
partners = self.partner1 | self.partner2
|
||||||
|
wizard = self.wiz.with_context(
|
||||||
|
active_ids=partners.ids,
|
||||||
|
).create({})
|
||||||
|
|
||||||
|
# Edit one invoice
|
||||||
|
# including a new account
|
||||||
|
# that will be the only one not excluded
|
||||||
|
partner_invoice = self.env["account.move"].search(
|
||||||
|
[
|
||||||
|
("partner_id", "in", partners.ids),
|
||||||
|
("state", "=", "posted"),
|
||||||
|
],
|
||||||
|
limit=1,
|
||||||
|
)
|
||||||
|
account = partner_invoice.line_ids.account_id.filtered(
|
||||||
|
lambda a: a.account_type == wizard.account_type
|
||||||
|
)
|
||||||
|
copy_account = account.copy()
|
||||||
|
partner_invoice.line_ids.filtered(
|
||||||
|
lambda line: line.account_id == account
|
||||||
|
).account_id = copy_account
|
||||||
|
partner_invoice.line_ids.flush_recordset()
|
||||||
|
wizard_accounts = self.env["account.account"].search(
|
||||||
|
[
|
||||||
|
("id", "!=", copy_account.id),
|
||||||
|
("account_type", "=", wizard.account_type),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
wizard.excluded_accounts_selector = ", ".join(
|
||||||
|
[account.code for account in wizard_accounts]
|
||||||
|
)
|
||||||
|
# pre-condition
|
||||||
|
self.assertTrue(wizard.excluded_accounts_selector)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
data = wizard._prepare_statement()
|
||||||
|
report = self.statement_model._get_report_values(partners.ids, data)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
# Only the new invoice is shown
|
||||||
|
invoice_partner = partner_invoice.partner_id
|
||||||
|
invoice_partner_data = report["data"][invoice_partner.id]["currencies"]
|
||||||
|
invoice_partner_move_lines = invoice_partner_data[
|
||||||
|
partner_invoice.currency_id.id
|
||||||
|
]["lines"]
|
||||||
|
self.assertEqual(len(invoice_partner_move_lines), 1)
|
||||||
|
self.assertEqual(invoice_partner_move_lines[0]["name"], partner_invoice.name)
|
||||||
|
|
||||||
|
other_partner = partners - invoice_partner
|
||||||
|
other_partner_data = report["data"].get(other_partner.id)
|
||||||
|
self.assertFalse(other_partner_data)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
|
from odoo.osv import expression
|
||||||
|
|
||||||
|
|
||||||
class StatementCommon(models.AbstractModel):
|
class StatementCommon(models.AbstractModel):
|
||||||
@@ -38,6 +39,44 @@ class StatementCommon(models.AbstractModel):
|
|||||||
[("asset_receivable", "Receivable"), ("liability_payable", "Payable")],
|
[("asset_receivable", "Receivable"), ("liability_payable", "Payable")],
|
||||||
default="asset_receivable",
|
default="asset_receivable",
|
||||||
)
|
)
|
||||||
|
excluded_accounts_selector = fields.Char(
|
||||||
|
string="Accounts to exclude",
|
||||||
|
help="Select account codes to be excluded "
|
||||||
|
"with a comma-separated list of expressions like 70%.",
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_excluded_accounts_domain(self, selector):
|
||||||
|
"""Convert an account codes selector to a domain to search accounts.
|
||||||
|
|
||||||
|
The selector is a comma-separated list of expressions like 70%.
|
||||||
|
The algorithm is the same as
|
||||||
|
AccountingExpressionProcessor._account_codes_to_domain
|
||||||
|
of `mis_builder` module.
|
||||||
|
"""
|
||||||
|
if not selector:
|
||||||
|
selector = ""
|
||||||
|
domains = []
|
||||||
|
for account_code in selector.split(","):
|
||||||
|
account_code = account_code.strip()
|
||||||
|
if "%" in account_code:
|
||||||
|
domains.append(
|
||||||
|
[
|
||||||
|
("code", "=like", account_code),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
domains.append(
|
||||||
|
[
|
||||||
|
("code", "=", account_code),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return expression.OR(domains)
|
||||||
|
|
||||||
|
def _get_excluded_accounts(self):
|
||||||
|
self.ensure_one()
|
||||||
|
domain = self._get_excluded_accounts_domain(self.excluded_accounts_selector)
|
||||||
|
return self.env["account.account"].search(domain)
|
||||||
|
|
||||||
@api.onchange("aging_type")
|
@api.onchange("aging_type")
|
||||||
def onchange_aging_type(self):
|
def onchange_aging_type(self):
|
||||||
@@ -59,6 +98,7 @@ class StatementCommon(models.AbstractModel):
|
|||||||
"account_type": self.account_type,
|
"account_type": self.account_type,
|
||||||
"aging_type": self.aging_type,
|
"aging_type": self.aging_type,
|
||||||
"filter_negative_balances": self.filter_negative_balances,
|
"filter_negative_balances": self.filter_negative_balances,
|
||||||
|
"excluded_accounts_ids": self._get_excluded_accounts().ids,
|
||||||
}
|
}
|
||||||
|
|
||||||
def button_export_html(self):
|
def button_export_html(self):
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
/>
|
/>
|
||||||
<label for="account_type" />
|
<label for="account_type" />
|
||||||
<field name="account_type" nolabel="1" widget="radio" />
|
<field name="account_type" nolabel="1" widget="radio" />
|
||||||
|
<field name="excluded_accounts_selector" />
|
||||||
</group>
|
</group>
|
||||||
<group name="aging_report">
|
<group name="aging_report">
|
||||||
<field name="show_aging_buckets" />
|
<field name="show_aging_buckets" />
|
||||||
|
|||||||
Reference in New Issue
Block a user