Browse Source

Merge pull request #485 from Eficent/10.0-afr-backport-account-group

[10.0][account_financial_report_qweb] backport latest changes from 11.0
pull/497/head
Jordi Ballester Alomar 6 years ago
committed by GitHub
parent
commit
9e0a4579f0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 88
      account_financial_report_qweb/README.rst
  2. 4
      account_financial_report_qweb/__manifest__.py
  3. 31
      account_financial_report_qweb/models/account_group.py
  4. 20
      account_financial_report_qweb/readme/CONTRIBUTORS.rst
  5. 16
      account_financial_report_qweb/readme/DESCRIPTION.rst
  6. 9
      account_financial_report_qweb/readme/HISTORY.rst
  7. 47
      account_financial_report_qweb/report/abstract_report_xlsx.py
  8. 356
      account_financial_report_qweb/report/general_ledger.py
  9. 2
      account_financial_report_qweb/report/general_ledger_xlsx.py
  10. 4
      account_financial_report_qweb/report/open_items.py
  11. 2
      account_financial_report_qweb/report/open_items_xlsx.py
  12. 4
      account_financial_report_qweb/report/templates/general_ledger.xml
  13. 4
      account_financial_report_qweb/report/templates/open_items.xml
  14. 188
      account_financial_report_qweb/report/templates/trial_balance.xml
  15. 290
      account_financial_report_qweb/report/trial_balance.py
  16. 33
      account_financial_report_qweb/report/trial_balance_xlsx.py
  17. 447
      account_financial_report_qweb/static/description/index.html
  18. 40
      account_financial_report_qweb/tests/test_general_ledger.py
  19. 4
      account_financial_report_qweb/tests/test_open_items.py
  20. 8
      account_financial_report_qweb/tests/test_trial_balance.py
  21. 24
      account_financial_report_qweb/wizard/aged_partner_balance_wizard.py
  22. 11
      account_financial_report_qweb/wizard/aged_partner_balance_wizard_view.xml
  23. 25
      account_financial_report_qweb/wizard/general_ledger_wizard.py
  24. 8
      account_financial_report_qweb/wizard/general_ledger_wizard_view.xml
  25. 9
      account_financial_report_qweb/wizard/journal_report_wizard.py
  26. 28
      account_financial_report_qweb/wizard/open_items_wizard.py
  27. 13
      account_financial_report_qweb/wizard/open_items_wizard_view.xml
  28. 67
      account_financial_report_qweb/wizard/trial_balance_wizard.py
  29. 13
      account_financial_report_qweb/wizard/trial_balance_wizard_view.xml

88
account_financial_report_qweb/README.rst

