[IMP] account_financial_report: analytic info + filters in the
open items and aged partner balance reports. This is useful in project based companies where it is important the assets & liabilities by projects. Long term projects my have outstanding invoices for months.pull/1138/head
parent
f37d54516d
commit
85ead5cd59
|
@ -6,6 +6,7 @@ import operator
|
|||
from datetime import date, datetime, timedelta
|
||||
|
||||
from odoo import api, models
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
|
@ -148,10 +149,38 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
date_from,
|
||||
only_posted_moves,
|
||||
show_move_line_details,
|
||||
analytic_account_ids,
|
||||
no_analytic,
|
||||
):
|
||||
domain = self._get_move_lines_domain_not_reconciled(
|
||||
company_id, account_ids, partner_ids, only_posted_moves, date_from
|
||||
)
|
||||
if no_analytic:
|
||||
domain = expression.AND(
|
||||
[
|
||||
domain,
|
||||
[
|
||||
(
|
||||
"analytic_account_id",
|
||||
"=",
|
||||
False,
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
elif analytic_account_ids:
|
||||
domain = expression.AND(
|
||||
[
|
||||
domain,
|
||||
[
|
||||
(
|
||||
"analytic_account_id",
|
||||
"in",
|
||||
analytic_account_ids,
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
ml_fields = self._get_ml_fields()
|
||||
line_model = self.env["account.move.line"]
|
||||
move_lines = line_model.search_read(domain=domain, fields=ml_fields)
|
||||
|
@ -224,6 +253,10 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = move_line["ref"] + str(" - ") + move_line["name"]
|
||||
if move_line["analytic_account_id"]:
|
||||
analytic = move_line["analytic_account_id"][1]
|
||||
else:
|
||||
analytic = False
|
||||
move_line_data.update(
|
||||
{
|
||||
"line_rec": line_model.browse(move_line["id"]),
|
||||
|
@ -235,6 +268,7 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
"ref_label": ref_label,
|
||||
"due_date": move_line["date_maturity"],
|
||||
"residual": move_line["amount_residual"],
|
||||
"analytic_account_id": analytic,
|
||||
}
|
||||
)
|
||||
ag_pb_data[acc_id][prt_id]["move_lines"].append(move_line_data)
|
||||
|
@ -416,6 +450,8 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
aged_partner_configuration = self.env[
|
||||
"account.age.report.configuration"
|
||||
].browse(data["age_partner_config_id"])
|
||||
analytic_account_ids = data["analytic_account_ids"]
|
||||
no_analytic = data["no_analytic"]
|
||||
(ag_pb_data, accounts_data, partners_data, journals_data,) = self.with_context(
|
||||
age_partner_config=aged_partner_configuration
|
||||
)._get_move_lines_data(
|
||||
|
@ -426,6 +462,8 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
date_from,
|
||||
only_posted_moves,
|
||||
show_move_line_details,
|
||||
analytic_account_ids,
|
||||
no_analytic,
|
||||
)
|
||||
aged_partner_data = self.with_context(
|
||||
age_partner_config=aged_partner_configuration
|
||||
|
@ -458,4 +496,5 @@ class AgedPartnerBalanceReport(models.AbstractModel):
|
|||
"amount_residual",
|
||||
"reconciled",
|
||||
"date_maturity",
|
||||
"analytic_account_id",
|
||||
]
|
||||
|
|
|
@ -104,9 +104,14 @@ class AgedPartnerBalanceXslx(models.AbstractModel):
|
|||
2: {"header": _("Journal"), "field": "journal", "width": 8},
|
||||
3: {"header": _("Account"), "field": "account", "width": 9},
|
||||
4: {"header": _("Partner"), "field": "partner", "width": 25},
|
||||
5: {"header": _("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
6: {"header": _("Due date"), "field": "due_date", "width": 11},
|
||||
7: {
|
||||
5: {
|
||||
"header": _("Analytic Account"),
|
||||
"field": "analytic_account_id",
|
||||
"width": 25,
|
||||
},
|
||||
6: {"header": _("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
7: {"header": _("Due date"), "field": "due_date", "width": 11},
|
||||
8: {
|
||||
"header": _("Residual"),
|
||||
"field": "residual",
|
||||
"field_footer_total": "residual",
|
||||
|
@ -114,7 +119,7 @@ class AgedPartnerBalanceXslx(models.AbstractModel):
|
|||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
8: {
|
||||
9: {
|
||||
"header": _("Current"),
|
||||
"field": "current",
|
||||
"field_footer_total": "current",
|
||||
|
|
|
@ -7,6 +7,7 @@ import operator
|
|||
from datetime import date, datetime
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
|
@ -68,10 +69,14 @@ class OpenItemsReport(models.AbstractModel):
|
|||
company_id,
|
||||
date_from,
|
||||
grouped_by,
|
||||
analytic_account_ids,
|
||||
no_analytic,
|
||||
):
|
||||
domain = self._get_move_lines_domain_not_reconciled(
|
||||
company_id, account_ids, partner_ids, only_posted_moves, date_from
|
||||
)
|
||||
# moved out to avoid too complex method error
|
||||
domain = self.get_analytic_domain(domain, analytic_account_ids, no_analytic)
|
||||
ml_fields = self._get_ml_fields()
|
||||
move_lines = self.env["account.move.line"].search_read(
|
||||
domain=domain, fields=ml_fields
|
||||
|
@ -148,7 +153,10 @@ class OpenItemsReport(models.AbstractModel):
|
|||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = move_line["ref"] + str(" - ") + move_line["name"]
|
||||
|
||||
if analytic_account_ids and move_line["analytic_account_id"]:
|
||||
analytic_account_id = move_line["analytic_account_id"][1]
|
||||
else:
|
||||
analytic_account_id = False
|
||||
move_line.update(
|
||||
{
|
||||
"date": move_line["date"],
|
||||
|
@ -167,6 +175,7 @@ class OpenItemsReport(models.AbstractModel):
|
|||
"currency_name": move_line["currency_id"][1]
|
||||
if move_line["currency_id"]
|
||||
else False,
|
||||
"analytic_account_id": analytic_account_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -247,6 +256,9 @@ class OpenItemsReport(models.AbstractModel):
|
|||
only_posted_moves = data["only_posted_moves"]
|
||||
show_partner_details = data["show_partner_details"]
|
||||
grouped_by = data["grouped_by"]
|
||||
analytic_account_ids = data["analytic_account_ids"]
|
||||
no_analytic = data["no_analytic"]
|
||||
|
||||
(
|
||||
move_lines_data,
|
||||
partners_data,
|
||||
|
@ -261,6 +273,8 @@ class OpenItemsReport(models.AbstractModel):
|
|||
company_id,
|
||||
date_from,
|
||||
grouped_by,
|
||||
analytic_account_ids,
|
||||
no_analytic,
|
||||
)
|
||||
|
||||
total_amount = self._calculate_amounts(open_items_move_lines_data)
|
||||
|
@ -288,6 +302,7 @@ class OpenItemsReport(models.AbstractModel):
|
|||
|
||||
def _get_ml_fields(self):
|
||||
return self.COMMON_ML_FIELDS + [
|
||||
"analytic_account_id",
|
||||
"amount_residual",
|
||||
"reconciled",
|
||||
"currency_id",
|
||||
|
@ -297,3 +312,32 @@ class OpenItemsReport(models.AbstractModel):
|
|||
"debit",
|
||||
"amount_currency",
|
||||
]
|
||||
|
||||
def get_analytic_domain(self, domain, analytic_account_ids, no_analytic):
|
||||
if no_analytic:
|
||||
domain = expression.AND(
|
||||
[
|
||||
domain,
|
||||
[
|
||||
(
|
||||
"analytic_account_id",
|
||||
"=",
|
||||
False,
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
elif analytic_account_ids:
|
||||
domain = expression.AND(
|
||||
[
|
||||
domain,
|
||||
[
|
||||
(
|
||||
"analytic_account_id",
|
||||
"in",
|
||||
analytic_account_ids,
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
return domain
|
||||
|
|
|
@ -27,15 +27,20 @@ class OpenItemsXslx(models.AbstractModel):
|
|||
2: {"header": _("Journal"), "field": "journal", "width": 8},
|
||||
3: {"header": _("Account"), "field": "account", "width": 9},
|
||||
4: {"header": _("Partner"), "field": "partner_name", "width": 25},
|
||||
5: {"header": _("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
6: {"header": _("Due date"), "field": "date_maturity", "width": 11},
|
||||
7: {
|
||||
5: {
|
||||
"header": _("Analytic Account"),
|
||||
"field": "analytic_account_id",
|
||||
"width": 25,
|
||||
},
|
||||
6: {"header": _("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
7: {"header": _("Due date"), "field": "date_maturity", "width": 11},
|
||||
8: {
|
||||
"header": _("Original"),
|
||||
"field": "original",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
8: {
|
||||
9: {
|
||||
"header": _("Residual"),
|
||||
"field": "amount_residual",
|
||||
"field_final_balance": "residual",
|
||||
|
@ -45,21 +50,21 @@ class OpenItemsXslx(models.AbstractModel):
|
|||
}
|
||||
if report.foreign_currency:
|
||||
foreign_currency = {
|
||||
9: {
|
||||
10: {
|
||||
"header": _("Cur."),
|
||||
"field": "currency_name",
|
||||
"field_currency_balance": "currency_name",
|
||||
"type": "currency_name",
|
||||
"width": 7,
|
||||
},
|
||||
10: {
|
||||
11: {
|
||||
"header": _("Cur. Original"),
|
||||
"field": "amount_currency",
|
||||
"field_final_balance": "amount_currency",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
11: {
|
||||
12: {
|
||||
"header": _("Cur. Residual"),
|
||||
"field": "amount_residual_currency",
|
||||
"field_final_balance": "amount_currency",
|
||||
|
|
|
@ -218,6 +218,21 @@
|
|||
<div class="act_as_cell" style="width: 5.00%;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">Account</div>
|
||||
<t t-if="analytic_account_ids">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 9.50%;">Partner</div>
|
||||
<!--## analytic account -->
|
||||
<div
|
||||
class="act_as_cell"
|
||||
style="width: 9.50%;"
|
||||
>Analytic Account</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 9.50%;">
|
||||
Ref -
|
||||
Label
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 10.50%;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
|
@ -225,6 +240,7 @@
|
|||
Ref -
|
||||
Label
|
||||
</div>
|
||||
</t>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Due
|
||||
|
@ -311,6 +327,39 @@
|
|||
<t t-out="line['account']" />
|
||||
</span>
|
||||
</div>
|
||||
<t t-if="analytic_account_ids">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].partner_id.id"
|
||||
res-model="res.partner"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['partner']" />
|
||||
</span>
|
||||
</div>
|
||||
<!-- ANAL -->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].analytic_account_id.id"
|
||||
res-model="analytic_account_id"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['analytic_account_id']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].id"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['ref_label']" />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
|
@ -331,6 +380,7 @@
|
|||
<t t-out="line['ref_label']" />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
|
|
|
@ -245,6 +245,22 @@
|
|||
<div class="act_as_cell" style="width: 4.78%;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 5.38%;">Account</div>
|
||||
|
||||
<t t-if="analytic_account_ids">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 13.19%;">Partner</div>
|
||||
<!--## analytic_account-->
|
||||
<div
|
||||
class="act_as_cell"
|
||||
style="width: 13.19%;"
|
||||
>Analytic Account</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 13.19%;">
|
||||
Ref -
|
||||
Label
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 15.07%;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
|
@ -252,6 +268,7 @@
|
|||
Ref -
|
||||
Label
|
||||
</div>
|
||||
</t>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.47%;">
|
||||
Due
|
||||
|
@ -324,6 +341,20 @@
|
|||
<t t-esc="line['partner_name']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## cost_center-->
|
||||
<t t-if="analytic_account_ids">
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['analytic_account_id']">
|
||||
<span
|
||||
t-att-res-id="line['analytic_account_id']"
|
||||
res-model="account.analytic.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-raw="line['analytic_account_id']" />
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-esc="line['ref_label']" />
|
||||
|
|
|
@ -43,6 +43,10 @@ class AgedPartnerBalanceWizard(models.TransientModel):
|
|||
age_partner_config_id = fields.Many2one(
|
||||
"account.age.report.configuration", string="Intervals configuration"
|
||||
)
|
||||
analytic_account_ids = fields.Many2many(
|
||||
comodel_name="account.analytic.account", string="Filter analytic accounts"
|
||||
)
|
||||
no_analytic = fields.Boolean("Only no analytic items")
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
|
@ -86,17 +90,27 @@ class AgedPartnerBalanceWizard(models.TransientModel):
|
|||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
res = {"domain": {"account_ids": [], "partner_ids": []}}
|
||||
res = {
|
||||
"domain": {"account_ids": [], "partner_ids": [], "analytic_account_ids": []}
|
||||
}
|
||||
if not self.company_id:
|
||||
return res
|
||||
else:
|
||||
res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)]
|
||||
res["domain"]["partner_ids"] += self._get_partner_ids_domain()
|
||||
res["domain"]["analytic_account_ids"] += [
|
||||
("company_id", "=", self.company_id.id)
|
||||
]
|
||||
return res
|
||||
|
||||
@api.onchange("account_ids")
|
||||
def onchange_account_ids(self):
|
||||
return {"domain": {"account_ids": [("reconcile", "=", True)]}}
|
||||
return {
|
||||
"domain": {
|
||||
"account_ids": [("reconcile", "=", True)],
|
||||
"analytic_account_ids": [],
|
||||
}
|
||||
}
|
||||
|
||||
@api.onchange("receivable_accounts_only", "payable_accounts_only")
|
||||
def onchange_type_accounts_only(self):
|
||||
|
@ -142,6 +156,8 @@ class AgedPartnerBalanceWizard(models.TransientModel):
|
|||
"show_move_line_details": self.show_move_line_details,
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
"age_partner_config_id": self.age_partner_config_id.id,
|
||||
"analytic_account_ids": self.analytic_account_ids.ids or [],
|
||||
"no_analytic": self.no_analytic,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
|
|
|
@ -62,6 +62,17 @@
|
|||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
<group
|
||||
name="Filter analytic accounts"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
>
|
||||
<field
|
||||
name="analytic_account_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<field name="no_analytic" />
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="button_export_html"
|
||||
|
|
|
@ -63,6 +63,10 @@ class OpenItemsReportWizard(models.TransientModel):
|
|||
selection=[("partners", "Partners"), ("salesperson", "Partner Salesperson")],
|
||||
default="partners",
|
||||
)
|
||||
analytic_account_ids = fields.Many2many(
|
||||
comodel_name="account.analytic.account", string="Filter analytic accounts"
|
||||
)
|
||||
no_analytic = fields.Boolean("Only no analytic items")
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
|
@ -109,12 +113,17 @@ class OpenItemsReportWizard(models.TransientModel):
|
|||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
res = {"domain": {"account_ids": [], "partner_ids": []}}
|
||||
res = {
|
||||
"domain": {"account_ids": [], "partner_ids": [], "analytic_account_ids": []}
|
||||
}
|
||||
if not self.company_id:
|
||||
return res
|
||||
else:
|
||||
res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)]
|
||||
res["domain"]["partner_ids"] += self._get_partner_ids_domain()
|
||||
res["domain"]["analytic_account_ids"] += [
|
||||
("company_id", "=", self.company_id.id)
|
||||
]
|
||||
return res
|
||||
|
||||
@api.onchange("account_ids")
|
||||
|
@ -179,8 +188,10 @@ class OpenItemsReportWizard(models.TransientModel):
|
|||
"target_move": self.target_move,
|
||||
"account_ids": self.account_ids.ids,
|
||||
"partner_ids": self.partner_ids.ids or [],
|
||||
"analytic_account_ids": self.analytic_account_ids.ids or [],
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
"grouped_by": self.grouped_by,
|
||||
"no_analytic": self.no_analytic,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
|
|
|
@ -62,6 +62,17 @@
|
|||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
<group
|
||||
name="Filter analytic accounts"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
>
|
||||
<field
|
||||
name="analytic_account_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<field name="no_analytic" />
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="button_export_html"
|
||||
|
|
Loading…
Reference in New Issue