209
account_financial_report/README.rst
Normal file
209
account_financial_report/README.rst
Normal file
@@ -0,0 +1,209 @@
|
||||
=========================
|
||||
Account Financial Reports
|
||||
=========================
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:4d56adc35fff26b88020bebb3cd0fcb302b7c7c7483639925cfc4f9b850d8ac4
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--reporting-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/account-financial-reporting/tree/18.0/account_financial_report
|
||||
:alt: OCA/account-financial-reporting
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/account-financial-reporting-18-0/account-financial-reporting-18-0-account_financial_report
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/account-financial-reporting&target_branch=18.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module adds a set of financial reports. They are accessible under
|
||||
Invoicing / Reporting / OCA accounting reports.
|
||||
|
||||
- General ledger
|
||||
- Trial Balance
|
||||
- Open Items
|
||||
- Aged Partner Balance
|
||||
- VAT Report
|
||||
- Journal Ledger
|
||||
|
||||
Currently General ledger, Trial Balance and Open Items are fully
|
||||
compatible with a foreign currency set up in account in order to display
|
||||
balances. Moreover, any foreign currency used in account move lines is
|
||||
properly shown.
|
||||
|
||||
In case that in an account has not been configured a second currency
|
||||
foreign currency balances are not available.
|
||||
|
||||
Invoicing / Settings / Invoicing / OCA Aged Report Configuration you
|
||||
will be able to set dynamic intervals that will appear on the Aged
|
||||
Partner Balance. For further information, check CONFIGURE.rst
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
To configure dynamic intervals for Aged Partner Balance you need to:
|
||||
|
||||
Go on 'Settings' -> 'Invoicing' -> 'OCA Aged Report Configuration'.
|
||||
|
||||
Click on option 'Configurations' and create new record.
|
||||
|
||||
Create new interval. The name established on line will be the column to
|
||||
display in Aged Partner Balance. Inferior limit established on line is
|
||||
the interval
|
||||
|
||||
Example of configuration inferior limit:
|
||||
|
||||
-> 15 -> 30 -> 60
|
||||
|
||||
It means the first interval is from 0 to 15, the second from 16 to 30,
|
||||
and the third is 61+.
|
||||
|
||||
Go on 'Invoicing' -> 'Reporting' -> 'OCA accounting reports' -> 'Aged
|
||||
Partner Balance'
|
||||
|
||||
When wizard is open, you need to select your interval configuration and
|
||||
print report.
|
||||
|
||||
If you want to get default interval configuration any time you wish to
|
||||
print Aged Partner Report, you can set default interval configuration
|
||||
per company in:
|
||||
|
||||
'Settings' -> 'Invoicing' -> 'OCA Aged Report Configuration'.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
- 'VAT Report' is valid only for cases where it's met that for each Tax
|
||||
defined: all the "Account tags" of all the 'Repartition for Invoices'
|
||||
or 'Repartition for Credit Notes' are different.
|
||||
- It would be nice to have in reports a column indicating the state of
|
||||
the entries when the option "All Entries" is selected in "Target
|
||||
Moves" field in a wizard
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
11.0.2.5.0 (2019-04-26)
|
||||
-----------------------
|
||||
|
||||
- In the Trial Balance you have an option to hide parent hierarchy
|
||||
levels
|
||||
|
||||
11.0.2.4.1 (2019-01-08)
|
||||
-----------------------
|
||||
|
||||
- Handle better multicompany behaviour
|
||||
- Improve how title appears in the reports
|
||||
- Improve performance in General Ledger
|
||||
|
||||
11.0.2.3.1 (2018-11-29)
|
||||
-----------------------
|
||||
|
||||
- In the Trial Balance you can apply a filter by hierarchy levels
|
||||
- In the General Ledger you can apply a filter by Analytic Tag
|
||||
- In the Journal Ledger the field 'Journal' is now optional
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-reporting/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/account-financial-reporting/issues/new?body=module:%20account_financial_report%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* Camptocamp
|
||||
* initOS GmbH
|
||||
* redCOR AG
|
||||
* ForgeFlow
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
- Jordi Ballester <jordi.ballester@forgeflow.com>
|
||||
- Yannick Vaucher <yannick.vaucher@camptocamp.com>
|
||||
- Simone Orsi <simone.orsi@abstract.com>
|
||||
- Leonardo Pistone <leonardo.pistone@camptocamp.com>
|
||||
- Damien Crier <damien.crier@camptocamp.com>
|
||||
- Andrea Stirpe <a.stirpe@onestein.nl>
|
||||
- Thomas Rehn <thomas.rehn@initos.com>
|
||||
- Andrea Gallina <4everamd@gmail.com>
|
||||
- Robert Rottermann <robert@redcor.ch>
|
||||
- Ciro Urselli <c.urselli@apuliasoftware.it>
|
||||
- Francesco Apruzzese <opencode@e-ware.org>
|
||||
- Lorenzo Battistini <https://github.com/eLBati>
|
||||
- Julien Coux <julien.coux@camptocamp.com>
|
||||
- Akim Juillerat <akim.juillerat@camptocamp.com>
|
||||
- Alexis de Lattre <alexis@via.ecp.fr>
|
||||
- Mihai Fekete <feketemihai@gmail.com>
|
||||
- Miquel Ra??ch <miquel.raich@forgeflow.com>
|
||||
- Joan Sisquella <joan.sisquella@forgeflow.com>
|
||||
- `Tecnativa <https://www.tecnativa.com>`__:
|
||||
|
||||
- Pedro M. Baeza
|
||||
- Sergio Teruel
|
||||
- Ernesto Tejeda
|
||||
- João Marques
|
||||
- Alexandre D. D??az
|
||||
- V??ctor Mart??nez
|
||||
- Carolina Fernandez
|
||||
|
||||
- `Sygel <https://www.sygel.es>`__:
|
||||
|
||||
- Harald Panten
|
||||
- Valentin Vinagre
|
||||
|
||||
- Lois Rilo <lois.rilo@forgeflow.com>
|
||||
- Saran Lim. <saranl@ecosoft.co.th>
|
||||
- Omar Casti??eira <omar@comunitea.com>
|
||||
- Chau Le <chaulb@trobz.com>
|
||||
|
||||
Much of the work in this module was done at a sprint in Sorrento, Italy
|
||||
in April 2016.
|
||||
|
||||
Other credits
|
||||
-------------
|
||||
|
||||
The migration of this module from 17.0 to 18.0 was financially supported
|
||||
by Camptocamp.
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/account-financial-reporting <https://github.com/OCA/account-financial-reporting/tree/18.0/account_financial_report>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
7
account_financial_report/__init__.py
Normal file
7
account_financial_report/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# Author: Damien Crier
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import models
|
||||
from . import report
|
||||
from . import wizard
|
||||
58
account_financial_report/__manifest__.py
Normal file
58
account_financial_report/__manifest__.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
{
|
||||
"name": "Account Financial Reports",
|
||||
"version": "18.0.1.0.0",
|
||||
"category": "Reporting",
|
||||
"summary": "OCA Financial Reports",
|
||||
"author": "Camptocamp,"
|
||||
"initOS GmbH,"
|
||||
"redCOR AG,"
|
||||
"ForgeFlow,"
|
||||
"Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/account-financial-reporting",
|
||||
"depends": ["account", "date_range", "report_xlsx"],
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"security/security.xml",
|
||||
"wizard/aged_partner_balance_wizard_view.xml",
|
||||
"wizard/general_ledger_wizard_view.xml",
|
||||
"wizard/journal_ledger_wizard_view.xml",
|
||||
"wizard/open_items_wizard_view.xml",
|
||||
"wizard/trial_balance_wizard_view.xml",
|
||||
"wizard/vat_report_wizard_view.xml",
|
||||
"view/account_age_report_configuration_views.xml",
|
||||
"menuitems.xml",
|
||||
"reports.xml",
|
||||
"report/templates/layouts.xml",
|
||||
"report/templates/aged_partner_balance.xml",
|
||||
"report/templates/general_ledger.xml",
|
||||
"report/templates/journal_ledger.xml",
|
||||
"report/templates/open_items.xml",
|
||||
"report/templates/trial_balance.xml",
|
||||
"report/templates/vat_report.xml",
|
||||
"view/account_view.xml",
|
||||
"view/report_general_ledger.xml",
|
||||
"view/report_journal_ledger.xml",
|
||||
"view/report_trial_balance.xml",
|
||||
"view/report_open_items.xml",
|
||||
"view/report_aged_partner_balance.xml",
|
||||
"view/report_vat_report.xml",
|
||||
"view/res_config_settings_views.xml",
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"account_financial_report/static/src/js/*",
|
||||
"account_financial_report/static/src/scss/*",
|
||||
"account_financial_report/static/src/xml/**/*",
|
||||
],
|
||||
},
|
||||
"installable": True,
|
||||
"application": True,
|
||||
"auto_install": False,
|
||||
"license": "AGPL-3",
|
||||
}
|
||||
1948
account_financial_report/i18n/account_financial_report.pot
Normal file
1948
account_financial_report/i18n/account_financial_report.pot
Normal file
File diff suppressed because it is too large
Load Diff
2234
account_financial_report/i18n/ar.po
Normal file
2234
account_financial_report/i18n/ar.po
Normal file
File diff suppressed because it is too large
Load Diff
2078
account_financial_report/i18n/ca.po
Normal file
2078
account_financial_report/i18n/ca.po
Normal file
File diff suppressed because it is too large
Load Diff
2383
account_financial_report/i18n/de.po
Normal file
2383
account_financial_report/i18n/de.po
Normal file
File diff suppressed because it is too large
Load Diff
2081
account_financial_report/i18n/es.po
Normal file
2081
account_financial_report/i18n/es.po
Normal file
File diff suppressed because it is too large
Load Diff
2120
account_financial_report/i18n/es_AR.po
Normal file
2120
account_financial_report/i18n/es_AR.po
Normal file
File diff suppressed because it is too large
Load Diff
1934
account_financial_report/i18n/es_MX.po
Normal file
1934
account_financial_report/i18n/es_MX.po
Normal file
File diff suppressed because it is too large
Load Diff
2341
account_financial_report/i18n/fr.po
Normal file
2341
account_financial_report/i18n/fr.po
Normal file
File diff suppressed because it is too large
Load Diff
2316
account_financial_report/i18n/fr_CH.po
Normal file
2316
account_financial_report/i18n/fr_CH.po
Normal file
File diff suppressed because it is too large
Load Diff
2066
account_financial_report/i18n/fr_FR.po
Normal file
2066
account_financial_report/i18n/fr_FR.po
Normal file
File diff suppressed because it is too large
Load Diff
1986
account_financial_report/i18n/hr.po
Normal file
1986
account_financial_report/i18n/hr.po
Normal file
File diff suppressed because it is too large
Load Diff
1970
account_financial_report/i18n/hr_HR.po
Normal file
1970
account_financial_report/i18n/hr_HR.po
Normal file
File diff suppressed because it is too large
Load Diff
2188
account_financial_report/i18n/it.po
Normal file
2188
account_financial_report/i18n/it.po
Normal file
File diff suppressed because it is too large
Load Diff
1945
account_financial_report/i18n/ja.po
Normal file
1945
account_financial_report/i18n/ja.po
Normal file
File diff suppressed because it is too large
Load Diff
2365
account_financial_report/i18n/nl.po
Normal file
2365
account_financial_report/i18n/nl.po
Normal file
File diff suppressed because it is too large
Load Diff
1958
account_financial_report/i18n/nl_NL.po
Normal file
1958
account_financial_report/i18n/nl_NL.po
Normal file
File diff suppressed because it is too large
Load Diff
2083
account_financial_report/i18n/pt.po
Normal file
2083
account_financial_report/i18n/pt.po
Normal file
File diff suppressed because it is too large
Load Diff
2429
account_financial_report/i18n/pt_BR.po
Normal file
2429
account_financial_report/i18n/pt_BR.po
Normal file
File diff suppressed because it is too large
Load Diff
2218
account_financial_report/i18n/ro.po
Normal file
2218
account_financial_report/i18n/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
2026
account_financial_report/i18n/sv.po
Normal file
2026
account_financial_report/i18n/sv.po
Normal file
File diff suppressed because it is too large
Load Diff
1951
account_financial_report/i18n/tr.po
Normal file
1951
account_financial_report/i18n/tr.po
Normal file
File diff suppressed because it is too large
Load Diff
45
account_financial_report/menuitems.xml
Normal file
45
account_financial_report/menuitems.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<menuitem
|
||||
parent="account.menu_finance_reports"
|
||||
id="menu_oca_reports"
|
||||
name="OCA accounting reports"
|
||||
groups="account.group_account_user"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_general_ledger_wizard"
|
||||
id="menu_general_ledger_wizard"
|
||||
sequence="10"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_journal_ledger_wizard"
|
||||
id="menu_journal_ledger_wizard"
|
||||
sequence="15"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_trial_balance_wizard"
|
||||
id="menu_trial_balance_wizard"
|
||||
sequence="20"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_open_items_wizard"
|
||||
id="menu_open_items_wizard"
|
||||
sequence="30"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_aged_partner_balance_wizard"
|
||||
id="menu_aged_partner_balance_wizard"
|
||||
sequence="40"
|
||||
/>
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_vat_report_wizard"
|
||||
id="menu_vat_report_wizard"
|
||||
sequence="50"
|
||||
/>
|
||||
</odoo>
|
||||
6
account_financial_report/models/__init__.py
Normal file
6
account_financial_report/models/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from . import account_age_report_configuration
|
||||
from . import account_group
|
||||
from . import account
|
||||
from . import account_move_line
|
||||
from . import ir_actions_report
|
||||
from . import res_config_settings
|
||||
13
account_financial_report/models/account.py
Normal file
13
account_financial_report/models/account.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# © 2011 Guewen Baconnier (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountAccount(models.Model):
|
||||
_inherit = "account.account"
|
||||
|
||||
centralized = fields.Boolean(
|
||||
help="If flagged, no details will be displayed in "
|
||||
"the General Ledger report (the webkit one only), "
|
||||
"only centralized amounts per period.",
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
# Copyright 2023 Ernesto García
|
||||
# Copyright 2023 Carolina Fernandez
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class AccountAgeReportConfiguration(models.Model):
|
||||
_name = "account.age.report.configuration"
|
||||
_description = "Model to set intervals for Age partner balance report"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
company_id = fields.Many2one(
|
||||
"res.company", default=lambda self: self.env.company, readonly=True
|
||||
)
|
||||
line_ids = fields.One2many(
|
||||
"account.age.report.configuration.line", "account_age_report_config_id"
|
||||
)
|
||||
|
||||
@api.constrains("line_ids")
|
||||
def _check_line_ids(self):
|
||||
for rec in self:
|
||||
if not rec.line_ids:
|
||||
raise ValidationError(self.env._("Must complete Configuration Lines"))
|
||||
|
||||
|
||||
class AccountAgeReportConfigurationLine(models.Model):
|
||||
_name = "account.age.report.configuration.line"
|
||||
_description = "Model to set interval lines for Age partner balance report"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
account_age_report_config_id = fields.Many2one("account.age.report.configuration")
|
||||
inferior_limit = fields.Integer()
|
||||
|
||||
@api.constrains("inferior_limit")
|
||||
def _check_inferior_limit(self):
|
||||
for rec in self:
|
||||
if rec.inferior_limit <= 0:
|
||||
raise ValidationError(
|
||||
self.env._("Inferior Limit must be greather than zero")
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"unique_name_config_combination",
|
||||
"UNIQUE(name,account_age_report_config_id)",
|
||||
"Name must be unique per report configuration",
|
||||
)
|
||||
]
|
||||
67
account_financial_report/models/account_group.py
Normal file
67
account_financial_report/models/account_group.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# © 2018 Forest and Biomass Romania SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AccountGroup(models.Model):
|
||||
_inherit = "account.group"
|
||||
|
||||
group_child_ids = fields.One2many(
|
||||
comodel_name="account.group", inverse_name="parent_id", string="Child Groups"
|
||||
)
|
||||
level = fields.Integer(compute="_compute_level", recursive=True)
|
||||
account_ids = fields.One2many(
|
||||
comodel_name="account.account", inverse_name="group_id", string="Accounts"
|
||||
)
|
||||
compute_account_ids = fields.Many2many(
|
||||
"account.account",
|
||||
recursive=True,
|
||||
compute="_compute_group_accounts",
|
||||
string="Compute accounts",
|
||||
store=True,
|
||||
)
|
||||
complete_name = fields.Char(
|
||||
"Full Name", compute="_compute_complete_name", recursive=True
|
||||
)
|
||||
complete_code = fields.Char(
|
||||
"Full Code", compute="_compute_complete_code", recursive=True
|
||||
)
|
||||
|
||||
@api.depends("name", "parent_id.complete_name")
|
||||
def _compute_complete_name(self):
|
||||
"""Forms complete name of location from parent location to child location."""
|
||||
for group in self:
|
||||
if group.parent_id.complete_name:
|
||||
group.complete_name = f"{group.parent_id.complete_name}/{group.name}"
|
||||
else:
|
||||
group.complete_name = group.name
|
||||
|
||||
@api.depends("code_prefix_start", "parent_id.complete_code")
|
||||
def _compute_complete_code(self):
|
||||
"""Forms complete code of location from parent location to child location."""
|
||||
for group in self:
|
||||
if group.parent_id.complete_code:
|
||||
group.complete_code = (
|
||||
f"{group.parent_id.complete_code}/{group.code_prefix_start}"
|
||||
)
|
||||
else:
|
||||
group.complete_code = group.code_prefix_start
|
||||
|
||||
@api.depends("parent_id", "parent_id.level")
|
||||
def _compute_level(self):
|
||||
for group in self:
|
||||
if not group.parent_id:
|
||||
group.level = 0
|
||||
else:
|
||||
group.level = group.parent_id.level + 1
|
||||
|
||||
@api.depends(
|
||||
"account_ids",
|
||||
"group_child_ids.compute_account_ids",
|
||||
)
|
||||
def _compute_group_accounts(self):
|
||||
for one in self:
|
||||
one.compute_account_ids = (
|
||||
one.account_ids | one.group_child_ids.compute_account_ids
|
||||
)
|
||||
70
account_financial_report/models/account_move_line.py
Normal file
70
account_financial_report/models/account_move_line.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright 2019 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.fields import Command
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
analytic_account_ids = fields.Many2many(
|
||||
"account.analytic.account", compute="_compute_analytic_account_ids", store=True
|
||||
)
|
||||
|
||||
@api.depends("analytic_distribution")
|
||||
def _compute_analytic_account_ids(self):
|
||||
# Prefetch all involved analytic accounts
|
||||
batch_by_analytic_account = defaultdict(lambda: self.env["account.move.line"])
|
||||
for record in self.filtered("analytic_distribution"):
|
||||
# NB: ``analytic_distribution`` is a JSON field where keys can be either
|
||||
# 'account.id' or 'account.id,account.id'
|
||||
# Eg: https://github.com/odoo/odoo/blob/8479b4e/addons/sale/models/account_move_line.py#L158
|
||||
for key in record.analytic_distribution:
|
||||
for account_id in map(int, key.split(",")):
|
||||
batch_by_analytic_account[account_id] += record
|
||||
existing_account_ids = set(
|
||||
self.env["account.analytic.account"]
|
||||
.browse(batch_by_analytic_account)
|
||||
.exists()
|
||||
.ids
|
||||
)
|
||||
# Store them
|
||||
self.analytic_account_ids = [Command.clear()]
|
||||
for account_id, records in batch_by_analytic_account.items():
|
||||
if account_id in existing_account_ids:
|
||||
records.analytic_account_ids = [Command.link(account_id)]
|
||||
|
||||
def init(self):
|
||||
"""
|
||||
The join between accounts_partners subquery and account_move_line
|
||||
can be heavy to compute on big databases.
|
||||
Join sample:
|
||||
JOIN
|
||||
account_move_line ml
|
||||
ON ap.account_id = ml.account_id
|
||||
AND ml.date < '2018-12-30'
|
||||
AND ap.partner_id = ml.partner_id
|
||||
AND ap.include_initial_balance = TRUE
|
||||
By adding the following index, performances are strongly increased.
|
||||
:return:
|
||||
"""
|
||||
self._cr.execute(
|
||||
"SELECT indexname FROM pg_indexes WHERE indexname = " "%s",
|
||||
("account_move_line_account_id_partner_id_index",),
|
||||
)
|
||||
if not self._cr.fetchone():
|
||||
self._cr.execute(
|
||||
"""
|
||||
CREATE INDEX account_move_line_account_id_partner_id_index
|
||||
ON account_move_line (account_id, partner_id)"""
|
||||
)
|
||||
|
||||
@api.model
|
||||
def search_count(self, domain, limit=None):
|
||||
# In Big DataBase every time you change the domain widget this method
|
||||
# takes a lot of time. This improves performance
|
||||
if self.env.context.get("skip_search_count"):
|
||||
return 0
|
||||
return super().search_count(domain, limit=limit)
|
||||
27
account_financial_report/models/ir_actions_report.py
Normal file
27
account_financial_report/models/ir_actions_report.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2020 Onestein (<https://www.onestein.eu>)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class IrActionsReport(models.Model):
|
||||
_inherit = "ir.actions.report"
|
||||
|
||||
@api.model
|
||||
def _prepare_account_financial_report_context(self, data):
|
||||
lang = data and data.get("account_financial_report_lang") or ""
|
||||
return dict(self.env.context or {}, lang=lang) if lang else False
|
||||
|
||||
@api.model
|
||||
def _render_qweb_html(self, report_ref, docids, data=None):
|
||||
context = self._prepare_account_financial_report_context(data)
|
||||
obj = self.with_context(**context) if context else self
|
||||
return super(IrActionsReport, obj)._render_qweb_html(
|
||||
report_ref, docids, data=data
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _render_xlsx(self, report_ref, docids, data=None):
|
||||
context = self._prepare_account_financial_report_context(data)
|
||||
obj = self.with_context(**context) if context else self
|
||||
return super(IrActionsReport, obj)._render_xlsx(report_ref, docids, data=data)
|
||||
14
account_financial_report/models/res_config_settings.py
Normal file
14
account_financial_report/models/res_config_settings.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2023 Tecnativa - Carolina Fernandez
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
default_age_partner_config_id = fields.Many2one(
|
||||
"account.age.report.configuration",
|
||||
string="Intervals configuration",
|
||||
default_model="aged.partner.balance.report.wizard",
|
||||
)
|
||||
3
account_financial_report/pyproject.toml
Normal file
3
account_financial_report/pyproject.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ["whool"]
|
||||
build-backend = "whool.buildapi"
|
||||
26
account_financial_report/readme/CONFIGURE.md
Normal file
26
account_financial_report/readme/CONFIGURE.md
Normal file
@@ -0,0 +1,26 @@
|
||||
To configure dynamic intervals for Aged Partner Balance you need to:
|
||||
|
||||
Go on 'Settings' -> 'Invoicing' -> 'OCA Aged Report Configuration'.
|
||||
|
||||
Click on option 'Configurations' and create new record.
|
||||
|
||||
Create new interval.
|
||||
The name established on line will be the column to display in Aged Partner Balance.
|
||||
Inferior limit established on line is the interval
|
||||
|
||||
Example of configuration inferior limit:
|
||||
|
||||
-> 15
|
||||
-> 30
|
||||
-> 60
|
||||
|
||||
It means the first interval is from 0 to 15, the second from 16 to 30, and the third is 61+.
|
||||
|
||||
Go on 'Invoicing' -> 'Reporting' -> 'OCA accounting reports' -> 'Aged Partner Balance'
|
||||
|
||||
When wizard is open, you need to select your interval configuration and print report.
|
||||
|
||||
If you want to get default interval configuration any time you wish to print Aged Partner Report,
|
||||
you can set default interval configuration per company in:
|
||||
|
||||
'Settings' -> 'Invoicing' -> 'OCA Aged Report Configuration'.
|
||||
36
account_financial_report/readme/CONTRIBUTORS.md
Normal file
36
account_financial_report/readme/CONTRIBUTORS.md
Normal file
@@ -0,0 +1,36 @@
|
||||
- Jordi Ballester \<<jordi.ballester@forgeflow.com>\>
|
||||
- Yannick Vaucher \<<yannick.vaucher@camptocamp.com>\>
|
||||
- Simone Orsi \<<simone.orsi@abstract.com>\>
|
||||
- Leonardo Pistone \<<leonardo.pistone@camptocamp.com>\>
|
||||
- Damien Crier \<<damien.crier@camptocamp.com>\>
|
||||
- Andrea Stirpe \<<a.stirpe@onestein.nl>\>
|
||||
- Thomas Rehn \<<thomas.rehn@initos.com>\>
|
||||
- Andrea Gallina \<<4everamd@gmail.com>\>
|
||||
- Robert Rottermann \<<robert@redcor.ch>\>
|
||||
- Ciro Urselli \<<c.urselli@apuliasoftware.it>\>
|
||||
- Francesco Apruzzese \<<opencode@e-ware.org>\>
|
||||
- Lorenzo Battistini \<<https://github.com/eLBati>\>
|
||||
- Julien Coux \<<julien.coux@camptocamp.com>\>
|
||||
- Akim Juillerat \<<akim.juillerat@camptocamp.com>\>
|
||||
- Alexis de Lattre \<<alexis@via.ecp.fr>\>
|
||||
- Mihai Fekete \<<feketemihai@gmail.com>\>
|
||||
- Miquel Ra??ch \<<miquel.raich@forgeflow.com>\>
|
||||
- Joan Sisquella \<<joan.sisquella@forgeflow.com>\>
|
||||
- [Tecnativa](https://www.tecnativa.com):
|
||||
- Pedro M. Baeza
|
||||
- Sergio Teruel
|
||||
- Ernesto Tejeda
|
||||
- João Marques
|
||||
- Alexandre D. D??az
|
||||
- V??ctor Mart??nez
|
||||
- Carolina Fernandez
|
||||
- [Sygel](https://www.sygel.es):
|
||||
- Harald Panten
|
||||
- Valentin Vinagre
|
||||
- Lois Rilo \<<lois.rilo@forgeflow.com>\>
|
||||
- Saran Lim. \<<saranl@ecosoft.co.th>\>
|
||||
- Omar Casti??eira \<<omar@comunitea.com>\>
|
||||
- Chau Le \<<chaulb@trobz.com>\>
|
||||
|
||||
Much of the work in this module was done at a sprint in Sorrento, Italy
|
||||
in April 2016.
|
||||
1
account_financial_report/readme/CREDITS.md
Normal file
1
account_financial_report/readme/CREDITS.md
Normal file
@@ -0,0 +1 @@
|
||||
The migration of this module from 17.0 to 18.0 was financially supported by Camptocamp.
|
||||
21
account_financial_report/readme/DESCRIPTION.md
Normal file
21
account_financial_report/readme/DESCRIPTION.md
Normal file
@@ -0,0 +1,21 @@
|
||||
This module adds a set of financial reports. They are accessible under
|
||||
Invoicing / Reporting / OCA accounting reports.
|
||||
|
||||
- General ledger
|
||||
- Trial Balance
|
||||
- Open Items
|
||||
- Aged Partner Balance
|
||||
- VAT Report
|
||||
- Journal Ledger
|
||||
|
||||
Currently General ledger, Trial Balance and Open Items are fully
|
||||
compatible with a foreign currency set up in account in order to display
|
||||
balances. Moreover, any foreign currency used in account move lines is
|
||||
properly shown.
|
||||
|
||||
In case that in an account has not been configured a second currency
|
||||
foreign currency balances are not available.
|
||||
|
||||
Invoicing / Settings / Invoicing / OCA Aged Report Configuration you will be able to set
|
||||
dynamic intervals that will appear on the Aged Partner Balance.
|
||||
For further information, check CONFIGURE.rst
|
||||
16
account_financial_report/readme/HISTORY.md
Normal file
16
account_financial_report/readme/HISTORY.md
Normal file
@@ -0,0 +1,16 @@
|
||||
## 11.0.2.5.0 (2019-04-26)
|
||||
|
||||
- In the Trial Balance you have an option to hide parent hierarchy
|
||||
levels
|
||||
|
||||
## 11.0.2.4.1 (2019-01-08)
|
||||
|
||||
- Handle better multicompany behaviour
|
||||
- Improve how title appears in the reports
|
||||
- Improve performance in General Ledger
|
||||
|
||||
## 11.0.2.3.1 (2018-11-29)
|
||||
|
||||
- In the Trial Balance you can apply a filter by hierarchy levels
|
||||
- In the General Ledger you can apply a filter by Analytic Tag
|
||||
- In the Journal Ledger the field 'Journal' is now optional
|
||||
6
account_financial_report/readme/ROADMAP.md
Normal file
6
account_financial_report/readme/ROADMAP.md
Normal file
@@ -0,0 +1,6 @@
|
||||
- 'VAT Report' is valid only for cases where it's met that for each Tax
|
||||
defined: all the "Account tags" of all the 'Repartition for Invoices'
|
||||
or 'Repartition for Credit Notes' are different.
|
||||
- It would be nice to have in reports a column indicating the state of
|
||||
the entries when the option "All Entries" is selected in "Target
|
||||
Moves" field in a wizard
|
||||
19
account_financial_report/report/__init__.py
Normal file
19
account_financial_report/report/__init__.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# © 2015 Yannick Vaucher (Camptocamp)
|
||||
# © 2016 Damien Crier (Camptocamp)
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
|
||||
from . import abstract_report
|
||||
from . import abstract_report_xlsx
|
||||
from . import aged_partner_balance
|
||||
from . import aged_partner_balance_xlsx
|
||||
from . import general_ledger
|
||||
from . import general_ledger_xlsx
|
||||
from . import journal_ledger
|
||||
from . import journal_ledger_xlsx
|
||||
from . import open_items
|
||||
from . import open_items_xlsx
|
||||
from . import trial_balance
|
||||
from . import trial_balance_xlsx
|
||||
from . import vat_report
|
||||
from . import vat_report_xlsx
|
||||
164
account_financial_report/report/abstract_report.py
Normal file
164
account_financial_report/report/abstract_report.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class AgedPartnerBalanceReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.abstract_report"
|
||||
_description = "Abstract Report"
|
||||
COMMON_ML_FIELDS = [
|
||||
"account_id",
|
||||
"partner_id",
|
||||
"journal_id",
|
||||
"date",
|
||||
"ref",
|
||||
"id",
|
||||
"move_id",
|
||||
"name",
|
||||
]
|
||||
|
||||
@api.model
|
||||
def _get_move_lines_domain_not_reconciled(
|
||||
self, company_id, account_ids, partner_ids, only_posted_moves, date_from
|
||||
):
|
||||
domain = [
|
||||
("account_id", "in", account_ids),
|
||||
("company_id", "=", company_id),
|
||||
("reconciled", "=", False),
|
||||
]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if date_from:
|
||||
domain += [("date", ">", date_from)]
|
||||
return domain
|
||||
|
||||
@api.model
|
||||
def _get_new_move_lines_domain(
|
||||
self, new_ml_ids, account_ids, company_id, partner_ids, only_posted_moves
|
||||
):
|
||||
domain = [
|
||||
("account_id", "in", account_ids),
|
||||
("company_id", "=", company_id),
|
||||
("id", "in", new_ml_ids),
|
||||
]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
return domain
|
||||
|
||||
def _recalculate_move_lines(
|
||||
self,
|
||||
move_lines,
|
||||
debit_ids,
|
||||
credit_ids,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
ml_ids,
|
||||
account_ids,
|
||||
company_id,
|
||||
partner_ids,
|
||||
only_posted_moves,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
):
|
||||
debit_ids = set(debit_ids)
|
||||
credit_ids = set(credit_ids)
|
||||
in_credit_but_not_in_debit = credit_ids - debit_ids
|
||||
reconciled_ids = list(debit_ids) + list(in_credit_but_not_in_debit)
|
||||
reconciled_ids = set(reconciled_ids)
|
||||
ml_ids = set(ml_ids)
|
||||
new_ml_ids = reconciled_ids - ml_ids
|
||||
new_ml_ids = list(new_ml_ids)
|
||||
new_domain = self._get_new_move_lines_domain(
|
||||
new_ml_ids, account_ids, company_id, partner_ids, only_posted_moves
|
||||
)
|
||||
company_currency = self.env["res.company"].browse(company_id).currency_id
|
||||
ml_fields = self._get_ml_fields()
|
||||
new_move_lines = self.env["account.move.line"].search_read(
|
||||
domain=new_domain, fields=ml_fields
|
||||
)
|
||||
move_lines = move_lines + new_move_lines
|
||||
for move_line in move_lines:
|
||||
ml_id = move_line["id"]
|
||||
if ml_id in debit_ids:
|
||||
if move_line.get("amount_residual", False):
|
||||
move_line["amount_residual"] += debit_amount[ml_id]
|
||||
else:
|
||||
move_line["amount_residual"] = debit_amount[ml_id]
|
||||
if move_line.get("amount_residual_currency", False):
|
||||
move_line["amount_residual_currency"] += debit_amount_currency[
|
||||
ml_id
|
||||
]
|
||||
else:
|
||||
move_line["amount_residual_currency"] = debit_amount_currency[ml_id]
|
||||
if ml_id in credit_ids:
|
||||
if move_line.get("amount_residual", False):
|
||||
move_line["amount_residual"] -= credit_amount[ml_id]
|
||||
else:
|
||||
move_line["amount_residual"] = -credit_amount[ml_id]
|
||||
if move_line.get("amount_residual_currency", False):
|
||||
move_line["amount_residual_currency"] -= credit_amount_currency[
|
||||
ml_id
|
||||
]
|
||||
else:
|
||||
move_line["amount_residual_currency"] = -credit_amount_currency[
|
||||
ml_id
|
||||
]
|
||||
# Set amount_currency=0 to keep the same behaviour as in v13
|
||||
# Conditions: if there is no curency_id defined or it is equal
|
||||
# to the company's curency_id
|
||||
if "amount_currency" in move_line and (
|
||||
"currency_id" not in move_line
|
||||
or move_line["currency_id"] == company_currency.id
|
||||
):
|
||||
move_line["amount_currency"] = 0
|
||||
return move_lines
|
||||
|
||||
def _get_accounts_data(self, accounts_ids):
|
||||
accounts = self.env["account.account"].browse(accounts_ids)
|
||||
accounts_data = {}
|
||||
for account in accounts:
|
||||
accounts_data.update(
|
||||
{
|
||||
account.id: {
|
||||
"id": account.id,
|
||||
"code": account.code,
|
||||
"name": account.name,
|
||||
"hide_account": False,
|
||||
"group_id": account.group_id.id,
|
||||
"currency_id": account.currency_id.id,
|
||||
"currency_name": account.currency_id.name,
|
||||
"centralized": account.centralized,
|
||||
}
|
||||
}
|
||||
)
|
||||
return accounts_data
|
||||
|
||||
def _get_journals_data(self, journals_ids):
|
||||
journals = self.env["account.journal"].search_fetch(
|
||||
[("id", "in", journals_ids)], ["code"]
|
||||
)
|
||||
journals_data = {}
|
||||
for journal in journals:
|
||||
journals_data.update({journal.id: {"id": journal.id, "code": journal.code}})
|
||||
return journals_data
|
||||
|
||||
def _get_ml_fields(self):
|
||||
return self.COMMON_ML_FIELDS + [
|
||||
"amount_residual",
|
||||
"reconciled",
|
||||
"currency_id",
|
||||
"credit",
|
||||
"date_maturity",
|
||||
"amount_residual_currency",
|
||||
"debit",
|
||||
"amount_currency",
|
||||
]
|
||||
697
account_financial_report/report/abstract_report_xlsx.py
Normal file
697
account_financial_report/report/abstract_report_xlsx.py
Normal file
@@ -0,0 +1,697 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
from odoo import models
|
||||
|
||||
|
||||
class AbstractReportXslx(models.AbstractModel):
|
||||
_name = "report.account_financial_report.abstract_report_xlsx"
|
||||
_description = "Abstract XLSX Account Financial Report"
|
||||
_inherit = "report.report_xlsx.abstract"
|
||||
|
||||
def get_workbook_options(self):
|
||||
vals = super().get_workbook_options()
|
||||
vals.update({"constant_memory": True})
|
||||
return vals
|
||||
|
||||
def generate_xlsx_report(self, workbook, data, objects):
|
||||
# Initialize report variables
|
||||
report_data = {
|
||||
"workbook": None,
|
||||
"sheet": None, # main sheet which will contains report
|
||||
"columns": None, # columns of the report
|
||||
"row_pos": None, # row_pos must be incremented at each writing lines
|
||||
"formats": None,
|
||||
}
|
||||
self._define_formats(workbook, report_data)
|
||||
# Get report data
|
||||
report_name = self._get_report_name(objects, data=data)
|
||||
report_footer = self._get_report_footer()
|
||||
filters = self._get_report_filters(objects)
|
||||
report_data["columns"] = self._get_report_columns(objects)
|
||||
report_data["workbook"] = workbook
|
||||
report_data["sheet"] = workbook.add_worksheet(report_name[:31])
|
||||
self._set_column_width(report_data)
|
||||
# Fill report
|
||||
report_data["row_pos"] = 0
|
||||
self._write_report_title(report_name, report_data)
|
||||
self._write_filters(filters, report_data)
|
||||
self._generate_report_content(workbook, objects, data, report_data)
|
||||
self._write_report_footer(report_footer, report_data)
|
||||
|
||||
def _define_formats(self, workbook, report_data):
|
||||
"""Add cell formats to current workbook.
|
||||
Those formats can be used on all cell.
|
||||
Available formats are :
|
||||
* format_bold
|
||||
* format_right
|
||||
* format_right_bold_italic
|
||||
* format_header_left
|
||||
* format_header_center
|
||||
* format_header_right
|
||||
* format_header_amount
|
||||
* format_amount
|
||||
* format_percent_bold_italic
|
||||
"""
|
||||
currency_id = self.env["res.company"]._default_currency_id()
|
||||
report_data["formats"] = {
|
||||
"format_bold": workbook.add_format({"bold": True}),
|
||||
"format_right": workbook.add_format({"align": "right"}),
|
||||
"format_left": workbook.add_format({"align": "left"}),
|
||||
"format_right_bold_italic": workbook.add_format(
|
||||
{"align": "right", "bold": True, "italic": True}
|
||||
),
|
||||
"format_header_left": workbook.add_format(
|
||||
{"bold": True, "border": True, "bg_color": "#FFFFCC"}
|
||||
),
|
||||
"format_header_center": workbook.add_format(
|
||||
{"bold": True, "align": "center", "border": True, "bg_color": "#FFFFCC"}
|
||||
),
|
||||
"format_header_right": workbook.add_format(
|
||||
{"bold": True, "align": "right", "border": True, "bg_color": "#FFFFCC"}
|
||||
),
|
||||
"format_header_amount": workbook.add_format(
|
||||
{"bold": True, "border": True, "bg_color": "#FFFFCC"}
|
||||
),
|
||||
"format_amount": workbook.add_format(),
|
||||
"format_amount_bold": workbook.add_format({"bold": True}),
|
||||
"format_percent_bold_italic": workbook.add_format(
|
||||
{"bold": True, "italic": True}
|
||||
),
|
||||
}
|
||||
report_data["formats"]["format_amount"].set_num_format(
|
||||
"#,##0." + "0" * currency_id.decimal_places
|
||||
)
|
||||
report_data["formats"]["format_header_amount"].set_num_format(
|
||||
"#,##0." + "0" * currency_id.decimal_places
|
||||
)
|
||||
report_data["formats"]["format_percent_bold_italic"].set_num_format("#,##0.00%")
|
||||
report_data["formats"]["format_amount_bold"].set_num_format(
|
||||
"#,##0." + "0" * currency_id.decimal_places
|
||||
)
|
||||
|
||||
def _set_column_width(self, report_data):
|
||||
"""Set width for all defined columns.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for position, column in report_data["columns"].items():
|
||||
report_data["sheet"].set_column(position, position, column["width"])
|
||||
|
||||
def _write_report_title(self, title, report_data):
|
||||
"""Write report title on current line using all defined columns width.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
0,
|
||||
report_data["row_pos"],
|
||||
len(report_data["columns"]) - 1,
|
||||
title,
|
||||
report_data["formats"]["format_bold"],
|
||||
)
|
||||
report_data["row_pos"] += 3
|
||||
|
||||
def _write_report_footer(self, footer, report_data):
|
||||
"""Write report footer .
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
if footer:
|
||||
report_data["row_pos"] += 1
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
0,
|
||||
report_data["row_pos"],
|
||||
len(report_data["columns"]) - 1,
|
||||
footer,
|
||||
report_data["formats"]["format_left"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def _write_filters(self, filters, report_data):
|
||||
"""Write one line per filters on starting on current line.
|
||||
Columns number for filter name is defined
|
||||
with `_get_col_count_filter_name` method.
|
||||
Columns number for filter value is define
|
||||
with `_get_col_count_filter_value` method.
|
||||
"""
|
||||
col_name = 1
|
||||
col_count_filter_name = self._get_col_count_filter_name()
|
||||
col_count_filter_value = self._get_col_count_filter_value()
|
||||
col_value = col_name + col_count_filter_name + 1
|
||||
for title, value in filters:
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
col_name,
|
||||
report_data["row_pos"],
|
||||
col_name + col_count_filter_name - 1,
|
||||
title,
|
||||
report_data["formats"]["format_header_left"],
|
||||
)
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
col_value,
|
||||
report_data["row_pos"],
|
||||
col_value + col_count_filter_value - 1,
|
||||
value,
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def write_array_title(self, title, report_data):
|
||||
"""Write array title on current line using all defined columns width.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
0,
|
||||
report_data["row_pos"],
|
||||
len(report_data["columns"]) - 1,
|
||||
title,
|
||||
report_data["formats"]["format_bold"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_array_header(self, report_data):
|
||||
"""Write array header on current line using all defined columns name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
column["header"],
|
||||
report_data["formats"]["format_header_center"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_line(self, line_object, report_data):
|
||||
"""Write a line on current line using all defined columns field name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
value = getattr(line_object, column["field"])
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "many2one":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value.name or "",
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
elif cell_type == "string":
|
||||
if (
|
||||
hasattr(line_object, "account_group_id")
|
||||
and line_object.account_group_id
|
||||
):
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_bold"],
|
||||
)
|
||||
else:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, value or ""
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
if (
|
||||
hasattr(line_object, "account_group_id")
|
||||
and line_object.account_group_id
|
||||
):
|
||||
cell_format = report_data["formats"]["format_amount_bold"]
|
||||
else:
|
||||
cell_format = report_data["formats"]["format_amount"]
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), cell_format
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if line_object.currency_id:
|
||||
format_amt = self._get_currency_amt_format(line_object, report_data)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_line_from_dict(self, line_dict, report_data):
|
||||
"""Write a line on current line"""
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
value = line_dict.get(column["field"], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
if line_dict.get("type", "") == "group_type":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_bold"],
|
||||
)
|
||||
else:
|
||||
if (
|
||||
not isinstance(value, str)
|
||||
and not isinstance(value, bool)
|
||||
and not isinstance(value, int)
|
||||
):
|
||||
value = value and value.strftime("%d/%m/%Y")
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, value or ""
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
if (
|
||||
line_dict.get("account_group_id", False)
|
||||
and line_dict["account_group_id"]
|
||||
):
|
||||
cell_format = report_data["formats"]["format_amount_bold"]
|
||||
else:
|
||||
cell_format = report_data["formats"]["format_amount"]
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), cell_format
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if line_dict.get("currency_name", False):
|
||||
format_amt = self._get_currency_amt_format_dict(
|
||||
line_dict, report_data
|
||||
)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
elif cell_type == "currency_name":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
else:
|
||||
self.write_non_standard_column(cell_type, col_pos, value)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_initial_balance(self, my_object, label, report_data):
|
||||
"""Write a specific initial balance line on current line
|
||||
using defined columns field_initial_balance name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
col_pos_label = self._get_col_pos_initial_balance_label()
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
col_pos_label,
|
||||
label,
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if column.get("field_initial_balance"):
|
||||
value = getattr(my_object, column["field_initial_balance"])
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, value or ""
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
float(value),
|
||||
report_data["formats"]["format_amount"],
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if my_object.currency_id:
|
||||
format_amt = self._get_currency_amt_format(
|
||||
my_object, report_data
|
||||
)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
elif column.get("field_currency_balance"):
|
||||
value = getattr(my_object, column["field_currency_balance"])
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "many2one":
|
||||
if my_object.currency_id:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value.name or "",
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_initial_balance_from_dict(self, my_object, label, report_data):
|
||||
"""Write a specific initial balance line on current line
|
||||
using defined columns field_initial_balance name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
col_pos_label = self._get_col_pos_initial_balance_label()
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
col_pos_label,
|
||||
label,
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if column.get("field_initial_balance"):
|
||||
value = my_object.get(column["field_initial_balance"], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, value or ""
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
float(value),
|
||||
report_data["formats"]["format_amount"],
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if my_object["currency_id"]:
|
||||
format_amt = self._get_currency_amt_format(
|
||||
my_object, report_data
|
||||
)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
elif column.get("field_currency_balance"):
|
||||
value = my_object.get(column["field_currency_balance"], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "many2one":
|
||||
if my_object["currency_id"]:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value.name or "",
|
||||
report_data["formats"]["format_right"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_ending_balance(self, my_object, name, label, report_data):
|
||||
"""Write a specific ending balance line on current line
|
||||
using defined columns field_final_balance name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for i in range(0, len(report_data["columns"])):
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
i,
|
||||
"",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
row_count_name = self._get_col_count_final_balance_name()
|
||||
col_pos_label = self._get_col_pos_final_balance_label()
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
0,
|
||||
report_data["row_pos"],
|
||||
row_count_name - 1,
|
||||
name,
|
||||
report_data["formats"]["format_header_left"],
|
||||
)
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
col_pos_label,
|
||||
label,
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if column.get("field_final_balance"):
|
||||
value = getattr(my_object, column["field_final_balance"])
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
float(value),
|
||||
report_data["formats"]["format_header_amount"],
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if my_object.currency_id:
|
||||
format_amt = self._get_currency_amt_header_format(
|
||||
my_object, report_data
|
||||
)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
elif column.get("field_currency_balance"):
|
||||
value = getattr(my_object, column["field_currency_balance"])
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "many2one":
|
||||
if my_object.currency_id:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value.name or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def write_ending_balance_from_dict(self, my_object, name, label, report_data):
|
||||
"""Write a specific ending balance line on current line
|
||||
using defined columns field_final_balance name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for i in range(0, len(report_data["columns"])):
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
i,
|
||||
"",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
row_count_name = self._get_col_count_final_balance_name()
|
||||
col_pos_label = self._get_col_pos_final_balance_label()
|
||||
report_data["sheet"].merge_range(
|
||||
report_data["row_pos"],
|
||||
0,
|
||||
report_data["row_pos"],
|
||||
row_count_name - 1,
|
||||
name,
|
||||
report_data["formats"]["format_header_left"],
|
||||
)
|
||||
report_data["sheet"].write(
|
||||
report_data["row_pos"],
|
||||
col_pos_label,
|
||||
label,
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if column.get("field_final_balance"):
|
||||
value = my_object.get(column["field_final_balance"], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
float(value),
|
||||
report_data["formats"]["format_header_amount"],
|
||||
)
|
||||
elif cell_type == "amount_currency":
|
||||
if my_object["currency_id"]:
|
||||
format_amt = self._get_currency_amt_format_dict(
|
||||
my_object, report_data
|
||||
)
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
elif column.get("field_currency_balance"):
|
||||
value = my_object.get(column["field_currency_balance"], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "many2one":
|
||||
if my_object["currency_id"]:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
elif cell_type == "currency_name":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def _get_currency_amt_format(self, line_object, report_data):
|
||||
"""Return amount format specific for each currency."""
|
||||
if "account_group_id" in line_object and line_object["account_group_id"]:
|
||||
format_amt = report_data["formats"]["format_amount_bold"]
|
||||
field_prefix = "format_amount_bold"
|
||||
else:
|
||||
format_amt = report_data["formats"]["format_amount"]
|
||||
field_prefix = "format_amount"
|
||||
if "currency_id" in line_object and line_object.get("currency_id", False):
|
||||
if isinstance(line_object["currency_id"], int):
|
||||
currency = self.env["res.currency"].browse(line_object["currency_id"])
|
||||
else:
|
||||
currency = line_object["currency_id"]
|
||||
field_name = f"{field_prefix}_{currency.name}"
|
||||
if hasattr(self, field_name):
|
||||
format_amt = getattr(self, field_name)
|
||||
else:
|
||||
format_amt = report_data["workbook"].add_format()
|
||||
report_data["field_name"] = format_amt
|
||||
format_amt.set_num_format(self._report_xlsx_currency_format(currency))
|
||||
return format_amt
|
||||
|
||||
def _get_currency_amt_format_dict(self, line_dict, report_data):
|
||||
"""Return amount format specific for each currency."""
|
||||
if line_dict.get("account_group_id", False) and line_dict["account_group_id"]:
|
||||
format_amt = report_data["formats"]["format_amount_bold"]
|
||||
field_prefix = "format_amount_bold"
|
||||
else:
|
||||
format_amt = report_data["formats"]["format_amount"]
|
||||
field_prefix = "format_amount"
|
||||
if line_dict.get("currency_id", False) and line_dict["currency_id"]:
|
||||
if isinstance(line_dict["currency_id"], int):
|
||||
currency = self.env["res.currency"].browse(line_dict["currency_id"])
|
||||
else:
|
||||
currency = line_dict["currency_id"]
|
||||
field_name = f"{field_prefix}_{currency.name}"
|
||||
if hasattr(self, field_name):
|
||||
format_amt = getattr(self, field_name)
|
||||
else:
|
||||
format_amt = report_data["workbook"].add_format()
|
||||
report_data["field_name"] = format_amt
|
||||
format_amt.set_num_format(self._report_xlsx_currency_format(currency))
|
||||
return format_amt
|
||||
|
||||
def _get_currency_amt_header_format(self, line_object, report_data):
|
||||
"""Return amount header format for each currency."""
|
||||
format_amt = report_data["formats"]["format_header_amount"]
|
||||
if line_object.currency_id:
|
||||
field_name = f"format_header_amount_{line_object.currency_id.name}"
|
||||
if hasattr(self, field_name):
|
||||
format_amt = getattr(self, field_name)
|
||||
else:
|
||||
format_amt = report_data["workbook"].add_format(
|
||||
{"bold": True, "border": True, "bg_color": "#FFFFCC"}
|
||||
)
|
||||
report_data["field_name"] = format_amt
|
||||
format_amount = "#,##0." + (
|
||||
"0" * line_object.currency_id.decimal_places
|
||||
)
|
||||
format_amt.set_num_format(format_amount)
|
||||
return format_amt
|
||||
|
||||
def _get_currency_amt_header_format_dict(self, line_object, report_data):
|
||||
"""Return amount header format for each currency."""
|
||||
format_amt = report_data["formats"]["format_header_amount"]
|
||||
if line_object["currency_id"]:
|
||||
field_name = f"format_header_amount_{line_object['currency_name']}"
|
||||
if hasattr(self, field_name):
|
||||
format_amt = getattr(self, field_name)
|
||||
else:
|
||||
format_amt = report_data["workbook"].add_format(
|
||||
{"bold": True, "border": True, "bg_color": "#FFFFCC"}
|
||||
)
|
||||
report_data["field_name"] = format_amt
|
||||
currency = self.env["res.currency"].browse(line_object["currency_id"])
|
||||
format_amount = "#,##0." + ("0" * currency.decimal_places)
|
||||
format_amt.set_num_format(format_amount)
|
||||
return format_amt
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
"""
|
||||
Allow to fetch report content to be displayed.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_report_complete_name(self, report, prefix, data=None):
|
||||
if report.company_id:
|
||||
suffix = (
|
||||
f" - {report.company_id.name} - {report.company_id.currency_id.name}"
|
||||
)
|
||||
return prefix + suffix
|
||||
return prefix
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
"""
|
||||
Allow to define the report name.
|
||||
Report name will be used as sheet name and as report title.
|
||||
:return: the report name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_report_footer(self):
|
||||
"""
|
||||
Allow to define the report footer.
|
||||
:return: the report footer
|
||||
"""
|
||||
return False
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
"""
|
||||
Allow to define the report columns
|
||||
which will be used to generate report.
|
||||
:return: the report columns as dict
|
||||
:Example:
|
||||
{
|
||||
0: {'header': 'Simple column',
|
||||
'field': 'field_name_on_my_object',
|
||||
'width': 11},
|
||||
1: {'header': 'Amount column',
|
||||
'field': 'field_name_on_my_object',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
"""
|
||||
:return: the report filters as list
|
||||
:Example:
|
||||
[
|
||||
['first_filter_name', 'first_filter_value'],
|
||||
['second_filter_name', 'second_filter_value']
|
||||
]
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
"""
|
||||
:return: the columns number used for filter names.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
"""
|
||||
:return: the columns number used for filter values.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_pos_initial_balance_label(self):
|
||||
"""
|
||||
:return: the columns position used for initial balance label.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
"""
|
||||
:return: the columns number used for final balance name.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
"""
|
||||
:return: the columns position used for final balance label.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def write_non_standard_column(self, cell_type, col_pos, value):
|
||||
"""
|
||||
Write columns out of the columns type defined here.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
472
account_financial_report/report/aged_partner_balance.py
Normal file
472
account_financial_report/report/aged_partner_balance.py
Normal file
@@ -0,0 +1,472 @@
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import operator
|
||||
from datetime import date, datetime, timedelta
|
||||
|
||||
from odoo import api, models
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
class AgedPartnerBalanceReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.aged_partner_balance"
|
||||
_description = "Aged Partner Balance Report"
|
||||
_inherit = "report.account_financial_report.abstract_report"
|
||||
|
||||
@api.model
|
||||
def _initialize_account(self, ag_pb_data, acc_id):
|
||||
ag_pb_data[acc_id] = {}
|
||||
ag_pb_data[acc_id]["id"] = acc_id
|
||||
ag_pb_data[acc_id]["residual"] = 0.0
|
||||
ag_pb_data[acc_id]["current"] = 0.0
|
||||
ag_pb_data[acc_id]["30_days"] = 0.0
|
||||
ag_pb_data[acc_id]["60_days"] = 0.0
|
||||
ag_pb_data[acc_id]["90_days"] = 0.0
|
||||
ag_pb_data[acc_id]["120_days"] = 0.0
|
||||
ag_pb_data[acc_id]["older"] = 0.0
|
||||
for interval_line in self.env.context["age_partner_config"].line_ids:
|
||||
ag_pb_data[acc_id][interval_line] = 0.0
|
||||
return ag_pb_data
|
||||
|
||||
@api.model
|
||||
def _initialize_partner(self, ag_pb_data, acc_id, prt_id):
|
||||
ag_pb_data[acc_id][prt_id] = {}
|
||||
ag_pb_data[acc_id][prt_id]["id"] = acc_id
|
||||
ag_pb_data[acc_id][prt_id]["residual"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["current"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["30_days"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["60_days"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["90_days"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["120_days"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["older"] = 0.0
|
||||
ag_pb_data[acc_id][prt_id]["move_lines"] = []
|
||||
for interval_line in self.env.context["age_partner_config"].line_ids:
|
||||
ag_pb_data[acc_id][prt_id][interval_line] = 0.0
|
||||
return ag_pb_data
|
||||
|
||||
@api.model
|
||||
def _calculate_amounts(
|
||||
self, ag_pb_data, acc_id, prt_id, residual, due_date, date_at_object
|
||||
):
|
||||
ag_pb_data[acc_id]["residual"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["residual"] += residual
|
||||
interval_lines = self.env.context["age_partner_config"].line_ids
|
||||
today = date_at_object
|
||||
if not due_date or today <= due_date:
|
||||
ag_pb_data[acc_id]["current"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["current"] += residual
|
||||
due_date = today
|
||||
elif today <= due_date + timedelta(days=30):
|
||||
ag_pb_data[acc_id]["30_days"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["30_days"] += residual
|
||||
elif today <= due_date + timedelta(days=60):
|
||||
ag_pb_data[acc_id]["60_days"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["60_days"] += residual
|
||||
elif today <= due_date + timedelta(days=90):
|
||||
ag_pb_data[acc_id]["90_days"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["90_days"] += residual
|
||||
elif today <= due_date + timedelta(days=120):
|
||||
ag_pb_data[acc_id]["120_days"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["120_days"] += residual
|
||||
else:
|
||||
ag_pb_data[acc_id]["older"] += residual
|
||||
ag_pb_data[acc_id][prt_id]["older"] += residual
|
||||
|
||||
days_difference = abs((today - due_date).days)
|
||||
for index, line in enumerate(interval_lines):
|
||||
lower_limit = 0 if not index else interval_lines[index - 1].inferior_limit
|
||||
next_line = interval_lines[index] if index < len(interval_lines) else None
|
||||
interval_range = self._get_values_for_range_intervals(
|
||||
lower_limit, next_line.inferior_limit
|
||||
)
|
||||
if (
|
||||
days_difference in interval_range
|
||||
or days_difference == line.inferior_limit
|
||||
):
|
||||
ag_pb_data[acc_id][line] += residual
|
||||
ag_pb_data[acc_id][prt_id][line] += residual
|
||||
break
|
||||
return ag_pb_data
|
||||
|
||||
def _get_values_for_range_intervals(self, num1, num2):
|
||||
min_num = min(num1, num2)
|
||||
max_num = max(num1, num2)
|
||||
if abs(num2 - num1) == 1:
|
||||
return [max_num]
|
||||
return list(range(min_num + 1, max_num))
|
||||
|
||||
def _get_account_partial_reconciled(self, company_id, date_at_object):
|
||||
domain = [("max_date", ">", date_at_object), ("company_id", "=", company_id)]
|
||||
fields = [
|
||||
"debit_move_id",
|
||||
"credit_move_id",
|
||||
"amount",
|
||||
"debit_amount_currency",
|
||||
"credit_amount_currency",
|
||||
]
|
||||
accounts_partial_reconcile = self.env["account.partial.reconcile"].search_read(
|
||||
domain=domain, fields=fields
|
||||
)
|
||||
debit_amount = {}
|
||||
debit_amount_currency = {}
|
||||
credit_amount = {}
|
||||
credit_amount_currency = {}
|
||||
for account_partial_reconcile_data in accounts_partial_reconcile:
|
||||
debit_move_id = account_partial_reconcile_data["debit_move_id"][0]
|
||||
credit_move_id = account_partial_reconcile_data["credit_move_id"][0]
|
||||
if debit_move_id not in debit_amount.keys():
|
||||
debit_amount[debit_move_id] = 0.0
|
||||
debit_amount_currency[debit_move_id] = 0.0
|
||||
debit_amount_currency[debit_move_id] += account_partial_reconcile_data[
|
||||
"debit_amount_currency"
|
||||
]
|
||||
debit_amount[debit_move_id] += account_partial_reconcile_data["amount"]
|
||||
if credit_move_id not in credit_amount.keys():
|
||||
credit_amount[credit_move_id] = 0.0
|
||||
credit_amount_currency[credit_move_id] = 0.0
|
||||
credit_amount[credit_move_id] += account_partial_reconcile_data["amount"]
|
||||
credit_amount_currency[credit_move_id] += account_partial_reconcile_data[
|
||||
"credit_amount_currency"
|
||||
]
|
||||
account_partial_reconcile_data.update(
|
||||
{"debit_move_id": debit_move_id, "credit_move_id": credit_move_id}
|
||||
)
|
||||
return (
|
||||
accounts_partial_reconcile,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
)
|
||||
|
||||
def _get_move_lines_data(
|
||||
self,
|
||||
company_id,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
date_at_object,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_move_line_details,
|
||||
):
|
||||
domain = self._get_move_lines_domain_not_reconciled(
|
||||
company_id, account_ids, partner_ids, only_posted_moves, date_from
|
||||
)
|
||||
ml_fields = self._get_ml_fields()
|
||||
line_model = self.env["account.move.line"]
|
||||
move_lines = line_model.search_read(domain=domain, fields=ml_fields)
|
||||
journals_ids = set()
|
||||
partners_ids = set()
|
||||
partners_data = {}
|
||||
ag_pb_data = {}
|
||||
if date_at_object < date.today():
|
||||
(
|
||||
acc_partial_rec,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
) = self._get_account_partial_reconciled(company_id, date_at_object)
|
||||
if acc_partial_rec:
|
||||
ml_ids = list(map(operator.itemgetter("id"), move_lines))
|
||||
debit_ids = list(
|
||||
map(operator.itemgetter("debit_move_id"), acc_partial_rec)
|
||||
)
|
||||
credit_ids = list(
|
||||
map(operator.itemgetter("credit_move_id"), acc_partial_rec)
|
||||
)
|
||||
move_lines = self._recalculate_move_lines(
|
||||
move_lines,
|
||||
debit_ids,
|
||||
credit_ids,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
ml_ids,
|
||||
account_ids,
|
||||
company_id,
|
||||
partner_ids,
|
||||
only_posted_moves,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
)
|
||||
move_lines = [
|
||||
move_line
|
||||
for move_line in move_lines
|
||||
if move_line["date"] <= date_at_object
|
||||
and not float_is_zero(move_line["amount_residual"], precision_digits=2)
|
||||
]
|
||||
for move_line in move_lines:
|
||||
journals_ids.add(move_line["journal_id"][0])
|
||||
acc_id = move_line["account_id"][0]
|
||||
if move_line["partner_id"]:
|
||||
prt_id = move_line["partner_id"][0]
|
||||
prt_name = move_line["partner_id"][1]
|
||||
else:
|
||||
prt_id = 0
|
||||
prt_name = ""
|
||||
if prt_id not in partners_ids:
|
||||
partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
|
||||
partners_ids.add(prt_id)
|
||||
if acc_id not in ag_pb_data.keys():
|
||||
ag_pb_data = self._initialize_account(ag_pb_data, acc_id)
|
||||
if prt_id not in ag_pb_data[acc_id]:
|
||||
ag_pb_data = self._initialize_partner(ag_pb_data, acc_id, prt_id)
|
||||
move_line_data = {}
|
||||
if show_move_line_details:
|
||||
if move_line["ref"] == move_line["name"]:
|
||||
if move_line["ref"]:
|
||||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = ""
|
||||
elif not move_line["ref"]:
|
||||
ref_label = move_line["name"]
|
||||
elif not move_line["name"]:
|
||||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = move_line["ref"] + " - " + move_line["name"]
|
||||
move_line_data.update(
|
||||
{
|
||||
"line_rec": line_model.browse(move_line["id"]),
|
||||
"date": move_line["date"],
|
||||
"entry": move_line["move_id"][1],
|
||||
"jnl_id": move_line["journal_id"][0],
|
||||
"acc_id": acc_id,
|
||||
"partner": prt_name,
|
||||
"ref_label": ref_label,
|
||||
"due_date": move_line["date_maturity"],
|
||||
"residual": move_line["amount_residual"],
|
||||
}
|
||||
)
|
||||
ag_pb_data[acc_id][prt_id]["move_lines"].append(move_line_data)
|
||||
ag_pb_data = self._calculate_amounts(
|
||||
ag_pb_data,
|
||||
acc_id,
|
||||
prt_id,
|
||||
move_line["amount_residual"],
|
||||
move_line["date_maturity"],
|
||||
date_at_object,
|
||||
)
|
||||
journals_data = self._get_journals_data(list(journals_ids))
|
||||
accounts_data = self._get_accounts_data(ag_pb_data.keys())
|
||||
return ag_pb_data, accounts_data, partners_data, journals_data
|
||||
|
||||
@api.model
|
||||
def _compute_maturity_date(self, ml, date_at_object):
|
||||
ml.update(
|
||||
{
|
||||
"current": 0.0,
|
||||
"30_days": 0.0,
|
||||
"60_days": 0.0,
|
||||
"90_days": 0.0,
|
||||
"120_days": 0.0,
|
||||
"older": 0.0,
|
||||
}
|
||||
)
|
||||
interval_lines = self.env.context["age_partner_config"].line_ids
|
||||
for interval_line in interval_lines:
|
||||
ml[interval_line] = 0.0
|
||||
due_date = ml["due_date"]
|
||||
amount = ml["residual"]
|
||||
today = date_at_object
|
||||
if not due_date or today <= due_date:
|
||||
ml["current"] += amount
|
||||
due_date = today
|
||||
elif today <= due_date + timedelta(days=30):
|
||||
ml["30_days"] += amount
|
||||
elif today <= due_date + timedelta(days=60):
|
||||
ml["60_days"] += amount
|
||||
elif today <= due_date + timedelta(days=90):
|
||||
ml["90_days"] += amount
|
||||
elif today <= due_date + timedelta(days=120):
|
||||
ml["120_days"] += amount
|
||||
else:
|
||||
ml["older"] += amount
|
||||
if due_date:
|
||||
days_difference = abs((today - due_date).days)
|
||||
for index, interval_line in enumerate(interval_lines):
|
||||
lower_limit = (
|
||||
0 if not index else interval_lines[index - 1].inferior_limit
|
||||
)
|
||||
next_line = (
|
||||
interval_lines[index] if index < len(interval_lines) else None
|
||||
)
|
||||
interval_range = self._get_values_for_range_intervals(
|
||||
lower_limit, next_line.inferior_limit
|
||||
)
|
||||
if (
|
||||
days_difference in interval_range
|
||||
or days_difference == interval_line.inferior_limit
|
||||
):
|
||||
ml[interval_line] += amount
|
||||
break
|
||||
|
||||
def _create_account_list(
|
||||
self,
|
||||
ag_pb_data,
|
||||
accounts_data,
|
||||
partners_data,
|
||||
journals_data,
|
||||
show_move_line_details,
|
||||
date_at_oject,
|
||||
):
|
||||
aged_partner_data = []
|
||||
interval_lines = self.env.context["age_partner_config"].line_ids
|
||||
for account in accounts_data.values():
|
||||
acc_id = account["id"]
|
||||
account.update(
|
||||
{
|
||||
"residual": ag_pb_data[acc_id]["residual"],
|
||||
"current": ag_pb_data[acc_id]["current"],
|
||||
"30_days": ag_pb_data[acc_id]["30_days"],
|
||||
"60_days": ag_pb_data[acc_id]["60_days"],
|
||||
"90_days": ag_pb_data[acc_id]["90_days"],
|
||||
"120_days": ag_pb_data[acc_id]["120_days"],
|
||||
"older": ag_pb_data[acc_id]["older"],
|
||||
"partners": [],
|
||||
}
|
||||
)
|
||||
for interval_line in interval_lines:
|
||||
account[interval_line] = ag_pb_data[acc_id][interval_line]
|
||||
for prt_id in ag_pb_data[acc_id]:
|
||||
if isinstance(prt_id, int):
|
||||
partner = {
|
||||
"name": partners_data[prt_id]["name"],
|
||||
"residual": ag_pb_data[acc_id][prt_id]["residual"],
|
||||
"current": ag_pb_data[acc_id][prt_id]["current"],
|
||||
"30_days": ag_pb_data[acc_id][prt_id]["30_days"],
|
||||
"60_days": ag_pb_data[acc_id][prt_id]["60_days"],
|
||||
"90_days": ag_pb_data[acc_id][prt_id]["90_days"],
|
||||
"120_days": ag_pb_data[acc_id][prt_id]["120_days"],
|
||||
"older": ag_pb_data[acc_id][prt_id]["older"],
|
||||
}
|
||||
for interval_line in interval_lines:
|
||||
partner[interval_line] = ag_pb_data[acc_id][prt_id][
|
||||
interval_line
|
||||
]
|
||||
if show_move_line_details:
|
||||
move_lines = []
|
||||
for ml in ag_pb_data[acc_id][prt_id]["move_lines"]:
|
||||
ml.update(
|
||||
{
|
||||
"journal": journals_data[ml["jnl_id"]]["code"],
|
||||
"account": accounts_data[ml["acc_id"]]["code"],
|
||||
}
|
||||
)
|
||||
self._compute_maturity_date(ml, date_at_oject)
|
||||
move_lines.append(ml)
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
partner.update({"move_lines": move_lines})
|
||||
account["partners"].append(partner)
|
||||
aged_partner_data.append(account)
|
||||
return aged_partner_data
|
||||
|
||||
@api.model
|
||||
def _calculate_percent(self, aged_partner_data):
|
||||
interval_lines = self.env.context["age_partner_config"].line_ids
|
||||
for account in aged_partner_data:
|
||||
if abs(account["residual"]) > 0.01:
|
||||
total = account["residual"]
|
||||
account.update(
|
||||
{
|
||||
"percent_current": abs(
|
||||
round((account["current"] / total) * 100, 2)
|
||||
),
|
||||
"percent_30_days": abs(
|
||||
round((account["30_days"] / total) * 100, 2)
|
||||
),
|
||||
"percent_60_days": abs(
|
||||
round((account["60_days"] / total) * 100, 2)
|
||||
),
|
||||
"percent_90_days": abs(
|
||||
round((account["90_days"] / total) * 100, 2)
|
||||
),
|
||||
"percent_120_days": abs(
|
||||
round((account["120_days"] / total) * 100, 2)
|
||||
),
|
||||
"percent_older": abs(
|
||||
round((account["older"] / total) * 100, 2)
|
||||
),
|
||||
}
|
||||
)
|
||||
for interval_line in interval_lines:
|
||||
account[f"percent_{interval_line.id}"] = abs(
|
||||
round((account[interval_line] / total) * 100, 2)
|
||||
)
|
||||
else:
|
||||
account.update(
|
||||
{
|
||||
"percent_current": 0.0,
|
||||
"percent_30_days": 0.0,
|
||||
"percent_60_days": 0.0,
|
||||
"percent_90_days": 0.0,
|
||||
"percent_120_days": 0.0,
|
||||
"percent_older": 0.0,
|
||||
}
|
||||
)
|
||||
for interval_line in interval_lines:
|
||||
account[f"percent_{interval_line.id}"] = 0.0
|
||||
return aged_partner_data
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
wizard_id = data["wizard_id"]
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
company_id = data["company_id"]
|
||||
account_ids = data["account_ids"]
|
||||
partner_ids = data["partner_ids"]
|
||||
date_at = data["date_at"]
|
||||
date_at_object = datetime.strptime(date_at, "%Y-%m-%d").date()
|
||||
date_from = data["date_from"]
|
||||
only_posted_moves = data["only_posted_moves"]
|
||||
show_move_line_details = data["show_move_line_details"]
|
||||
aged_partner_configuration = self.env[
|
||||
"account.age.report.configuration"
|
||||
].browse(data["age_partner_config_id"])
|
||||
(
|
||||
ag_pb_data,
|
||||
accounts_data,
|
||||
partners_data,
|
||||
journals_data,
|
||||
) = self.with_context(
|
||||
age_partner_config=aged_partner_configuration
|
||||
)._get_move_lines_data(
|
||||
company_id,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
date_at_object,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_move_line_details,
|
||||
)
|
||||
aged_partner_data = self.with_context(
|
||||
age_partner_config=aged_partner_configuration
|
||||
)._create_account_list(
|
||||
ag_pb_data,
|
||||
accounts_data,
|
||||
partners_data,
|
||||
journals_data,
|
||||
show_move_line_details,
|
||||
date_at_object,
|
||||
)
|
||||
aged_partner_data = self.with_context(
|
||||
age_partner_config=aged_partner_configuration
|
||||
)._calculate_percent(aged_partner_data)
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "aged.partner.balance.report.wizard",
|
||||
"docs": self.env["aged.partner.balance.report.wizard"].browse(wizard_id),
|
||||
"company_name": company.display_name,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_at": date_at,
|
||||
"only_posted_moves": only_posted_moves,
|
||||
"aged_partner_balance": aged_partner_data,
|
||||
"show_move_lines_details": show_move_line_details,
|
||||
"age_partner_config": aged_partner_configuration,
|
||||
}
|
||||
|
||||
def _get_ml_fields(self):
|
||||
return self.COMMON_ML_FIELDS + [
|
||||
"amount_residual",
|
||||
"reconciled",
|
||||
"date_maturity",
|
||||
]
|
||||
367
account_financial_report/report/aged_partner_balance_xlsx.py
Normal file
367
account_financial_report/report/aged_partner_balance_xlsx.py
Normal file
@@ -0,0 +1,367 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class AgedPartnerBalanceXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_aged_partner_balance_xlsx"
|
||||
_description = "Aged Partner Balance XLSL Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = self.env._("Aged Partner Balance")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns_without_move_line_details(self, report, column_index):
|
||||
report_columns = {
|
||||
0: {"header": self.env._("Partner"), "field": "name", "width": 70},
|
||||
1: {
|
||||
"header": self.env._("Residual"),
|
||||
"field": "residual",
|
||||
"field_footer_total": "residual",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
2: {
|
||||
"header": self.env._("Current"),
|
||||
"field": "current",
|
||||
"field_footer_total": "current",
|
||||
"field_footer_percent": "percent_current",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
if not report.age_partner_config_id:
|
||||
report_columns.update(
|
||||
{
|
||||
3: {
|
||||
"header": self.env._("Age ≤ 30 d."),
|
||||
"field": "30_days",
|
||||
"field_footer_total": "30_days",
|
||||
"field_footer_percent": "percent_30_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
4: {
|
||||
"header": self.env._("Age ≤ 60 d."),
|
||||
"field": "60_days",
|
||||
"field_footer_total": "60_days",
|
||||
"field_footer_percent": "percent_60_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
5: {
|
||||
"header": self.env._("Age ≤ 90 d."),
|
||||
"field": "90_days",
|
||||
"field_footer_total": "90_days",
|
||||
"field_footer_percent": "percent_90_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
6: {
|
||||
"header": self.env._("Age ≤ 120 d."),
|
||||
"field": "120_days",
|
||||
"field_footer_total": "120_days",
|
||||
"field_footer_percent": "percent_120_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
7: {
|
||||
"header": self.env._("Older"),
|
||||
"field": "older",
|
||||
"field_footer_total": "older",
|
||||
"field_footer_percent": "percent_older",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
)
|
||||
for interval in report.age_partner_config_id.line_ids:
|
||||
report_columns[column_index] = {
|
||||
"header": interval.name,
|
||||
"field": interval,
|
||||
"field_footer_total": interval,
|
||||
"field_footer_percent": f"percent_{interval.id}",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
}
|
||||
column_index += 1
|
||||
return report_columns
|
||||
|
||||
def _get_report_columns_with_move_line_details(self, report, column_index):
|
||||
report_columns = {
|
||||
0: {"header": self.env._("Date"), "field": "date", "width": 11},
|
||||
1: {"header": self.env._("Entry"), "field": "entry", "width": 18},
|
||||
2: {"header": self.env._("Journal"), "field": "journal", "width": 8},
|
||||
3: {"header": self.env._("Account"), "field": "account", "width": 9},
|
||||
4: {"header": self.env._("Partner"), "field": "partner", "width": 25},
|
||||
5: {"header": self.env._("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
6: {"header": self.env._("Due date"), "field": "due_date", "width": 11},
|
||||
7: {
|
||||
"header": self.env._("Residual"),
|
||||
"field": "residual",
|
||||
"field_footer_total": "residual",
|
||||
"field_final_balance": "residual",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
8: {
|
||||
"header": self.env._("Current"),
|
||||
"field": "current",
|
||||
"field_footer_total": "current",
|
||||
"field_footer_percent": "percent_current",
|
||||
"field_final_balance": "current",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
if not report.age_partner_config_id:
|
||||
report_columns.update(
|
||||
{
|
||||
9: {
|
||||
"header": self.env._("Age ≤ 30 d."),
|
||||
"field": "30_days",
|
||||
"field_footer_total": "30_days",
|
||||
"field_footer_percent": "percent_30_days",
|
||||
"field_final_balance": "30_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
10: {
|
||||
"header": self.env._("Age ≤ 60 d."),
|
||||
"field": "60_days",
|
||||
"field_footer_total": "60_days",
|
||||
"field_footer_percent": "percent_60_days",
|
||||
"field_final_balance": "60_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
11: {
|
||||
"header": self.env._("Age ≤ 90 d."),
|
||||
"field": "90_days",
|
||||
"field_footer_total": "90_days",
|
||||
"field_footer_percent": "percent_90_days",
|
||||
"field_final_balance": "90_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
12: {
|
||||
"header": self.env._("Age ≤ 120 d."),
|
||||
"field": "120_days",
|
||||
"field_footer_total": "120_days",
|
||||
"field_footer_percent": "percent_120_days",
|
||||
"field_final_balance": "120_days",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
13: {
|
||||
"header": self.env._("Older"),
|
||||
"field": "older",
|
||||
"field_footer_total": "older",
|
||||
"field_footer_percent": "percent_older",
|
||||
"field_final_balance": "older",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
)
|
||||
for interval in report.age_partner_config_id.line_ids:
|
||||
report_columns[column_index] = {
|
||||
"header": interval.name,
|
||||
"field": interval,
|
||||
"field_footer_total": interval,
|
||||
"field_footer_percent": f"percent_{interval.id}",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
}
|
||||
column_index += 1
|
||||
return report_columns
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
if not report.show_move_line_details:
|
||||
return self._get_report_columns_without_move_line_details(
|
||||
report, column_index=3
|
||||
)
|
||||
return self._get_report_columns_with_move_line_details(report, column_index=9)
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[self.env._("Date at filter"), report.date_at.strftime("%d/%m/%Y")],
|
||||
[
|
||||
self.env._("Target moves filter"),
|
||||
self.env._("All posted entries")
|
||||
if report.target_move == "posted"
|
||||
else self.env._("All entries"),
|
||||
],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 3
|
||||
|
||||
def _get_col_pos_footer_label(self, report):
|
||||
return 0 if not report.show_move_line_details else 5
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.aged_partner_balance"
|
||||
]._get_report_values(report, data)
|
||||
show_move_line_details = res_data["show_move_lines_details"]
|
||||
aged_partner_balance = res_data["aged_partner_balance"]
|
||||
if not show_move_line_details:
|
||||
# For each account
|
||||
for account in aged_partner_balance:
|
||||
# Write account title
|
||||
self.write_array_title(
|
||||
account["code"] + " - " + account["name"], report_data
|
||||
)
|
||||
|
||||
# Display array header for partners lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# Display partner lines
|
||||
for partner in account["partners"]:
|
||||
self.write_line_from_dict(partner, report_data)
|
||||
|
||||
# Display account lines
|
||||
self.write_account_footer_from_dict(
|
||||
report,
|
||||
account,
|
||||
("Total"),
|
||||
"field_footer_total",
|
||||
report_data["formats"]["format_header_right"],
|
||||
report_data["formats"]["format_header_amount"],
|
||||
False,
|
||||
report_data,
|
||||
)
|
||||
self.write_account_footer_from_dict(
|
||||
report,
|
||||
account,
|
||||
("Percents"),
|
||||
"field_footer_percent",
|
||||
report_data["formats"]["format_right_bold_italic"],
|
||||
report_data["formats"]["format_percent_bold_italic"],
|
||||
True,
|
||||
report_data,
|
||||
)
|
||||
|
||||
# 2 lines break
|
||||
report_data["row_pos"] += 2
|
||||
else:
|
||||
# For each account
|
||||
for account in aged_partner_balance:
|
||||
# Write account title
|
||||
self.write_array_title(
|
||||
account["code"] + " - " + account["name"], report_data
|
||||
)
|
||||
|
||||
# For each partner
|
||||
for partner in account["partners"]:
|
||||
# Write partner title
|
||||
self.write_array_title(partner["name"], report_data)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# Display account move lines
|
||||
for line in partner["move_lines"]:
|
||||
self.write_line_from_dict(line, report_data)
|
||||
|
||||
# Display ending balance line for partner
|
||||
self.write_ending_balance_from_dict(partner, report_data)
|
||||
|
||||
# Line break
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
# Display account lines
|
||||
self.write_account_footer_from_dict(
|
||||
report,
|
||||
account,
|
||||
("Total"),
|
||||
"field_footer_total",
|
||||
report_data["formats"]["format_header_right"],
|
||||
report_data["formats"]["format_header_amount"],
|
||||
False,
|
||||
report_data,
|
||||
)
|
||||
|
||||
self.write_account_footer_from_dict(
|
||||
report,
|
||||
account,
|
||||
("Percents"),
|
||||
"field_footer_percent",
|
||||
report_data["formats"]["format_right_bold_italic"],
|
||||
report_data["formats"]["format_percent_bold_italic"],
|
||||
True,
|
||||
report_data,
|
||||
)
|
||||
|
||||
# 2 lines break
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def write_ending_balance_from_dict(self, my_object, report_data):
|
||||
"""
|
||||
Specific function to write ending partner balance
|
||||
for Aged Partner Balance
|
||||
"""
|
||||
name = None
|
||||
label = self.env._("Partner cumul aged balance")
|
||||
return super().write_ending_balance_from_dict(
|
||||
my_object, name, label, report_data
|
||||
)
|
||||
|
||||
def write_account_footer_from_dict(
|
||||
self,
|
||||
report,
|
||||
account,
|
||||
label,
|
||||
field_name,
|
||||
string_format,
|
||||
amount_format,
|
||||
amount_is_percent,
|
||||
report_data,
|
||||
):
|
||||
"""
|
||||
Specific function to write account footer for Aged Partner Balance
|
||||
"""
|
||||
col_pos_footer_label = self._get_col_pos_footer_label(report)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if col_pos == col_pos_footer_label or column.get(field_name):
|
||||
if col_pos == col_pos_footer_label:
|
||||
value = label
|
||||
else:
|
||||
value = account.get(column[field_name], False)
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string" or col_pos == col_pos_footer_label:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, value or "", string_format
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
number = float(value)
|
||||
if amount_is_percent:
|
||||
number /= 100
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, number, amount_format
|
||||
)
|
||||
else:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"], col_pos, "", string_format
|
||||
)
|
||||
|
||||
report_data["row_pos"] += 1
|
||||
944
account_financial_report/report/general_ledger.py
Normal file
944
account_financial_report/report/general_ledger.py
Normal file
@@ -0,0 +1,944 @@
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# Copyright 2022 Tecnativa - V??ctor Mart??nez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import calendar
|
||||
import datetime
|
||||
import operator
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
class GeneralLedgerReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.general_ledger"
|
||||
_description = "General Ledger Report"
|
||||
_inherit = "report.account_financial_report.abstract_report"
|
||||
|
||||
def _get_analytic_data(self, account_ids):
|
||||
analytic_accounts = self.env["account.analytic.account"].search_fetch(
|
||||
[("id", "in", account_ids)], ["name"]
|
||||
)
|
||||
analytic_data = {}
|
||||
for account in analytic_accounts:
|
||||
analytic_data.update({account.id: {"name": account.name}})
|
||||
return analytic_data
|
||||
|
||||
def _get_taxes_data(self, taxes_ids):
|
||||
taxes = self.env["account.tax"].search_fetch(
|
||||
[("id", "in", taxes_ids)], ["amount", "amount_type", "display_name"]
|
||||
)
|
||||
taxes_data = {}
|
||||
for tax in taxes:
|
||||
taxes_data.update(
|
||||
{
|
||||
tax.id: {
|
||||
"id": tax.id,
|
||||
"amount": tax.amount,
|
||||
"amount_type": tax.amount_type,
|
||||
"display_name": tax.display_name,
|
||||
}
|
||||
}
|
||||
)
|
||||
if tax.amount_type == "percent" or tax.amount_type == "division":
|
||||
taxes_data[tax.id]["string"] = "%"
|
||||
else:
|
||||
taxes_data[tax.id]["string"] = ""
|
||||
taxes_data[tax.id]["tax_name"] = (
|
||||
tax.display_name
|
||||
+ " ("
|
||||
+ str(tax.amount)
|
||||
+ taxes_data[tax.id]["string"]
|
||||
+ ")"
|
||||
)
|
||||
return taxes_data
|
||||
|
||||
def _get_account_type_domain(self, grouped_by):
|
||||
"""To avoid set all possible types, set in or not in as operator of the types
|
||||
we are interested in. In v15 we used the internal_type field (type of
|
||||
account.account.type)."""
|
||||
at_op = "in" if grouped_by != "taxes" else "not in"
|
||||
return [
|
||||
("account_type", at_op, ["asset_receivable", "liability_payable"]),
|
||||
]
|
||||
|
||||
def _get_acc_prt_accounts_ids(self, company_id, grouped_by):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
] + self._get_account_type_domain(grouped_by)
|
||||
acc_prt_accounts = self.env["account.account"].search(accounts_domain)
|
||||
return acc_prt_accounts.ids
|
||||
|
||||
def _get_initial_balances_bs_ml_domain(
|
||||
self, account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=False
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", True),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = []
|
||||
domain += base_domain
|
||||
domain += [("date", "<", date_from)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
if acc_prt:
|
||||
domain += self._get_account_type_domain(grouped_by)
|
||||
return domain
|
||||
|
||||
def _get_initial_balances_pl_ml_domain(
|
||||
self, account_ids, company_id, date_from, fy_start_date, base_domain
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", False),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = []
|
||||
domain += base_domain
|
||||
domain += [("date", "<", date_from), ("date", ">=", fy_start_date)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
return domain
|
||||
|
||||
def _get_accounts_initial_balance(self, initial_domain_bs, initial_domain_pl):
|
||||
gl_initial_acc_bs = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_bs,
|
||||
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id"],
|
||||
)
|
||||
gl_initial_acc_pl = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_pl,
|
||||
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id"],
|
||||
)
|
||||
gl_initial_acc = gl_initial_acc_bs + gl_initial_acc_pl
|
||||
return gl_initial_acc
|
||||
|
||||
def _get_initial_balance_fy_pl_ml_domain(
|
||||
self, account_ids, company_id, fy_start_date, base_domain
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", False),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = []
|
||||
domain += base_domain
|
||||
domain += [("date", "<", fy_start_date)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
return domain
|
||||
|
||||
def _get_pl_initial_balance(
|
||||
self, account_ids, company_id, fy_start_date, foreign_currency, base_domain
|
||||
):
|
||||
domain = self._get_initial_balance_fy_pl_ml_domain(
|
||||
account_ids, company_id, fy_start_date, base_domain
|
||||
)
|
||||
initial_balances = self.env["account.move.line"].read_group(
|
||||
domain=domain,
|
||||
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id"],
|
||||
)
|
||||
pl_initial_balance = {
|
||||
"debit": 0.0,
|
||||
"credit": 0.0,
|
||||
"balance": 0.0,
|
||||
"bal_curr": 0.0,
|
||||
}
|
||||
for initial_balance in initial_balances:
|
||||
pl_initial_balance["debit"] += initial_balance["debit"]
|
||||
pl_initial_balance["credit"] += initial_balance["credit"]
|
||||
pl_initial_balance["balance"] += initial_balance["balance"]
|
||||
pl_initial_balance["bal_curr"] += initial_balance["amount_currency"]
|
||||
return pl_initial_balance
|
||||
|
||||
def _get_gl_initial_acc(
|
||||
self,
|
||||
account_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
fy_start_date,
|
||||
base_domain,
|
||||
grouped_by,
|
||||
):
|
||||
initial_domain_bs = self._get_initial_balances_bs_ml_domain(
|
||||
account_ids, company_id, date_from, base_domain, grouped_by
|
||||
)
|
||||
initial_domain_pl = self._get_initial_balances_pl_ml_domain(
|
||||
account_ids, company_id, date_from, fy_start_date, base_domain
|
||||
)
|
||||
return self._get_accounts_initial_balance(initial_domain_bs, initial_domain_pl)
|
||||
|
||||
def _prepare_gen_ld_data_item(self, gl):
|
||||
res = {}
|
||||
for key_bal in ["init_bal", "fin_bal"]:
|
||||
res[key_bal] = {}
|
||||
for key_field in ["credit", "debit", "balance", "bal_curr"]:
|
||||
field_name = key_field if key_field != "bal_curr" else "amount_currency"
|
||||
res[key_bal][key_field] = gl[field_name]
|
||||
return res
|
||||
|
||||
def _prepare_gen_ld_data(self, gl_initial_acc, domain, grouped_by):
|
||||
data = {}
|
||||
for gl in gl_initial_acc:
|
||||
acc_id = gl["account_id"][0]
|
||||
data[acc_id] = self._prepare_gen_ld_data_item(gl)
|
||||
data[acc_id]["id"] = acc_id
|
||||
if grouped_by:
|
||||
data[acc_id][grouped_by] = False
|
||||
method = f"_prepare_gen_ld_data_group_{grouped_by}"
|
||||
if not hasattr(self, method):
|
||||
return data
|
||||
return getattr(self, method)(data, domain, grouped_by)
|
||||
|
||||
def _prepare_gen_ld_data_group_partners(self, data, domain, grouped_by):
|
||||
gl_initial_acc_prt = self.env["account.move.line"].read_group(
|
||||
domain=domain,
|
||||
fields=[
|
||||
"account_id",
|
||||
"partner_id",
|
||||
"debit",
|
||||
"credit",
|
||||
"balance",
|
||||
"amount_currency:sum",
|
||||
],
|
||||
groupby=["account_id", "partner_id"],
|
||||
lazy=False,
|
||||
)
|
||||
if gl_initial_acc_prt:
|
||||
for gl in gl_initial_acc_prt:
|
||||
if not gl["partner_id"]:
|
||||
prt_id = 0
|
||||
prt_name = _("Missing Partner")
|
||||
else:
|
||||
prt_id = gl["partner_id"][0]
|
||||
prt_name = gl["partner_id"][1]
|
||||
acc_id = gl["account_id"][0]
|
||||
data[acc_id][prt_id] = self._prepare_gen_ld_data_item(gl)
|
||||
data[acc_id][prt_id]["id"] = prt_id
|
||||
data[acc_id][prt_id]["name"] = prt_name
|
||||
data[acc_id][grouped_by] = True
|
||||
return data
|
||||
|
||||
def _prepare_gen_ld_data_group_taxes(self, data, domain, grouped_by):
|
||||
gl_initial_acc_prt = self.env["account.move.line"].read_group(
|
||||
domain=domain,
|
||||
fields=[
|
||||
"account_id",
|
||||
"debit",
|
||||
"credit",
|
||||
"balance",
|
||||
"amount_currency:sum",
|
||||
"tax_line_id",
|
||||
],
|
||||
groupby=["account_id"],
|
||||
lazy=False,
|
||||
)
|
||||
if gl_initial_acc_prt:
|
||||
for gl in gl_initial_acc_prt:
|
||||
if "tax_line_id" in gl and gl["tax_line_id"]:
|
||||
tax_id = gl["tax_line_id"][0]
|
||||
tax_name = gl["tax_line_id"][1]
|
||||
else:
|
||||
tax_id = 0
|
||||
tax_name = "Missing Tax"
|
||||
acc_id = gl["account_id"][0]
|
||||
data[acc_id][tax_id] = self._prepare_gen_ld_data_item(gl)
|
||||
data[acc_id][tax_id]["id"] = tax_id
|
||||
data[acc_id][tax_id]["name"] = tax_name
|
||||
data[acc_id][grouped_by] = True
|
||||
return data
|
||||
|
||||
def _get_initial_balance_data(
|
||||
self,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
unaffected_earnings_account,
|
||||
fy_start_date,
|
||||
cost_center_ids,
|
||||
extra_domain,
|
||||
grouped_by,
|
||||
):
|
||||
# If explicit list of accounts is provided,
|
||||
# don't include unaffected earnings account
|
||||
if account_ids:
|
||||
unaffected_earnings_account = False
|
||||
base_domain = []
|
||||
if company_id:
|
||||
base_domain += [("company_id", "in", [company_id])]
|
||||
if partner_ids:
|
||||
base_domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
base_domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
base_domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if cost_center_ids:
|
||||
base_domain += [("analytic_account_ids", "in", cost_center_ids)]
|
||||
if extra_domain:
|
||||
base_domain += extra_domain
|
||||
gl_initial_acc = self._get_gl_initial_acc(
|
||||
account_ids, company_id, date_from, fy_start_date, base_domain, grouped_by
|
||||
)
|
||||
domain = self._get_initial_balances_bs_ml_domain(
|
||||
account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=True
|
||||
)
|
||||
data = self._prepare_gen_ld_data(gl_initial_acc, domain, grouped_by)
|
||||
accounts_ids = list(data.keys())
|
||||
unaffected_id = unaffected_earnings_account
|
||||
if unaffected_id:
|
||||
if unaffected_id not in accounts_ids:
|
||||
accounts_ids.append(unaffected_id)
|
||||
data[unaffected_id] = self._initialize_data(foreign_currency)
|
||||
data[unaffected_id]["id"] = unaffected_id
|
||||
data[unaffected_id]["mame"] = ""
|
||||
data[unaffected_id][grouped_by] = False
|
||||
pl_initial_balance = self._get_pl_initial_balance(
|
||||
account_ids, company_id, fy_start_date, foreign_currency, base_domain
|
||||
)
|
||||
for key_bal in ["init_bal", "fin_bal"]:
|
||||
fields_balance = ["credit", "debit", "balance"]
|
||||
if foreign_currency:
|
||||
fields_balance.append("bal_curr")
|
||||
for field_name in fields_balance:
|
||||
data[unaffected_id][key_bal][field_name] += pl_initial_balance[
|
||||
field_name
|
||||
]
|
||||
return data
|
||||
|
||||
@api.model
|
||||
def _get_move_line_data(self, move_line):
|
||||
move_line_data = {
|
||||
"id": move_line["id"],
|
||||
"date": move_line["date"],
|
||||
"entry": move_line["move_name"],
|
||||
"entry_id": move_line["move_id"][0],
|
||||
"journal_id": move_line["journal_id"][0],
|
||||
"account_id": move_line["account_id"][0],
|
||||
"partner_id": move_line["partner_id"][0]
|
||||
if move_line["partner_id"]
|
||||
else False,
|
||||
"partner_name": move_line["partner_id"][1]
|
||||
if move_line["partner_id"]
|
||||
else "",
|
||||
"ref": "" if not move_line["ref"] else move_line["ref"],
|
||||
"name": "" if not move_line["name"] else move_line["name"],
|
||||
"tax_ids": move_line["tax_ids"],
|
||||
"tax_line_id": move_line["tax_line_id"],
|
||||
"debit": move_line["debit"],
|
||||
"credit": move_line["credit"],
|
||||
"balance": move_line["balance"],
|
||||
"bal_curr": move_line["amount_currency"],
|
||||
"rec_id": move_line["full_reconcile_id"][0]
|
||||
if move_line["full_reconcile_id"]
|
||||
else False,
|
||||
"rec_name": move_line["full_reconcile_id"][1]
|
||||
if move_line["full_reconcile_id"]
|
||||
else "",
|
||||
"currency_id": move_line["currency_id"],
|
||||
"analytic_distribution": move_line["analytic_distribution"] or {},
|
||||
}
|
||||
if (
|
||||
move_line_data["ref"] == move_line_data["name"]
|
||||
or move_line_data["ref"] == ""
|
||||
):
|
||||
ref_label = move_line_data["name"]
|
||||
elif move_line_data["name"] == "":
|
||||
ref_label = move_line_data["ref"]
|
||||
else:
|
||||
ref_label = move_line_data["ref"] + " - " + move_line_data["name"]
|
||||
move_line_data.update({"ref_label": ref_label})
|
||||
return move_line_data
|
||||
|
||||
@api.model
|
||||
def _get_period_domain(
|
||||
self,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
only_posted_moves,
|
||||
date_to,
|
||||
date_from,
|
||||
cost_center_ids,
|
||||
):
|
||||
domain = [
|
||||
("display_type", "not in", ["line_note", "line_section"]),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
]
|
||||
if account_ids:
|
||||
domain += [("account_id", "in", account_ids)]
|
||||
if company_id:
|
||||
domain += [("company_id", "=", company_id)]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
|
||||
if cost_center_ids:
|
||||
domain += [("analytic_account_ids", "in", cost_center_ids)]
|
||||
return domain
|
||||
|
||||
def _initialize_data(self, foreign_currency):
|
||||
res = {}
|
||||
for key_bal in ["init_bal", "fin_bal"]:
|
||||
res[key_bal] = {}
|
||||
for key_field in ["balance", "credit", "debit"]:
|
||||
res[key_bal][key_field] = 0.0
|
||||
if foreign_currency:
|
||||
res[key_bal]["bal_curr"] = 0.0
|
||||
return res
|
||||
|
||||
def _get_reconciled_after_date_to_ids(self, full_reconcile_ids, date_to):
|
||||
full_reconcile_ids = list(full_reconcile_ids)
|
||||
domain = [
|
||||
("max_date", ">", date_to),
|
||||
("full_reconcile_id", "in", full_reconcile_ids),
|
||||
]
|
||||
fields = ["full_reconcile_id"]
|
||||
reconciled_after_date_to = self.env["account.partial.reconcile"].search_read(
|
||||
domain=domain, fields=fields
|
||||
)
|
||||
rec_after_date_to_ids = list(
|
||||
map(operator.itemgetter("full_reconcile_id"), reconciled_after_date_to)
|
||||
)
|
||||
rec_after_date_to_ids = [i[0] for i in rec_after_date_to_ids]
|
||||
return rec_after_date_to_ids
|
||||
|
||||
def _prepare_ml_items(self, move_line, grouped_by):
|
||||
res = []
|
||||
if grouped_by == "partners":
|
||||
item_id = move_line["partner_id"][0] if move_line["partner_id"] else 0
|
||||
item_name = (
|
||||
move_line["partner_id"][1]
|
||||
if move_line["partner_id"]
|
||||
else _("Missing Partner")
|
||||
)
|
||||
res.append({"id": item_id, "name": item_name})
|
||||
elif grouped_by == "taxes":
|
||||
if move_line["tax_line_id"]:
|
||||
item_id = move_line["tax_line_id"][0]
|
||||
item_name = move_line["tax_line_id"][1]
|
||||
res.append({"id": item_id, "name": item_name})
|
||||
elif move_line["tax_ids"]:
|
||||
for tax_id in move_line["tax_ids"]:
|
||||
tax_item = self.env["account.tax"].search_fetch(
|
||||
[("id", "=", tax_id)], ["name"]
|
||||
)
|
||||
res.append({"id": tax_item.id, "name": tax_item.name})
|
||||
else:
|
||||
res.append({"id": 0, "name": "Missing Tax"})
|
||||
else:
|
||||
res.append({"id": 0, "name": ""})
|
||||
return res
|
||||
|
||||
def _get_period_ml_data(
|
||||
self,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
date_from,
|
||||
date_to,
|
||||
gen_ld_data,
|
||||
cost_center_ids,
|
||||
extra_domain,
|
||||
grouped_by,
|
||||
):
|
||||
domain = self._get_period_domain(
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
only_posted_moves,
|
||||
date_to,
|
||||
date_from,
|
||||
cost_center_ids,
|
||||
)
|
||||
if extra_domain:
|
||||
domain += extra_domain
|
||||
ml_fields = self._get_ml_fields()
|
||||
move_lines = self.env["account.move.line"].search_read(
|
||||
domain=domain, fields=ml_fields, order="date,move_name"
|
||||
)
|
||||
journal_ids = set()
|
||||
full_reconcile_ids = set()
|
||||
taxes_ids = set()
|
||||
analytic_ids = set()
|
||||
full_reconcile_data = {}
|
||||
acc_prt_account_ids = self._get_acc_prt_accounts_ids(company_id, grouped_by)
|
||||
for move_line in move_lines:
|
||||
journal_ids.add(move_line["journal_id"][0])
|
||||
for tax_id in move_line["tax_ids"]:
|
||||
taxes_ids.add(tax_id)
|
||||
for analytic_account in move_line["analytic_distribution"] or {}:
|
||||
analytic_ids.add(int(analytic_account))
|
||||
if move_line["full_reconcile_id"]:
|
||||
rec_id = move_line["full_reconcile_id"][0]
|
||||
if rec_id not in full_reconcile_ids:
|
||||
full_reconcile_data.update(
|
||||
{
|
||||
rec_id: {
|
||||
"id": rec_id,
|
||||
"name": move_line["full_reconcile_id"][1],
|
||||
}
|
||||
}
|
||||
)
|
||||
full_reconcile_ids.add(rec_id)
|
||||
acc_id = move_line["account_id"][0]
|
||||
ml_id = move_line["id"]
|
||||
if acc_id not in gen_ld_data.keys():
|
||||
gen_ld_data[acc_id] = self._initialize_data(foreign_currency)
|
||||
gen_ld_data[acc_id]["id"] = acc_id
|
||||
gen_ld_data[acc_id]["mame"] = move_line["account_id"][1]
|
||||
if grouped_by:
|
||||
gen_ld_data[acc_id][grouped_by] = False
|
||||
if acc_id in acc_prt_account_ids:
|
||||
item_ids = self._prepare_ml_items(move_line, grouped_by)
|
||||
for item in item_ids:
|
||||
item_id = item["id"]
|
||||
if item_id not in gen_ld_data[acc_id]:
|
||||
if grouped_by:
|
||||
gen_ld_data[acc_id][grouped_by] = True
|
||||
gen_ld_data[acc_id][item_id] = self._initialize_data(
|
||||
foreign_currency
|
||||
)
|
||||
gen_ld_data[acc_id][item_id]["id"] = item_id
|
||||
gen_ld_data[acc_id][item_id]["name"] = item["name"]
|
||||
gen_ld_data[acc_id][item_id][ml_id] = self._get_move_line_data(
|
||||
move_line
|
||||
)
|
||||
gen_ld_data[acc_id][item_id]["fin_bal"]["credit"] += move_line[
|
||||
"credit"
|
||||
]
|
||||
gen_ld_data[acc_id][item_id]["fin_bal"]["debit"] += move_line[
|
||||
"debit"
|
||||
]
|
||||
gen_ld_data[acc_id][item_id]["fin_bal"]["balance"] += move_line[
|
||||
"balance"
|
||||
]
|
||||
if foreign_currency:
|
||||
gen_ld_data[acc_id][item_id]["fin_bal"]["bal_curr"] += (
|
||||
move_line["amount_currency"]
|
||||
)
|
||||
else:
|
||||
gen_ld_data[acc_id][ml_id] = self._get_move_line_data(move_line)
|
||||
gen_ld_data[acc_id]["fin_bal"]["credit"] += move_line["credit"]
|
||||
gen_ld_data[acc_id]["fin_bal"]["debit"] += move_line["debit"]
|
||||
gen_ld_data[acc_id]["fin_bal"]["balance"] += move_line["balance"]
|
||||
if foreign_currency:
|
||||
gen_ld_data[acc_id]["fin_bal"]["bal_curr"] += move_line[
|
||||
"amount_currency"
|
||||
]
|
||||
journals_data = self._get_journals_data(list(journal_ids))
|
||||
accounts_data = self._get_accounts_data(gen_ld_data.keys())
|
||||
taxes_data = self._get_taxes_data(list(taxes_ids))
|
||||
analytic_data = self._get_analytic_data(list(analytic_ids))
|
||||
rec_after_date_to_ids = self._get_reconciled_after_date_to_ids(
|
||||
full_reconcile_data.keys(), date_to
|
||||
)
|
||||
return (
|
||||
gen_ld_data,
|
||||
accounts_data,
|
||||
journals_data,
|
||||
full_reconcile_data,
|
||||
taxes_data,
|
||||
analytic_data,
|
||||
rec_after_date_to_ids,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _recalculate_cumul_balance(
|
||||
self, move_lines, last_cumul_balance, rec_after_date_to_ids
|
||||
):
|
||||
for move_line in move_lines:
|
||||
move_line["balance"] += last_cumul_balance
|
||||
last_cumul_balance = move_line["balance"]
|
||||
if move_line["rec_id"] in rec_after_date_to_ids:
|
||||
move_line["rec_name"] = "(" + _("future") + ") " + move_line["rec_name"]
|
||||
return move_lines
|
||||
|
||||
def _create_account(self, account, acc_id, gen_led_data, rec_after_date_to_ids):
|
||||
move_lines = []
|
||||
for ml_id in gen_led_data[acc_id].keys():
|
||||
if not isinstance(ml_id, int):
|
||||
account.update({ml_id: gen_led_data[acc_id][ml_id]})
|
||||
else:
|
||||
move_lines += [gen_led_data[acc_id][ml_id]]
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
move_lines = self._recalculate_cumul_balance(
|
||||
move_lines,
|
||||
gen_led_data[acc_id]["init_bal"]["balance"],
|
||||
rec_after_date_to_ids,
|
||||
)
|
||||
account.update({"move_lines": move_lines})
|
||||
return account
|
||||
|
||||
def _create_account_not_show_item(
|
||||
self, account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by
|
||||
):
|
||||
move_lines = []
|
||||
for prt_id in gen_led_data[acc_id].keys():
|
||||
if not isinstance(prt_id, int):
|
||||
account.update({prt_id: gen_led_data[acc_id][prt_id]})
|
||||
elif isinstance(gen_led_data[acc_id][prt_id], dict):
|
||||
for ml_id in gen_led_data[acc_id][prt_id].keys():
|
||||
if isinstance(ml_id, int):
|
||||
move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
move_lines = self._recalculate_cumul_balance(
|
||||
move_lines,
|
||||
gen_led_data[acc_id]["init_bal"]["balance"],
|
||||
rec_after_date_to_ids,
|
||||
)
|
||||
account.update({"move_lines": move_lines, grouped_by: False})
|
||||
return account
|
||||
|
||||
def _get_list_grouped_item(
|
||||
self, data, account, rec_after_date_to_ids, hide_account_at_0, rounding
|
||||
):
|
||||
list_grouped = []
|
||||
for data_id in data.keys():
|
||||
group_item = {}
|
||||
move_lines = []
|
||||
if not isinstance(data_id, int):
|
||||
account.update({data_id: data[data_id]})
|
||||
else:
|
||||
for ml_id in data[data_id].keys():
|
||||
if not isinstance(ml_id, int):
|
||||
group_item.update({ml_id: data[data_id][ml_id]})
|
||||
else:
|
||||
move_lines += [data[data_id][ml_id]]
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
move_lines = self._recalculate_cumul_balance(
|
||||
move_lines,
|
||||
data[data_id]["init_bal"]["balance"],
|
||||
rec_after_date_to_ids,
|
||||
)
|
||||
group_item.update({"move_lines": move_lines})
|
||||
if (
|
||||
hide_account_at_0
|
||||
and float_is_zero(
|
||||
data[data_id]["init_bal"]["balance"],
|
||||
precision_rounding=rounding,
|
||||
)
|
||||
and group_item["move_lines"] == []
|
||||
):
|
||||
continue
|
||||
list_grouped += [group_item]
|
||||
return account, list_grouped
|
||||
|
||||
def _create_general_ledger(
|
||||
self,
|
||||
gen_led_data,
|
||||
accounts_data,
|
||||
grouped_by,
|
||||
rec_after_date_to_ids,
|
||||
hide_account_at_0,
|
||||
):
|
||||
general_ledger = []
|
||||
rounding = self.env.company.currency_id.rounding
|
||||
for acc_id in gen_led_data.keys():
|
||||
account = {}
|
||||
account.update(
|
||||
{
|
||||
"code": accounts_data[acc_id]["code"],
|
||||
"name": accounts_data[acc_id]["name"],
|
||||
"type": "account",
|
||||
"currency_id": accounts_data[acc_id]["currency_id"],
|
||||
"centralized": accounts_data[acc_id]["centralized"],
|
||||
"grouped_by": grouped_by,
|
||||
}
|
||||
)
|
||||
if grouped_by and not gen_led_data[acc_id][grouped_by]:
|
||||
account = self._create_account(
|
||||
account, acc_id, gen_led_data, rec_after_date_to_ids
|
||||
)
|
||||
if (
|
||||
hide_account_at_0
|
||||
and float_is_zero(
|
||||
gen_led_data[acc_id]["init_bal"]["balance"],
|
||||
precision_rounding=rounding,
|
||||
)
|
||||
and account["move_lines"] == []
|
||||
):
|
||||
continue
|
||||
else:
|
||||
if grouped_by:
|
||||
account, list_grouped = self._get_list_grouped_item(
|
||||
gen_led_data[acc_id],
|
||||
account,
|
||||
rec_after_date_to_ids,
|
||||
hide_account_at_0,
|
||||
rounding,
|
||||
)
|
||||
account.update({"list_grouped": list_grouped})
|
||||
if (
|
||||
hide_account_at_0
|
||||
and float_is_zero(
|
||||
gen_led_data[acc_id]["init_bal"]["balance"],
|
||||
precision_rounding=rounding,
|
||||
)
|
||||
and account["list_grouped"] == []
|
||||
):
|
||||
continue
|
||||
else:
|
||||
account = self._create_account_not_show_item(
|
||||
account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by
|
||||
)
|
||||
if (
|
||||
hide_account_at_0
|
||||
and float_is_zero(
|
||||
gen_led_data[acc_id]["init_bal"]["balance"],
|
||||
precision_rounding=rounding,
|
||||
)
|
||||
and account["move_lines"] == []
|
||||
):
|
||||
continue
|
||||
general_ledger += [account]
|
||||
return general_ledger
|
||||
|
||||
@api.model
|
||||
def _calculate_centralization(self, centralized_ml, move_line, date_to):
|
||||
jnl_id = move_line["journal_id"]
|
||||
month = move_line["date"].month
|
||||
if jnl_id not in centralized_ml.keys():
|
||||
centralized_ml[jnl_id] = {}
|
||||
if month not in centralized_ml[jnl_id].keys():
|
||||
centralized_ml[jnl_id][month] = {}
|
||||
last_day_month = calendar.monthrange(move_line["date"].year, month)
|
||||
date = datetime.date(move_line["date"].year, month, last_day_month[1])
|
||||
if date > date_to:
|
||||
date = date_to
|
||||
centralized_ml[jnl_id][month].update(
|
||||
{
|
||||
"journal_id": jnl_id,
|
||||
"ref_label": "Centralized entries",
|
||||
"date": date,
|
||||
"debit": 0.0,
|
||||
"credit": 0.0,
|
||||
"balance": 0.0,
|
||||
"bal_curr": 0.0,
|
||||
"partner_id": False,
|
||||
"rec_id": 0,
|
||||
"entry_id": False,
|
||||
"tax_ids": [],
|
||||
"tax_line_id": False,
|
||||
"full_reconcile_id": False,
|
||||
"id": False,
|
||||
"currency_id": False,
|
||||
"analytic_distribution": {},
|
||||
}
|
||||
)
|
||||
centralized_ml[jnl_id][month]["debit"] += move_line["debit"]
|
||||
centralized_ml[jnl_id][month]["credit"] += move_line["credit"]
|
||||
centralized_ml[jnl_id][month]["balance"] += (
|
||||
move_line["debit"] - move_line["credit"]
|
||||
)
|
||||
centralized_ml[jnl_id][month]["bal_curr"] += move_line["bal_curr"]
|
||||
return centralized_ml
|
||||
|
||||
@api.model
|
||||
def _get_centralized_ml(self, account, date_to, grouped_by):
|
||||
centralized_ml = {}
|
||||
if isinstance(date_to, str):
|
||||
date_to = datetime.datetime.strptime(date_to, "%Y-%m-%d").date()
|
||||
if grouped_by and account[grouped_by]:
|
||||
for item in account["list_grouped"]:
|
||||
for move_line in item["move_lines"]:
|
||||
centralized_ml = self._calculate_centralization(
|
||||
centralized_ml,
|
||||
move_line,
|
||||
date_to,
|
||||
)
|
||||
else:
|
||||
for move_line in account["move_lines"]:
|
||||
centralized_ml = self._calculate_centralization(
|
||||
centralized_ml,
|
||||
move_line,
|
||||
date_to,
|
||||
)
|
||||
list_centralized_ml = []
|
||||
for jnl_id in centralized_ml.keys():
|
||||
list_centralized_ml += list(centralized_ml[jnl_id].values())
|
||||
return list_centralized_ml
|
||||
|
||||
# flake8: noqa: C901
|
||||
def _get_report_values(self, docids, data):
|
||||
wizard_id = data["wizard_id"]
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
company_id = data["company_id"]
|
||||
date_to = data["date_to"]
|
||||
date_from = data["date_from"]
|
||||
partner_ids = data["partner_ids"]
|
||||
account_ids = data["account_ids"]
|
||||
cost_center_ids = data["cost_center_ids"]
|
||||
grouped_by = data["grouped_by"]
|
||||
hide_account_at_0 = data["hide_account_at_0"]
|
||||
foreign_currency = data["foreign_currency"]
|
||||
only_posted_moves = data["only_posted_moves"]
|
||||
unaffected_earnings_account = data["unaffected_earnings_account"]
|
||||
fy_start_date = data["fy_start_date"]
|
||||
extra_domain = data["domain"]
|
||||
gen_ld_data = self._get_initial_balance_data(
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
unaffected_earnings_account,
|
||||
fy_start_date,
|
||||
cost_center_ids,
|
||||
extra_domain,
|
||||
grouped_by,
|
||||
)
|
||||
centralize = data["centralize"]
|
||||
(
|
||||
gen_ld_data,
|
||||
accounts_data,
|
||||
journals_data,
|
||||
full_reconcile_data,
|
||||
taxes_data,
|
||||
analytic_data,
|
||||
rec_after_date_to_ids,
|
||||
) = self._get_period_ml_data(
|
||||
account_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
date_from,
|
||||
date_to,
|
||||
gen_ld_data,
|
||||
cost_center_ids,
|
||||
extra_domain,
|
||||
grouped_by,
|
||||
)
|
||||
general_ledger = self._create_general_ledger(
|
||||
gen_ld_data,
|
||||
accounts_data,
|
||||
grouped_by,
|
||||
rec_after_date_to_ids,
|
||||
hide_account_at_0,
|
||||
)
|
||||
if centralize:
|
||||
for account in general_ledger:
|
||||
if account["centralized"]:
|
||||
centralized_ml = self._get_centralized_ml(
|
||||
account, date_to, grouped_by
|
||||
)
|
||||
account["move_lines"] = centralized_ml
|
||||
account["move_lines"] = self._recalculate_cumul_balance(
|
||||
account["move_lines"],
|
||||
gen_ld_data[account["id"]]["init_bal"]["balance"],
|
||||
rec_after_date_to_ids,
|
||||
)
|
||||
if grouped_by and account[grouped_by]:
|
||||
account[grouped_by] = False
|
||||
del account["list_grouped"]
|
||||
general_ledger = sorted(general_ledger, key=lambda k: k["code"])
|
||||
# Set the bal_curr of the initial balance to 0 if it does not correspond
|
||||
# (reducing the corresponding of the bal_curr of the initial balance).
|
||||
for gl_item in general_ledger:
|
||||
if not foreign_currency:
|
||||
continue
|
||||
if (
|
||||
not gl_item["currency_id"]
|
||||
or gl_item["currency_id"] != company.currency_id
|
||||
):
|
||||
gl_item["fin_bal"]["bal_curr"] -= gl_item["init_bal"]["bal_curr"]
|
||||
gl_item["init_bal"]["bal_curr"] = 0
|
||||
if "list_grouped" in gl_item:
|
||||
for lg_item in gl_item["list_grouped"]:
|
||||
lg_item["fin_bal"]["bal_curr"] -= lg_item["init_bal"][
|
||||
"bal_curr"
|
||||
]
|
||||
lg_item["init_bal"]["bal_curr"] = 0
|
||||
# Set the fin_bal_currency_id value if the account does not have it set
|
||||
# and there are move lines in a currency different from that of
|
||||
# the company (USD for example).
|
||||
for gl_item in general_ledger:
|
||||
fin_bal_currency_ids = []
|
||||
fin_bal_currency_id = gl_item["currency_id"]
|
||||
if gl_item["currency_id"] or not foreign_currency:
|
||||
gl_item["fin_bal_currency_id"] = fin_bal_currency_id
|
||||
continue
|
||||
gl_item["fin_bal"]["bal_curr"] = gl_item["init_bal"]["bal_curr"]
|
||||
if "move_lines" in gl_item:
|
||||
for ml in gl_item["move_lines"]:
|
||||
ml_currency_id = (
|
||||
ml["currency_id"][0] if ml["currency_id"] else False
|
||||
)
|
||||
if ml_currency_id and ml_currency_id != company.currency_id.id:
|
||||
gl_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
|
||||
if ml_currency_id not in fin_bal_currency_ids:
|
||||
fin_bal_currency_ids.append(ml_currency_id)
|
||||
elif "list_grouped" in gl_item:
|
||||
fin_bal_currency_ids = []
|
||||
for lg_item in gl_item["list_grouped"]:
|
||||
lg_item["fin_bal"]["bal_curr"] = lg_item["init_bal"]["bal_curr"]
|
||||
for ml in lg_item["move_lines"]:
|
||||
ml_currency_id = (
|
||||
ml["currency_id"][0] if ml["currency_id"] else False
|
||||
)
|
||||
if ml_currency_id and ml_currency_id != company.currency_id.id:
|
||||
lg_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
|
||||
gl_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
|
||||
if ml_currency_id not in fin_bal_currency_ids:
|
||||
fin_bal_currency_ids.append(ml_currency_id)
|
||||
# If there is only 1 currency, we set that one as fin_bal_currency_id
|
||||
# The use of different move lines with different currencies (EUR + GBP)
|
||||
# will be excluded. We use a different field to avoid showing the initial
|
||||
# balance and/or distorting data.
|
||||
if not gl_item["currency_id"] and len(fin_bal_currency_ids) == 1:
|
||||
fin_bal_currency_id = fin_bal_currency_ids[0]
|
||||
gl_item["fin_bal_currency_id"] = fin_bal_currency_id
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "general.ledger.report.wizard",
|
||||
"docs": self.env["general.ledger.report.wizard"].browse(wizard_id),
|
||||
"foreign_currency": data["foreign_currency"],
|
||||
"company_name": company.display_name,
|
||||
"company_currency": company.currency_id,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_from": data["date_from"],
|
||||
"date_to": data["date_to"],
|
||||
"only_posted_moves": data["only_posted_moves"],
|
||||
"hide_account_at_0": data["hide_account_at_0"],
|
||||
"show_cost_center": data["show_cost_center"],
|
||||
"general_ledger": general_ledger,
|
||||
"accounts_data": accounts_data,
|
||||
"journals_data": journals_data,
|
||||
"full_reconcile_data": full_reconcile_data,
|
||||
"taxes_data": taxes_data,
|
||||
"centralize": centralize,
|
||||
"analytic_data": analytic_data,
|
||||
"filter_partner_ids": True if partner_ids else False,
|
||||
"currency_model": self.env["res.currency"],
|
||||
}
|
||||
|
||||
def _get_ml_fields(self):
|
||||
return self.COMMON_ML_FIELDS + [
|
||||
"analytic_distribution",
|
||||
"full_reconcile_id",
|
||||
"tax_line_id",
|
||||
"currency_id",
|
||||
"credit",
|
||||
"debit",
|
||||
"amount_currency",
|
||||
"balance",
|
||||
"tax_ids",
|
||||
"move_name",
|
||||
]
|
||||
397
account_financial_report/report/general_ledger_xlsx.py
Normal file
397
account_financial_report/report/general_ledger_xlsx.py
Normal file
@@ -0,0 +1,397 @@
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# Copyright 2022 Tecnativa - V??ctor Mart??nez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class GeneralLedgerXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_general_ledger_xlsx"
|
||||
_description = "General Ledger XLSL Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = _("General Ledger")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
res = [
|
||||
{"header": _("Date"), "field": "date", "width": 11},
|
||||
{"header": _("Entry"), "field": "entry", "width": 18},
|
||||
{"header": _("Journal"), "field": "journal", "width": 8},
|
||||
{"header": _("Account"), "field": "account", "width": 9},
|
||||
{"header": _("Taxes"), "field": "taxes_description", "width": 15},
|
||||
{"header": _("Partner"), "field": "partner_name", "width": 25},
|
||||
{"header": _("Ref - Label"), "field": "ref_label", "width": 40},
|
||||
]
|
||||
if report.show_cost_center:
|
||||
res += [
|
||||
{
|
||||
"header": _("Analytic Distribution"),
|
||||
"field": "analytic_distribution",
|
||||
"width": 20,
|
||||
},
|
||||
]
|
||||
res += [
|
||||
{"header": _("Rec."), "field": "rec_name", "width": 15},
|
||||
{
|
||||
"header": _("Debit"),
|
||||
"field": "debit",
|
||||
"field_initial_balance": "initial_debit",
|
||||
"field_final_balance": "final_debit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
{
|
||||
"header": _("Credit"),
|
||||
"field": "credit",
|
||||
"field_initial_balance": "initial_credit",
|
||||
"field_final_balance": "final_credit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
{
|
||||
"header": _("Cumul. Bal."),
|
||||
"field": "balance",
|
||||
"field_initial_balance": "initial_balance",
|
||||
"field_final_balance": "final_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
]
|
||||
if report.foreign_currency:
|
||||
res += [
|
||||
{
|
||||
"header": _("Amount cur."),
|
||||
"field": "bal_curr",
|
||||
"field_initial_balance": "initial_bal_curr",
|
||||
"field_final_balance": "final_bal_curr",
|
||||
"type": "amount_currency",
|
||||
"width": 10,
|
||||
},
|
||||
{
|
||||
"header": _("Cumul cur."),
|
||||
"field": "total_bal_curr",
|
||||
"field_initial_balance": "initial_bal_curr",
|
||||
"field_final_balance": "final_bal_curr",
|
||||
"type": "amount_currency",
|
||||
"width": 10,
|
||||
},
|
||||
]
|
||||
res_as_dict = {}
|
||||
for i, column in enumerate(res):
|
||||
res_as_dict[i] = column
|
||||
return res_as_dict
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[
|
||||
_("Date range filter"),
|
||||
_("From: %(date_from)s To: %(date_to)s")
|
||||
% ({"date_from": report.date_from, "date_to": report.date_to}),
|
||||
],
|
||||
[
|
||||
_("Target moves filter"),
|
||||
_("All posted entries")
|
||||
if report.target_move == "posted"
|
||||
else _("All entries"),
|
||||
],
|
||||
[
|
||||
_("Account balance at 0 filter"),
|
||||
_("Hide") if report.hide_account_at_0 else _("Show"),
|
||||
],
|
||||
[_("Centralize filter"), _("Yes") if report.centralize else _("No")],
|
||||
[
|
||||
_("Show foreign currency"),
|
||||
_("Yes") if report.foreign_currency else _("No"),
|
||||
],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 2
|
||||
|
||||
def _get_col_pos_initial_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
# flake8: noqa: C901
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.general_ledger"
|
||||
]._get_report_values(report, data)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
accounts_data = res_data["accounts_data"]
|
||||
journals_data = res_data["journals_data"]
|
||||
taxes_data = res_data["taxes_data"]
|
||||
analytic_data = res_data["analytic_data"]
|
||||
filter_partner_ids = res_data["filter_partner_ids"]
|
||||
foreign_currency = res_data["foreign_currency"]
|
||||
company_currency = res_data["company_currency"]
|
||||
# For each account
|
||||
for account in general_ledger:
|
||||
# Write account title
|
||||
total_bal_curr = 0
|
||||
self.write_array_title(
|
||||
account["code"] + " - " + accounts_data[account["id"]]["name"],
|
||||
report_data,
|
||||
)
|
||||
|
||||
if "list_grouped" not in account:
|
||||
# Display array header for move lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# Display initial balance line for account
|
||||
account.update(
|
||||
{
|
||||
"initial_debit": account["init_bal"]["debit"],
|
||||
"initial_credit": account["init_bal"]["credit"],
|
||||
"initial_balance": account["init_bal"]["balance"],
|
||||
}
|
||||
)
|
||||
if foreign_currency and account["currency_id"]:
|
||||
account.update(
|
||||
{"initial_bal_curr": account["init_bal"]["bal_curr"]}
|
||||
)
|
||||
self.write_initial_balance_from_dict(account, report_data)
|
||||
|
||||
# Display account move lines
|
||||
for line in account["move_lines"]:
|
||||
line.update(
|
||||
{
|
||||
"account": account["code"],
|
||||
"journal": journals_data[line["journal_id"]]["code"],
|
||||
}
|
||||
)
|
||||
line_currency_id = (
|
||||
line["currency_id"][0] if line["currency_id"] else False
|
||||
)
|
||||
if line_currency_id and line_currency_id != company_currency.id:
|
||||
line.update(
|
||||
{
|
||||
"currency_name": line["currency_id"][1],
|
||||
"currency_id": line["currency_id"][0],
|
||||
}
|
||||
)
|
||||
if line["ref_label"] != "Centralized entries":
|
||||
taxes_description = ""
|
||||
analytic_distribution = ""
|
||||
for tax_id in line["tax_ids"]:
|
||||
taxes_description += taxes_data[tax_id]["tax_name"] + " "
|
||||
if line["tax_line_id"]:
|
||||
taxes_description += line["tax_line_id"][1]
|
||||
for account_id, value in line["analytic_distribution"].items():
|
||||
if value < 100:
|
||||
analytic_distribution += "%s %d%% " % (
|
||||
analytic_data[int(account_id)]["name"],
|
||||
value,
|
||||
)
|
||||
else:
|
||||
analytic_distribution += (
|
||||
f"{analytic_data[int(account_id)]['name']} "
|
||||
)
|
||||
line.update(
|
||||
{
|
||||
"taxes_description": taxes_description,
|
||||
"analytic_distribution": analytic_distribution,
|
||||
}
|
||||
)
|
||||
if (
|
||||
foreign_currency
|
||||
and line_currency_id
|
||||
and line_currency_id != company_currency.id
|
||||
):
|
||||
total_bal_curr += line["bal_curr"]
|
||||
line.update({"total_bal_curr": total_bal_curr})
|
||||
self.write_line_from_dict(line, report_data)
|
||||
# Display ending balance line for account
|
||||
account.update(
|
||||
{
|
||||
"final_debit": account["fin_bal"]["debit"],
|
||||
"final_credit": account["fin_bal"]["credit"],
|
||||
"final_balance": account["fin_bal"]["balance"],
|
||||
}
|
||||
)
|
||||
if foreign_currency and account["currency_id"]:
|
||||
account.update(
|
||||
{
|
||||
"final_bal_curr": account["fin_bal"]["bal_curr"],
|
||||
}
|
||||
)
|
||||
self.write_ending_balance_from_dict(account, report_data)
|
||||
|
||||
else:
|
||||
# For each partner
|
||||
total_bal_curr = 0
|
||||
for group_item in account["list_grouped"]:
|
||||
# Write partner title
|
||||
self.write_array_title(group_item["name"], report_data)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
account.update(
|
||||
{
|
||||
"currency_id": accounts_data[account["id"]]["currency_id"],
|
||||
"currency_name": accounts_data[account["id"]][
|
||||
"currency_name"
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Display initial balance line for partner
|
||||
group_item.update(
|
||||
{
|
||||
"initial_debit": group_item["init_bal"]["debit"],
|
||||
"initial_credit": group_item["init_bal"]["credit"],
|
||||
"initial_balance": group_item["init_bal"]["balance"],
|
||||
"type": "partner",
|
||||
"grouped_by": account["grouped_by"]
|
||||
if "grouped_by" in account
|
||||
else "",
|
||||
"currency_id": accounts_data[account["id"]]["currency_id"],
|
||||
"currency_name": accounts_data[account["id"]][
|
||||
"currency_name"
|
||||
],
|
||||
}
|
||||
)
|
||||
if foreign_currency and account["currency_id"]:
|
||||
group_item.update(
|
||||
{
|
||||
"initial_bal_curr": group_item["init_bal"]["bal_curr"],
|
||||
}
|
||||
)
|
||||
self.write_initial_balance_from_dict(group_item, report_data)
|
||||
|
||||
# Display account move lines
|
||||
for line in group_item["move_lines"]:
|
||||
line.update(
|
||||
{
|
||||
"account": account["code"],
|
||||
"journal": journals_data[line["journal_id"]]["code"],
|
||||
}
|
||||
)
|
||||
line_currency_id = (
|
||||
line["currency_id"][0] if line["currency_id"] else False
|
||||
)
|
||||
if line_currency_id and line_currency_id != company_currency.id:
|
||||
line.update(
|
||||
{
|
||||
"currency_name": line["currency_id"][1],
|
||||
"currency_id": line["currency_id"][0],
|
||||
}
|
||||
)
|
||||
if line["ref_label"] != "Centralized entries":
|
||||
taxes_description = ""
|
||||
analytic_distribution = ""
|
||||
for tax_id in line["tax_ids"]:
|
||||
taxes_description += (
|
||||
taxes_data[tax_id]["tax_name"] + " "
|
||||
)
|
||||
for account_id, value in line[
|
||||
"analytic_distribution"
|
||||
].items():
|
||||
if value < 100:
|
||||
analytic_distribution += "%s %d%% " % (
|
||||
analytic_data[int(account_id)]["name"],
|
||||
value,
|
||||
)
|
||||
else:
|
||||
analytic_distribution += (
|
||||
f"{analytic_data[int(account_id)]['name']} "
|
||||
)
|
||||
line.update(
|
||||
{
|
||||
"taxes_description": taxes_description,
|
||||
"analytic_distribution": analytic_distribution,
|
||||
}
|
||||
)
|
||||
if (
|
||||
foreign_currency
|
||||
and line_currency_id
|
||||
and line_currency_id != company_currency.id
|
||||
):
|
||||
total_bal_curr += line["bal_curr"]
|
||||
line.update({"total_bal_curr": total_bal_curr})
|
||||
self.write_line_from_dict(line, report_data)
|
||||
|
||||
# Display ending balance line for partner
|
||||
group_item.update(
|
||||
{
|
||||
"final_debit": group_item["fin_bal"]["debit"],
|
||||
"final_credit": group_item["fin_bal"]["credit"],
|
||||
"final_balance": group_item["fin_bal"]["balance"],
|
||||
}
|
||||
)
|
||||
if foreign_currency and group_item["currency_id"]:
|
||||
group_item.update(
|
||||
{
|
||||
"final_bal_curr": group_item["fin_bal"]["bal_curr"],
|
||||
}
|
||||
)
|
||||
self.write_ending_balance_from_dict(group_item, report_data)
|
||||
|
||||
# Line break
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
if not filter_partner_ids:
|
||||
account.update(
|
||||
{
|
||||
"final_debit": account["fin_bal"]["debit"],
|
||||
"final_credit": account["fin_bal"]["credit"],
|
||||
"final_balance": account["fin_bal"]["balance"],
|
||||
}
|
||||
)
|
||||
if foreign_currency and account["fin_bal_currency_id"]:
|
||||
account.update(
|
||||
{
|
||||
"final_bal_curr": total_bal_curr,
|
||||
"currency_id": account["fin_bal_currency_id"],
|
||||
}
|
||||
)
|
||||
self.write_ending_balance_from_dict(account, report_data)
|
||||
|
||||
# 2 lines break
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def write_initial_balance_from_dict(self, my_object, report_data):
|
||||
"""Specific function to write initial balance for General Ledger"""
|
||||
label = False
|
||||
if "account" not in my_object["type"] and "grouped_by" in my_object:
|
||||
if my_object["grouped_by"] == "partners":
|
||||
label = _("Partner Initial balance")
|
||||
elif my_object["grouped_by"] == "taxes":
|
||||
label = _("Tax Initial balance")
|
||||
label = label if label else _("Initial balance")
|
||||
return super().write_initial_balance_from_dict(my_object, label, report_data)
|
||||
|
||||
def write_ending_balance_from_dict(self, my_object, report_data):
|
||||
"""Specific function to write ending balance for General Ledger"""
|
||||
label = name = False
|
||||
if "account" in my_object["type"]:
|
||||
name = my_object["code"] + " - " + my_object["name"]
|
||||
elif "grouped_by" in my_object:
|
||||
name = my_object["name"]
|
||||
if my_object["grouped_by"] == "partners":
|
||||
label = _("Partner ending balance")
|
||||
elif my_object["grouped_by"] == "taxes":
|
||||
label = _("Tax ending balance")
|
||||
label = label if label else _("Ending balance")
|
||||
return super().write_ending_balance_from_dict(
|
||||
my_object, name, label, report_data
|
||||
)
|
||||
376
account_financial_report/report/journal_ledger.py
Normal file
376
account_financial_report/report/journal_ledger.py
Normal file
@@ -0,0 +1,376 @@
|
||||
# Copyright 2019-20 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import itertools
|
||||
import operator
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class JournalLedgerReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.journal_ledger"
|
||||
_description = "Journal Ledger Report"
|
||||
|
||||
def _get_journal_ledger_data(self, journal):
|
||||
return {
|
||||
"id": journal.id,
|
||||
"name": journal.name,
|
||||
"currency_id": journal.currency_id.id,
|
||||
"currency_name": journal.currency_id
|
||||
and journal.currency_id.name
|
||||
or journal.company_id.currency_id.name,
|
||||
"debit": 0.0,
|
||||
"credit": 0.0,
|
||||
}
|
||||
|
||||
def _get_journal_ledgers_domain(self, wizard, journal_ids, company):
|
||||
domain = []
|
||||
if company:
|
||||
domain += [("company_id", "=", company.id)]
|
||||
if journal_ids:
|
||||
domain += [("id", "in", journal_ids)]
|
||||
return domain
|
||||
|
||||
def _get_journal_ledgers(self, wizard, journal_ids, company):
|
||||
journals = self.env["account.journal"].search(
|
||||
self._get_journal_ledgers_domain(wizard, journal_ids, company),
|
||||
order="name asc",
|
||||
)
|
||||
journal_ledgers_data = []
|
||||
for journal in journals:
|
||||
journal_ledgers_data.append(self._get_journal_ledger_data(journal))
|
||||
return journal_ledgers_data
|
||||
|
||||
def _get_moves_domain(self, wizard, journal_ids):
|
||||
domain = [
|
||||
("journal_id", "in", journal_ids),
|
||||
("date", ">=", wizard.date_from),
|
||||
("date", "<=", wizard.date_to),
|
||||
]
|
||||
if wizard.move_target != "all":
|
||||
domain += [("state", "=", wizard.move_target)]
|
||||
else:
|
||||
domain += [("state", "in", ["posted", "draft"])]
|
||||
return domain
|
||||
|
||||
def _get_moves_order(self, wizard, journal_ids):
|
||||
search_order = ""
|
||||
if wizard.sort_option == "move_name":
|
||||
search_order = "name asc"
|
||||
elif wizard.sort_option == "date":
|
||||
search_order = "date asc, name asc"
|
||||
return search_order
|
||||
|
||||
def _get_moves_data(self, move):
|
||||
return {
|
||||
"move_id": move.id,
|
||||
"journal_id": move.journal_id.id,
|
||||
"entry": move.name,
|
||||
}
|
||||
|
||||
def _get_moves(self, wizard, journal_ids):
|
||||
moves = self.env["account.move"].search(
|
||||
self._get_moves_domain(wizard, journal_ids),
|
||||
order=self._get_moves_order(wizard, journal_ids),
|
||||
)
|
||||
Moves = []
|
||||
move_data = {}
|
||||
for move in moves:
|
||||
move_data[move.id] = self._get_moves_data(move)
|
||||
Moves.append(move_data[move.id])
|
||||
return moves.ids, Moves, move_data
|
||||
|
||||
def _get_move_lines_domain(self, move_ids, wizard, journal_ids):
|
||||
return [
|
||||
("display_type", "not in", ["line_note", "line_section"]),
|
||||
("move_id", "in", move_ids),
|
||||
]
|
||||
|
||||
def _get_move_lines_order(self, move_ids, wizard, journal_ids):
|
||||
"""Add `move_id` to make sure the order of the records is correct
|
||||
(especially if we use auto-sequence).
|
||||
"""
|
||||
return "move_id"
|
||||
|
||||
def _get_move_lines_data(self, ml, wizard, ml_taxes, auto_sequence, exigible):
|
||||
base_debit = base_credit = tax_debit = tax_credit = base_balance = (
|
||||
tax_balance
|
||||
) = 0.0
|
||||
if exigible:
|
||||
base_debit = ml_taxes and ml.debit or 0.0
|
||||
base_credit = ml_taxes and ml.credit or 0.0
|
||||
base_balance = ml_taxes and ml.balance or 0.0
|
||||
tax_debit = ml.tax_line_id and ml.debit or 0.0
|
||||
tax_credit = ml.tax_line_id and ml.credit or 0.0
|
||||
tax_balance = ml.tax_line_id and ml.balance or 0.0
|
||||
return {
|
||||
"move_line_id": ml.id,
|
||||
"move_id": ml.move_id.id,
|
||||
"date": ml.date,
|
||||
"journal_id": ml.journal_id.id,
|
||||
"account_id": ml.account_id.id,
|
||||
"partner_id": ml.partner_id.id,
|
||||
"label": ml.name,
|
||||
"debit": ml.debit,
|
||||
"credit": ml.credit,
|
||||
"company_currency_id": ml.company_currency_id.id,
|
||||
"amount_currency": ml.amount_currency,
|
||||
"currency_id": ml.currency_id.id,
|
||||
"tax_line_id": ml.tax_line_id.id,
|
||||
"tax_ids": list(ml_taxes.keys()),
|
||||
"base_debit": base_debit,
|
||||
"base_credit": base_credit,
|
||||
"tax_debit": tax_debit,
|
||||
"tax_credit": tax_credit,
|
||||
"base_balance": base_balance,
|
||||
"tax_balance": tax_balance,
|
||||
"auto_sequence": str(auto_sequence).zfill(6),
|
||||
}
|
||||
|
||||
def _get_account_data(self, accounts):
|
||||
data = {}
|
||||
for account in accounts:
|
||||
data[account.id] = self._get_account_id_data(account)
|
||||
return data
|
||||
|
||||
def _get_account_id_data(self, account):
|
||||
return {
|
||||
"name": account.name,
|
||||
"code": account.code,
|
||||
"account_type": account.account_type,
|
||||
}
|
||||
|
||||
def _get_partner_data(self, partners):
|
||||
data = {}
|
||||
for partner in partners:
|
||||
data[partner.id] = self._get_partner_id_data(partner)
|
||||
return data
|
||||
|
||||
def _get_partner_id_data(self, partner):
|
||||
return {"name": partner.name}
|
||||
|
||||
def _get_currency_data(self, currencies):
|
||||
data = {}
|
||||
for currency in currencies:
|
||||
data[currency.id] = self._get_currency_id_data(currency)
|
||||
return data
|
||||
|
||||
def _get_currency_id_data(self, currency):
|
||||
return {"name": currency.name}
|
||||
|
||||
def _get_tax_line_data(self, taxes):
|
||||
data = {}
|
||||
for tax in taxes:
|
||||
data[tax.id] = self._get_tax_line_id_data(tax)
|
||||
return data
|
||||
|
||||
def _get_tax_line_id_data(self, tax):
|
||||
return {"name": tax.name, "description": tax.description}
|
||||
|
||||
def _get_query_taxes(self):
|
||||
return """
|
||||
SELECT aml_at_rel.account_move_line_id, aml_at_rel.account_tax_id,
|
||||
at.description, at.name
|
||||
FROM account_move_line_account_tax_rel AS aml_at_rel
|
||||
LEFT JOIN
|
||||
account_tax AS at on (at.id = aml_at_rel.account_tax_id)
|
||||
WHERE account_move_line_id IN %(move_line_ids)s
|
||||
"""
|
||||
|
||||
def _get_query_taxes_params(self, move_lines):
|
||||
return {"move_line_ids": tuple(move_lines.ids)}
|
||||
|
||||
def _get_move_lines(self, move_ids, wizard, journal_ids):
|
||||
move_lines = self.env["account.move.line"].search(
|
||||
self._get_move_lines_domain(move_ids, wizard, journal_ids),
|
||||
order=self._get_move_lines_order(move_ids, wizard, journal_ids),
|
||||
)
|
||||
move_lines_exigible = self.env["account.move.line"].search(
|
||||
self._get_move_lines_domain(move_ids, wizard, journal_ids)
|
||||
+ self.env["account.move.line"]._get_tax_exigible_domain(),
|
||||
)
|
||||
move_line_ids_taxes_data = {}
|
||||
if move_lines:
|
||||
# Get the taxes ids for the move lines
|
||||
query_taxes_params = self._get_query_taxes_params(move_lines)
|
||||
query_taxes = self._get_query_taxes()
|
||||
self.env.cr.execute(query_taxes, query_taxes_params)
|
||||
# Fetch the taxes associated to the move line
|
||||
for (
|
||||
move_line_id,
|
||||
account_tax_id,
|
||||
tax_description,
|
||||
tax_name,
|
||||
) in self.env.cr.fetchall():
|
||||
if move_line_id not in move_line_ids_taxes_data.keys():
|
||||
move_line_ids_taxes_data[move_line_id] = {}
|
||||
move_line_ids_taxes_data[move_line_id][account_tax_id] = {
|
||||
"name": tax_name,
|
||||
"description": tax_description,
|
||||
}
|
||||
Move_Lines = {}
|
||||
accounts = self.env["account.account"]
|
||||
partners = self.env["res.partner"]
|
||||
currencies = self.env["res.currency"]
|
||||
tax_lines = self.env["account.tax"]
|
||||
auto_sequence = len(move_ids)
|
||||
for ml in move_lines:
|
||||
if ml.account_id not in accounts:
|
||||
accounts |= ml.account_id
|
||||
if ml.partner_id not in partners:
|
||||
partners |= ml.partner_id
|
||||
if ml.currency_id not in currencies:
|
||||
currencies |= ml.currency_id
|
||||
if ml.tax_line_id not in tax_lines:
|
||||
tax_lines |= ml.tax_line_id
|
||||
if ml.move_id.id not in Move_Lines.keys():
|
||||
Move_Lines[ml.move_id.id] = []
|
||||
auto_sequence -= 1
|
||||
taxes = (
|
||||
ml.id in move_line_ids_taxes_data.keys()
|
||||
and move_line_ids_taxes_data[ml.id]
|
||||
or {}
|
||||
)
|
||||
exigible = ml in move_lines_exigible
|
||||
Move_Lines[ml.move_id.id].append(
|
||||
self._get_move_lines_data(ml, wizard, taxes, auto_sequence, exigible)
|
||||
)
|
||||
account_ids_data = self._get_account_data(accounts)
|
||||
partner_ids_data = self._get_partner_data(partners)
|
||||
currency_ids_data = self._get_currency_data(currencies)
|
||||
tax_line_ids_data = self._get_tax_line_data(tax_lines)
|
||||
return (
|
||||
move_lines.ids,
|
||||
Move_Lines,
|
||||
account_ids_data,
|
||||
partner_ids_data,
|
||||
currency_ids_data,
|
||||
tax_line_ids_data,
|
||||
move_line_ids_taxes_data,
|
||||
)
|
||||
|
||||
def _get_journal_tax_lines(self, wizard, moves_data):
|
||||
journals_taxes_data = {}
|
||||
for move_data in moves_data:
|
||||
report_move_lines = move_data["report_move_lines"]
|
||||
for report_move_line in report_move_lines:
|
||||
ml_data = report_move_line
|
||||
tax_ids = []
|
||||
if ml_data["tax_line_id"]:
|
||||
tax_ids.append(ml_data["tax_line_id"])
|
||||
if ml_data["tax_ids"]:
|
||||
tax_ids += ml_data["tax_ids"]
|
||||
tax_ids = list(set(tax_ids))
|
||||
journal_id = ml_data["journal_id"]
|
||||
if journal_id not in journals_taxes_data.keys():
|
||||
journals_taxes_data[journal_id] = {}
|
||||
taxes = self.env["account.tax"].search_fetch(
|
||||
[("id", "in", tax_ids)], ["name", "description"]
|
||||
)
|
||||
for tax in taxes:
|
||||
if tax.id not in journals_taxes_data[journal_id]:
|
||||
journals_taxes_data[journal_id][tax.id] = {
|
||||
"base_debit": 0.0,
|
||||
"base_credit": 0.0,
|
||||
"base_balance": 0.0,
|
||||
"tax_debit": 0.0,
|
||||
"tax_credit": 0.0,
|
||||
"tax_balance": 0.0,
|
||||
"tax_name": tax.name,
|
||||
"tax_code": tax.description,
|
||||
}
|
||||
field_keys = [
|
||||
"base_debit",
|
||||
"base_credit",
|
||||
"base_balance",
|
||||
"tax_debit",
|
||||
"tax_credit",
|
||||
"tax_balance",
|
||||
]
|
||||
for field_key in field_keys:
|
||||
journals_taxes_data[journal_id][tax.id][field_key] += ml_data[
|
||||
field_key
|
||||
]
|
||||
journals_taxes_data_2 = {}
|
||||
for journal_id in journals_taxes_data.keys():
|
||||
journals_taxes_data_2[journal_id] = []
|
||||
for tax_id in journals_taxes_data[journal_id].keys():
|
||||
journals_taxes_data_2[journal_id] += [
|
||||
journals_taxes_data[journal_id][tax_id]
|
||||
]
|
||||
return journals_taxes_data_2
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
wizard_id = data["wizard_id"]
|
||||
wizard = self.env["journal.ledger.report.wizard"].browse(wizard_id)
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
journal_ids = data["journal_ids"]
|
||||
journal_ledgers_data = self._get_journal_ledgers(wizard, journal_ids, company)
|
||||
move_ids, moves_data, move_ids_data = self._get_moves(wizard, journal_ids)
|
||||
journal_moves_data = {}
|
||||
for key, items in itertools.groupby(
|
||||
moves_data, operator.itemgetter("journal_id")
|
||||
):
|
||||
if key not in journal_moves_data.keys():
|
||||
journal_moves_data[key] = []
|
||||
journal_moves_data[key] += list(items)
|
||||
move_lines_data = account_ids_data = partner_ids_data = currency_ids_data = (
|
||||
tax_line_ids_data
|
||||
) = move_line_ids_taxes_data = {}
|
||||
if move_ids:
|
||||
move_lines = self._get_move_lines(move_ids, wizard, journal_ids)
|
||||
move_lines_data = move_lines[1]
|
||||
account_ids_data = move_lines[2]
|
||||
partner_ids_data = move_lines[3]
|
||||
currency_ids_data = move_lines[4]
|
||||
tax_line_ids_data = move_lines[5]
|
||||
for move_data in moves_data:
|
||||
move_id = move_data["move_id"]
|
||||
move_data["report_move_lines"] = []
|
||||
if move_id in move_lines_data.keys():
|
||||
move_data["report_move_lines"] += move_lines_data[move_id]
|
||||
journals_taxes_data = {}
|
||||
if moves_data:
|
||||
journals_taxes_data = self._get_journal_tax_lines(wizard, moves_data)
|
||||
for journal_ledger_data in journal_ledgers_data:
|
||||
journal_id = journal_ledger_data["id"]
|
||||
journal_ledger_data["tax_lines"] = journals_taxes_data.get(journal_id, [])
|
||||
journal_totals = {}
|
||||
for move_id in move_lines_data.keys():
|
||||
for move_line_data in move_lines_data[move_id]:
|
||||
journal_id = move_line_data["journal_id"]
|
||||
if journal_id not in journal_totals.keys():
|
||||
journal_totals[journal_id] = {"debit": 0.0, "credit": 0.0}
|
||||
for item in ["debit", "credit"]:
|
||||
journal_totals[journal_id][item] += move_line_data[item]
|
||||
for journal_ledger_data in journal_ledgers_data:
|
||||
journal_id = journal_ledger_data["id"]
|
||||
if journal_id in journal_moves_data.keys():
|
||||
journal_ledger_data["report_moves"] = journal_moves_data[journal_id]
|
||||
else:
|
||||
journal_ledger_data["report_moves"] = []
|
||||
if journal_id in journal_totals.keys():
|
||||
for item in ["debit", "credit"]:
|
||||
journal_ledger_data[item] += journal_totals[journal_id][item]
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "journal.ledger.report.wizard",
|
||||
"docs": self.env["journal.ledger.report.wizard"].browse(wizard_id),
|
||||
"group_option": data["group_option"],
|
||||
"foreign_currency": data["foreign_currency"],
|
||||
"with_account_name": data["with_account_name"],
|
||||
"company_name": company.display_name,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_from": data["date_from"],
|
||||
"date_to": data["date_to"],
|
||||
"move_target": data["move_target"],
|
||||
"with_auto_sequence": data["with_auto_sequence"],
|
||||
"account_ids_data": account_ids_data,
|
||||
"partner_ids_data": partner_ids_data,
|
||||
"currency_ids_data": currency_ids_data,
|
||||
"move_ids_data": move_ids_data,
|
||||
"tax_line_data": tax_line_ids_data,
|
||||
"move_line_ids_taxes_data": move_line_ids_taxes_data,
|
||||
"Journal_Ledgers": journal_ledgers_data,
|
||||
"Moves": moves_data,
|
||||
}
|
||||
268
account_financial_report/report/journal_ledger_xlsx.py
Normal file
268
account_financial_report/report/journal_ledger_xlsx.py
Normal file
@@ -0,0 +1,268 @@
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class JournalLedgerXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_journal_ledger_xlsx"
|
||||
_description = "Journal Ledger XLSX Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = _("Journal Ledger")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
columns = [
|
||||
{"header": _("Entry"), "field": "entry", "width": 18},
|
||||
{"header": _("Date"), "field": "date", "width": 11},
|
||||
{"header": _("Account"), "field": "account_code", "width": 9},
|
||||
]
|
||||
|
||||
if report.with_auto_sequence:
|
||||
columns.insert(
|
||||
0, {"header": _("Sequence"), "field": "auto_sequence", "width": 10}
|
||||
)
|
||||
|
||||
if report.with_account_name:
|
||||
columns.append(
|
||||
{"header": _("Account Name"), "field": "account_name", "width": 15}
|
||||
)
|
||||
|
||||
columns += [
|
||||
{"header": _("Partner"), "field": "partner", "width": 25},
|
||||
{"header": _("Ref - Label"), "field": "label", "width": 40},
|
||||
{"header": _("Taxes"), "field": "taxes_description", "width": 11},
|
||||
{"header": _("Debit"), "field": "debit", "type": "amount", "width": 14},
|
||||
{"header": _("Credit"), "field": "credit", "type": "amount", "width": 14},
|
||||
]
|
||||
|
||||
if report.foreign_currency:
|
||||
columns += [
|
||||
{
|
||||
"header": _("Currency"),
|
||||
"field": "currency_name",
|
||||
"width": 14,
|
||||
"type": "currency_name",
|
||||
},
|
||||
{
|
||||
"header": _("Amount Currency"),
|
||||
"field": "amount_currency",
|
||||
"type": "amount",
|
||||
"width": 18,
|
||||
},
|
||||
]
|
||||
|
||||
columns_as_dict = {}
|
||||
for i, column in enumerate(columns):
|
||||
columns_as_dict[i] = column
|
||||
return columns_as_dict
|
||||
|
||||
def _get_journal_tax_columns(self, report):
|
||||
return {
|
||||
0: {"header": _("Name"), "field": "tax_name", "width": 35},
|
||||
1: {"header": _("Description"), "field": "tax_code", "width": 18},
|
||||
2: {
|
||||
"header": _("Base Debit"),
|
||||
"field": "base_debit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
3: {
|
||||
"header": _("Base Credit"),
|
||||
"field": "base_credit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
4: {
|
||||
"header": _("Base Balance"),
|
||||
"field": "base_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
5: {
|
||||
"header": _("Tax Debit"),
|
||||
"field": "tax_debit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
6: {
|
||||
"header": _("Tax Credit"),
|
||||
"field": "tax_credit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
7: {
|
||||
"header": _("Tax Balance"),
|
||||
"field": "tax_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 3
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
target_label_by_value = {
|
||||
value: label
|
||||
for value, label in self.env[
|
||||
"journal.ledger.report.wizard"
|
||||
]._get_move_targets()
|
||||
}
|
||||
|
||||
sort_option_label_by_value = {
|
||||
value: label
|
||||
for value, label in self.env[
|
||||
"journal.ledger.report.wizard"
|
||||
]._get_sort_options()
|
||||
}
|
||||
|
||||
return [
|
||||
[_("Company"), report.company_id.name],
|
||||
[
|
||||
_("Date range filter"),
|
||||
_("From: %(date_from)s To: %(date_to)s")
|
||||
% ({"date_from": report.date_from, "date_to": report.date_to}),
|
||||
],
|
||||
[
|
||||
_("Target moves filter"),
|
||||
_("%s") % target_label_by_value[report.move_target],
|
||||
],
|
||||
[
|
||||
_("Entries sorted by"),
|
||||
_("%s") % sort_option_label_by_value[report.sort_option],
|
||||
],
|
||||
[
|
||||
_("Journals"),
|
||||
", ".join(
|
||||
[
|
||||
f"{report_journal.code} - {report_journal.name}"
|
||||
for report_journal in report.journal_ids
|
||||
]
|
||||
),
|
||||
],
|
||||
]
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.journal_ledger"
|
||||
]._get_report_values(report, data)
|
||||
group_option = report.group_option
|
||||
if group_option == "journal":
|
||||
for ledger in res_data["Journal_Ledgers"]:
|
||||
self._generate_journal_content(
|
||||
workbook, report, res_data, ledger, report_data
|
||||
)
|
||||
elif group_option == "none":
|
||||
self._generate_no_group_content(workbook, report, res_data, report_data)
|
||||
|
||||
def _generate_no_group_content(self, workbook, report, res_data, report_data):
|
||||
self._generate_moves_content(
|
||||
workbook, "Report", report, res_data, res_data["Moves"], report_data
|
||||
)
|
||||
self._generate_no_group_taxes_summary(workbook, report, res_data, report_data)
|
||||
|
||||
def _generate_journal_content(
|
||||
self, workbook, report, res_data, ledger, report_data
|
||||
):
|
||||
journal = self.env["account.journal"].browse(ledger["id"])
|
||||
currency_name = (
|
||||
journal.currency_id
|
||||
and journal.currency_id.name
|
||||
or journal.company_id.currency_id.name
|
||||
)
|
||||
sheet_name = f"{journal.code} ({currency_name}) - {journal.name}"
|
||||
self._generate_moves_content(
|
||||
workbook, sheet_name, report, res_data, ledger["report_moves"], report_data
|
||||
)
|
||||
self._generate_journal_taxes_summary(workbook, ledger, report_data)
|
||||
|
||||
def _generate_no_group_taxes_summary(self, workbook, report, res_data, report_data):
|
||||
self._generate_taxes_summary(
|
||||
workbook, "Tax Report", res_data["tax_line_data"], report_data
|
||||
)
|
||||
|
||||
def _generate_journal_taxes_summary(self, workbook, ledger, report_data):
|
||||
journal = self.env["account.journal"].browse(ledger["id"])
|
||||
currency_name = (
|
||||
journal.currency_id
|
||||
and journal.currency_id.name
|
||||
or journal.company_id.currency_id.name
|
||||
)
|
||||
sheet_name = f"Tax - {journal.code} ({currency_name}) - {journal.name}"
|
||||
self._generate_taxes_summary(
|
||||
workbook, sheet_name, ledger["tax_lines"], report_data
|
||||
)
|
||||
|
||||
def _generate_moves_content(
|
||||
self, workbook, sheet_name, report, res_data, moves, report_data
|
||||
):
|
||||
report_data["workbook"] = workbook
|
||||
report_data["sheet"] = workbook.add_worksheet(sheet_name)
|
||||
self._set_column_width(report_data)
|
||||
|
||||
report_data["row_pos"] = 1
|
||||
|
||||
self.write_array_title(sheet_name, report_data)
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
self.write_array_header(report_data)
|
||||
account_ids_data = res_data["account_ids_data"]
|
||||
partner_ids_data = res_data["partner_ids_data"]
|
||||
currency_ids_data = res_data["currency_ids_data"]
|
||||
move_ids_data = res_data["move_ids_data"]
|
||||
for move in moves:
|
||||
for line in move["report_move_lines"]:
|
||||
currency_data = currency_ids_data.get(line["currency_id"], False)
|
||||
currency_name = currency_data and currency_data["name"] or ""
|
||||
account_data = account_ids_data.get(line["account_id"], False)
|
||||
account_name = account_data and account_data["name"] or ""
|
||||
account_code = account_data and account_data["code"] or ""
|
||||
move_data = move_ids_data.get(line["move_id"], False)
|
||||
move_entry = move_data and move_data["entry"] or ""
|
||||
line["partner"] = self._get_partner_name(
|
||||
line["partner_id"], partner_ids_data
|
||||
)
|
||||
line["auto_sequence"] = line["auto_sequence"]
|
||||
line["account_code"] = account_code
|
||||
line["account_name"] = account_name
|
||||
line["currency_name"] = currency_name
|
||||
line["entry"] = move_entry
|
||||
line["taxes_description"] = report._get_ml_tax_description(
|
||||
line,
|
||||
res_data["tax_line_data"].get(line["tax_line_id"]),
|
||||
res_data["move_line_ids_taxes_data"].get(
|
||||
line["move_line_id"], False
|
||||
),
|
||||
)
|
||||
self.write_line_from_dict(line, report_data)
|
||||
report_data["row_pos"] += 1
|
||||
|
||||
def _generate_taxes_summary(
|
||||
self, workbook, sheet_name, tax_lines_dict, report_data
|
||||
):
|
||||
report_data["workbook"] = workbook
|
||||
report_data["sheet"] = workbook.add_worksheet(sheet_name)
|
||||
|
||||
report_data["row_pos"] = 1
|
||||
self.write_array_title(sheet_name, report_data)
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def _get_partner_name(self, partner_id, partner_data):
|
||||
if partner_id in partner_data.keys():
|
||||
return partner_data[partner_id]["name"]
|
||||
else:
|
||||
return ""
|
||||
305
account_financial_report/report/open_items.py
Normal file
305
account_financial_report/report/open_items.py
Normal file
@@ -0,0 +1,305 @@
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import operator
|
||||
from datetime import date, datetime
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
class OpenItemsReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.open_items"
|
||||
_description = "Open Items Report"
|
||||
_inherit = "report.account_financial_report.abstract_report"
|
||||
|
||||
def _get_account_partial_reconciled(self, company_id, date_at_object):
|
||||
domain = [("max_date", ">", date_at_object), ("company_id", "=", company_id)]
|
||||
fields = [
|
||||
"debit_move_id",
|
||||
"credit_move_id",
|
||||
"amount",
|
||||
"debit_amount_currency",
|
||||
"credit_amount_currency",
|
||||
]
|
||||
accounts_partial_reconcile = self.env["account.partial.reconcile"].search_read(
|
||||
domain=domain, fields=fields
|
||||
)
|
||||
debit_amount = {}
|
||||
debit_amount_currency = {}
|
||||
credit_amount = {}
|
||||
credit_amount_currency = {}
|
||||
for account_partial_reconcile_data in accounts_partial_reconcile:
|
||||
debit_move_id = account_partial_reconcile_data["debit_move_id"][0]
|
||||
credit_move_id = account_partial_reconcile_data["credit_move_id"][0]
|
||||
if debit_move_id not in debit_amount.keys():
|
||||
debit_amount[debit_move_id] = 0.0
|
||||
debit_amount_currency[debit_move_id] = 0.0
|
||||
debit_amount[debit_move_id] += account_partial_reconcile_data["amount"]
|
||||
debit_amount_currency[debit_move_id] += account_partial_reconcile_data[
|
||||
"debit_amount_currency"
|
||||
]
|
||||
if credit_move_id not in credit_amount.keys():
|
||||
credit_amount[credit_move_id] = 0.0
|
||||
credit_amount_currency[credit_move_id] = 0.0
|
||||
credit_amount[credit_move_id] += account_partial_reconcile_data["amount"]
|
||||
credit_amount_currency[credit_move_id] += account_partial_reconcile_data[
|
||||
"credit_amount_currency"
|
||||
]
|
||||
account_partial_reconcile_data.update(
|
||||
{"debit_move_id": debit_move_id, "credit_move_id": credit_move_id}
|
||||
)
|
||||
return (
|
||||
accounts_partial_reconcile,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
)
|
||||
|
||||
def _get_data(
|
||||
self,
|
||||
account_ids,
|
||||
partner_ids,
|
||||
date_at_object,
|
||||
only_posted_moves,
|
||||
company_id,
|
||||
date_from,
|
||||
):
|
||||
domain = self._get_move_lines_domain_not_reconciled(
|
||||
company_id, account_ids, partner_ids, only_posted_moves, date_from
|
||||
)
|
||||
ml_fields = self._get_ml_fields()
|
||||
move_lines = self.env["account.move.line"].search_read(
|
||||
domain=domain, fields=ml_fields
|
||||
)
|
||||
journals_ids = set()
|
||||
partners_ids = set()
|
||||
partners_data = {}
|
||||
if date_at_object < date.today():
|
||||
(
|
||||
acc_partial_rec,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
) = self._get_account_partial_reconciled(company_id, date_at_object)
|
||||
if acc_partial_rec:
|
||||
ml_ids = list(map(operator.itemgetter("id"), move_lines))
|
||||
debit_ids = list(
|
||||
map(operator.itemgetter("debit_move_id"), acc_partial_rec)
|
||||
)
|
||||
credit_ids = list(
|
||||
map(operator.itemgetter("credit_move_id"), acc_partial_rec)
|
||||
)
|
||||
move_lines = self._recalculate_move_lines(
|
||||
move_lines,
|
||||
debit_ids,
|
||||
credit_ids,
|
||||
debit_amount,
|
||||
credit_amount,
|
||||
ml_ids,
|
||||
account_ids,
|
||||
company_id,
|
||||
partner_ids,
|
||||
only_posted_moves,
|
||||
debit_amount_currency,
|
||||
credit_amount_currency,
|
||||
)
|
||||
move_lines = [
|
||||
move_line
|
||||
for move_line in move_lines
|
||||
if move_line["date"] <= date_at_object
|
||||
and not float_is_zero(move_line["amount_residual"], precision_digits=2)
|
||||
]
|
||||
|
||||
open_items_move_lines_data = {}
|
||||
for move_line in move_lines:
|
||||
journals_ids.add(move_line["journal_id"][0])
|
||||
acc_id = move_line["account_id"][0]
|
||||
# Partners data
|
||||
if move_line["partner_id"]:
|
||||
prt_id = move_line["partner_id"][0]
|
||||
prt_name = move_line["partner_id"][1]
|
||||
else:
|
||||
prt_id = 0
|
||||
prt_name = _("Missing Partner")
|
||||
if prt_id not in partners_ids:
|
||||
partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
|
||||
partners_ids.add(prt_id)
|
||||
|
||||
# Move line update
|
||||
original = 0
|
||||
|
||||
if not float_is_zero(move_line["credit"], precision_digits=2):
|
||||
original = move_line["credit"] * (-1)
|
||||
if not float_is_zero(move_line["debit"], precision_digits=2):
|
||||
original = move_line["debit"]
|
||||
|
||||
if move_line["ref"] == move_line["name"]:
|
||||
if move_line["ref"]:
|
||||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = ""
|
||||
elif not move_line["ref"]:
|
||||
ref_label = move_line["name"]
|
||||
elif not move_line["name"]:
|
||||
ref_label = move_line["ref"]
|
||||
else:
|
||||
ref_label = move_line["ref"] + " - " + move_line["name"]
|
||||
|
||||
move_line.update(
|
||||
{
|
||||
"date": move_line["date"],
|
||||
"date_maturity": move_line["date_maturity"]
|
||||
and move_line["date_maturity"].strftime("%d/%m/%Y"),
|
||||
"original": original,
|
||||
"partner_id": prt_id,
|
||||
"partner_name": prt_name,
|
||||
"ref_label": ref_label,
|
||||
"journal_id": move_line["journal_id"][0],
|
||||
"move_name": move_line["move_id"][1],
|
||||
"entry_id": move_line["move_id"][0],
|
||||
"currency_id": move_line["currency_id"][0]
|
||||
if move_line["currency_id"]
|
||||
else False,
|
||||
"currency_name": move_line["currency_id"][1]
|
||||
if move_line["currency_id"]
|
||||
else False,
|
||||
}
|
||||
)
|
||||
|
||||
# Open Items Move Lines Data
|
||||
if acc_id not in open_items_move_lines_data.keys():
|
||||
open_items_move_lines_data[acc_id] = {prt_id: [move_line]}
|
||||
else:
|
||||
if prt_id not in open_items_move_lines_data[acc_id].keys():
|
||||
open_items_move_lines_data[acc_id][prt_id] = [move_line]
|
||||
else:
|
||||
open_items_move_lines_data[acc_id][prt_id].append(move_line)
|
||||
journals_data = self._get_journals_data(list(journals_ids))
|
||||
accounts_data = self._get_accounts_data(open_items_move_lines_data.keys())
|
||||
return (
|
||||
move_lines,
|
||||
partners_data,
|
||||
journals_data,
|
||||
accounts_data,
|
||||
open_items_move_lines_data,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _calculate_amounts(self, open_items_move_lines_data):
|
||||
total_amount = {}
|
||||
for account_id in open_items_move_lines_data.keys():
|
||||
total_amount[account_id] = {}
|
||||
total_amount[account_id]["residual"] = 0.0
|
||||
for partner_id in open_items_move_lines_data[account_id].keys():
|
||||
total_amount[account_id][partner_id] = {}
|
||||
total_amount[account_id][partner_id]["residual"] = 0.0
|
||||
for move_line in open_items_move_lines_data[account_id][partner_id]:
|
||||
total_amount[account_id][partner_id]["residual"] += move_line[
|
||||
"amount_residual"
|
||||
]
|
||||
total_amount[account_id]["residual"] += move_line["amount_residual"]
|
||||
return total_amount
|
||||
|
||||
@api.model
|
||||
def _order_open_items_by_date(
|
||||
self,
|
||||
open_items_move_lines_data,
|
||||
show_partner_details,
|
||||
partners_data,
|
||||
accounts_data,
|
||||
):
|
||||
# We need to order by account code, partner_name and date
|
||||
accounts_data_sorted = sorted(accounts_data.items(), key=lambda x: x[1]["code"])
|
||||
account_ids_sorted = [account[0] for account in accounts_data_sorted]
|
||||
new_open_items = {}
|
||||
if not show_partner_details:
|
||||
for acc_id in account_ids_sorted:
|
||||
new_open_items[acc_id] = {}
|
||||
move_lines = []
|
||||
for prt_id in open_items_move_lines_data[acc_id]:
|
||||
for move_line in open_items_move_lines_data[acc_id][prt_id]:
|
||||
move_lines += [move_line]
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
new_open_items[acc_id] = move_lines
|
||||
else:
|
||||
for acc_id in account_ids_sorted:
|
||||
new_open_items[acc_id] = {}
|
||||
for prt_id in sorted(
|
||||
open_items_move_lines_data[acc_id],
|
||||
key=lambda i: partners_data[i]["name"],
|
||||
):
|
||||
new_open_items[acc_id][prt_id] = {}
|
||||
move_lines = []
|
||||
for move_line in open_items_move_lines_data[acc_id][prt_id]:
|
||||
move_lines += [move_line]
|
||||
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
|
||||
new_open_items[acc_id][prt_id] = move_lines
|
||||
return new_open_items
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
wizard_id = data["wizard_id"]
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
company_id = data["company_id"]
|
||||
account_ids = data["account_ids"]
|
||||
partner_ids = data["partner_ids"]
|
||||
date_at = data["date_at"]
|
||||
date_at_object = datetime.strptime(date_at, "%Y-%m-%d").date()
|
||||
date_from = data["date_from"]
|
||||
only_posted_moves = data["only_posted_moves"]
|
||||
show_partner_details = data["show_partner_details"]
|
||||
|
||||
(
|
||||
move_lines_data,
|
||||
partners_data,
|
||||
journals_data,
|
||||
accounts_data,
|
||||
open_items_move_lines_data,
|
||||
) = self._get_data(
|
||||
account_ids,
|
||||
partner_ids,
|
||||
date_at_object,
|
||||
only_posted_moves,
|
||||
company_id,
|
||||
date_from,
|
||||
)
|
||||
|
||||
total_amount = self._calculate_amounts(open_items_move_lines_data)
|
||||
open_items_move_lines_data = self._order_open_items_by_date(
|
||||
open_items_move_lines_data,
|
||||
show_partner_details,
|
||||
partners_data,
|
||||
accounts_data,
|
||||
)
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "open.items.report.wizard",
|
||||
"docs": self.env["open.items.report.wizard"].browse(wizard_id),
|
||||
"foreign_currency": data["foreign_currency"],
|
||||
"show_partner_details": data["show_partner_details"],
|
||||
"company_name": company.display_name,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_at": date_at_object.strftime("%d/%m/%Y"),
|
||||
"hide_account_at_0": data["hide_account_at_0"],
|
||||
"target_move": data["target_move"],
|
||||
"journals_data": journals_data,
|
||||
"partners_data": partners_data,
|
||||
"accounts_data": accounts_data,
|
||||
"total_amount": total_amount,
|
||||
"Open_Items": open_items_move_lines_data,
|
||||
}
|
||||
|
||||
def _get_ml_fields(self):
|
||||
return self.COMMON_ML_FIELDS + [
|
||||
"amount_residual",
|
||||
"reconciled",
|
||||
"currency_id",
|
||||
"credit",
|
||||
"date_maturity",
|
||||
"amount_residual_currency",
|
||||
"debit",
|
||||
"amount_currency",
|
||||
]
|
||||
216
account_financial_report/report/open_items_xlsx.py
Normal file
216
account_financial_report/report/open_items_xlsx.py
Normal file
@@ -0,0 +1,216 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class OpenItemsXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_open_items_xlsx"
|
||||
_description = "Open Items XLSX Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = _("Open Items")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
res = {
|
||||
0: {"header": _("Date"), "field": "date", "width": 11},
|
||||
1: {"header": _("Entry"), "field": "move_name", "width": 18},
|
||||
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: {
|
||||
"header": _("Original"),
|
||||
"field": "original",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
8: {
|
||||
"header": _("Residual"),
|
||||
"field": "amount_residual",
|
||||
"field_final_balance": "residual",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
if report.foreign_currency:
|
||||
foreign_currency = {
|
||||
9: {
|
||||
"header": _("Cur."),
|
||||
"field": "currency_name",
|
||||
"field_currency_balance": "currency_name",
|
||||
"type": "currency_name",
|
||||
"width": 7,
|
||||
},
|
||||
10: {
|
||||
"header": _("Cur. Original"),
|
||||
"field": "amount_currency",
|
||||
"field_final_balance": "amount_currency",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
11: {
|
||||
"header": _("Cur. Residual"),
|
||||
"field": "amount_residual_currency",
|
||||
"field_final_balance": "amount_currency",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
res = {**res, **foreign_currency}
|
||||
return res
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_("Date at filter"), report.date_at.strftime("%d/%m/%Y")],
|
||||
[
|
||||
_("Target moves filter"),
|
||||
_("All posted entries")
|
||||
if report.target_move == "posted"
|
||||
else _("All entries"),
|
||||
],
|
||||
[
|
||||
_("Account balance at 0 filter"),
|
||||
_("Hide") if report.hide_account_at_0 else _("Show"),
|
||||
],
|
||||
[
|
||||
_("Show foreign currency"),
|
||||
_("Yes") if report.foreign_currency else _("No"),
|
||||
],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.open_items"
|
||||
]._get_report_values(report, data)
|
||||
# For each account
|
||||
Open_items = res_data["Open_Items"]
|
||||
accounts_data = res_data["accounts_data"]
|
||||
partners_data = res_data["partners_data"]
|
||||
journals_data = res_data["journals_data"]
|
||||
total_amount = res_data["total_amount"]
|
||||
show_partner_details = res_data["show_partner_details"]
|
||||
for account_id in Open_items.keys():
|
||||
# Write account title
|
||||
self.write_array_title(
|
||||
accounts_data[account_id]["code"]
|
||||
+ " - "
|
||||
+ accounts_data[account_id]["name"],
|
||||
report_data,
|
||||
)
|
||||
|
||||
# For each partner
|
||||
if Open_items[account_id]:
|
||||
if show_partner_details:
|
||||
for partner_id in Open_items[account_id]:
|
||||
type_object = "partner"
|
||||
# Write partner title
|
||||
self.write_array_title(
|
||||
partners_data[partner_id]["name"], report_data
|
||||
)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# Display account move lines
|
||||
for line in Open_items[account_id][partner_id]:
|
||||
line.update(
|
||||
{
|
||||
"account": accounts_data[account_id]["code"],
|
||||
"journal": journals_data[line["journal_id"]][
|
||||
"code"
|
||||
],
|
||||
}
|
||||
)
|
||||
self.write_line_from_dict(line, report_data)
|
||||
|
||||
# Display ending balance line for partner
|
||||
partners_data[partner_id].update(
|
||||
{
|
||||
"currency_id": accounts_data[account_id]["currency_id"],
|
||||
"currency_name": accounts_data[account_id][
|
||||
"currency_name"
|
||||
],
|
||||
}
|
||||
)
|
||||
self.write_ending_balance_from_dict(
|
||||
partners_data[partner_id],
|
||||
type_object,
|
||||
total_amount,
|
||||
report_data,
|
||||
account_id=account_id,
|
||||
partner_id=partner_id,
|
||||
)
|
||||
|
||||
# Line break
|
||||
report_data["row_pos"] += 1
|
||||
else:
|
||||
# Display array header for move lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# Display account move lines
|
||||
for line in Open_items[account_id]:
|
||||
line.update(
|
||||
{
|
||||
"account": accounts_data[account_id]["code"],
|
||||
"journal": journals_data[line["journal_id"]]["code"],
|
||||
}
|
||||
)
|
||||
self.write_line_from_dict(line, report_data)
|
||||
|
||||
# Display ending balance line for account
|
||||
type_object = "account"
|
||||
self.write_ending_balance_from_dict(
|
||||
accounts_data[account_id],
|
||||
type_object,
|
||||
total_amount,
|
||||
report_data,
|
||||
account_id=account_id,
|
||||
)
|
||||
|
||||
# 2 lines break
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def write_ending_balance_from_dict(
|
||||
self,
|
||||
my_object,
|
||||
type_object,
|
||||
total_amount,
|
||||
report_data,
|
||||
account_id=False,
|
||||
partner_id=False,
|
||||
):
|
||||
"""Specific function to write ending balance for Open Items"""
|
||||
if type_object == "partner":
|
||||
name = my_object["name"]
|
||||
my_object["residual"] = total_amount[account_id][partner_id]["residual"]
|
||||
label = _("Partner ending balance")
|
||||
elif type_object == "account":
|
||||
name = my_object["code"] + " - " + my_object["name"]
|
||||
my_object["residual"] = total_amount[account_id]["residual"]
|
||||
label = _("Ending balance")
|
||||
return super().write_ending_balance_from_dict(
|
||||
my_object, name, label, report_data
|
||||
)
|
||||
@@ -0,0 +1,811 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="aged_partner_balance">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_base"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="show_move_line_details" t-value="show_move_line_details" />
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">
|
||||
Aged Partner Balance -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<div class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-esc="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_filters" />
|
||||
<t t-foreach="aged_partner_balance" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<div class="act_as_caption account_title" style="width: 100%;">
|
||||
<span t-esc="account['code']" />
|
||||
-
|
||||
<span t-esc="account['name']" />
|
||||
</div>
|
||||
<!-- Display account lines -->
|
||||
<t t-if="not show_move_line_details">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display account header -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_lines_header"
|
||||
/>
|
||||
<t t-foreach="account['partners']" t-as="partner">
|
||||
<!-- Display one line per partner -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_lines"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!-- Display account footer -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_account_ending_cumul"
|
||||
/>
|
||||
</t>
|
||||
<!-- Display account move lines -->
|
||||
<t t-if="show_move_line_details">
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="account['partners']" t-as="partner">
|
||||
<div class="page_break">
|
||||
<!-- Display partner header -->
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-esc="partner['name']" />
|
||||
</div>
|
||||
<!-- Display partner move lines -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_move_lines"
|
||||
/>
|
||||
<!-- Display partner footer -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_partner_ending_cumul"
|
||||
>
|
||||
<t t-set="partner_cumul_line" t-value="partner" />
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<!-- Display account footer -->
|
||||
<t
|
||||
t-call="account_financial_report.report_aged_partner_balance_account_ending_cumul"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_filters">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date at filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="date_at" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="only_posted_moves">All posted entries</t>
|
||||
<t t-if="not only_posted_moves">All entries</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_lines_header">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 32.52%;">Partner</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">Residual</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">Not due</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">1 - 30 d.</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">31 - 60 d.</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">61 - 90 d.</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">91 - 120 d.</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell" style="width: 9.64%;">> 120 d.</div>
|
||||
</t>
|
||||
<!--## dynamic columns-->
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell">
|
||||
<span t-out="column_dynamic.name" />
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_lines">
|
||||
<!-- Display each partner lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-esc="partner['name']" />
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-out="partner[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_move_lines">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display table headers for move lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 6.00%;">
|
||||
Date
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 7.00%;">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 5.00%;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">Account</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 10.50%;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 18.00%;">
|
||||
Ref -
|
||||
Label
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Due
|
||||
date
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">Residual</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">Current</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Age ≤ 30
|
||||
d.
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Age ≤ 60
|
||||
d.
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Age ≤ 90
|
||||
d.
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">
|
||||
Age ≤ 120
|
||||
d.
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell" style="width: 6.00%;">Older</div>
|
||||
</t>
|
||||
<!--## current-->
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="column_dynamic.name" />
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Display each move lines -->
|
||||
<t t-foreach="partner['move_lines']" t-as="line">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].id"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<!--## We don't use t-field because it throws an error on click -->
|
||||
<t t-esc="line['date']" t-options="{'widget': 'date'}" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].move_id.id"
|
||||
res-model="account.move"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['entry']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].move_id.journal_id.id"
|
||||
res-model="account.journal"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['journal']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].account_id.id"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['account']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## 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>
|
||||
<!--## 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>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['line_rec'].id"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<!--## We don't use t-field because it throws an error on click -->
|
||||
<t
|
||||
t-esc="line['due_date']"
|
||||
t-options="{'widget': 'date'}"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['current'] == 0">
|
||||
<span
|
||||
t-esc="line['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['30_days'] == 0">
|
||||
<span
|
||||
t-esc="line['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['60_days'] == 0">
|
||||
<span
|
||||
t-esc="line['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['90_days'] == 0">
|
||||
<span
|
||||
t-esc="line['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['120_days'] == 0">
|
||||
<span
|
||||
t-esc="line['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['older'] == 0">
|
||||
<span
|
||||
t-esc="line['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line[column_dynamic] == 0">
|
||||
<span
|
||||
t-esc="line[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
domain="[('id', 'in', (line['line_rec'] | line['line_rec'].matched_debit_ids.mapped('debit_move_id') | line['line_rec'].matched_credit_ids.mapped('credit_move_id')).ids)]"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="line[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_partner_ending_cumul">
|
||||
<!-- Display ending balance line for partner -->
|
||||
<div class="act_as_table list_table" style="width: 100%;">
|
||||
<div class="act_as_row lines" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell right" style="width: 52.00%;">
|
||||
Partner
|
||||
cumul aged balance
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.00%;" />
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%;">
|
||||
<span
|
||||
t-esc="partner_cumul_line['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="partner_cumul_line[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="report_aged_partner_balance_account_ending_cumul">
|
||||
<!-- Display ending balance line for account -->
|
||||
<div class="act_as_table list_table" style="width: 100%;">
|
||||
<div class="act_as_row lines" style="font-weight: bold;">
|
||||
<t t-if="not show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 32.52%;">Total</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span
|
||||
t-esc="account['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="account[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 52.00%;">Total</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.00%;" />
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['current']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['30_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['60_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['90_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['120_days']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span
|
||||
t-esc="account['older']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="account[column_dynamic]"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_row" style="font-weight: bold; font-style: italic;">
|
||||
<t t-if="not show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 32.52%;">Percents</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;" />
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_current']" />
|
||||
%
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_30_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_60_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_90_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_120_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 9.64%;">
|
||||
<span t-esc="account['percent_older']" />
|
||||
%
|
||||
</div>
|
||||
</t>
|
||||
<!--## current-->
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span t-esc="account['percent_'+str(column_dynamic.id)]" />
|
||||
%
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 52.00%;">Percents</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.00%;" />
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%" />
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_current']" />
|
||||
%
|
||||
</div>
|
||||
<t t-if="not age_partner_config">
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_30_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_60_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_90_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_120_days']" />
|
||||
%
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 6.00%">
|
||||
<span t-esc="account['percent_older']" />
|
||||
%
|
||||
</div>
|
||||
</t>
|
||||
<!--## current-->
|
||||
<t t-foreach="age_partner_config.line_ids" t-as="column_dynamic">
|
||||
<div class="act_as_cell amount">
|
||||
<span t-esc="account['percent_'+str(column_dynamic.id)]" />
|
||||
%
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
783
account_financial_report/report/templates/general_ledger.xml
Normal file
783
account_financial_report/report/templates/general_ledger.xml
Normal file
@@ -0,0 +1,783 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="general_ledger">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_general_ledger_base" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="report_general_ledger_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="foreign_currency" t-value="foreign_currency" />
|
||||
<t t-set="filter_partner_ids" t-value="filter_partner_ids" />
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">
|
||||
General Ledger -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<div class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-out="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_general_ledger_filters" />
|
||||
<t t-foreach="general_ledger" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<div class="act_as_caption account_title" style="width: 100%">
|
||||
<span t-out="account['code']" />
|
||||
-
|
||||
<span t-out="account['name']" />
|
||||
</div>
|
||||
<t t-if="'list_grouped' not in account">
|
||||
<!-- Display account move lines without partner regroup -->
|
||||
<t t-set="type" t-value='"account_type"' />
|
||||
<t
|
||||
t-call="account_financial_report.report_general_ledger_lines"
|
||||
>
|
||||
<t t-set="account_or_group_item_object" t-value="account" />
|
||||
</t>
|
||||
<!-- Display account footer -->
|
||||
<t
|
||||
t-call="account_financial_report.report_general_ledger_ending_cumul"
|
||||
>
|
||||
<t t-set="account_or_group_item_object" t-value="account" />
|
||||
<t t-set="type" t-value='"account_type"' />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="'list_grouped' in account">
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="account['list_grouped']" t-as="group_item">
|
||||
<t t-set="type" t-value='"grouped_type"' />
|
||||
<div class="page_break">
|
||||
<!-- Display partner header -->
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-out="group_item['name']" />
|
||||
</div>
|
||||
<!-- Display partner move lines -->
|
||||
<t
|
||||
t-call="account_financial_report.report_general_ledger_lines"
|
||||
>
|
||||
<t
|
||||
t-set="account_or_group_item_object"
|
||||
t-value="group_item"
|
||||
/>
|
||||
</t>
|
||||
<!-- Display partner footer -->
|
||||
<t
|
||||
t-call="account_financial_report.report_general_ledger_ending_cumul"
|
||||
>
|
||||
<t
|
||||
t-set="account_or_group_item_object"
|
||||
t-value="group_item"
|
||||
/>
|
||||
<t t-set="type" t-value='"grouped_type"' />
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<!-- Display account footer -->
|
||||
<t t-if="not filter_partner_ids">
|
||||
<t
|
||||
t-call="account_financial_report.report_general_ledger_ending_cumul"
|
||||
>
|
||||
<t
|
||||
t-set="account_or_group_item_object"
|
||||
t-value="account"
|
||||
/>
|
||||
<t t-set="type" t-value='"account_type"' />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_general_ledger_filters">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date range filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account balance at 0 filter</div>
|
||||
<div class="act_as_cell">Centralize filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
From:
|
||||
<span t-out="date_from" />
|
||||
To:
|
||||
<span t-out="date_to" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="only_posted_moves">All posted entries</t>
|
||||
<t t-if="not only_posted_moves">All entries</t>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="hide_account_at_0">Hide</t>
|
||||
<t t-if="not hide_account_at_0">Show</t>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="centralize">Yes</t>
|
||||
<t t-if="not centralize">No</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_general_ledger_lines">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 3.51%;">
|
||||
Date
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 8.03%">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 4.13%;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 4.75%;">Account</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 8.89%;">Taxes</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 12.01%;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 16.9%;">
|
||||
Ref -
|
||||
Label
|
||||
</div>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell" style="width: 8.03%;">
|
||||
Analytic Distribution
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_analytic_tags">
|
||||
<!--## analytic tags-->
|
||||
<div class="act_as_cell" style="width: 4.75%;">Tags</div>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell" style="width: 2.41%;">Rec.</div>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">Debit</div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">Credit</div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">
|
||||
Cumul. Bal.
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<!--## amount_currency-->
|
||||
<div
|
||||
class="act_as_cell amount"
|
||||
style="width: 3.63%;"
|
||||
>Amount cur.
|
||||
</div>
|
||||
<!--## amount_currency cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">Cumul cur.
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Display first line with initial balance -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## taxes-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if='type == "account_type"'>Initial balance</t>
|
||||
<t t-if='type == "grouped_type"'>
|
||||
<t t-if="'partners' in account">Partner initial balance</t>
|
||||
<t t-if="'taxes' in account">Tax initial balance</t>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
<t t-if="show_analytic_tags">
|
||||
<!--## analytic tags-->
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell" />
|
||||
<t
|
||||
t-set="misc_domain"
|
||||
t-value="[('account_id', '=', account['id']),('date', '<', date_from)]"
|
||||
/>
|
||||
<t
|
||||
t-set="misc_grouped_domain"
|
||||
t-value="[('partner_id', '=', account_or_group_item_object['id'])]"
|
||||
t-if="'partners' in account"
|
||||
/>
|
||||
<t t-set="misc_grouped_domain" t-value="[]" t-else="" />
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-set="debit_domain" t-value="[('debit', '<>', 0)]" />
|
||||
<t t-if="type == 'account_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+debit_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+debit_domain+misc_grouped_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-set="credit_domain" t-value="[('credit', '<>', 0)]" />
|
||||
<t t-if="type == 'account_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+credit_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+credit_domain+misc_grouped_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="type == 'account_type'">
|
||||
<span t-att-domain="misc_domain" res-model="account.move.line">
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+misc_grouped_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<t t-if="account['currency_id']">
|
||||
<t
|
||||
t-set="account_currency"
|
||||
t-value="currency_model.browse(account['currency_id'])"
|
||||
/>
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<t t-if="type == 'account_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+misc_grouped_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<t t-if="type == 'account_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span
|
||||
t-att-domain="misc_domain+misc_grouped_domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['init_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not account['currency_id']">
|
||||
<div class="act_as_cell" style="width: 3.63%;" />
|
||||
<div class="act_as_cell" style="width: 3.63%;" />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<!-- Display each lines -->
|
||||
<t t-set="total_bal_curr" t-value="0" />
|
||||
<t t-foreach="account_or_group_item_object['move_lines']" t-as="line">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['id']">
|
||||
<!--## We don't use t-field because it throws an error on click -->
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="line['date']"
|
||||
t-options="{'widget': 'date'}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>
|
||||
<!--## We don't use t-field because it throws an error on click -->
|
||||
<t
|
||||
t-out="line['date']"
|
||||
t-options="{'widget': 'date'}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['entry_id']">
|
||||
<span
|
||||
t-att-res-id="line['entry_id']"
|
||||
res-model="account.move"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['entry']" />
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['journal_id']"
|
||||
res-model="account.journal"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="o._get_atr_from_dict(line['journal_id'], journals_data, 'code')"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="account['id']"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="account['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## taxes-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="taxes_data and line['tax_ids']">
|
||||
<t t-foreach="line['tax_ids']" t-as="tax_id">
|
||||
<span
|
||||
t-out="o._get_atr_from_dict(tax_id, taxes_data, 'tax_name')"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="line['tax_line_id']">
|
||||
<span t-out="line['tax_line_id'][1]" />
|
||||
</t>
|
||||
</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['partner_id']">
|
||||
<span
|
||||
t-att-res-id="line['partner_id']"
|
||||
res-model="res.partner"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['partner_name']" />
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['id']">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['ref_label']" />
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>
|
||||
<t t-out="line['ref_label']" />
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## cost_center-->
|
||||
<t t-if="show_cost_center">
|
||||
<div class="act_as_cell left">
|
||||
<t
|
||||
t-foreach="line['analytic_distribution']"
|
||||
t-as="analytic_id"
|
||||
>
|
||||
<div>
|
||||
<span
|
||||
t-att-res-id="analytic_id"
|
||||
res-model="account.analytic.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="o._get_atr_from_dict(int(analytic_id), analytic_data, 'name')"
|
||||
/>
|
||||
<t
|
||||
t-if="int(line['analytic_distribution'][analytic_id]) < 100"
|
||||
>
|
||||
<t
|
||||
t-out="int(line['analytic_distribution'][analytic_id])"
|
||||
/>%
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_analytic_tags">
|
||||
<!--## analytic tags-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-if="line['tag_ids']">
|
||||
<t t-foreach="line['tag_ids']" t-as="tag_id">
|
||||
<span
|
||||
t-out="o._get_atr_from_dict(tag_id, tags_data, 'name')"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell">
|
||||
<t t-if="line['rec_id']">
|
||||
<span
|
||||
t-att-res-id="line['rec_id']"
|
||||
res-model="account.full.reconcile"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="line['rec_name']" />
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['id']">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="line['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>
|
||||
<t
|
||||
t-out="line['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['id']">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="line['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>
|
||||
<t
|
||||
t-out="line['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount">
|
||||
<t t-if="line['id']">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="line['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>
|
||||
<t
|
||||
t-out="line['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<t t-if="line['currency_id']">
|
||||
<t
|
||||
t-set="line_currency"
|
||||
t-value="currency_model.browse(line['currency_id'][0])"
|
||||
/>
|
||||
<t
|
||||
t-set="total_bal_curr"
|
||||
t-value="total_bal_curr + line['bal_curr']"
|
||||
t-if="line_currency!=company_currency"
|
||||
/>
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
t-out="line['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': line_currency}"
|
||||
t-if="line_currency!=company_currency"
|
||||
/>
|
||||
</div>
|
||||
<!--## amount_currency cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<span
|
||||
t-att-res-id="line['id']"
|
||||
res-model="account.move.line"
|
||||
view-type="form"
|
||||
t-out="total_bal_curr"
|
||||
t-options="{'widget': 'monetary', 'display_currency': line_currency}"
|
||||
t-if="line_currency!=company_currency"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not line['currency_id']">
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount" style="width: 3.63%;" />
|
||||
<!--## amount_currency cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 3.63%;" />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_general_ledger_ending_cumul">
|
||||
<!-- Display ending balance line for account or partner -->
|
||||
<div class="act_as_table list_table" style="width: 100%;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<t t-if='type == "account_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 41.32%;">
|
||||
<span t-out="account['code']" />
|
||||
-
|
||||
<span t-out="account['name']" />
|
||||
</div>
|
||||
<div class="act_as_cell right" style="width: 16.9%;">Ending balance
|
||||
</div>
|
||||
</t>
|
||||
<t t-if='type == "grouped_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 41.32%;" />
|
||||
<div class="act_as_cell right" style="width: 16.9%;">
|
||||
<t t-if="'partners' in account">Partner ending balance</t>
|
||||
<t t-if="'taxes' in account">Tax ending balance</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell" style="width: 8.03%" />
|
||||
</t>
|
||||
<t t-if="show_analytic_tags">
|
||||
<!--## analytic tags-->
|
||||
<div class="act_as_cell" style="width: 4.75%;" />
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell" style="width: 2.41%;" />
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">
|
||||
<span
|
||||
t-out="account_or_group_item_object['fin_bal']['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">
|
||||
<span
|
||||
t-out="account_or_group_item_object['fin_bal']['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 8.02%;">
|
||||
<span
|
||||
t-out="account_or_group_item_object['fin_bal']['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': company_currency}"
|
||||
/>
|
||||
</div>
|
||||
<!--## currency_name + amount_currency-->
|
||||
<t
|
||||
t-set="misc_domain"
|
||||
t-value="[('account_id', '=', account['id']),('date', '<', date_from)]"
|
||||
/>
|
||||
<t
|
||||
t-set="misc_grouped_domain"
|
||||
t-value="[('partner_id', '=', account_or_group_item_object['id'])]"
|
||||
t-if="'partners' in account"
|
||||
/>
|
||||
<t t-set="misc_grouped_domain" t-value="[]" t-else="" />
|
||||
<t t-if="foreign_currency">
|
||||
<t t-if="account['fin_bal_currency_id']">
|
||||
<t
|
||||
t-set="account_currency"
|
||||
t-value="currency_model.browse(account['fin_bal_currency_id'])"
|
||||
/>
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<t t-if="type == 'account_type'">
|
||||
<span>
|
||||
<a
|
||||
t-att-data-t-att-domain="misc_domain"
|
||||
t-att-data-res-model="'account.move.line'"
|
||||
class="o_account_financial_reports_web_action_monetary_multi"
|
||||
style="color: black;"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['fin_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span>
|
||||
<a
|
||||
t-att-data-t-att-domain="misc_domain+misc_grouped_domain"
|
||||
t-att-data-res-model="'account.move.line'"
|
||||
class="o_account_financial_reports_web_action_monetary_multi"
|
||||
style="color: black;"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['fin_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 3.63%;">
|
||||
<t t-if="type == 'account_type'">
|
||||
<span>
|
||||
<a
|
||||
t-att-data-t-att-domain="misc_domain"
|
||||
t-att-data-res-model="'account.move.line'"
|
||||
class="o_account_financial_reports_web_action_monetary_multi"
|
||||
style="color: black;"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['fin_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="type == 'grouped_type'">
|
||||
<span>
|
||||
<a
|
||||
t-att-data-t-att-domain="misc_domain+misc_grouped_domain"
|
||||
t-att-data-res-model="'account.move.line'"
|
||||
class="o_account_financial_reports_web_action_monetary_multi"
|
||||
style="color: black;"
|
||||
>
|
||||
<t
|
||||
t-out="account_or_group_item_object['fin_bal']['bal_curr']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': account_currency}"
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not account['currency_id']">
|
||||
<div class="act_as_cell amount" style="width: 3.63%;" />
|
||||
<div class="act_as_cell amount" style="width: 3.63%;" />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
511
account_financial_report/report/templates/journal_ledger.xml
Normal file
511
account_financial_report/report/templates/journal_ledger.xml
Normal file
@@ -0,0 +1,511 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2018 ForgeFlow S.L.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<template id="journal_ledger">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_journal_ledger_base" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="report_journal_ledger_base">
|
||||
<t t-set="with_auto_sequence" t-value="with_auto_sequence" />
|
||||
<t t-set="display_currency" t-value="foreign_currency" />
|
||||
<t t-set="display_account_name" t-value="with_account_name" />
|
||||
<t t-set="title">
|
||||
Journal Ledger -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<t t-set="company_name" t-value="Company_Name" />
|
||||
<div class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-esc="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="group_option == 'none'">
|
||||
<div class="page_break">
|
||||
<t t-call="account_financial_report.report_journal_all" />
|
||||
<br />
|
||||
<t t-call="account_financial_report.report_journal_all_taxes" />
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="group_option == 'journal'">
|
||||
<t t-foreach="Journal_Ledgers" t-as="journal">
|
||||
<div class="page_break">
|
||||
<t
|
||||
t-call="account_financial_report.report_journal_ledger_journal"
|
||||
/>
|
||||
<br />
|
||||
<t
|
||||
t-call="account_financial_report.report_journal_ledger_journal_taxes"
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_all">
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<t
|
||||
t-call="account_financial_report.report_journal_ledger_journal_table_header"
|
||||
/>
|
||||
<t t-foreach="Moves" t-as="move">
|
||||
<t t-call="account_financial_report.report_journal_move" />
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_ledger_journal">
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<div class="act_as_caption account_title" style="width: 100%;">
|
||||
<span t-esc="journal['name']" />
|
||||
(
|
||||
<span t-esc="journal['currency_name']" />
|
||||
) -
|
||||
<span t-esc="date_from" t-options="{'widget': 'date'}" />
|
||||
to
|
||||
<span t-esc="date_to" t-options="{'widget': 'date'}" />
|
||||
-
|
||||
<span t-esc="move_target" />
|
||||
Moves
|
||||
</div>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<t
|
||||
t-call="account_financial_report.report_journal_ledger_journal_table_header"
|
||||
/>
|
||||
<t
|
||||
t-call="account_financial_report.report_journal_ledger_journal_first_line"
|
||||
/>
|
||||
<t t-foreach="journal['report_moves']" t-as="move">
|
||||
<t t-call="account_financial_report.report_journal_move" />
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_ledger_journal_table_header">
|
||||
<t t-if="not display_account_name">
|
||||
<t t-set="account_column_style">width: 8.11%;</t>
|
||||
<t t-if="not with_auto_sequence">
|
||||
<t t-set="label_column_style">
|
||||
width: 38.92%;
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-set="label_column_style">
|
||||
width: 31.35%;
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="not with_auto_sequence">
|
||||
<t t-set="account_column_style">
|
||||
width: 23.78%;
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-set="account_column_style">
|
||||
width: 16.21%;
|
||||
</t>
|
||||
</t>
|
||||
<t t-set="label_column_style">width: 23.24%;</t>
|
||||
</t>
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<t t-if="with_auto_sequence">
|
||||
<div
|
||||
class="act_as_cell first_column"
|
||||
name="entry"
|
||||
style="width: 7.57%;"
|
||||
>
|
||||
Sequence
|
||||
</div>
|
||||
</t>
|
||||
<div
|
||||
t-att-class="'act_as_cell' if with_auto_sequence else 'act_as_cell first_column'"
|
||||
class="act_as_cell"
|
||||
name="entry"
|
||||
style="width: 7.57%;"
|
||||
>
|
||||
Entry
|
||||
</div>
|
||||
<div class="act_as_cell" name="date" style="width: 5.41%;">Date</div>
|
||||
<div
|
||||
class="act_as_cell"
|
||||
name="account"
|
||||
t-att-style="account_column_style"
|
||||
>
|
||||
Account
|
||||
</div>
|
||||
<div class="act_as_cell" name="partner" style="width: 15.14%;">
|
||||
Partner
|
||||
</div>
|
||||
<div class="act_as_cell" name="label" t-att-style="label_column_style">
|
||||
Ref - Label
|
||||
</div>
|
||||
<div class="act_as_cell" name="taxes" style="width: 7.57%;">Taxes</div>
|
||||
<div class="act_as_cell" name="debit" style="width: 8.65%;">Debit</div>
|
||||
<div class="act_as_cell" name="credit" style="width: 8.65%;">
|
||||
Credit
|
||||
</div>
|
||||
<t t-if="display_currency">
|
||||
<div class="act_as_cell" name="currency_name" style="width: 2.16%;">
|
||||
Cur.
|
||||
</div>
|
||||
<div
|
||||
class="act_as_cell"
|
||||
name="amount_currency"
|
||||
style="width: 6.49%;"
|
||||
>
|
||||
Amount Cur.
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_ledger_journal_first_line">
|
||||
<div class="act_as_row lines">
|
||||
<t t-if="with_auto_sequence">
|
||||
<div class="act_as_cell" name="Sequence" />
|
||||
</t>
|
||||
<div class="act_as_cell" name="entry" />
|
||||
<div class="act_as_cell" name="date" />
|
||||
<div class="act_as_cell" name="account" />
|
||||
<div class="act_as_cell" name="partner" />
|
||||
<div class="act_as_cell" name="label" />
|
||||
<div class="act_as_cell" name="taxes" />
|
||||
<div class="act_as_cell amount" name="debit">
|
||||
<b>
|
||||
<span
|
||||
t-esc="journal['debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</b>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="credit">
|
||||
<b>
|
||||
<span
|
||||
t-esc="journal['credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</b>
|
||||
</div>
|
||||
<t t-if="display_currency">
|
||||
<div class="act_as_cell" name="currency_name" />
|
||||
<div class="act_as_cell amount" name="amount_currency" />
|
||||
</t>
|
||||
</div>
|
||||
<div style="width: 100%" />
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_move">
|
||||
<t t-set="display_move_info" t-value="True" />
|
||||
<t t-set="last_partner" t-eval="None" />
|
||||
<t t-set="display_partner" t-eval="True" />
|
||||
<t t-foreach="move['report_move_lines']" t-as="move_line">
|
||||
<div class="act_as_row lines">
|
||||
<t
|
||||
t-set="current_partner"
|
||||
t-value="o._get_partner_name(move_line['partner_id'], partner_ids_data)"
|
||||
/>
|
||||
<t t-set="display_partner" t-value="current_partner != last_partner" />
|
||||
<t t-call="account_financial_report.report_journal_move_line" />
|
||||
<t t-set="last_partner" t-value="current_partner" />
|
||||
<t t-set="display_move_info" t-value="False" />
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_move_line">
|
||||
<div class="act_as_cell left" name="auto_sequence" t-if="with_auto_sequence">
|
||||
<span t-if="display_move_info" t-esc="move_line['auto_sequence']" />
|
||||
</div>
|
||||
<div class="act_as_cell left" name="entry">
|
||||
<t t-if="display_move_info">
|
||||
<span
|
||||
t-att-res-id="move_line['move_id']"
|
||||
res-model="account.move"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-esc="o._get_atr_from_dict(move_line['move_id'], move_ids_data, 'entry')"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_cell left" name="date">
|
||||
<span
|
||||
t-if="display_move_info"
|
||||
t-esc="move_line['date']"
|
||||
t-options="{'widget': 'date'}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell left" name="account">
|
||||
<span
|
||||
t-esc="o._get_atr_from_dict(move_line['account_id'], account_ids_data, 'code')"
|
||||
/>
|
||||
<span t-if="display_account_name">
|
||||
-
|
||||
<span
|
||||
t-esc="o._get_atr_from_dict(move_line['account_id'], account_ids_data, 'name')"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_cell left" name="partner">
|
||||
<span
|
||||
t-if="display_partner"
|
||||
t-esc="o._get_partner_name(move_line['partner_id'], partner_ids_data)"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell left" name="label">
|
||||
<span t-if="move_line['label']" t-esc="move_line['label']" />
|
||||
<span t-if="not move_line['label']">/</span>
|
||||
</div>
|
||||
<div class="act_as_cell left" name="taxes">
|
||||
<t
|
||||
t-set="tax_line_dat"
|
||||
t-value="o._get_data_from_dict(move_line['tax_line_id'], tax_line_data)"
|
||||
/>
|
||||
<t
|
||||
t-set="move_line_ids_taxes_dat"
|
||||
t-value="o._get_data_from_dict(move_line['move_line_id'], move_line_ids_taxes_data)"
|
||||
/>
|
||||
<span
|
||||
t-esc="o._get_ml_tax_description(move_line, tax_line_dat, move_line_ids_taxes_dat)"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="debit">
|
||||
<t t-if="move_line['debit']">
|
||||
<span
|
||||
t-esc="move_line['debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="credit">
|
||||
<t t-if="move_line['credit']">
|
||||
<span
|
||||
t-esc="move_line['credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="display_currency">
|
||||
<div class="act_as_cell" name="currency_name">
|
||||
<t t-if="move_line['currency_id']">
|
||||
<span
|
||||
t-esc="currency_ids_data.get(move_line['currency_id'], '').get('name', '')"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="amount_currency">
|
||||
<t t-if="move_line['amount_currency']">
|
||||
<span
|
||||
t-esc="move_line['amount_currency']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_ledger_journal_taxes">
|
||||
<b>Taxes summary</b>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<div
|
||||
class="act_as_cell first_column"
|
||||
name="name"
|
||||
style="width: 30.97%;"
|
||||
>
|
||||
Name
|
||||
</div>
|
||||
<div class="act_as_cell" name="description" style="width: 13.27%;">
|
||||
Description
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_amount" style="width: 27.88%;">
|
||||
Base Amount
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_amount" style="width: 27.88%;">
|
||||
Tax Amount
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div
|
||||
class="act_as_cell first_column"
|
||||
name="name"
|
||||
style="width: 30.97%;"
|
||||
/>
|
||||
<div class="act_as_cell" name="description" style="width: 13.27%;" />
|
||||
<div class="act_as_cell" name="base_debit" style="width: 9.29%;">
|
||||
Debit
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_credit" style="width: 9.29%;">
|
||||
Credit
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_balance" style="width: 9.29%;">
|
||||
Balance
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_debit" style="width: 9.29%;">
|
||||
Debit
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_credit" style="width: 9.29%;">
|
||||
Credit
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_balance" style="width: 9.29%;">
|
||||
Balance
|
||||
</div>
|
||||
</div>
|
||||
<t t-foreach="journal['tax_lines']" t-as="tax_line">
|
||||
<div class="act_as_row lines">
|
||||
<div class="act_as_cell left" name="tax_name">
|
||||
<span t-esc="tax_line['tax_name']" />
|
||||
</div>
|
||||
<div class="act_as_cell left" name="tax_code">
|
||||
<span t-esc="tax_line['tax_code']" />
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_debit">
|
||||
<span
|
||||
t-esc="tax_line['base_debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_credit">
|
||||
<span
|
||||
t-esc="tax_line['base_credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_balance">
|
||||
<span
|
||||
t-esc="tax_line['base_balance']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_debit">
|
||||
<span
|
||||
t-esc="tax_line['tax_debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_credit">
|
||||
<span
|
||||
t-esc="tax_line['tax_credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_balance">
|
||||
<span
|
||||
t-esc="tax_line['tax_balance']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_journal_all_taxes">
|
||||
<b>Taxes summary</b>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<div
|
||||
class="act_as_cell first_column"
|
||||
name="name"
|
||||
style="width: 30.97%;"
|
||||
>
|
||||
Name
|
||||
</div>
|
||||
<div class="act_as_cell" name="description" style="width: 13.27%;">
|
||||
Description
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_amount" style="width: 27.88%;">
|
||||
Base Amount
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_amount" style="width: 27.88%;">
|
||||
Tax Amount
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
10
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell first_column" name="name" style="width: 30.97%;" />
|
||||
<div class="act_as_cell" name="description" style="width: 13.27%;" />
|
||||
<div class="act_as_cell" name="base_debit" style="width: 9.29%;">
|
||||
Debit
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_credit" style="width: 9.29%;">
|
||||
Credit
|
||||
</div>
|
||||
<div class="act_as_cell" name="base_balance" style="width: 9.29%;">
|
||||
Balance
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_debit" style="width: 9.29%;">
|
||||
Debit
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_credit" style="width: 9.29%;">
|
||||
Credit
|
||||
</div>
|
||||
<div class="act_as_cell" name="tax_balance" style="width: 9.29%;">
|
||||
Balance
|
||||
</div>
|
||||
</div>
|
||||
<t t-foreach="ReportTaxLines" t-as="tax_line">
|
||||
<div class="act_as_row lines">
|
||||
<div class="act_as_cell left" name="tax_name">
|
||||
<span t-esc="tax_line['tax_name']" />
|
||||
</div>
|
||||
<div class="act_as_cell left" name="tax_code">
|
||||
<span t-esc="tax_line['tax_code']" />
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_debit">
|
||||
<span
|
||||
t-esc="tax_line['base_debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_credit">
|
||||
<span
|
||||
t-esc="tax_line['base_credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="base_balance">
|
||||
<span
|
||||
t-esc="tax_line['base_balance']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_debit">
|
||||
<span
|
||||
t-esc="tax_line['tax_debit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_credit">
|
||||
<span
|
||||
t-esc="tax_line['tax_credit']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" name="tax_balance">
|
||||
<span
|
||||
t-esc="tax_line['tax_balance']"
|
||||
t-options="{'widget': 'float', 'precision': 2}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
36
account_financial_report/report/templates/layouts.xml
Normal file
36
account_financial_report/report/templates/layouts.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="account_financial_report.html_container">
|
||||
<t t-call-assets="web.assets_backend" />
|
||||
<t t-set="body_classname" t-value="'container'" />
|
||||
<t t-call="web.report_layout">
|
||||
<t t-out="0" />
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.internal_layout">
|
||||
<div class="article o_account_financial_reports_page">
|
||||
<t t-call-assets="web.assets_backend" />
|
||||
<t t-out="0" />
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="row">
|
||||
<div class="col-6 custom_footer">
|
||||
<span
|
||||
t-out="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6 text-right custom_footer">
|
||||
<ul class="list-inline">
|
||||
<li class="list-inline-item">
|
||||
<span class="page" />
|
||||
</li>
|
||||
<li class="list-inline-item">/</li>
|
||||
<li class="list-inline-item">
|
||||
<span class="topage" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
328
account_financial_report/report/templates/open_items.xml
Normal file
328
account_financial_report/report/templates/open_items.xml
Normal file
@@ -0,0 +1,328 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="open_items">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_open_items_base" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.report_open_items_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="foreign_currency" t-value="foreign_currency" />
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">
|
||||
Open Items -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<t t-set="company_name" t-value="Company_Name" />
|
||||
<div class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-esc="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_open_items_filters" />
|
||||
<t t-foreach="Open_Items.keys()" t-as="account_id">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<div class="account_title" style="width: 100%;">
|
||||
<span t-esc="accounts_data[account_id]['code']" />
|
||||
-
|
||||
<span t-esc="accounts_data[account_id]['name']" />
|
||||
</div>
|
||||
<t t-if="not show_partner_details">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<t
|
||||
t-call="account_financial_report.report_open_items_lines_header"
|
||||
/>
|
||||
<!-- Display account move lines -->
|
||||
<t t-foreach="Open_Items[account_id]" t-as="line">
|
||||
<t
|
||||
t-call="account_financial_report.report_open_items_lines"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<div class="page_break">
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="Open_Items[account_id]" t-as="partner_id">
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-esc="partners_data[partner_id]['name']" />
|
||||
</div>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display partner header -->
|
||||
<t
|
||||
t-call="account_financial_report.report_open_items_lines_header"
|
||||
/>
|
||||
<!-- Display partner move lines -->
|
||||
<t
|
||||
t-foreach="Open_Items[account_id][partner_id]"
|
||||
t-as="line"
|
||||
>
|
||||
<t
|
||||
t-call="account_financial_report.report_open_items_lines"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<t
|
||||
t-call="account_financial_report.report_open_items_ending_cumul"
|
||||
>
|
||||
<t
|
||||
t-set="account_or_partner_id"
|
||||
t-value="partners_data[partner_id]"
|
||||
/>
|
||||
<t
|
||||
t-set="currency_id"
|
||||
t-value="accounts_data[account_id]['currency_name']"
|
||||
/>
|
||||
<t t-set="type" t-value='"partner_type"' />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_open_items_ending_cumul">
|
||||
<t
|
||||
t-set="account_or_partner_id"
|
||||
t-value="accounts_data[account_id]"
|
||||
/>
|
||||
<t
|
||||
t-set="currency_id"
|
||||
t-value="accounts_data[account_id]['currency_name']"
|
||||
/>
|
||||
<t t-set="type" t-value='"account_type"' />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_open_items_filters">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date at filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account balance at 0 filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="date_at" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="target_move == 'posted'">All posted entries</t>
|
||||
<t t-if="target_move == 'all'">All entries</t>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="hide_account_at_0">Hide</t>
|
||||
<t t-if="not hide_account_at_0">Show</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_open_items_lines_header">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 5.51%;">Date</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 9.76%;">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 4.78%;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 5.38%;">Account</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 15.07%;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 24.5%;">
|
||||
Ref -
|
||||
Label
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.47%;">
|
||||
Due
|
||||
date
|
||||
</div>
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell" style="width: 6.57%;">Original</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 6.57%;">Residual</div>
|
||||
<t t-if="foreign_currency">
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell" style="width: 2.25%;">Cur.</div>
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell amount" style="width: 6.57%;">
|
||||
Cur. Original
|
||||
</div>
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell amount" style="width: 6.57%;">
|
||||
Cur. Residual
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_open_items_lines">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-out="line['date'].strftime('%d/%m/%Y')" />
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="line['entry_id']"
|
||||
res-model="account.move"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-esc="line['move_name']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="journals_data[line['journal_id']]['id']"
|
||||
res-model="account.journal"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-esc="journals_data[line['journal_id']]['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-att-res-id="accounts_data[account_id]['id']"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-esc="accounts_data[account_id]['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span
|
||||
t-if="line.get('partner_id', False)"
|
||||
t-att-res-id="line['partner_id']"
|
||||
res-model="res.partner"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-esc="line['partner_name']" />
|
||||
</span>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-esc="line['ref_label']" />
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-esc="line['date_maturity']" />
|
||||
</div>
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-if="line.get('original', False)"
|
||||
t-esc="line['original']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="line['amount_residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<t t-if="line['currency_id']">
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-esc="line['currency_name']" />
|
||||
</div>
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="line['amount_currency']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env['res.currency'].browse(line['currency_id'])}"
|
||||
/>
|
||||
</div>
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell amount">
|
||||
<span
|
||||
t-esc="line['amount_residual_currency']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env['res.currency'].browse(line['currency_id'])}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not line['currency_id']">
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_open_items_ending_cumul">
|
||||
<!-- Display ending balance line for account or partner -->
|
||||
<div class="act_as_table list_table" style="width: 100%;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<t t-if='type == "account_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 36.34%;">
|
||||
<span t-esc="accounts_data[account_id]['code']" />
|
||||
-
|
||||
<span t-esc="accounts_data[account_id]['name']" />
|
||||
</div>
|
||||
<div class="act_as_cell right" style="width: 28.66%;">
|
||||
Ending
|
||||
balance
|
||||
</div>
|
||||
</t>
|
||||
<t t-if='type == "partner_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 36.34%;" />
|
||||
<div class="act_as_cell right" style="width: 28.66%;">
|
||||
Partner ending balance
|
||||
</div>
|
||||
</t>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 6.47%;" />
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell amount" style="width: 6.57%;" />
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount" style="width: 6.57%;">
|
||||
<t t-if='type == "account_type"'>
|
||||
<span
|
||||
t-esc="total_amount[account_id]['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-if='type == "partner_type"'>
|
||||
<span
|
||||
t-esc="total_amount[account_id][partner_id]['residual']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!--## amount_total_due_currency + amount_residual_currency -->
|
||||
<t t-if="foreign_currency">
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell" />
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
992
account_financial_report/report/templates/trial_balance.xml
Normal file
992
account_financial_report/report/templates/trial_balance.xml
Normal file
@@ -0,0 +1,992 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="trial_balance">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_trial_balance_base" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="report_trial_balance_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="show_partner_details" t-value="show_partner_details" />
|
||||
<t t-set="foreign_currency" t-value="foreign_currency" />
|
||||
<t t-set="show_hierarchy_level" t-value="show_hierarchy_level" />
|
||||
<t t-set="limit_hierarchy_level" t-value="limit_hierarchy_level" />
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">
|
||||
Trial Balance -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<t t-set="company_name" t-value="Company_Name" />
|
||||
<!-- <t t-set="res_company" t-value="company_id"/>-->
|
||||
<t class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-out="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_trial_balance_filters" />
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;" />
|
||||
<!-- Display account lines -->
|
||||
<t t-set="aml_domain_extra" t-value="[]" />
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="trial_balance_grouped">
|
||||
<t t-foreach="trial_balance_grouped" t-as="grouped_item">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell" style="width: 100%;">
|
||||
<t t-esc="grouped_item['name']" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<t
|
||||
t-set="aml_domain_extra"
|
||||
t-if="grouped_item['id'] > 0"
|
||||
t-value="[('analytic_account_id', '=', grouped_item['id'])]"
|
||||
/>
|
||||
<t
|
||||
t-set="aml_domain_extra"
|
||||
t-else=""
|
||||
t-value="[('analytic_account_id', '=', False)]"
|
||||
/>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_lines_header"
|
||||
/>
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="grouped_item['account_data']" t-as="balance">
|
||||
<!-- Adapt -->
|
||||
<t t-set="style" t-value="'font-size:12px;'" />
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_line"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!-- Display footer with totals !-->
|
||||
<t t-set="balance" t-value="grouped_item" />
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_account_footer"
|
||||
/>
|
||||
</t>
|
||||
<!-- TOTAL !-->
|
||||
<t t-if="grouped_by">
|
||||
<t t-set="balance" t-value="total_amount_grouped" />
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_account_footer"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display account header -->
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_lines_header"
|
||||
/>
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="trial_balance" t-as="balance">
|
||||
<!-- Adapt -->
|
||||
<t t-set="style" t-value="'font-size:12px;'" />
|
||||
<!-- Different style for account group -->
|
||||
<t t-if="show_hierarchy">
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="style"
|
||||
t-value="style + 'font-weight: bold; color: blue;'"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_hierarchy and limit_hierarchy_level">
|
||||
<t
|
||||
t-if="show_hierarchy_level > balance['level'] and (not hide_parent_hierarchy_level or (show_hierarchy_level - 1) == balance['level'])"
|
||||
>
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_line"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_line"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<!-- Display partner lines -->
|
||||
<t t-if="show_partner_details">
|
||||
<t t-set="padding" t-value="0" />
|
||||
<t t-foreach="total_amount.keys()" t-as="account_id">
|
||||
<div class="page_break">
|
||||
<t t-set="style" t-value="'font-size:12px;'" />
|
||||
<!-- Display account header -->
|
||||
<div
|
||||
class="act_as_table list_table"
|
||||
style="margin-top: 10px;"
|
||||
/>
|
||||
<div class="act_as_caption account_title" style="width: 100%;">
|
||||
<span
|
||||
t-att-res-id="account_id"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t
|
||||
t-out="accounts_data[account_id]['code']"
|
||||
/> - <t t-out="accounts_data[account_id]['name']" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display account/partner header -->
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_lines_header"
|
||||
/>
|
||||
<!-- Adapt style -->
|
||||
<t t-set="padding" t-value="padding+4" />
|
||||
<!-- Display each partners -->
|
||||
<t
|
||||
t-foreach="total_amount[account_id].keys()"
|
||||
t-as="partner_id"
|
||||
>
|
||||
<t t-if="isinstance(partner_id, int)">
|
||||
<t t-set="type" t-value='"partner_type"' />
|
||||
<!-- Display partner line -->
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_line"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-set="padding" t-value="padding-4" />
|
||||
</div>
|
||||
<!-- Display account footer -->
|
||||
<t t-set="type" t-value='"account_type"' />
|
||||
<t
|
||||
t-call="account_financial_report.report_trial_balance_account_footer"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.report_trial_balance_filters">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date range filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account at 0 filter</div>
|
||||
<div class="act_as_cell">Limit hierarchy levels</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
From:
|
||||
<span t-out="date_from" t-options="{'widget': 'date'}" />
|
||||
To
|
||||
<span t-out="date_to" t-options="{'widget': 'date'}" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="only_posted_moves">All posted entries</t>
|
||||
<t t-if="not only_posted_moves">All entries</t>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="hide_account_at_0">Hide</t>
|
||||
<t t-if="not hide_account_at_0">Show</t>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="limit_hierarchy_level">
|
||||
Level
|
||||
<span t-out="show_hierarchy_level" />
|
||||
</t>
|
||||
<t t-if="not limit_hierarchy_level">No limit</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_trial_balance_lines_header">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<t t-if="not show_partner_details">
|
||||
<!--## Code-->
|
||||
<div class="act_as_cell" style="width: 8%;">Code</div>
|
||||
<!--## Account-->
|
||||
<div class="act_as_cell" style="width: 25%;">Account</div>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<!--## Partner-->
|
||||
<div class="act_as_cell" style="width: 33%;">Partner</div>
|
||||
</t>
|
||||
<!--## Initial balance-->
|
||||
<div class="act_as_cell" style="width: 9%;">
|
||||
Initial
|
||||
balance
|
||||
</div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell" style="width: 9%;">Debit</div>
|
||||
<!--## Credit-->
|
||||
<div class="act_as_cell" style="width: 9%;">Credit</div>
|
||||
<!--## Period balance-->
|
||||
<div class="act_as_cell" style="width: 9%;">Period balance</div>
|
||||
<!--## Ending balance-->
|
||||
<div class="act_as_cell" style="width: 9%;">Ending balance</div>
|
||||
<t t-if="foreign_currency">
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell" style="width: 11%;">Initial
|
||||
balance cur.</div>
|
||||
<div class="act_as_cell" style="width: 11%;">Ending balance
|
||||
cur.</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_trial_balance_line">
|
||||
<t
|
||||
t-set="aml_domain_common"
|
||||
t-if="only_posted_moves"
|
||||
t-value="[('parent_state', '=', 'posted')]"
|
||||
/>
|
||||
<t
|
||||
t-set="aml_domain_common"
|
||||
t-else=""
|
||||
t-value="[('parent_state', 'in', ('posted', 'draft'))]"
|
||||
/>
|
||||
<!-- # line -->
|
||||
<div class="act_as_row lines">
|
||||
<t t-if="not show_partner_details">
|
||||
<!--## Code-->
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<div class="act_as_cell left" t-att-style="style">
|
||||
<span
|
||||
t-att-res-id="balance['id']"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="balance['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<!-- ## Account/Partner-->
|
||||
<div class="act_as_cell left" t-att-style="style">
|
||||
<span
|
||||
t-att-res-id="balance['id']"
|
||||
res-model="account.account"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="balance['name']" />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<div class="act_as_cell left" t-att-style="style">
|
||||
<t t-set="res_model" t-value="'account.group'" />
|
||||
<span
|
||||
t-att-res-id="balance['id']"
|
||||
res-model="account.group"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="balance['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_cell left" t-att-style="style">
|
||||
<t t-set="res_model" t-value="'account.group'" />
|
||||
<span
|
||||
t-att-res-id="balance['id']"
|
||||
res-model="account.group"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="balance['name']" />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<div class="act_as_cell left" t-att-style="style">
|
||||
<t t-set="res_model" t-value="'res.partner'" />
|
||||
<span
|
||||
t-att-res-id="partner_id"
|
||||
res-model="res.partner"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-out="partners_data[partner_id]['name']" />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
<!--## Initial balance-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id']),
|
||||
('date', '<', date_from)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['initial_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', 'in', balance['account_ids']),
|
||||
('date', '<', date_from)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['initial_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', int(account_id)),
|
||||
('partner_id', '=', int(partner_id)),
|
||||
('date', '<', date_from)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['initial_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('debit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', 'in', balance['account_ids']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('debit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', int(account_id)),
|
||||
('partner_id', '=', int(partner_id)),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('debit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!-- <!–## Credit–>-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('credit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', 'in', balance['account_ids']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('credit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', int(account_id)),
|
||||
('partner_id', '=', int(partner_id)),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('credit', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!-- <!–## Period balance–>-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('balance', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', 'in', balance['account_ids']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', int(account_id)),
|
||||
('partner_id', '=', int(partner_id)),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to),
|
||||
('balance', '<>', 0)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<!-- <!–## Ending balance–>-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id']),
|
||||
('date', '<=', date_to)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['ending_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', 'in', balance['account_ids'])]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['ending_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', int(account_id)),
|
||||
('partner_id', '=', int(partner_id)),
|
||||
('date', '<=', date_to)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['ending_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t t-if="balance['currency_id']">
|
||||
<t
|
||||
t-set="balance_currency"
|
||||
t-value="currency_model.browse(balance['currency_id'])"
|
||||
/>
|
||||
<!--## Initial balance cur.-->
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id'])]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['initial_currency_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': balance_currency}"
|
||||
/>
|
||||
</span>
|
||||
<!-- <t t-if="line.account_group_id">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', 'in', line.compute_account_ids.ids)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="line.initial_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </t>-->
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<t t-if="total_amount[account_id]['currency_id']">
|
||||
<t t-if="type == 'partner_type'">
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', account_id),
|
||||
('partner_id', '=', partner_id)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-set="total_amount_item_currency"
|
||||
t-value="currency_model.browse(total_amount[account_id]['currency_id'])"
|
||||
/>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['initial_currency_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': total_amount_item_currency}"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<!--## Ending balance cur.-->
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t t-if="balance['currency_id']">
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', balance['id'])]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common+aml_domain_extra"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-out="balance['ending_currency_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': balance_currency}"
|
||||
/>
|
||||
</span>
|
||||
<!-- <t t-if="line.account_group_id">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', 'in', line.compute_account_ids.ids)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="line.final_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </t>-->
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<t t-if="total_amount[account_id]['currency_id']">
|
||||
<div class="act_as_cell amount" t-att-style="style">
|
||||
<t t-if="type == 'partner_type'">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('account_id', '=', account_id),
|
||||
('partner_id', '=', partner_id)]"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain+aml_domain_common"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-set="total_amount_item_currency"
|
||||
t-value="currency_model.browse(total_amount[account_id]['currency_id'])"
|
||||
/>
|
||||
<t
|
||||
t-out="total_amount[account_id][partner_id]['ending_currency_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': total_amount_item_currency}"
|
||||
/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<t t-if="not total_amount[account_id]['currency_id']">
|
||||
<!--## balance_currency-->
|
||||
<div class="act_as_cell" />
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="not show_partner_details">
|
||||
<t t-if="balance['type'] == 'account_type'">
|
||||
<t t-if="not balance['currency_id']">
|
||||
<!--## balance_currency-->
|
||||
<div class="act_as_cell" />
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="balance['type'] == 'group_type'">
|
||||
<!--## balance_currency-->
|
||||
<div class="act_as_cell" />
|
||||
<div class="act_as_cell" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
<!-- <template id="account_financial_report.report_trial_balance_account_footer">-->
|
||||
<!-- <!– Display account footer –>-->
|
||||
<!-- <div class="act_as_table list_table" style="width: 100%;">-->
|
||||
<!-- <div class="act_as_row labels" style="font-weight: bold;">-->
|
||||
<!-- <!–## Account–>-->
|
||||
<!-- <div class="act_as_cell left" style="width: 61.44%;">-->
|
||||
<!-- <t t-set="res_model" t-value="'account.account'"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-active-id="account.account_id.id"-->
|
||||
<!-- t-att-data-res-model="res_model"-->
|
||||
<!-- class="o_account_financial_reports_web_action"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.code"/> - <t t-att-style="style" t-out="account.name"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## Initial balance–>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 9.64%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id),-->
|
||||
<!-- ('date', '<', o.date_from.strftime('%Y-%m-%d'))]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.initial_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## Debit–>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 9.64%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id),-->
|
||||
<!-- ('date', '>=', account.report_id.date_from.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('date', '<=', account.report_id.date_to.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('debit', '<>', 0)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.debit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## Credit–>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 9.64%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id),-->
|
||||
<!-- ('date', '>=', account.report_id.date_from.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('date', '<=', account.report_id.date_to.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('credit', '<>', 0)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## Period Balance –>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 9.64%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id),-->
|
||||
<!-- ('date', '>=', account.report_id.date_from.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('date', '<=', account.report_id.date_to.strftime('%Y-%m-%d')),-->
|
||||
<!-- ('period_balance', '<>', 0)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.period_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## Ending balance–>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 9.64%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style" >-->
|
||||
<!-- <t t-att-style="style" t-out="account.final_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <t t-if="foreign_currency">-->
|
||||
<!-- <t t-if="account.currency_id.id">-->
|
||||
<!-- <!–## currency_name–>-->
|
||||
<!-- <div class="act_as_cell" style="width: 4.43%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id)]"/>-->
|
||||
<!-- <span t-field="account.currency_id.display_name"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–## balance_currency–>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 8.86%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id),-->
|
||||
<!-- ('date', '<', date_from.strftime('%Y-%m-%d'))]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style">-->
|
||||
<!-- <t t-att-style="style" t-out="account.initial_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': account.account_id.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="act_as_cell amount" style="width: 8.86%;">-->
|
||||
<!-- <t t-set="domain"-->
|
||||
<!-- t-value="[('account_id', '=', account.account_id.id)]"/>-->
|
||||
<!-- <span>-->
|
||||
<!-- <a t-att-data-t-att-domain="domain"-->
|
||||
<!-- t-att-data-res-model="'account.move.line'"-->
|
||||
<!-- class="o_account_financial_reports_web_action_monetary_multi"-->
|
||||
<!-- t-att-style="style" >-->
|
||||
<!-- <t t-att-style="style" t-out="account.final_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': account.account_id.currency_id}"/></a>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </t>-->
|
||||
<!-- <t t-if="not account.currency_id.id">-->
|
||||
<!-- <div class="act_as_cell" style="width: 4.43%;"/>-->
|
||||
<!-- <div class="act_as_cell" style="width: 8.86%;"/>-->
|
||||
<!-- <div class="act_as_cell" style="width: 8.86%;"/>-->
|
||||
<!-- </t>-->
|
||||
<!-- </t>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<template id="account_financial_report.report_trial_balance_account_footer">
|
||||
<!-- Display ending balance line for account or partner -->
|
||||
<div class="act_as_table list_table" style="width: 100%;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 33%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span t-out="balance['name']" />
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-out="accounts_data[account_id]['code']" />
|
||||
-
|
||||
<span t-out="accounts_data[account_id]['name']" />
|
||||
</t>
|
||||
</div>
|
||||
<!--## Initial Balance-->
|
||||
<div class="act_as_cell amount" style="width: 9%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span
|
||||
t-out="balance['initial_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
t-out="total_amount[account_id]['initial_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell amount" style="width: 9%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span
|
||||
t-out="balance['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
t-out="total_amount[account_id]['debit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!--## Credit-->
|
||||
<div class="act_as_cell amount" style="width: 9%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span
|
||||
t-out="balance['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
t-out="total_amount[account_id]['credit']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!--## Period balance-->
|
||||
<div class="act_as_cell amount" style="width: 9%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span
|
||||
t-out="balance['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
t-out="total_amount[account_id]['balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<!--## Ending balance-->
|
||||
<div class="act_as_cell amount" style="width: 9%;">
|
||||
<t
|
||||
t-if="grouped_by and balance['type'] in ('analytic_account_type', 'total')"
|
||||
>
|
||||
<span
|
||||
t-out="balance['ending_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span
|
||||
t-out="total_amount[account_id]['ending_balance']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="foreign_currency">
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell" style="width: 11%;" />
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell" style="width: 11%;" />
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
167
account_financial_report/report/templates/vat_report.xml
Normal file
167
account_financial_report/report/templates/vat_report.xml
Normal file
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="vat_report">
|
||||
<t t-call="account_financial_report.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_vat_report_base" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="account_financial_report.report_vat_report_base">
|
||||
<t t-set="title">
|
||||
VAT Report -
|
||||
<t t-out="company_name" />
|
||||
-
|
||||
<t t-out="currency_name" />
|
||||
</t>
|
||||
<t t-set="company_name" t-value="company_name" />
|
||||
<div class="page">
|
||||
<div class="row">
|
||||
<h4
|
||||
class="mt0"
|
||||
t-esc="title or 'Odoo Report'"
|
||||
style="text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_vat_report_filters" />
|
||||
<div class="page_break" />
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## code-->
|
||||
<div class="act_as_cell first_column" style="width: 5%;">
|
||||
Code
|
||||
</div>
|
||||
<!--## name-->
|
||||
<div class="act_as_cell" style="width: 65%;">Name</div>
|
||||
<!--## net-->
|
||||
<div class="act_as_cell" style="width: 15%;">Net</div>
|
||||
<!--## tax-->
|
||||
<div class="act_as_cell" style="width: 15%;">Tax</div>
|
||||
</div>
|
||||
</div>
|
||||
<t t-foreach="vat_report" t-as="tag_or_group">
|
||||
<div class="act_as_row lines" style="font-weight: bold;">
|
||||
<div
|
||||
class="act_as_cell left oe_tooltip_string"
|
||||
style="width: 5%;"
|
||||
>
|
||||
<span
|
||||
t-att-res-id="res_id"
|
||||
t-att-res-model="res_model"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-att-style="style" t-out="tag_or_group['code']" />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="act_as_cell left oe_tooltip_string"
|
||||
style="width: 65%;"
|
||||
>
|
||||
<span
|
||||
t-att-res-id="res_id"
|
||||
t-att-res-model="res_model"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-att-style="style" t-out="tag_or_group['name']" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 15%;">
|
||||
<t
|
||||
t-att-style="style"
|
||||
t-out="tag_or_group['net']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 15%;">
|
||||
<t
|
||||
t-att-style="style"
|
||||
t-out="tag_or_group['tax']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="tax_detail">
|
||||
<t t-foreach="tag_or_group['taxes']" t-as="tax">
|
||||
<div class="act_as_row lines">
|
||||
<div class="act_as_cell" style="width: 5%;" />
|
||||
<div
|
||||
class="act_as_cell left oe_tooltip_string"
|
||||
style="padding-left: 20px; width: 65%;"
|
||||
>
|
||||
<span
|
||||
t-att-res-id="tax['id']"
|
||||
t-att-res-model="res_model"
|
||||
view-type="form"
|
||||
>
|
||||
<t t-att-style="style" t-out="tax['name']" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 15%;">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('tax_ids', 'in', tax['id']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)]+request.env['account.move.line']._get_tax_exigible_domain()"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-att-style="style"
|
||||
t-out="tax['net']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="act_as_cell amount" style="width: 15%;">
|
||||
<t
|
||||
t-set="domain"
|
||||
t-value="[('tax_line_id', '=', tax['id']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)]+request.env['account.move.line']._get_tax_exigible_domain()"
|
||||
/>
|
||||
<span
|
||||
t-att-domain="domain"
|
||||
res-model="account.move.line"
|
||||
>
|
||||
<t
|
||||
t-att-style="style"
|
||||
t-out="tax['tax']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="account_financial_report.report_vat_report_filters">
|
||||
<div class="act_as_table data_table" style="width: 100%;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date From</div>
|
||||
<div class="act_as_cell">Date To</div>
|
||||
<div class="act_as_cell">Based On</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="date_from" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="date_to" />
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<span t-esc="based_on" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
961
account_financial_report/report/trial_balance.py
Normal file
961
account_financial_report/report/trial_balance.py
Normal file
@@ -0,0 +1,961 @@
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# © 2018 Forest and Biomass Romania SA
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.tools.float_utils import float_is_zero
|
||||
|
||||
|
||||
class TrialBalanceReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.trial_balance"
|
||||
_description = "Trial Balance Report"
|
||||
_inherit = "report.account_financial_report.abstract_report"
|
||||
|
||||
def _get_initial_balances_bs_ml_domain(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", True),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = [("date", "<", date_from)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
if company_id:
|
||||
domain += [("company_id", "=", company_id)]
|
||||
if journal_ids:
|
||||
domain += [("journal_id", "in", journal_ids)]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if show_partner_details:
|
||||
domain += [
|
||||
(
|
||||
"account_id.account_type",
|
||||
"in",
|
||||
["asset_receivable", "liability_payable"],
|
||||
)
|
||||
]
|
||||
return domain
|
||||
|
||||
def _get_initial_balances_pl_ml_domain(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
fy_start_date,
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", False),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = [("date", "<", date_from), ("date", ">=", fy_start_date)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
if company_id:
|
||||
domain += [("company_id", "=", company_id)]
|
||||
if journal_ids:
|
||||
domain += [("journal_id", "in", journal_ids)]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if show_partner_details:
|
||||
domain += [
|
||||
(
|
||||
"account_id.account_type",
|
||||
"in",
|
||||
["asset_receivable", "liability_payable"],
|
||||
)
|
||||
]
|
||||
return domain
|
||||
|
||||
@api.model
|
||||
def _get_period_ml_domain(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_to,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
):
|
||||
domain = [
|
||||
("display_type", "not in", ["line_note", "line_section"]),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
]
|
||||
if company_id:
|
||||
domain += [("company_id", "=", company_id)]
|
||||
if account_ids:
|
||||
domain += [("account_id", "in", account_ids)]
|
||||
if journal_ids:
|
||||
domain += [("journal_id", "in", journal_ids)]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if show_partner_details:
|
||||
domain += [
|
||||
(
|
||||
"account_id.account_type",
|
||||
"in",
|
||||
["asset_receivable", "liability_payable"],
|
||||
)
|
||||
]
|
||||
return domain
|
||||
|
||||
def _get_initial_balance_fy_pl_ml_domain(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
fy_start_date,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
):
|
||||
accounts_domain = [
|
||||
("company_ids", "in", [company_id]),
|
||||
("include_initial_balance", "=", False),
|
||||
]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
domain = [("date", "<", fy_start_date)]
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
domain += [("account_id", "in", accounts.ids)]
|
||||
if company_id:
|
||||
domain += [("company_id", "=", company_id)]
|
||||
if journal_ids:
|
||||
domain += [("journal_id", "in", journal_ids)]
|
||||
if partner_ids:
|
||||
domain += [("partner_id", "in", partner_ids)]
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
if show_partner_details:
|
||||
domain += [
|
||||
(
|
||||
"account_id.account_type",
|
||||
"in",
|
||||
["asset_receivable", "liability_payable"],
|
||||
)
|
||||
]
|
||||
return domain
|
||||
|
||||
def _get_pl_initial_balance(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
fy_start_date,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
foreign_currency,
|
||||
):
|
||||
domain = self._get_initial_balance_fy_pl_ml_domain(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
fy_start_date,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
)
|
||||
initial_balances = self.env["account.move.line"].read_group(
|
||||
domain=domain,
|
||||
fields=["account_id", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id"],
|
||||
)
|
||||
pl_initial_balance = 0.0
|
||||
pl_initial_currency_balance = 0.0
|
||||
for initial_balance in initial_balances:
|
||||
pl_initial_balance += initial_balance["balance"]
|
||||
if foreign_currency:
|
||||
pl_initial_currency_balance += round(
|
||||
initial_balance["amount_currency"], 2
|
||||
)
|
||||
return pl_initial_balance, pl_initial_currency_balance
|
||||
|
||||
@api.model
|
||||
def _compute_account_amount(
|
||||
self, total_amount, tb_initial_acc, tb_period_acc, foreign_currency
|
||||
):
|
||||
for tb in tb_period_acc:
|
||||
acc_id = tb["account_id"][0]
|
||||
total_amount[acc_id] = self._prepare_total_amount(tb, foreign_currency)
|
||||
total_amount[acc_id]["credit"] = tb["credit"]
|
||||
total_amount[acc_id]["debit"] = tb["debit"]
|
||||
total_amount[acc_id]["balance"] = tb["balance"]
|
||||
total_amount[acc_id]["initial_balance"] = 0.0
|
||||
if foreign_currency:
|
||||
total_amount[acc_id]["initial_currency_balance"] = 0.0
|
||||
if "__context" in tb and "group_by" in tb["__context"]:
|
||||
group_by = tb["__context"]["group_by"][0]
|
||||
gb_data = {}
|
||||
tb_grouped = self.env["account.move.line"].read_group(
|
||||
domain=tb["__domain"],
|
||||
fields=[
|
||||
group_by,
|
||||
"debit",
|
||||
"credit",
|
||||
"balance",
|
||||
"amount_currency:sum",
|
||||
],
|
||||
groupby=[group_by],
|
||||
)
|
||||
for tb2 in tb_grouped:
|
||||
gb_id = tb2[group_by][0] if tb2[group_by] else 0
|
||||
gb_data[gb_id] = self._prepare_total_amount(tb2, foreign_currency)
|
||||
gb_data[gb_id]["credit"] = tb2["credit"]
|
||||
gb_data[gb_id]["debit"] = tb2["debit"]
|
||||
gb_data[gb_id]["balance"] = tb2["balance"]
|
||||
gb_data[gb_id]["initial_balance"] = 0.0
|
||||
if foreign_currency:
|
||||
gb_data[gb_id]["initial_currency_balance"] = 0.0
|
||||
total_amount[acc_id]["group_by"] = group_by
|
||||
total_amount[acc_id]["group_by_data"] = gb_data
|
||||
for tb in tb_initial_acc:
|
||||
acc_id = tb["account_id"]
|
||||
if acc_id not in total_amount.keys():
|
||||
total_amount[acc_id] = self._prepare_total_amount(tb, foreign_currency)
|
||||
total_amount[acc_id]["group_by_data"] = {}
|
||||
total_amount[acc_id]["group_by_data"][0] = self._prepare_total_amount(
|
||||
tb, foreign_currency
|
||||
)
|
||||
else:
|
||||
total_amount[acc_id]["initial_balance"] = tb["balance"]
|
||||
total_amount[acc_id]["ending_balance"] += tb["balance"]
|
||||
if foreign_currency:
|
||||
total_amount[acc_id]["initial_currency_balance"] = round(
|
||||
tb["amount_currency"], 2
|
||||
)
|
||||
total_amount[acc_id]["ending_currency_balance"] += round(
|
||||
tb["amount_currency"], 2
|
||||
)
|
||||
if "group_by_data" in tb:
|
||||
for gb_key in list(tb["group_by_data"]):
|
||||
tb2 = tb["group_by_data"][gb_key]
|
||||
if "group_by_data" in total_amount[acc_id]:
|
||||
if gb_key not in total_amount[acc_id]["group_by_data"]:
|
||||
total_amount[acc_id]["group_by_data"][gb_key] = (
|
||||
self._prepare_total_amount(tb2, foreign_currency)
|
||||
)
|
||||
else:
|
||||
total_amount[acc_id]["group_by_data"][gb_key][
|
||||
"initial_balance"
|
||||
] = tb2["balance"]
|
||||
total_amount[acc_id]["group_by_data"][gb_key][
|
||||
"ending_balance"
|
||||
] += tb2["balance"]
|
||||
if foreign_currency:
|
||||
total_amount[acc_id]["group_by_data"][gb_key][
|
||||
"initial_currency_balance"
|
||||
] = round(tb2["amount_currency"], 2)
|
||||
total_amount[acc_id]["group_by_data"][gb_key][
|
||||
"ending_currency_balance"
|
||||
] += round(tb2["amount_currency"], 2)
|
||||
return total_amount
|
||||
|
||||
@api.model
|
||||
def _prepare_total_amount(self, tb, foreign_currency):
|
||||
res = {
|
||||
"credit": 0.0,
|
||||
"debit": 0.0,
|
||||
"balance": 0.0,
|
||||
"initial_balance": tb["balance"],
|
||||
"ending_balance": tb["balance"],
|
||||
}
|
||||
if foreign_currency:
|
||||
res["initial_currency_balance"] = round(tb["amount_currency"], 2)
|
||||
res["ending_currency_balance"] = round(tb["amount_currency"], 2)
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _compute_acc_prt_amount(
|
||||
self, total_amount, tb, acc_id, prt_id, foreign_currency
|
||||
):
|
||||
# Add keys to dict if not exists
|
||||
if acc_id not in total_amount:
|
||||
total_amount[acc_id] = self._prepare_total_amount(tb, foreign_currency)
|
||||
if prt_id not in total_amount[acc_id]:
|
||||
total_amount[acc_id][prt_id] = self._prepare_total_amount(
|
||||
tb, foreign_currency
|
||||
)
|
||||
else:
|
||||
# Increase balance field values
|
||||
total_amount[acc_id][prt_id]["initial_balance"] = tb["balance"]
|
||||
total_amount[acc_id][prt_id]["ending_balance"] += tb["balance"]
|
||||
if foreign_currency:
|
||||
total_amount[acc_id][prt_id]["initial_currency_balance"] = round(
|
||||
tb["amount_currency"], 2
|
||||
)
|
||||
total_amount[acc_id][prt_id]["ending_currency_balance"] += round(
|
||||
tb["amount_currency"], 2
|
||||
)
|
||||
total_amount[acc_id][prt_id]["partner_name"] = (
|
||||
tb["partner_id"][1] if tb["partner_id"] else _("Missing Partner")
|
||||
)
|
||||
return total_amount
|
||||
|
||||
@api.model
|
||||
def _compute_partner_amount(
|
||||
self, total_amount, tb_initial_prt, tb_period_prt, foreign_currency
|
||||
):
|
||||
partners_ids = set()
|
||||
partners_data = {}
|
||||
for tb in tb_period_prt:
|
||||
acc_id = tb["account_id"][0]
|
||||
prt_id = tb["partner_id"][0] if tb["partner_id"] else 0
|
||||
if prt_id not in partners_ids:
|
||||
partner_name = (
|
||||
tb["partner_id"][1] if tb["partner_id"] else _("Missing Partner")
|
||||
)
|
||||
partners_data.update({prt_id: {"id": prt_id, "name": partner_name}})
|
||||
total_amount[acc_id][prt_id] = self._prepare_total_amount(
|
||||
tb, foreign_currency
|
||||
)
|
||||
total_amount[acc_id][prt_id]["credit"] = tb["credit"]
|
||||
total_amount[acc_id][prt_id]["debit"] = tb["debit"]
|
||||
total_amount[acc_id][prt_id]["balance"] = tb["balance"]
|
||||
total_amount[acc_id][prt_id]["initial_balance"] = 0.0
|
||||
total_amount[acc_id][prt_id]["partner_name"] = partners_data[prt_id]["name"]
|
||||
partners_ids.add(prt_id)
|
||||
for tb in tb_initial_prt:
|
||||
acc_id = tb["account_id"][0]
|
||||
prt_id = tb["partner_id"][0] if tb["partner_id"] else 0
|
||||
if prt_id not in partners_ids:
|
||||
partner_name = (
|
||||
tb["partner_id"][1] if tb["partner_id"] else _("Missing Partner")
|
||||
)
|
||||
partners_data.update({prt_id: {"id": prt_id, "name": partner_name}})
|
||||
total_amount = self._compute_acc_prt_amount(
|
||||
total_amount, tb, acc_id, prt_id, foreign_currency
|
||||
)
|
||||
# sort on partner_name
|
||||
for acc_id, total_data in total_amount.items():
|
||||
tmp_list = sorted(
|
||||
total_data.items(),
|
||||
key=lambda x: isinstance(x[0], int)
|
||||
and isinstance(x[1], dict)
|
||||
and x[1]["partner_name"]
|
||||
or x[0],
|
||||
)
|
||||
total_amount[acc_id] = {}
|
||||
for key, value in tmp_list:
|
||||
total_amount[acc_id][key] = value
|
||||
return total_amount, partners_data
|
||||
|
||||
def _remove_accounts_at_cero(self, total_amount, show_partner_details, company):
|
||||
def is_removable(d):
|
||||
rounding = company.currency_id.rounding
|
||||
return (
|
||||
float_is_zero(d["initial_balance"], precision_rounding=rounding)
|
||||
and float_is_zero(d["credit"], precision_rounding=rounding)
|
||||
and float_is_zero(d["debit"], precision_rounding=rounding)
|
||||
and float_is_zero(d["ending_balance"], precision_rounding=rounding)
|
||||
)
|
||||
|
||||
accounts_to_remove = []
|
||||
for acc_id, ta_data in total_amount.items():
|
||||
if is_removable(ta_data):
|
||||
accounts_to_remove.append(acc_id)
|
||||
elif show_partner_details:
|
||||
partner_to_remove = []
|
||||
for key, value in ta_data.items():
|
||||
# If the show_partner_details option is checked,
|
||||
# the partner data is in the same account data dict
|
||||
# but with the partner id as the key
|
||||
if isinstance(key, int) and is_removable(value):
|
||||
partner_to_remove.append(key)
|
||||
for partner_id in partner_to_remove:
|
||||
del ta_data[partner_id]
|
||||
for account_id in accounts_to_remove:
|
||||
del total_amount[account_id]
|
||||
|
||||
# flake8: noqa: C901
|
||||
@api.model
|
||||
def _get_data(
|
||||
self,
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_to,
|
||||
date_from,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
hide_account_at_0,
|
||||
unaffected_earnings_account,
|
||||
fy_start_date,
|
||||
grouped_by,
|
||||
):
|
||||
accounts_domain = [("company_ids", "in", [company_id])]
|
||||
if account_ids:
|
||||
accounts_domain += [("id", "in", account_ids)]
|
||||
# If explicit list of accounts is provided,
|
||||
# don't include unaffected earnings account
|
||||
unaffected_earnings_account = False
|
||||
accounts = self.env["account.account"].search(accounts_domain)
|
||||
tb_initial_acc = []
|
||||
for account in accounts:
|
||||
tb_initial_acc.append(
|
||||
{"account_id": account.id, "balance": 0.0, "amount_currency": 0.0}
|
||||
)
|
||||
groupby_fields = ["account_id"]
|
||||
if grouped_by:
|
||||
groupby_fields.append("analytic_account_ids")
|
||||
initial_domain_bs = self._get_initial_balances_bs_ml_domain(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
)
|
||||
tb_initial_acc_bs = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_bs,
|
||||
fields=["account_id", "balance", "amount_currency:sum"],
|
||||
groupby=groupby_fields,
|
||||
)
|
||||
initial_domain_pl = self._get_initial_balances_pl_ml_domain(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
fy_start_date,
|
||||
)
|
||||
tb_initial_acc_pl = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_pl,
|
||||
fields=["account_id", "balance", "amount_currency:sum"],
|
||||
groupby=groupby_fields,
|
||||
)
|
||||
tb_initial_acc_rg = tb_initial_acc_bs + tb_initial_acc_pl
|
||||
for account_rg in tb_initial_acc_rg:
|
||||
element = list(
|
||||
filter(
|
||||
lambda acc_dict: acc_dict["account_id"]
|
||||
== account_rg["account_id"][0],
|
||||
tb_initial_acc,
|
||||
)
|
||||
)
|
||||
if element:
|
||||
element[0]["balance"] += account_rg["balance"]
|
||||
element[0]["amount_currency"] += account_rg["amount_currency"]
|
||||
if "__context" in account_rg and "group_by" in account_rg["__context"]:
|
||||
group_by = account_rg["__context"]["group_by"][0]
|
||||
gb_data = {}
|
||||
account_rg_grouped = self.env["account.move.line"].read_group(
|
||||
domain=account_rg["__domain"],
|
||||
fields=[group_by, "balance", "amount_currency:sum"],
|
||||
groupby=[group_by],
|
||||
)
|
||||
for a_rg2 in account_rg_grouped:
|
||||
gb_id = a_rg2[group_by][0] if a_rg2[group_by] else 0
|
||||
gb_data[gb_id] = {
|
||||
"balance": a_rg2["balance"],
|
||||
"amount_currency": a_rg2["amount_currency"],
|
||||
}
|
||||
element[0]["group_by"] = group_by
|
||||
element[0]["group_by_data"] = gb_data
|
||||
if hide_account_at_0:
|
||||
tb_initial_acc = [p for p in tb_initial_acc if p["balance"] != 0]
|
||||
|
||||
period_domain = self._get_period_ml_domain(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_to,
|
||||
date_from,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
)
|
||||
tb_period_acc = self.env["account.move.line"].read_group(
|
||||
domain=period_domain,
|
||||
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
|
||||
groupby=groupby_fields,
|
||||
)
|
||||
|
||||
if show_partner_details:
|
||||
tb_initial_prt_bs = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_bs,
|
||||
fields=["account_id", "partner_id", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id", "partner_id"],
|
||||
lazy=False,
|
||||
)
|
||||
tb_initial_prt_pl = self.env["account.move.line"].read_group(
|
||||
domain=initial_domain_pl,
|
||||
fields=["account_id", "partner_id", "balance", "amount_currency:sum"],
|
||||
groupby=["account_id", "partner_id"],
|
||||
)
|
||||
tb_initial_prt = tb_initial_prt_bs + tb_initial_prt_pl
|
||||
if hide_account_at_0:
|
||||
tb_initial_prt = [p for p in tb_initial_prt if p["balance"] != 0]
|
||||
tb_period_prt = self.env["account.move.line"].read_group(
|
||||
domain=period_domain,
|
||||
fields=[
|
||||
"account_id",
|
||||
"partner_id",
|
||||
"debit",
|
||||
"credit",
|
||||
"balance",
|
||||
"amount_currency:sum",
|
||||
],
|
||||
groupby=["account_id", "partner_id"],
|
||||
lazy=False,
|
||||
)
|
||||
total_amount = {}
|
||||
partners_data = []
|
||||
total_amount = self._compute_account_amount(
|
||||
total_amount, tb_initial_acc, tb_period_acc, foreign_currency
|
||||
)
|
||||
if show_partner_details:
|
||||
total_amount, partners_data = self._compute_partner_amount(
|
||||
total_amount, tb_initial_prt, tb_period_prt, foreign_currency
|
||||
)
|
||||
# Remove accounts a 0 from collections
|
||||
if hide_account_at_0:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
self._remove_accounts_at_cero(total_amount, show_partner_details, company)
|
||||
|
||||
accounts_ids = list(total_amount.keys())
|
||||
unaffected_id = unaffected_earnings_account
|
||||
if unaffected_id:
|
||||
if unaffected_id not in accounts_ids:
|
||||
accounts_ids.append(unaffected_id)
|
||||
total_amount[unaffected_id] = {}
|
||||
total_amount[unaffected_id]["initial_balance"] = 0.0
|
||||
total_amount[unaffected_id]["balance"] = 0.0
|
||||
total_amount[unaffected_id]["credit"] = 0.0
|
||||
total_amount[unaffected_id]["debit"] = 0.0
|
||||
total_amount[unaffected_id]["ending_balance"] = 0.0
|
||||
if foreign_currency:
|
||||
total_amount[unaffected_id]["amount_currency"] = 0
|
||||
total_amount[unaffected_id]["initial_currency_balance"] = 0.0
|
||||
total_amount[unaffected_id]["ending_currency_balance"] = 0.0
|
||||
if grouped_by:
|
||||
total_amount[unaffected_id]["group_by"] = grouped_by
|
||||
total_amount[unaffected_id]["group_by_data"] = {}
|
||||
# Fix to prevent side effects
|
||||
if (
|
||||
foreign_currency
|
||||
and "amount_currency" not in total_amount[unaffected_id]
|
||||
):
|
||||
total_amount[unaffected_id]["amount_currency"] = 0
|
||||
group_by_data_item = self._prepare_total_amount(
|
||||
total_amount[unaffected_id], foreign_currency
|
||||
)
|
||||
total_amount[unaffected_id]["group_by_data"][0] = group_by_data_item
|
||||
accounts_data = self._get_accounts_data(accounts_ids)
|
||||
(
|
||||
pl_initial_balance,
|
||||
pl_initial_currency_balance,
|
||||
) = self._get_pl_initial_balance(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
fy_start_date,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
foreign_currency,
|
||||
)
|
||||
if unaffected_id:
|
||||
total_amount[unaffected_id]["ending_balance"] += pl_initial_balance
|
||||
total_amount[unaffected_id]["initial_balance"] += pl_initial_balance
|
||||
if foreign_currency:
|
||||
total_amount[unaffected_id]["ending_currency_balance"] += (
|
||||
pl_initial_currency_balance
|
||||
)
|
||||
total_amount[unaffected_id]["initial_currency_balance"] += (
|
||||
pl_initial_currency_balance
|
||||
)
|
||||
if grouped_by:
|
||||
total_amount[unaffected_id]["group_by_data"][0]["ending_balance"] = (
|
||||
total_amount[unaffected_id]["ending_balance"]
|
||||
)
|
||||
total_amount[unaffected_id]["group_by_data"][0]["initial_balance"] = (
|
||||
total_amount[unaffected_id]["initial_balance"]
|
||||
)
|
||||
if foreign_currency:
|
||||
total_amount[unaffected_id]["group_by_data"][0][
|
||||
"ending_currency_balance"
|
||||
] = total_amount[unaffected_id]["ending_currency_balance"]
|
||||
total_amount[unaffected_id]["group_by_data"][0][
|
||||
"initial_currency_balance"
|
||||
] = total_amount[unaffected_id]["initial_currency_balance"]
|
||||
return total_amount, accounts_data, partners_data
|
||||
|
||||
def _get_data_grouped(self, total_amount, accounts_data, foreign_currency):
|
||||
"""Get the data grouped by analytical account instead of as used
|
||||
"without grouping".
|
||||
"""
|
||||
trial_balance = {}
|
||||
total_amount_grouped = {"type": "total", "name": _("TOTAL")}
|
||||
f_names = [
|
||||
"credit",
|
||||
"debit",
|
||||
"balance",
|
||||
"initial_balance",
|
||||
"ending_balance",
|
||||
"initial_currency_balance",
|
||||
"ending_currency_balance",
|
||||
]
|
||||
for f_name in f_names:
|
||||
total_amount_grouped[f_name] = 0
|
||||
for a_id in list(total_amount.keys()):
|
||||
for key in list(total_amount[a_id]["group_by_data"].keys()):
|
||||
total_amount_item2 = total_amount[a_id]["group_by_data"][key]
|
||||
if key not in trial_balance:
|
||||
trial_balance[key] = {}
|
||||
for f_name in f_names:
|
||||
if f_name in total_amount_item2:
|
||||
trial_balance[key][f_name] = 0
|
||||
trial_balance[key]["account_data"] = {}
|
||||
for f_name in f_names:
|
||||
if f_name in total_amount_item2:
|
||||
trial_balance[key][f_name] += total_amount_item2[f_name]
|
||||
# Prepare data_item
|
||||
data_item = total_amount_item2
|
||||
data_item["type"] = "account_type"
|
||||
data_item["id"] = a_id
|
||||
data_item["name"] = accounts_data[a_id]["name"]
|
||||
data_item["code"] = accounts_data[a_id]["code"]
|
||||
if foreign_currency:
|
||||
data_item["currency_id"] = accounts_data[a_id]["currency_id"]
|
||||
data_item["currency_name"] = accounts_data[a_id]["currency_name"]
|
||||
trial_balance[key]["account_data"][a_id] = data_item
|
||||
analytic_account_ids = list(trial_balance.keys())
|
||||
aa_data = {}
|
||||
aaa_model = self.env["account.analytic.account"].with_context(active_test=False)
|
||||
analytic_accounts = aaa_model.search_read(
|
||||
domain=[("id", "in", analytic_account_ids)],
|
||||
fields=["display_name"],
|
||||
)
|
||||
for aa in analytic_accounts:
|
||||
aa_data[aa["id"]] = aa
|
||||
for aa_id in analytic_account_ids:
|
||||
trial_balance[aa_id]["id"] = aa_id
|
||||
trial_balance[aa_id]["type"] = "analytic_account_type"
|
||||
trial_balance[aa_id]["name"] = (
|
||||
aa_data[aa_id]["display_name"]
|
||||
if aa_id in aa_data
|
||||
else _("Without analytic account")
|
||||
)
|
||||
account_data_item = list(trial_balance[aa_id]["account_data"].values())
|
||||
account_data_item = sorted(account_data_item, key=lambda k: k["code"])
|
||||
trial_balance[aa_id]["account_data"] = account_data_item
|
||||
for f_name in f_names:
|
||||
if f_name in trial_balance[aa_id]:
|
||||
total_amount_grouped[f_name] += trial_balance[aa_id][f_name]
|
||||
trial_balance = list(trial_balance.values())
|
||||
trial_balance = sorted(trial_balance, key=lambda k: k["name"])
|
||||
return trial_balance, total_amount_grouped
|
||||
|
||||
def _get_hierarchy_groups(self, group_ids, groups_data, foreign_currency):
|
||||
for group_id in group_ids:
|
||||
parent_id = groups_data[group_id]["parent_id"]
|
||||
while parent_id:
|
||||
if parent_id not in groups_data.keys():
|
||||
group = self.env["account.group"].browse(parent_id)
|
||||
groups_data[group.id] = {
|
||||
"id": group.id,
|
||||
"code": group.code_prefix_start,
|
||||
"name": group.name,
|
||||
"parent_id": group.parent_id.id,
|
||||
"complete_code": group.complete_code,
|
||||
"account_ids": group.compute_account_ids.ids,
|
||||
"type": "group_type",
|
||||
"initial_balance": 0,
|
||||
"debit": 0,
|
||||
"credit": 0,
|
||||
"balance": 0,
|
||||
"ending_balance": 0,
|
||||
}
|
||||
if foreign_currency:
|
||||
groups_data[group.id].update(
|
||||
initial_currency_balance=0,
|
||||
ending_currency_balance=0,
|
||||
)
|
||||
acc_keys = ["debit", "credit", "balance"]
|
||||
acc_keys += ["initial_balance", "ending_balance"]
|
||||
for acc_key in acc_keys:
|
||||
groups_data[parent_id][acc_key] += groups_data[group_id][acc_key]
|
||||
if foreign_currency:
|
||||
groups_data[group_id]["initial_currency_balance"] += groups_data[
|
||||
group_id
|
||||
]["initial_currency_balance"]
|
||||
groups_data[group_id]["ending_currency_balance"] += groups_data[
|
||||
group_id
|
||||
]["ending_currency_balance"]
|
||||
parent_id = groups_data[parent_id]["parent_id"]
|
||||
return groups_data
|
||||
|
||||
def _get_groups_data(self, accounts_data, total_amount, foreign_currency):
|
||||
accounts_ids = list(accounts_data.keys())
|
||||
accounts = self.env["account.account"].browse(accounts_ids)
|
||||
account_group_relation = {}
|
||||
for account in accounts:
|
||||
accounts_data[account.id]["complete_code"] = (
|
||||
account.group_id.complete_code + " / " + account.code
|
||||
if account.group_id.id
|
||||
else ""
|
||||
)
|
||||
if account.group_id.id:
|
||||
if account.group_id.id not in account_group_relation.keys():
|
||||
account_group_relation.update({account.group_id.id: [account.id]})
|
||||
else:
|
||||
account_group_relation[account.group_id.id].append(account.id)
|
||||
groups = self.env["account.group"].browse(account_group_relation.keys())
|
||||
groups_data = {}
|
||||
for group in groups:
|
||||
groups_data.update(
|
||||
{
|
||||
group.id: {
|
||||
"id": group.id,
|
||||
"code": group.code_prefix_start,
|
||||
"name": group.name,
|
||||
"parent_id": group.parent_id.id,
|
||||
"type": "group_type",
|
||||
"complete_code": group.complete_code,
|
||||
"account_ids": group.compute_account_ids.ids,
|
||||
"initial_balance": 0.0,
|
||||
"credit": 0.0,
|
||||
"debit": 0.0,
|
||||
"balance": 0.0,
|
||||
"ending_balance": 0.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
if foreign_currency:
|
||||
groups_data[group.id]["initial_currency_balance"] = 0.0
|
||||
groups_data[group.id]["ending_currency_balance"] = 0.0
|
||||
for group_id in account_group_relation.keys():
|
||||
for account_id in account_group_relation[group_id]:
|
||||
groups_data[group_id]["initial_balance"] += total_amount[account_id][
|
||||
"initial_balance"
|
||||
]
|
||||
groups_data[group_id]["debit"] += total_amount[account_id]["debit"]
|
||||
groups_data[group_id]["credit"] += total_amount[account_id]["credit"]
|
||||
groups_data[group_id]["balance"] += total_amount[account_id]["balance"]
|
||||
groups_data[group_id]["ending_balance"] += total_amount[account_id][
|
||||
"ending_balance"
|
||||
]
|
||||
if foreign_currency:
|
||||
groups_data[group_id]["initial_currency_balance"] += total_amount[
|
||||
account_id
|
||||
]["initial_currency_balance"]
|
||||
groups_data[group_id]["ending_currency_balance"] += total_amount[
|
||||
account_id
|
||||
]["ending_currency_balance"]
|
||||
group_ids = list(groups_data.keys())
|
||||
groups_data = self._get_hierarchy_groups(
|
||||
group_ids,
|
||||
groups_data,
|
||||
foreign_currency,
|
||||
)
|
||||
return groups_data
|
||||
|
||||
def _get_computed_groups_data(self, accounts_data, total_amount, foreign_currency):
|
||||
groups = self.env["account.group"].search([("id", "!=", False)])
|
||||
groups_data = {}
|
||||
for group in groups:
|
||||
len_group_code = len(group.code_prefix_start)
|
||||
groups_data.update(
|
||||
{
|
||||
group.id: {
|
||||
"id": group.id,
|
||||
"code": group.code_prefix_start,
|
||||
"name": group.name,
|
||||
"parent_id": group.parent_id.id,
|
||||
"type": "group_type",
|
||||
"complete_code": group.complete_code,
|
||||
"account_ids": group.compute_account_ids.ids,
|
||||
"initial_balance": 0.0,
|
||||
"credit": 0.0,
|
||||
"debit": 0.0,
|
||||
"balance": 0.0,
|
||||
"ending_balance": 0.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
if foreign_currency:
|
||||
groups_data[group.id]["initial_currency_balance"] = 0.0
|
||||
groups_data[group.id]["ending_currency_balance"] = 0.0
|
||||
for account in accounts_data.values():
|
||||
if group.code_prefix_start == account["code"][:len_group_code]:
|
||||
acc_id = account["id"]
|
||||
group_id = group.id
|
||||
groups_data[group_id]["initial_balance"] += total_amount[acc_id][
|
||||
"initial_balance"
|
||||
]
|
||||
groups_data[group_id]["debit"] += total_amount[acc_id]["debit"]
|
||||
groups_data[group_id]["credit"] += total_amount[acc_id]["credit"]
|
||||
groups_data[group_id]["balance"] += total_amount[acc_id]["balance"]
|
||||
groups_data[group_id]["ending_balance"] += total_amount[acc_id][
|
||||
"ending_balance"
|
||||
]
|
||||
if foreign_currency:
|
||||
groups_data[group_id]["initial_currency_balance"] += (
|
||||
total_amount[acc_id]["initial_currency_balance"]
|
||||
)
|
||||
groups_data[group_id]["ending_currency_balance"] += (
|
||||
total_amount[acc_id]["ending_currency_balance"]
|
||||
)
|
||||
return groups_data
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
show_partner_details = data["show_partner_details"]
|
||||
wizard_id = data["wizard_id"]
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
company_id = data["company_id"]
|
||||
partner_ids = data["partner_ids"]
|
||||
journal_ids = data["journal_ids"]
|
||||
account_ids = data["account_ids"]
|
||||
date_to = data["date_to"]
|
||||
date_from = data["date_from"]
|
||||
hide_account_at_0 = data["hide_account_at_0"]
|
||||
show_hierarchy = data["show_hierarchy"]
|
||||
show_hierarchy_level = data["show_hierarchy_level"]
|
||||
foreign_currency = data["foreign_currency"]
|
||||
only_posted_moves = data["only_posted_moves"]
|
||||
unaffected_earnings_account = data["unaffected_earnings_account"]
|
||||
fy_start_date = data["fy_start_date"]
|
||||
grouped_by = data["grouped_by"]
|
||||
total_amount, accounts_data, partners_data = self._get_data(
|
||||
account_ids,
|
||||
journal_ids,
|
||||
partner_ids,
|
||||
company_id,
|
||||
date_to,
|
||||
date_from,
|
||||
foreign_currency,
|
||||
only_posted_moves,
|
||||
show_partner_details,
|
||||
hide_account_at_0,
|
||||
unaffected_earnings_account,
|
||||
fy_start_date,
|
||||
grouped_by,
|
||||
)
|
||||
trial_balance_grouped = False
|
||||
total_amount_grouped = False
|
||||
if grouped_by:
|
||||
trial_balance_grouped, total_amount_grouped = self._get_data_grouped(
|
||||
total_amount, accounts_data, foreign_currency
|
||||
)
|
||||
trial_balance = []
|
||||
if not show_partner_details:
|
||||
for account_id in accounts_data.keys():
|
||||
accounts_data[account_id].update(
|
||||
{
|
||||
"initial_balance": total_amount[account_id]["initial_balance"],
|
||||
"credit": total_amount[account_id]["credit"],
|
||||
"debit": total_amount[account_id]["debit"],
|
||||
"balance": total_amount[account_id]["balance"],
|
||||
"ending_balance": total_amount[account_id]["ending_balance"],
|
||||
"group_by": (
|
||||
total_amount[account_id]["group_by"]
|
||||
if "group_by" in total_amount[account_id]
|
||||
else False
|
||||
),
|
||||
"group_by_data": (
|
||||
total_amount[account_id]["group_by_data"]
|
||||
if "group_by_data" in total_amount[account_id]
|
||||
else False
|
||||
),
|
||||
"type": "account_type",
|
||||
}
|
||||
)
|
||||
if foreign_currency:
|
||||
accounts_data[account_id].update(
|
||||
{
|
||||
"ending_currency_balance": total_amount[account_id][
|
||||
"ending_currency_balance"
|
||||
],
|
||||
"initial_currency_balance": total_amount[account_id][
|
||||
"initial_currency_balance"
|
||||
],
|
||||
}
|
||||
)
|
||||
if show_hierarchy:
|
||||
groups_data = self._get_groups_data(
|
||||
accounts_data, total_amount, foreign_currency
|
||||
)
|
||||
trial_balance = list(groups_data.values())
|
||||
trial_balance += list(accounts_data.values())
|
||||
trial_balance = sorted(trial_balance, key=lambda k: k["complete_code"])
|
||||
for trial in trial_balance:
|
||||
counter = trial["complete_code"].count("/")
|
||||
trial["level"] = counter
|
||||
else:
|
||||
trial_balance = list(accounts_data.values())
|
||||
trial_balance = sorted(trial_balance, key=lambda k: k["code"])
|
||||
else:
|
||||
if foreign_currency:
|
||||
for account_id in accounts_data.keys():
|
||||
total_amount[account_id]["currency_id"] = accounts_data[account_id][
|
||||
"currency_id"
|
||||
]
|
||||
total_amount[account_id]["currency_name"] = accounts_data[
|
||||
account_id
|
||||
]["currency_name"]
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "trial.balance.report.wizard",
|
||||
"docs": self.env["trial.balance.report.wizard"].browse(wizard_id),
|
||||
"foreign_currency": data["foreign_currency"],
|
||||
"company_name": company.display_name,
|
||||
"company_currency": company.currency_id,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_from": data["date_from"],
|
||||
"date_to": data["date_to"],
|
||||
"only_posted_moves": data["only_posted_moves"],
|
||||
"hide_account_at_0": data["hide_account_at_0"],
|
||||
"show_partner_details": data["show_partner_details"],
|
||||
"limit_hierarchy_level": data["limit_hierarchy_level"],
|
||||
"show_hierarchy": show_hierarchy,
|
||||
"hide_parent_hierarchy_level": data["hide_parent_hierarchy_level"],
|
||||
"trial_balance": trial_balance,
|
||||
"trial_balance_grouped": trial_balance_grouped,
|
||||
"total_amount": total_amount,
|
||||
"total_amount_grouped": total_amount_grouped,
|
||||
"accounts_data": accounts_data,
|
||||
"partners_data": partners_data,
|
||||
"show_hierarchy_level": show_hierarchy_level,
|
||||
"currency_model": self.env["res.currency"],
|
||||
"grouped_by": grouped_by,
|
||||
}
|
||||
323
account_financial_report/report/trial_balance_xlsx.py
Normal file
323
account_financial_report/report/trial_balance_xlsx.py
Normal file
@@ -0,0 +1,323 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class TrialBalanceXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_trial_balance_xlsx"
|
||||
_description = "Trial Balance XLSX Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data=False):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = _("Trial Balance")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
if not report.show_partner_details:
|
||||
res = {
|
||||
0: {"header": _("Code"), "field": "code", "width": 10},
|
||||
1: {"header": _("Account"), "field": "name", "width": 60},
|
||||
2: {
|
||||
"header": _("Initial balance"),
|
||||
"field": "initial_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
3: {
|
||||
"header": _("Debit"),
|
||||
"field": "debit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
4: {
|
||||
"header": _("Credit"),
|
||||
"field": "credit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
5: {
|
||||
"header": _("Period balance"),
|
||||
"field": "balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
6: {
|
||||
"header": _("Ending balance"),
|
||||
"field": "ending_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
if report.foreign_currency:
|
||||
foreign_currency = {
|
||||
7: {
|
||||
"header": _("Initial balance"),
|
||||
"field": "initial_currency_balance",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
8: {
|
||||
"header": _("Ending balance"),
|
||||
"field": "ending_currency_balance",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
res = {**res, **foreign_currency}
|
||||
return res
|
||||
else:
|
||||
res = {
|
||||
0: {"header": _("Partner"), "field": "name", "width": 70},
|
||||
1: {
|
||||
"header": _("Initial balance"),
|
||||
"field": "initial_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
2: {
|
||||
"header": _("Debit"),
|
||||
"field": "debit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
3: {
|
||||
"header": _("Credit"),
|
||||
"field": "credit",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
4: {
|
||||
"header": _("Period balance"),
|
||||
"field": "balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
5: {
|
||||
"header": _("Ending balance"),
|
||||
"field": "ending_balance",
|
||||
"type": "amount",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
if report.foreign_currency:
|
||||
foreign_currency = {
|
||||
6: {
|
||||
"header": _("Initial balance"),
|
||||
"field": "initial_currency_balance",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
7: {
|
||||
"header": _("Ending balance"),
|
||||
"field": "ending_currency_balance",
|
||||
"type": "amount_currency",
|
||||
"width": 14,
|
||||
},
|
||||
}
|
||||
res = {**res, **foreign_currency}
|
||||
return res
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[
|
||||
_("Date range filter"),
|
||||
_("From: %(date_from)s To: %(date_to)s")
|
||||
% ({"date_from": report.date_from, "date_to": report.date_to}),
|
||||
],
|
||||
[
|
||||
_("Target moves filter"),
|
||||
_("All posted entries")
|
||||
if report.target_move == "posted"
|
||||
else _("All entries"),
|
||||
],
|
||||
[
|
||||
_("Account at 0 filter"),
|
||||
_("Hide") if report.hide_account_at_0 else _("Show"),
|
||||
],
|
||||
[
|
||||
_("Show foreign currency"),
|
||||
_("Yes") if report.foreign_currency else _("No"),
|
||||
],
|
||||
[
|
||||
_("Limit hierarchy levels"),
|
||||
_("Level %s") % (report.show_hierarchy_level)
|
||||
if report.limit_hierarchy_level
|
||||
else _("No limit"),
|
||||
],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 3
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.trial_balance"
|
||||
]._get_report_values(report, data)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
trial_balance_grouped = res_data["trial_balance_grouped"]
|
||||
total_amount = res_data["total_amount"]
|
||||
total_amount_grouped = res_data["total_amount_grouped"]
|
||||
partners_data = res_data["partners_data"]
|
||||
accounts_data = res_data["accounts_data"]
|
||||
show_hierarchy = res_data["show_hierarchy"]
|
||||
show_partner_details = res_data["show_partner_details"]
|
||||
show_hierarchy_level = res_data["show_hierarchy_level"]
|
||||
foreign_currency = res_data["foreign_currency"]
|
||||
limit_hierarchy_level = res_data["limit_hierarchy_level"]
|
||||
hide_parent_hierarchy_level = res_data["hide_parent_hierarchy_level"]
|
||||
grouped_by = res_data["grouped_by"]
|
||||
if not show_partner_details:
|
||||
if grouped_by:
|
||||
# For each grouped
|
||||
for grouped_item in trial_balance_grouped:
|
||||
self.write_array_title(grouped_item["name"], report_data)
|
||||
# Display array header for account lines
|
||||
self.write_array_header(report_data)
|
||||
# For each account
|
||||
for balance in grouped_item["account_data"]:
|
||||
self.write_line_from_dict(balance, report_data)
|
||||
# Footer with totals
|
||||
grouped_item["code"] = ""
|
||||
grouped_item["currency_id"] = False
|
||||
self.write_account_footer(grouped_item, _("Total"), report_data)
|
||||
report_data["row_pos"] += 1
|
||||
# Last line with totals
|
||||
total_amount_grouped["currency_id"] = False
|
||||
total_amount_grouped["code"] = ""
|
||||
self.write_account_footer(total_amount_grouped, _("TOTAL"), report_data)
|
||||
else:
|
||||
# Display array header for account lines
|
||||
self.write_array_header(report_data)
|
||||
# For each account
|
||||
for balance in trial_balance:
|
||||
if show_hierarchy and limit_hierarchy_level:
|
||||
if show_hierarchy_level > balance["level"] and (
|
||||
not hide_parent_hierarchy_level
|
||||
or (show_hierarchy_level - 1) == balance["level"]
|
||||
):
|
||||
# Display account lines
|
||||
self.write_line_from_dict(balance, report_data)
|
||||
else:
|
||||
self.write_line_from_dict(balance, report_data)
|
||||
else:
|
||||
for account_id in total_amount:
|
||||
# Write account title
|
||||
self.write_array_title(
|
||||
accounts_data[account_id]["code"]
|
||||
+ "- "
|
||||
+ accounts_data[account_id]["name"],
|
||||
report_data,
|
||||
)
|
||||
# Display array header for partner lines
|
||||
self.write_array_header(report_data)
|
||||
|
||||
# For each partner
|
||||
for partner_id in total_amount[account_id]:
|
||||
if isinstance(partner_id, int):
|
||||
# Display partner lines
|
||||
self.write_line_from_dict_order(
|
||||
total_amount[account_id][partner_id],
|
||||
partners_data[partner_id],
|
||||
report_data,
|
||||
)
|
||||
|
||||
# Display account footer line
|
||||
accounts_data[account_id].update(
|
||||
{
|
||||
"initial_balance": total_amount[account_id]["initial_balance"],
|
||||
"credit": total_amount[account_id]["credit"],
|
||||
"debit": total_amount[account_id]["debit"],
|
||||
"balance": total_amount[account_id]["balance"],
|
||||
"ending_balance": total_amount[account_id]["ending_balance"],
|
||||
}
|
||||
)
|
||||
if foreign_currency:
|
||||
accounts_data[account_id].update(
|
||||
{
|
||||
"initial_currency_balance": total_amount[account_id][
|
||||
"initial_currency_balance"
|
||||
],
|
||||
"ending_currency_balance": total_amount[account_id][
|
||||
"ending_currency_balance"
|
||||
],
|
||||
}
|
||||
)
|
||||
self.write_account_footer(
|
||||
accounts_data[account_id],
|
||||
accounts_data[account_id]["code"]
|
||||
+ "- "
|
||||
+ accounts_data[account_id]["name"],
|
||||
report_data,
|
||||
)
|
||||
|
||||
# Line break
|
||||
report_data["row_pos"] += 2
|
||||
|
||||
def write_line_from_dict_order(self, total_amount, partner_data, report_data):
|
||||
total_amount.update({"name": str(partner_data["name"])})
|
||||
self.write_line_from_dict(total_amount, report_data)
|
||||
|
||||
def write_line(self, line_object, type_object, report_data):
|
||||
"""Write a line on current line using all defined columns field name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
if type_object == "partner":
|
||||
line_object.currency_id = line_object.report_account_id.currency_id
|
||||
elif type_object == "account":
|
||||
line_object.currency_id = line_object.currency_id
|
||||
return super().write_line(line_object, report_data)
|
||||
|
||||
def write_account_footer(self, account, name_value, report_data):
|
||||
"""Specific function to write account footer for Trial Balance"""
|
||||
format_amt = self._get_currency_amt_header_format_dict(account, report_data)
|
||||
for col_pos, column in report_data["columns"].items():
|
||||
if column["field"] == "name":
|
||||
value = name_value
|
||||
else:
|
||||
value = account[column["field"]]
|
||||
cell_type = column.get("type", "string")
|
||||
if cell_type == "string":
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value or "",
|
||||
report_data["formats"]["format_header_left"],
|
||||
)
|
||||
elif cell_type == "amount":
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
float(value),
|
||||
report_data["formats"]["format_header_amount"],
|
||||
)
|
||||
elif cell_type == "many2one" and account["currency_id"]:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
value.name or "",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
elif cell_type == "amount_currency" and account["currency_id"]:
|
||||
report_data["sheet"].write_number(
|
||||
report_data["row_pos"], col_pos, float(value), format_amt
|
||||
)
|
||||
else:
|
||||
report_data["sheet"].write_string(
|
||||
report_data["row_pos"],
|
||||
col_pos,
|
||||
"",
|
||||
report_data["formats"]["format_header_right"],
|
||||
)
|
||||
report_data["row_pos"] += 1
|
||||
243
account_financial_report/report/vat_report.py
Normal file
243
account_financial_report/report/vat_report.py
Normal file
@@ -0,0 +1,243 @@
|
||||
# Copyright 2018 Forest and Biomass Romania
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import operator
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class VATReport(models.AbstractModel):
|
||||
_name = "report.account_financial_report.vat_report"
|
||||
_description = "Vat Report Report"
|
||||
|
||||
def _get_tax_data(self, tax_ids):
|
||||
taxes = self.env["account.tax"].browse(tax_ids)
|
||||
tax_data = {}
|
||||
for tax in taxes:
|
||||
tax_data.update(
|
||||
{
|
||||
tax.id: {
|
||||
"id": tax.id,
|
||||
"name": tax.name,
|
||||
"tax_group_id": tax.tax_group_id.id,
|
||||
"type_tax_use": tax.type_tax_use,
|
||||
"amount_type": tax.amount_type,
|
||||
"tags_ids": tax.invoice_repartition_line_ids.tag_ids.ids,
|
||||
}
|
||||
}
|
||||
)
|
||||
return tax_data
|
||||
|
||||
@api.model
|
||||
def _get_tax_report_domain(self, company_id, date_from, date_to, only_posted_moves):
|
||||
domain = [
|
||||
("company_id", "=", company_id),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
("tax_line_id", "!=", False),
|
||||
] + self.env["account.move.line"]._get_tax_exigible_domain()
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
return domain
|
||||
|
||||
@api.model
|
||||
def _get_net_report_domain(self, company_id, date_from, date_to, only_posted_moves):
|
||||
domain = [
|
||||
("company_id", "=", company_id),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
] + self.env["account.move.line"]._get_tax_exigible_domain()
|
||||
if only_posted_moves:
|
||||
domain += [("move_id.state", "=", "posted")]
|
||||
else:
|
||||
domain += [("move_id.state", "in", ["posted", "draft"])]
|
||||
return domain
|
||||
|
||||
def _get_vat_report_data(self, company_id, date_from, date_to, only_posted_moves):
|
||||
tax_domain = self._get_tax_report_domain(
|
||||
company_id, date_from, date_to, only_posted_moves
|
||||
)
|
||||
ml_fields = self._get_ml_fields_vat_report()
|
||||
tax_move_lines = self.env["account.move.line"].search_read(
|
||||
domain=tax_domain,
|
||||
fields=ml_fields,
|
||||
)
|
||||
net_domain = self._get_net_report_domain(
|
||||
company_id, date_from, date_to, only_posted_moves
|
||||
)
|
||||
taxed_move_lines = self.env["account.move.line"].search_read(
|
||||
domain=net_domain,
|
||||
fields=ml_fields,
|
||||
)
|
||||
taxed_move_lines = list(filter(lambda d: d["tax_ids"], taxed_move_lines))
|
||||
vat_data = []
|
||||
for tax_move_line in tax_move_lines:
|
||||
vat_data.append(
|
||||
{
|
||||
"net": 0.0,
|
||||
"tax": tax_move_line["balance"],
|
||||
"tax_line_id": tax_move_line["tax_line_id"][0],
|
||||
}
|
||||
)
|
||||
for taxed_move_line in taxed_move_lines:
|
||||
for tax_id in taxed_move_line["tax_ids"]:
|
||||
vat_data.append(
|
||||
{
|
||||
"net": taxed_move_line["balance"],
|
||||
"tax": 0.0,
|
||||
"tax_line_id": tax_id,
|
||||
}
|
||||
)
|
||||
tax_ids = list(map(operator.itemgetter("tax_line_id"), vat_data))
|
||||
tax_ids = list(set(tax_ids))
|
||||
tax_data = self._get_tax_data(tax_ids)
|
||||
return vat_data, tax_data
|
||||
|
||||
def _get_tax_group_data(self, tax_group_ids):
|
||||
tax_groups = self.env["account.tax.group"].search_fetch(
|
||||
[("id", "in", tax_group_ids)], ["name", "sequence"]
|
||||
)
|
||||
tax_group_data = {}
|
||||
for tax_group in tax_groups:
|
||||
tax_group_data.update(
|
||||
{
|
||||
tax_group.id: {
|
||||
"id": tax_group.id,
|
||||
"name": tax_group.name,
|
||||
"code": str(tax_group.sequence),
|
||||
}
|
||||
}
|
||||
)
|
||||
return tax_group_data
|
||||
|
||||
def _get_vat_report_group_data(self, vat_report_data, tax_data, tax_detail):
|
||||
vat_report = {}
|
||||
for tax_move_line in vat_report_data:
|
||||
tax_id = tax_move_line["tax_line_id"]
|
||||
if tax_data[tax_id]["amount_type"] == "group":
|
||||
pass
|
||||
else:
|
||||
tax_group_id = tax_data[tax_id]["tax_group_id"]
|
||||
if tax_group_id not in vat_report.keys():
|
||||
vat_report[tax_group_id] = {}
|
||||
vat_report[tax_group_id]["net"] = 0.0
|
||||
vat_report[tax_group_id]["tax"] = 0.0
|
||||
vat_report[tax_group_id][tax_id] = dict(tax_data[tax_id])
|
||||
vat_report[tax_group_id][tax_id].update({"net": 0.0, "tax": 0.0})
|
||||
else:
|
||||
if tax_id not in vat_report[tax_group_id].keys():
|
||||
vat_report[tax_group_id][tax_id] = dict(tax_data[tax_id])
|
||||
vat_report[tax_group_id][tax_id].update(
|
||||
{"net": 0.0, "tax": 0.0}
|
||||
)
|
||||
vat_report[tax_group_id]["net"] += tax_move_line["net"]
|
||||
vat_report[tax_group_id]["tax"] += tax_move_line["tax"]
|
||||
vat_report[tax_group_id][tax_id]["net"] += tax_move_line["net"]
|
||||
vat_report[tax_group_id][tax_id]["tax"] += tax_move_line["tax"]
|
||||
tax_group_data = self._get_tax_group_data(list(vat_report.keys()))
|
||||
vat_report_list = []
|
||||
for tax_group_id in vat_report.keys():
|
||||
vat_report[tax_group_id]["name"] = tax_group_data[tax_group_id]["name"]
|
||||
vat_report[tax_group_id]["code"] = tax_group_data[tax_group_id]["code"]
|
||||
if tax_detail:
|
||||
vat_report[tax_group_id]["taxes"] = []
|
||||
for tax_id in vat_report[tax_group_id]:
|
||||
if isinstance(tax_id, int):
|
||||
vat_report[tax_group_id]["taxes"].append(
|
||||
vat_report[tax_group_id][tax_id]
|
||||
)
|
||||
vat_report_list.append(vat_report[tax_group_id])
|
||||
return vat_report_list
|
||||
|
||||
def _get_tags_data(self, tags_ids):
|
||||
tags = self.env["account.account.tag"].search_fetch(
|
||||
[("id", "in", tags_ids)], ["name"]
|
||||
)
|
||||
tags_data = {}
|
||||
for tag in tags:
|
||||
tags_data.update({tag.id: {"code": "", "name": tag.name}})
|
||||
return tags_data
|
||||
|
||||
def _get_vat_report_tag_data(self, vat_report_data, tax_data, tax_detail):
|
||||
vat_report = {}
|
||||
for tax_move_line in vat_report_data:
|
||||
tax_id = tax_move_line["tax_line_id"]
|
||||
tags_ids = tax_data[tax_id]["tags_ids"]
|
||||
if tax_data[tax_id]["amount_type"] == "group":
|
||||
continue
|
||||
else:
|
||||
if tags_ids:
|
||||
for tag_id in tags_ids:
|
||||
if tag_id not in vat_report.keys():
|
||||
vat_report[tag_id] = {}
|
||||
vat_report[tag_id]["net"] = 0.0
|
||||
vat_report[tag_id]["tax"] = 0.0
|
||||
vat_report[tag_id][tax_id] = dict(tax_data[tax_id])
|
||||
vat_report[tag_id][tax_id].update({"net": 0.0, "tax": 0.0})
|
||||
else:
|
||||
if tax_id not in vat_report[tag_id].keys():
|
||||
vat_report[tag_id][tax_id] = dict(tax_data[tax_id])
|
||||
vat_report[tag_id][tax_id].update(
|
||||
{"net": 0.0, "tax": 0.0}
|
||||
)
|
||||
vat_report[tag_id][tax_id]["net"] += tax_move_line["net"]
|
||||
vat_report[tag_id][tax_id]["tax"] += tax_move_line["tax"]
|
||||
vat_report[tag_id]["net"] += tax_move_line["net"]
|
||||
vat_report[tag_id]["tax"] += tax_move_line["tax"]
|
||||
tags_data = self._get_tags_data(list(vat_report.keys()))
|
||||
vat_report_list = []
|
||||
for tag_id in vat_report.keys():
|
||||
vat_report[tag_id]["name"] = tags_data[tag_id]["name"]
|
||||
vat_report[tag_id]["code"] = tags_data[tag_id]["code"]
|
||||
if tax_detail:
|
||||
vat_report[tag_id]["taxes"] = []
|
||||
for tax_id in vat_report[tag_id]:
|
||||
if isinstance(tax_id, int):
|
||||
vat_report[tag_id]["taxes"].append(vat_report[tag_id][tax_id])
|
||||
vat_report_list.append(vat_report[tag_id])
|
||||
return vat_report_list
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
wizard_id = data["wizard_id"]
|
||||
company = self.env["res.company"].browse(data["company_id"])
|
||||
company_id = data["company_id"]
|
||||
date_from = data["date_from"]
|
||||
date_to = data["date_to"]
|
||||
based_on = data["based_on"]
|
||||
tax_detail = data["tax_detail"]
|
||||
only_posted_moves = data["only_posted_moves"]
|
||||
vat_report_data, tax_data = self._get_vat_report_data(
|
||||
company_id, date_from, date_to, only_posted_moves
|
||||
)
|
||||
if based_on == "taxgroups":
|
||||
vat_report = self._get_vat_report_group_data(
|
||||
vat_report_data, tax_data, tax_detail
|
||||
)
|
||||
else:
|
||||
vat_report = self._get_vat_report_tag_data(
|
||||
vat_report_data, tax_data, tax_detail
|
||||
)
|
||||
return {
|
||||
"doc_ids": [wizard_id],
|
||||
"doc_model": "vat.report.wizard",
|
||||
"docs": self.env["vat.report.wizard"].browse(wizard_id),
|
||||
"company_name": company.display_name,
|
||||
"currency_name": company.currency_id.name,
|
||||
"date_to": data["date_to"],
|
||||
"date_from": data["date_from"],
|
||||
"based_on": data["based_on"],
|
||||
"tax_detail": data["tax_detail"],
|
||||
"vat_report": vat_report,
|
||||
}
|
||||
|
||||
def _get_ml_fields_vat_report(self):
|
||||
return [
|
||||
"id",
|
||||
"tax_base_amount",
|
||||
"balance",
|
||||
"tax_line_id",
|
||||
"tax_ids",
|
||||
]
|
||||
61
account_financial_report/report/vat_report_xlsx.py
Normal file
61
account_financial_report/report/vat_report_xlsx.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2018 Forest and Biomass Romania
|
||||
# Copyright 2021 Tecnativa - João Marques
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class VATReportXslx(models.AbstractModel):
|
||||
_name = "report.a_f_r.report_vat_report_xlsx"
|
||||
_description = "Vat Report XLSX Report"
|
||||
_inherit = "report.account_financial_report.abstract_report_xlsx"
|
||||
|
||||
def _get_report_name(self, report, data):
|
||||
company_id = data.get("company_id", False)
|
||||
report_name = _("Vat Report")
|
||||
if company_id:
|
||||
company = self.env["res.company"].browse(company_id)
|
||||
suffix = f" - {company.name} - {company.currency_id.name}"
|
||||
report_name = report_name + suffix
|
||||
return report_name
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
return {
|
||||
0: {"header": _("Code"), "field": "code", "width": 5},
|
||||
1: {"header": _("Name"), "field": "name", "width": 100},
|
||||
2: {"header": _("Net"), "field": "net", "type": "amount", "width": 14},
|
||||
3: {"header": _("Tax"), "field": "tax", "type": "amount", "width": 14},
|
||||
}
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_("Date from"), report.date_from.strftime("%d/%m/%Y")],
|
||||
[_("Date to"), report.date_to.strftime("%d/%m/%Y")],
|
||||
[
|
||||
_("Based on"),
|
||||
_("Tax Tags") if report.based_on == "taxtags" else _("Tax Groups"),
|
||||
],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 0
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 2
|
||||
|
||||
def _generate_report_content(self, workbook, report, data, report_data):
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.vat_report"
|
||||
]._get_report_values(report, data)
|
||||
vat_report = res_data["vat_report"]
|
||||
tax_detail = res_data["tax_detail"]
|
||||
# For each tax_tag tax_group
|
||||
self.write_array_header(report_data)
|
||||
for tag_or_group in vat_report:
|
||||
# Write taxtag line
|
||||
self.write_line_from_dict(tag_or_group, report_data)
|
||||
|
||||
# For each tax if detail taxes
|
||||
if tax_detail:
|
||||
for tax in tag_or_group["taxes"]:
|
||||
self.write_line_from_dict(tax, report_data)
|
||||
173
account_financial_report/reports.xml
Normal file
173
account_financial_report/reports.xml
Normal file
@@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<!-- PDF REPORTS : paperformat -->
|
||||
<record id="report_qweb_paperformat" model="report.paperformat">
|
||||
<field name="name">Account financial report qweb paperformat</field>
|
||||
<field name="default" eval="True" />
|
||||
<field name="format">custom</field>
|
||||
<field name="page_height">297</field>
|
||||
<field name="page_width">210</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">12</field>
|
||||
<field name="margin_bottom">8</field>
|
||||
<field name="margin_left">5</field>
|
||||
<field name="margin_right">5</field>
|
||||
<field name="header_line" eval="False" />
|
||||
<field name="header_spacing">10</field>
|
||||
<field name="dpi">110</field>
|
||||
</record>
|
||||
|
||||
<!-- PDF/HMTL REPORTS -->
|
||||
<!-- General Ledger -->
|
||||
<record id="action_print_report_general_ledger_qweb" model="ir.actions.report">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="model">general.ledger.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.general_ledger</field>
|
||||
<field name="report_file">account_financial_report.general_ledger</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record id="action_print_report_general_ledger_html" model="ir.actions.report">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="model">general.ledger.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.general_ledger</field>
|
||||
<field name="report_file">account_financial_report.general_ledger</field>
|
||||
</record>
|
||||
<!-- Journal Ledger -->
|
||||
<record id="action_print_journal_ledger_wizard_qweb" model="ir.actions.report">
|
||||
<field name="name">ournal Ledger</field>
|
||||
<field name="model">journal.ledger.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.journal_ledger</field>
|
||||
<field name="report_file">account_financial_report.journal_ledger</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record id="action_print_journal_ledger_wizard_html" model="ir.actions.report">
|
||||
<field name="name">Journal Ledger</field>
|
||||
<field name="model">journal.ledger.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.journal_ledger</field>
|
||||
<field name="report_file">account_financial_report.journal_ledger</field>
|
||||
</record>
|
||||
<!-- Trial Balance -->
|
||||
<record id="action_report_trial_balance_qweb" model="ir.actions.report">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="model">trial.balance.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.trial_balance</field>
|
||||
<field name="report_file">account_financial_report.trial_balance</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record id="action_report_trial_balance_html" model="ir.actions.report">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="model">trial.balance.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.trial_balance</field>
|
||||
<field name="report_file">account_financial_report.trial_balance</field>
|
||||
</record>
|
||||
<!-- Open Items -->
|
||||
<record id="action_print_report_open_items_qweb" model="ir.actions.report">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="model">open.items.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.open_items</field>
|
||||
<field name="report_file">account_financial_report.open_items</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record id="action_print_report_open_items_html" model="ir.actions.report">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="model">open.items.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.open_items</field>
|
||||
<field name="report_file">account_financial_report.open_items</field>
|
||||
</record>
|
||||
<!-- Aged Partner Balance -->
|
||||
<record
|
||||
id="action_print_report_aged_partner_balance_qweb"
|
||||
model="ir.actions.report"
|
||||
>
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="model">aged.partner.balance.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.aged_partner_balance</field>
|
||||
<field name="report_file">account_financial_report.aged_partner_balance</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record
|
||||
id="action_print_report_aged_partner_balance_html"
|
||||
model="ir.actions.report"
|
||||
>
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="model">aged.partner.balance.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.aged_partner_balance</field>
|
||||
<field name="report_file">account_financial_report.aged_partner_balance</field>
|
||||
</record>
|
||||
<!-- VAT Report -->
|
||||
<record id="action_print_report_vat_report_qweb" model="ir.actions.report">
|
||||
<field name="name">VAT Report</field>
|
||||
<field name="model">vat.report.wizard</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">account_financial_report.vat_report</field>
|
||||
<field name="report_file">account_financial_report.vat_report</field>
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat" />
|
||||
</record>
|
||||
<record id="action_print_report_vat_report_html" model="ir.actions.report">
|
||||
<field name="name">VAT Report</field>
|
||||
<field name="model">vat.report.wizard</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">account_financial_report.vat_report</field>
|
||||
<field name="report_file">account_financial_report.vat_report</field>
|
||||
</record>
|
||||
|
||||
<!-- XLSX REPORTS -->
|
||||
<record id="action_report_general_ledger_xlsx" model="ir.actions.report">
|
||||
<field name="name">General Ledger XLSX</field>
|
||||
<field name="model">general.ledger.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_general_ledger_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_general_ledger</field>
|
||||
</record>
|
||||
<record id="action_report_journal_ledger_xlsx" model="ir.actions.report">
|
||||
<field name="name">Journal Ledger XLSX</field>
|
||||
<field name="model">journal.ledger.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_journal_ledger_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_journal_ledger</field>
|
||||
</record>
|
||||
<record id="action_report_trial_balance_xlsx" model="ir.actions.report">
|
||||
<field name="name">Trial Balance XLSX</field>
|
||||
<field name="model">trial.balance.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_trial_balance_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_trial_balance</field>
|
||||
</record>
|
||||
<record id="action_report_open_items_xlsx" model="ir.actions.report">
|
||||
<field name="name">Open Items XLSX</field>
|
||||
<field name="model">open.items.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_open_items_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_open_items</field>
|
||||
</record>
|
||||
<record id="action_report_aged_partner_balance_xlsx" model="ir.actions.report">
|
||||
<field name="name">Aged Partner Balance XLSX</field>
|
||||
<field name="model">aged.partner.balance.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_aged_partner_balance_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_aged_partner_balance</field>
|
||||
</record>
|
||||
<record id="action_report_vat_report_xlsx" model="ir.actions.report">
|
||||
<field name="name">VAT Report XLSX</field>
|
||||
<field name="model">vat.report.wizard</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_vat_report_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_vat_report</field>
|
||||
</record>
|
||||
</odoo>
|
||||
9
account_financial_report/security/ir.model.access.csv
Normal file
9
account_financial_report/security/ir.model.access.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_aged_partner_balance_report_wizard,access_aged_partner_balance_report_wizard,model_aged_partner_balance_report_wizard,base.group_user,1,1,1,1
|
||||
access_general_ledger_report_wizard,access_general_ledger_report_wizard,model_general_ledger_report_wizard,base.group_user,1,1,1,1
|
||||
access_journal_ledger_report_wizard,access_journal_ledger_report_wizard,model_journal_ledger_report_wizard,base.group_user,1,1,1,1
|
||||
access_open_items_report_wizard,access_open_items_report_wizard,model_open_items_report_wizard,base.group_user,1,1,1,1
|
||||
access_trial_balance_report_wizard,access_trial_balance_report_wizard,model_trial_balance_report_wizard,base.group_user,1,1,1,1
|
||||
access_vat_report_wizard,access_vat_report_wizard,model_vat_report_wizard,base.group_user,1,1,1,1
|
||||
access_account_age_report_configuration,access_account_age_report_configuration,model_account_age_report_configuration,base.group_user,1,1,1,1
|
||||
access_account_age_report_configuration_line,access_account_age_report_configuration_line,model_account_age_report_configuration_line,base.group_user,1,1,1,1
|
||||
|
8
account_financial_report/security/security.xml
Normal file
8
account_financial_report/security/security.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.rule" id="account_age_report_configuration_rule">
|
||||
<field name="name">Account age report configuration rule</field>
|
||||
<field name="model_id" ref="model_account_age_report_configuration" />
|
||||
<field name="domain_force">[('company_id', 'in', company_ids + [False])]</field>
|
||||
</record>
|
||||
</odoo>
|
||||
BIN
account_financial_report/static/description/icon.png
Normal file
BIN
account_financial_report/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
554
account_financial_report/static/description/index.html
Normal file
554
account_financial_report/static/description/index.html
Normal file
@@ -0,0 +1,554 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>Account Financial Reports</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="account-financial-reports">
|
||||
<h1 class="title">Account Financial Reports</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:4d56adc35fff26b88020bebb3cd0fcb302b7c7c7483639925cfc4f9b850d8ac4
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/account-financial-reporting/tree/18.0/account_financial_report"><img alt="OCA/account-financial-reporting" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--reporting-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/account-financial-reporting-18-0/account-financial-reporting-18-0-account_financial_report"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/account-financial-reporting&target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module adds a set of financial reports. They are accessible under
|
||||
Invoicing / Reporting / OCA accounting reports.</p>
|
||||
<ul class="simple">
|
||||
<li>General ledger</li>
|
||||
<li>Trial Balance</li>
|
||||
<li>Open Items</li>
|
||||
<li>Aged Partner Balance</li>
|
||||
<li>VAT Report</li>
|
||||
<li>Journal Ledger</li>
|
||||
</ul>
|
||||
<p>Currently General ledger, Trial Balance and Open Items are fully
|
||||
compatible with a foreign currency set up in account in order to display
|
||||
balances. Moreover, any foreign currency used in account move lines is
|
||||
properly shown.</p>
|
||||
<p>In case that in an account has not been configured a second currency
|
||||
foreign currency balances are not available.</p>
|
||||
<p>Invoicing / Settings / Invoicing / OCA Aged Report Configuration you
|
||||
will be able to set dynamic intervals that will appear on the Aged
|
||||
Partner Balance. For further information, check CONFIGURE.rst</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-2">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#changelog" id="toc-entry-3">Changelog</a><ul>
|
||||
<li><a class="reference internal" href="#section-1" id="toc-entry-4">11.0.2.5.0 (2019-04-26)</a></li>
|
||||
<li><a class="reference internal" href="#section-2" id="toc-entry-5">11.0.2.4.1 (2019-01-08)</a></li>
|
||||
<li><a class="reference internal" href="#section-3" id="toc-entry-6">11.0.2.3.1 (2018-11-29)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-7">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="toc-entry-8">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="toc-entry-9">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="toc-entry-10">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="toc-entry-11">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-12">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
|
||||
<p>To configure dynamic intervals for Aged Partner Balance you need to:</p>
|
||||
<p>Go on ‘Settings’ -> ‘Invoicing’ -> ‘OCA Aged Report Configuration’.</p>
|
||||
<p>Click on option ‘Configurations’ and create new record.</p>
|
||||
<p>Create new interval. The name established on line will be the column to
|
||||
display in Aged Partner Balance. Inferior limit established on line is
|
||||
the interval</p>
|
||||
<p>Example of configuration inferior limit:</p>
|
||||
<p>-> 15 -> 30 -> 60</p>
|
||||
<p>It means the first interval is from 0 to 15, the second from 16 to 30,
|
||||
and the third is 61+.</p>
|
||||
<p>Go on ‘Invoicing’ -> ‘Reporting’ -> ‘OCA accounting reports’ -> ‘Aged
|
||||
Partner Balance’</p>
|
||||
<p>When wizard is open, you need to select your interval configuration and
|
||||
print report.</p>
|
||||
<p>If you want to get default interval configuration any time you wish to
|
||||
print Aged Partner Report, you can set default interval configuration
|
||||
per company in:</p>
|
||||
<p>‘Settings’ -> ‘Invoicing’ -> ‘OCA Aged Report Configuration’.</p>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1>
|
||||
<ul class="simple">
|
||||
<li>‘VAT Report’ is valid only for cases where it’s met that for each Tax
|
||||
defined: all the “Account tags” of all the ‘Repartition for Invoices’
|
||||
or ‘Repartition for Credit Notes’ are different.</li>
|
||||
<li>It would be nice to have in reports a column indicating the state of
|
||||
the entries when the option “All Entries” is selected in “Target
|
||||
Moves” field in a wizard</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="changelog">
|
||||
<h1><a class="toc-backref" href="#toc-entry-3">Changelog</a></h1>
|
||||
<div class="section" id="section-1">
|
||||
<h2><a class="toc-backref" href="#toc-entry-4">11.0.2.5.0 (2019-04-26)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>In the Trial Balance you have an option to hide parent hierarchy
|
||||
levels</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-2">
|
||||
<h2><a class="toc-backref" href="#toc-entry-5">11.0.2.4.1 (2019-01-08)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Handle better multicompany behaviour</li>
|
||||
<li>Improve how title appears in the reports</li>
|
||||
<li>Improve performance in General Ledger</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-3">
|
||||
<h2><a class="toc-backref" href="#toc-entry-6">11.0.2.3.1 (2018-11-29)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>In the Trial Balance you can apply a filter by hierarchy levels</li>
|
||||
<li>In the General Ledger you can apply a filter by Analytic Tag</li>
|
||||
<li>In the Journal Ledger the field ‘Journal’ is now optional</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#toc-entry-7">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-financial-reporting/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/account-financial-reporting/issues/new?body=module:%20account_financial_report%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#toc-entry-8">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#toc-entry-9">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Camptocamp</li>
|
||||
<li>initOS GmbH</li>
|
||||
<li>redCOR AG</li>
|
||||
<li>ForgeFlow</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#toc-entry-10">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Jordi Ballester <<a class="reference external" href="mailto:jordi.ballester@forgeflow.com">jordi.ballester@forgeflow.com</a>></li>
|
||||
<li>Yannick Vaucher <<a class="reference external" href="mailto:yannick.vaucher@camptocamp.com">yannick.vaucher@camptocamp.com</a>></li>
|
||||
<li>Simone Orsi <<a class="reference external" href="mailto:simone.orsi@abstract.com">simone.orsi@abstract.com</a>></li>
|
||||
<li>Leonardo Pistone <<a class="reference external" href="mailto:leonardo.pistone@camptocamp.com">leonardo.pistone@camptocamp.com</a>></li>
|
||||
<li>Damien Crier <<a class="reference external" href="mailto:damien.crier@camptocamp.com">damien.crier@camptocamp.com</a>></li>
|
||||
<li>Andrea Stirpe <<a class="reference external" href="mailto:a.stirpe@onestein.nl">a.stirpe@onestein.nl</a>></li>
|
||||
<li>Thomas Rehn <<a class="reference external" href="mailto:thomas.rehn@initos.com">thomas.rehn@initos.com</a>></li>
|
||||
<li>Andrea Gallina <<a class="reference external" href="mailto:4everamd@gmail.com">4everamd@gmail.com</a>></li>
|
||||
<li>Robert Rottermann <<a class="reference external" href="mailto:robert@redcor.ch">robert@redcor.ch</a>></li>
|
||||
<li>Ciro Urselli <<a class="reference external" href="mailto:c.urselli@apuliasoftware.it">c.urselli@apuliasoftware.it</a>></li>
|
||||
<li>Francesco Apruzzese <<a class="reference external" href="mailto:opencode@e-ware.org">opencode@e-ware.org</a>></li>
|
||||
<li>Lorenzo Battistini <<a class="reference external" href="https://github.com/eLBati">https://github.com/eLBati</a>></li>
|
||||
<li>Julien Coux <<a class="reference external" href="mailto:julien.coux@camptocamp.com">julien.coux@camptocamp.com</a>></li>
|
||||
<li>Akim Juillerat <<a class="reference external" href="mailto:akim.juillerat@camptocamp.com">akim.juillerat@camptocamp.com</a>></li>
|
||||
<li>Alexis de Lattre <<a class="reference external" href="mailto:alexis@via.ecp.fr">alexis@via.ecp.fr</a>></li>
|
||||
<li>Mihai Fekete <<a class="reference external" href="mailto:feketemihai@gmail.com">feketemihai@gmail.com</a>></li>
|
||||
<li>Miquel Ra??ch <<a class="reference external" href="mailto:miquel.raich@forgeflow.com">miquel.raich@forgeflow.com</a>></li>
|
||||
<li>Joan Sisquella <<a class="reference external" href="mailto:joan.sisquella@forgeflow.com">joan.sisquella@forgeflow.com</a>></li>
|
||||
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
|
||||
<li>Pedro M. Baeza</li>
|
||||
<li>Sergio Teruel</li>
|
||||
<li>Ernesto Tejeda</li>
|
||||
<li>João Marques</li>
|
||||
<li>Alexandre D. D??az</li>
|
||||
<li>V??ctor Mart??nez</li>
|
||||
<li>Carolina Fernandez</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference external" href="https://www.sygel.es">Sygel</a>:<ul>
|
||||
<li>Harald Panten</li>
|
||||
<li>Valentin Vinagre</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Lois Rilo <<a class="reference external" href="mailto:lois.rilo@forgeflow.com">lois.rilo@forgeflow.com</a>></li>
|
||||
<li>Saran Lim. <<a class="reference external" href="mailto:saranl@ecosoft.co.th">saranl@ecosoft.co.th</a>></li>
|
||||
<li>Omar Casti??eira <<a class="reference external" href="mailto:omar@comunitea.com">omar@comunitea.com</a>></li>
|
||||
<li>Chau Le <<a class="reference external" href="mailto:chaulb@trobz.com">chaulb@trobz.com</a>></li>
|
||||
</ul>
|
||||
<p>Much of the work in this module was done at a sprint in Sorrento, Italy
|
||||
in April 2016.</p>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h2><a class="toc-backref" href="#toc-entry-11">Other credits</a></h2>
|
||||
<p>The migration of this module from 17.0 to 18.0 was financially supported
|
||||
by Camptocamp.</p>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#toc-entry-12">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-reporting/tree/18.0/account_financial_report">OCA/account-financial-reporting</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
72
account_financial_report/static/src/js/report.esm.js
Normal file
72
account_financial_report/static/src/js/report.esm.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import {useComponent, useEffect} from "@odoo/owl";
|
||||
|
||||
function toTitleCase(str) {
|
||||
return str
|
||||
.replaceAll(".", " ")
|
||||
.replace(
|
||||
/\w\S*/g,
|
||||
(txt) => `${txt.charAt(0).toUpperCase()}${txt.substr(1).toLowerCase()}`
|
||||
);
|
||||
}
|
||||
|
||||
function enrich(component, targetElement, selector, isIFrame = false) {
|
||||
// eslint-disable-next-line no-undef
|
||||
let doc = window.document;
|
||||
let contentDocument = targetElement;
|
||||
|
||||
// If we are in an iframe, we need to take the right document
|
||||
// both for the element and the doc
|
||||
if (isIFrame) {
|
||||
contentDocument = targetElement.contentDocument;
|
||||
doc = contentDocument;
|
||||
}
|
||||
|
||||
// If there are selector, we may have multiple blocks of code to enrich
|
||||
const targets = [];
|
||||
if (selector) {
|
||||
targets.push(...contentDocument.querySelectorAll(selector));
|
||||
} else {
|
||||
targets.push(contentDocument);
|
||||
}
|
||||
|
||||
// Search the elements with the selector, update them and bind an action.
|
||||
for (const currentTarget of targets) {
|
||||
const elementsToWrap = currentTarget.querySelectorAll("[res-model][domain]");
|
||||
for (const element of elementsToWrap.values()) {
|
||||
const wrapper = doc.createElement("a");
|
||||
wrapper.setAttribute("href", "#");
|
||||
wrapper.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
component.env.services.action.doAction({
|
||||
type: "ir.actions.act_window",
|
||||
res_model: element.getAttribute("res-model"),
|
||||
domain: element.getAttribute("domain"),
|
||||
name: toTitleCase(element.getAttribute("res-model")),
|
||||
views: [
|
||||
[false, "list"],
|
||||
[false, "form"],
|
||||
],
|
||||
});
|
||||
});
|
||||
element.parentNode.insertBefore(wrapper, element);
|
||||
wrapper.appendChild(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useEnrichWithActionLinks(ref, selector = null) {
|
||||
const comp = useComponent();
|
||||
useEffect(
|
||||
(element) => {
|
||||
// If we get an iframe, we need to wait until everything is loaded
|
||||
if (element.matches("iframe")) {
|
||||
element.addEventListener("load", () =>
|
||||
enrich(comp, element, selector, true)
|
||||
);
|
||||
} else {
|
||||
enrich(comp, element, selector);
|
||||
}
|
||||
},
|
||||
() => [ref.el]
|
||||
);
|
||||
}
|
||||
39
account_financial_report/static/src/js/report_action.esm.js
Normal file
39
account_financial_report/static/src/js/report_action.esm.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import {ReportAction} from "@web/webclient/actions/reports/report_action";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
import {useEnrichWithActionLinks} from "./report.esm";
|
||||
|
||||
const MODULE_NAME = "account_financial_report";
|
||||
|
||||
patch(ReportAction.prototype, {
|
||||
setup() {
|
||||
super.setup(...arguments);
|
||||
this.isAccountFinancialReport = this.props.report_name.startsWith(
|
||||
`${MODULE_NAME}.`
|
||||
);
|
||||
useEnrichWithActionLinks(this.iframe);
|
||||
},
|
||||
|
||||
export() {
|
||||
this.action.doAction({
|
||||
type: "ir.actions.report",
|
||||
report_type: "xlsx",
|
||||
report_name: this._get_xlsx_name(this.props.report_name),
|
||||
report_file: this._get_xlsx_name(this.props.report_file),
|
||||
data: this.props.data || {},
|
||||
context: this.props.context || {},
|
||||
display_name: this.title,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} str
|
||||
* @returns {String}
|
||||
*/
|
||||
_get_xlsx_name(str) {
|
||||
if (typeof str !== "string") {
|
||||
return str;
|
||||
}
|
||||
const parts = str.split(".");
|
||||
return `a_f_r.report_${parts[parts.length - 1]}_xlsx`;
|
||||
},
|
||||
});
|
||||
148
account_financial_report/static/src/scss/report.scss
Normal file
148
account_financial_report/static/src/scss/report.scss
Normal file
@@ -0,0 +1,148 @@
|
||||
a {
|
||||
color: #00337b;
|
||||
}
|
||||
|
||||
.act_as_table {
|
||||
display: table !important;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.act_as_row {
|
||||
display: table-row !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.act_as_cell {
|
||||
display: table-cell !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.act_as_thead {
|
||||
display: table-header-group !important;
|
||||
}
|
||||
|
||||
.act_as_tbody {
|
||||
display: table-row-group !important;
|
||||
}
|
||||
|
||||
.list_table,
|
||||
.data_table,
|
||||
.totals_table {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.act_as_row.labels {
|
||||
background-color: #f0f0f0 !important;
|
||||
}
|
||||
|
||||
.list_table,
|
||||
.data_table,
|
||||
.totals_table,
|
||||
.list_table .act_as_row {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
padding: 2px 3px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.totals_table {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.list_table {
|
||||
.act_as_row {
|
||||
&.labels,
|
||||
&.initial_balance,
|
||||
&.lines {
|
||||
border-color: grey !important;
|
||||
border-bottom: 1px solid lightGrey !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.data_table {
|
||||
.act_as_cell {
|
||||
border: 1px solid lightGrey;
|
||||
text-align: center;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.act_as_row.labels {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.totals_table {
|
||||
.act_as_cell {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.act_as_row.labels {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.list_table .act_as_cell {
|
||||
&.first_column {
|
||||
padding-left: 0;
|
||||
/* border-left:1px solid lightGrey; uncomment to active column lines */
|
||||
}
|
||||
|
||||
/* border-right:1px solid lightGrey; uncomment to active column lines */
|
||||
}
|
||||
|
||||
.initial_balance .act_as_cell {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.account_title {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
|
||||
&.labels {
|
||||
background-color: #f0f0f0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.act_as_cell {
|
||||
&.amount {
|
||||
word-wrap: normal;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow_ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.custom_footer {
|
||||
font-size: 7px !important;
|
||||
}
|
||||
|
||||
.page_break {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.button_row {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.o_account_financial_reports_page {
|
||||
padding-top: 10px;
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
font-family: Helvetica, Arial;
|
||||
}
|
||||
10
account_financial_report/static/src/scss/report_html.scss
Normal file
10
account_financial_report/static/src/scss/report_html.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
// Styles of HTML report
|
||||
.account_title {
|
||||
span {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.act_as_cell {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
18
account_financial_report/static/src/xml/report.xml
Normal file
18
account_financial_report/static/src/xml/report.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<!-- Buttons of the Control Panel -->
|
||||
<t
|
||||
t-name="info.ReportAction"
|
||||
t-inherit="web.ReportAction"
|
||||
t-inherit-mode="extension"
|
||||
>
|
||||
<xpath expr="//button" position="after">
|
||||
<button
|
||||
t-if="isAccountFinancialReport"
|
||||
t-on-click="export"
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
title="Export"
|
||||
>Export</button>
|
||||
</xpath>
|
||||
</t>
|
||||
</template>
|
||||
10
account_financial_report/tests/__init__.py
Normal file
10
account_financial_report/tests/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
|
||||
from . import test_aged_partner_balance
|
||||
from . import test_general_ledger
|
||||
from . import test_journal_ledger
|
||||
from . import test_open_items
|
||||
from . import test_trial_balance
|
||||
from . import test_vat_report
|
||||
from . import test_age_report_configuration
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright 2023 Tecnativa - Carolina Fernandez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import common, tagged
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestAccountAgeReportConfiguration(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.account_age_report_config = cls.env[
|
||||
"account.age.report.configuration"
|
||||
].create(
|
||||
{
|
||||
"name": "Intervals configuration",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "1-30",
|
||||
"inferior_limit": 30,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
def test_check_line_ids_constraint(self):
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env["account.age.report.configuration"].create(
|
||||
{"name": "Interval configuration", "line_ids": False}
|
||||
)
|
||||
|
||||
def test_check_lower_inferior_limit_constraint(self):
|
||||
with self.assertRaises(ValidationError):
|
||||
self.account_age_report_config.line_ids.inferior_limit = 0
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
self.account_age_report_config.line_ids.inferior_limit = -1
|
||||
124
account_financial_report/tests/test_aged_partner_balance.py
Normal file
124
account_financial_report/tests/test_aged_partner_balance.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# Copyright 2021 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests import TransactionCase, tagged
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, test_reports
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestAgedPartnerBalance(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
cls.wizard_model = cls.env["aged.partner.balance.report.wizard"]
|
||||
# Check that report is produced correctly
|
||||
cls.wizard_with_line_details = cls.wizard_model.create(
|
||||
{
|
||||
"show_move_line_details": True,
|
||||
"receivable_accounts_only": True,
|
||||
}
|
||||
)
|
||||
cls.wizard_without_line_details = cls.wizard_model.create(
|
||||
{
|
||||
"show_move_line_details": False,
|
||||
"receivable_accounts_only": True,
|
||||
}
|
||||
)
|
||||
cls.account_age_report_config = cls.env[
|
||||
"account.age.report.configuration"
|
||||
].create(
|
||||
{
|
||||
"name": "Intervals configuration",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "1-30",
|
||||
"inferior_limit": 30,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
def test_report_without_aged_report_configuration(self):
|
||||
"""Check that report is produced correctly."""
|
||||
wizard = self.wizard_with_line_details
|
||||
wizard.onchange_type_accounts_only()
|
||||
data = wizard._prepare_report_aged_partner_balance()
|
||||
|
||||
# Simulate web client behavior:
|
||||
# default value is a datetime.date but web client sends back strings
|
||||
data.update({"date_at": data["date_at"].strftime(DEFAULT_SERVER_DATE_FORMAT)})
|
||||
result = test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
"account_financial_report.aged_partner_balance",
|
||||
wizard.ids,
|
||||
data=data,
|
||||
)
|
||||
self.assertTrue(result)
|
||||
second_wizard = self.wizard_without_line_details
|
||||
second_wizard.onchange_type_accounts_only()
|
||||
data = second_wizard._prepare_report_aged_partner_balance()
|
||||
|
||||
# Simulate web client behavior:
|
||||
# default value is a datetime.date but web client sends back strings
|
||||
data.update({"date_at": data["date_at"].strftime(DEFAULT_SERVER_DATE_FORMAT)})
|
||||
result = test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
"account_financial_report.aged_partner_balance",
|
||||
second_wizard.ids,
|
||||
data=data,
|
||||
)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_report_with_aged_report_configuration(self):
|
||||
"""Check that report is produced correctly."""
|
||||
wizard = self.wizard_with_line_details
|
||||
wizard.age_partner_config_id = self.account_age_report_config.id
|
||||
|
||||
wizard.onchange_type_accounts_only()
|
||||
data = wizard._prepare_report_aged_partner_balance()
|
||||
|
||||
# Simulate web client behavior:
|
||||
# default value is a datetime.date but web client sends back strings
|
||||
data.update({"date_at": data["date_at"].strftime(DEFAULT_SERVER_DATE_FORMAT)})
|
||||
result = test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
"account_financial_report.aged_partner_balance",
|
||||
wizard.ids,
|
||||
data=data,
|
||||
)
|
||||
self.assertTrue(result)
|
||||
|
||||
second_wizard = self.wizard_without_line_details
|
||||
second_wizard.age_partner_config_id = self.account_age_report_config.id
|
||||
|
||||
second_wizard.onchange_type_accounts_only()
|
||||
data = second_wizard._prepare_report_aged_partner_balance()
|
||||
|
||||
# Simulate web client behavior:
|
||||
# default value is a datetime.date but web client sends back strings
|
||||
data.update({"date_at": data["date_at"].strftime(DEFAULT_SERVER_DATE_FORMAT)})
|
||||
result = test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
"account_financial_report.aged_partner_balance",
|
||||
second_wizard.ids,
|
||||
data=data,
|
||||
)
|
||||
self.assertTrue(result)
|
||||
733
account_financial_report/tests/test_general_ledger.py
Normal file
733
account_financial_report/tests/test_general_ledger.py
Normal file
@@ -0,0 +1,733 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
from odoo import api, fields
|
||||
from odoo.tests import tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestGeneralLedgerReport(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
cls.before_previous_fy_year = fields.Date.from_string("2014-05-05")
|
||||
cls.previous_fy_date_start = fields.Date.from_string("2015-01-01")
|
||||
cls.previous_fy_date_end = fields.Date.from_string("2015-12-31")
|
||||
cls.fy_date_start = fields.Date.from_string("2016-01-01")
|
||||
cls.fy_date_end = fields.Date.from_string("2016-12-31")
|
||||
# Get accounts
|
||||
cls.receivable_account = cls.company_data["default_account_receivable"]
|
||||
cls.income_account = cls.company_data["default_account_revenue"]
|
||||
cls.unaffected_account = cls.env["account.account"].search(
|
||||
[
|
||||
(
|
||||
"account_type",
|
||||
"=",
|
||||
"equity_unaffected",
|
||||
),
|
||||
("company_ids", "in", [cls.env.user.company_id.id]),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
cls.partner = cls.env.ref("base.res_partner_12")
|
||||
|
||||
def _add_move(
|
||||
self,
|
||||
date,
|
||||
receivable_debit,
|
||||
receivable_credit,
|
||||
income_debit,
|
||||
income_credit,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=0,
|
||||
):
|
||||
journal = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.env.user.company_id.id)], limit=1
|
||||
)
|
||||
partner = self.env.ref("base.res_partner_12")
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": date,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": receivable_debit,
|
||||
"credit": receivable_credit,
|
||||
"account_id": self.receivable_account.id,
|
||||
"partner_id": partner.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": income_debit,
|
||||
"credit": income_credit,
|
||||
"account_id": self.income_account.id,
|
||||
"partner_id": partner.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": unaffected_debit,
|
||||
"credit": unaffected_credit,
|
||||
"account_id": self.unaffected_account.id,
|
||||
"partner_id": partner.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
move = self.env["account.move"].create(move_vals)
|
||||
move.action_post()
|
||||
|
||||
def _get_report_lines(self, with_partners=False, account_ids=False):
|
||||
centralize = True
|
||||
if with_partners:
|
||||
centralize = False
|
||||
company = self.env.user.company_id
|
||||
general_ledger = self.env["general.ledger.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.fy_date_start,
|
||||
"date_to": self.fy_date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": False,
|
||||
"company_id": company.id,
|
||||
"account_ids": account_ids,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
"centralize": centralize,
|
||||
}
|
||||
)
|
||||
data = general_ledger._prepare_report_general_ledger()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.general_ledger"
|
||||
]._get_report_values(general_ledger, data)
|
||||
return res_data
|
||||
|
||||
@api.model
|
||||
def check_account_in_report(self, account_id, general_ledger):
|
||||
account_in_report = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id:
|
||||
account_in_report = True
|
||||
break
|
||||
return account_in_report
|
||||
|
||||
@api.model
|
||||
def check_partner_in_report(self, account_id, partner_id, general_ledger):
|
||||
partner_in_report = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id and account["partners"]:
|
||||
for partner in account["list_grouped"]:
|
||||
if partner["id"] == partner_id:
|
||||
partner_in_report = True
|
||||
return partner_in_report
|
||||
|
||||
@api.model
|
||||
def _get_initial_balance(self, account_id, general_ledger):
|
||||
initial_balance = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id:
|
||||
initial_balance = account["init_bal"]
|
||||
return initial_balance
|
||||
|
||||
@api.model
|
||||
def _get_partner_initial_balance(self, account_id, partner_id, general_ledger):
|
||||
initial_balance = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id and account["partners"]:
|
||||
for partner in account["list_grouped"]:
|
||||
if partner["id"] == partner_id:
|
||||
initial_balance = partner["init_bal"]
|
||||
return initial_balance
|
||||
|
||||
@api.model
|
||||
def _get_final_balance(self, account_id, general_ledger):
|
||||
final_balance = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id:
|
||||
final_balance = account["fin_bal"]
|
||||
return final_balance
|
||||
|
||||
@api.model
|
||||
def _get_partner_final_balance(self, account_id, partner_id, general_ledger):
|
||||
final_balance = False
|
||||
for account in general_ledger:
|
||||
if account["id"] == account_id and account["partners"]:
|
||||
for partner in account["list_grouped"]:
|
||||
if partner["id"] == partner_id:
|
||||
final_balance = partner["fin_bal"]
|
||||
return final_balance
|
||||
|
||||
def test_01_account_balance(self):
|
||||
# Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
self.assertFalse(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
self.assertFalse(check_income_account)
|
||||
self.assertTrue(
|
||||
self.check_account_in_report(self.unaffected_account.id, general_ledger)
|
||||
)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
self.assertFalse(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
receivable_init_balance = self._get_initial_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
receivable_fin_balance = self._get_final_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(receivable_init_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_init_balance["credit"], 0)
|
||||
self.assertEqual(receivable_init_balance["balance"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["credit"], 0)
|
||||
self.assertEqual(receivable_fin_balance["balance"], 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
receivable_init_balance = self._get_initial_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
receivable_fin_balance = self._get_final_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
income_init_balance = self._get_initial_balance(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
income_fin_balance = self._get_final_balance(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(receivable_init_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_init_balance["credit"], 0)
|
||||
self.assertEqual(receivable_init_balance["balance"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["credit"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["balance"], 0)
|
||||
|
||||
self.assertEqual(income_init_balance["debit"], 0)
|
||||
self.assertEqual(income_init_balance["credit"], 0)
|
||||
self.assertEqual(income_init_balance["balance"], 0)
|
||||
self.assertEqual(income_fin_balance["debit"], 1000)
|
||||
self.assertEqual(income_fin_balance["credit"], 0)
|
||||
self.assertEqual(income_fin_balance["balance"], 1000)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines(
|
||||
account_ids=(self.receivable_account + self.income_account).ids
|
||||
)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
self.assertTrue(
|
||||
self.check_account_in_report(self.receivable_account.id, general_ledger)
|
||||
)
|
||||
self.assertTrue(
|
||||
self.check_account_in_report(self.income_account.id, general_ledger)
|
||||
)
|
||||
self.assertFalse(
|
||||
self.check_account_in_report(self.unaffected_account.id, general_ledger)
|
||||
)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
receivable_init_balance = self._get_initial_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
receivable_fin_balance = self._get_final_balance(
|
||||
self.receivable_account.id, general_ledger
|
||||
)
|
||||
income_init_balance = self._get_initial_balance(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
income_fin_balance = self._get_final_balance(
|
||||
self.income_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(receivable_init_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_init_balance["credit"], 0)
|
||||
self.assertEqual(receivable_init_balance["balance"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["debit"], 1000)
|
||||
self.assertEqual(receivable_fin_balance["credit"], 2000)
|
||||
self.assertEqual(receivable_fin_balance["balance"], -1000)
|
||||
|
||||
self.assertEqual(income_init_balance["debit"], 0)
|
||||
self.assertEqual(income_init_balance["credit"], 0)
|
||||
self.assertEqual(income_init_balance["balance"], 0)
|
||||
self.assertEqual(income_fin_balance["debit"], 2000)
|
||||
self.assertEqual(income_fin_balance["credit"], 0)
|
||||
self.assertEqual(income_fin_balance["balance"], 2000)
|
||||
|
||||
def test_02_partner_balance(self):
|
||||
# Generate the general ledger line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_partner = self.check_partner_in_report(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
self.assertFalse(check_partner)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_partner = self.check_partner_in_report(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_partner)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_initial_balance = self._get_partner_initial_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
partner_final_balance = self._get_partner_final_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(partner_initial_balance["debit"], 1000)
|
||||
self.assertEqual(partner_initial_balance["credit"], 0)
|
||||
self.assertEqual(partner_initial_balance["balance"], 1000)
|
||||
self.assertEqual(partner_final_balance["debit"], 1000)
|
||||
self.assertEqual(partner_final_balance["credit"], 0)
|
||||
self.assertEqual(partner_final_balance["balance"], 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_partner = self.check_partner_in_report(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_partner)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_initial_balance = self._get_partner_initial_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
partner_final_balance = self._get_partner_final_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(partner_initial_balance["debit"], 1000)
|
||||
self.assertEqual(partner_initial_balance["credit"], 0)
|
||||
self.assertEqual(partner_initial_balance["balance"], 1000)
|
||||
self.assertEqual(partner_final_balance["debit"], 1000)
|
||||
self.assertEqual(partner_final_balance["credit"], 1000)
|
||||
self.assertEqual(partner_final_balance["balance"], 0)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_partner = self.check_partner_in_report(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_partner)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_initial_balance = self._get_partner_initial_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
partner_final_balance = self._get_partner_final_balance(
|
||||
self.receivable_account.id, self.partner.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(partner_initial_balance["debit"], 1000)
|
||||
self.assertEqual(partner_initial_balance["credit"], 0)
|
||||
self.assertEqual(partner_initial_balance["balance"], 1000)
|
||||
self.assertEqual(partner_final_balance["debit"], 1000)
|
||||
self.assertEqual(partner_final_balance["credit"], 2000)
|
||||
self.assertEqual(partner_final_balance["balance"], -1000)
|
||||
|
||||
def test_03_unaffected_account_balance(self):
|
||||
# Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["balance"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], 0)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_init_balance["balance"], -1000)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], -1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
unaffected_debit=1000,
|
||||
unaffected_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_init_balance["balance"], -1000)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], 0)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=3000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=3000,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_init_balance["balance"], -1000)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 4000)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], -3000)
|
||||
|
||||
def test_04_unaffected_account_balance_2_years(self):
|
||||
# Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["balance"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], 0)
|
||||
|
||||
# Add a move at any date 2 years before the balance
|
||||
# (to create an historic)
|
||||
self._add_move(
|
||||
date=self.before_previous_fy_year,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 1000)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_init_balance["balance"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 0)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], 1000)
|
||||
|
||||
# Affect the company's result last year
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_start,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=1000,
|
||||
)
|
||||
|
||||
# Add another move last year to test the initial balance this year
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=500,
|
||||
income_debit=500,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
res_data = self._get_report_lines()
|
||||
general_ledger = res_data["general_ledger"]
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
unaffected_init_balance = self._get_initial_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
unaffected_fin_balance = self._get_final_balance(
|
||||
self.unaffected_account.id, general_ledger
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_init_balance["debit"], 1500)
|
||||
self.assertEqual(unaffected_init_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_init_balance["balance"], 500)
|
||||
self.assertEqual(unaffected_fin_balance["debit"], 1500)
|
||||
self.assertEqual(unaffected_fin_balance["credit"], 1000)
|
||||
self.assertEqual(unaffected_fin_balance["balance"], 500)
|
||||
|
||||
def test_partner_filter(self):
|
||||
partner_1 = self.env.ref("base.res_partner_1")
|
||||
partner_2 = self.env.ref("base.res_partner_2")
|
||||
partner_3 = self.env.ref("base.res_partner_3")
|
||||
partner_4 = self.env.ref("base.res_partner_4")
|
||||
partner_1.write({"is_company": False, "parent_id": partner_2.id})
|
||||
partner_3.write({"is_company": False})
|
||||
|
||||
expected_list = [partner_2.id, partner_3.id, partner_4.id]
|
||||
context = {
|
||||
"active_ids": [partner_1.id, partner_2.id, partner_3.id, partner_4.id],
|
||||
"active_model": "res.partner",
|
||||
}
|
||||
|
||||
wizard = self.env["general.ledger.report.wizard"].with_context(**context)
|
||||
self.assertEqual(wizard._default_partners(), expected_list)
|
||||
|
||||
def test_validate_date(self):
|
||||
company_id = self.env.user.company_id
|
||||
company_id.write({"fiscalyear_last_day": 31, "fiscalyear_last_month": "12"})
|
||||
user = self.env.ref("base.user_root").with_context(company_id=company_id.id)
|
||||
wizard = self.env["general.ledger.report.wizard"].with_context(user=user.id)
|
||||
self.assertEqual(wizard._init_date_from(), time.strftime("%Y") + "-01-01")
|
||||
|
||||
def test_validate_date_range(self):
|
||||
data_type = self.env["date.range.type"].create(
|
||||
{"name": "Fiscal year", "company_id": False, "allow_overlap": False}
|
||||
)
|
||||
|
||||
dr = self.env["date.range"].create(
|
||||
{
|
||||
"name": "FS2015",
|
||||
"date_start": "2018-01-01",
|
||||
"date_end": "2018-12-31",
|
||||
"type_id": data_type.id,
|
||||
}
|
||||
)
|
||||
|
||||
wizard = self.env["general.ledger.report.wizard"].create(
|
||||
{"date_range_id": dr.id}
|
||||
)
|
||||
wizard.onchange_date_range_id()
|
||||
self.assertEqual(wizard.date_from, date(2018, 1, 1))
|
||||
self.assertEqual(wizard.date_to, date(2018, 12, 31))
|
||||
282
account_financial_report/tests/test_journal_ledger.py
Normal file
282
account_financial_report/tests/test_journal_ledger.py
Normal file
@@ -0,0 +1,282 @@
|
||||
# Copyright 2017 ACSONE SA/NV
|
||||
# Copyright 2019-20 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.fields import Date
|
||||
from odoo.tests import Form, tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestJournalReport(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
cls.AccountObj = cls.env["account.account"]
|
||||
cls.InvoiceObj = cls.env["account.move"]
|
||||
cls.JournalObj = cls.env["account.journal"]
|
||||
cls.MoveObj = cls.env["account.move"]
|
||||
cls.TaxObj = cls.env["account.tax"]
|
||||
cls.JournalLedgerReportWizard = cls.env["journal.ledger.report.wizard"]
|
||||
cls.JournalLedgerReport = cls.env[
|
||||
"report.account_financial_report.journal_ledger"
|
||||
]
|
||||
cls.company = cls.company_data["company"]
|
||||
cls.company.account_sale_tax_id = False
|
||||
cls.company.account_purchase_tax_id = False
|
||||
today = datetime.today()
|
||||
last_year = today - relativedelta(years=1)
|
||||
cls.previous_fy_date_start = Date.to_string(last_year.replace(month=1, day=1))
|
||||
cls.previous_fy_date_end = Date.to_string(last_year.replace(month=12, day=31))
|
||||
cls.fy_date_start = Date.to_string(today.replace(month=1, day=1))
|
||||
cls.fy_date_end = Date.to_string(today.replace(month=12, day=31))
|
||||
cls.receivable_account = cls.company_data["default_account_receivable"]
|
||||
cls.income_account = cls.company_data["default_account_revenue"]
|
||||
cls.expense_account = cls.company_data["default_account_expense"]
|
||||
cls.payable_account = cls.company_data["default_account_payable"]
|
||||
cls.journal_sale = cls.company_data["default_journal_sale"]
|
||||
cls.journal_purchase = cls.company_data["default_journal_purchase"]
|
||||
cls.tax_15_s = cls.company_data["default_tax_sale"]
|
||||
cls.tax_15_s.sequence = 30
|
||||
cls.tax_15_s.amount = 15.0
|
||||
cls.tax_15_s.amount_type = "percent"
|
||||
cls.tax_15_s.include_base_amount = False
|
||||
cls.tax_15_s.type_tax_use = "sale"
|
||||
cls.tax_20_s = cls.tax_15_s.copy(
|
||||
{
|
||||
"sequence": 30,
|
||||
"name": "Tax 20.0% (Percentage of Price)",
|
||||
"amount": 20.0,
|
||||
"amount_type": "percent",
|
||||
"include_base_amount": False,
|
||||
"type_tax_use": "sale",
|
||||
}
|
||||
)
|
||||
cls.tax_15_p = cls.company_data["default_tax_purchase"]
|
||||
cls.tax_15_p.sequence = 30
|
||||
cls.tax_15_p.amount = 15.0
|
||||
cls.tax_15_p.amount_type = "percent"
|
||||
cls.tax_15_p.include_base_amount = False
|
||||
cls.tax_15_p.type_tax_use = "purchase"
|
||||
cls.tax_20_p = cls.tax_15_p.copy(
|
||||
{
|
||||
"sequence": 30,
|
||||
"name": "Tax 20.0% (Percentage of Price)",
|
||||
"amount": 20.0,
|
||||
"amount_type": "percent",
|
||||
"include_base_amount": False,
|
||||
"type_tax_use": "purchase",
|
||||
}
|
||||
)
|
||||
cls.partner_2 = cls.env.ref("base.res_partner_2")
|
||||
|
||||
def _add_move(
|
||||
self,
|
||||
date,
|
||||
journal,
|
||||
receivable_debit,
|
||||
receivable_credit,
|
||||
income_debit,
|
||||
income_credit,
|
||||
):
|
||||
move_name = "move name"
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": date,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": move_name,
|
||||
"debit": receivable_debit,
|
||||
"credit": receivable_credit,
|
||||
"account_id": self.receivable_account.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": move_name,
|
||||
"debit": income_debit,
|
||||
"credit": income_credit,
|
||||
"account_id": self.income_account.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
return self.MoveObj.create(move_vals)
|
||||
|
||||
def check_report_journal_debit_credit(
|
||||
self, res_data, expected_debit, expected_credit
|
||||
):
|
||||
self.assertEqual(
|
||||
expected_debit, sum(rec["debit"] for rec in res_data["Journal_Ledgers"])
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
expected_credit, sum(rec["credit"] for rec in res_data["Journal_Ledgers"])
|
||||
)
|
||||
|
||||
def check_report_journal_debit_credit_taxes(
|
||||
self,
|
||||
res_data,
|
||||
expected_base_debit,
|
||||
expected_base_credit,
|
||||
expected_tax_debit,
|
||||
expected_tax_credit,
|
||||
):
|
||||
for rec in res_data["Journal_Ledgers"]:
|
||||
self.assertEqual(
|
||||
expected_base_debit,
|
||||
sum(tax_line["base_debit"] for tax_line in rec["tax_lines"]),
|
||||
)
|
||||
self.assertEqual(
|
||||
expected_base_credit,
|
||||
sum(tax_line["base_credit"] for tax_line in rec["tax_lines"]),
|
||||
)
|
||||
self.assertEqual(
|
||||
expected_tax_debit,
|
||||
sum(tax_line["tax_debit"] for tax_line in rec["tax_lines"]),
|
||||
)
|
||||
self.assertEqual(
|
||||
expected_tax_credit,
|
||||
sum(tax_line["tax_credit"] for tax_line in rec["tax_lines"]),
|
||||
)
|
||||
|
||||
def test_01_test_total(self):
|
||||
today_date = Date.today()
|
||||
last_year_date = Date.to_string(datetime.today() - relativedelta(years=1))
|
||||
|
||||
move1 = self._add_move(today_date, self.journal_sale, 0, 100, 100, 0)
|
||||
move2 = self._add_move(last_year_date, self.journal_sale, 0, 100, 100, 0)
|
||||
|
||||
wiz = self.JournalLedgerReportWizard.create(
|
||||
{
|
||||
"date_from": self.fy_date_start,
|
||||
"date_to": self.fy_date_end,
|
||||
"company_id": self.company.id,
|
||||
"journal_ids": [(6, 0, self.journal_sale.ids)],
|
||||
"move_target": "all",
|
||||
}
|
||||
)
|
||||
data = wiz._prepare_report_journal_ledger()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 100, 100)
|
||||
|
||||
move3 = self._add_move(today_date, self.journal_sale, 0, 100, 100, 0)
|
||||
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 200, 200)
|
||||
wiz.move_target = "posted"
|
||||
data = wiz._prepare_report_journal_ledger()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 0, 0)
|
||||
|
||||
move1.action_post()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 100, 100)
|
||||
|
||||
move2.action_post()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 100, 100)
|
||||
|
||||
move3.action_post()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 200, 200)
|
||||
|
||||
wiz.date_from = self.previous_fy_date_start
|
||||
data = wiz._prepare_report_journal_ledger()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 300, 300)
|
||||
|
||||
def test_02_test_taxes_out_invoice(self):
|
||||
move_form = Form(
|
||||
self.env["account.move"].with_context(default_move_type="out_invoice")
|
||||
)
|
||||
move_form.partner_id = self.partner_2
|
||||
move_form.journal_id = self.journal_sale
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.name = "test"
|
||||
line_form.quantity = 1.0
|
||||
line_form.price_unit = 100
|
||||
line_form.account_id = self.income_account
|
||||
line_form.tax_ids.add(self.tax_15_s)
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.name = "test"
|
||||
line_form.quantity = 1.0
|
||||
line_form.price_unit = 100
|
||||
line_form.account_id = self.income_account
|
||||
line_form.tax_ids.add(self.tax_15_s)
|
||||
line_form.tax_ids.add(self.tax_20_s)
|
||||
invoice = move_form.save()
|
||||
invoice.action_post()
|
||||
|
||||
wiz = self.JournalLedgerReportWizard.create(
|
||||
{
|
||||
"date_from": self.fy_date_start,
|
||||
"date_to": self.fy_date_end,
|
||||
"company_id": self.company.id,
|
||||
"journal_ids": [(6, 0, self.journal_sale.ids)],
|
||||
"move_target": "all",
|
||||
}
|
||||
)
|
||||
data = wiz._prepare_report_journal_ledger()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
self.check_report_journal_debit_credit(res_data, 250, 250)
|
||||
self.check_report_journal_debit_credit_taxes(res_data, 0, 300, 0, 50)
|
||||
|
||||
def test_03_test_taxes_in_invoice(self):
|
||||
move_form = Form(
|
||||
self.env["account.move"].with_context(default_move_type="in_invoice")
|
||||
)
|
||||
move_form.partner_id = self.partner_2
|
||||
move_form.journal_id = self.journal_purchase
|
||||
move_form.invoice_date = Date.today()
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.name = "test"
|
||||
line_form.quantity = 1.0
|
||||
line_form.price_unit = 100
|
||||
line_form.account_id = self.expense_account
|
||||
line_form.tax_ids.add(self.tax_15_p)
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.name = "test"
|
||||
line_form.quantity = 1.0
|
||||
line_form.price_unit = 100
|
||||
line_form.account_id = self.expense_account
|
||||
line_form.tax_ids.add(self.tax_15_p)
|
||||
line_form.tax_ids.add(self.tax_20_p)
|
||||
move_form.invoice_date = move_form.date
|
||||
invoice = move_form.save()
|
||||
invoice.action_post()
|
||||
|
||||
wiz = self.JournalLedgerReportWizard.create(
|
||||
{
|
||||
"date_from": self.fy_date_start,
|
||||
"date_to": self.fy_date_end,
|
||||
"company_id": self.company.id,
|
||||
"journal_ids": [(6, 0, self.journal_purchase.ids)],
|
||||
"move_target": "all",
|
||||
}
|
||||
)
|
||||
data = wiz._prepare_report_journal_ledger()
|
||||
res_data = self.JournalLedgerReport._get_report_values(wiz, data)
|
||||
|
||||
self.check_report_journal_debit_credit(res_data, 250, 250)
|
||||
self.check_report_journal_debit_credit_taxes(res_data, 300, 0, 50, 0)
|
||||
41
account_financial_report/tests/test_open_items.py
Normal file
41
account_financial_report/tests/test_open_items.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests import tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestOpenItems(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
|
||||
def test_partner_filter(self):
|
||||
partner_1 = self.env.ref("base.res_partner_1")
|
||||
partner_2 = self.env.ref("base.res_partner_2")
|
||||
partner_3 = self.env.ref("base.res_partner_3")
|
||||
partner_4 = self.env.ref("base.res_partner_4")
|
||||
partner_1.write({"is_company": False, "parent_id": partner_2.id})
|
||||
partner_3.write({"is_company": False})
|
||||
|
||||
expected_list = [partner_2.id, partner_3.id, partner_4.id]
|
||||
context = {
|
||||
"active_ids": [partner_1.id, partner_2.id, partner_3.id, partner_4.id],
|
||||
"active_model": "res.partner",
|
||||
}
|
||||
|
||||
wizard = self.env["open.items.report.wizard"].with_context(**context)
|
||||
self.assertEqual(wizard._default_partners(), expected_list)
|
||||
723
account_financial_report/tests/test_trial_balance.py
Normal file
723
account_financial_report/tests/test_trial_balance.py
Normal file
@@ -0,0 +1,723 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import re
|
||||
|
||||
from odoo.tests import tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestTrialBalanceReport(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
# Remove previous account groups and related invoices to avoid conflicts
|
||||
group_obj = cls.env["account.group"]
|
||||
cls.group1 = group_obj.create({"code_prefix_start": "1", "name": "Group 1"})
|
||||
cls.group11 = group_obj.create(
|
||||
{"code_prefix_start": "11", "name": "Group 11", "parent_id": cls.group1.id}
|
||||
)
|
||||
cls.group2 = group_obj.create({"code_prefix_start": "2", "name": "Group 2"})
|
||||
# Set accounts
|
||||
cls.account001 = cls._create_account_account(
|
||||
cls,
|
||||
{
|
||||
"code": "001",
|
||||
"name": "Account 001",
|
||||
"group_id": cls.group2.id,
|
||||
"account_type": "income_other",
|
||||
},
|
||||
)
|
||||
cls.account100 = cls.company_data["default_account_receivable"]
|
||||
cls.account100.group_id = cls.group1.id
|
||||
cls.account110 = cls.env["account.account"].search(
|
||||
[
|
||||
(
|
||||
"account_type",
|
||||
"=",
|
||||
"equity_unaffected",
|
||||
),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
cls.account200 = cls._create_account_account(
|
||||
cls,
|
||||
{
|
||||
"code": "200",
|
||||
"name": "Account 200",
|
||||
"group_id": cls.group2.id,
|
||||
"account_type": "income_other",
|
||||
},
|
||||
)
|
||||
cls.account300 = cls._create_account_account(
|
||||
cls,
|
||||
{
|
||||
"code": "300",
|
||||
"name": "Account 300",
|
||||
"account_type": "income_other",
|
||||
},
|
||||
)
|
||||
cls.account201 = cls._create_account_account(
|
||||
cls,
|
||||
{
|
||||
"code": "201",
|
||||
"name": "Account 201",
|
||||
"group_id": cls.group2.id,
|
||||
"account_type": "income_other",
|
||||
},
|
||||
)
|
||||
cls.previous_fy_date_start = "2015-01-01"
|
||||
cls.previous_fy_date_end = "2015-12-31"
|
||||
cls.fy_date_start = "2016-01-01"
|
||||
cls.fy_date_end = "2016-12-31"
|
||||
cls.date_start = "2016-01-01"
|
||||
cls.date_end = "2016-12-31"
|
||||
cls.partner = cls.env.ref("base.res_partner_12")
|
||||
cls.unaffected_account = cls.env["account.account"].search(
|
||||
[
|
||||
(
|
||||
"account_type",
|
||||
"=",
|
||||
"equity_unaffected",
|
||||
),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
|
||||
def _create_account_account(self, vals):
|
||||
item = self.env["account.account"].create(vals)
|
||||
if "group_id" in vals:
|
||||
item.group_id = vals["group_id"]
|
||||
return item
|
||||
|
||||
def _add_move(
|
||||
self,
|
||||
date,
|
||||
receivable_debit,
|
||||
receivable_credit,
|
||||
income_debit,
|
||||
income_credit,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=0,
|
||||
):
|
||||
journal = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.env.user.company_id.id)], limit=1
|
||||
)
|
||||
partner = self.env.ref("base.res_partner_12")
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": date,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": receivable_debit,
|
||||
"credit": receivable_credit,
|
||||
"partner_id": partner.id,
|
||||
"account_id": self.account100.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": income_debit,
|
||||
"credit": income_credit,
|
||||
"partner_id": partner.id,
|
||||
"account_id": self.account200.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": unaffected_debit,
|
||||
"credit": unaffected_credit,
|
||||
"partner_id": partner.id,
|
||||
"account_id": self.account110.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": receivable_debit,
|
||||
"credit": receivable_credit,
|
||||
"partner_id": partner.id,
|
||||
"account_id": self.account300.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"debit": receivable_credit,
|
||||
"credit": receivable_debit,
|
||||
"partner_id": partner.id,
|
||||
"account_id": self.account201.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
move = self.env["account.move"].create(move_vals)
|
||||
move.action_post()
|
||||
|
||||
def _get_report_lines(
|
||||
self, with_partners=False, account_ids=False, show_hierarchy=False
|
||||
):
|
||||
company = self.env.user.company_id
|
||||
trial_balance = self.env["trial.balance.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_start,
|
||||
"date_to": self.date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": True,
|
||||
"show_hierarchy": show_hierarchy,
|
||||
"company_id": company.id,
|
||||
"account_ids": account_ids,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
"show_partner_details": with_partners,
|
||||
}
|
||||
)
|
||||
data = trial_balance._prepare_report_trial_balance()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.trial_balance"
|
||||
]._get_report_values(trial_balance, data)
|
||||
return res_data
|
||||
|
||||
def check_account_in_report(self, account_id, trial_balance):
|
||||
account_in_report = False
|
||||
for account in trial_balance:
|
||||
if account["id"] == account_id and account["type"] == "account_type":
|
||||
account_in_report = True
|
||||
break
|
||||
return account_in_report
|
||||
|
||||
def _get_account_lines(self, account_id, trial_balance):
|
||||
lines = False
|
||||
for account in trial_balance:
|
||||
if account["id"] == account_id and account["type"] == "account_type":
|
||||
lines = {
|
||||
"initial_balance": account["initial_balance"],
|
||||
"debit": account["debit"],
|
||||
"credit": account["credit"],
|
||||
"final_balance": account["ending_balance"],
|
||||
}
|
||||
return lines
|
||||
|
||||
def _get_group_lines(self, group_id, trial_balance):
|
||||
lines = False
|
||||
for group in trial_balance:
|
||||
if group["id"] == group_id and group["type"] == "group_type":
|
||||
lines = {
|
||||
"initial_balance": group["initial_balance"],
|
||||
"debit": group["debit"],
|
||||
"credit": group["credit"],
|
||||
"final_balance": group["ending_balance"],
|
||||
}
|
||||
return lines
|
||||
|
||||
def check_partner_in_report(self, account_id, partner_id, total_amount):
|
||||
partner_in_report = False
|
||||
if account_id in total_amount.keys():
|
||||
if partner_id in total_amount[account_id]:
|
||||
partner_in_report = True
|
||||
return partner_in_report
|
||||
|
||||
def _get_partner_lines(self, account_id, partner_id, total_amount):
|
||||
acc_id = account_id
|
||||
prt_id = partner_id
|
||||
lines = {
|
||||
"initial_balance": total_amount[acc_id][prt_id]["initial_balance"],
|
||||
"debit": total_amount[acc_id][prt_id]["debit"],
|
||||
"credit": total_amount[acc_id][prt_id]["credit"],
|
||||
"final_balance": total_amount[acc_id][prt_id]["ending_balance"],
|
||||
}
|
||||
return lines
|
||||
|
||||
def _sum_all_accounts(self, trial_balance, feature):
|
||||
total = 0.0
|
||||
for account in trial_balance:
|
||||
if account["type"] == "account_type":
|
||||
for key in account.keys():
|
||||
if key == feature:
|
||||
total += account[key]
|
||||
return total
|
||||
|
||||
def test_00_account_group(self):
|
||||
self.assertTrue(self.account100 in self.group1.compute_account_ids)
|
||||
self.assertTrue(self.account200 in self.group2.compute_account_ids)
|
||||
|
||||
def test_02_account_balance_hierarchy(self):
|
||||
# Generate the general ledger line
|
||||
res_data = self._get_report_lines(show_hierarchy=True)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
self.assertFalse(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
self.assertFalse(check_income_account)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(show_hierarchy=True)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
self.assertFalse(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
account_receivable_lines = self._get_account_lines(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
group1_lines = self._get_group_lines(self.group1.id, trial_balance)
|
||||
|
||||
self.assertEqual(account_receivable_lines["initial_balance"], 1000)
|
||||
self.assertEqual(account_receivable_lines["debit"], 0)
|
||||
self.assertEqual(account_receivable_lines["credit"], 0)
|
||||
self.assertEqual(account_receivable_lines["final_balance"], 1000)
|
||||
|
||||
self.assertEqual(group1_lines["initial_balance"], 1000)
|
||||
self.assertEqual(group1_lines["debit"], 0)
|
||||
self.assertEqual(group1_lines["credit"], 0)
|
||||
self.assertEqual(group1_lines["final_balance"], 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(show_hierarchy=True)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
account_receivable_lines = self._get_account_lines(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
account_income_lines = self._get_account_lines(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
group1_lines = self._get_group_lines(self.group1.id, trial_balance)
|
||||
group2_lines = self._get_group_lines(self.group2.id, trial_balance)
|
||||
|
||||
self.assertEqual(account_receivable_lines["initial_balance"], 1000)
|
||||
self.assertEqual(account_receivable_lines["debit"], 0)
|
||||
self.assertEqual(account_receivable_lines["credit"], 1000)
|
||||
self.assertEqual(account_receivable_lines["final_balance"], 0)
|
||||
|
||||
self.assertEqual(account_income_lines["initial_balance"], 0)
|
||||
self.assertEqual(account_income_lines["debit"], 1000)
|
||||
self.assertEqual(account_income_lines["credit"], 0)
|
||||
self.assertEqual(account_income_lines["final_balance"], 1000)
|
||||
|
||||
self.assertEqual(group1_lines["initial_balance"], 1000)
|
||||
self.assertEqual(group1_lines["debit"], 0)
|
||||
self.assertEqual(group1_lines["credit"], 1000)
|
||||
self.assertEqual(group1_lines["final_balance"], 0)
|
||||
|
||||
self.assertEqual(group2_lines["initial_balance"], 0)
|
||||
self.assertEqual(group2_lines["debit"], 2000)
|
||||
self.assertEqual(group2_lines["credit"], 0)
|
||||
self.assertEqual(group2_lines["final_balance"], 2000)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(show_hierarchy=True)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
check_receivable_account = self.check_account_in_report(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_receivable_account)
|
||||
check_income_account = self.check_account_in_report(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_income_account)
|
||||
|
||||
# Check the initial and final balance
|
||||
account_receivable_lines = self._get_account_lines(
|
||||
self.account100.id, trial_balance
|
||||
)
|
||||
account_income_lines = self._get_account_lines(
|
||||
self.account200.id, trial_balance
|
||||
)
|
||||
group1_lines = self._get_group_lines(self.group1.id, trial_balance)
|
||||
group2_lines = self._get_group_lines(self.group2.id, trial_balance)
|
||||
|
||||
self.assertEqual(account_receivable_lines["initial_balance"], 1000)
|
||||
self.assertEqual(account_receivable_lines["debit"], 0)
|
||||
self.assertEqual(account_receivable_lines["credit"], 2000)
|
||||
self.assertEqual(account_receivable_lines["final_balance"], -1000)
|
||||
|
||||
self.assertEqual(account_income_lines["initial_balance"], 0)
|
||||
self.assertEqual(account_income_lines["debit"], 2000)
|
||||
self.assertEqual(account_income_lines["credit"], 0)
|
||||
self.assertEqual(account_income_lines["final_balance"], 2000)
|
||||
|
||||
self.assertEqual(group1_lines["initial_balance"], 1000)
|
||||
self.assertEqual(group1_lines["debit"], 0)
|
||||
self.assertEqual(group1_lines["credit"], 2000)
|
||||
self.assertEqual(group1_lines["final_balance"], -1000)
|
||||
|
||||
self.assertEqual(group2_lines["initial_balance"], 0)
|
||||
self.assertEqual(group2_lines["debit"], 4000)
|
||||
self.assertEqual(group2_lines["credit"], 0)
|
||||
self.assertEqual(group2_lines["final_balance"], 4000)
|
||||
|
||||
def test_03_partner_balance(self):
|
||||
# Generate the trial balance line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
total_amount = res_data["total_amount"]
|
||||
check_partner_receivable = self.check_partner_in_report(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
self.assertFalse(check_partner_receivable)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
total_amount = res_data["total_amount"]
|
||||
check_partner_receivable = self.check_partner_in_report(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
self.assertTrue(check_partner_receivable)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_lines = self._get_partner_lines(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
|
||||
self.assertEqual(partner_lines["initial_balance"], 1000)
|
||||
self.assertEqual(partner_lines["debit"], 0)
|
||||
self.assertEqual(partner_lines["credit"], 0)
|
||||
self.assertEqual(partner_lines["final_balance"], 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
total_amount = res_data["total_amount"]
|
||||
check_partner_receivable = self.check_partner_in_report(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
self.assertTrue(check_partner_receivable)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_lines = self._get_partner_lines(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
|
||||
self.assertEqual(partner_lines["initial_balance"], 1000)
|
||||
self.assertEqual(partner_lines["debit"], 0)
|
||||
self.assertEqual(partner_lines["credit"], 1000)
|
||||
self.assertEqual(partner_lines["final_balance"], 0)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0,
|
||||
)
|
||||
|
||||
# Re Generate the trial balance line
|
||||
res_data = self._get_report_lines(with_partners=True)
|
||||
total_amount = res_data["total_amount"]
|
||||
check_partner_receivable = self.check_partner_in_report(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
self.assertTrue(check_partner_receivable)
|
||||
|
||||
# Check the initial and final balance
|
||||
partner_lines = self._get_partner_lines(
|
||||
self.account100.id, self.partner.id, total_amount
|
||||
)
|
||||
|
||||
self.assertEqual(partner_lines["initial_balance"], 1000)
|
||||
self.assertEqual(partner_lines["debit"], 0)
|
||||
self.assertEqual(partner_lines["credit"], 2000)
|
||||
self.assertEqual(partner_lines["final_balance"], -1000)
|
||||
|
||||
def test_04_undistributed_pl(self):
|
||||
# Add a P&L Move in the previous FY
|
||||
journal = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.env.user.company_id.id)], limit=1
|
||||
)
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": self.previous_fy_date_end,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 0.0, "credit": 1000.0, "account_id": self.account300.id},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 1000.0, "credit": 0.0, "account_id": self.account100.id},
|
||||
),
|
||||
],
|
||||
}
|
||||
move = self.env["account.move"].create(move_vals)
|
||||
move.action_post()
|
||||
# Generate the trial balance line
|
||||
company = self.env.user.company_id
|
||||
trial_balance = self.env["trial.balance.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_start,
|
||||
"date_to": self.date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": False,
|
||||
"show_hierarchy": False,
|
||||
"company_id": company.id,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
}
|
||||
)
|
||||
data = trial_balance._prepare_report_trial_balance()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.trial_balance"
|
||||
]._get_report_values(trial_balance, data)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
unaffected_lines = self._get_account_lines(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_lines["initial_balance"], -1000)
|
||||
self.assertEqual(unaffected_lines["debit"], 0)
|
||||
self.assertEqual(unaffected_lines["credit"], 0)
|
||||
self.assertEqual(unaffected_lines["final_balance"], -1000)
|
||||
# Add a P&L Move to the current FY
|
||||
journal = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.env.user.company_id.id)], limit=1
|
||||
)
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": self.date_start,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 0.0, "credit": 1000.0, "account_id": self.account300.id},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 1000.0, "credit": 0.0, "account_id": self.account100.id},
|
||||
),
|
||||
],
|
||||
}
|
||||
move = self.env["account.move"].create(move_vals)
|
||||
move.action_post()
|
||||
# Re Generate the trial balance line
|
||||
trial_balance = self.env["trial.balance.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_start,
|
||||
"date_to": self.date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": False,
|
||||
"show_hierarchy": False,
|
||||
"company_id": company.id,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
}
|
||||
)
|
||||
data = trial_balance._prepare_report_trial_balance()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.trial_balance"
|
||||
]._get_report_values(trial_balance, data)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
# The unaffected earnings account is not affected by a journal entry
|
||||
# made to the P&L in the current fiscal year.
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
unaffected_lines = self._get_account_lines(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_lines["initial_balance"], -1000)
|
||||
self.assertEqual(unaffected_lines["debit"], 0)
|
||||
self.assertEqual(unaffected_lines["credit"], 0)
|
||||
self.assertEqual(unaffected_lines["final_balance"], -1000)
|
||||
# Add a Move including Unaffected Earnings to the current FY
|
||||
journal = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.env.user.company_id.id)], limit=1
|
||||
)
|
||||
move_vals = {
|
||||
"journal_id": journal.id,
|
||||
"date": self.date_start,
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 0.0, "credit": 1000.0, "account_id": self.account110.id},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{"debit": 1000.0, "credit": 0.0, "account_id": self.account100.id},
|
||||
),
|
||||
],
|
||||
}
|
||||
move = self.env["account.move"].create(move_vals)
|
||||
move.action_post()
|
||||
# Re Generate the trial balance line
|
||||
trial_balance = self.env["trial.balance.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_start,
|
||||
"date_to": self.date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": False,
|
||||
"show_hierarchy": False,
|
||||
"company_id": company.id,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
}
|
||||
)
|
||||
data = trial_balance._prepare_report_trial_balance()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.trial_balance"
|
||||
]._get_report_values(trial_balance, data)
|
||||
trial_balance = res_data["trial_balance"]
|
||||
# The unaffected earnings account affected by a journal entry
|
||||
# made to the unaffected earnings in the current fiscal year.
|
||||
check_unaffected_account = self.check_account_in_report(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
self.assertTrue(check_unaffected_account)
|
||||
|
||||
unaffected_lines = self._get_account_lines(
|
||||
self.unaffected_account.id, trial_balance
|
||||
)
|
||||
|
||||
self.assertEqual(unaffected_lines["initial_balance"], -1000)
|
||||
self.assertEqual(unaffected_lines["debit"], 0)
|
||||
self.assertEqual(unaffected_lines["credit"], 1000)
|
||||
self.assertEqual(unaffected_lines["final_balance"], -2000)
|
||||
|
||||
# The totals for the Trial Balance are zero
|
||||
total_initial_balance = self._sum_all_accounts(trial_balance, "initial_balance")
|
||||
total_final_balance = self._sum_all_accounts(trial_balance, "ending_balance")
|
||||
total_debit = self._sum_all_accounts(trial_balance, "debit")
|
||||
total_credit = self._sum_all_accounts(trial_balance, "credit")
|
||||
|
||||
self.assertEqual(total_initial_balance, 0)
|
||||
self.assertEqual(total_final_balance, 0)
|
||||
self.assertEqual(total_debit, total_credit)
|
||||
|
||||
def test_05_all_accounts_loaded(self):
|
||||
# Tests if all accounts which code is number are loaded
|
||||
# when the account_code_ fields changed
|
||||
all_accounts = (
|
||||
self.env["account.account"]
|
||||
.search([], order="code")
|
||||
.filtered(lambda acc: re.fullmatch(r"[0-9]+(\.[0-9]+)?", acc.code))
|
||||
)
|
||||
company = self.env.user.company_id
|
||||
trial_balance = self.env["trial.balance.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_start,
|
||||
"date_to": self.date_end,
|
||||
"target_move": "posted",
|
||||
"hide_account_at_0": False,
|
||||
"show_hierarchy": False,
|
||||
"company_id": company.id,
|
||||
"fy_start_date": self.fy_date_start,
|
||||
"account_code_from": self.account001.id,
|
||||
"account_code_to": all_accounts[-1].id,
|
||||
}
|
||||
)
|
||||
trial_balance.on_change_account_range()
|
||||
# sets are needed because some codes are duplicated and
|
||||
# thus the length of all_accounts would be higher
|
||||
all_accounts_code_set = set()
|
||||
trial_balance_code_set = set()
|
||||
[all_accounts_code_set.add(account.code) for account in all_accounts]
|
||||
[
|
||||
trial_balance_code_set.add(account.code)
|
||||
for account in trial_balance.account_ids
|
||||
]
|
||||
self.assertEqual(len(trial_balance_code_set), len(all_accounts_code_set))
|
||||
self.assertTrue(trial_balance_code_set == all_accounts_code_set)
|
||||
396
account_financial_report/tests/test_vat_report.py
Normal file
396
account_financial_report/tests/test_vat_report.py
Normal file
@@ -0,0 +1,396 @@
|
||||
# Copyright 2018 Forest and Biomass Romania
|
||||
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests import Form, tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestVATReport(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def init_invoice(
|
||||
cls,
|
||||
move_type,
|
||||
name=None,
|
||||
partner=None,
|
||||
invoice_date=None,
|
||||
post=False,
|
||||
lines=None,
|
||||
taxes=None,
|
||||
):
|
||||
move_form = Form(
|
||||
cls.env["account.move"].with_context(default_move_type=move_type)
|
||||
)
|
||||
move_form.invoice_date = invoice_date or fields.Date.from_string("2019-01-01")
|
||||
move_form.partner_id = partner or cls.partner_a
|
||||
lines = lines or []
|
||||
for line in lines:
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.product_id = line[0]
|
||||
line_form.name = "Test"
|
||||
line_form.account_id = line[1]
|
||||
line_form.quantity = line[2]
|
||||
line_form.price_unit = line[3]
|
||||
if taxes:
|
||||
line_form.tax_ids.clear()
|
||||
line_form.tax_ids.add(taxes)
|
||||
rslt = move_form.save()
|
||||
if post:
|
||||
rslt.action_post()
|
||||
return rslt
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
cls.date_from = time.strftime("%Y-%m-01")
|
||||
cls.date_to = time.strftime("%Y-%m-28")
|
||||
cls.company = cls.env.user.company_id
|
||||
cls.company.country_id = cls.env.ref("base.us").id
|
||||
cls.receivable_account = cls.company_data["default_account_receivable"]
|
||||
cls.income_account = cls.company_data["default_account_revenue"]
|
||||
cls.expense_account = cls.company_data["default_account_expense"]
|
||||
cls.tax_account = cls.env["account.account"].search(
|
||||
[
|
||||
("company_ids", "in", [cls.company.id]),
|
||||
(
|
||||
"account_type",
|
||||
"=",
|
||||
"liability_non_current",
|
||||
),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
cls.bank_journal = cls.company_data["default_journal_bank"]
|
||||
cls.tax_tag_01 = cls.env["account.account.tag"].create(
|
||||
{
|
||||
"name": "Tag 01",
|
||||
"applicability": "taxes",
|
||||
"country_id": cls.company.country_id.id,
|
||||
}
|
||||
)
|
||||
cls.tax_tag_02 = cls.env["account.account.tag"].create(
|
||||
{
|
||||
"name": "Tag 02",
|
||||
"applicability": "taxes",
|
||||
"country_id": cls.company.country_id.id,
|
||||
}
|
||||
)
|
||||
cls.tax_tag_03 = cls.env["account.account.tag"].create(
|
||||
{
|
||||
"name": "Tag 03",
|
||||
"applicability": "taxes",
|
||||
"country_id": cls.company.country_id.id,
|
||||
}
|
||||
)
|
||||
cls.tax_group_10 = cls.env["account.tax.group"].create(
|
||||
{"name": "Tax 10%", "sequence": 1}
|
||||
)
|
||||
cls.tax_group_20 = cls.env["account.tax.group"].create(
|
||||
{"name": "Tax 20%", "sequence": 2}
|
||||
)
|
||||
cls.tax_10 = cls.env["account.tax"].create(
|
||||
{
|
||||
"name": "Tax 10.0%",
|
||||
"amount": 10.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"company_id": cls.company.id,
|
||||
"tax_group_id": cls.tax_group_10.id,
|
||||
"invoice_repartition_line_ids": [
|
||||
(0, 0, {"factor_percent": 100, "repartition_type": "base"}),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"factor_percent": 100,
|
||||
"repartition_type": "tax",
|
||||
"account_id": cls.tax_account.id,
|
||||
"tag_ids": [(6, 0, [cls.tax_tag_01.id, cls.tax_tag_02.id])],
|
||||
},
|
||||
),
|
||||
],
|
||||
"refund_repartition_line_ids": [
|
||||
(0, 0, {"factor_percent": 100, "repartition_type": "base"}),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"factor_percent": 100,
|
||||
"repartition_type": "tax",
|
||||
"account_id": cls.tax_account.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.tax_20 = cls.env["account.tax"].create(
|
||||
{
|
||||
"sequence": 30,
|
||||
"name": "Tax 20.0%",
|
||||
"amount": 20.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"company_id": cls.company.id,
|
||||
"cash_basis_transition_account_id": cls.tax_account.id,
|
||||
"tax_group_id": cls.tax_group_20.id,
|
||||
"invoice_repartition_line_ids": [
|
||||
(0, 0, {"factor_percent": 100, "repartition_type": "base"}),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"factor_percent": 100,
|
||||
"repartition_type": "tax",
|
||||
"account_id": cls.tax_account.id,
|
||||
"tag_ids": [(6, 0, [cls.tax_tag_02.id, cls.tax_tag_03.id])],
|
||||
},
|
||||
),
|
||||
],
|
||||
"refund_repartition_line_ids": [
|
||||
(0, 0, {"factor_percent": 100, "repartition_type": "base"}),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"factor_percent": 100,
|
||||
"repartition_type": "tax",
|
||||
"account_id": cls.tax_account.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.init_invoice(
|
||||
"out_invoice",
|
||||
name="Test invoice 1",
|
||||
partner=cls.env.ref("base.res_partner_2"),
|
||||
invoice_date=time.strftime("%Y-%m-03"),
|
||||
post=True,
|
||||
lines=[
|
||||
(cls.env.ref("product.product_product_4"), cls.income_account, 1, 100.0)
|
||||
],
|
||||
taxes=cls.tax_10,
|
||||
)
|
||||
cls.init_invoice(
|
||||
"out_invoice",
|
||||
name="Test invoice 2",
|
||||
partner=cls.env.ref("base.res_partner_2"),
|
||||
invoice_date=time.strftime("%Y-%m-04"),
|
||||
post=True,
|
||||
lines=[
|
||||
(
|
||||
cls.env.ref("product.product_product_4"),
|
||||
cls.income_account,
|
||||
1,
|
||||
250.0,
|
||||
),
|
||||
],
|
||||
taxes=cls.tax_20,
|
||||
)
|
||||
|
||||
def _get_report_lines(self, taxgroups=False):
|
||||
based_on = "taxtags"
|
||||
if taxgroups:
|
||||
based_on = "taxgroups"
|
||||
vat_report = self.env["vat.report.wizard"].create(
|
||||
{
|
||||
"date_from": self.date_from,
|
||||
"date_to": self.date_to,
|
||||
"company_id": self.company.id,
|
||||
"based_on": based_on,
|
||||
"tax_detail": True,
|
||||
}
|
||||
)
|
||||
data = vat_report._prepare_vat_report()
|
||||
res_data = self.env[
|
||||
"report.account_financial_report.vat_report"
|
||||
]._get_report_values(vat_report, data)
|
||||
return res_data
|
||||
|
||||
def check_tag_or_group_in_report(self, tag_or_group_name, vat_report):
|
||||
tag_or_group_in_report = False
|
||||
for tag_or_group in vat_report:
|
||||
if tag_or_group["name"] == tag_or_group_name:
|
||||
tag_or_group_in_report = True
|
||||
break
|
||||
return tag_or_group_in_report
|
||||
|
||||
def check_tax_in_report(self, tax_name, vat_report):
|
||||
tax_in_report = False
|
||||
for tag_or_group in vat_report:
|
||||
if tag_or_group["taxes"]:
|
||||
for tax in tag_or_group["taxes"]:
|
||||
if tax["name"] == tax_name:
|
||||
tax_in_report = True
|
||||
return tax_in_report
|
||||
|
||||
def _get_tag_or_group_line(self, tag_or_group_name, vat_report):
|
||||
tag_or_group_net = False
|
||||
tag_or_group_tax = False
|
||||
for tag_or_group in vat_report:
|
||||
if tag_or_group["name"] == tag_or_group_name:
|
||||
tag_or_group_net = tag_or_group["net"]
|
||||
tag_or_group_tax = tag_or_group["tax"]
|
||||
return tag_or_group_net, tag_or_group_tax
|
||||
|
||||
def _get_tax_line(self, tax_name, vat_report):
|
||||
tax_net = False
|
||||
tax_tax = False
|
||||
for tag_or_group in vat_report:
|
||||
if tag_or_group["taxes"]:
|
||||
for tax in tag_or_group["taxes"]:
|
||||
if tax["name"] == tax_name:
|
||||
tax_net = tax["net"]
|
||||
tax_tax = tax["tax"]
|
||||
return tax_net, tax_tax
|
||||
|
||||
def test_01_compute(self):
|
||||
# Generate the vat lines
|
||||
res_data = self._get_report_lines()
|
||||
vat_report = res_data["vat_report"]
|
||||
|
||||
# Check report based on taxtags
|
||||
check_tax_tag_01 = self.check_tag_or_group_in_report(
|
||||
self.tax_tag_01.name, vat_report
|
||||
)
|
||||
self.assertTrue(check_tax_tag_01)
|
||||
check_tax_tag_02 = self.check_tag_or_group_in_report(
|
||||
self.tax_tag_02.name, vat_report
|
||||
)
|
||||
self.assertTrue(check_tax_tag_02)
|
||||
check_tax_tag_03 = self.check_tag_or_group_in_report(
|
||||
self.tax_tag_03.name, vat_report
|
||||
)
|
||||
self.assertTrue(check_tax_tag_03)
|
||||
check_tax_10 = self.check_tax_in_report(self.tax_10.name, vat_report)
|
||||
self.assertTrue(check_tax_10)
|
||||
check_tax_20 = self.check_tax_in_report(self.tax_20.name, vat_report)
|
||||
self.assertTrue(check_tax_20)
|
||||
|
||||
tag_01_net, tag_01_tax = self._get_tag_or_group_line(
|
||||
self.tax_tag_01.name, vat_report
|
||||
)
|
||||
tag_02_net, tag_02_tax = self._get_tag_or_group_line(
|
||||
self.tax_tag_02.name, vat_report
|
||||
)
|
||||
tag_03_net, tag_03_tax = self._get_tag_or_group_line(
|
||||
self.tax_tag_03.name, vat_report
|
||||
)
|
||||
tax_10_net, tax_10_tax = self._get_tax_line(self.tax_10.name, vat_report)
|
||||
tax_20_net, tax_20_tax = self._get_tax_line(self.tax_20.name, vat_report)
|
||||
|
||||
self.assertEqual(tag_01_net, -100)
|
||||
self.assertEqual(tag_01_tax, -10)
|
||||
self.assertEqual(tag_02_net, -350)
|
||||
self.assertEqual(tag_02_tax, -60)
|
||||
self.assertEqual(tag_03_net, -250)
|
||||
self.assertEqual(tag_03_tax, -50)
|
||||
self.assertEqual(tax_10_net, -100)
|
||||
self.assertEqual(tax_10_tax, -10)
|
||||
self.assertEqual(tax_20_net, -250)
|
||||
self.assertEqual(tax_20_tax, -50)
|
||||
|
||||
# Check report based on taxgroups
|
||||
res_data = self._get_report_lines(taxgroups=True)
|
||||
vat_report = res_data["vat_report"]
|
||||
|
||||
check_group_10 = self.check_tag_or_group_in_report(
|
||||
self.tax_group_10.name, vat_report
|
||||
)
|
||||
self.assertTrue(check_group_10)
|
||||
check_group_20 = self.check_tag_or_group_in_report(
|
||||
self.tax_group_20.name, vat_report
|
||||
)
|
||||
self.assertTrue(check_group_20)
|
||||
check_tax_10 = self.check_tax_in_report(self.tax_10.name, vat_report)
|
||||
self.assertTrue(check_tax_10)
|
||||
check_tax_20 = self.check_tax_in_report(self.tax_20.name, vat_report)
|
||||
self.assertTrue(check_tax_20)
|
||||
|
||||
group_10_net, group_10_tax = self._get_tag_or_group_line(
|
||||
self.tax_group_10.name, vat_report
|
||||
)
|
||||
group_20_net, group_20_tax = self._get_tag_or_group_line(
|
||||
self.tax_group_20.name, vat_report
|
||||
)
|
||||
tax_10_net, tax_10_tax = self._get_tax_line(self.tax_10.name, vat_report)
|
||||
tax_20_net, tax_20_tax = self._get_tax_line(self.tax_20.name, vat_report)
|
||||
|
||||
self.assertEqual(group_10_net, -100)
|
||||
self.assertEqual(group_10_tax, -10)
|
||||
self.assertEqual(group_20_net, -250)
|
||||
self.assertEqual(group_20_tax, -50)
|
||||
self.assertEqual(tax_10_net, -100)
|
||||
self.assertEqual(tax_10_tax, -10)
|
||||
self.assertEqual(tax_20_net, -250)
|
||||
self.assertEqual(tax_20_tax, -50)
|
||||
|
||||
def test_wizard_date_range(self):
|
||||
vat_wizard = self.env["vat.report.wizard"]
|
||||
date_range = self.env["date.range"]
|
||||
self.type = self.env["date.range.type"].create(
|
||||
{"name": "Month", "company_id": False, "allow_overlap": False}
|
||||
)
|
||||
dt = date_range.create(
|
||||
{
|
||||
"name": "FS2016",
|
||||
"date_start": time.strftime("%Y-%m-01"),
|
||||
"date_end": time.strftime("%Y-%m-28"),
|
||||
"type_id": self.type.id,
|
||||
}
|
||||
)
|
||||
wizard = vat_wizard.create(
|
||||
{
|
||||
"date_range_id": dt.id,
|
||||
"date_from": time.strftime("%Y-%m-28"),
|
||||
"date_to": time.strftime("%Y-%m-01"),
|
||||
"tax_detail": True,
|
||||
}
|
||||
)
|
||||
wizard.onchange_date_range_id()
|
||||
self.assertEqual(
|
||||
wizard.date_from, date(date.today().year, date.today().month, 1)
|
||||
)
|
||||
self.assertEqual(
|
||||
wizard.date_to, date(date.today().year, date.today().month, 28)
|
||||
)
|
||||
wizard._export("qweb-pdf")
|
||||
wizard.button_export_html()
|
||||
wizard.button_export_pdf()
|
||||
wizard.button_export_xlsx()
|
||||
wizard = vat_wizard.create(
|
||||
{
|
||||
"date_range_id": dt.id,
|
||||
"date_from": time.strftime("%Y-%m-28"),
|
||||
"date_to": time.strftime("%Y-%m-01"),
|
||||
"based_on": "taxgroups",
|
||||
"tax_detail": True,
|
||||
}
|
||||
)
|
||||
wizard.onchange_date_range_id()
|
||||
self.assertEqual(
|
||||
wizard.date_from, date(date.today().year, date.today().month, 1)
|
||||
)
|
||||
self.assertEqual(
|
||||
wizard.date_to, date(date.today().year, date.today().month, 28)
|
||||
)
|
||||
wizard._export("qweb-pdf")
|
||||
wizard.button_export_html()
|
||||
wizard.button_export_pdf()
|
||||
wizard.button_export_xlsx()
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2023 Ernesto Garcia <ernesto.garcia@tecnativa.com>
|
||||
Copyright 2023 Carolina Fernandez <carolina.fernandez@tecnativa.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="aged_partner_report_configuration_form" model="ir.ui.view">
|
||||
<field name="name">Age partner report configuration form</field>
|
||||
<field name="model">account.age.report.configuration</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="company_id" />
|
||||
</group>
|
||||
<field name="line_ids">
|
||||
<list editable="bottom">
|
||||
<field name="name" />
|
||||
<field name="inferior_limit" />
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="aged_partner_report_configuration_tree" model="ir.ui.view">
|
||||
<field name="name">Age partner report configuration list</field>
|
||||
<field name="model">account.age.report.configuration</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name" />
|
||||
<field name="company_id" />
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_aged_partner_report_configuration" model="ir.actions.act_window">
|
||||
<field name="name">Age Partner Report Configuration</field>
|
||||
<field name="res_model">account.age.report.configuration</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
14
account_financial_report/view/account_view.xml
Normal file
14
account_financial_report/view/account_view.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_account_specific_form">
|
||||
<field name="name">account.account.form.inherit</field>
|
||||
<field name="inherit_id" ref="account.view_account_form" />
|
||||
<field name="model">account.account</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="deprecated" position="after">
|
||||
<field name="centralized" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_aged_partner_balance">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
9
account_financial_report/view/report_general_ledger.xml
Normal file
9
account_financial_report/view/report_general_ledger.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_general_ledger">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_general_ledger_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
9
account_financial_report/view/report_journal_ledger.xml
Normal file
9
account_financial_report/view/report_journal_ledger.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_journal_ledger">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_journal_ledger_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
9
account_financial_report/view/report_open_items.xml
Normal file
9
account_financial_report/view/report_open_items.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_open_items">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_open_items_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
9
account_financial_report/view/report_trial_balance.xml
Normal file
9
account_financial_report/view/report_trial_balance.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_trial_balance">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_trial_balance_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
9
account_financial_report/view/report_vat_report.xml
Normal file
9
account_financial_report/view/report_vat_report.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<template id="report_vat_report">
|
||||
<div class="o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons" />
|
||||
<t t-call="account_financial_report.report_vat_report_base" />
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
51
account_financial_report/view/res_config_settings_views.xml
Normal file
51
account_financial_report/view/res_config_settings_views.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!-- Copyright 2023 Tecnativa - Carolina Fernandez
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="account.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//block[@id='analytic']" position="after">
|
||||
<block
|
||||
title="OCA Aged Report Configuration"
|
||||
id="oca_aged_report_config"
|
||||
>
|
||||
<div
|
||||
id="main_oca_aged_report_config"
|
||||
class="col-12 col-lg-12 o_setting_box"
|
||||
>
|
||||
<div class="o_setting_left_pane" />
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Intervals configuration</span>
|
||||
<div class="text-muted">
|
||||
Here you can set the intervals that will appear on the Aged Partner Balance.
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div class="row mt16">
|
||||
<label
|
||||
for="default_age_partner_config_id"
|
||||
class="col-lg-3 o_light_label"
|
||||
/>
|
||||
<field
|
||||
name="default_age_partner_config_id"
|
||||
options="{'no_create_edit': True, 'no_open': True}"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt8">
|
||||
<button
|
||||
type="action"
|
||||
name="%(account_financial_report.action_aged_partner_report_configuration)d"
|
||||
string="Configurations"
|
||||
class="btn-link"
|
||||
icon="fa-arrow-right"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</block>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
7
account_financial_report/wizard/__init__.py
Normal file
7
account_financial_report/wizard/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from . import abstract_wizard
|
||||
from . import aged_partner_balance_wizard
|
||||
from . import general_ledger_wizard
|
||||
from . import journal_ledger_wizard
|
||||
from . import open_items_wizard
|
||||
from . import trial_balance_wizard
|
||||
from . import vat_report_wizard
|
||||
51
account_financial_report/wizard/abstract_wizard.py
Normal file
51
account_financial_report/wizard/abstract_wizard.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Copyright 2019 Lorenzo Battistini @ TAKOBI
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AbstractWizard(models.AbstractModel):
|
||||
_name = "account_financial_report_abstract_wizard"
|
||||
_description = "Abstract Wizard"
|
||||
|
||||
def _get_partner_ids_domain(self):
|
||||
return [
|
||||
"&",
|
||||
"|",
|
||||
("company_id", "=", self.company_id.id),
|
||||
("company_id", "=", False),
|
||||
"|",
|
||||
("parent_id", "=", False),
|
||||
("is_company", "=", True),
|
||||
]
|
||||
|
||||
def _default_partners(self):
|
||||
context = self.env.context
|
||||
if context.get("active_ids") and context.get("active_model") == "res.partner":
|
||||
partners = self.env["res.partner"].browse(context["active_ids"])
|
||||
corp_partners = partners.filtered("parent_id")
|
||||
partners -= corp_partners
|
||||
partners |= corp_partners.mapped("commercial_partner_id")
|
||||
return partners.ids
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
default=lambda self: self.env.company.id,
|
||||
required=False,
|
||||
string="Company",
|
||||
)
|
||||
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
report_type = "qweb-html"
|
||||
return self._export(report_type)
|
||||
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = "qweb-pdf"
|
||||
return self._export(report_type)
|
||||
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = "xlsx"
|
||||
return self._export(report_type)
|
||||
153
account_financial_report/wizard/aged_partner_balance_wizard.py
Normal file
153
account_financial_report/wizard/aged_partner_balance_wizard.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# Author: Damien Crier, Andrea Stirpe, Kevin Graveman, Dennis Sluijk
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA, Onestein B.V.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgedPartnerBalanceWizard(models.TransientModel):
|
||||
"""Aged partner balance report wizard."""
|
||||
|
||||
_name = "aged.partner.balance.report.wizard"
|
||||
_description = "Aged Partner Balance Wizard"
|
||||
_inherit = "account_financial_report_abstract_wizard"
|
||||
|
||||
date_at = fields.Date(required=True, default=fields.Date.context_today)
|
||||
date_from = fields.Date()
|
||||
target_move = fields.Selection(
|
||||
[("posted", "All Posted Entries"), ("all", "All Entries")],
|
||||
string="Target Moves",
|
||||
required=True,
|
||||
default="posted",
|
||||
)
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name="account.account",
|
||||
string="Filter accounts",
|
||||
domain=[("reconcile", "=", True)],
|
||||
required=True,
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(comodel_name="res.partner", string="Filter partners")
|
||||
show_move_line_details = fields.Boolean()
|
||||
|
||||
account_code_from = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Starting account in a range",
|
||||
)
|
||||
account_code_to = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Ending account in a range",
|
||||
)
|
||||
age_partner_config_id = fields.Many2one(
|
||||
"account.age.report.configuration", string="Intervals configuration"
|
||||
)
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
if (
|
||||
self.account_code_from
|
||||
and self.account_code_from.code.isdigit()
|
||||
and self.account_code_to
|
||||
and self.account_code_to.code.isdigit()
|
||||
):
|
||||
start_range = int(self.account_code_from.code)
|
||||
end_range = int(self.account_code_to.code)
|
||||
self.account_ids = self.env["account.account"].search(
|
||||
[
|
||||
("code", ">=", start_range),
|
||||
("code", "<=", end_range),
|
||||
("reconcile", "=", True),
|
||||
]
|
||||
)
|
||||
if self.company_id:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: self.company_id in a.company_ids
|
||||
)
|
||||
return {
|
||||
"domain": {
|
||||
"account_code_from": [("reconcile", "=", True)],
|
||||
"account_code_to": [("reconcile", "=", True)],
|
||||
}
|
||||
}
|
||||
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
if self.company_id and self.partner_ids:
|
||||
self.partner_ids = self.partner_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
if self.company_id and self.account_ids:
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
self.onchange_type_accounts_only()
|
||||
else:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: self.company_id in a.company_ids
|
||||
)
|
||||
res = {"domain": {"account_ids": [], "partner_ids": []}}
|
||||
if not self.company_id:
|
||||
return res
|
||||
else:
|
||||
res["domain"]["account_ids"] += [
|
||||
("company_ids", "in", [self.company_id.id])
|
||||
]
|
||||
res["domain"]["partner_ids"] += self._get_partner_ids_domain()
|
||||
return res
|
||||
|
||||
@api.onchange("account_ids")
|
||||
def onchange_account_ids(self):
|
||||
return {"domain": {"account_ids": [("reconcile", "=", True)]}}
|
||||
|
||||
@api.onchange("receivable_accounts_only", "payable_accounts_only")
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
domain = [("company_ids", "in", [self.company_id.id])]
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [
|
||||
("account_type", "in", ("asset_receivable", "liability_payable"))
|
||||
]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [("account_type", "=", "asset_receivable")]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [("account_type", "=", "liability_payable")]
|
||||
self.account_ids = self.env["account.account"].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
def _print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
data = self._prepare_report_aged_partner_balance()
|
||||
if report_type == "xlsx":
|
||||
report_name = "a_f_r.report_aged_partner_balance_xlsx"
|
||||
else:
|
||||
report_name = "account_financial_report.aged_partner_balance"
|
||||
return (
|
||||
self.env["ir.actions.report"]
|
||||
.search(
|
||||
[("report_name", "=", report_name), ("report_type", "=", report_type)],
|
||||
limit=1,
|
||||
)
|
||||
.report_action(self, data=data)
|
||||
)
|
||||
|
||||
def _prepare_report_aged_partner_balance(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"wizard_id": self.id,
|
||||
"date_at": self.date_at,
|
||||
"date_from": self.date_from or False,
|
||||
"only_posted_moves": self.target_move == "posted",
|
||||
"company_id": self.company_id.id,
|
||||
"account_ids": self.account_ids.ids,
|
||||
"partner_ids": self.partner_ids.ids,
|
||||
"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,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
return self._print_report(report_type)
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<!-- AGED PARTNER BALANCE -->
|
||||
<record id="aged_partner_balance_wizard" model="ir.ui.view">
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="model">aged.partner.balance.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field
|
||||
name="company_id"
|
||||
options="{'no_create': True}"
|
||||
groups="base.group_multi_company"
|
||||
/>
|
||||
</group>
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_at" />
|
||||
<field name="date_from" />
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio" />
|
||||
<field name="show_move_line_details" />
|
||||
</group>
|
||||
</group>
|
||||
<group name="partner_filter" col="1">
|
||||
<label for="partner_ids" />
|
||||
<field
|
||||
name="partner_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<group name="account_filter" col="4">
|
||||
<label for="age_partner_config_id" />
|
||||
<field name="age_partner_config_id" nolabel="1" />
|
||||
<label for="account_ids" colspan="4" />
|
||||
<field name="receivable_accounts_only" />
|
||||
<field name="payable_accounts_only" />
|
||||
<label for="account_code_from" string="From Code" />
|
||||
<div>
|
||||
<div class="o_row">
|
||||
<field
|
||||
name="account_code_from"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<span class="oe_inline">To</span>
|
||||
<field
|
||||
name="account_code_to"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<field
|
||||
name="account_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="button_export_html"
|
||||
string="View"
|
||||
type="object"
|
||||
default_focus="1"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button
|
||||
name="button_export_pdf"
|
||||
string="Export PDF"
|
||||
type="object"
|
||||
/>
|
||||
<button
|
||||
name="button_export_xlsx"
|
||||
string="Export XLSX"
|
||||
type="object"
|
||||
/>
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_aged_partner_balance_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="res_model">aged.partner.balance.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="aged_partner_balance_wizard" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
323
account_financial_report/wizard/general_ledger_wizard.py
Normal file
323
account_financial_report/wizard/general_ledger_wizard.py
Normal file
@@ -0,0 +1,323 @@
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Author: Jordi Ballester
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2017 Akretion - Alexis de Lattre
|
||||
# Copyright 2017 ForgeFlow, S.L.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
import time
|
||||
from ast import literal_eval
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import date_utils
|
||||
|
||||
|
||||
class GeneralLedgerReportWizard(models.TransientModel):
|
||||
"""General ledger report wizard."""
|
||||
|
||||
_name = "general.ledger.report.wizard"
|
||||
_description = "General Ledger Report Wizard"
|
||||
_inherit = "account_financial_report_abstract_wizard"
|
||||
|
||||
date_range_id = fields.Many2one(comodel_name="date.range", string="Date range")
|
||||
date_from = fields.Date(required=True, default=lambda self: self._init_date_from())
|
||||
date_to = fields.Date(required=True, default=fields.Date.context_today)
|
||||
fy_start_date = fields.Date(compute="_compute_fy_start_date")
|
||||
target_move = fields.Selection(
|
||||
[("posted", "All Posted Entries"), ("all", "All Entries")],
|
||||
string="Target Moves",
|
||||
required=True,
|
||||
default="posted",
|
||||
)
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name="account.account", string="Filter accounts"
|
||||
)
|
||||
centralize = fields.Boolean(string="Activate centralization", default=True)
|
||||
hide_account_at_0 = fields.Boolean(
|
||||
string="Hide account ending balance at 0",
|
||||
help="Use this filter to hide an account or a partner "
|
||||
"with an ending balance at 0. "
|
||||
"If partners are filtered, "
|
||||
"debits and credits totals will not match the trial balance.",
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name="res.partner",
|
||||
string="Filter partners",
|
||||
default=lambda self: self._default_partners(),
|
||||
)
|
||||
account_journal_ids = fields.Many2many(
|
||||
comodel_name="account.journal", string="Filter journals"
|
||||
)
|
||||
cost_center_ids = fields.Many2many(
|
||||
comodel_name="account.analytic.account", string="Filter cost centers"
|
||||
)
|
||||
only_one_unaffected_earnings_account = fields.Boolean(
|
||||
readonly=True,
|
||||
default=lambda self: self._only_one_unaffected_earnings_account(),
|
||||
)
|
||||
foreign_currency = fields.Boolean(
|
||||
string="Show foreign currency",
|
||||
help="Display foreign currency for move lines, unless "
|
||||
"account currency is not setup through chart of accounts "
|
||||
"will display initial and final balance in that currency.",
|
||||
default=lambda self: self._default_foreign_currency(),
|
||||
)
|
||||
account_code_from = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Starting account in a range",
|
||||
)
|
||||
account_code_to = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Ending account in a range",
|
||||
)
|
||||
grouped_by = fields.Selection(
|
||||
selection=[("", "None"), ("partners", "Partners"), ("taxes", "Taxes")],
|
||||
default="partners",
|
||||
)
|
||||
show_cost_center = fields.Boolean(
|
||||
string="Show Analytic Account",
|
||||
default=True,
|
||||
)
|
||||
domain = fields.Char(
|
||||
string="Journal Items Domain",
|
||||
default=[],
|
||||
help="This domain will be used to select specific domain for Journal " "Items",
|
||||
)
|
||||
|
||||
def _get_account_move_lines_domain(self):
|
||||
domain = literal_eval(self.domain) if self.domain else []
|
||||
return domain
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
if (
|
||||
self.account_code_from
|
||||
and self.account_code_from.code.isdigit()
|
||||
and self.account_code_to
|
||||
and self.account_code_to.code.isdigit()
|
||||
):
|
||||
start_range = int(self.account_code_from.code)
|
||||
end_range = int(self.account_code_to.code)
|
||||
self.account_ids = self.env["account.account"].search(
|
||||
[("code", ">=", start_range), ("code", "<=", end_range)]
|
||||
)
|
||||
if self.company_id:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
|
||||
def _init_date_from(self):
|
||||
"""set start date to begin of current year if fiscal year running"""
|
||||
today = fields.Date.context_today(self)
|
||||
company = self.company_id or self.env.company
|
||||
last_fsc_month = company.fiscalyear_last_month
|
||||
last_fsc_day = company.fiscalyear_last_day
|
||||
|
||||
if (
|
||||
today.month < int(last_fsc_month)
|
||||
or today.month == int(last_fsc_month)
|
||||
and today.day <= last_fsc_day
|
||||
):
|
||||
return time.strftime("%Y-01-01")
|
||||
else:
|
||||
return False
|
||||
|
||||
def _default_foreign_currency(self):
|
||||
return self.env.user.has_group("base.group_multi_currency")
|
||||
|
||||
@api.depends("date_from")
|
||||
def _compute_fy_start_date(self):
|
||||
for wiz in self:
|
||||
if wiz.date_from:
|
||||
date_from, date_to = date_utils.get_fiscal_year(
|
||||
wiz.date_from,
|
||||
day=self.company_id.fiscalyear_last_day,
|
||||
month=int(self.company_id.fiscalyear_last_month),
|
||||
)
|
||||
wiz.fy_start_date = date_from
|
||||
else:
|
||||
wiz.fy_start_date = False
|
||||
|
||||
def _only_one_unaffected_earnings_account(self):
|
||||
count = self.env["account.account"].search_count(
|
||||
[
|
||||
("account_type", "=", "equity_unaffected"),
|
||||
("company_ids", "in", [self.company_id.id or self.env.company.id]),
|
||||
]
|
||||
)
|
||||
return count == 1
|
||||
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
self.only_one_unaffected_earnings_account = (
|
||||
self._only_one_unaffected_earnings_account()
|
||||
)
|
||||
if (
|
||||
self.company_id
|
||||
and self.date_range_id.company_id
|
||||
and self.date_range_id.company_id != self.company_id
|
||||
):
|
||||
self.date_range_id = False
|
||||
if self.company_id and self.account_journal_ids:
|
||||
self.account_journal_ids = self.account_journal_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
if self.company_id and self.partner_ids:
|
||||
self.partner_ids = self.partner_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
if self.company_id and self.account_ids:
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
self.onchange_type_accounts_only()
|
||||
else:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
if self.company_id and self.cost_center_ids:
|
||||
self.cost_center_ids = self.cost_center_ids.filtered(
|
||||
lambda c: c.company_id == self.company_id
|
||||
)
|
||||
res = {
|
||||
"domain": {
|
||||
"account_ids": [],
|
||||
"partner_ids": [],
|
||||
"account_journal_ids": [],
|
||||
"cost_center_ids": [],
|
||||
"date_range_id": [],
|
||||
}
|
||||
}
|
||||
if not self.company_id:
|
||||
return res
|
||||
else:
|
||||
res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)]
|
||||
res["domain"]["account_journal_ids"] += [
|
||||
("company_id", "=", self.company_id.id)
|
||||
]
|
||||
res["domain"]["partner_ids"] += self._get_partner_ids_domain()
|
||||
res["domain"]["cost_center_ids"] += [
|
||||
("company_id", "=", self.company_id.id)
|
||||
]
|
||||
res["domain"]["date_range_id"] += [
|
||||
"|",
|
||||
("company_id", "=", self.company_id.id),
|
||||
("company_id", "=", False),
|
||||
]
|
||||
return res
|
||||
|
||||
@api.onchange("date_range_id")
|
||||
def onchange_date_range_id(self):
|
||||
"""Handle date range change."""
|
||||
if self.date_range_id:
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
|
||||
@api.constrains("company_id", "date_range_id")
|
||||
def _check_company_id_date_range_id(self):
|
||||
for rec in self.sudo():
|
||||
if (
|
||||
rec.company_id
|
||||
and rec.date_range_id.company_id
|
||||
and rec.company_id != rec.date_range_id.company_id
|
||||
):
|
||||
raise ValidationError(
|
||||
self.env._(
|
||||
"The Company in the General Ledger Report Wizard and in "
|
||||
"Date Range must be the same."
|
||||
)
|
||||
)
|
||||
|
||||
@api.onchange("receivable_accounts_only", "payable_accounts_only")
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = [("company_ids", "in", [self.company_id.id])]
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [
|
||||
("account_type", "in", ("asset_receivable", "liability_payable"))
|
||||
]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [("account_type", "=", "asset_receivable")]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [("account_type", "=", "liability_payable")]
|
||||
self.account_ids = self.env["account.account"].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.onchange("partner_ids")
|
||||
def onchange_partner_ids(self):
|
||||
"""Handle partners change."""
|
||||
if self.partner_ids:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = True
|
||||
else:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = False
|
||||
|
||||
@api.depends("company_id")
|
||||
def _compute_unaffected_earnings_account(self):
|
||||
for record in self:
|
||||
record.unaffected_earnings_account = self.env["account.account"].search(
|
||||
[
|
||||
("account_type", "=", "equity_unaffected"),
|
||||
("company_ids", "in", [record.company_id.id]),
|
||||
]
|
||||
)
|
||||
|
||||
unaffected_earnings_account = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
compute="_compute_unaffected_earnings_account",
|
||||
store=True,
|
||||
)
|
||||
|
||||
def _print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
data = self._prepare_report_general_ledger()
|
||||
if report_type == "xlsx":
|
||||
report_name = "a_f_r.report_general_ledger_xlsx"
|
||||
else:
|
||||
report_name = "account_financial_report.general_ledger"
|
||||
return (
|
||||
self.env["ir.actions.report"]
|
||||
.search(
|
||||
[("report_name", "=", report_name), ("report_type", "=", report_type)],
|
||||
limit=1,
|
||||
)
|
||||
.report_action(self, data=data)
|
||||
)
|
||||
|
||||
def _prepare_report_general_ledger(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"wizard_id": self.id,
|
||||
"date_from": self.date_from,
|
||||
"date_to": self.date_to,
|
||||
"only_posted_moves": self.target_move == "posted",
|
||||
"hide_account_at_0": self.hide_account_at_0,
|
||||
"foreign_currency": self.foreign_currency,
|
||||
"company_id": self.company_id.id,
|
||||
"account_ids": self.account_ids.ids,
|
||||
"partner_ids": self.partner_ids.ids,
|
||||
"grouped_by": self.grouped_by,
|
||||
"cost_center_ids": self.cost_center_ids.ids,
|
||||
"show_cost_center": self.show_cost_center,
|
||||
"journal_ids": self.account_journal_ids.ids,
|
||||
"centralize": self.centralize,
|
||||
"fy_start_date": self.fy_start_date,
|
||||
"unaffected_earnings_account": self.unaffected_earnings_account.id,
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
"domain": self._get_account_move_lines_domain(),
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
return self._print_report(report_type)
|
||||
|
||||
def _get_atr_from_dict(self, obj_id, data, key):
|
||||
try:
|
||||
return data[obj_id][key]
|
||||
except KeyError:
|
||||
return data[str(obj_id)][key]
|
||||
163
account_financial_report/wizard/general_ledger_wizard_view.xml
Normal file
163
account_financial_report/wizard/general_ledger_wizard_view.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<!-- GENERAL LEDGER -->
|
||||
<record id="general_ledger_wizard" model="ir.ui.view">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="model">general.ledger.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field
|
||||
name="company_id"
|
||||
options="{'no_create': True}"
|
||||
groups="base.group_multi_company"
|
||||
/>
|
||||
</group>
|
||||
<div invisible="not only_one_unaffected_earnings_account">
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_range_id" />
|
||||
<field name="date_from" />
|
||||
<field name="date_to" />
|
||||
<field name="fy_start_date" invisible="1" />
|
||||
<field name="target_move" widget="radio" />
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="grouped_by" />
|
||||
<field name="centralize" />
|
||||
<field name="hide_account_at_0" />
|
||||
<field name="foreign_currency" />
|
||||
<field name="show_cost_center" />
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Filter accounts">
|
||||
<group name="account_filter" col="4">
|
||||
<label for="account_ids" colspan="4" />
|
||||
<field name="receivable_accounts_only" />
|
||||
<field name="payable_accounts_only" />
|
||||
<label for="account_code_from" string="From Code" />
|
||||
<div>
|
||||
<div class="o_row">
|
||||
<field
|
||||
name="account_code_from"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<span class="oe_inline">To</span>
|
||||
<field
|
||||
name="account_code_to"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<field
|
||||
name="account_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Filter partners">
|
||||
<field
|
||||
name="partner_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</page>
|
||||
<page
|
||||
string="Filter analytic accounts"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
>
|
||||
<field
|
||||
name="cost_center_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</page>
|
||||
<page string="Additional Filtering">
|
||||
<style>
|
||||
.o_domain_show_selection_button {display: none}
|
||||
</style>
|
||||
<field
|
||||
name="domain"
|
||||
widget="domain"
|
||||
options="{'model': 'account.move.line', 'in_dialog': True}"
|
||||
context="{'skip_search_count': 1}"
|
||||
/>
|
||||
</page>
|
||||
</notebook>
|
||||
</div>
|
||||
<div invisible="only_one_unaffected_earnings_account">
|
||||
<field name="only_one_unaffected_earnings_account" invisible="1" />
|
||||
<group />
|
||||
<h4>
|
||||
General Ledger can be computed only if selected company have
|
||||
only one unaffected earnings account.
|
||||
</h4>
|
||||
<group />
|
||||
</div>
|
||||
<footer>
|
||||
<div invisible="not only_one_unaffected_earnings_account">
|
||||
<button
|
||||
name="button_export_html"
|
||||
string="View"
|
||||
type="object"
|
||||
default_focus="1"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_pdf"
|
||||
string="Export PDF"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_xlsx"
|
||||
string="Export XLSX"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
<div invisible="only_one_unaffected_earnings_account">
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_general_ledger_wizard" model="ir.actions.act_window">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="res_model">general.ledger.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="general_ledger_wizard" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
<!--Add to res.partner action-->
|
||||
<record
|
||||
id="act_action_general_ledger_wizard_partner_relation"
|
||||
model="ir.actions.act_window"
|
||||
>
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="res_model">general.ledger.report.wizard</field>
|
||||
<field name="binding_model_id" ref="base.model_res_partner" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="general_ledger_wizard" />
|
||||
<field
|
||||
name="context"
|
||||
eval="{
|
||||
'default_receivable_accounts_only':1,
|
||||
'default_payable_accounts_only':1,
|
||||
}"
|
||||
/>
|
||||
<field name="groups_id" eval="[(4, ref('account.group_account_manager'))]" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
161
account_financial_report/wizard/journal_ledger_wizard.py
Normal file
161
account_financial_report/wizard/journal_ledger_wizard.py
Normal file
@@ -0,0 +1,161 @@
|
||||
# Copyright 2017 ACSONE SA/NV
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class JournalLedgerReportWizard(models.TransientModel):
|
||||
"""Journal Ledger report wizard."""
|
||||
|
||||
_name = "journal.ledger.report.wizard"
|
||||
_description = "Journal Ledger Report Wizard"
|
||||
_inherit = "account_financial_report_abstract_wizard"
|
||||
|
||||
date_range_id = fields.Many2one(comodel_name="date.range", string="Date range")
|
||||
date_from = fields.Date(string="Start date", required=True)
|
||||
date_to = fields.Date(string="End date", required=True)
|
||||
journal_ids = fields.Many2many(
|
||||
comodel_name="account.journal", string="Journals", required=False
|
||||
)
|
||||
move_target = fields.Selection(
|
||||
selection="_get_move_targets", default="posted", required=True
|
||||
)
|
||||
foreign_currency = fields.Boolean()
|
||||
sort_option = fields.Selection(
|
||||
selection="_get_sort_options",
|
||||
string="Sort entries by",
|
||||
default="move_name",
|
||||
required=True,
|
||||
)
|
||||
group_option = fields.Selection(
|
||||
selection="_get_group_options",
|
||||
string="Group entries by",
|
||||
default="journal",
|
||||
required=True,
|
||||
)
|
||||
with_account_name = fields.Boolean(default=False)
|
||||
with_auto_sequence = fields.Boolean(string="Show Auto Sequence", default=False)
|
||||
|
||||
@api.model
|
||||
def _get_move_targets(self):
|
||||
return [
|
||||
("all", self.env._("All")),
|
||||
("posted", self.env._("Posted")),
|
||||
("draft", self.env._("Not Posted")),
|
||||
]
|
||||
|
||||
@api.model
|
||||
def _get_sort_options(self):
|
||||
return [("move_name", self.env._("Entry number")), ("date", self.env._("Date"))]
|
||||
|
||||
@api.model
|
||||
def _get_group_options(self):
|
||||
return [("journal", self.env._("Journal")), ("none", self.env._("No group"))]
|
||||
|
||||
@api.onchange("date_range_id")
|
||||
def onchange_date_range_id(self):
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
if (
|
||||
self.company_id
|
||||
and self.date_range_id.company_id
|
||||
and self.date_range_id.company_id != self.company_id
|
||||
):
|
||||
self.date_range_id = False
|
||||
if self.company_id and self.journal_ids:
|
||||
self.journal_ids = self.journal_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
res = {"domain": {"journal_ids": []}}
|
||||
if not self.company_id:
|
||||
return res
|
||||
else:
|
||||
res["domain"]["journal_ids"] += [("company_id", "=", self.company_id.id)]
|
||||
return res
|
||||
|
||||
def _print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
data = self._prepare_report_journal_ledger()
|
||||
if report_type == "xlsx":
|
||||
report_name = "a_f_r.report_journal_ledger_xlsx"
|
||||
else:
|
||||
report_name = "account_financial_report.journal_ledger"
|
||||
return (
|
||||
self.env["ir.actions.report"]
|
||||
.search(
|
||||
[("report_name", "=", report_name), ("report_type", "=", report_type)],
|
||||
limit=1,
|
||||
)
|
||||
.report_action(self, data=data)
|
||||
)
|
||||
|
||||
def _prepare_report_journal_ledger(self):
|
||||
self.ensure_one()
|
||||
journals = self.journal_ids
|
||||
if not journals:
|
||||
# Not selecting a journal means that we'll display all journals
|
||||
journals = self.env["account.journal"].search(
|
||||
[("company_id", "=", self.company_id.id)]
|
||||
)
|
||||
return {
|
||||
"wizard_id": self.id,
|
||||
"date_from": self.date_from,
|
||||
"date_to": self.date_to,
|
||||
"move_target": self.move_target,
|
||||
"foreign_currency": self.foreign_currency,
|
||||
"company_id": self.company_id.id,
|
||||
"journal_ids": journals.ids,
|
||||
"sort_option": self.sort_option,
|
||||
"group_option": self.group_option,
|
||||
"with_account_name": self.with_account_name,
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
"with_auto_sequence": self.with_auto_sequence,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
self.ensure_one()
|
||||
return self._print_report(report_type)
|
||||
|
||||
@api.model
|
||||
def _get_ml_tax_description(
|
||||
self, move_line_data, tax_line_data, move_line_taxes_data
|
||||
):
|
||||
taxes_description = ""
|
||||
if move_line_data["tax_line_id"]:
|
||||
taxes_description = tax_line_data["description"] or tax_line_data["name"]
|
||||
elif move_line_taxes_data:
|
||||
tax_names = []
|
||||
for tax_key in move_line_taxes_data:
|
||||
tax = move_line_taxes_data[tax_key]
|
||||
tax_names.append(tax["description"] or tax["name"])
|
||||
taxes_description = ",".join(tax_names)
|
||||
return taxes_description
|
||||
|
||||
@api.model
|
||||
def _get_partner_name(self, partner_id, partner_data):
|
||||
if partner_id in partner_data.keys():
|
||||
return partner_data[partner_id]["name"]
|
||||
else:
|
||||
return ""
|
||||
|
||||
@api.model
|
||||
def _get_atr_from_dict(self, obj_id, data, key):
|
||||
try:
|
||||
return data[obj_id][key]
|
||||
except KeyError:
|
||||
return data[str(obj_id)][key]
|
||||
|
||||
@api.model
|
||||
def _get_data_from_dict(self, obj_id, data):
|
||||
if data:
|
||||
if isinstance(list(data.keys())[0], int):
|
||||
return data.get(obj_id, False)
|
||||
else:
|
||||
return data.get(obj_id(obj_id), False)
|
||||
else:
|
||||
return False
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2017 ACSONE SA/NV
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="journal_ledger_wizard" model="ir.ui.view">
|
||||
<field name="name">Journal Ledger</field>
|
||||
<field name="model">journal.ledger.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</group>
|
||||
<separator string="Periods" />
|
||||
<group>
|
||||
<group>
|
||||
<field name="date_range_id" />
|
||||
<field name="date_from" />
|
||||
<field name="date_to" />
|
||||
</group>
|
||||
<group />
|
||||
</group>
|
||||
<separator string="Options" />
|
||||
<group name="options">
|
||||
<group>
|
||||
<field
|
||||
name="move_target"
|
||||
widget="radio"
|
||||
options="{'horizontal': true}"
|
||||
/>
|
||||
<field name="sort_option" />
|
||||
<field name="group_option" />
|
||||
<field name="foreign_currency" />
|
||||
<field name="with_account_name" />
|
||||
<field name="with_auto_sequence" />
|
||||
</group>
|
||||
<group />
|
||||
</group>
|
||||
<separator string="Journals" />
|
||||
<group>
|
||||
<field name="journal_ids" widget="many2many_tags" />
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="button_export_html"
|
||||
string="View"
|
||||
type="object"
|
||||
default_focus="1"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_pdf"
|
||||
string="Export PDF"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_xlsx"
|
||||
string="Export XLSX"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_journal_ledger_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Journal Ledger</field>
|
||||
<field name="res_model">journal.ledger.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="journal_ledger_wizard" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
171
account_financial_report/wizard/open_items_wizard.py
Normal file
171
account_financial_report/wizard/open_items_wizard.py
Normal file
@@ -0,0 +1,171 @@
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class OpenItemsReportWizard(models.TransientModel):
|
||||
"""Open items report wizard."""
|
||||
|
||||
_name = "open.items.report.wizard"
|
||||
_description = "Open Items Report Wizard"
|
||||
_inherit = "account_financial_report_abstract_wizard"
|
||||
|
||||
date_at = fields.Date(required=True, default=fields.Date.context_today)
|
||||
date_from = fields.Date()
|
||||
target_move = fields.Selection(
|
||||
[("posted", "All Posted Entries"), ("all", "All Entries")],
|
||||
string="Target Moves",
|
||||
required=True,
|
||||
default="posted",
|
||||
)
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name="account.account",
|
||||
string="Filter accounts",
|
||||
domain=[("reconcile", "=", True)],
|
||||
required=True,
|
||||
)
|
||||
hide_account_at_0 = fields.Boolean(
|
||||
string="Hide account ending balance at 0",
|
||||
default=True,
|
||||
help="Use this filter to hide an account or a partner "
|
||||
"with an ending balance at 0. "
|
||||
"If partners are filtered, "
|
||||
"debits and credits totals will not match the trial balance.",
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name="res.partner",
|
||||
string="Filter partners",
|
||||
default=lambda self: self._default_partners(),
|
||||
)
|
||||
foreign_currency = fields.Boolean(
|
||||
string="Show foreign currency",
|
||||
help="Display foreign currency for move lines, unless "
|
||||
"account currency is not setup through chart of accounts "
|
||||
"will display initial and final balance in that currency.",
|
||||
default=lambda self: self._default_foreign_currency(),
|
||||
)
|
||||
show_partner_details = fields.Boolean(
|
||||
default=True,
|
||||
)
|
||||
account_code_from = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
)
|
||||
account_code_to = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Ending account in a range",
|
||||
)
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
if (
|
||||
self.account_code_from
|
||||
and self.account_code_from.code.isdigit()
|
||||
and self.account_code_to
|
||||
and self.account_code_to.code.isdigit()
|
||||
):
|
||||
start_range = int(self.account_code_from.code)
|
||||
end_range = int(self.account_code_to.code)
|
||||
self.account_ids = self.env["account.account"].search(
|
||||
[
|
||||
("code", ">=", start_range),
|
||||
("code", "<=", end_range),
|
||||
("reconcile", "=", True),
|
||||
]
|
||||
)
|
||||
if self.company_id:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
return {
|
||||
"domain": {
|
||||
"account_code_from": [("reconcile", "=", True)],
|
||||
"account_code_to": [("reconcile", "=", True)],
|
||||
}
|
||||
}
|
||||
|
||||
def _default_foreign_currency(self):
|
||||
return self.env.user.has_group("base.group_multi_currency")
|
||||
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
if self.company_id and self.partner_ids:
|
||||
self.partner_ids = self.partner_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
if self.company_id and self.account_ids:
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
self.onchange_type_accounts_only()
|
||||
else:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
res = {"domain": {"account_ids": [], "partner_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()
|
||||
return res
|
||||
|
||||
@api.onchange("account_ids")
|
||||
def onchange_account_ids(self):
|
||||
return {"domain": {"account_ids": [("reconcile", "=", True)]}}
|
||||
|
||||
@api.onchange("receivable_accounts_only", "payable_accounts_only")
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
domain = [("company_ids", "in", [self.company_id.id])]
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [
|
||||
("account_type", "in", ("asset_receivable", "liability_payable"))
|
||||
]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [("account_type", "=", "asset_receivable")]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [("account_type", "=", "liability_payable")]
|
||||
self.account_ids = self.env["account.account"].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
def _print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
data = self._prepare_report_open_items()
|
||||
if report_type == "xlsx":
|
||||
report_name = "a_f_r.report_open_items_xlsx"
|
||||
else:
|
||||
report_name = "account_financial_report.open_items"
|
||||
return (
|
||||
self.env["ir.actions.report"]
|
||||
.search(
|
||||
[("report_name", "=", report_name), ("report_type", "=", report_type)],
|
||||
limit=1,
|
||||
)
|
||||
.report_action(self, data=data)
|
||||
)
|
||||
|
||||
def _prepare_report_open_items(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"wizard_id": self.id,
|
||||
"date_at": fields.Date.to_string(self.date_at),
|
||||
"date_from": self.date_from or False,
|
||||
"only_posted_moves": self.target_move == "posted",
|
||||
"hide_account_at_0": self.hide_account_at_0,
|
||||
"foreign_currency": self.foreign_currency,
|
||||
"show_partner_details": self.show_partner_details,
|
||||
"company_id": self.company_id.id,
|
||||
"target_move": self.target_move,
|
||||
"account_ids": self.account_ids.ids,
|
||||
"partner_ids": self.partner_ids.ids or [],
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
return self._print_report(report_type)
|
||||
117
account_financial_report/wizard/open_items_wizard_view.xml
Normal file
117
account_financial_report/wizard/open_items_wizard_view.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<!-- OPEN ITEMS -->
|
||||
<record id="open_items_wizard" model="ir.ui.view">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="model">open.items.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field
|
||||
name="company_id"
|
||||
options="{'no_create': True}"
|
||||
groups="base.group_multi_company"
|
||||
/>
|
||||
</group>
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_at" />
|
||||
<field name="date_from" />
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio" />
|
||||
<field name="show_partner_details" />
|
||||
<field name="hide_account_at_0" />
|
||||
<field name="foreign_currency" />
|
||||
</group>
|
||||
</group>
|
||||
<group name="partner_filter" col="1">
|
||||
<label for="partner_ids" />
|
||||
<field
|
||||
name="partner_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<group name="account_filter" col="4">
|
||||
<field name="receivable_accounts_only" />
|
||||
<field name="payable_accounts_only" />
|
||||
<label for="account_code_from" string="From Code" />
|
||||
<div>
|
||||
<div class="o_row">
|
||||
<field
|
||||
name="account_code_from"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<span class="oe_inline">To</span>
|
||||
<field
|
||||
name="account_code_to"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<field
|
||||
name="account_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="button_export_html"
|
||||
string="View"
|
||||
type="object"
|
||||
default_focus="1"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_pdf"
|
||||
string="Export PDF"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_xlsx"
|
||||
string="Export XLSX"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_open_items_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="res_model">open.items.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="open_items_wizard" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
<!--Add to res.partner action-->
|
||||
<record
|
||||
id="act_action_open_items_wizard_partner_relation"
|
||||
model="ir.actions.act_window"
|
||||
>
|
||||
<field name="name">Open Items Partner</field>
|
||||
<field name="res_model">open.items.report.wizard</field>
|
||||
<field name="binding_model_id" ref="base.model_res_partner" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="open_items_wizard" />
|
||||
<field
|
||||
name="context"
|
||||
eval="{
|
||||
'default_receivable_accounts_only':1,
|
||||
'default_payable_accounts_only':1,
|
||||
}"
|
||||
/>
|
||||
<field name="groups_id" eval="[(4, ref('account.group_account_manager'))]" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
284
account_financial_report/wizard/trial_balance_wizard.py
Normal file
284
account_financial_report/wizard/trial_balance_wizard.py
Normal file
@@ -0,0 +1,284 @@
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2017 Akretion - Alexis de Lattre
|
||||
# Copyright 2018 ForgeFlow, S.L.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import date_utils
|
||||
|
||||
|
||||
class TrialBalanceReportWizard(models.TransientModel):
|
||||
"""Trial balance report wizard."""
|
||||
|
||||
_name = "trial.balance.report.wizard"
|
||||
_description = "Trial Balance Report Wizard"
|
||||
_inherit = "account_financial_report_abstract_wizard"
|
||||
|
||||
date_range_id = fields.Many2one(comodel_name="date.range", string="Date range")
|
||||
date_from = fields.Date(required=True)
|
||||
date_to = fields.Date(required=True)
|
||||
fy_start_date = fields.Date(compute="_compute_fy_start_date")
|
||||
target_move = fields.Selection(
|
||||
[("posted", "All Posted Entries"), ("all", "All Entries")],
|
||||
string="Target Moves",
|
||||
required=True,
|
||||
default="posted",
|
||||
)
|
||||
show_hierarchy = fields.Boolean(
|
||||
string="Show hierarchy",
|
||||
help="Use when your account groups are hierarchical",
|
||||
)
|
||||
limit_hierarchy_level = fields.Boolean("Limit hierarchy levels")
|
||||
show_hierarchy_level = fields.Integer("Hierarchy Levels to display", default=1)
|
||||
hide_parent_hierarchy_level = fields.Boolean(
|
||||
"Do not display parent levels", default=False
|
||||
)
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name="account.account", string="Filter accounts"
|
||||
)
|
||||
hide_account_at_0 = fields.Boolean(
|
||||
string="Hide accounts at 0",
|
||||
default=True,
|
||||
help="When this option is enabled, the trial balance will "
|
||||
"not display accounts that have initial balance = "
|
||||
"debit = credit = end balance = 0",
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
show_partner_details = fields.Boolean()
|
||||
partner_ids = fields.Many2many(comodel_name="res.partner", string="Filter partners")
|
||||
journal_ids = fields.Many2many(comodel_name="account.journal")
|
||||
only_one_unaffected_earnings_account = fields.Boolean(
|
||||
readonly=True,
|
||||
default=lambda self: self._only_one_unaffected_earnings_account(),
|
||||
)
|
||||
foreign_currency = fields.Boolean(
|
||||
string="Show foreign currency",
|
||||
help="Display foreign currency for move lines, unless "
|
||||
"account currency is not setup through chart of accounts "
|
||||
"will display initial and final balance in that currency.",
|
||||
)
|
||||
account_code_from = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Starting account in a range",
|
||||
)
|
||||
account_code_to = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
help="Ending account in a range",
|
||||
)
|
||||
grouped_by = fields.Selection(
|
||||
selection=[("analytic_account", "Analytic Account")], default=False
|
||||
)
|
||||
|
||||
@api.onchange("grouped_by")
|
||||
def onchange_grouped_by(self):
|
||||
if self.grouped_by == "analytic_account":
|
||||
self.show_partner_details = False
|
||||
self.show_hierarchy = False
|
||||
|
||||
@api.onchange("account_code_from", "account_code_to")
|
||||
def on_change_account_range(self):
|
||||
if (
|
||||
self.account_code_from
|
||||
and self.account_code_from.code.isdigit()
|
||||
and self.account_code_to
|
||||
and self.account_code_to.code.isdigit()
|
||||
):
|
||||
start_range = self.account_code_from.code
|
||||
end_range = self.account_code_to.code
|
||||
self.account_ids = self.env["account.account"].search(
|
||||
[("code", ">=", start_range), ("code", "<=", end_range)]
|
||||
)
|
||||
if self.company_id:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: self.company_id in a.company_ids
|
||||
)
|
||||
|
||||
@api.constrains("show_hierarchy", "show_hierarchy_level")
|
||||
def _check_show_hierarchy_level(self):
|
||||
for rec in self:
|
||||
if rec.show_hierarchy and rec.show_hierarchy_level <= 0:
|
||||
raise UserError(
|
||||
self.env._(
|
||||
"The hierarchy level to filter on must be greater than 0."
|
||||
)
|
||||
)
|
||||
|
||||
@api.depends("date_from")
|
||||
def _compute_fy_start_date(self):
|
||||
for wiz in self:
|
||||
if wiz.date_from:
|
||||
date_from, date_to = date_utils.get_fiscal_year(
|
||||
wiz.date_from,
|
||||
day=self.company_id.fiscalyear_last_day,
|
||||
month=int(self.company_id.fiscalyear_last_month),
|
||||
)
|
||||
wiz.fy_start_date = date_from
|
||||
else:
|
||||
wiz.fy_start_date = False
|
||||
|
||||
def _only_one_unaffected_earnings_account(self):
|
||||
count = self.env["account.account"].search_count(
|
||||
[
|
||||
("account_type", "=", "equity_unaffected"),
|
||||
("company_ids", "in", [self.company_id.id or self.env.company.id]),
|
||||
]
|
||||
)
|
||||
return count == 1
|
||||
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
self.only_one_unaffected_earnings_account = (
|
||||
self._only_one_unaffected_earnings_account()
|
||||
)
|
||||
if (
|
||||
self.company_id
|
||||
and self.date_range_id.company_id
|
||||
and self.date_range_id.company_id != self.company_id
|
||||
):
|
||||
self.date_range_id = False
|
||||
if self.company_id and self.partner_ids:
|
||||
self.partner_ids = self.partner_ids.filtered(
|
||||
lambda p: p.company_id == self.company_id or not p.company_id
|
||||
)
|
||||
if self.company_id and self.journal_ids:
|
||||
self.journal_ids = self.journal_ids.filtered(
|
||||
lambda a: a.company_id == self.company_id
|
||||
)
|
||||
if self.company_id and self.account_ids:
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
self.onchange_type_accounts_only()
|
||||
else:
|
||||
self.account_ids = self.account_ids.filtered(
|
||||
lambda a: self.company_id in a.company_ids
|
||||
)
|
||||
res = {
|
||||
"domain": {
|
||||
"account_ids": [],
|
||||
"partner_ids": [],
|
||||
"date_range_id": [],
|
||||
"journal_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"]["date_range_id"] += [
|
||||
"|",
|
||||
("company_id", "=", self.company_id.id),
|
||||
("company_id", "=", False),
|
||||
]
|
||||
res["domain"]["journal_ids"] += [("company_id", "=", self.company_id.id)]
|
||||
return res
|
||||
|
||||
@api.onchange("date_range_id")
|
||||
def onchange_date_range_id(self):
|
||||
"""Handle date range change."""
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
|
||||
@api.constrains("company_id", "date_range_id")
|
||||
def _check_company_id_date_range_id(self):
|
||||
for rec in self.sudo():
|
||||
if (
|
||||
rec.company_id
|
||||
and rec.date_range_id.company_id
|
||||
and rec.company_id != rec.date_range_id.company_id
|
||||
):
|
||||
raise ValidationError(
|
||||
self.env._(
|
||||
"The Company in the Trial Balance Report Wizard and in "
|
||||
"Date Range must be the same."
|
||||
)
|
||||
)
|
||||
|
||||
@api.onchange("receivable_accounts_only", "payable_accounts_only")
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = [("company_ids", "in", [self.company_id.id])]
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [
|
||||
("account_type", "in", ("asset_receivable", "liability_payable"))
|
||||
]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [("account_type", "=", "asset_receivable")]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [("account_type", "=", "liability_payable")]
|
||||
self.account_ids = self.env["account.account"].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.onchange("show_partner_details")
|
||||
def onchange_show_partner_details(self):
|
||||
"""Handle partners change."""
|
||||
if self.show_partner_details:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = True
|
||||
self.grouped_by = False
|
||||
else:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = False
|
||||
|
||||
@api.depends("company_id")
|
||||
def _compute_unaffected_earnings_account(self):
|
||||
for record in self:
|
||||
record.unaffected_earnings_account = self.env["account.account"].search(
|
||||
[
|
||||
("account_type", "=", "equity_unaffected"),
|
||||
("company_ids", "in", [record.company_id.id]),
|
||||
]
|
||||
)
|
||||
|
||||
unaffected_earnings_account = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
compute="_compute_unaffected_earnings_account",
|
||||
store=True,
|
||||
)
|
||||
|
||||
def _print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
data = self._prepare_report_trial_balance()
|
||||
if report_type == "xlsx":
|
||||
report_name = "a_f_r.report_trial_balance_xlsx"
|
||||
else:
|
||||
report_name = "account_financial_report.trial_balance"
|
||||
return (
|
||||
self.env["ir.actions.report"]
|
||||
.search(
|
||||
[("report_name", "=", report_name), ("report_type", "=", report_type)],
|
||||
limit=1,
|
||||
)
|
||||
.report_action(self, data=data)
|
||||
)
|
||||
|
||||
def _prepare_report_trial_balance(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"wizard_id": self.id,
|
||||
"date_from": self.date_from,
|
||||
"date_to": self.date_to,
|
||||
"only_posted_moves": self.target_move == "posted",
|
||||
"hide_account_at_0": self.hide_account_at_0,
|
||||
"foreign_currency": self.foreign_currency,
|
||||
"company_id": self.company_id.id,
|
||||
"account_ids": self.account_ids.ids or [],
|
||||
"partner_ids": self.partner_ids.ids or [],
|
||||
"journal_ids": self.journal_ids.ids or [],
|
||||
"fy_start_date": self.fy_start_date,
|
||||
"show_hierarchy": self.show_hierarchy,
|
||||
"limit_hierarchy_level": self.limit_hierarchy_level,
|
||||
"show_hierarchy_level": self.show_hierarchy_level,
|
||||
"hide_parent_hierarchy_level": self.hide_parent_hierarchy_level,
|
||||
"show_partner_details": self.show_partner_details,
|
||||
"unaffected_earnings_account": self.unaffected_earnings_account.id,
|
||||
"account_financial_report_lang": self.env.lang,
|
||||
"grouped_by": self.grouped_by,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
return self._print_report(report_type)
|
||||
158
account_financial_report/wizard/trial_balance_wizard_view.xml
Normal file
158
account_financial_report/wizard/trial_balance_wizard_view.xml
Normal file
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<!-- TRIAL BALANCE -->
|
||||
<record id="trial_balance_wizard" model="ir.ui.view">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="model">trial.balance.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<div
|
||||
class="alert alert-warning"
|
||||
role="alert"
|
||||
invisible="grouped_by!='analytic_account'"
|
||||
>
|
||||
<i class="fa fa-exclamation-triangle mr-3" />
|
||||
Duplicate amounts may be shown because more than one analytical account may be defined in the journal items.
|
||||
</div>
|
||||
<group name="main_info">
|
||||
<field
|
||||
name="company_id"
|
||||
options="{'no_create': True}"
|
||||
groups="base.group_multi_company"
|
||||
/>
|
||||
</group>
|
||||
<div invisible="not only_one_unaffected_earnings_account">
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_range_id" />
|
||||
<field name="date_from" />
|
||||
<field name="date_to" />
|
||||
<field name="fy_start_date" invisible="1" />
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio" />
|
||||
<field name="grouped_by" invisible="1" />
|
||||
<field
|
||||
name="grouped_by"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
/>
|
||||
<field name="hide_account_at_0" />
|
||||
<field name="show_partner_details" invisible="grouped_by" />
|
||||
<field
|
||||
name="show_hierarchy"
|
||||
invisible="show_partner_details == True or grouped_by"
|
||||
/>
|
||||
<field
|
||||
name="limit_hierarchy_level"
|
||||
invisible="show_hierarchy == False or show_partner_details == True"
|
||||
/>
|
||||
<field
|
||||
name="show_hierarchy_level"
|
||||
invisible="limit_hierarchy_level == False"
|
||||
/>
|
||||
<field
|
||||
name="hide_parent_hierarchy_level"
|
||||
invisible="limit_hierarchy_level == False"
|
||||
/>
|
||||
<field name="foreign_currency" />
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
name="partner_filter"
|
||||
invisible="show_partner_details == True"
|
||||
col="1"
|
||||
>
|
||||
<label for="partner_ids" />
|
||||
<field
|
||||
name="partner_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<label for="journal_ids" />
|
||||
<field
|
||||
name="journal_ids"
|
||||
widget="many2many_tags"
|
||||
nolabel="1"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<group invisible="show_partner_details == True" />
|
||||
<div />
|
||||
<group name="account_filter" col="4">
|
||||
<label for="account_ids" colspan="4" />
|
||||
<field name="receivable_accounts_only" />
|
||||
<field name="payable_accounts_only" />
|
||||
<label for="account_code_from" string="From Code" />
|
||||
<div>
|
||||
<div class="o_row">
|
||||
<field
|
||||
name="account_code_from"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<span class="oe_inline">To</span>
|
||||
<field
|
||||
name="account_code_to"
|
||||
class="oe_inline"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<field
|
||||
name="account_ids"
|
||||
nolabel="1"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True}"
|
||||
colspan="4"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
<div invisible="only_one_unaffected_earnings_account">
|
||||
<field name="only_one_unaffected_earnings_account" invisible="1" />
|
||||
<group />
|
||||
<h4>
|
||||
Trial Balance can be computed only if selected company have only
|
||||
one unaffected earnings account.
|
||||
</h4>
|
||||
<group />
|
||||
</div>
|
||||
<footer>
|
||||
<div invisible="not only_one_unaffected_earnings_account">
|
||||
<button
|
||||
name="button_export_html"
|
||||
string="View"
|
||||
type="object"
|
||||
default_focus="1"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_pdf"
|
||||
string="Export PDF"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button
|
||||
name="button_export_xlsx"
|
||||
string="Export XLSX"
|
||||
type="object"
|
||||
/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
<div invisible="only_one_unaffected_earnings_account">
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_trial_balance_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="res_model">trial.balance.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="trial_balance_wizard" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user