@ -1,42 +1,85 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
======================
QWeb Financial Reports
======================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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 :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :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/10.0/account_financial_report_qweb
: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-10-0/account-financial-reporting-10-0-account_financial_report_qweb
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/91/10.0
:alt: Try me on Runbot
=============================
account_financial_report_qweb
=============================
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds a set of financial reports. They are accessible under This module adds a set of financial reports. They are accessible under
Accounting / Reporting / OCA Reports. Accounting / Reporting / OCA Reports.
- General ledger - General ledger
- Journal Ledger
- Trial Balance - Trial Balance
- Open Items - Open Items
- Aged Partner Balance - Aged Partner Balance
- VAT Report
- Journal Ledger
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/91/10.0
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.
**Table of contents**
.. contents::
:local:
Changelog
=========
10.0.2.0.0 (2018-11-29)
~~~~~~~~~~~~~~~~~~~~~~~
* The Trial Balance now allows to display the hierarchy of accounts
* In the Trial Balance you can apply a filter by hierarchy levels
* In the Journal Ledger the field 'Journal' is now optional
Bug Tracker 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 smashing it by providing a detailed and welcomed feedback.
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 smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/account-financial-reporting/issues/new?body=module:%20account_financial_report_qweb%0Aversion:%2010.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 Credits
======= =======
Images
------
Authors
~~~~~~~
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
* Camptocamp SA
* initOS GmbH
* redCOR AG
* ACSONE SA/NV
Contributors Contributors
------------
~~~~~~~~~~~~
* Jordi Ballester <jordi.ballester@eficient.com> * Jordi Ballester <jordi.ballester@eficient.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com> * Yannick Vaucher <yannick.vaucher@camptocamp.com>
@ -53,22 +96,25 @@ Contributors
* Julien Coux <julien.coux@camptocamp.com> * Julien Coux <julien.coux@camptocamp.com>
* Akim Juillerat <akim.juillerat@camptocamp.com> * Akim Juillerat <akim.juillerat@camptocamp.com>
* Alexis de Lattre <alexis@via.ecp.fr> * Alexis de Lattre <alexis@via.ecp.fr>
* Mihai Fekete <feketemihai@gmail.com>
* Benjamin Willig <benjamin.willig@acsone.eu> * Benjamin Willig <benjamin.willig@acsone.eu>
Much of the work in this module was done at a sprint in Sorrento, Italy in Much of the work in this module was done at a sprint in Sorrento, Italy in
April 2016. April 2016.
Maintainer
----------
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png .. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association :alt: Odoo Community Association
:target: https://odoo-community.org :target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.
This module is part of the `OCA/account-financial-reporting <https://github.com/OCA/account-financial-reporting/tree/10.0/account_financial_report_qweb>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

4
account_financial_report_qweb/__manifest__.py

@ -5,7 +5,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{ {
'name': 'QWeb Financial Reports', 'name': 'QWeb Financial Reports',
'version': '10.0.1.5.3',
'version': '10.0.2.0.0',
'category': 'Reporting', 'category': 'Reporting',
'summary': 'OCA Financial Reports', 'summary': 'OCA Financial Reports',
'author': 'Camptocamp SA,' 'author': 'Camptocamp SA,'
@ -16,9 +16,11 @@
"website": "https://odoo-community.org/", "website": "https://odoo-community.org/",
'depends': [ 'depends': [
'account', 'account',
'account_group', # account-financial-tools
'date_range', 'date_range',
'report_xlsx', 'report_xlsx',
'report', 'report',
'web_widget_many2many_tags_multi_selection',
], ],
'data': [ 'data': [
'wizard/aged_partner_balance_wizard_view.xml', 'wizard/aged_partner_balance_wizard_view.xml',

31
account_financial_report_qweb/models/account_group.py

@ -0,0 +1,31 @@
# coding: utf-8
# Copyright 2018 Eficent
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
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')
compute_account_ids = fields.Many2many(
'account.account',
compute='_compute_group_accounts',
string="Accounts", store=True)
@api.multi
@api.depends('code_prefix', 'account_ids', 'account_ids.code',
'group_child_ids', 'group_child_ids.account_ids.code')
def _compute_group_accounts(self):
account_obj = self.env['account.account']
accounts = account_obj.search([])
for group in self:
prefix = group.code_prefix if group.code_prefix else group.name
gr_acc = accounts.filtered(
lambda a: a.code.startswith(prefix)).ids
group.compute_account_ids = [(6, 0, gr_acc)]

20
account_financial_report_qweb/readme/CONTRIBUTORS.rst

@ -0,0 +1,20 @@
* Jordi Ballester <jordi.ballester@eficient.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 <lorenzo.battistini@agilebg.com>
* Julien Coux <julien.coux@camptocamp.com>
* Akim Juillerat <akim.juillerat@camptocamp.com>
* Alexis de Lattre <alexis@via.ecp.fr>
* Mihai Fekete <feketemihai@gmail.com>
* Benjamin Willig <benjamin.willig@acsone.eu>
Much of the work in this module was done at a sprint in Sorrento, Italy in
April 2016.

16
account_financial_report_qweb/readme/DESCRIPTION.rst

@ -0,0 +1,16 @@
This module adds a set of financial reports. They are accessible under
Accounting / Reporting / OCA 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.

9
account_financial_report_qweb/readme/HISTORY.rst

@ -0,0 +1,9 @@
10.0.2.0.0 (2018-11-29)
~~~~~~~~~~~~~~~~~~~~~~~
* The Trial Balance now allows to display the hierarchy of accounts
* In the Trial Balance you can apply a filter by hierarchy levels
* The Trial Balance shows the unaffected earnings account computed as:
initial balance: sum of past unaffected earnings + P&L result; debit, credit
and period balance: totals only for the unaffected earnings account.
* In the Journal Ledger the field 'Journal' is now optional

47
account_financial_report_qweb/report/abstract_report_xlsx.py

@ -23,6 +23,7 @@ class AbstractReportXslx(ReportXlsx):
# Formats # Formats
self.format_right = None self.format_right = None
self.format_left = None
self.format_right_bold_italic = None self.format_right_bold_italic = None
self.format_bold = None self.format_bold = None
self.format_header_left = None self.format_header_left = None
@ -43,6 +44,7 @@ class AbstractReportXslx(ReportXlsx):
self._define_formats(workbook) self._define_formats(workbook)
report_name = self._get_report_name() report_name = self._get_report_name()
report_footer = self._get_report_footer()
filters = self._get_report_filters(report) filters = self._get_report_filters(report)
self.columns = self._get_report_columns(report) self.columns = self._get_report_columns(report)
@ -57,6 +59,8 @@ class AbstractReportXslx(ReportXlsx):
self._generate_report_content(workbook, report) self._generate_report_content(workbook, report)
self._write_report_footer(report_footer)
def add_sheet(self, workbook, sheet_name): def add_sheet(self, workbook, sheet_name):
return workbook.add_worksheet(sheet_name) return workbook.add_worksheet(sheet_name)
@ -80,6 +84,7 @@ class AbstractReportXslx(ReportXlsx):
""" """
self.format_bold = workbook.add_format({'bold': True}) self.format_bold = workbook.add_format({'bold': True})
self.format_right = workbook.add_format({'align': 'right'}) self.format_right = workbook.add_format({'align': 'right'})
self.format_left = workbook.add_format({'align': 'left'})
self.format_right_bold_italic = workbook.add_format( self.format_right_bold_italic = workbook.add_format(
{'align': 'right', 'bold': True, 'italic': True} {'align': 'right', 'bold': True, 'italic': True}
) )
@ -107,6 +112,9 @@ class AbstractReportXslx(ReportXlsx):
self.format_amount = workbook.add_format() self.format_amount = workbook.add_format()
self.format_amount.set_num_format( self.format_amount.set_num_format(
'#,##0.'+'0'*currency_id.decimal_places) '#,##0.'+'0'*currency_id.decimal_places)
self.format_amount_bold = workbook.add_format({'bold': True})
self.format_amount_bold.set_num_format(
'#,##0.'+'0'*currency_id.decimal_places)
self.format_percent_bold_italic = workbook.add_format( self.format_percent_bold_italic = workbook.add_format(
{'bold': True, 'italic': True} {'bold': True, 'italic': True}
) )
@ -135,6 +143,18 @@ class AbstractReportXslx(ReportXlsx):
) )
self.row_pos += 3 self.row_pos += 3
def _write_report_footer(self, footer):
"""Write report footer .
Columns are defined with `_get_report_columns` method.
"""
if footer:
self.row_pos += 1
self.sheet.merge_range(
self.row_pos, 0, self.row_pos, len(self.columns) - 1,
footer, self.format_left
)
self.row_pos += 1
def _write_filters(self, filters): def _write_filters(self, filters):
"""Write one line per filters on starting on current line. """Write one line per filters on starting on current line.
Columns number for filter name is defined Columns number for filter name is defined
@ -188,10 +208,20 @@ class AbstractReportXslx(ReportXlsx):
value = getattr(line_object, column['field']) value = getattr(line_object, column['field'])
cell_type = column.get('type', 'string') cell_type = column.get('type', 'string')
if cell_type == 'string': if cell_type == 'string':
if hasattr(line_object, 'account_group_id') and \
line_object.account_group_id:
self.sheet.write_string(self.row_pos, col_pos, value or '',
self.format_bold)
else:
self.sheet.write_string(self.row_pos, col_pos, value or '') self.sheet.write_string(self.row_pos, col_pos, value or '')
elif cell_type == 'amount': elif cell_type == 'amount':
if hasattr(line_object, 'account_group_id') and \
line_object.account_group_id:
cell_format = self.format_amount_bold
else:
cell_format = self.format_amount
self.sheet.write_number( self.sheet.write_number(
self.row_pos, col_pos, float(value), self.format_amount
self.row_pos, col_pos, float(value), cell_format
) )
elif cell_type == 'amount_currency': elif cell_type == 'amount_currency':
if line_object.currency_id: if line_object.currency_id:
@ -288,10 +318,16 @@ class AbstractReportXslx(ReportXlsx):
def _get_currency_amt_format(self, line_object): def _get_currency_amt_format(self, line_object):
""" Return amount format specific for each currency. """ """ Return amount format specific for each currency. """
if hasattr(line_object, 'account_group_id') and \
line_object.account_group_id:
format_amt = getattr(self, 'format_amount_bold')
field_prefix = 'format_amount_bold'
else:
format_amt = getattr(self, 'format_amount') format_amt = getattr(self, 'format_amount')
field_prefix = 'format_amount'
if line_object.currency_id: if line_object.currency_id:
field_name = \ field_name = \
'format_amount_%s' % line_object.currency_id.name
'%s_%s' % (field_prefix, line_object.currency_id.name)
if hasattr(self, field_name): if hasattr(self, field_name):
format_amt = getattr(self, field_name) format_amt = getattr(self, field_name)
else: else:
@ -333,6 +369,13 @@ class AbstractReportXslx(ReportXlsx):
""" """
raise NotImplementedError() 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): def _get_report_columns(self, report):
""" """
Allow to define the report columns Allow to define the report columns

356
account_financial_report_qweb/report/general_ledger.py

@ -29,7 +29,7 @@ class GeneralLedgerReport(models.TransientModel):
date_to = fields.Date() date_to = fields.Date()
fy_start_date = fields.Date() fy_start_date = fields.Date()
only_posted_moves = fields.Boolean() only_posted_moves = fields.Boolean()
hide_account_balance_at_0 = fields.Boolean()
hide_account_at_0 = fields.Boolean()
foreign_currency = fields.Boolean() foreign_currency = fields.Boolean()
show_analytic_tags = fields.Boolean() show_analytic_tags = fields.Boolean()
company_id = fields.Many2one(comodel_name='res.company') company_id = fields.Many2one(comodel_name='res.company')
@ -552,7 +552,7 @@ WHERE
OR f.balance IS NOT NULL AND f.balance != 0 OR f.balance IS NOT NULL AND f.balance != 0
) )
""" """
if self.hide_account_balance_at_0:
if self.hide_account_at_0:
query_inject_account += """ query_inject_account += """
AND AND
f.balance IS NOT NULL AND f.balance != 0 f.balance IS NOT NULL AND f.balance != 0
@ -613,7 +613,7 @@ AND
tuple(self.filter_cost_center_ids.ids), tuple(self.filter_cost_center_ids.ids),
) )
query_inject_account_params += ( query_inject_account_params += (
self.id or 'NULL',
self.id,
self.env.uid, self.env.uid,
) )
self.env.cr.execute(query_inject_account, query_inject_account_params) self.env.cr.execute(query_inject_account, query_inject_account_params)
@ -934,7 +934,7 @@ WHERE
OR f.balance IS NOT NULL AND f.balance != 0 OR f.balance IS NOT NULL AND f.balance != 0
) )
""" """
if self.hide_account_balance_at_0:
if self.hide_account_at_0:
query_inject_partner += """ query_inject_partner += """
AND AND
f.balance IS NOT NULL AND f.balance != 0 f.balance IS NOT NULL AND f.balance != 0
@ -1559,158 +1559,160 @@ WHERE
} }
self.env.cr.execute(query_update_analytic_tags, params) self.env.cr.execute(query_update_analytic_tags, params)
def _get_unaffected_earnings_account_sub_subquery_sum_initial(
self
):
""" Return subquery used to compute sum amounts on
unaffected earnings accounts """
sub_subquery_sum_amounts = """
def _inject_unaffected_earnings_account_values(self):
"""Inject the report values of the unaffected earnings account
for report_general_ledger_qweb_account."""
# Fetch the profit and loss accounts
query_unaffected_earnings_account_ids = """
SELECT a.id
FROM account_account as a
INNER JOIN account_account_type as at
ON at.id = a.user_type_id
WHERE at.include_initial_balance = FALSE
"""
self.env.cr.execute(query_unaffected_earnings_account_ids)
pl_account_ids = [r[0] for r in self.env.cr.fetchall()]
unaffected_earnings_account_ids = \
pl_account_ids + [self.unaffected_earnings_account.id]
# Fetch the current fiscal year start date
date = fields.Datetime.from_string(self.date_from)
res = self.company_id.compute_fiscalyear_dates(date)
fy_start_date = res['date_from']
query_select_previous_fy_unaffected_earnings_params = {
'date_to': fy_start_date,
'company_id': self.company_id.id,
'account_ids': tuple(unaffected_earnings_account_ids),
'analytic_tag_ids': tuple(self.filter_analytic_tag_ids.ids),
}
query_select_previous_fy_unaffected_earnings = ''
q_analytic_tags = ''
if self.filter_analytic_tag_ids:
q_analytic_tags = """
WITH move_lines_on_tags AS
(
SELECT SELECT
SUM(ml.balance) AS initial_balance,
0.0 AS final_balance
DISTINCT ml.id AS ml_id
FROM FROM
account_account a account_account a
INNER JOIN
account_account_type at ON a.user_type_id = at.id
INNER JOIN INNER JOIN
account_move_line ml account_move_line ml
ON a.id = ml.account_id ON a.id = ml.account_id
AND ml.date < %(date_from)s
"""
if self.only_posted_moves:
sub_subquery_sum_amounts += """
INNER JOIN INNER JOIN
account_move m ON ml.move_id = m.id AND m.state = 'posted'
"""
if self.filter_cost_center_ids:
sub_subquery_sum_amounts += """
account_analytic_tag_account_move_line_rel atml
ON atml.account_move_line_id = ml.id
INNER JOIN INNER JOIN
account_analytic_account aa
account_analytic_tag aat
ON ON
ml.analytic_account_id = aa.id
atml.account_analytic_tag_id = aat.id
WHERE
aat.id IN %(analytic_tag_ids)s
)
"""
query_select_previous_fy_unaffected_earnings += q_analytic_tags
query_select_previous_fy_unaffected_earnings += """
SELECT sum(ml.balance) as balance
FROM account_move_line as ml
INNER JOIN account_move as am
ON am.id = ml.move_id
INNER JOIN account_journal j
ON am.journal_id = j.id
"""
if self.filter_cost_center_ids:
query_select_previous_fy_unaffected_earnings += """
INNER JOIN account_analytic_account aa
ON aml.analytic_account_id = aa.id
AND aa.id IN %(cost_center_ids)s AND aa.id IN %(cost_center_ids)s
""" """
query_select_previous_fy_unaffected_earnings_params[
'cost_center_ids'] = tuple(self.filter_cost_center_ids.ids)
if self.filter_analytic_tag_ids: if self.filter_analytic_tag_ids:
sub_subquery_sum_amounts += """
INNER JOIN
move_lines_on_tags ON ml.id = move_lines_on_tags.ml_id
query_select_previous_fy_unaffected_earnings += """
INNER JOIN move_lines_on_tags ON ml.id =
move_lines_on_tags.ml_id
""" """
sub_subquery_sum_amounts += """
WHERE
a.company_id = %(company_id)s
AND
a.id IN %(unaffected_earnings_account_ids)s
query_select_previous_fy_unaffected_earnings += """
WHERE ml.date < %(date_to)s
AND ml.company_id = %(company_id)s
AND ml.account_id IN %(account_ids)s
""" """
if self.filter_journal_ids: if self.filter_journal_ids:
sub_subquery_sum_amounts += """
AND
ml.journal_id in %(filter_journal_ids)s """
return sub_subquery_sum_amounts
def _get_unaffected_earnings_account_sub_subquery_sum_final(self):
""" Return subquery used to compute sum amounts on
unaffected earnings accounts """
sub_subquery_sum_amounts = """
SELECT
0.0 AS initial_balance,
SUM(ml.balance) AS final_balance
"""
sub_subquery_sum_amounts += """
FROM
account_account a
INNER JOIN
account_account_type at ON a.user_type_id = at.id
INNER JOIN
account_move_line ml
ON a.id = ml.account_id
AND ml.date <= %(date_to)s
query_select_previous_fy_unaffected_earnings += """
AND j.id IN %(journal_ids)s
""" """
query_select_previous_fy_unaffected_earnings_params[
'journal_ids'] = tuple(self.filter_journal_ids.ids)
if self.only_posted_moves: if self.only_posted_moves:
sub_subquery_sum_amounts += """
INNER JOIN
account_move m ON ml.move_id = m.id AND m.state = 'posted'
query_select_previous_fy_unaffected_earnings += """
AND am.state = 'posted'
"""
self.env.cr.execute(
query_select_previous_fy_unaffected_earnings,
query_select_previous_fy_unaffected_earnings_params)
res = self.env.cr.fetchone()
unaffected_earnings_initial_balance = res[0] or 0.0
# Now select the current period unaffected earnings,
# excluding the current period P&L.
query_select_period_unaffected_earnings_params = {
'date_from': self.date_from,
'date_to': self.date_to,
'company_id': self.company_id.id,
'unaffected_earnings_id': self.unaffected_earnings_account.id,
'analytic_tag_ids': tuple(self.filter_analytic_tag_ids.ids),
}
query_select_period_unaffected_earnings = ''
if self.filter_analytic_tag_ids:
query_select_period_unaffected_earnings += q_analytic_tags
query_select_period_unaffected_earnings += """
SELECT
sum(ml.debit) as sum_debit,
sum(ml.credit) as sum_credit,
sum(ml.balance) as balance
FROM account_move_line as ml
INNER JOIN account_move as am
ON am.id = ml.move_id
INNER JOIN account_journal j
ON am.journal_id = j.id
""" """
if self.filter_cost_center_ids: if self.filter_cost_center_ids:
sub_subquery_sum_amounts += """
INNER JOIN
account_analytic_account aa
ON
ml.analytic_account_id = aa.id
query_select_period_unaffected_earnings += """
INNER JOIN account_analytic_account aa
ON aml.analytic_account_id = aa.id
AND aa.id IN %(cost_center_ids)s AND aa.id IN %(cost_center_ids)s
""" """
query_select_period_unaffected_earnings_params[
'cost_center_ids'] = tuple(self.filter_cost_center_ids.ids)
if self.filter_analytic_tag_ids: if self.filter_analytic_tag_ids:
sub_subquery_sum_amounts += """
INNER JOIN
move_lines_on_tags ON ml.id = move_lines_on_tags.ml_id
query_select_period_unaffected_earnings += """
INNER JOIN move_lines_on_tags
ON ml.id = move_lines_on_tags.ml_id
""" """
sub_subquery_sum_amounts += """
WHERE
a.company_id = %(company_id)s
AND
a.id IN %(unaffected_earnings_account_ids)s
query_select_period_unaffected_earnings += """
WHERE am.date >= %(date_from)s
AND ml.date <= %(date_to)s
AND ml.company_id = %(company_id)s
AND ml.account_id = %(unaffected_earnings_id)s
""" """
if self.filter_journal_ids: if self.filter_journal_ids:
sub_subquery_sum_amounts += """
AND
ml.journal_id in %(filter_journal_ids)s
"""
return sub_subquery_sum_amounts
def _inject_unaffected_earnings_account_values(self):
"""Inject the report values of the unaffected earnings account
for report_general_ledger_qweb_account."""
subquery_sum_amounts = """
SELECT
SUM(COALESCE(sub.initial_balance, 0.0)) AS initial_balance,
SUM(COALESCE(sub.final_balance, 0.0)) AS final_balance
FROM
(
"""
# Initial balances
subquery_sum_amounts += \
self._get_unaffected_earnings_account_sub_subquery_sum_initial()
subquery_sum_amounts += """
UNION
"""
subquery_sum_amounts += \
self._get_unaffected_earnings_account_sub_subquery_sum_final()
subquery_sum_amounts += """
) sub
query_select_period_unaffected_earnings += """
AND j.id IN %(journal_ids)s
""" """
query_select_period_unaffected_earnings_params[
'journal_ids'] = tuple(self.filter_journal_ids.ids)
if self.only_posted_moves:
query_select_period_unaffected_earnings += """
AND am.state = 'posted'
"""
self.env.cr.execute(query_select_period_unaffected_earnings,
query_select_period_unaffected_earnings_params)
res = self.env.cr.fetchone()
unaffected_earnings_period_debit = res[0] or 0.0
unaffected_earnings_period_credit = res[1] or 0.0
unaffected_earnings_period_balance = res[2] or 0.0
# pylint: disable=sql-injection # pylint: disable=sql-injection
query_inject_account = """ query_inject_account = """
WITH
"""
if self.filter_analytic_tag_ids:
query_inject_account += """
move_lines_on_tags AS
(
SELECT
DISTINCT ml.id AS ml_id
FROM
account_account a
INNER JOIN
account_move_line ml
ON a.id = ml.account_id
INNER JOIN
account_analytic_tag_account_move_line_rel atml
ON atml.account_move_line_id = ml.id
INNER JOIN
account_analytic_tag aat
ON
atml.account_analytic_tag_id = aat.id
WHERE
aat.id IN %(analytic_tag_ids)s
),
"""
query_inject_account += """
sum_amounts AS ( """ + subquery_sum_amounts + """ )
INSERT INTO INSERT INTO
report_general_ledger_qweb_account
(
report_general_ledger_qweb_account (
report_id, report_id,
create_uid, create_uid,
create_date, create_date,
@ -1718,65 +1720,47 @@ WHERE
code, code,
name, name,
is_partner_account, is_partner_account,
initial_debit,
initial_credit,
initial_balance, initial_balance,
final_balance,
currency_id
)
SELECT
%(report_id)s AS report_id,
%(user_id)s AS create_uid,
NOW() AS create_date,
a.id AS account_id,
a.code,
a.name,
False AS is_partner_account,
COALESCE(i.initial_balance, 0.0) AS initial_balance,
COALESCE(i.final_balance, 0.0) AS final_balance,
c.id as currency_id
FROM
account_account a
LEFT JOIN
res_currency c ON c.id = a.currency_id,
sum_amounts i
WHERE
a.company_id = %(company_id)s
AND a.id = %(unaffected_earnings_account_id)s
"""
query_inject_account_params = {}
if self.filter_analytic_tag_ids:
query_inject_account_params['analytic_tag_ids'] = \
tuple(self.filter_analytic_tag_ids.ids)
query_inject_account_params.update({
'date_from': self.date_from,
'date_to': self.date_to,
'fy_start_date': self.fy_start_date,
})
if self.filter_cost_center_ids:
query_inject_account_params['cost_center_ids'] = \
tuple(self.filter_cost_center_ids.ids)
query_inject_account_params['company_id'] = self.company_id.id
query_inject_account_params['unaffected_earnings_account_id'] = \
self.unaffected_earnings_account.id
query_inject_account_params['report_id'] = self.id
query_inject_account_params['user_id'] = self.env.uid
if self.filter_journal_ids:
query_inject_account_params['filter_journal_ids'] = (tuple(
self.filter_journal_ids.ids,
),)
# Fetch the profit and loss accounts
query_unaffected_earnings_account_ids = """
SELECT a.id
FROM account_account as a
INNER JOIN account_account_type as at
ON at.id = a.user_type_id
WHERE at.include_initial_balance = FALSE
"""
self.env.cr.execute(query_unaffected_earnings_account_ids)
pl_account_ids = [r[0] for r in self.env.cr.fetchall()]
query_inject_account_params['unaffected_earnings_account_ids'] = \
tuple(pl_account_ids + [self.unaffected_earnings_account.id])
final_debit,
final_credit,
final_balance
)
VALUES (
%(report_id)s,
%(user_id)s,
NOW(),
%(account_id)s,
%(code)s,
%(name)s,
False,
%(initial_debit)s,
%(initial_credit)s,
%(initial_balance)s,
%(final_debit)s,
%(final_credit)s,
%(final_balance)s
)
"""
initial_debit = unaffected_earnings_initial_balance >= 0 and \
unaffected_earnings_initial_balance or 0
initial_credit = unaffected_earnings_initial_balance < 0 and \
-1 * unaffected_earnings_initial_balance or 0
final_balance = unaffected_earnings_initial_balance + \
unaffected_earnings_period_balance
query_inject_account_params = {
'report_id': self.id,
'user_id': self.env.uid,
'account_id': self.unaffected_earnings_account.id,
'code': self.unaffected_earnings_account.code,
'name': self.unaffected_earnings_account.name,
'initial_debit': initial_debit,
'initial_credit': initial_credit,
'initial_balance': unaffected_earnings_initial_balance,
'final_debit': initial_debit + unaffected_earnings_period_debit,
'final_credit': initial_credit + unaffected_earnings_period_credit,
'final_balance': final_balance,
}
self.env.cr.execute(query_inject_account, self.env.cr.execute(query_inject_account,
query_inject_account_params) query_inject_account_params)

2
account_financial_report_qweb/report/general_ledger_xlsx.py

@ -89,7 +89,7 @@ class GeneralLedgerXslx(abstract_report_xlsx.AbstractReportXslx):
], ],
[ [
_('Account balance at 0 filter'), _('Account balance at 0 filter'),
_('Hide') if report.hide_account_balance_at_0 else _('Show'),
_('Hide') if report.hide_account_at_0 else _('Show'),
], ],
[ [
_('Centralize filter'), _('Centralize filter'),

4
account_financial_report_qweb/report/open_items.py

@ -22,7 +22,7 @@ class OpenItemsReport(models.TransientModel):
# Filters fields, used for data computation # Filters fields, used for data computation
date_at = fields.Date() date_at = fields.Date()
only_posted_moves = fields.Boolean() only_posted_moves = fields.Boolean()
hide_account_balance_at_0 = fields.Boolean()
hide_account_at_0 = fields.Boolean()
foreign_currency = fields.Boolean() foreign_currency = fields.Boolean()
company_id = fields.Many2one(comodel_name='res.company') company_id = fields.Many2one(comodel_name='res.company')
filter_account_ids = fields.Many2many(comodel_name='account.account') filter_account_ids = fields.Many2many(comodel_name='account.account')
@ -188,7 +188,7 @@ class OpenItemsReportCompute(models.TransientModel):
self._inject_line_values(only_empty_partner_line=True) self._inject_line_values(only_empty_partner_line=True)
self._clean_partners_and_accounts() self._clean_partners_and_accounts()
self._compute_partners_and_accounts_cumul() self._compute_partners_and_accounts_cumul()
if self.hide_account_balance_at_0:
if self.hide_account_at_0:
self._clean_partners_and_accounts( self._clean_partners_and_accounts(
only_delete_account_balance_at_0=True only_delete_account_balance_at_0=True
) )

2
account_financial_report_qweb/report/open_items_xlsx.py

@ -63,7 +63,7 @@ class OpenItemsXslx(abstract_report_xlsx.AbstractReportXslx):
_('All posted entries') if report.only_posted_moves else _( _('All posted entries') if report.only_posted_moves else _(
'All entries')], 'All entries')],
[_('Account balance at 0 filter'), [_('Account balance at 0 filter'),
_('Hide') if report.hide_account_balance_at_0 else _('Show')],
_('Hide') if report.hide_account_at_0 else _('Show')],
[_('Show foreign currency'), [_('Show foreign currency'),
_('Yes') if report.foreign_currency else _('No')], _('Yes') if report.foreign_currency else _('No')],
] ]

4
account_financial_report_qweb/report/templates/general_ledger.xml

@ -93,8 +93,8 @@
<t t-if="not o.only_posted_moves">All entries</t> <t t-if="not o.only_posted_moves">All entries</t>
</div> </div>
<div class="act_as_cell"> <div class="act_as_cell">
<t t-if="o.hide_account_balance_at_0">Hide</t>
<t t-if="not o.hide_account_balance_at_0">Show</t>
<t t-if="o.hide_account_at_0">Hide</t>
<t t-if="not o.hide_account_at_0">Show</t>
</div> </div>
<div class="act_as_cell"> <div class="act_as_cell">
<t t-if="o.centralize">Yes</t> <t t-if="o.centralize">Yes</t>

4
account_financial_report_qweb/report/templates/open_items.xml

@ -75,8 +75,8 @@
<t t-if="not o.only_posted_moves">All entries</t> <t t-if="not o.only_posted_moves">All entries</t>
</div> </div>
<div class="act_as_cell"> <div class="act_as_cell">
<t t-if="o.hide_account_balance_at_0">Hide</t>
<t t-if="not o.hide_account_balance_at_0">Show</t>
<t t-if="o.hide_account_at_0">Hide</t>
<t t-if="not o.hide_account_at_0">Show</t>
</div> </div>
</div> </div>
</div> </div>

188
account_financial_report_qweb/report/templates/trial_balance.xml

@ -27,20 +27,29 @@
<!-- Display account lines --> <!-- Display account lines -->
<t t-if="not show_partner_details"> <t t-if="not show_partner_details">
<div class="act_as_table data_table" style="width: 1325px !important;">
<div class="act_as_table data_table" style="width: 100%;">
<!-- Display account header --> <!-- Display account header -->
<t t-call="account_financial_report_qweb.report_trial_balance_qweb_lines_header"/> <t t-call="account_financial_report_qweb.report_trial_balance_qweb_lines_header"/>
<!-- Display each lines --> <!-- Display each lines -->
<t t-foreach="o.account_ids" t-as="line">
<t t-foreach="o.account_ids.filtered(lambda a: not a.hide_line)" t-as="line">
<t t-set="type" t-value='"account_type"'/> <t t-set="type" t-value='"account_type"'/>
<!-- Adapt --> <!-- Adapt -->
<t t-set="style" t-value="'font-size:8px;'"/> <t t-set="style" t-value="'font-size:8px;'"/>
<t t-set="padding" t-value="line.level * 4"/> <t t-set="padding" t-value="line.level * 4"/>
<t t-if="o.hide_account_at_0">
<t t-set="style" t-value="'font-size: 14px;'"/>
</t>
<t t-if="o.hierarchy_on != 'none'">
<t t-set="style" t-value="'font-size: ' + str(14 - line.level) + 'px; margin-left: ' + str(line.level * 4) + 'px;'"/> <t t-set="style" t-value="'font-size: ' + str(14 - line.level) + 'px; margin-left: ' + str(line.level * 4) + 'px;'"/>
</t>
<t t-if="line.account_group_id">
<t t-set="style" t-value="style + 'font-weight: bold; color: blue;'"/>
</t>
<!-- Display account lines --> <!-- Display account lines -->
<t t-call="account_financial_report_qweb.report_trial_balance_qweb_line"/> <t t-call="account_financial_report_qweb.report_trial_balance_qweb_line"/>
<!-- Adapt style -->
</t> </t>
</div> </div>
</t> </t>
@ -94,13 +103,13 @@
</t> </t>
</div> </div>
</template> </template>
<template id="account_financial_report_qweb.report_trial_balance_qweb_filters"> <template id="account_financial_report_qweb.report_trial_balance_qweb_filters">
<div class="act_as_table data_table" style="width: 100%;"> <div class="act_as_table data_table" style="width: 100%;">
<div class="act_as_row labels"> <div class="act_as_row labels">
<div class="act_as_cell">Date range filter</div> <div class="act_as_cell">Date range filter</div>
<div class="act_as_cell">Target moves 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">Account at 0 filter</div>
<div class="act_as_cell">Limit hierarchy levels</div>
</div> </div>
<div class="act_as_row"> <div class="act_as_row">
<div class="act_as_cell"> <div class="act_as_cell">
@ -111,8 +120,16 @@
<t t-if="not o.only_posted_moves">All entries</t> <t t-if="not o.only_posted_moves">All entries</t>
</div> </div>
<div class="act_as_cell"> <div class="act_as_cell">
<t t-if="o.hide_account_balance_at_0">Hide</t>
<t t-if="not o.hide_account_balance_at_0">Show</t>
<t t-if="o.hide_account_at_0">Hide</t>
<t t-if="not o.hide_account_at_0">Show</t>
</div>
<div class="act_as_cell">
<t t-if="o.limit_hierarchy_level">
Level <span t-field="o.show_hierarchy_level"/>
</t>
<t t-if="not o.limit_hierarchy_level">
No limit
</t>
</div> </div>
</div> </div>
</div> </div>
@ -126,12 +143,12 @@
<!--## Code--> <!--## Code-->
<div class="act_as_cell" style="width: 8.86%;">Code</div> <div class="act_as_cell" style="width: 8.86%;">Code</div>
<!--## Account--> <!--## Account-->
<div class="act_as_cell" style="width: 52.58%;">Account
<div class="act_as_cell" style="width: 37.58%;">Account
</div> </div>
</t> </t>
<t t-if="show_partner_details"> <t t-if="show_partner_details">
<!--## Partner--> <!--## Partner-->
<div class="act_as_cell" style="width: 61.44%;">Partner
<div class="act_as_cell" style="width: 46.44%;">Partner
</div> </div>
</t> </t>
<!--## Initial balance--> <!--## Initial balance-->
@ -141,6 +158,8 @@
<div class="act_as_cell" style="width: 9.64%;">Debit</div> <div class="act_as_cell" style="width: 9.64%;">Debit</div>
<!--## Credit--> <!--## Credit-->
<div class="act_as_cell" style="width: 9.64%;">Credit</div> <div class="act_as_cell" style="width: 9.64%;">Credit</div>
<!--## Period balance-->
<div class="act_as_cell" style="width: 9.64%;">Period balance</div>
<!--## Ending balance--> <!--## Ending balance-->
<div class="act_as_cell" style="width: 9.64%;">Ending balance</div> <div class="act_as_cell" style="width: 9.64%;">Ending balance</div>
<t t-if="foreign_currency"> <t t-if="foreign_currency">
@ -170,6 +189,16 @@
<t t-att-style="style" t-raw="line.code"/></a> <t t-att-style="style" t-raw="line.code"/></a>
</span> </span>
</t> </t>
<t t-if="line.account_group_id">
<t t-set="res_model" t-value="'account.group'"/>
<span>
<a t-att-data-active-id="line.account_group_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-raw="line.code"/></a>
</span>
</t>
</div> </div>
</t> </t>
<!--## Account/Partner--> <!--## Account/Partner-->
@ -186,6 +215,16 @@
<t t-att-style="style" t-raw="line.name"/></a> <t t-att-style="style" t-raw="line.name"/></a>
</span> </span>
</t> </t>
<t t-if="line.account_group_id">
<t t-set="res_model" t-value="'account.group'"/>
<span>
<a t-att-data-active-id="line.account_group_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-raw="line.name"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="account_or_partner_line" t-value="line.report_account_id"/> <t t-set="account_or_partner_line" t-value="line.report_account_id"/>
@ -214,6 +253,18 @@
<t t-att-style="style" t-raw="line.initial_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> <t t-att-style="style" t-raw="line.initial_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span> </span>
</t> </t>
<t t-if="line.account_group_id">
<t t-set="domain"
t-value="[('account_id', 'in', line.compute_account_ids.ids),
('date', '&lt;', o.date_from)]"/>
<span>
<a t-att-data-domain="domain"
t-att-data-res-model="'account.move.line'"
class="o_account_financial_reports_web_action_multi"
t-att-style="style">
<t t-att-style="style" t-raw="line.initial_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -246,6 +297,20 @@
<t t-att-style="style" t-raw="line.debit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> <t t-att-style="style" t-raw="line.debit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span> </span>
</t> </t>
<t t-if="line.account_group_id">
<t t-set="domain"
t-value="[('account_id', 'in', line.compute_account_ids.ids),
('date', '&gt;=', line.report_id.date_from),
('date', '&lt;=', line.report_id.date_to),
('debit', '&lt;&gt;', 0)]"/>
<span>
<a t-att-data-domain="domain"
t-att-data-res-model="'account.move.line'"
class="o_account_financial_reports_web_action_multi"
t-att-style="style">
<t t-att-style="style" t-raw="line.debit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -280,6 +345,20 @@
<t t-att-style="style" t-raw="line.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> <t t-att-style="style" t-raw="line.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span> </span>
</t> </t>
<t t-if="line.account_group_id">
<t t-set="domain"
t-value="[('account_id', 'in', line.compute_account_ids.ids),
('date', '&gt;=', line.report_id.date_from),
('date', '&lt;=', line.report_id.date_to),
('credit', '&lt;&gt;', 0)]"/>
<span>
<a t-att-data-domain="domain"
t-att-data-res-model="'account.move.line'"
class="o_account_financial_reports_web_action_multi"
t-att-style="style">
<t t-att-style="style" t-raw="line.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -297,6 +376,51 @@
</span> </span>
</t> </t>
</div> </div>
<!--## Period balance-->
<div class="act_as_cell amount">
<t t-if="type == 'account_type'">
<t t-if="line.account_id">
<t t-set="domain"
t-value="[('account_id', '=', line.account_id.id),
('date', '&gt;=', line.report_id.date_from),
('date', '&lt;=', line.report_id.date_to)]"/>
<span>
<a t-att-data-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-raw="line.period_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
<t t-if="line.account_group_id">
<t t-set="domain"
t-value="[('account_id', 'in', line.compute_account_ids.ids),
('date', '&gt;=', line.report_id.date_from),
('date', '&lt;=', line.report_id.date_to)]"/>
<span>
<a t-att-data-domain="domain"
t-att-data-res-model="'account.move.line'"
class="o_account_financial_reports_web_action_multi"
t-att-style="style">
<t t-att-style="style" t-raw="line.period_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</t>
<t t-if="type == 'partner_type'">
<t t-set="domain"
t-value="[('account_id', '=', line.report_account_id.account_id.id),
('partner_id', '=', line.partner_id.id),
('date', '&gt;=', line.report_account_id.report_id.date_from),
('date', '&lt;=', line.report_account_id.report_id.date_to)]"/>
<span>
<a t-att-data-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-raw="line.period_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</div>
<!--## Ending balance--> <!--## Ending balance-->
<div class="act_as_cell amount"> <div class="act_as_cell amount">
<t t-if="type == 'account_type'"> <t t-if="type == 'account_type'">
@ -311,6 +435,17 @@
<t t-att-style="style" t-raw="line.final_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> <t t-att-style="style" t-raw="line.final_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span> </span>
</t> </t>
<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-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-raw="line.final_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -345,6 +480,17 @@
<t t-att-style="style" t-raw="line.initial_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a> <t t-att-style="style" t-raw="line.initial_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>
</span> </span>
</t> </t>
<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-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-raw="line.initial_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -373,6 +519,17 @@
<t t-att-style="style" t-raw="line.final_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a> <t t-att-style="style" t-raw="line.final_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>
</span> </span>
</t> </t>
<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-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-raw="line.final_balance_foreign_currency" t-options="{'widget': 'monetary', 'display_currency': line.currency_id}"/></a>
</span>
</t>
</t> </t>
<t t-if="type == 'partner_type'"> <t t-if="type == 'partner_type'">
<t t-set="domain" <t t-set="domain"
@ -456,6 +613,21 @@
<t t-att-style="style" t-raw="account.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> <t t-att-style="style" t-raw="account.credit" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span> </span>
</div> </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', '&gt;=', account.report_id.date_from),
('date', '&lt;=', account.report_id.date_to),
('period_balance', '&lt;&gt;', 0)]"/>
<span>
<a t-att-data-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-raw="account.period_balance" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a>
</span>
</div>
<!--## Ending balance--> <!--## Ending balance-->
<div class="act_as_cell amount" style="width: 9.64%;"> <div class="act_as_cell amount" style="width: 9.64%;">
<t t-set="domain" <t t-set="domain"

290
account_financial_report_qweb/report/trial_balance.py

@ -24,14 +24,29 @@ class TrialBalanceReport(models.TransientModel):
date_to = fields.Date() date_to = fields.Date()
fy_start_date = fields.Date() fy_start_date = fields.Date()
only_posted_moves = fields.Boolean() only_posted_moves = fields.Boolean()
hide_account_balance_at_0 = fields.Boolean()
hide_account_at_0 = fields.Boolean()
foreign_currency = fields.Boolean() foreign_currency = fields.Boolean()
company_id = fields.Many2one(comodel_name='res.company') company_id = fields.Many2one(comodel_name='res.company')
filter_account_ids = fields.Many2many(comodel_name='account.account') filter_account_ids = fields.Many2many(comodel_name='account.account')
filter_partner_ids = fields.Many2many(comodel_name='res.partner') filter_partner_ids = fields.Many2many(comodel_name='res.partner')
filter_journal_ids = fields.Many2many(comodel_name='account.journal') filter_journal_ids = fields.Many2many(comodel_name='account.journal')
show_partner_details = fields.Boolean() show_partner_details = fields.Boolean()
hierarchy_on = fields.Selection(
[('computed', 'Computed Accounts'),
('relation', 'Child Accounts'),
('none', 'No hierarchy')],
string='Hierarchy On',
required=True,
default='computed',
help="""Computed Accounts: Use when the account group have codes
that represent prefixes of the actual accounts.\n
Child Accounts: Use when your account groups are hierarchical.\n
No hierarchy: Use to display just the accounts, without any grouping.
""", period_balance=fields.Float(digits=(16, 2))
)
limit_hierarchy_level = fields.Boolean('Limit hierarchy levels')
show_hierarchy_level = fields.Integer('Hierarchy Levels to display',
default=1)
# General Ledger Report Data fields, # General Ledger Report Data fields,
# used as base for compute the data reports # used as base for compute the data reports
general_ledger_id = fields.Many2one( general_ledger_id = fields.Many2one(
@ -49,17 +64,17 @@ class TrialBalanceReportAccount(models.TransientModel):
_name = 'report_trial_balance_qweb_account' _name = 'report_trial_balance_qweb_account'
_inherit = 'report_qweb_abstract' _inherit = 'report_qweb_abstract'
_order = 'code ASC'
_order = 'sequence, code ASC, name'
report_id = fields.Many2one( report_id = fields.Many2one(
comodel_name='report_trial_balance_qweb', comodel_name='report_trial_balance_qweb',
ondelete='cascade', ondelete='cascade',
index=True index=True
) )
hide_line = fields.Boolean(compute='_compute_hide_line')
# Data fields, used to keep link with real object # Data fields, used to keep link with real object
sequence = fields.Integer(index=True, default=0)
level = fields.Integer(index=True, default=0)
sequence = fields.Integer(index=True, default=1)
level = fields.Integer(index=True, default=1)
# Data fields, used to keep link with real object # Data fields, used to keep link with real object
account_id = fields.Many2one( account_id = fields.Many2one(
@ -67,6 +82,20 @@ class TrialBalanceReportAccount(models.TransientModel):
index=True index=True
) )
account_group_id = fields.Many2one(
'account.group',
index=True
)
parent_id = fields.Many2one(
'account.group',
index=True
)
child_account_ids = fields.Char(
string="Accounts")
compute_account_ids = fields.Many2many(
'account.account',
string="Accounts", store=True)
# Data fields, used for report display # Data fields, used for report display
code = fields.Char() code = fields.Char()
name = fields.Char() name = fields.Char()
@ -75,6 +104,7 @@ class TrialBalanceReportAccount(models.TransientModel):
initial_balance_foreign_currency = fields.Float(digits=(16, 2)) initial_balance_foreign_currency = fields.Float(digits=(16, 2))
debit = fields.Float(digits=(16, 2)) debit = fields.Float(digits=(16, 2))
credit = fields.Float(digits=(16, 2)) credit = fields.Float(digits=(16, 2))
period_balance = fields.Float(digits=(16, 2))
currency_id = fields.Many2one(comodel_name='res.currency') currency_id = fields.Many2one(comodel_name='res.currency')
final_balance = fields.Float(digits=(16, 2)) final_balance = fields.Float(digits=(16, 2))
final_balance_foreign_currency = fields.Float(digits=(16, 2)) final_balance_foreign_currency = fields.Float(digits=(16, 2))
@ -85,6 +115,21 @@ class TrialBalanceReportAccount(models.TransientModel):
inverse_name='report_account_id' inverse_name='report_account_id'
) )
@api.multi
def _compute_hide_line(self):
for rec in self:
report = rec.report_id
rec.hide_line = False
if report.hide_account_at_0 and (
not rec.initial_balance and
not rec.final_balance and
not rec.debit and
not rec.credit):
rec.hide_line = True
elif report.limit_hierarchy_level and \
rec.level > report.show_hierarchy_level:
rec.hide_line = True
class TrialBalanceReportPartner(models.TransientModel): class TrialBalanceReportPartner(models.TransientModel):
@ -110,6 +155,7 @@ class TrialBalanceReportPartner(models.TransientModel):
initial_balance_foreign_currency = fields.Float(digits=(16, 2)) initial_balance_foreign_currency = fields.Float(digits=(16, 2))
debit = fields.Float(digits=(16, 2)) debit = fields.Float(digits=(16, 2))
credit = fields.Float(digits=(16, 2)) credit = fields.Float(digits=(16, 2))
period_balance = fields.Float(digits=(16, 2))
currency_id = fields.Many2one(comodel_name='res.currency') currency_id = fields.Many2one(comodel_name='res.currency')
final_balance = fields.Float(digits=(16, 2)) final_balance = fields.Float(digits=(16, 2))
final_balance_foreign_currency = fields.Float(digits=(16, 2)) final_balance_foreign_currency = fields.Float(digits=(16, 2))
@ -169,7 +215,7 @@ class TrialBalanceReportCompute(models.TransientModel):
'date_from': self.date_from, 'date_from': self.date_from,
'date_to': self.date_to, 'date_to': self.date_to,
'only_posted_moves': self.only_posted_moves, 'only_posted_moves': self.only_posted_moves,
'hide_account_balance_at_0': self.hide_account_balance_at_0,
'hide_account_at_0': self.hide_account_at_0,
'foreign_currency': self.foreign_currency, 'foreign_currency': self.foreign_currency,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'filter_account_ids': [(6, 0, account_ids.ids)], 'filter_account_ids': [(6, 0, account_ids.ids)],
@ -201,8 +247,21 @@ class TrialBalanceReportCompute(models.TransientModel):
self._inject_account_values(account_ids) self._inject_account_values(account_ids)
if self.show_partner_details: if self.show_partner_details:
self._inject_partner_values() self._inject_partner_values()
# Refresh cache because all data are computed with SQL requests
self.invalidate_cache()
if not self.filter_account_ids:
if self.hierarchy_on != 'none':
self._inject_account_group_values()
if self.hierarchy_on == 'computed':
self._update_account_group_computed_values()
else:
self._update_account_group_child_values()
self._update_account_sequence()
self._add_account_group_account_values()
self.refresh()
if not self.filter_account_ids and self.hierarchy_on != 'none':
self._compute_group_accounts()
else:
for line in self.account_ids:
line.write({'level': 0})
def _inject_account_values(self, account_ids): def _inject_account_values(self, account_ids):
"""Inject report values for report_trial_balance_qweb_account""" """Inject report values for report_trial_balance_qweb_account"""
@ -214,11 +273,13 @@ INSERT INTO
create_uid, create_uid,
create_date, create_date,
account_id, account_id,
parent_id,
code, code,
name, name,
initial_balance, initial_balance,
debit, debit,
credit, credit,
period_balance,
final_balance, final_balance,
currency_id, currency_id,
initial_balance_foreign_currency, initial_balance_foreign_currency,
@ -229,11 +290,13 @@ SELECT
%s AS create_uid, %s AS create_uid,
NOW() AS create_date, NOW() AS create_date,
acc.id, acc.id,
acc.group_id,
acc.code, acc.code,
acc.name, acc.name,
coalesce(rag.initial_balance, 0) AS initial_balance, coalesce(rag.initial_balance, 0) AS initial_balance,
coalesce(rag.final_debit - rag.initial_debit, 0) AS debit, coalesce(rag.final_debit - rag.initial_debit, 0) AS debit,
coalesce(rag.final_credit - rag.initial_credit, 0) AS credit, coalesce(rag.final_credit - rag.initial_credit, 0) AS credit,
coalesce(rag.final_balance - rag.initial_balance, 0) AS period_balance,
coalesce(rag.final_balance, 0) AS final_balance, coalesce(rag.final_balance, 0) AS final_balance,
rag.currency_id AS currency_id, rag.currency_id AS currency_id,
coalesce(rag.initial_balance_foreign_currency, 0) coalesce(rag.initial_balance_foreign_currency, 0)
@ -247,9 +310,6 @@ FROM
WHERE WHERE
acc.id in %s acc.id in %s
""" """
if self.hide_account_balance_at_0:
query_inject_account += """ AND
final_balance IS NOT NULL AND final_balance != 0"""
query_inject_account_params = ( query_inject_account_params = (
self.id, self.id,
self.env.uid, self.env.uid,
@ -273,6 +333,7 @@ INSERT INTO
initial_balance_foreign_currency, initial_balance_foreign_currency,
debit, debit,
credit, credit,
period_balance,
final_balance, final_balance,
final_balance_foreign_currency final_balance_foreign_currency
) )
@ -286,6 +347,7 @@ SELECT
rpg.initial_balance_foreign_currency AS initial_balance_foreign_currency, rpg.initial_balance_foreign_currency AS initial_balance_foreign_currency,
rpg.final_debit - rpg.initial_debit AS debit, rpg.final_debit - rpg.initial_debit AS debit,
rpg.final_credit - rpg.initial_credit AS credit, rpg.final_credit - rpg.initial_credit AS credit,
rpg.final_balance - rpg.initial_balance AS period_balance,
rpg.final_balance AS final_balance, rpg.final_balance AS final_balance,
rpg.final_balance_foreign_currency AS final_balance_foreign_currency rpg.final_balance_foreign_currency AS final_balance_foreign_currency
FROM FROM
@ -304,3 +366,207 @@ AND ra.report_id = %s
self.id, self.id,
) )
self.env.cr.execute(query_inject_partner, query_inject_partner_params) self.env.cr.execute(query_inject_partner, query_inject_partner_params)
def _inject_account_group_values(self):
"""Inject report values for report_trial_balance_qweb_account"""
query_inject_account_group = """
INSERT INTO
report_trial_balance_qweb_account
(
report_id,
create_uid,
create_date,
account_group_id,
parent_id,
code,
name,
sequence,
level
)
SELECT
%s AS report_id,
%s AS create_uid,
NOW() AS create_date,
accgroup.id,
accgroup.parent_id,
coalesce(accgroup.code_prefix, accgroup.name),
accgroup.name,
accgroup.parent_left * 100000,
accgroup.level
FROM
account_group accgroup"""
query_inject_account_params = (
self.id,
self.env.uid,
)
self.env.cr.execute(query_inject_account_group,
query_inject_account_params)
def _update_account_group_child_values(self):
"""Compute values for report_trial_balance_qweb_account group
in child."""
query_update_account_group = """
WITH computed AS (WITH RECURSIVE cte AS (
SELECT account_group_id, code, account_group_id AS parent_id,
initial_balance, initial_balance_foreign_currency, debit, credit,
period_balance, final_balance, final_balance_foreign_currency
FROM report_trial_balance_qweb_account
WHERE report_id = %s
GROUP BY report_trial_balance_qweb_account.id
UNION ALL
SELECT c.account_group_id, c.code, p.account_group_id,
p.initial_balance, p.initial_balance_foreign_currency, p.debit, p.credit,
p.period_balance, p.final_balance, p.final_balance_foreign_currency
FROM cte c
JOIN report_trial_balance_qweb_account p USING (parent_id)
WHERE p.report_id = %s
)
SELECT account_group_id, code,
sum(initial_balance) AS initial_balance,
sum(initial_balance_foreign_currency) AS initial_balance_foreign_currency,
sum(debit) AS debit,
sum(credit) AS credit,
sum(debit) - sum(credit) AS period_balance,
sum(final_balance) AS final_balance,
sum(final_balance_foreign_currency) AS final_balance_foreign_currency
FROM cte
GROUP BY cte.account_group_id, cte.code
ORDER BY account_group_id
)
UPDATE report_trial_balance_qweb_account
SET initial_balance = computed.initial_balance,
initial_balance_foreign_currency =
computed.initial_balance_foreign_currency,
debit = computed.debit,
credit = computed.credit,
period_balance = computed.period_balance,
final_balance = computed.final_balance,
final_balance_foreign_currency =
computed.final_balance_foreign_currency
FROM computed
WHERE report_trial_balance_qweb_account.account_group_id =
computed.account_group_id
AND report_trial_balance_qweb_account.report_id = %s
"""
query_update_account_params = (self.id, self.id, self.id,)
self.env.cr.execute(query_update_account_group,
query_update_account_params)
def _add_account_group_account_values(self):
"""Compute values for report_trial_balance_qweb_account group in
child."""
query_update_account_group = """
DROP AGGREGATE IF EXISTS array_concat_agg(anyarray);
CREATE AGGREGATE array_concat_agg(anyarray) (
SFUNC = array_cat,
STYPE = anyarray
);
WITH aggr AS(WITH computed AS (WITH RECURSIVE cte AS (
SELECT account_group_id, account_group_id AS parent_id,
ARRAY[account_id]::int[] as child_account_ids
FROM report_trial_balance_qweb_account
WHERE report_id = %s
GROUP BY report_trial_balance_qweb_account.id
UNION ALL
SELECT c.account_group_id, p.account_group_id, ARRAY[p.account_id]::int[]
FROM cte c
JOIN report_trial_balance_qweb_account p USING (parent_id)
WHERE p.report_id = %s
)
SELECT account_group_id,
array_concat_agg(DISTINCT child_account_ids)::int[] as child_account_ids
FROM cte
GROUP BY cte.account_group_id, cte.child_account_ids
ORDER BY account_group_id
)
SELECT account_group_id,
array_concat_agg(DISTINCT child_account_ids)::int[]
AS child_account_ids from computed
GROUP BY account_group_id)
UPDATE report_trial_balance_qweb_account
SET child_account_ids = aggr.child_account_ids
FROM aggr
WHERE report_trial_balance_qweb_account.account_group_id =
aggr.account_group_id
AND report_trial_balance_qweb_account.report_id = %s
"""
query_update_account_params = (self.id, self.id, self.id,)
self.env.cr.execute(query_update_account_group,
query_update_account_params)
def _update_account_group_computed_values(self):
"""Compute values for report_trial_balance_qweb_account group
in compute."""
query_update_account_group = """
WITH RECURSIVE accgroup AS
(SELECT
accgroup.id,
sum(coalesce(ra.initial_balance, 0)) as initial_balance,
sum(coalesce(ra.initial_balance_foreign_currency, 0))
as initial_balance_foreign_currency,
sum(coalesce(ra.debit, 0)) as debit,
sum(coalesce(ra.credit, 0)) as credit,
sum(coalesce(ra.debit, 0)) - sum(coalesce(ra.credit, 0)) as period_balance,
sum(coalesce(ra.final_balance, 0)) as final_balance,
sum(coalesce(ra.final_balance_foreign_currency, 0))
as final_balance_foreign_currency
FROM
account_group accgroup
LEFT OUTER JOIN account_account AS acc
ON strpos(acc.code, accgroup.code_prefix) = 1
LEFT OUTER JOIN report_trial_balance_qweb_account AS ra
ON ra.account_id = acc.id
WHERE ra.report_id = %s
GROUP BY accgroup.id
)
UPDATE report_trial_balance_qweb_account
SET initial_balance = accgroup.initial_balance,
initial_balance_foreign_currency =
accgroup.initial_balance_foreign_currency,
debit = accgroup.debit,
credit = accgroup.credit,
period_balance = accgroup.period_balance,
final_balance = accgroup.final_balance,
final_balance_foreign_currency =
accgroup.final_balance_foreign_currency
FROM accgroup
WHERE report_trial_balance_qweb_account.account_group_id = accgroup.id
"""
query_update_account_params = (self.id,)
self.env.cr.execute(query_update_account_group,
query_update_account_params)
def _update_account_sequence(self):
"""Compute sequence, level for report_trial_balance_qweb_
account account."""
query_update_account_group = """
UPDATE report_trial_balance_qweb_account
SET sequence = newline.sequence + 1,
level = newline.level + 1
FROM report_trial_balance_qweb_account as newline
WHERE newline.account_group_id = report_trial_balance_qweb_account.parent_id
AND report_trial_balance_qweb_account.report_id = newline.report_id
AND report_trial_balance_qweb_account.account_id is not null
AND report_trial_balance_qweb_account.report_id = %s"""
query_update_account_params = (self.id,)
self.env.cr.execute(query_update_account_group,
query_update_account_params)
def _compute_group_accounts(self):
groups = self.account_ids.filtered(
lambda a: a.account_group_id is not False)
for group in groups:
if self.hierarchy_on == 'compute':
group.compute_account_ids = \
group.account_group_id.compute_account_ids
else:
if group.child_account_ids:
chacc = group.child_account_ids.replace(
'}', '').replace('{', '').split(',')
if 'NULL' in chacc:
chacc.remove('NULL')
if chacc:
group.compute_account_ids = [
(6, 0, [int(g) for g in chacc])]

33
account_financial_report_qweb/report/trial_balance_xlsx.py

@ -35,22 +35,26 @@ class TrialBalanceXslx(abstract_report_xlsx.AbstractReportXslx):
'field': 'credit', 'field': 'credit',
'type': 'amount', 'type': 'amount',
'width': 14}, 'width': 14},
5: {'header': _('Ending balance'),
5: {'header': _('Period balance'),
'field': 'period_balance',
'type': 'amount',
'width': 14},
6: {'header': _('Ending balance'),
'field': 'final_balance', 'field': 'final_balance',
'type': 'amount', 'type': 'amount',
'width': 14}, 'width': 14},
} }
if report.foreign_currency: if report.foreign_currency:
foreign_currency = { foreign_currency = {
6: {'header': _('Cur.'),
7: {'header': _('Cur.'),
'field': 'currency_id', 'field': 'currency_id',
'field_currency_balance': 'currency_id', 'field_currency_balance': 'currency_id',
'type': 'many2one', 'width': 7}, 'type': 'many2one', 'width': 7},
7: {'header': _('Initial balance'),
8: {'header': _('Initial balance'),
'field': 'initial_balance_foreign_currency', 'field': 'initial_balance_foreign_currency',
'type': 'amount_currency', 'type': 'amount_currency',
'width': 14}, 'width': 14},
8: {'header': _('Ending balance'),
9: {'header': _('Ending balance'),
'field': 'final_balance_foreign_currency', 'field': 'final_balance_foreign_currency',
'type': 'amount_currency', 'type': 'amount_currency',
'width': 14}, 'width': 14},
@ -72,22 +76,26 @@ class TrialBalanceXslx(abstract_report_xlsx.AbstractReportXslx):
'field': 'credit', 'field': 'credit',
'type': 'amount', 'type': 'amount',
'width': 14}, 'width': 14},
4: {'header': _('Ending balance'),
4: {'header': _('Period balance'),
'field': 'period_balance',
'type': 'amount',
'width': 14},
5: {'header': _('Ending balance'),
'field': 'final_balance', 'field': 'final_balance',
'type': 'amount', 'type': 'amount',
'width': 14}, 'width': 14},
} }
if report.foreign_currency: if report.foreign_currency:
foreign_currency = { foreign_currency = {
5: {'header': _('Cur.'),
6: {'header': _('Cur.'),
'field': 'currency_id', 'field': 'currency_id',
'field_currency_balance': 'currency_id', 'field_currency_balance': 'currency_id',
'type': 'many2one', 'width': 7}, 'type': 'many2one', 'width': 7},
6: {'header': _('Initial balance'),
7: {'header': _('Initial balance'),
'field': 'initial_balance_foreign_currency', 'field': 'initial_balance_foreign_currency',
'type': 'amount_currency', 'type': 'amount_currency',
'width': 14}, 'width': 14},
7: {'header': _('Ending balance'),
8: {'header': _('Ending balance'),
'field': 'final_balance_foreign_currency', 'field': 'final_balance_foreign_currency',
'type': 'amount_currency', 'type': 'amount_currency',
'width': 14}, 'width': 14},
@ -102,10 +110,13 @@ class TrialBalanceXslx(abstract_report_xlsx.AbstractReportXslx):
[_('Target moves filter'), [_('Target moves filter'),
_('All posted entries') if report.only_posted_moves _('All posted entries') if report.only_posted_moves
else _('All entries')], else _('All entries')],
[_('Account balance at 0 filter'),
_('Hide') if report.hide_account_balance_at_0 else _('Show')],
[_('Account at 0 filter'),
_('Hide') if report.hide_account_at_0 else _('Show')],
[_('Show foreign currency'), [_('Show foreign currency'),
_('Yes') if report.foreign_currency else _('No')], _('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): def _get_col_count_filter_name(self):
@ -121,7 +132,7 @@ class TrialBalanceXslx(abstract_report_xlsx.AbstractReportXslx):
self.write_array_header() self.write_array_header()
# For each account # For each account
for account in report.account_ids:
for account in report.account_ids.filtered(lambda a: not a.hide_line):
if not report.show_partner_details: if not report.show_partner_details:
# Display account lines # Display account lines
self.write_line(account, 'account') self.write_line(account, 'account')

447
account_financial_report_qweb/static/description/index.html

@ -0,0 +1,447 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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 0.12: http://docutils.sourceforge.net/" />
<title>QWeb Financial Reports</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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 }
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 {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.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;
}
.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 } */
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: grey; } /* 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 {
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="qweb-financial-reports">
<h1 class="title">QWeb Financial Reports</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" 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" href="https://github.com/OCA/account-financial-reporting/tree/10.0/account_financial_report_qweb"><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" href="https://translation.odoo-community.org/projects/account-financial-reporting-10-0/account-financial-reporting-10-0-account_financial_report_qweb"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/91/10.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module adds a set of financial reports. They are accessible under
Accounting / Reporting / OCA 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><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#changelog" id="id2">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id3">10.0.2.0.0 (2018-11-29)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id2">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id3">10.0.2.0.0 (2018-11-29)</a></h2>
<ul class="simple">
<li>The Trial Balance now allows to display the hierarchy of accounts</li>
<li>In the Trial Balance you can apply a filter by hierarchy levels</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="#id4">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 smashing 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_qweb%0Aversion:%2010.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="#id5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
<ul class="simple">
<li>Camptocamp SA</li>
<li>initOS GmbH</li>
<li>redCOR AG</li>
<li>ACSONE SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<ul class="simple">
<li>Jordi Ballester &lt;<a class="reference external" href="mailto:jordi.ballester&#64;eficient.com">jordi.ballester&#64;eficient.com</a>&gt;</li>
<li>Yannick Vaucher &lt;<a class="reference external" href="mailto:yannick.vaucher&#64;camptocamp.com">yannick.vaucher&#64;camptocamp.com</a>&gt;</li>
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;abstract.com">simone.orsi&#64;abstract.com</a>&gt;</li>
<li>Leonardo Pistone &lt;<a class="reference external" href="mailto:leonardo.pistone&#64;camptocamp.com">leonardo.pistone&#64;camptocamp.com</a>&gt;</li>
<li>Damien Crier &lt;<a class="reference external" href="mailto:damien.crier&#64;camptocamp.com">damien.crier&#64;camptocamp.com</a>&gt;</li>
<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</a>&gt;</li>
<li>Thomas Rehn &lt;<a class="reference external" href="mailto:thomas.rehn&#64;initos.com">thomas.rehn&#64;initos.com</a>&gt;</li>
<li>Andrea Gallina &lt;<a class="reference external" href="mailto:4everamd&#64;gmail.com">4everamd&#64;gmail.com</a>&gt;</li>
<li>Robert Rottermann &lt;<a class="reference external" href="mailto:robert&#64;redcor.ch">robert&#64;redcor.ch</a>&gt;</li>
<li>Ciro Urselli &lt;<a class="reference external" href="mailto:c.urselli&#64;apuliasoftware.it">c.urselli&#64;apuliasoftware.it</a>&gt;</li>
<li>Francesco Apruzzese &lt;<a class="reference external" href="mailto:opencode&#64;e-ware.org">opencode&#64;e-ware.org</a>&gt;</li>
<li>Lorenzo Battistini &lt;<a class="reference external" href="mailto:lorenzo.battistini&#64;agilebg.com">lorenzo.battistini&#64;agilebg.com</a>&gt;</li>
<li>Julien Coux &lt;<a class="reference external" href="mailto:julien.coux&#64;camptocamp.com">julien.coux&#64;camptocamp.com</a>&gt;</li>
<li>Akim Juillerat &lt;<a class="reference external" href="mailto:akim.juillerat&#64;camptocamp.com">akim.juillerat&#64;camptocamp.com</a>&gt;</li>
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis&#64;via.ecp.fr">alexis&#64;via.ecp.fr</a>&gt;</li>
<li>Mihai Fekete &lt;<a class="reference external" href="mailto:feketemihai&#64;gmail.com">feketemihai&#64;gmail.com</a>&gt;</li>
<li>Benjamin Willig &lt;<a class="reference external" href="mailto:benjamin.willig&#64;acsone.eu">benjamin.willig&#64;acsone.eu</a>&gt;</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="maintainers">
<h2><a class="toc-backref" href="#id8">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/10.0/account_financial_report_qweb">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>

40
account_financial_report_qweb/tests/test_general_ledger.py

@ -42,14 +42,14 @@ class TestGeneralLedger(a_t_f_c.AbstractTestForeignCurrency):
def _getAdditionalFiltersToBeTested(self): def _getAdditionalFiltersToBeTested(self):
additional_filters = [ additional_filters = [
{'only_posted_moves': True}, {'only_posted_moves': True},
{'hide_account_balance_at_0': True},
{'hide_account_at_0': True},
{'centralize': True}, {'centralize': True},
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
{'only_posted_moves': True, 'hide_account_at_0': True},
{'only_posted_moves': True, 'centralize': True}, {'only_posted_moves': True, 'centralize': True},
{'hide_account_balance_at_0': True, 'centralize': True},
{'hide_account_at_0': True, 'centralize': True},
{ {
'only_posted_moves': True, 'only_posted_moves': True,
'hide_account_balance_at_0': True,
'hide_account_at_0': True,
'centralize': True 'centralize': True
}, },
] ]
@ -155,7 +155,7 @@ class TestGeneralLedgerReport(common.TransactionCase):
'date_from': self.fy_date_start, 'date_from': self.fy_date_start,
'date_to': self.fy_date_end, 'date_to': self.fy_date_end,
'only_posted_moves': True, 'only_posted_moves': True,
'hide_account_balance_at_0': False,
'hide_account_at_0': False,
'company_id': company.id, 'company_id': company.id,
'fy_start_date': self.fy_date_start, 'fy_start_date': self.fy_date_start,
}) })
@ -377,10 +377,10 @@ class TestGeneralLedgerReport(common.TransactionCase):
# Check the initial and final balance # Check the initial and final balance
self.assertEqual(lines['unaffected'].initial_debit, 0) self.assertEqual(lines['unaffected'].initial_debit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 1000)
self.assertEqual(lines['unaffected'].initial_balance, -1000) self.assertEqual(lines['unaffected'].initial_balance, -1000)
self.assertEqual(lines['unaffected'].final_debit, -0)
self.assertEqual(lines['unaffected'].final_credit, 0)
self.assertEqual(lines['unaffected'].final_debit, 0)
self.assertEqual(lines['unaffected'].final_credit, 1000)
self.assertEqual(lines['unaffected'].final_balance, -1000) self.assertEqual(lines['unaffected'].final_balance, -1000)
# Add reversale move of the initial move the first day of fiscal year # Add reversale move of the initial move the first day of fiscal year
@ -402,11 +402,11 @@ class TestGeneralLedgerReport(common.TransactionCase):
# Check the initial and final balance # Check the initial and final balance
self.assertEqual(lines['unaffected'].initial_debit, 0) self.assertEqual(lines['unaffected'].initial_debit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 1000)
self.assertEqual(lines['unaffected'].initial_balance, -1000) self.assertEqual(lines['unaffected'].initial_balance, -1000)
self.assertEqual(lines['unaffected'].final_debit, 0)
self.assertEqual(lines['unaffected'].final_credit, 0)
self.assertEqual(lines['unaffected'].final_balance, -1000)
self.assertEqual(lines['unaffected'].final_debit, 1000)
self.assertEqual(lines['unaffected'].final_credit, 1000)
self.assertEqual(lines['unaffected'].final_balance, 0)
# Add another move at the end day of fiscal year # Add another move at the end day of fiscal year
# to check that it correctly used on report # to check that it correctly used on report
@ -426,11 +426,11 @@ class TestGeneralLedgerReport(common.TransactionCase):
# Check the initial and final balance # Check the initial and final balance
self.assertEqual(lines['unaffected'].initial_debit, 0) self.assertEqual(lines['unaffected'].initial_debit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 0)
self.assertEqual(lines['unaffected'].initial_credit, 1000)
self.assertEqual(lines['unaffected'].initial_balance, -1000) self.assertEqual(lines['unaffected'].initial_balance, -1000)
self.assertEqual(lines['unaffected'].final_debit, 0)
self.assertEqual(lines['unaffected'].final_credit, 0)
self.assertEqual(lines['unaffected'].final_balance, -4000)
self.assertEqual(lines['unaffected'].final_debit, 1000)
self.assertEqual(lines['unaffected'].final_credit, 4000)
self.assertEqual(lines['unaffected'].final_balance, -3000)
def test_04_unaffected_account_balance_2_years(self): def test_04_unaffected_account_balance_2_years(self):
# Generate the general ledger line # Generate the general ledger line
@ -460,10 +460,10 @@ class TestGeneralLedgerReport(common.TransactionCase):
self.assertEqual(len(lines['unaffected']), 1) self.assertEqual(len(lines['unaffected']), 1)
# Check the initial and final balance # Check the initial and final balance
self.assertEqual(lines['unaffected'].initial_debit, 0)
self.assertEqual(lines['unaffected'].initial_debit, 1000)
self.assertEqual(lines['unaffected'].initial_credit, 0) self.assertEqual(lines['unaffected'].initial_credit, 0)
self.assertEqual(lines['unaffected'].initial_balance, 1000) self.assertEqual(lines['unaffected'].initial_balance, 1000)
self.assertEqual(lines['unaffected'].final_debit, 0)
self.assertEqual(lines['unaffected'].final_debit, 1000)
self.assertEqual(lines['unaffected'].final_credit, 0) self.assertEqual(lines['unaffected'].final_credit, 0)
self.assertEqual(lines['unaffected'].final_balance, 1000) self.assertEqual(lines['unaffected'].final_balance, 1000)
@ -493,9 +493,9 @@ class TestGeneralLedgerReport(common.TransactionCase):
self.assertEqual(len(lines['unaffected']), 1) self.assertEqual(len(lines['unaffected']), 1)
# Check the initial and final balance # Check the initial and final balance
self.assertEqual(lines['unaffected'].initial_debit, 0)
self.assertEqual(lines['unaffected'].initial_debit, 500)
self.assertEqual(lines['unaffected'].initial_credit, 0) self.assertEqual(lines['unaffected'].initial_credit, 0)
self.assertEqual(lines['unaffected'].initial_balance, 500) self.assertEqual(lines['unaffected'].initial_balance, 500)
self.assertEqual(lines['unaffected'].final_debit, 0)
self.assertEqual(lines['unaffected'].final_debit, 500)
self.assertEqual(lines['unaffected'].final_credit, 0) self.assertEqual(lines['unaffected'].final_credit, 0)
self.assertEqual(lines['unaffected'].final_balance, 500) self.assertEqual(lines['unaffected'].final_balance, 500)

4
account_financial_report_qweb/tests/test_open_items.py

@ -37,6 +37,6 @@ class TestOpenItems(a_t_f_c.AbstractTestForeignCurrency):
def _getAdditionalFiltersToBeTested(self): def _getAdditionalFiltersToBeTested(self):
return [ return [
{'only_posted_moves': True}, {'only_posted_moves': True},
{'hide_account_balance_at_0': True},
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
{'hide_account_at_0': True},
{'only_posted_moves': True, 'hide_account_at_0': True},
] ]

8
account_financial_report_qweb/tests/test_trial_balance.py

@ -41,14 +41,14 @@ class TestTrialBalance(a_t_f_c.AbstractTestForeignCurrency):
def _getAdditionalFiltersToBeTested(self): def _getAdditionalFiltersToBeTested(self):
return [ return [
{'only_posted_moves': True}, {'only_posted_moves': True},
{'hide_account_balance_at_0': True},
{'hide_account_at_0': True},
{'show_partner_details': True}, {'show_partner_details': True},
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
{'only_posted_moves': True, 'hide_account_at_0': True},
{'only_posted_moves': True, 'show_partner_details': True}, {'only_posted_moves': True, 'show_partner_details': True},
{'hide_account_balance_at_0': True, 'show_partner_details': True},
{'hide_account_at_0': True, 'show_partner_details': True},
{ {
'only_posted_moves': True, 'only_posted_moves': True,
'hide_account_balance_at_0': True,
'hide_account_at_0': True,
'show_partner_details': True 'show_partner_details': True
}, },
] ]

24
account_financial_report_qweb/wizard/aged_partner_balance_wizard.py

@ -4,7 +4,6 @@
# Copyright 2016 Camptocamp SA, Onestein B.V. # Copyright 2016 Camptocamp SA, Onestein B.V.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval
@ -21,7 +20,7 @@ class AgedPartnerBalance(models.TransientModel):
string='Company' string='Company'
) )
date_at = fields.Date(required=True, date_at = fields.Date(required=True,
default=fields.Date.to_string(datetime.today()))
default=fields.Date.context_today)
target_move = fields.Selection([('posted', 'All Posted Entries'), target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries')], ('all', 'All Entries')],
string='Target Moves', string='Target Moves',
@ -54,27 +53,6 @@ class AgedPartnerBalance(models.TransientModel):
else: else:
self.account_ids = None self.account_ids = None
@api.model
def create(self, vals):
"""
This is a workaround for bug https://github.com/odoo/odoo/issues/14761
This bug impacts M2M fields in wizards filled-up via onchange
It replaces the workaround widget="many2many_tags" on
field name="account_ids" which prevented from selecting several
accounts at the same time (quite useful when you want to select
an interval of accounts for example)
"""
if 'account_ids' in vals and isinstance(vals['account_ids'], list):
account_ids = []
for account in vals['account_ids']:
if account[0] in (1, 4):
account_ids.append(account[1])
elif account[0] == 6 and isinstance(account[2], list):
account_ids += account[2]
vals['account_ids'] = [(6, 0, account_ids)]
res = super(AgedPartnerBalance, self).create(vals)
return res
@api.multi @api.multi
def button_export_html(self): def button_export_html(self):
self.ensure_one() self.ensure_one()

11
account_financial_report_qweb/wizard/aged_partner_balance_wizard_view.xml

@ -19,15 +19,16 @@
<field name="show_move_line_details"/> <field name="show_move_line_details"/>
</group> </group>
</group> </group>
<group name="partner_filter" col="1">
<label for="partner_ids"/> <label for="partner_ids"/>
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
<group/>
<label for="account_ids"/>
<group col="4">
<field name="partner_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}"/>
</group>
<group name="account_filter" col="4">
<label for="account_ids" colspan="4"/>
<field name="receivable_accounts_only"/> <field name="receivable_accounts_only"/>
<field name="payable_accounts_only"/> <field name="payable_accounts_only"/>
<field name="account_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}" colspan="4"/>
</group> </group>
<field name="account_ids" nolabel="1" options="{'no_create': True}"/>
<footer> <footer>
<button name="button_export_html" string="View" <button name="button_export_html" string="View"
type="object" default_focus="1" class="oe_highlight"/> type="object" default_focus="1" class="oe_highlight"/>

25
account_financial_report_qweb/wizard/general_ledger_wizard.py

@ -38,7 +38,7 @@ class GeneralLedgerReportWizard(models.TransientModel):
) )
centralize = fields.Boolean(string='Activate centralization', centralize = fields.Boolean(string='Activate centralization',
default=True) default=True)
hide_account_balance_at_0 = fields.Boolean(
hide_account_at_0 = fields.Boolean(
string='Hide account ending balance at 0', string='Hide account ending balance at 0',
help='Use this filter to hide an account or a partner ' help='Use this filter to hide an account or a partner '
'with an ending balance at 0. ' 'with an ending balance at 0. '
@ -117,27 +117,6 @@ class GeneralLedgerReportWizard(models.TransientModel):
else: else:
self.account_ids = None self.account_ids = None
@api.model
def create(self, vals):
"""
This is a workaround for bug https://github.com/odoo/odoo/issues/14761
This bug impacts M2M fields in wizards filled-up via onchange
It replaces the workaround widget="many2many_tags" on
field name="account_ids" which prevented from selecting several
accounts at the same time (quite useful when you want to select
an interval of accounts for example)
"""
if 'account_ids' in vals and isinstance(vals['account_ids'], list):
account_ids = []
for account in vals['account_ids']:
if account[0] in (1, 4):
account_ids.append(account[1])
elif account[0] == 6 and isinstance(account[2], list):
account_ids += account[2]
vals['account_ids'] = [(6, 0, account_ids)]
res = super(GeneralLedgerReportWizard, self).create(vals)
return res
@api.onchange('partner_ids') @api.onchange('partner_ids')
def onchange_partner_ids(self): def onchange_partner_ids(self):
"""Handle partners change.""" """Handle partners change."""
@ -181,7 +160,7 @@ class GeneralLedgerReportWizard(models.TransientModel):
'date_from': self.date_from, 'date_from': self.date_from,
'date_to': self.date_to, 'date_to': self.date_to,
'only_posted_moves': self.target_move == 'posted', 'only_posted_moves': self.target_move == 'posted',
'hide_account_balance_at_0': self.hide_account_balance_at_0,
'hide_account_at_0': self.hide_account_at_0,
'foreign_currency': self.foreign_currency, 'foreign_currency': self.foreign_currency,
'show_analytic_tags': self.show_analytic_tags, 'show_analytic_tags': self.show_analytic_tags,
'company_id': self.company_id.id, 'company_id': self.company_id.id,

8
account_financial_report_qweb/wizard/general_ledger_wizard_view.xml

@ -22,7 +22,7 @@
<group name="other_filters"> <group name="other_filters">
<field name="target_move" widget="radio"/> <field name="target_move" widget="radio"/>
<field name="centralize"/> <field name="centralize"/>
<field name="hide_account_balance_at_0"/>
<field name="hide_account_at_0"/>
<field name="foreign_currency"/> <field name="foreign_currency"/>
<field name="show_analytic_tags"/> <field name="show_analytic_tags"/>
</group> </group>
@ -33,16 +33,16 @@
<field name="receivable_accounts_only"/> <field name="receivable_accounts_only"/>
<field name="payable_accounts_only"/> <field name="payable_accounts_only"/>
</group> </group>
<field name="account_ids" nolabel="1" options="{'no_create': True}"/>
<field name="account_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}"/>
</page> </page>
<page string="Filter partners"> <page string="Filter partners">
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
<field name="partner_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}"/>
</page> </page>
<page string="Filter cost centers" groups="analytic.group_analytic_accounting"> <page string="Filter cost centers" groups="analytic.group_analytic_accounting">
<field name="cost_center_ids" nolabel="1" options="{'no_create': True}" groups="analytic.group_analytic_accounting"/> <field name="cost_center_ids" nolabel="1" options="{'no_create': True}" groups="analytic.group_analytic_accounting"/>
</page> </page>
<page string="Filter analytic tags"> <page string="Filter analytic tags">
<field name="analytic_tag_ids" nolabel="1" options="{'no_create': True}"/>
<field name="analytic_tag_ids" widget="many2many_tags" nolabel="1" options="{'no_create': True}"/>
</page> </page>
</notebook> </notebook>
</div> </div>

9
account_financial_report_qweb/wizard/journal_report_wizard.py

@ -36,7 +36,7 @@ class JournalReportWizard(models.TransientModel):
comodel_name='account.journal', comodel_name='account.journal',
string="Journals", string="Journals",
domain="[('company_id', '=', company_id)]", domain="[('company_id', '=', company_id)]",
required=True,
required=False,
) )
move_target = fields.Selection( move_target = fields.Selection(
selection='_get_move_targets', selection='_get_move_targets',
@ -119,13 +119,18 @@ class JournalReportWizard(models.TransientModel):
@api.multi @api.multi
def _prepare_report_journal(self): def _prepare_report_journal(self):
self.ensure_one() 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 { return {
'date_from': self.date_from, 'date_from': self.date_from,
'date_to': self.date_to, 'date_to': self.date_to,
'move_target': self.move_target, 'move_target': self.move_target,
'foreign_currency': self.foreign_currency, 'foreign_currency': self.foreign_currency,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'journal_ids': [(6, 0, self.journal_ids.ids)],
'journal_ids': [(6, 0, journals.ids)],
'sort_option': self.sort_option, 'sort_option': self.sort_option,
'group_option': self.group_option, 'group_option': self.group_option,
'with_account_name': self.with_account_name, 'with_account_name': self.with_account_name,

28
account_financial_report_qweb/wizard/open_items_wizard.py

@ -4,7 +4,6 @@
# Copyright 2016 Camptocamp SA # Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from odoo import models, fields, api from odoo import models, fields, api
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval
@ -21,7 +20,7 @@ class OpenItemsReportWizard(models.TransientModel):
string='Company' string='Company'
) )
date_at = fields.Date(required=True, date_at = fields.Date(required=True,
default=fields.Date.to_string(datetime.today()))
default=fields.Date.context_today)
target_move = fields.Selection([('posted', 'All Posted Entries'), target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries')], ('all', 'All Entries')],
string='Target Moves', string='Target Moves',
@ -32,7 +31,7 @@ class OpenItemsReportWizard(models.TransientModel):
string='Filter accounts', string='Filter accounts',
domain=[('reconcile', '=', True)], domain=[('reconcile', '=', True)],
) )
hide_account_balance_at_0 = fields.Boolean(
hide_account_at_0 = fields.Boolean(
string='Hide account ending balance at 0', string='Hide account ending balance at 0',
help='Use this filter to hide an account or a partner ' help='Use this filter to hide an account or a partner '
'with an ending balance at 0. ' 'with an ending balance at 0. '
@ -67,27 +66,6 @@ class OpenItemsReportWizard(models.TransientModel):
else: else:
self.account_ids = None self.account_ids = None
@api.model
def create(self, vals):
"""
This is a workaround for bug https://github.com/odoo/odoo/issues/14761
This bug impacts M2M fields in wizards filled-up via onchange
It replaces the workaround widget="many2many_tags" on
field name="account_ids" which prevented from selecting several
accounts at the same time (quite useful when you want to select
an interval of accounts for example)
"""
if 'account_ids' in vals and isinstance(vals['account_ids'], list):
account_ids = []
for account in vals['account_ids']:
if account[0] in (1, 4):
account_ids.append(account[1])
elif account[0] == 6 and isinstance(account[2], list):
account_ids += account[2]
vals['account_ids'] = [(6, 0, account_ids)]
res = super(OpenItemsReportWizard, self).create(vals)
return res
@api.multi @api.multi
def button_export_html(self): def button_export_html(self):
self.ensure_one() self.ensure_one()
@ -122,7 +100,7 @@ class OpenItemsReportWizard(models.TransientModel):
return { return {
'date_at': self.date_at, 'date_at': self.date_at,
'only_posted_moves': self.target_move == 'posted', 'only_posted_moves': self.target_move == 'posted',
'hide_account_balance_at_0': self.hide_account_balance_at_0,
'hide_account_at_0': self.hide_account_at_0,
'foreign_currency': self.foreign_currency, 'foreign_currency': self.foreign_currency,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'filter_account_ids': [(6, 0, self.account_ids.ids)], 'filter_account_ids': [(6, 0, self.account_ids.ids)],

13
account_financial_report_qweb/wizard/open_items_wizard_view.xml

@ -16,19 +16,20 @@
</group> </group>
<group name="other_filters"> <group name="other_filters">
<field name="target_move" widget="radio"/> <field name="target_move" widget="radio"/>
<field name="hide_account_balance_at_0"/>
<field name="hide_account_at_0"/>
<field name="foreign_currency"/> <field name="foreign_currency"/>
</group> </group>
</group> </group>
<group name="partner_filter" col="1">
<label for="partner_ids"/> <label for="partner_ids"/>
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
<group/>
<label for="account_ids"/>
<group col="4">
<field name="partner_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}"/>
</group>
<group name="account_filter" col="4">
<label for="account_ids" colspan="4"/>
<field name="receivable_accounts_only"/> <field name="receivable_accounts_only"/>
<field name="payable_accounts_only"/> <field name="payable_accounts_only"/>
<field name="account_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}" colspan="4"/>
</group> </group>
<field name="account_ids" nolabel="1" options="{'no_create': True}"/>
<footer> <footer>
<button name="button_export_html" string="View" <button name="button_export_html" string="View"
type="object" default_focus="1" class="oe_highlight"/> type="object" default_focus="1" class="oe_highlight"/>

67
account_financial_report_qweb/wizard/trial_balance_wizard.py

@ -2,10 +2,12 @@
# Author: Julien Coux # Author: Julien Coux
# Copyright 2016 Camptocamp SA # Copyright 2016 Camptocamp SA
# Copyright 2017 Akretion - Alexis de Lattre # Copyright 2017 Akretion - Alexis de Lattre
# Copyright 2018 Eficent Business and IT Consuting Services, S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api
from odoo import api, fields, models, _
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval
from odoo.exceptions import UserError
class TrialBalanceReportWizard(models.TransientModel): class TrialBalanceReportWizard(models.TransientModel):
@ -31,16 +33,31 @@ class TrialBalanceReportWizard(models.TransientModel):
string='Target Moves', string='Target Moves',
required=True, required=True,
default='all') default='all')
hierarchy_on = fields.Selection(
[('computed', 'Computed Accounts'),
('relation', 'Child Accounts'),
('none', 'No hierarchy')],
string='Hierarchy On',
required=True,
default='computed',
help="""Computed Accounts: Use when the account group have codes
that represent prefixes of the actual accounts.\n
Child Accounts: Use when your account groups are hierarchical.\n
No hierarchy: Use to display just the accounts, without any grouping.
""",
)
limit_hierarchy_level = fields.Boolean('Limit hierarchy levels')
show_hierarchy_level = fields.Integer('Hierarchy Levels to display',
default=1)
account_ids = fields.Many2many( account_ids = fields.Many2many(
comodel_name='account.account', comodel_name='account.account',
string='Filter accounts', string='Filter accounts',
) )
hide_account_balance_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.'
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() receivable_accounts_only = fields.Boolean()
payable_accounts_only = fields.Boolean() payable_accounts_only = fields.Boolean()
@ -66,6 +83,14 @@ class TrialBalanceReportWizard(models.TransientModel):
'will display initial and final balance in that currency.' 'will display initial and final balance in that currency.'
) )
@api.multi
@api.constrains('hierarchy_on', 'show_hierarchy_level')
def _check_show_hierarchy_level(self):
for rec in self:
if rec.hierarchy_on != 'none' and rec.show_hierarchy_level <= 0:
raise UserError(_('The hierarchy level to filter on must be '
'greater than 0.'))
@api.depends('date_from') @api.depends('date_from')
def _compute_fy_start_date(self): def _compute_fy_start_date(self):
for wiz in self.filtered('date_from'): for wiz in self.filtered('date_from'):
@ -105,36 +130,13 @@ class TrialBalanceReportWizard(models.TransientModel):
else: else:
self.account_ids = None self.account_ids = None
@api.model
def create(self, vals):
"""
This is a workaround for bug https://github.com/odoo/odoo/issues/14761
This bug impacts M2M fields in wizards filled-up via onchange
It replaces the workaround widget="many2many_tags" on
field name="account_ids" which prevented from selecting several
accounts at the same time (quite useful when you want to select
an interval of accounts for example)
"""
if 'account_ids' in vals and isinstance(vals['account_ids'], list):
account_ids = []
for account in vals['account_ids']:
if account[0] in (1, 4):
account_ids.append(account[1])
elif account[0] == 6 and isinstance(account[2], list):
account_ids += account[2]
vals['account_ids'] = [(6, 0, account_ids)]
res = super(TrialBalanceReportWizard, self).create(vals)
return res
@api.onchange('show_partner_details') @api.onchange('show_partner_details')
def onchange_show_partner_details(self): def onchange_show_partner_details(self):
"""Handle partners change.""" """Handle partners change."""
if self.show_partner_details: if self.show_partner_details:
self.receivable_accounts_only = self.payable_accounts_only = True self.receivable_accounts_only = self.payable_accounts_only = True
self.hide_account_balance_at_0 = True
else: else:
self.receivable_accounts_only = self.payable_accounts_only = False self.receivable_accounts_only = self.payable_accounts_only = False
self.hide_account_balance_at_0 = False
@api.multi @api.multi
def button_export_html(self): def button_export_html(self):
@ -171,13 +173,16 @@ class TrialBalanceReportWizard(models.TransientModel):
'date_from': self.date_from, 'date_from': self.date_from,
'date_to': self.date_to, 'date_to': self.date_to,
'only_posted_moves': self.target_move == 'posted', 'only_posted_moves': self.target_move == 'posted',
'hide_account_balance_at_0': self.hide_account_balance_at_0,
'hide_account_at_0': self.hide_account_at_0,
'foreign_currency': self.foreign_currency, 'foreign_currency': self.foreign_currency,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'filter_account_ids': [(6, 0, self.account_ids.ids)], 'filter_account_ids': [(6, 0, self.account_ids.ids)],
'filter_partner_ids': [(6, 0, self.partner_ids.ids)], 'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
'filter_journal_ids': [(6, 0, self.journal_ids.ids)], 'filter_journal_ids': [(6, 0, self.journal_ids.ids)],
'fy_start_date': self.fy_start_date, 'fy_start_date': self.fy_start_date,
'hierarchy_on': self.hierarchy_on,
'limit_hierarchy_level': self.limit_hierarchy_level,
'show_hierarchy_level': self.show_hierarchy_level,
'show_partner_details': self.show_partner_details, 'show_partner_details': self.show_partner_details,
} }

13
account_financial_report_qweb/wizard/trial_balance_wizard_view.xml

@ -21,21 +21,24 @@
</group> </group>
<group name="other_filters"> <group name="other_filters">
<field name="target_move" widget="radio"/> <field name="target_move" widget="radio"/>
<field name="hide_account_balance_at_0"/>
<field name="hide_account_at_0"/>
<field name="show_partner_details"/> <field name="show_partner_details"/>
<field name="hierarchy_on" widget="radio" attrs="{'invisible':[('show_partner_details','=',True)]}"/>
<field name="limit_hierarchy_level" attrs="{'invisible':['|', ('hierarchy_on','=','none'),('show_partner_details','=',True)]}"/>
<field name="show_hierarchy_level" attrs="{'invisible':[('limit_hierarchy_level','=', False)]}"/>
<field name="foreign_currency"/> <field name="foreign_currency"/>
</group> </group>
</group> </group>
<group name="partner_filter" attrs="{'invisible':[('show_partner_details','!=',True)]}" col="1"> <group name="partner_filter" attrs="{'invisible':[('show_partner_details','!=',True)]}" col="1">
<label for="partner_ids"/> <label for="partner_ids"/>
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
<field name="partner_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}"/>
</group> </group>
<label for="account_ids"/>
<group col="4">
<group name="account_filter" col="4">
<label for="account_ids" colspan="4"/>
<field name="receivable_accounts_only"/> <field name="receivable_accounts_only"/>
<field name="payable_accounts_only"/> <field name="payable_accounts_only"/>
<field name="account_ids" nolabel="1" widget="many2many_tags" options="{'no_create': True}" colspan="4"/>
</group> </group>
<field name="account_ids" nolabel="1" options="{'no_create': True}"/>
</div> </div>
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}"> <div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}">
<field name="not_only_one_unaffected_earnings_account" invisible="1"/> <field name="not_only_one_unaffected_earnings_account" invisible="1"/>

Loading…
Cancel
Save