Merge pull request #367 from Eficent/11.0-mig-account_financial_report_qweb
[11.0][mig] account_financial_reportpull/372/head
commit
a4fa97d10f
|
@ -39,6 +39,7 @@ coverage.xml
|
|||
|
||||
# Pycharm
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
======================
|
||||
QWeb Financial Reports
|
||||
======================
|
||||
|
||||
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
|
||||
|
||||
.. 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/11.0
|
||||
|
||||
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.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* 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>
|
||||
|
||||
Much of the work in this module was done at a sprint in Sorrento, Italy in
|
||||
April 2016.
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
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.
|
||||
|
||||
To contribute to this module, please visit https://odoo-community.org.
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import models
|
||||
from . import report
|
||||
from . import wizard
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
{
|
||||
'name': 'Account Financial Reports',
|
||||
'version': '11.0.1.1.0',
|
||||
'category': 'Reporting',
|
||||
'summary': 'OCA Financial Reports',
|
||||
'author': 'Camptocamp SA,'
|
||||
'initOS GmbH,'
|
||||
'redCOR AG,'
|
||||
'Odoo Community Association (OCA)',
|
||||
"website": "https://odoo-community.org/",
|
||||
'depends': [
|
||||
'account',
|
||||
'date_range',
|
||||
'account_fiscal_year',
|
||||
'report_xlsx',
|
||||
],
|
||||
'data': [
|
||||
'wizard/aged_partner_balance_wizard_view.xml',
|
||||
'wizard/general_ledger_wizard_view.xml',
|
||||
'wizard/open_items_wizard_view.xml',
|
||||
'wizard/trial_balance_wizard_view.xml',
|
||||
'menuitems.xml',
|
||||
'reports.xml',
|
||||
'report/templates/layouts.xml',
|
||||
'report/templates/aged_partner_balance.xml',
|
||||
'report/templates/general_ledger.xml',
|
||||
'report/templates/open_items.xml',
|
||||
'report/templates/trial_balance.xml',
|
||||
'view/account_view.xml',
|
||||
'view/report_template.xml',
|
||||
'view/report_general_ledger.xml',
|
||||
'view/report_trial_balance.xml',
|
||||
'view/report_open_items.xml',
|
||||
'view/report_aged_partner_balance.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
'license': 'AGPL-3',
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<menuitem
|
||||
parent="account.menu_finance_reports"
|
||||
id="menu_oca_reports"
|
||||
name="OCA accounting reports"
|
||||
groups="account.group_account_manager,account.group_account_user"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_general_ledger_wizard"
|
||||
id="menu_general_ledger_wizard"
|
||||
sequence="10"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_trial_balance_wizard"
|
||||
id="menu_trial_balance_wizard"
|
||||
sequence="20"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_open_items_wizard"
|
||||
id="menu_open_items_wizard"
|
||||
sequence="30"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
parent="menu_oca_reports"
|
||||
action="action_aged_partner_balance_wizard"
|
||||
id="menu_aged_partner_balance_wizard"
|
||||
sequence="40"
|
||||
/>
|
||||
|
||||
<!-- Hide odoo PDF reports menu -->
|
||||
<menuitem
|
||||
id="account.menu_finance_legal_statement"
|
||||
name="PDF Reports"
|
||||
parent="account.menu_finance_reports"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="account.menu_general_ledger"
|
||||
name="General Ledger"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
action="account.action_account_general_ledger_menu"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="account.menu_general_Balance_report"
|
||||
name="Trial Balance"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
action="account.action_account_balance_menu"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="account.menu_account_report_bs"
|
||||
name="Balance Sheet"
|
||||
action="account.action_account_report_bs"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="account.menu_account_report_pl"
|
||||
name="Profit and Loss"
|
||||
action="account.action_account_report_pl"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="account.menu_aged_trial_balance"
|
||||
name="Aged Partner Balance"
|
||||
action="account.action_account_aged_balance_view"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
groups="base.group_erp_manager"
|
||||
/>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import account
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
# © 2011 Guewen Baconnier (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class AccountAccount(models.Model):
|
||||
_inherit = 'account.account'
|
||||
|
||||
centralized = fields.Boolean(
|
||||
'Centralized',
|
||||
help="If flagged, no details will be displayed in "
|
||||
"the General Ledger report (the webkit one only), "
|
||||
"only centralized amounts per period.")
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
# © 2015 Yannick Vaucher (Camptocamp)
|
||||
# © 2016 Damien Crier (Camptocamp)
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
|
||||
from . import abstract_report_xlsx
|
||||
from . import aged_partner_balance
|
||||
from . import aged_partner_balance_xlsx
|
||||
from . import general_ledger
|
||||
from . import general_ledger_xlsx
|
||||
from . import open_items
|
||||
from . import open_items_xlsx
|
||||
from . import trial_balance
|
||||
from . import trial_balance_xlsx
|
|
@ -0,0 +1,301 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
from odoo import models
|
||||
|
||||
|
||||
class AbstractReportXslx(models.AbstractModel):
|
||||
_name = 'report.account_financial_report.abstract_report_xlsx'
|
||||
_inherit = 'report.report_xlsx.abstract'
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
# main sheet which will contains report
|
||||
self.sheet = None
|
||||
|
||||
# columns of the report
|
||||
self.columns = None
|
||||
|
||||
# row_pos must be incremented at each writing lines
|
||||
self.row_pos = None
|
||||
|
||||
# Formats
|
||||
self.format_right = None
|
||||
self.format_right_bold_italic = None
|
||||
self.format_bold = None
|
||||
self.format_header_left = None
|
||||
self.format_header_center = None
|
||||
self.format_header_right = None
|
||||
self.format_header_amount = None
|
||||
self.format_amount = None
|
||||
self.format_percent_bold_italic = None
|
||||
|
||||
def get_workbook_options(self):
|
||||
return {'constant_memory': True}
|
||||
|
||||
def generate_xlsx_report(self, workbook, data, objects):
|
||||
report = objects
|
||||
|
||||
self.row_pos = 0
|
||||
|
||||
self._define_formats(workbook)
|
||||
|
||||
report_name = self._get_report_name()
|
||||
filters = self._get_report_filters(report)
|
||||
self.columns = self._get_report_columns(report)
|
||||
|
||||
self.sheet = workbook.add_worksheet(report_name[:31])
|
||||
|
||||
self._set_column_width()
|
||||
|
||||
self._write_report_title(report_name)
|
||||
|
||||
self._write_filters(filters)
|
||||
|
||||
self._generate_report_content(workbook, report)
|
||||
|
||||
def _define_formats(self, workbook):
|
||||
""" Add cell formats to current workbook.
|
||||
Those formats can be used on all cell.
|
||||
|
||||
Available formats are :
|
||||
* format_bold
|
||||
* format_right
|
||||
* format_right_bold_italic
|
||||
* format_header_left
|
||||
* format_header_center
|
||||
* format_header_right
|
||||
* format_header_amount
|
||||
* format_amount
|
||||
* format_percent_bold_italic
|
||||
"""
|
||||
self.format_bold = workbook.add_format({'bold': True})
|
||||
self.format_right = workbook.add_format({'align': 'right'})
|
||||
self.format_right_bold_italic = workbook.add_format(
|
||||
{'align': 'right', 'bold': True, 'italic': True}
|
||||
)
|
||||
self.format_header_left = workbook.add_format(
|
||||
{'bold': True,
|
||||
'border': True,
|
||||
'bg_color': '#FFFFCC'})
|
||||
self.format_header_center = workbook.add_format(
|
||||
{'bold': True,
|
||||
'align': 'center',
|
||||
'border': True,
|
||||
'bg_color': '#FFFFCC'})
|
||||
self.format_header_right = workbook.add_format(
|
||||
{'bold': True,
|
||||
'align': 'right',
|
||||
'border': True,
|
||||
'bg_color': '#FFFFCC'})
|
||||
self.format_header_amount = workbook.add_format(
|
||||
{'bold': True,
|
||||
'border': True,
|
||||
'bg_color': '#FFFFCC'})
|
||||
self.format_header_amount.set_num_format('#,##0.00')
|
||||
self.format_amount = workbook.add_format()
|
||||
self.format_amount.set_num_format('#,##0.00')
|
||||
self.format_percent_bold_italic = workbook.add_format(
|
||||
{'bold': True, 'italic': True}
|
||||
)
|
||||
self.format_percent_bold_italic.set_num_format('#,##0.00%')
|
||||
|
||||
def _set_column_width(self):
|
||||
"""Set width for all defined columns.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for position, column in self.columns.items():
|
||||
self.sheet.set_column(position, position, column['width'])
|
||||
|
||||
def _write_report_title(self, title):
|
||||
"""Write report title on current line using all defined columns width.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
self.sheet.merge_range(
|
||||
self.row_pos, 0, self.row_pos, len(self.columns) - 1,
|
||||
title, self.format_bold
|
||||
)
|
||||
self.row_pos += 3
|
||||
|
||||
def _write_filters(self, filters):
|
||||
"""Write one line per filters on starting on current line.
|
||||
Columns number for filter name is defined
|
||||
with `_get_col_count_filter_name` method.
|
||||
Columns number for filter value is define
|
||||
with `_get_col_count_filter_value` method.
|
||||
"""
|
||||
col_name = 1
|
||||
col_count_filter_name = self._get_col_count_filter_name()
|
||||
col_count_filter_value = self._get_col_count_filter_value()
|
||||
col_value = col_name + col_count_filter_name + 1
|
||||
for title, value in filters:
|
||||
self.sheet.merge_range(
|
||||
self.row_pos, col_name,
|
||||
self.row_pos, col_name + col_count_filter_name - 1,
|
||||
title, self.format_header_left)
|
||||
self.sheet.merge_range(
|
||||
self.row_pos, col_value,
|
||||
self.row_pos, col_value + col_count_filter_value - 1,
|
||||
value)
|
||||
self.row_pos += 1
|
||||
self.row_pos += 2
|
||||
|
||||
def write_array_title(self, title):
|
||||
"""Write array title on current line using all defined columns width.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
self.sheet.merge_range(
|
||||
self.row_pos, 0, self.row_pos, len(self.columns) - 1,
|
||||
title, self.format_bold
|
||||
)
|
||||
self.row_pos += 1
|
||||
|
||||
def write_array_header(self):
|
||||
"""Write array header on current line using all defined columns name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for col_pos, column in self.columns.items():
|
||||
self.sheet.write(self.row_pos, col_pos, column['header'],
|
||||
self.format_header_center)
|
||||
self.row_pos += 1
|
||||
|
||||
def write_line(self, line_object):
|
||||
"""Write a line on current line using all defined columns field name.
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for col_pos, column in self.columns.items():
|
||||
value = getattr(line_object, column['field'])
|
||||
cell_type = column.get('type', 'string')
|
||||
if cell_type == 'string':
|
||||
self.sheet.write_string(self.row_pos, col_pos, value or '')
|
||||
elif cell_type == 'amount':
|
||||
self.sheet.write_number(
|
||||
self.row_pos, col_pos, float(value), self.format_amount
|
||||
)
|
||||
self.row_pos += 1
|
||||
|
||||
def write_initial_balance(self, my_object, label):
|
||||
"""Write a specific initial balance line on current line
|
||||
using defined columns field_initial_balance name.
|
||||
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
col_pos_label = self._get_col_pos_initial_balance_label()
|
||||
self.sheet.write(self.row_pos, col_pos_label, label, self.format_right)
|
||||
for col_pos, column in self.columns.items():
|
||||
if column.get('field_initial_balance'):
|
||||
value = getattr(my_object, column['field_initial_balance'])
|
||||
cell_type = column.get('type', 'string')
|
||||
if cell_type == 'string':
|
||||
self.sheet.write_string(self.row_pos, col_pos, value or '')
|
||||
elif cell_type == 'amount':
|
||||
self.sheet.write_number(
|
||||
self.row_pos, col_pos, float(value), self.format_amount
|
||||
)
|
||||
self.row_pos += 1
|
||||
|
||||
def write_ending_balance(self, my_object, name, label):
|
||||
"""Write a specific ending balance line on current line
|
||||
using defined columns field_final_balance name.
|
||||
|
||||
Columns are defined with `_get_report_columns` method.
|
||||
"""
|
||||
for i in range(0, len(self.columns)):
|
||||
self.sheet.write(self.row_pos, i, '', self.format_header_right)
|
||||
row_count_name = self._get_col_count_final_balance_name()
|
||||
col_pos_label = self._get_col_pos_final_balance_label()
|
||||
self.sheet.merge_range(
|
||||
self.row_pos, 0, self.row_pos, row_count_name - 1, name,
|
||||
self.format_header_left
|
||||
)
|
||||
self.sheet.write(self.row_pos, col_pos_label, label,
|
||||
self.format_header_right)
|
||||
for col_pos, column in self.columns.items():
|
||||
if column.get('field_final_balance'):
|
||||
value = getattr(my_object, column['field_final_balance'])
|
||||
cell_type = column.get('type', 'string')
|
||||
if cell_type == 'string':
|
||||
self.sheet.write_string(self.row_pos, col_pos, value or '',
|
||||
self.format_header_right)
|
||||
elif cell_type == 'amount':
|
||||
self.sheet.write_number(
|
||||
self.row_pos, col_pos, float(value),
|
||||
self.format_header_amount
|
||||
)
|
||||
self.row_pos += 1
|
||||
|
||||
def _generate_report_content(self, workbook, report):
|
||||
pass
|
||||
|
||||
def _get_report_name(self):
|
||||
"""
|
||||
Allow to define the report name.
|
||||
Report name will be used as sheet name and as report title.
|
||||
|
||||
:return: the report name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
"""
|
||||
Allow to define the report columns
|
||||
which will be used to generate report.
|
||||
|
||||
:return: the report columns as dict
|
||||
|
||||
:Example:
|
||||
|
||||
{
|
||||
0: {'header': 'Simple column',
|
||||
'field': 'field_name_on_my_object',
|
||||
'width': 11},
|
||||
1: {'header': 'Amount column',
|
||||
'field': 'field_name_on_my_object',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
"""
|
||||
:return: the report filters as list
|
||||
|
||||
:Example:
|
||||
|
||||
[
|
||||
['first_filter_name', 'first_filter_value'],
|
||||
['second_filter_name', 'second_filter_value']
|
||||
]
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
"""
|
||||
:return: the columns number used for filter names.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
"""
|
||||
:return: the columns number used for filter values.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_pos_initial_balance_label(self):
|
||||
"""
|
||||
:return: the columns position used for initial balance label.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
"""
|
||||
:return: the columns number used for final balance name.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
"""
|
||||
:return: the columns position used for final balance label.
|
||||
"""
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,628 @@
|
|||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class AgedPartnerBalanceReport(models.TransientModel):
|
||||
""" Here, we just define class fields.
|
||||
For methods, go more bottom at this file.
|
||||
|
||||
The class hierarchy is :
|
||||
* AgedPartnerBalanceReport
|
||||
** AgedPartnerBalanceReportAccount
|
||||
*** AgedPartnerBalanceReportPartner
|
||||
**** AgedPartnerBalanceReportLine
|
||||
**** AgedPartnerBalanceReportMoveLine
|
||||
If "show_move_line_details" is selected
|
||||
"""
|
||||
|
||||
_name = 'report_aged_partner_balance'
|
||||
|
||||
# Filters fields, used for data computation
|
||||
date_at = fields.Date()
|
||||
only_posted_moves = fields.Boolean()
|
||||
company_id = fields.Many2one(comodel_name='res.company')
|
||||
filter_account_ids = fields.Many2many(comodel_name='account.account')
|
||||
filter_partner_ids = fields.Many2many(comodel_name='res.partner')
|
||||
show_move_line_details = fields.Boolean()
|
||||
|
||||
# Open Items Report Data fields, used as base for compute the data reports
|
||||
open_items_id = fields.Many2one(comodel_name='report_open_items')
|
||||
|
||||
# Data fields, used to browse report data
|
||||
account_ids = fields.One2many(
|
||||
comodel_name='report_aged_partner_balance_account',
|
||||
inverse_name='report_id'
|
||||
)
|
||||
|
||||
|
||||
class AgedPartnerBalanceReportAccount(models.TransientModel):
|
||||
_name = 'report_aged_partner_balance_account'
|
||||
_order = 'code ASC'
|
||||
|
||||
report_id = fields.Many2one(
|
||||
comodel_name='report_aged_partner_balance',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
account_id = fields.Many2one(
|
||||
'account.account',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
code = fields.Char()
|
||||
name = fields.Char()
|
||||
|
||||
cumul_amount_residual = fields.Float(digits=(16, 2))
|
||||
cumul_current = fields.Float(digits=(16, 2))
|
||||
cumul_age_30_days = fields.Float(digits=(16, 2))
|
||||
cumul_age_60_days = fields.Float(digits=(16, 2))
|
||||
cumul_age_90_days = fields.Float(digits=(16, 2))
|
||||
cumul_age_120_days = fields.Float(digits=(16, 2))
|
||||
cumul_older = fields.Float(digits=(16, 2))
|
||||
|
||||
percent_current = fields.Float(digits=(16, 2))
|
||||
percent_age_30_days = fields.Float(digits=(16, 2))
|
||||
percent_age_60_days = fields.Float(digits=(16, 2))
|
||||
percent_age_90_days = fields.Float(digits=(16, 2))
|
||||
percent_age_120_days = fields.Float(digits=(16, 2))
|
||||
percent_older = fields.Float(digits=(16, 2))
|
||||
|
||||
# Data fields, used to browse report data
|
||||
partner_ids = fields.One2many(
|
||||
comodel_name='report_aged_partner_balance_partner',
|
||||
inverse_name='report_account_id'
|
||||
)
|
||||
|
||||
|
||||
class AgedPartnerBalanceReportPartner(models.TransientModel):
|
||||
_name = 'report_aged_partner_balance_partner'
|
||||
|
||||
report_account_id = fields.Many2one(
|
||||
comodel_name='report_aged_partner_balance_account',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
partner_id = fields.Many2one(
|
||||
'res.partner',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
name = fields.Char()
|
||||
|
||||
# Data fields, used to browse report data
|
||||
move_line_ids = fields.One2many(
|
||||
comodel_name='report_aged_partner_balance_move_line',
|
||||
inverse_name='report_partner_id'
|
||||
)
|
||||
line_ids = fields.One2many(
|
||||
comodel_name='report_aged_partner_balance_line',
|
||||
inverse_name='report_partner_id'
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _generate_order_by(self, order_spec, query):
|
||||
"""Custom order to display "No partner allocated" at last position."""
|
||||
return """
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN
|
||||
"report_aged_partner_balance_partner"."partner_id" IS NOT NULL
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
"report_aged_partner_balance_partner"."name"
|
||||
"""
|
||||
|
||||
|
||||
class AgedPartnerBalanceReportLine(models.TransientModel):
|
||||
_name = 'report_aged_partner_balance_line'
|
||||
|
||||
report_partner_id = fields.Many2one(
|
||||
comodel_name='report_aged_partner_balance_partner',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
partner = fields.Char()
|
||||
amount_residual = fields.Float(digits=(16, 2))
|
||||
current = fields.Float(digits=(16, 2))
|
||||
age_30_days = fields.Float(digits=(16, 2))
|
||||
age_60_days = fields.Float(digits=(16, 2))
|
||||
age_90_days = fields.Float(digits=(16, 2))
|
||||
age_120_days = fields.Float(digits=(16, 2))
|
||||
older = fields.Float(digits=(16, 2))
|
||||
|
||||
|
||||
class AgedPartnerBalanceReportMoveLine(models.TransientModel):
|
||||
_name = 'report_aged_partner_balance_move_line'
|
||||
|
||||
report_partner_id = fields.Many2one(
|
||||
comodel_name='report_aged_partner_balance_partner',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
move_line_id = fields.Many2one('account.move.line')
|
||||
|
||||
# Data fields, used for report display
|
||||
date = fields.Date()
|
||||
date_due = fields.Date()
|
||||
entry = fields.Char()
|
||||
journal = fields.Char()
|
||||
account = fields.Char()
|
||||
partner = fields.Char()
|
||||
label = fields.Char()
|
||||
|
||||
amount_residual = fields.Float(digits=(16, 2))
|
||||
current = fields.Float(digits=(16, 2))
|
||||
age_30_days = fields.Float(digits=(16, 2))
|
||||
age_60_days = fields.Float(digits=(16, 2))
|
||||
age_90_days = fields.Float(digits=(16, 2))
|
||||
age_120_days = fields.Float(digits=(16, 2))
|
||||
older = fields.Float(digits=(16, 2))
|
||||
|
||||
|
||||
class AgedPartnerBalanceReportCompute(models.TransientModel):
|
||||
""" Here, we just define methods.
|
||||
For class fields, go more top at this file.
|
||||
"""
|
||||
|
||||
_inherit = 'report_aged_partner_balance'
|
||||
|
||||
@api.multi
|
||||
def print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
if report_type == 'xlsx':
|
||||
report_name = 'a_f_r.report_aged_partner_balance_xlsx'
|
||||
else:
|
||||
report_name = 'account_financial_report.' \
|
||||
'report_aged_partner_balance_qweb'
|
||||
report = self.env['ir.actions.report'].search(
|
||||
[('report_name', '=', report_name),
|
||||
('report_type', '=', report_type)], limit=1)
|
||||
return report.report_action(self)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
context = dict(self.env.context)
|
||||
report = self.browse(context.get('active_id'))
|
||||
if report:
|
||||
rcontext['o'] = report
|
||||
result['html'] = self.env.ref(
|
||||
'account_financial_report.report_aged_partner_balance').render(
|
||||
rcontext)
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_html(self, given_context=None):
|
||||
return self._get_html()
|
||||
|
||||
def _prepare_report_open_items(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_at': self.date_at,
|
||||
'only_posted_moves': self.only_posted_moves,
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.filter_account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.filter_partner_ids.ids)],
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def compute_data_for_report(self):
|
||||
self.ensure_one()
|
||||
# Compute Open Items Report Data.
|
||||
# The data of Aged Partner Balance Report
|
||||
# are based on Open Items Report data.
|
||||
model = self.env['report_open_items']
|
||||
self.open_items_id = model.create(self._prepare_report_open_items())
|
||||
self.open_items_id.compute_data_for_report()
|
||||
|
||||
# Compute report data
|
||||
self._inject_account_values()
|
||||
self._inject_partner_values()
|
||||
self._inject_line_values()
|
||||
self._inject_line_values(only_empty_partner_line=True)
|
||||
if self.show_move_line_details:
|
||||
self._inject_move_line_values()
|
||||
self._inject_move_line_values(only_empty_partner_line=True)
|
||||
self._compute_accounts_cumul()
|
||||
# Refresh cache because all data are computed with SQL requests
|
||||
self.refresh()
|
||||
|
||||
def _inject_account_values(self):
|
||||
"""Inject report values for report_aged_partner_balance_account"""
|
||||
query_inject_account = """
|
||||
INSERT INTO
|
||||
report_aged_partner_balance_account
|
||||
(
|
||||
report_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
account_id,
|
||||
code,
|
||||
name
|
||||
)
|
||||
SELECT
|
||||
%s AS report_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rao.account_id,
|
||||
rao.code,
|
||||
rao.name
|
||||
FROM
|
||||
report_open_items_account rao
|
||||
WHERE
|
||||
rao.report_id = %s
|
||||
"""
|
||||
query_inject_account_params = (
|
||||
self.id,
|
||||
self.env.uid,
|
||||
self.open_items_id.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_account, query_inject_account_params)
|
||||
|
||||
def _inject_partner_values(self):
|
||||
"""Inject report values for report_aged_partner_balance_partner"""
|
||||
query_inject_partner = """
|
||||
INSERT INTO
|
||||
report_aged_partner_balance_partner
|
||||
(
|
||||
report_account_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
partner_id,
|
||||
name
|
||||
)
|
||||
SELECT
|
||||
ra.id AS report_account_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rpo.partner_id,
|
||||
rpo.name
|
||||
FROM
|
||||
report_open_items_partner rpo
|
||||
INNER JOIN
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code
|
||||
WHERE
|
||||
rao.report_id = %s
|
||||
AND ra.report_id = %s
|
||||
"""
|
||||
query_inject_partner_params = (
|
||||
self.env.uid,
|
||||
self.open_items_id.id,
|
||||
self.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_partner, query_inject_partner_params)
|
||||
|
||||
def _inject_line_values(self, only_empty_partner_line=False):
|
||||
""" Inject report values for report_aged_partner_balance_line.
|
||||
|
||||
The "only_empty_partner_line" value is used
|
||||
to compute data without partner.
|
||||
"""
|
||||
query_inject_line = """
|
||||
WITH
|
||||
date_range AS
|
||||
(
|
||||
SELECT
|
||||
%s AS date_current,
|
||||
DATE %s - INTEGER '30' AS date_less_30_days,
|
||||
DATE %s - INTEGER '60' AS date_less_60_days,
|
||||
DATE %s - INTEGER '90' AS date_less_90_days,
|
||||
DATE %s - INTEGER '120' AS date_less_120_days,
|
||||
DATE %s - INTEGER '150' AS date_older
|
||||
)
|
||||
INSERT INTO
|
||||
report_aged_partner_balance_line
|
||||
(
|
||||
report_partner_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
partner,
|
||||
amount_residual,
|
||||
current,
|
||||
age_30_days,
|
||||
age_60_days,
|
||||
age_90_days,
|
||||
age_120_days,
|
||||
older
|
||||
)
|
||||
SELECT
|
||||
rp.id AS report_partner_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rp.name,
|
||||
SUM(rlo.amount_residual) AS amount_residual,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN rlo.date_due > date_range.date_less_30_days
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS current,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_60_days
|
||||
AND rlo.date_due <= date_range.date_less_30_days
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS age_30_days,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_90_days
|
||||
AND rlo.date_due <= date_range.date_less_60_days
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS age_60_days,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_120_days
|
||||
AND rlo.date_due <= date_range.date_less_90_days
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS age_90_days,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_older
|
||||
AND rlo.date_due <= date_range.date_less_120_days
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS age_120_days,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN rlo.date_due <= date_range.date_older
|
||||
THEN rlo.amount_residual
|
||||
END
|
||||
) AS older
|
||||
FROM
|
||||
date_range,
|
||||
report_open_items_move_line rlo
|
||||
INNER JOIN
|
||||
report_open_items_partner rpo ON rlo.report_partner_id = rpo.id
|
||||
INNER JOIN
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_partner rp
|
||||
ON
|
||||
ra.id = rp.report_account_id
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
query_inject_line += """
|
||||
AND rpo.partner_id = rp.partner_id
|
||||
"""
|
||||
elif only_empty_partner_line:
|
||||
query_inject_line += """
|
||||
AND rpo.partner_id IS NULL
|
||||
AND rp.partner_id IS NULL
|
||||
"""
|
||||
query_inject_line += """
|
||||
WHERE
|
||||
rao.report_id = %s
|
||||
AND ra.report_id = %s
|
||||
GROUP BY
|
||||
rp.id
|
||||
"""
|
||||
query_inject_line_params = (self.date_at,) * 6
|
||||
query_inject_line_params += (
|
||||
self.env.uid,
|
||||
self.open_items_id.id,
|
||||
self.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_line, query_inject_line_params)
|
||||
|
||||
def _inject_move_line_values(self, only_empty_partner_line=False):
|
||||
""" Inject report values for report_aged_partner_balance_move_line
|
||||
|
||||
The "only_empty_partner_line" value is used
|
||||
to compute data without partner.
|
||||
"""
|
||||
query_inject_move_line = """
|
||||
WITH
|
||||
date_range AS
|
||||
(
|
||||
SELECT
|
||||
%s AS date_current,
|
||||
DATE %s - INTEGER '30' AS date_less_30_days,
|
||||
DATE %s - INTEGER '60' AS date_less_60_days,
|
||||
DATE %s - INTEGER '90' AS date_less_90_days,
|
||||
DATE %s - INTEGER '120' AS date_less_120_days,
|
||||
DATE %s - INTEGER '150' AS date_older
|
||||
)
|
||||
INSERT INTO
|
||||
report_aged_partner_balance_move_line
|
||||
(
|
||||
report_partner_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
date,
|
||||
date_due,
|
||||
entry,
|
||||
journal,
|
||||
account,
|
||||
partner,
|
||||
label,
|
||||
amount_residual,
|
||||
current,
|
||||
age_30_days,
|
||||
age_60_days,
|
||||
age_90_days,
|
||||
age_120_days,
|
||||
older
|
||||
)
|
||||
SELECT
|
||||
rp.id AS report_partner_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rlo.date,
|
||||
rlo.date_due,
|
||||
rlo.entry,
|
||||
rlo.journal,
|
||||
rlo.account,
|
||||
rlo.partner,
|
||||
rlo.label,
|
||||
rlo.amount_residual AS amount_residual,
|
||||
CASE
|
||||
WHEN rlo.date_due > date_range.date_less_30_days
|
||||
THEN rlo.amount_residual
|
||||
END AS current,
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_60_days
|
||||
AND rlo.date_due <= date_range.date_less_30_days
|
||||
THEN rlo.amount_residual
|
||||
END AS age_30_days,
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_90_days
|
||||
AND rlo.date_due <= date_range.date_less_60_days
|
||||
THEN rlo.amount_residual
|
||||
END AS age_60_days,
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_less_120_days
|
||||
AND rlo.date_due <= date_range.date_less_90_days
|
||||
THEN rlo.amount_residual
|
||||
END AS age_90_days,
|
||||
CASE
|
||||
WHEN
|
||||
rlo.date_due > date_range.date_older
|
||||
AND rlo.date_due <= date_range.date_less_120_days
|
||||
THEN rlo.amount_residual
|
||||
END AS age_120_days,
|
||||
CASE
|
||||
WHEN rlo.date_due <= date_range.date_older
|
||||
THEN rlo.amount_residual
|
||||
END AS older
|
||||
FROM
|
||||
date_range,
|
||||
report_open_items_move_line rlo
|
||||
INNER JOIN
|
||||
report_open_items_partner rpo ON rlo.report_partner_id = rpo.id
|
||||
INNER JOIN
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_partner rp
|
||||
ON
|
||||
ra.id = rp.report_account_id
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
AND rpo.partner_id = rp.partner_id
|
||||
"""
|
||||
elif only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
AND rpo.partner_id IS NULL
|
||||
AND rp.partner_id IS NULL
|
||||
"""
|
||||
query_inject_move_line += """
|
||||
WHERE
|
||||
rao.report_id = %s
|
||||
AND ra.report_id = %s
|
||||
"""
|
||||
query_inject_move_line_params = (self.date_at,) * 6
|
||||
query_inject_move_line_params += (
|
||||
self.env.uid,
|
||||
self.open_items_id.id,
|
||||
self.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_move_line,
|
||||
query_inject_move_line_params)
|
||||
|
||||
def _compute_accounts_cumul(self):
|
||||
""" Compute cumulative amount for
|
||||
report_aged_partner_balance_account.
|
||||
"""
|
||||
query_compute_accounts_cumul = """
|
||||
WITH
|
||||
cumuls AS
|
||||
(
|
||||
SELECT
|
||||
ra.id AS report_account_id,
|
||||
SUM(rl.amount_residual) AS cumul_amount_residual,
|
||||
SUM(rl.current) AS cumul_current,
|
||||
SUM(rl.age_30_days) AS cumul_age_30_days,
|
||||
SUM(rl.age_60_days) AS cumul_age_60_days,
|
||||
SUM(rl.age_90_days) AS cumul_age_90_days,
|
||||
SUM(rl.age_120_days) AS cumul_age_120_days,
|
||||
SUM(rl.older) AS cumul_older
|
||||
FROM
|
||||
report_aged_partner_balance_line rl
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_partner rp
|
||||
ON rl.report_partner_id = rp.id
|
||||
INNER JOIN
|
||||
report_aged_partner_balance_account ra
|
||||
ON rp.report_account_id = ra.id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
GROUP BY
|
||||
ra.id
|
||||
)
|
||||
UPDATE
|
||||
report_aged_partner_balance_account
|
||||
SET
|
||||
cumul_amount_residual = c.cumul_amount_residual,
|
||||
cumul_current = c.cumul_current,
|
||||
cumul_age_30_days = c.cumul_age_30_days,
|
||||
cumul_age_60_days = c.cumul_age_60_days,
|
||||
cumul_age_90_days = c.cumul_age_90_days,
|
||||
cumul_age_120_days = c.cumul_age_120_days,
|
||||
cumul_older = c.cumul_older,
|
||||
percent_current =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_current / c.cumul_amount_residual
|
||||
END,
|
||||
percent_age_30_days =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_age_30_days / c.cumul_amount_residual
|
||||
END,
|
||||
percent_age_60_days =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_age_60_days / c.cumul_amount_residual
|
||||
END,
|
||||
percent_age_90_days =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_age_90_days / c.cumul_amount_residual
|
||||
END,
|
||||
percent_age_120_days =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_age_120_days / c.cumul_amount_residual
|
||||
END,
|
||||
percent_older =
|
||||
CASE
|
||||
WHEN c.cumul_amount_residual != 0
|
||||
THEN 100 * c.cumul_older / c.cumul_amount_residual
|
||||
END
|
||||
FROM
|
||||
cumuls c
|
||||
WHERE
|
||||
id = c.report_account_id
|
||||
"""
|
||||
params_compute_accounts_cumul = (self.id,)
|
||||
self.env.cr.execute(query_compute_accounts_cumul,
|
||||
params_compute_accounts_cumul)
|
|
@ -0,0 +1,257 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class AgedPartnerBalanceXslx(models.AbstractModel):
|
||||
_name = 'report.a_f_r.report_aged_partner_balance_xlsx'
|
||||
_inherit = 'report.account_financial_report.abstract_report_xlsx'
|
||||
|
||||
def _get_report_name(self):
|
||||
return _('Aged Partner Balance')
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
if not report.show_move_line_details:
|
||||
return {
|
||||
0: {'header': _('Partner'), 'field': 'partner', 'width': 70},
|
||||
1: {'header': _('Residual'),
|
||||
'field': 'amount_residual',
|
||||
'field_footer_total': 'cumul_amount_residual',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
2: {'header': _('Current'),
|
||||
'field': 'current',
|
||||
'field_footer_total': 'cumul_current',
|
||||
'field_footer_percent': 'percent_current',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
3: {'header': _(u'Age ≤ 30 d.'),
|
||||
'field': 'age_30_days',
|
||||
'field_footer_total': 'cumul_age_30_days',
|
||||
'field_footer_percent': 'percent_age_30_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
4: {'header': _(u'Age ≤ 60 d.'),
|
||||
'field': 'age_60_days',
|
||||
'field_footer_total': 'cumul_age_60_days',
|
||||
'field_footer_percent': 'percent_age_60_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
5: {'header': _(u'Age ≤ 90 d.'),
|
||||
'field': 'age_90_days',
|
||||
'field_footer_total': 'cumul_age_90_days',
|
||||
'field_footer_percent': 'percent_age_90_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
6: {'header': _(u'Age ≤ 120 d.'),
|
||||
'field': 'age_120_days',
|
||||
'field_footer_total': 'cumul_age_120_days',
|
||||
'field_footer_percent': 'percent_age_120_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
7: {'header': _('Older'),
|
||||
'field': 'older',
|
||||
'field_footer_total': 'cumul_older',
|
||||
'field_footer_percent': 'percent_older',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
else:
|
||||
return {
|
||||
0: {'header': _('Date'), 'field': 'date', 'width': 11},
|
||||
1: {'header': _('Entry'), 'field': 'entry', 'width': 18},
|
||||
2: {'header': _('Journal'), 'field': 'journal', 'width': 8},
|
||||
3: {'header': _('Account'), 'field': 'account', 'width': 9},
|
||||
4: {'header': _('Partner'), 'field': 'partner', 'width': 25},
|
||||
5: {'header': _('Ref - Label'), 'field': 'label', 'width': 40},
|
||||
6: {'header': _('Due date'), 'field': 'date_due', 'width': 11},
|
||||
7: {'header': _('Residual'),
|
||||
'field': 'amount_residual',
|
||||
'field_footer_total': 'cumul_amount_residual',
|
||||
'field_final_balance': 'amount_residual',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
8: {'header': _('Current'),
|
||||
'field': 'current',
|
||||
'field_footer_total': 'cumul_current',
|
||||
'field_footer_percent': 'percent_current',
|
||||
'field_final_balance': 'current',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
9: {'header': _(u'Age ≤ 30 d.'),
|
||||
'field': 'age_30_days',
|
||||
'field_footer_total': 'cumul_age_30_days',
|
||||
'field_footer_percent': 'percent_age_30_days',
|
||||
'field_final_balance': 'age_30_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
10: {'header': _(u'Age ≤ 60 d.'),
|
||||
'field': 'age_60_days',
|
||||
'field_footer_total': 'cumul_age_60_days',
|
||||
'field_footer_percent': 'percent_age_60_days',
|
||||
'field_final_balance': 'age_60_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
11: {'header': _(u'Age ≤ 90 d.'),
|
||||
'field': 'age_90_days',
|
||||
'field_footer_total': 'cumul_age_90_days',
|
||||
'field_footer_percent': 'percent_age_90_days',
|
||||
'field_final_balance': 'age_90_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
12: {'header': _(u'Age ≤ 120 d.'),
|
||||
'field': 'age_120_days',
|
||||
'field_footer_total': 'cumul_age_120_days',
|
||||
'field_footer_percent': 'percent_age_120_days',
|
||||
'field_final_balance': 'age_120_days',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
13: {'header': _('Older'),
|
||||
'field': 'older',
|
||||
'field_footer_total': 'cumul_older',
|
||||
'field_footer_percent': 'percent_older',
|
||||
'field_final_balance': 'older',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_('Date at filter'), report.date_at],
|
||||
[_('Target moves filter'),
|
||||
_('All posted entries') if report.only_posted_moves
|
||||
else _('All entries')],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 3
|
||||
|
||||
def _get_col_pos_footer_label(self, report):
|
||||
return 0 if not report.show_move_line_details else 5
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _generate_report_content(self, workbook, report):
|
||||
if not report.show_move_line_details:
|
||||
# For each account
|
||||
for account in report.account_ids:
|
||||
# Write account title
|
||||
self.write_array_title(account.code + ' - ' + account.name)
|
||||
|
||||
# Display array header for partners lines
|
||||
self.write_array_header()
|
||||
|
||||
# Display partner lines
|
||||
for partner in account.partner_ids:
|
||||
self.write_line(partner.line_ids)
|
||||
|
||||
# Display account lines
|
||||
self.write_account_footer(report,
|
||||
account,
|
||||
_('Total'),
|
||||
'field_footer_total',
|
||||
self.format_header_right,
|
||||
self.format_header_amount,
|
||||
False)
|
||||
self.write_account_footer(report,
|
||||
account,
|
||||
_('Percents'),
|
||||
'field_footer_percent',
|
||||
self.format_right_bold_italic,
|
||||
self.format_percent_bold_italic,
|
||||
True)
|
||||
|
||||
# 2 lines break
|
||||
self.row_pos += 2
|
||||
else:
|
||||
# For each account
|
||||
for account in report.account_ids:
|
||||
# Write account title
|
||||
self.write_array_title(account.code + ' - ' + account.name)
|
||||
|
||||
# For each partner
|
||||
for partner in account.partner_ids:
|
||||
# Write partner title
|
||||
self.write_array_title(partner.name)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header()
|
||||
|
||||
# Display account move lines
|
||||
for line in partner.move_line_ids:
|
||||
self.write_line(line)
|
||||
|
||||
# Display ending balance line for partner
|
||||
self.write_ending_balance(partner.line_ids)
|
||||
|
||||
# Line break
|
||||
self.row_pos += 1
|
||||
|
||||
# Display account lines
|
||||
self.write_account_footer(report,
|
||||
account,
|
||||
_('Total'),
|
||||
'field_footer_total',
|
||||
self.format_header_right,
|
||||
self.format_header_amount,
|
||||
False)
|
||||
self.write_account_footer(report,
|
||||
account,
|
||||
_('Percents'),
|
||||
'field_footer_percent',
|
||||
self.format_right_bold_italic,
|
||||
self.format_percent_bold_italic,
|
||||
True)
|
||||
|
||||
# 2 lines break
|
||||
self.row_pos += 2
|
||||
|
||||
def write_ending_balance(self, my_object):
|
||||
"""
|
||||
Specific function to write ending partner balance
|
||||
for Aged Partner Balance
|
||||
"""
|
||||
name = None
|
||||
label = _('Partner cumul aged balance')
|
||||
super(AgedPartnerBalanceXslx, self).write_ending_balance(
|
||||
my_object, name, label
|
||||
)
|
||||
|
||||
def write_account_footer(self, report, account, label, field_name,
|
||||
string_format, amount_format, amount_is_percent):
|
||||
"""
|
||||
Specific function to write account footer for Aged Partner Balance
|
||||
"""
|
||||
col_pos_footer_label = self._get_col_pos_footer_label(report)
|
||||
for col_pos, column in self.columns.items():
|
||||
if col_pos == col_pos_footer_label or column.get(field_name):
|
||||
if col_pos == col_pos_footer_label:
|
||||
value = label
|
||||
else:
|
||||
value = getattr(account, column[field_name])
|
||||
cell_type = column.get('type', 'string')
|
||||
if cell_type == 'string' or col_pos == col_pos_footer_label:
|
||||
self.sheet.write_string(self.row_pos, col_pos, value or '',
|
||||
string_format)
|
||||
elif cell_type == 'amount':
|
||||
number = float(value)
|
||||
if amount_is_percent:
|
||||
number /= 100
|
||||
self.sheet.write_number(self.row_pos, col_pos,
|
||||
number,
|
||||
amount_format)
|
||||
else:
|
||||
self.sheet.write_string(self.row_pos, col_pos, '',
|
||||
string_format)
|
||||
|
||||
self.row_pos += 1
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,137 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class GeneralLedgerXslx(models.AbstractModel):
|
||||
_name = 'report.a_f_r.report_general_ledger_xlsx'
|
||||
_inherit = 'report.account_financial_report.abstract_report_xlsx'
|
||||
|
||||
def _get_report_name(self):
|
||||
return _('General Ledger')
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
return {
|
||||
0: {'header': _('Date'), 'field': 'date', 'width': 11},
|
||||
1: {'header': _('Entry'), 'field': 'entry', 'width': 18},
|
||||
2: {'header': _('Journal'), 'field': 'journal', 'width': 8},
|
||||
3: {'header': _('Account'), 'field': 'account', 'width': 9},
|
||||
4: {'header': _('Partner'), 'field': 'partner', 'width': 25},
|
||||
5: {'header': _('Ref - Label'), 'field': 'label', 'width': 40},
|
||||
6: {'header': _('Cost center'),
|
||||
'field': 'cost_center',
|
||||
'width': 15},
|
||||
7: {'header': _('Rec.'), 'field': 'matching_number', 'width': 5},
|
||||
8: {'header': _('Debit'),
|
||||
'field': 'debit',
|
||||
'field_initial_balance': 'initial_debit',
|
||||
'field_final_balance': 'final_debit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
9: {'header': _('Credit'),
|
||||
'field': 'credit',
|
||||
'field_initial_balance': 'initial_credit',
|
||||
'field_final_balance': 'final_credit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
10: {'header': _('Cumul. Bal.'),
|
||||
'field': 'cumul_balance',
|
||||
'field_initial_balance': 'initial_balance',
|
||||
'field_final_balance': 'final_balance',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
11: {'header': _('Cur.'), 'field': 'currency_name', 'width': 7},
|
||||
12: {'header': _('Amount cur.'),
|
||||
'field': 'amount_currency',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_('Date range filter'),
|
||||
_('From: %s To: %s') % (report.date_from, report.date_to)],
|
||||
[_('Target moves filter'),
|
||||
_('All posted entries') if report.only_posted_moves
|
||||
else _('All entries')],
|
||||
[_('Account balance at 0 filter'),
|
||||
_('Hide') if report.hide_account_balance_at_0 else _('Show')],
|
||||
[_('Centralize filter'),
|
||||
_('Yes') if report.centralize else _('No')],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 2
|
||||
|
||||
def _get_col_pos_initial_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _generate_report_content(self, workbook, report):
|
||||
# For each account
|
||||
for account in report.account_ids:
|
||||
# Write account title
|
||||
self.write_array_title(account.code + ' - ' + account.name)
|
||||
|
||||
if not account.partner_ids:
|
||||
# Display array header for move lines
|
||||
self.write_array_header()
|
||||
|
||||
# Display initial balance line for account
|
||||
self.write_initial_balance(account, _('Initial balance'))
|
||||
|
||||
# Display account move lines
|
||||
for line in account.move_line_ids:
|
||||
self.write_line(line)
|
||||
|
||||
else:
|
||||
# For each partner
|
||||
for partner in account.partner_ids:
|
||||
# Write partner title
|
||||
self.write_array_title(partner.name)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header()
|
||||
|
||||
# Display initial balance line for partner
|
||||
self.write_initial_balance(partner, _('Initial balance'))
|
||||
|
||||
# Display account move lines
|
||||
for line in partner.move_line_ids:
|
||||
self.write_line(line)
|
||||
|
||||
# Display ending balance line for partner
|
||||
self.write_ending_balance(partner, 'partner')
|
||||
|
||||
# Line break
|
||||
self.row_pos += 1
|
||||
|
||||
# Display ending balance line for account
|
||||
self.write_ending_balance(account, 'account')
|
||||
|
||||
# 2 lines break
|
||||
self.row_pos += 2
|
||||
|
||||
def write_ending_balance(self, my_object, type_object):
|
||||
"""Specific function to write ending balance for General Ledger"""
|
||||
if type_object == 'partner':
|
||||
name = my_object.name
|
||||
label = _('Partner ending balance')
|
||||
elif type_object == 'account':
|
||||
name = my_object.code + ' - ' + my_object.name
|
||||
label = _('Ending balance')
|
||||
super(GeneralLedgerXslx, self).write_ending_balance(
|
||||
my_object, name, label
|
||||
)
|
|
@ -0,0 +1,776 @@
|
|||
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class OpenItemsReport(models.TransientModel):
|
||||
""" Here, we just define class fields.
|
||||
For methods, go more bottom at this file.
|
||||
|
||||
The class hierarchy is :
|
||||
* OpenItemsReport
|
||||
** OpenItemsReportAccount
|
||||
*** OpenItemsReportPartner
|
||||
**** OpenItemsReportMoveLine
|
||||
"""
|
||||
|
||||
_name = 'report_open_items'
|
||||
|
||||
# Filters fields, used for data computation
|
||||
date_at = fields.Date()
|
||||
only_posted_moves = fields.Boolean()
|
||||
hide_account_balance_at_0 = fields.Boolean()
|
||||
company_id = fields.Many2one(comodel_name='res.company')
|
||||
filter_account_ids = fields.Many2many(comodel_name='account.account')
|
||||
filter_partner_ids = fields.Many2many(comodel_name='res.partner')
|
||||
|
||||
# Flag fields, used for report display
|
||||
has_second_currency = fields.Boolean()
|
||||
|
||||
# Data fields, used to browse report data
|
||||
account_ids = fields.One2many(
|
||||
comodel_name='report_open_items_account',
|
||||
inverse_name='report_id'
|
||||
)
|
||||
|
||||
|
||||
class OpenItemsReportAccount(models.TransientModel):
|
||||
|
||||
_name = 'report_open_items_account'
|
||||
_order = 'code ASC'
|
||||
|
||||
report_id = fields.Many2one(
|
||||
comodel_name='report_open_items',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
account_id = fields.Many2one(
|
||||
'account.account',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
code = fields.Char()
|
||||
name = fields.Char()
|
||||
final_amount_residual = fields.Float(digits=(16, 2))
|
||||
|
||||
# Data fields, used to browse report data
|
||||
partner_ids = fields.One2many(
|
||||
comodel_name='report_open_items_partner',
|
||||
inverse_name='report_account_id'
|
||||
)
|
||||
|
||||
|
||||
class OpenItemsReportPartner(models.TransientModel):
|
||||
|
||||
_name = 'report_open_items_partner'
|
||||
|
||||
report_account_id = fields.Many2one(
|
||||
comodel_name='report_open_items_account',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
partner_id = fields.Many2one(
|
||||
'res.partner',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
name = fields.Char()
|
||||
final_amount_residual = fields.Float(digits=(16, 2))
|
||||
|
||||
# Data fields, used to browse report data
|
||||
move_line_ids = fields.One2many(
|
||||
comodel_name='report_open_items_move_line',
|
||||
inverse_name='report_partner_id'
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _generate_order_by(self, order_spec, query):
|
||||
"""Custom order to display "No partner allocated" at last position."""
|
||||
return """
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN "report_open_items_partner"."partner_id" IS NOT NULL
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
"report_open_items_partner"."name"
|
||||
"""
|
||||
|
||||
|
||||
class OpenItemsReportMoveLine(models.TransientModel):
|
||||
|
||||
_name = 'report_open_items_move_line'
|
||||
|
||||
report_partner_id = fields.Many2one(
|
||||
comodel_name='report_open_items_partner',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
move_line_id = fields.Many2one('account.move.line')
|
||||
|
||||
# Data fields, used for report display
|
||||
date = fields.Date()
|
||||
date_due = fields.Date()
|
||||
entry = fields.Char()
|
||||
journal = fields.Char()
|
||||
account = fields.Char()
|
||||
partner = fields.Char()
|
||||
label = fields.Char()
|
||||
amount_total_due = fields.Float(digits=(16, 2))
|
||||
amount_residual = fields.Float(digits=(16, 2))
|
||||
currency_name = fields.Char()
|
||||
amount_total_due_currency = fields.Float(digits=(16, 2))
|
||||
amount_residual_currency = fields.Float(digits=(16, 2))
|
||||
|
||||
|
||||
class OpenItemsReportCompute(models.TransientModel):
|
||||
""" Here, we just define methods.
|
||||
For class fields, go more top at this file.
|
||||
"""
|
||||
|
||||
_inherit = 'report_open_items'
|
||||
|
||||
@api.multi
|
||||
def print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
if report_type == 'xlsx':
|
||||
report_name = 'a_f_r.report_open_items_xlsx'
|
||||
else:
|
||||
report_name = 'account_financial_report.' \
|
||||
'report_open_items_qweb'
|
||||
return self.env['ir.actions.report'].search(
|
||||
[('report_name', '=', report_name),
|
||||
('report_type', '=', report_type)], limit=1).report_action(self)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
context = dict(self.env.context)
|
||||
report = self.browse(context.get('active_id'))
|
||||
if report:
|
||||
rcontext['o'] = report
|
||||
result['html'] = self.env.ref(
|
||||
'account_financial_report.report_open_items').render(
|
||||
rcontext)
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_html(self, given_context=None):
|
||||
return self._get_html()
|
||||
|
||||
@api.multi
|
||||
def compute_data_for_report(self):
|
||||
self.ensure_one()
|
||||
# Compute report data
|
||||
self._inject_account_values()
|
||||
self._inject_partner_values()
|
||||
self._inject_line_values()
|
||||
self._inject_line_values(only_empty_partner_line=True)
|
||||
self._clean_partners_and_accounts()
|
||||
self._compute_partners_and_accounts_cumul()
|
||||
if self.hide_account_balance_at_0:
|
||||
self._clean_partners_and_accounts(
|
||||
only_delete_account_balance_at_0=True
|
||||
)
|
||||
# Compute display flag
|
||||
self._compute_has_second_currency()
|
||||
# Refresh cache because all data are computed with SQL requests
|
||||
self.refresh()
|
||||
|
||||
def _inject_account_values(self):
|
||||
"""Inject report values for report_open_items_account."""
|
||||
query_inject_account = """
|
||||
WITH
|
||||
accounts AS
|
||||
(
|
||||
SELECT
|
||||
a.id,
|
||||
a.code,
|
||||
a.name,
|
||||
a.user_type_id
|
||||
FROM
|
||||
account_account a
|
||||
INNER JOIN
|
||||
account_move_line ml ON a.id = ml.account_id AND ml.date <= %s
|
||||
"""
|
||||
if self.filter_partner_ids:
|
||||
query_inject_account += """
|
||||
INNER JOIN
|
||||
res_partner p ON ml.partner_id = p.id
|
||||
"""
|
||||
if self.only_posted_moves:
|
||||
query_inject_account += """
|
||||
INNER JOIN
|
||||
account_move m ON ml.move_id = m.id AND m.state = 'posted'
|
||||
"""
|
||||
query_inject_account += """
|
||||
WHERE
|
||||
a.company_id = %s
|
||||
AND a.reconcile IS true
|
||||
"""
|
||||
if self.filter_account_ids:
|
||||
query_inject_account += """
|
||||
AND
|
||||
a.id IN %s
|
||||
"""
|
||||
if self.filter_partner_ids:
|
||||
query_inject_account += """
|
||||
AND
|
||||
p.id IN %s
|
||||
"""
|
||||
query_inject_account += """
|
||||
GROUP BY
|
||||
a.id
|
||||
)
|
||||
INSERT INTO
|
||||
report_open_items_account
|
||||
(
|
||||
report_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
account_id,
|
||||
code,
|
||||
name
|
||||
)
|
||||
SELECT
|
||||
%s AS report_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
a.id AS account_id,
|
||||
a.code,
|
||||
a.name
|
||||
FROM
|
||||
accounts a
|
||||
"""
|
||||
query_inject_account_params = (
|
||||
self.date_at,
|
||||
self.company_id.id,
|
||||
)
|
||||
if self.filter_account_ids:
|
||||
query_inject_account_params += (
|
||||
tuple(self.filter_account_ids.ids),
|
||||
)
|
||||
if self.filter_partner_ids:
|
||||
query_inject_account_params += (
|
||||
tuple(self.filter_partner_ids.ids),
|
||||
)
|
||||
query_inject_account_params += (
|
||||
self.id,
|
||||
self.env.uid,
|
||||
)
|
||||
self.env.cr.execute(query_inject_account, query_inject_account_params)
|
||||
|
||||
def _inject_partner_values(self):
|
||||
""" Inject report values for report_open_items_partner. """
|
||||
# pylint: disable=sql-injection
|
||||
query_inject_partner = """
|
||||
WITH
|
||||
accounts_partners AS
|
||||
(
|
||||
SELECT
|
||||
ra.id AS report_account_id,
|
||||
a.id AS account_id,
|
||||
at.include_initial_balance AS include_initial_balance,
|
||||
p.id AS partner_id,
|
||||
COALESCE(
|
||||
CASE
|
||||
WHEN
|
||||
NULLIF(p.name, '') IS NOT NULL
|
||||
AND NULLIF(p.ref, '') IS NOT NULL
|
||||
THEN p.name || ' (' || p.ref || ')'
|
||||
ELSE p.name
|
||||
END,
|
||||
'""" + _('No partner allocated') + """'
|
||||
) AS partner_name
|
||||
FROM
|
||||
report_open_items_account ra
|
||||
INNER JOIN
|
||||
account_account a ON ra.account_id = a.id
|
||||
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 <= %s
|
||||
"""
|
||||
if self.only_posted_moves:
|
||||
query_inject_partner += """
|
||||
INNER JOIN
|
||||
account_move m ON ml.move_id = m.id AND m.state = 'posted'
|
||||
"""
|
||||
query_inject_partner += """
|
||||
LEFT JOIN
|
||||
res_partner p ON ml.partner_id = p.id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
"""
|
||||
if self.filter_partner_ids:
|
||||
query_inject_partner += """
|
||||
AND
|
||||
p.id IN %s
|
||||
"""
|
||||
query_inject_partner += """
|
||||
GROUP BY
|
||||
ra.id,
|
||||
a.id,
|
||||
p.id,
|
||||
at.include_initial_balance
|
||||
)
|
||||
INSERT INTO
|
||||
report_open_items_partner
|
||||
(
|
||||
report_account_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
partner_id,
|
||||
name
|
||||
)
|
||||
SELECT
|
||||
ap.report_account_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
ap.partner_id,
|
||||
ap.partner_name
|
||||
FROM
|
||||
accounts_partners ap
|
||||
"""
|
||||
query_inject_partner_params = (
|
||||
self.date_at,
|
||||
self.id,
|
||||
)
|
||||
if self.filter_partner_ids:
|
||||
query_inject_partner_params += (
|
||||
tuple(self.filter_partner_ids.ids),
|
||||
)
|
||||
query_inject_partner_params += (
|
||||
self.env.uid,
|
||||
)
|
||||
self.env.cr.execute(query_inject_partner, query_inject_partner_params)
|
||||
|
||||
def _get_line_sub_query_move_lines(self,
|
||||
only_empty_partner_line=False,
|
||||
positive_balance=True):
|
||||
""" Return subquery used to compute sum amounts on lines """
|
||||
sub_query = """
|
||||
SELECT
|
||||
ml.id,
|
||||
ml.balance,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ml_past.id IS NOT NULL
|
||||
THEN pr.amount
|
||||
ELSE NULL
|
||||
END
|
||||
) AS partial_amount,
|
||||
ml.amount_currency,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ml_past.id IS NOT NULL
|
||||
THEN pr.amount_currency
|
||||
ELSE NULL
|
||||
END
|
||||
) AS partial_amount_currency,
|
||||
ml.currency_id
|
||||
FROM
|
||||
report_open_items_partner rp
|
||||
INNER JOIN
|
||||
report_open_items_account ra
|
||||
ON rp.report_account_id = ra.id
|
||||
INNER JOIN
|
||||
account_move_line ml
|
||||
ON ra.account_id = ml.account_id
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
sub_query += """
|
||||
AND rp.partner_id = ml.partner_id
|
||||
"""
|
||||
elif only_empty_partner_line:
|
||||
sub_query += """
|
||||
AND ml.partner_id IS NULL
|
||||
"""
|
||||
if not positive_balance:
|
||||
sub_query += """
|
||||
LEFT JOIN
|
||||
account_partial_reconcile pr
|
||||
ON ml.balance < 0 AND pr.credit_move_id = ml.id
|
||||
LEFT JOIN
|
||||
account_move_line ml_future
|
||||
ON ml.balance < 0 AND pr.debit_move_id = ml_future.id
|
||||
AND ml_future.date > %s
|
||||
LEFT JOIN
|
||||
account_move_line ml_past
|
||||
ON ml.balance < 0 AND pr.debit_move_id = ml_past.id
|
||||
AND ml_past.date <= %s
|
||||
"""
|
||||
else:
|
||||
sub_query += """
|
||||
LEFT JOIN
|
||||
account_partial_reconcile pr
|
||||
ON ml.balance > 0 AND pr.debit_move_id = ml.id
|
||||
LEFT JOIN
|
||||
account_move_line ml_future
|
||||
ON ml.balance > 0 AND pr.credit_move_id = ml_future.id
|
||||
AND ml_future.date > %s
|
||||
LEFT JOIN
|
||||
account_move_line ml_past
|
||||
ON ml.balance > 0 AND pr.credit_move_id = ml_past.id
|
||||
AND ml_past.date <= %s
|
||||
"""
|
||||
sub_query += """
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
GROUP BY
|
||||
ml.id,
|
||||
ml.balance,
|
||||
ml.amount_currency
|
||||
HAVING
|
||||
(
|
||||
ml.full_reconcile_id IS NULL
|
||||
OR MAX(ml_future.id) IS NOT NULL
|
||||
)
|
||||
"""
|
||||
return sub_query
|
||||
|
||||
def _inject_line_values(self, only_empty_partner_line=False):
|
||||
""" Inject report values for report_open_items_move_line.
|
||||
|
||||
The "only_empty_partner_line" value is used
|
||||
to compute data without partner.
|
||||
"""
|
||||
query_inject_move_line = """
|
||||
WITH
|
||||
move_lines_amount AS
|
||||
(
|
||||
"""
|
||||
query_inject_move_line += self._get_line_sub_query_move_lines(
|
||||
only_empty_partner_line=only_empty_partner_line,
|
||||
positive_balance=True
|
||||
)
|
||||
query_inject_move_line += """
|
||||
UNION
|
||||
"""
|
||||
query_inject_move_line += self._get_line_sub_query_move_lines(
|
||||
only_empty_partner_line=only_empty_partner_line,
|
||||
positive_balance=False
|
||||
)
|
||||
query_inject_move_line += """
|
||||
),
|
||||
move_lines AS
|
||||
(
|
||||
SELECT
|
||||
id,
|
||||
CASE
|
||||
WHEN SUM(partial_amount) > 0
|
||||
THEN
|
||||
CASE
|
||||
WHEN balance > 0
|
||||
THEN balance - SUM(partial_amount)
|
||||
ELSE balance + SUM(partial_amount)
|
||||
END
|
||||
ELSE balance
|
||||
END AS amount_residual,
|
||||
CASE
|
||||
WHEN SUM(partial_amount_currency) > 0
|
||||
THEN
|
||||
CASE
|
||||
WHEN amount_currency > 0
|
||||
THEN amount_currency - SUM(partial_amount_currency)
|
||||
ELSE amount_currency + SUM(partial_amount_currency)
|
||||
END
|
||||
ELSE amount_currency
|
||||
END AS amount_residual_currency,
|
||||
currency_id
|
||||
FROM
|
||||
move_lines_amount
|
||||
GROUP BY
|
||||
id,
|
||||
balance,
|
||||
amount_currency,
|
||||
currency_id
|
||||
)
|
||||
INSERT INTO
|
||||
report_open_items_move_line
|
||||
(
|
||||
report_partner_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
move_line_id,
|
||||
date,
|
||||
date_due,
|
||||
entry,
|
||||
journal,
|
||||
account,
|
||||
partner,
|
||||
label,
|
||||
amount_total_due,
|
||||
amount_residual,
|
||||
currency_name,
|
||||
amount_total_due_currency,
|
||||
amount_residual_currency
|
||||
)
|
||||
SELECT
|
||||
rp.id AS report_partner_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
ml.id AS move_line_id,
|
||||
ml.date,
|
||||
ml.date_maturity,
|
||||
m.name AS entry,
|
||||
j.code AS journal,
|
||||
a.code AS account,
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
CASE
|
||||
WHEN
|
||||
NULLIF(p.name, '') IS NOT NULL
|
||||
AND NULLIF(p.ref, '') IS NOT NULL
|
||||
THEN p.name || ' (' || p.ref || ')'
|
||||
ELSE p.name
|
||||
END AS partner,
|
||||
"""
|
||||
elif only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
'""" + _('No partner allocated') + """' AS partner,
|
||||
"""
|
||||
query_inject_move_line += """
|
||||
CONCAT_WS(' - ', NULLIF(ml.ref, ''), NULLIF(ml.name, '')) AS label,
|
||||
ml.balance,
|
||||
ml2.amount_residual,
|
||||
c.name AS currency_name,
|
||||
ml.amount_currency,
|
||||
ml2.amount_residual_currency
|
||||
FROM
|
||||
report_open_items_partner rp
|
||||
INNER JOIN
|
||||
report_open_items_account ra ON rp.report_account_id = ra.id
|
||||
INNER JOIN
|
||||
account_move_line ml ON ra.account_id = ml.account_id
|
||||
INNER JOIN
|
||||
move_lines ml2
|
||||
ON ml.id = ml2.id
|
||||
AND ml2.amount_residual IS NOT NULL
|
||||
AND ml2.amount_residual != 0
|
||||
INNER JOIN
|
||||
account_move m ON ml.move_id = m.id
|
||||
INNER JOIN
|
||||
account_journal j ON ml.journal_id = j.id
|
||||
INNER JOIN
|
||||
account_account a ON ml.account_id = a.id
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
INNER JOIN
|
||||
res_partner p
|
||||
ON ml.partner_id = p.id AND rp.partner_id = p.id
|
||||
"""
|
||||
query_inject_move_line += """
|
||||
LEFT JOIN
|
||||
account_full_reconcile fr ON ml.full_reconcile_id = fr.id
|
||||
LEFT JOIN
|
||||
res_currency c ON ml2.currency_id = c.id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
AND
|
||||
ml.date <= %s
|
||||
"""
|
||||
if self.only_posted_moves:
|
||||
query_inject_move_line += """
|
||||
AND
|
||||
m.state = 'posted'
|
||||
"""
|
||||
if only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
AND
|
||||
ml.partner_id IS NULL
|
||||
AND
|
||||
rp.partner_id IS NULL
|
||||
"""
|
||||
if not only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
ORDER BY
|
||||
a.code, p.name, ml.date, ml.id
|
||||
"""
|
||||
elif only_empty_partner_line:
|
||||
query_inject_move_line += """
|
||||
ORDER BY
|
||||
a.code, ml.date, ml.id
|
||||
"""
|
||||
self.env.cr.execute(
|
||||
query_inject_move_line,
|
||||
(self.date_at,
|
||||
self.date_at,
|
||||
self.id,
|
||||
self.date_at,
|
||||
self.date_at,
|
||||
self.id,
|
||||
self.env.uid,
|
||||
self.id,
|
||||
self.date_at,)
|
||||
)
|
||||
|
||||
def _compute_partners_and_accounts_cumul(self):
|
||||
""" Compute cumulative amount for
|
||||
report_open_items_partner and report_open_items_account.
|
||||
"""
|
||||
query_compute_partners_cumul = """
|
||||
UPDATE
|
||||
report_open_items_partner
|
||||
SET
|
||||
final_amount_residual =
|
||||
(
|
||||
SELECT
|
||||
SUM(rml.amount_residual) AS final_amount_residual
|
||||
FROM
|
||||
report_open_items_move_line rml
|
||||
WHERE
|
||||
rml.report_partner_id = report_open_items_partner.id
|
||||
)
|
||||
WHERE
|
||||
id IN
|
||||
(
|
||||
SELECT
|
||||
rp.id
|
||||
FROM
|
||||
report_open_items_account ra
|
||||
INNER JOIN
|
||||
report_open_items_partner rp
|
||||
ON ra.id = rp.report_account_id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
)
|
||||
"""
|
||||
params_compute_partners_cumul = (self.id,)
|
||||
self.env.cr.execute(query_compute_partners_cumul,
|
||||
params_compute_partners_cumul)
|
||||
query_compute_accounts_cumul = """
|
||||
UPDATE
|
||||
report_open_items_account
|
||||
SET
|
||||
final_amount_residual =
|
||||
(
|
||||
SELECT
|
||||
SUM(rp.final_amount_residual) AS final_amount_residual
|
||||
FROM
|
||||
report_open_items_partner rp
|
||||
WHERE
|
||||
rp.report_account_id = report_open_items_account.id
|
||||
)
|
||||
WHERE
|
||||
report_id = %s
|
||||
"""
|
||||
params_compute_accounts_cumul = (self.id,)
|
||||
self.env.cr.execute(query_compute_accounts_cumul,
|
||||
params_compute_accounts_cumul)
|
||||
|
||||
def _clean_partners_and_accounts(self,
|
||||
only_delete_account_balance_at_0=False):
|
||||
""" Delete empty data for
|
||||
report_open_items_partner and report_open_items_account.
|
||||
|
||||
The "only_delete_account_balance_at_0" value is used
|
||||
to delete also the data with cumulative amounts at 0.
|
||||
"""
|
||||
query_clean_partners = """
|
||||
DELETE FROM
|
||||
report_open_items_partner
|
||||
WHERE
|
||||
id IN
|
||||
(
|
||||
SELECT
|
||||
DISTINCT rp.id
|
||||
FROM
|
||||
report_open_items_account ra
|
||||
INNER JOIN
|
||||
report_open_items_partner rp
|
||||
ON ra.id = rp.report_account_id
|
||||
LEFT JOIN
|
||||
report_open_items_move_line rml
|
||||
ON rp.id = rml.report_partner_id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
"""
|
||||
if not only_delete_account_balance_at_0:
|
||||
query_clean_partners += """
|
||||
AND rml.id IS NULL
|
||||
"""
|
||||
elif only_delete_account_balance_at_0:
|
||||
query_clean_partners += """
|
||||
AND (
|
||||
rp.final_amount_residual IS NULL
|
||||
OR rp.final_amount_residual = 0
|
||||
)
|
||||
"""
|
||||
query_clean_partners += """
|
||||
)
|
||||
"""
|
||||
params_clean_partners = (self.id,)
|
||||
self.env.cr.execute(query_clean_partners, params_clean_partners)
|
||||
query_clean_accounts = """
|
||||
DELETE FROM
|
||||
report_open_items_account
|
||||
WHERE
|
||||
id IN
|
||||
(
|
||||
SELECT
|
||||
DISTINCT ra.id
|
||||
FROM
|
||||
report_open_items_account ra
|
||||
LEFT JOIN
|
||||
report_open_items_partner rp
|
||||
ON ra.id = rp.report_account_id
|
||||
WHERE
|
||||
ra.report_id = %s
|
||||
"""
|
||||
if not only_delete_account_balance_at_0:
|
||||
query_clean_accounts += """
|
||||
AND rp.id IS NULL
|
||||
"""
|
||||
elif only_delete_account_balance_at_0:
|
||||
query_clean_accounts += """
|
||||
AND (
|
||||
ra.final_amount_residual IS NULL
|
||||
OR ra.final_amount_residual = 0
|
||||
)
|
||||
"""
|
||||
query_clean_accounts += """
|
||||
)
|
||||
"""
|
||||
params_clean_accounts = (self.id,)
|
||||
self.env.cr.execute(query_clean_accounts, params_clean_accounts)
|
||||
|
||||
def _compute_has_second_currency(self):
|
||||
""" Compute "has_second_currency" flag which will used for display."""
|
||||
query_update_has_second_currency = """
|
||||
UPDATE
|
||||
report_open_items
|
||||
SET
|
||||
has_second_currency =
|
||||
(
|
||||
SELECT
|
||||
TRUE
|
||||
FROM
|
||||
report_open_items_move_line l
|
||||
INNER JOIN
|
||||
report_open_items_partner p
|
||||
ON l.report_partner_id = p.id
|
||||
INNER JOIN
|
||||
report_open_items_account a
|
||||
ON p.report_account_id = a.id
|
||||
WHERE
|
||||
a.report_id = %s
|
||||
AND l.currency_name IS NOT NULL
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE id = %s
|
||||
"""
|
||||
params = (self.id,) * 2
|
||||
self.env.cr.execute(query_update_has_second_currency, params)
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class OpenItemsXslx(models.AbstractModel):
|
||||
_name = 'report.a_f_r.report_open_items_xlsx'
|
||||
_inherit = 'report.account_financial_report.abstract_report_xlsx'
|
||||
|
||||
def _get_report_name(self):
|
||||
return _('Open Items')
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
return {
|
||||
0: {'header': _('Date'), 'field': 'date', 'width': 11},
|
||||
1: {'header': _('Entry'), 'field': 'entry', 'width': 18},
|
||||
2: {'header': _('Journal'), 'field': 'journal', 'width': 8},
|
||||
3: {'header': _('Account'), 'field': 'account', 'width': 9},
|
||||
4: {'header': _('Partner'), 'field': 'partner', 'width': 25},
|
||||
5: {'header': _('Ref - Label'), 'field': 'label', 'width': 40},
|
||||
6: {'header': _('Due date'), 'field': 'date_due', 'width': 11},
|
||||
7: {'header': _('Original'),
|
||||
'field': 'amount_total_due',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
8: {'header': _('Residual'),
|
||||
'field': 'amount_residual',
|
||||
'field_final_balance': 'final_amount_residual',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
9: {'header': _('Cur.'), 'field': 'currency_name', 'width': 7},
|
||||
10: {'header': _('Cur. Original'),
|
||||
'field': 'amount_total_due_currency',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
11: {'header': _('Cur. Residual'),
|
||||
'field': 'amount_residual_currency',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_('Date at filter'), report.date_at],
|
||||
[_('Target moves filter'),
|
||||
_('All posted entries') if report.only_posted_moves
|
||||
else _('All entries')],
|
||||
[_('Account balance at 0 filter'),
|
||||
_('Hide') if report.hide_account_balance_at_0 else _('Show')],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_final_balance_name(self):
|
||||
return 5
|
||||
|
||||
def _get_col_pos_final_balance_label(self):
|
||||
return 5
|
||||
|
||||
def _generate_report_content(self, workbook, report):
|
||||
# For each account
|
||||
for account in report.account_ids:
|
||||
# Write account title
|
||||
self.write_array_title(account.code + ' - ' + account.name)
|
||||
|
||||
# For each partner
|
||||
for partner in account.partner_ids:
|
||||
# Write partner title
|
||||
self.write_array_title(partner.name)
|
||||
|
||||
# Display array header for move lines
|
||||
self.write_array_header()
|
||||
|
||||
# Display account move lines
|
||||
for line in partner.move_line_ids:
|
||||
self.write_line(line)
|
||||
|
||||
# Display ending balance line for partner
|
||||
self.write_ending_balance(partner, 'partner')
|
||||
|
||||
# Line break
|
||||
self.row_pos += 1
|
||||
|
||||
# Display ending balance line for account
|
||||
self.write_ending_balance(account, 'account')
|
||||
|
||||
# 2 lines break
|
||||
self.row_pos += 2
|
||||
|
||||
def write_ending_balance(self, my_object, type_object):
|
||||
"""Specific function to write ending balance for Open Items"""
|
||||
if type_object == 'partner':
|
||||
name = my_object.name
|
||||
label = _('Partner ending balance')
|
||||
elif type_object == 'account':
|
||||
name = my_object.code + ' - ' + my_object.name
|
||||
label = _('Ending balance')
|
||||
super(OpenItemsXslx, self).write_ending_balance(my_object, name, label)
|
|
@ -0,0 +1,432 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_qweb">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_base"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="show_move_line_details" t-value="o.show_move_line_details"/>
|
||||
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">Aged Partner Balance</t>
|
||||
<t t-set="company_name" t-value="o.company_id.name"/>
|
||||
|
||||
<div class="page">
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_filters"/>
|
||||
|
||||
<t t-foreach="o.account_ids" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;"/>
|
||||
<div class="act_as_caption account_title" style="width: 1141px !important;">
|
||||
<span t-field="account.code"/>
|
||||
-
|
||||
<span t-field="account.name"/>
|
||||
</div>
|
||||
|
||||
<!-- Display account lines -->
|
||||
<t t-if="not show_move_line_details">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<!-- Display account header -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_lines_header"/>
|
||||
|
||||
<t t-foreach="account.partner_ids" t-as="partner">
|
||||
|
||||
<!-- Display one line per partner -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_lines"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_account_ending_cumul"/>
|
||||
</t>
|
||||
|
||||
<!-- Display account move lines -->
|
||||
<t t-if="show_move_line_details">
|
||||
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="account.partner_ids" t-as="partner">
|
||||
<div class="page_break">
|
||||
<!-- Display partner header -->
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-field="partner.name"/>
|
||||
</div>
|
||||
|
||||
<!-- Display partner move lines -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_move_lines"/>
|
||||
|
||||
<!-- Display partner footer -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_partner_ending_cumul">
|
||||
<t t-set="partner_cumul_line" t-value="partner.line_ids"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_account_ending_cumul"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_filters">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date at filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
<span t-field="o.date_at"/>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="o.only_posted_moves">All posted entries</t>
|
||||
<t t-if="not o.only_posted_moves">All entries</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_lines_header">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 370px;">Partner</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 110px;">Residual</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell" style="width: 110px;">Current</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell" style="width: 110px;">Age ≤ 30 d.</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell" style="width: 110px;">Age ≤ 60 d.</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell" style="width: 110px;">Age ≤ 90 d.</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell" style="width: 110px;">Age ≤ 120 d.</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell" style="width: 110px;">Older</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_lines">
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="partner.line_ids" t-as="line">
|
||||
<!-- # lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.partner"/>
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_residual"/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.current"/>
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_30_days"/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_60_days"/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_90_days"/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_120_days"/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.older"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_move_lines">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<!-- Display table headers for move lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 60px;">Date</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 100px;">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 40px;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 50px;">Account</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 120px;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 220px;">Ref - Label</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;">Due date</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 70px;">Residual</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell" style="width: 70px;">Current</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell" style="width: 70px;">Age ≤ 30 d.</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell" style="width: 70px;">Age ≤ 60 d.</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell" style="width: 70px;">Age ≤ 90 d.</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell" style="width: 70px;">Age ≤ 120 d.</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell" style="width: 70px;">Older</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Display each move lines -->
|
||||
<t t-foreach="partner.move_line_ids" t-as="line">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.date"/>
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.entry"/>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.journal"/>
|
||||
</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.account"/>
|
||||
</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.partner"/>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.label"/>
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.date_due"/>
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_residual"/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.current"/>
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_30_days"/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_60_days"/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_90_days"/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.age_120_days"/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.older"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_partner_ending_cumul">
|
||||
<!-- Display ending balance line for partner -->
|
||||
<div class="act_as_table list_table" style="width: 1141px !important;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell right" style="width: 590px;">Partner cumul aged balance</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;"/>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.amount_residual"/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.current"/>
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.age_30_days"/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.age_60_days"/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.age_90_days"/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.age_120_days"/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="partner_cumul_line.older"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_aged_partner_balance_account_ending_cumul">
|
||||
<!-- Display ending balance line for account -->
|
||||
<div class="act_as_table list_table" style="width: 1141px !important;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<t t-if="not show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 370px;">Total</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_amount_residual"/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_current"/>
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_age_30_days"/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_age_60_days"/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_age_90_days"/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_age_120_days"/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 110px;">
|
||||
<span t-field="account.cumul_older"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 590px;">Total</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;"/>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_amount_residual"/>
|
||||
</div>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_current"/>
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_age_30_days"/>
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_age_60_days"/>
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_age_90_days"/>
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_age_120_days"/>
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 70px;">
|
||||
<span t-field="account.cumul_older"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div class="act_as_row" style="font-weight: bold; font-style: italic;">
|
||||
<t t-if="not show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 370px;">Percents</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"/>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_current"/>%
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_age_30_days"/>%
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_age_60_days"/>%
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_age_90_days"/>%
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_age_120_days"/>
|
||||
%
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.percent_older"/>%
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="show_move_line_details">
|
||||
<!--## total-->
|
||||
<div class="act_as_cell right" style="width: 590px;">Percents</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;"/>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"/>
|
||||
<!--## current-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_current"/>%
|
||||
</div>
|
||||
<!--## age_30_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_age_30_days"/>%
|
||||
</div>
|
||||
<!--## age_60_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_age_60_days"/>%
|
||||
</div>
|
||||
<!--## age_90_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_age_90_days"/>%
|
||||
</div>
|
||||
<!--## age_120_days-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_age_120_days"/>%
|
||||
</div>
|
||||
<!--## older-->
|
||||
<div class="act_as_cell amount" style="width: 70px;"><span t-field="account.percent_older"/>%
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,263 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="report_general_ledger_qweb">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_general_ledger_base"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_general_ledger_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="show_cost_center" t-value="o.show_cost_center"/>
|
||||
<t t-set="has_second_currency" t-value="o.has_second_currency"/>
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">General Ledger</t>
|
||||
<t t-set="company_name" t-value="o.company_id.name"/>
|
||||
|
||||
<div class="page">
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_general_ledger_filters"/>
|
||||
|
||||
<t t-foreach="o.account_ids" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;"/>
|
||||
<div class="act_as_caption account_title" style="width: 1141px !important;">
|
||||
<span t-field="account.code"/> - <span t-field="account.name"/>
|
||||
</div>
|
||||
|
||||
<t t-if="not account.partner_ids">
|
||||
<!-- Display account move lines without partner regroup -->
|
||||
<t t-call="account_financial_report.report_general_ledger_lines">
|
||||
<t t-set="account_or_partner_object" t-value="account"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-if="account.partner_ids">
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="account.partner_ids" t-as="partner">
|
||||
<div class="page_break">
|
||||
<!-- Display partner header -->
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-field="partner.name"/>
|
||||
</div>
|
||||
|
||||
<!-- Display partner move lines -->
|
||||
<t t-call="account_financial_report.report_general_ledger_lines">
|
||||
<t t-set="account_or_partner_object" t-value="partner"/>
|
||||
</t>
|
||||
|
||||
<!-- Display partner footer -->
|
||||
<t t-call="account_financial_report.report_general_ledger_ending_cumul">
|
||||
<t t-set="account_or_partner_object" t-value="partner"/>
|
||||
<t t-set="type" t-value='"partner_type"'/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_general_ledger_ending_cumul">
|
||||
<t t-set="account_or_partner_object" t-value="account"/>
|
||||
<t t-set="type" t-value='"account_type"'/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_general_ledger_filters">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date range filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account balance at 0 filter</div>
|
||||
<div class="act_as_cell">Centralize filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
From: <span t-field="o.date_from"/> To: <span t-field="o.date_to"/>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="o.only_posted_moves">All posted entries</t>
|
||||
<t t-if="not o.only_posted_moves">All entries</t>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="o.centralize">Yes</t>
|
||||
<t t-if="not o.centralize">No</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_general_ledger_lines">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 60px;">Date</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 100px;">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 40px;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 50px;">Account</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 140px;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 290px;">Ref - Label</div>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell" style="width: 100px;">Cost center</div>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell" style="width: 25px;">Rec.</div>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Debit</div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Credit</div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Cumul. Bal.</div>
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell" style="width: 35px;">Cur.</div>
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Amount cur.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Display first line with initial balance -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell amount">Initial balance</div>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell"/>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_debit"/></div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_credit"/></div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_balance"/></div>
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell"/>
|
||||
</div>
|
||||
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="account_or_partner_object.move_line_ids" t-as="line">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left"><span t-field="line.date"/></div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-set="res_model" t-value="'account.move'"/>
|
||||
<span>
|
||||
<a t-att-data-active-id="line.move_line_id.move_id.id"
|
||||
t-att-data-res-model="res_model"
|
||||
class="o_account_financial_reports_web_action"
|
||||
style="color: black;">
|
||||
<t t-raw="line.entry"/></a>
|
||||
</span>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left"><span t-field="line.journal"/></div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left"><span t-field="line.account"/></div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-set="res_model" t-value="'res.partner'"/>
|
||||
<span t-if="line.partner">
|
||||
<a t-att-data-active-id="line.move_line_id.partner_id.id"
|
||||
t-att-data-res-model="res_model"
|
||||
class="o_account_financial_reports_web_action"
|
||||
style="color: black;"><t t-raw="line.partner"/></a>
|
||||
</span>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left"><span t-field="line.label"/></div>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell left"><span t-field="line.cost_center"/></div>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell"><span t-field="line.matching_number"/></div>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount"><span t-field="line.debit"/></div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount"><span t-field="line.credit"/></div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount"><span t-field="line.cumul_balance"/></div>
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell"><span t-field="line.currency_name"/></div>
|
||||
<t t-if="line.currency_name">
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount"><span t-field="line.amount_currency"/></div>
|
||||
</t>
|
||||
<t t-if="not line.currency_name">
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_general_ledger_ending_cumul">
|
||||
<!-- Display ending balance line for account or partner -->
|
||||
<div class="act_as_table list_table" style="width: 1141px !important;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<t t-if='type == "account_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 380px;"><span t-field="account_or_partner_object.code"/> - <span t-field="account_or_partner_object.name"/></div>
|
||||
<div class="act_as_cell right" style="width: 290px;">Ending balance</div>
|
||||
</t>
|
||||
<t t-if='type == "partner_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 380px;"/>
|
||||
<div class="act_as_cell right" style="width: 290px;">Partner ending balance</div>
|
||||
</t>
|
||||
<t t-if="show_cost_center">
|
||||
<!--## cost_center-->
|
||||
<div class="act_as_cell" style="width: 100px;"/>
|
||||
</t>
|
||||
<!--## matching_number-->
|
||||
<div class="act_as_cell" style="width: 25px;"/>
|
||||
<!--## debit-->
|
||||
<div class="act_as_cell amount" style="width: 75px;"><span t-field="account_or_partner_object.final_debit"/></div>
|
||||
<!--## credit-->
|
||||
<div class="act_as_cell amount" style="width: 75px;"><span t-field="account_or_partner_object.final_credit"/></div>
|
||||
<!--## balance cumulated-->
|
||||
<div class="act_as_cell amount" style="width: 75px; padding-right: 1px;"><span t-field="account_or_partner_object.final_balance"/></div>
|
||||
<!--## currency_name + amount_currency-->
|
||||
<div class="act_as_cell" style="width: 110px;"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="account_financial_report.internal_layout">
|
||||
<div class="header">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<span t-esc="title"/>
|
||||
</div>
|
||||
<div class="col-xs-6 text-right">
|
||||
<span t-esc="company_name"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article">
|
||||
<link href="/account_financial_report/static/src/css/report.css" rel="stylesheet"/>
|
||||
<t t-raw="0" />
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="row">
|
||||
<div class="col-xs-6 custom_footer">
|
||||
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</div>
|
||||
<div class="col-xs-6 text-right custom_footer">
|
||||
<ul class="list-inline">
|
||||
<li><span class="page"/></li>
|
||||
<li>/</li>
|
||||
<li><span class="topage"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,233 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="account_financial_report.report_open_items_qweb">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_open_items_base"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_open_items_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="has_second_currency" t-value="o.has_second_currency"/>
|
||||
|
||||
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">Open Items</t>
|
||||
<t t-set="company_name" t-value="o.company_id.name"/>
|
||||
|
||||
<div class="page">
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_open_items_filters"/>
|
||||
|
||||
<t t-foreach="o.account_ids" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;"/>
|
||||
<div class="act_as_caption account_title" style="width: 1141px !important;">
|
||||
<span t-field="account.code"/>
|
||||
-
|
||||
<span t-field="account.name"/>
|
||||
</div>
|
||||
|
||||
<!-- Display account partners -->
|
||||
<t t-foreach="account.partner_ids" t-as="partner">
|
||||
<div class="page_break">
|
||||
<!-- Display partner header -->
|
||||
<div class="act_as_caption account_title">
|
||||
<span t-field="partner.name"/>
|
||||
</div>
|
||||
|
||||
<!-- Display partner move lines -->
|
||||
<t t-call="account_financial_report.report_open_items_lines"/>
|
||||
|
||||
<!-- Display partner footer -->
|
||||
<t t-call="account_financial_report.report_open_items_ending_cumul">
|
||||
<t t-set="account_or_partner_object" t-value="partner"/>
|
||||
<t t-set="type" t-value='"partner_type"'/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_open_items_ending_cumul">
|
||||
<t t-set="account_or_partner_object" t-value="account"/>
|
||||
<t t-set="type" t-value='"account_type"'/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_open_items_filters">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date at filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account balance at 0 filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
<span t-field="o.date_at"/>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="o.only_posted_moves">All posted entries</t>
|
||||
<t t-if="not o.only_posted_moves">All entries</t>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_open_items_lines">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell first_column" style="width: 60px;">Date</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell" style="width: 100px;">Entry</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell" style="width: 40px;">Journal</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell" style="width: 50px;">Account</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell" style="width: 140px;">Partner</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell" style="width: 290px;">Ref - Label</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;">Due date</div>
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell" style="width: 75px;">Original</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell" style="width: 75px;">Residual</div>
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell" style="width: 35px;">Cur.</div>
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Cur. Original</div>
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">Cur. Residual</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="partner.move_line_ids" t-as="line">
|
||||
<!-- # lines or centralized lines -->
|
||||
<div class="act_as_row lines">
|
||||
<!--## date-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.date"/>
|
||||
</div>
|
||||
<!--## move-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-set="res_model" t-value="'account.move'"/>
|
||||
<span>
|
||||
<a t-att-data-active-id="line.move_line_id.move_id.id"
|
||||
t-att-data-res-model="res_model"
|
||||
class="o_account_financial_reports_web_action"
|
||||
style="color: black;">
|
||||
<t t-raw="line.entry"/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<!--## journal-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.journal"/>
|
||||
</div>
|
||||
<!--## account code-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.account"/>
|
||||
</div>
|
||||
<!--## partner-->
|
||||
<div class="act_as_cell left">
|
||||
<t t-set="res_model" t-value="'res.partner'"/>
|
||||
<span t-if="line.partner">
|
||||
<a t-att-data-active-id="line.move_line_id.partner_id.id"
|
||||
t-att-data-res-model="res_model"
|
||||
class="o_account_financial_reports_web_action"
|
||||
style="color: black;">
|
||||
<t t-raw="line.partner"/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<!--## ref - label-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.label"/>
|
||||
</div>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell left">
|
||||
<span t-field="line.date_due"/>
|
||||
</div>
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_total_due"/>
|
||||
</div>
|
||||
<!--## amount_residual-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_residual"/>
|
||||
</div>
|
||||
<!--## currency_name-->
|
||||
<div class="act_as_cell">
|
||||
<span t-field="line.currency_name"/>
|
||||
</div>
|
||||
<t t-if="line.currency_name">
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_total_due_currency"/>
|
||||
</div>
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell amount">
|
||||
<span t-field="line.amount_residual_currency"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not line.currency_name">
|
||||
<!--## amount_total_due_currency-->
|
||||
<div class="act_as_cell"/>
|
||||
<!--## amount_residual_currency-->
|
||||
<div class="act_as_cell"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_open_items_ending_cumul">
|
||||
<!-- Display ending balance line for account or partner -->
|
||||
<div class="act_as_table list_table" style="width: 1141px !important;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## date-->
|
||||
<t t-if='type == "account_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 380px;">
|
||||
<span t-field="account_or_partner_object.code"/>
|
||||
-
|
||||
<span t-field="account_or_partner_object.name"/>
|
||||
</div>
|
||||
<div class="act_as_cell right" style="width: 290px;">Ending balance</div>
|
||||
</t>
|
||||
<t t-if='type == "partner_type"'>
|
||||
<div class="act_as_cell first_column" style="width: 380px;"/>
|
||||
<div class="act_as_cell right" style="width: 290px;">Partner ending balance</div>
|
||||
</t>
|
||||
<!--## date_due-->
|
||||
<div class="act_as_cell" style="width: 60px;"/>
|
||||
<!--## amount_total_due-->
|
||||
<div class="act_as_cell amount" style="width: 75px;"/>
|
||||
<!--## amount_currency-->
|
||||
<div class="act_as_cell amount" style="width: 75px;">
|
||||
<span t-field="account_or_partner_object.final_amount_residual"/>
|
||||
</div>
|
||||
<!--## currency_name + amount_total_due_currency + amount_residual_currency -->
|
||||
<div class="act_as_cell" style="width: 185px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,155 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_qweb">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="account_financial_report.internal_layout">
|
||||
<t t-call="account_financial_report.report_trial_balance_base"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_base">
|
||||
<!-- Saved flag fields into variables, used to define columns display -->
|
||||
<t t-set="show_partner_details" t-value="o.show_partner_details"/>
|
||||
<!-- Defines global variables used by internal layout -->
|
||||
<t t-set="title">Trial Balance</t>
|
||||
<t t-set="company_name" t-value="o.company_id.name"/>
|
||||
<div class="page">
|
||||
<!-- Display filters -->
|
||||
<t t-call="account_financial_report.report_trial_balance_filters"/>
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;"/>
|
||||
|
||||
<!-- Display account lines -->
|
||||
<t t-if="not show_partner_details">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<!-- Display account header -->
|
||||
<t t-call="account_financial_report.report_trial_balance_lines_header"/>
|
||||
|
||||
<!-- Display each lines -->
|
||||
<t t-foreach="o.account_ids" t-as="line">
|
||||
<!-- Display account lines -->
|
||||
<t t-call="account_financial_report.report_trial_balance_line"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Display partner lines -->
|
||||
<t t-if="show_partner_details">
|
||||
<t t-foreach="o.account_ids" t-as="account">
|
||||
<div class="page_break">
|
||||
<!-- Display account header -->
|
||||
<div class="act_as_table list_table" style="margin-top: 10px;"/>
|
||||
<div class="act_as_caption account_title" style="width: 1141px !important;">
|
||||
<span t-field="account.code"/> - <span t-field="account.name"/>
|
||||
</div>
|
||||
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<!-- Display account/partner header -->
|
||||
<t t-call="account_financial_report.report_trial_balance_lines_header"/>
|
||||
|
||||
<!-- Display each partners -->
|
||||
<t t-foreach="account.partner_ids" t-as="line">
|
||||
<!-- Display partner line -->
|
||||
<t t-call="account_financial_report.report_trial_balance_line"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<!-- Display account footer -->
|
||||
<t t-call="account_financial_report.report_trial_balance_account_footer"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_filters">
|
||||
<div class="act_as_table data_table" style="width: 1140px !important;">
|
||||
<div class="act_as_row labels">
|
||||
<div class="act_as_cell">Date range filter</div>
|
||||
<div class="act_as_cell">Target moves filter</div>
|
||||
<div class="act_as_cell">Account balance at 0 filter</div>
|
||||
</div>
|
||||
<div class="act_as_row">
|
||||
<div class="act_as_cell">
|
||||
From: <span t-field="o.date_from"/> To: <span t-field="o.date_to"/>
|
||||
</div>
|
||||
<div class="act_as_cell">
|
||||
<t t-if="o.only_posted_moves">All posted entries</t>
|
||||
<t t-if="not o.only_posted_moves">All entries</t>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_lines_header">
|
||||
<!-- Display table headers for lines -->
|
||||
<div class="act_as_thead">
|
||||
<div class="act_as_row labels">
|
||||
<t t-if="not show_partner_details">
|
||||
<!--## Code-->
|
||||
<div class="act_as_cell" style="width: 100px;">Code</div>
|
||||
<!--## Account-->
|
||||
<div class="act_as_cell" style="width: 600px;">Account</div>
|
||||
</t>
|
||||
<t t-if="show_partner_details">
|
||||
<!--## Partner-->
|
||||
<div class="act_as_cell" style="width: 700px;">Partner</div>
|
||||
</t>
|
||||
<!--## Initial balance-->
|
||||
<div class="act_as_cell" style="width: 110px;">Initial balance</div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell" style="width: 110px;">Debit</div>
|
||||
<!--## Credit-->
|
||||
<div class="act_as_cell" style="width: 110px;">Credit</div>
|
||||
<!--## Ending balance-->
|
||||
<div class="act_as_cell" style="width: 110px;">Ending balance</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_line">
|
||||
<!-- # line -->
|
||||
<div class="act_as_row lines">
|
||||
<t t-if="not show_partner_details">
|
||||
<!--## Code-->
|
||||
<div class="act_as_cell left"><span t-field="line.code"/></div>
|
||||
</t>
|
||||
<!--## Account/Partner-->
|
||||
<div class="act_as_cell left"><span t-field="line.name"/></div>
|
||||
<!--## Initial balance-->
|
||||
<div class="act_as_cell amount"><span t-field="line.initial_balance"/></div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell amount"><span t-field="line.debit"/></div>
|
||||
<!--## Credit-->
|
||||
<div class="act_as_cell amount"><span t-field="line.credit"/></div>
|
||||
<!--## Ending balance-->
|
||||
<div class="act_as_cell amount"><span t-field="line.final_balance"/></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="account_financial_report.report_trial_balance_account_footer">
|
||||
<!-- Display account footer -->
|
||||
<div class="act_as_table list_table" style="width: 1141px !important;">
|
||||
<div class="act_as_row labels" style="font-weight: bold;">
|
||||
<!--## Account-->
|
||||
<div class="act_as_cell left" style="width: 700px;"><span t-field="account.code"/> - <span t-field="account.name"/></div>
|
||||
<!--## Initial balance-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.initial_balance"/></div>
|
||||
<!--## Debit-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.debit"/></div>
|
||||
<!--## Credit-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.credit"/></div>
|
||||
<!--## Ending balance-->
|
||||
<div class="act_as_cell amount" style="width: 110px;"><span t-field="account.final_balance"/></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,263 @@
|
|||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class TrialBalanceReport(models.TransientModel):
|
||||
""" Here, we just define class fields.
|
||||
For methods, go more bottom at this file.
|
||||
|
||||
The class hierarchy is :
|
||||
* TrialBalanceReport
|
||||
** TrialBalanceReportAccount
|
||||
*** TrialBalanceReportPartner
|
||||
If "show_partner_details" is selected
|
||||
"""
|
||||
|
||||
_name = 'report_trial_balance'
|
||||
|
||||
# Filters fields, used for data computation
|
||||
date_from = fields.Date()
|
||||
date_to = fields.Date()
|
||||
fy_start_date = fields.Date()
|
||||
only_posted_moves = fields.Boolean()
|
||||
hide_account_balance_at_0 = fields.Boolean()
|
||||
company_id = fields.Many2one(comodel_name='res.company')
|
||||
filter_account_ids = fields.Many2many(comodel_name='account.account')
|
||||
filter_partner_ids = fields.Many2many(comodel_name='res.partner')
|
||||
show_partner_details = fields.Boolean()
|
||||
|
||||
# General Ledger Report Data fields,
|
||||
# used as base for compute the data reports
|
||||
general_ledger_id = fields.Many2one(
|
||||
comodel_name='report_general_ledger'
|
||||
)
|
||||
|
||||
# Data fields, used to browse report data
|
||||
account_ids = fields.One2many(
|
||||
comodel_name='report_trial_balance_account',
|
||||
inverse_name='report_id'
|
||||
)
|
||||
|
||||
|
||||
class TrialBalanceReportAccount(models.TransientModel):
|
||||
_name = 'report_trial_balance_account'
|
||||
_order = 'code ASC'
|
||||
|
||||
report_id = fields.Many2one(
|
||||
comodel_name='report_trial_balance',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
account_id = fields.Many2one(
|
||||
'account.account',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
code = fields.Char()
|
||||
name = fields.Char()
|
||||
|
||||
initial_balance = fields.Float(digits=(16, 2))
|
||||
debit = fields.Float(digits=(16, 2))
|
||||
credit = fields.Float(digits=(16, 2))
|
||||
final_balance = fields.Float(digits=(16, 2))
|
||||
|
||||
# Data fields, used to browse report data
|
||||
partner_ids = fields.One2many(
|
||||
comodel_name='report_trial_balance_partner',
|
||||
inverse_name='report_account_id'
|
||||
)
|
||||
|
||||
|
||||
class TrialBalanceReportPartner(models.TransientModel):
|
||||
_name = 'report_trial_balance_partner'
|
||||
|
||||
report_account_id = fields.Many2one(
|
||||
comodel_name='report_trial_balance_account',
|
||||
ondelete='cascade',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used to keep link with real object
|
||||
partner_id = fields.Many2one(
|
||||
'res.partner',
|
||||
index=True
|
||||
)
|
||||
|
||||
# Data fields, used for report display
|
||||
name = fields.Char()
|
||||
|
||||
initial_balance = fields.Float(digits=(16, 2))
|
||||
debit = fields.Float(digits=(16, 2))
|
||||
credit = fields.Float(digits=(16, 2))
|
||||
final_balance = fields.Float(digits=(16, 2))
|
||||
|
||||
@api.model
|
||||
def _generate_order_by(self, order_spec, query):
|
||||
"""Custom order to display "No partner allocated" at last position."""
|
||||
return """
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN "report_trial_balance_partner"."partner_id" IS NOT NULL
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
"report_trial_balance_partner"."name"
|
||||
"""
|
||||
|
||||
|
||||
class TrialBalanceReportCompute(models.TransientModel):
|
||||
""" Here, we just define methods.
|
||||
For class fields, go more top at this file.
|
||||
"""
|
||||
|
||||
_inherit = 'report_trial_balance'
|
||||
|
||||
@api.multi
|
||||
def print_report(self, report_type):
|
||||
self.ensure_one()
|
||||
if report_type == 'xlsx':
|
||||
report_name = 'a_f_r.report_trial_balance_xlsx'
|
||||
else:
|
||||
report_name = 'account_financial_report.' \
|
||||
'report_trial_balance_qweb'
|
||||
return self.env['ir.actions.report'].search(
|
||||
[('report_name', '=', report_name),
|
||||
('report_type', '=', report_type)], limit=1).report_action(self)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
context = dict(self.env.context)
|
||||
report = self.browse(context.get('active_id'))
|
||||
if report:
|
||||
rcontext['o'] = report
|
||||
result['html'] = self.env.ref(
|
||||
'account_financial_report.report_trial_balance').render(
|
||||
rcontext)
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_html(self, given_context=None):
|
||||
return self._get_html()
|
||||
|
||||
def _prepare_report_general_ledger(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_from': self.date_from,
|
||||
'date_to': self.date_to,
|
||||
'only_posted_moves': self.only_posted_moves,
|
||||
'hide_account_balance_at_0': self.hide_account_balance_at_0,
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.filter_account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.filter_partner_ids.ids)],
|
||||
'fy_start_date': self.fy_start_date,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def compute_data_for_report(self):
|
||||
self.ensure_one()
|
||||
# Compute General Ledger Report Data.
|
||||
# The data of Trial Balance Report
|
||||
# are based on General Ledger Report data.
|
||||
model = self.env['report_general_ledger']
|
||||
self.general_ledger_id = model.create(
|
||||
self._prepare_report_general_ledger()
|
||||
)
|
||||
self.general_ledger_id.compute_data_for_report(
|
||||
with_line_details=False, with_partners=self.show_partner_details
|
||||
)
|
||||
|
||||
# Compute report data
|
||||
self._inject_account_values()
|
||||
if self.show_partner_details:
|
||||
self._inject_partner_values()
|
||||
# Refresh cache because all data are computed with SQL requests
|
||||
self.refresh()
|
||||
|
||||
def _inject_account_values(self):
|
||||
"""Inject report values for report_trial_balance_account"""
|
||||
query_inject_account = """
|
||||
INSERT INTO
|
||||
report_trial_balance_account
|
||||
(
|
||||
report_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
account_id,
|
||||
code,
|
||||
name,
|
||||
initial_balance,
|
||||
debit,
|
||||
credit,
|
||||
final_balance
|
||||
)
|
||||
SELECT
|
||||
%s AS report_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rag.account_id,
|
||||
rag.code,
|
||||
rag.name,
|
||||
rag.initial_balance AS initial_balance,
|
||||
rag.final_debit - rag.initial_debit AS debit,
|
||||
rag.final_credit - rag.initial_credit AS credit,
|
||||
rag.final_balance AS final_balance
|
||||
FROM
|
||||
report_general_ledger_account rag
|
||||
WHERE
|
||||
rag.report_id = %s
|
||||
"""
|
||||
query_inject_account_params = (
|
||||
self.id,
|
||||
self.env.uid,
|
||||
self.general_ledger_id.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_account, query_inject_account_params)
|
||||
|
||||
def _inject_partner_values(self):
|
||||
"""Inject report values for report_trial_balance_partner"""
|
||||
query_inject_partner = """
|
||||
INSERT INTO
|
||||
report_trial_balance_partner
|
||||
(
|
||||
report_account_id,
|
||||
create_uid,
|
||||
create_date,
|
||||
partner_id,
|
||||
name,
|
||||
initial_balance,
|
||||
debit,
|
||||
credit,
|
||||
final_balance
|
||||
)
|
||||
SELECT
|
||||
ra.id AS report_account_id,
|
||||
%s AS create_uid,
|
||||
NOW() AS create_date,
|
||||
rpg.partner_id,
|
||||
rpg.name,
|
||||
rpg.initial_balance AS initial_balance,
|
||||
rpg.final_debit - rpg.initial_debit AS debit,
|
||||
rpg.final_credit - rpg.initial_credit AS credit,
|
||||
rpg.final_balance AS final_balance
|
||||
FROM
|
||||
report_general_ledger_partner rpg
|
||||
INNER JOIN
|
||||
report_general_ledger_account rag ON rpg.report_account_id = rag.id
|
||||
INNER JOIN
|
||||
report_trial_balance_account ra ON rag.code = ra.code
|
||||
WHERE
|
||||
rag.report_id = %s
|
||||
AND ra.report_id = %s
|
||||
"""
|
||||
query_inject_partner_params = (
|
||||
self.env.uid,
|
||||
self.general_ledger_id.id,
|
||||
self.id,
|
||||
)
|
||||
self.env.cr.execute(query_inject_partner, query_inject_partner_params)
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class TrialBalanceXslx(models.AbstractModel):
|
||||
_name = 'report.a_f_r.report_trial_balance_xlsx'
|
||||
_inherit = 'report.account_financial_report.abstract_report_xlsx'
|
||||
|
||||
def _get_report_name(self):
|
||||
return _('Trial Balance')
|
||||
|
||||
def _get_report_columns(self, report):
|
||||
if not report.show_partner_details:
|
||||
return {
|
||||
0: {'header': _('Code'), 'field': 'code', 'width': 10},
|
||||
1: {'header': _('Account'), 'field': 'name', 'width': 60},
|
||||
2: {'header': _('Initial balance'),
|
||||
'field': 'initial_balance',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
3: {'header': _('Debit'),
|
||||
'field': 'debit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
4: {'header': _('Credit'),
|
||||
'field': 'credit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
5: {'header': _('Ending balance'),
|
||||
'field': 'final_balance',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
else:
|
||||
return {
|
||||
0: {'header': _('Partner'), 'field': 'name', 'width': 70},
|
||||
1: {'header': _('Initial balance'),
|
||||
'field': 'initial_balance',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
2: {'header': _('Debit'),
|
||||
'field': 'debit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
3: {'header': _('Credit'),
|
||||
'field': 'credit',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
4: {'header': _('Ending balance'),
|
||||
'field': 'final_balance',
|
||||
'type': 'amount',
|
||||
'width': 14},
|
||||
}
|
||||
|
||||
def _get_report_filters(self, report):
|
||||
return [
|
||||
[_('Date range filter'),
|
||||
_('From: %s To: %s') % (report.date_from, report.date_to)],
|
||||
[_('Target moves filter'),
|
||||
_('All posted entries') if report.only_posted_moves
|
||||
else _('All entries')],
|
||||
[_('Account balance at 0 filter'),
|
||||
_('Hide') if report.hide_account_balance_at_0 else _('Show')],
|
||||
]
|
||||
|
||||
def _get_col_count_filter_name(self):
|
||||
return 2
|
||||
|
||||
def _get_col_count_filter_value(self):
|
||||
return 3
|
||||
|
||||
def _generate_report_content(self, workbook, report):
|
||||
|
||||
if not report.show_partner_details:
|
||||
# Display array header for account lines
|
||||
self.write_array_header()
|
||||
|
||||
# For each account
|
||||
for account in report.account_ids:
|
||||
if not report.show_partner_details:
|
||||
# Display account lines
|
||||
self.write_line(account)
|
||||
|
||||
else:
|
||||
# Write account title
|
||||
self.write_array_title(account.code + ' - ' + account.name)
|
||||
|
||||
# Display array header for partner lines
|
||||
self.write_array_header()
|
||||
|
||||
# For each partner
|
||||
for partner in account.partner_ids:
|
||||
# Display partner lines
|
||||
self.write_line(partner)
|
||||
|
||||
# Display account footer line
|
||||
self.write_account_footer(account,
|
||||
account.code + ' - ' + account.name)
|
||||
|
||||
# Line break
|
||||
self.row_pos += 2
|
||||
|
||||
def write_account_footer(self, account, name_value):
|
||||
"""Specific function to write account footer for Trial Balance"""
|
||||
for col_pos, column in self.columns.items():
|
||||
if column['field'] == 'name':
|
||||
value = name_value
|
||||
else:
|
||||
value = getattr(account, column['field'])
|
||||
cell_type = column.get('type', 'string')
|
||||
if cell_type == 'string':
|
||||
self.sheet.write_string(self.row_pos, col_pos, value or '',
|
||||
self.format_header_left)
|
||||
elif cell_type == 'amount':
|
||||
self.sheet.write_number(self.row_pos, col_pos, float(value),
|
||||
self.format_header_amount)
|
||||
self.row_pos += 1
|
|
@ -0,0 +1,151 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- PDF/HMTL REPORTS -->
|
||||
|
||||
<!-- General Ledger -->
|
||||
<report
|
||||
id="action_report_general_ledger_qweb"
|
||||
model="report_general_ledger"
|
||||
string="General Ledger"
|
||||
report_type="qweb-pdf"
|
||||
name="account_financial_report.report_general_ledger_qweb"
|
||||
file="account_financial_report.report_general_ledger"
|
||||
/>
|
||||
<report
|
||||
id="action_report_general_ledger_html"
|
||||
model="report_general_ledger"
|
||||
string="General Ledger"
|
||||
report_type="qweb-html"
|
||||
name="account_financial_report.report_general_ledger_qweb"
|
||||
file="account_financial_report.report_general_ledger"
|
||||
/>
|
||||
|
||||
<!-- Trial Balance -->
|
||||
<report
|
||||
id="action_report_trial_balance_qweb"
|
||||
model="report_trial_balance"
|
||||
string="Trial Balance"
|
||||
report_type="qweb-pdf"
|
||||
name="account_financial_report.report_trial_balance_qweb"
|
||||
file="account_financial_report.report_trial_balance_qweb"
|
||||
/>
|
||||
<report
|
||||
id="action_report_trial_balance_html"
|
||||
model="report_trial_balance"
|
||||
string="Trial Balance"
|
||||
report_type="qweb-html"
|
||||
name="account_financial_report.report_trial_balance_qweb"
|
||||
file="account_financial_report.report_trial_balance_html"
|
||||
/>
|
||||
|
||||
<!-- Open Items -->
|
||||
<report
|
||||
id="action_report_open_items_qweb"
|
||||
model="report_open_items"
|
||||
string="Open Items"
|
||||
report_type="qweb-pdf"
|
||||
name="account_financial_report.report_open_items_qweb"
|
||||
file="account_financial_report.report_open_items_qweb"
|
||||
/>
|
||||
<report
|
||||
id="action_report_open_items_html"
|
||||
model="report_open_items"
|
||||
string="Open Items"
|
||||
report_type="qweb-html"
|
||||
name="account_financial_report.report_open_items_qweb"
|
||||
file="account_financial_report.report_open_items_html"
|
||||
/>
|
||||
|
||||
<!-- Aged Partner Balance -->
|
||||
<report
|
||||
id="action_report_aged_partner_balance_qweb"
|
||||
model="report_aged_partner_balance"
|
||||
string="Aged Partner Balance"
|
||||
report_type="qweb-pdf"
|
||||
name="account_financial_report.report_aged_partner_balance_qweb"
|
||||
file="account_financial_report.report_aged_partner_balance_qweb"
|
||||
/>
|
||||
<report
|
||||
id="action_report_aged_partner_balance_html"
|
||||
model="report_aged_partner_balance"
|
||||
string="Aged Partner Balance"
|
||||
report_type="qweb-html"
|
||||
name="account_financial_report.report_aged_partner_balance_qweb"
|
||||
file="account_financial_report.report_aged_partner_balance_html"
|
||||
/>
|
||||
|
||||
<!-- PDF REPORTS : paperformat -->
|
||||
|
||||
<record id="report_qweb_paperformat" model="report.paperformat">
|
||||
<field name="name">Account financial report qweb paperformat</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="format">custom</field>
|
||||
<field name="page_height">297</field>
|
||||
<field name="page_width">210</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">12</field>
|
||||
<field name="margin_bottom">8</field>
|
||||
<field name="margin_left">5</field>
|
||||
<field name="margin_right">5</field>
|
||||
<field name="header_line" eval="False"/>
|
||||
<field name="header_spacing">10</field>
|
||||
<field name="dpi">110</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_general_ledger_qweb" model="ir.actions.report">
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat"/>
|
||||
</record>
|
||||
|
||||
<record id="action_report_trial_balance_qweb" model="ir.actions.report">
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat"/>
|
||||
</record>
|
||||
|
||||
<record id="action_report_open_items_qweb" model="ir.actions.report">
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat"/>
|
||||
</record>
|
||||
|
||||
<record id="action_report_aged_partner_balance_qweb"
|
||||
model="ir.actions.report">
|
||||
<field name="paperformat_id" ref="report_qweb_paperformat"/>
|
||||
</record>
|
||||
|
||||
<!-- XLSX REPORTS -->
|
||||
|
||||
<record id="action_report_general_ledger_xlsx" model="ir.actions.report">
|
||||
<field name="name">General Ledger XLSX</field>
|
||||
<field name="model">report_general_ledger</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_general_ledger_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_general_ledger</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_trial_balance_xlsx" model="ir.actions.report">
|
||||
<field name="name">Trial Balance XLSX</field>
|
||||
<field name="model">report_trial_balance</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_trial_balance_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_trial_balance</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_open_items_xlsx" model="ir.actions.report">
|
||||
<field name="name">Open Items XLSX</field>
|
||||
<field name="model">report_open_items</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_open_items_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_open_items</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_aged_partner_balance_xlsx" model="ir.actions.report">
|
||||
<field name="name">Aged Partner Balance XLSX</field>
|
||||
<field name="model">report_aged_partner_balance</field>
|
||||
<field name="type">ir.actions.report</field>
|
||||
<field name="report_name">a_f_r.report_aged_partner_balance_xlsx</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_file">report_aged_partner_balance</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,105 @@
|
|||
body, table, td, span, div {
|
||||
font-family: Helvetica, Arial;
|
||||
}
|
||||
.act_as_table {
|
||||
display: table !important;
|
||||
}
|
||||
.act_as_row {
|
||||
display: table-row !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.act_as_cell {
|
||||
display: table-cell !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.act_as_thead {
|
||||
display: table-header-group !important;
|
||||
}
|
||||
.act_as_tbody {
|
||||
display: table-row-group !important;
|
||||
}
|
||||
.list_table, .data_table, .totals_table{
|
||||
width: 100% !important;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
.act_as_row.labels {
|
||||
background-color:#F0F0F0 !important;
|
||||
}
|
||||
.list_table, .data_table, .totals_table, .list_table .act_as_row {
|
||||
border-left:0px;
|
||||
border-right:0px;
|
||||
text-align:left;
|
||||
font-size:10px;
|
||||
padding-right:3px;
|
||||
padding-left:3px;
|
||||
padding-top:2px;
|
||||
padding-bottom:2px;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
.totals_table {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.list_table .act_as_row.labels, .list_table .act_as_row.initial_balance, .list_table .act_as_row.lines {
|
||||
border-color:grey !important;
|
||||
border-bottom:1px solid lightGrey !important;
|
||||
}
|
||||
.data_table .act_as_cell{
|
||||
border: 1px solid lightGrey;
|
||||
text-align: center;
|
||||
}
|
||||
.data_table .act_as_cell, .list_table .act_as_cell, .totals_table .act_as_cell {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.data_table .act_as_row.labels, .totals_table .act_as_row.labels {
|
||||
font-weight: bold;
|
||||
}
|
||||
.initial_balance .act_as_cell {
|
||||
font-style:italic;
|
||||
}
|
||||
.account_title {
|
||||
font-size:11px;
|
||||
font-weight:bold;
|
||||
}
|
||||
.account_title.labels {
|
||||
background-color:#F0F0F0 !important;
|
||||
}
|
||||
.act_as_cell.amount {
|
||||
word-wrap:normal;
|
||||
text-align:right;
|
||||
}
|
||||
.act_as_cell.left {
|
||||
text-align:left;
|
||||
}
|
||||
.act_as_cell.right {
|
||||
text-align:right;
|
||||
}
|
||||
.list_table .act_as_cell{
|
||||
padding-left: 5px;
|
||||
/* border-right:1px solid lightGrey; uncomment to active column lines */
|
||||
}
|
||||
.list_table .act_as_cell.first_column {
|
||||
padding-left: 0px;
|
||||
/* border-left:1px solid lightGrey; uncomment to active column lines */
|
||||
}
|
||||
.overflow_ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.custom_footer {
|
||||
font-size:7px !important;
|
||||
}
|
||||
.page_break {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.button_row {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.o_account_financial_reports_page {
|
||||
background-color: @odoo-view-background-color;
|
||||
color: @odoo-main-text-color;
|
||||
padding-top: 10px;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
odoo.define('account_financial_report.account_financial_report_backend', function (require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
var ControlPanelMixin = require('web.ControlPanelMixin');
|
||||
var session = require('web.session');
|
||||
var ReportWidget = require('account_financial_report.account_financial_report_widget');
|
||||
var framework = require('web.framework');
|
||||
var crash_manager = require('web.crash_manager');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var report_backend = Widget.extend(ControlPanelMixin, {
|
||||
// Stores all the parameters of the action.
|
||||
events: {
|
||||
'click .o_account_financial_reports_print': 'print',
|
||||
'click .o_account_financial_reports_export': 'export',
|
||||
},
|
||||
init: function(parent, action) {
|
||||
this.actionManager = parent;
|
||||
this.given_context = {};
|
||||
this.odoo_context = action.context;
|
||||
this.controller_url = action.context.url;
|
||||
if (action.context.context) {
|
||||
this.given_context = action.context.context;
|
||||
}
|
||||
this.given_context.active_id = action.context.active_id || action.params.active_id;
|
||||
this.given_context.model = action.context.active_model || false;
|
||||
this.given_context.ttype = action.context.ttype || false;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
willStart: function() {
|
||||
return $.when(this.get_html());
|
||||
},
|
||||
set_html: function() {
|
||||
var self = this;
|
||||
var def = $.when();
|
||||
if (!this.report_widget) {
|
||||
this.report_widget = new ReportWidget(this, this.given_context);
|
||||
def = this.report_widget.appendTo(this.$el);
|
||||
}
|
||||
def.then(function () {
|
||||
self.report_widget.$el.html(self.html);
|
||||
});
|
||||
},
|
||||
start: function() {
|
||||
this.set_html();
|
||||
return this._super();
|
||||
},
|
||||
// Fetches the html and is previous report.context if any, else create it
|
||||
get_html: function() {
|
||||
var self = this;
|
||||
var defs = [];
|
||||
return this._rpc({
|
||||
model: this.given_context.model,
|
||||
method: 'get_html',
|
||||
args: [self.given_context],
|
||||
context: self.odoo_context,
|
||||
})
|
||||
.then(function (result) {
|
||||
self.html = result.html;
|
||||
defs.push(self.update_cp());
|
||||
return $.when.apply($, defs);
|
||||
});
|
||||
},
|
||||
// Updates the control panel and render the elements that have yet to be rendered
|
||||
update_cp: function() {
|
||||
if (!this.$buttons) {
|
||||
|
||||
}
|
||||
var status = {
|
||||
breadcrumbs: this.actionManager.get_breadcrumbs(),
|
||||
cp_content: {$buttons: this.$buttons},
|
||||
};
|
||||
return this.update_control_panel(status);
|
||||
},
|
||||
do_show: function() {
|
||||
this._super();
|
||||
this.update_cp();
|
||||
},
|
||||
print: function(e) {
|
||||
var self = this;
|
||||
this._rpc({
|
||||
model: this.given_context.model,
|
||||
method: 'print_report',
|
||||
args: [this.given_context.active_id, 'qweb-pdf'],
|
||||
context: self.odoo_context,
|
||||
}).then(function(result){
|
||||
self.do_action(result);
|
||||
});
|
||||
},
|
||||
export: function(e) {
|
||||
var self = this;
|
||||
this._rpc({
|
||||
model: this.given_context.model,
|
||||
method: 'print_report',
|
||||
args: [this.given_context.active_id, 'xlsx'],
|
||||
context: self.odoo_context,
|
||||
})
|
||||
.then(function(result){
|
||||
self.do_action(result);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
core.action_registry.add("account_financial_report_backend", report_backend);
|
||||
return report_backend;
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
odoo.define('account_financial_report.account_financial_report_widget', function
|
||||
(require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var accountFinancialReportWidget = Widget.extend({
|
||||
events: {
|
||||
'click .o_account_financial_reports_web_action': 'boundLink',
|
||||
},
|
||||
init: function(parent) {
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
start: function() {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
boundLink: function(e) {
|
||||
var res_model = $(e.target).data('res-model')
|
||||
var res_id = $(e.target).data('active-id')
|
||||
return this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: res_model,
|
||||
res_id: res_id,
|
||||
views: [[false, 'form']],
|
||||
target: 'current'
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return accountFinancialReportWidget;
|
||||
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# © 2016 Julien Coux (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
|
||||
|
||||
from . import abstract_test
|
||||
from . import test_aged_partner_balance
|
||||
from . import test_general_ledger
|
||||
from . import test_open_items
|
||||
from . import test_trial_balance
|
|
@ -0,0 +1,246 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from xlrd import open_workbook
|
||||
except ImportError:
|
||||
_logger.debug('Can not import xlsxwriter`.')
|
||||
|
||||
|
||||
class AbstractTest(TransactionCase):
|
||||
"""Common technical tests for all reports."""
|
||||
|
||||
def setUp(cls):
|
||||
super(AbstractTest, cls).setUp()
|
||||
|
||||
cls.model = cls._getReportModel()
|
||||
|
||||
cls.qweb_report_name = cls._getQwebReportName()
|
||||
cls.xlsx_report_name = cls._getXlsxReportName()
|
||||
cls.xlsx_action_name = cls._getXlsxReportActionName()
|
||||
|
||||
cls.report_title = cls._getReportTitle()
|
||||
|
||||
cls.base_filters = cls._getBaseFilters()
|
||||
cls.additional_filters = cls._getAdditionalFiltersToBeTested()
|
||||
|
||||
cls.report = cls.model.create(cls.base_filters)
|
||||
cls.report.compute_data_for_report()
|
||||
|
||||
def test_01_generation_report_qweb(self):
|
||||
"""Check if report PDF/HTML is correctly generated"""
|
||||
|
||||
# Check if returned report action is correct
|
||||
report_type = 'qweb-pdf'
|
||||
report_action = self.report.print_report(report_type)
|
||||
self.assertDictContainsSubset(
|
||||
{
|
||||
'type': 'ir.actions.report',
|
||||
'report_name': self.qweb_report_name,
|
||||
'report_type': 'qweb-pdf',
|
||||
},
|
||||
report_action
|
||||
)
|
||||
|
||||
# Check if report template is correct
|
||||
report = self.env['ir.actions.report'].search(
|
||||
[('report_name', '=', self.qweb_report_name),
|
||||
('report_type', '=', report_type)], limit=1)
|
||||
self.assertEqual(report.report_type, 'qweb-pdf')
|
||||
|
||||
rep = report.render(self.report.ids, {})
|
||||
|
||||
self.assertTrue(self.report_title.encode('utf8') in rep[0])
|
||||
|
||||
self.assertTrue(
|
||||
self.report.account_ids[0].name.encode('utf8') in rep[0]
|
||||
)
|
||||
|
||||
def test_02_generation_report_html(self):
|
||||
"""Check if report HTML is correctly generated"""
|
||||
|
||||
# Check if returned report action is correct
|
||||
report_type = 'qweb-html'
|
||||
report_action = self.report.print_report(report_type)
|
||||
self.assertDictContainsSubset(
|
||||
{
|
||||
'type': 'ir.actions.report',
|
||||
'report_name': self.qweb_report_name,
|
||||
'report_type': 'qweb-html',
|
||||
},
|
||||
report_action
|
||||
)
|
||||
|
||||
# Check if report template is correct
|
||||
report = self.env['ir.actions.report'].search(
|
||||
[('report_name', '=', self.qweb_report_name),
|
||||
('report_type', '=', report_type)], limit=1)
|
||||
self.assertEqual(report.report_type, 'qweb-html')
|
||||
|
||||
rep = report.render(self.report.ids, {})
|
||||
|
||||
self.assertTrue(self.report_title.encode('utf8') in rep[0])
|
||||
self.assertTrue(
|
||||
self.report.account_ids[0].name.encode('utf8') in rep[0]
|
||||
)
|
||||
|
||||
def test_03_generation_report_xlsx(self):
|
||||
"""Check if report XLSX is correctly generated"""
|
||||
report_object = self.env['ir.actions.report']
|
||||
# Check if returned report action is correct
|
||||
report_type = 'xlsx'
|
||||
report_action = self.report.print_report(report_type)
|
||||
self.assertDictContainsSubset(
|
||||
{
|
||||
'type': 'ir.actions.report',
|
||||
'report_name': self.xlsx_report_name,
|
||||
'report_type': 'xlsx',
|
||||
},
|
||||
report_action
|
||||
)
|
||||
report = report_object._get_report_from_name(self.xlsx_report_name)
|
||||
self.assertEqual(report.report_type, 'xlsx')
|
||||
report_xlsx = report.render(self.report.ids, {})
|
||||
wb = open_workbook(file_contents=report_xlsx[0])
|
||||
sheet = wb.sheet_by_index(0)
|
||||
class_name = 'report.%s' % report.report_name
|
||||
self.assertEqual(sheet.cell(0, 0).value,
|
||||
self.env[class_name]._get_report_name())
|
||||
|
||||
def test_04_compute_data(self):
|
||||
"""Check that the SQL queries work with all filters options"""
|
||||
|
||||
for filters in [{}] + self.additional_filters:
|
||||
current_filter = self.base_filters.copy()
|
||||
current_filter.update(filters)
|
||||
|
||||
report = self.model.create(current_filter)
|
||||
report.compute_data_for_report()
|
||||
|
||||
self.assertGreaterEqual(len(report.account_ids), 1)
|
||||
|
||||
# Same filters with only one account
|
||||
current_filter = self.base_filters.copy()
|
||||
current_filter.update(filters)
|
||||
current_filter.update({
|
||||
'filter_account_ids':
|
||||
[(6, 0, report.account_ids[0].account_id.ids)],
|
||||
})
|
||||
|
||||
report2 = self.model.create(current_filter)
|
||||
report2.compute_data_for_report()
|
||||
|
||||
self.assertEqual(len(report2.account_ids), 1)
|
||||
self.assertEqual(report2.account_ids.name,
|
||||
report.account_ids[0].name)
|
||||
|
||||
if self._partner_test_is_possible(filters):
|
||||
# Same filters with only one partner
|
||||
report_partner_ids = report.account_ids.mapped('partner_ids')
|
||||
partner_ids = report_partner_ids.mapped('partner_id')
|
||||
|
||||
current_filter = self.base_filters.copy()
|
||||
current_filter.update(filters)
|
||||
current_filter.update({
|
||||
'filter_partner_ids': [(6, 0, partner_ids[0].ids)],
|
||||
})
|
||||
|
||||
report3 = self.model.create(current_filter)
|
||||
report3.compute_data_for_report()
|
||||
|
||||
self.assertGreaterEqual(len(report3.account_ids), 1)
|
||||
|
||||
report_partner_ids3 = report3.account_ids.mapped('partner_ids')
|
||||
partner_ids3 = report_partner_ids3.mapped('partner_id')
|
||||
|
||||
self.assertEqual(len(partner_ids3), 1)
|
||||
self.assertEqual(
|
||||
partner_ids3.name,
|
||||
partner_ids[0].name
|
||||
)
|
||||
|
||||
# Same filters with only one partner and one account
|
||||
report_partner_ids = report3.account_ids.mapped('partner_ids')
|
||||
report_account_id = report_partner_ids.filtered(
|
||||
lambda p: p.partner_id
|
||||
)[0].report_account_id
|
||||
|
||||
current_filter = self.base_filters.copy()
|
||||
current_filter.update(filters)
|
||||
current_filter.update({
|
||||
'filter_account_ids':
|
||||
[(6, 0, report_account_id.account_id.ids)],
|
||||
'filter_partner_ids': [(6, 0, partner_ids[0].ids)],
|
||||
})
|
||||
|
||||
report4 = self.model.create(current_filter)
|
||||
report4.compute_data_for_report()
|
||||
|
||||
self.assertEqual(len(report4.account_ids), 1)
|
||||
self.assertEqual(report4.account_ids.name,
|
||||
report_account_id.account_id.name)
|
||||
|
||||
report_partner_ids4 = report4.account_ids.mapped('partner_ids')
|
||||
partner_ids4 = report_partner_ids4.mapped('partner_id')
|
||||
|
||||
self.assertEqual(len(partner_ids4), 1)
|
||||
self.assertEqual(
|
||||
partner_ids4.name,
|
||||
partner_ids[0].name
|
||||
)
|
||||
|
||||
def _partner_test_is_possible(self, filters):
|
||||
"""
|
||||
:return:
|
||||
a boolean to indicate if partner test is possible
|
||||
with current filters
|
||||
"""
|
||||
return True
|
||||
|
||||
def _getReportModel(self):
|
||||
"""
|
||||
:return: the report model name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getQwebReportName(self):
|
||||
"""
|
||||
:return: the qweb report name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
"""
|
||||
:return: the xlsx report name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
"""
|
||||
:return: the xlsx report action name
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getReportTitle(self):
|
||||
"""
|
||||
:return: the report title displayed into the report
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getBaseFilters(self):
|
||||
"""
|
||||
:return: the minimum required filters to generate report
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _getAdditionalFiltersToBeTested(self):
|
||||
"""
|
||||
:return: the additional filters to generate report variants
|
||||
"""
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from . import abstract_test
|
||||
|
||||
|
||||
class TestAgedPartnerBalance(abstract_test.AbstractTest):
|
||||
"""
|
||||
Technical tests for Aged Partner Balance Report.
|
||||
"""
|
||||
|
||||
def _getReportModel(self):
|
||||
return self.env['report_aged_partner_balance']
|
||||
|
||||
def _getQwebReportName(self):
|
||||
return 'account_financial_report.report_aged_partner_balance_qweb'
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
return 'a_f_r.report_aged_partner_balance_xlsx'
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
return 'account_financial_report.' \
|
||||
'action_report_aged_partner_balance_xlsx'
|
||||
|
||||
def _getReportTitle(self):
|
||||
return 'Odoo Report'
|
||||
|
||||
def _getBaseFilters(self):
|
||||
return {
|
||||
'date_at': time.strftime('%Y-12-31'),
|
||||
'company_id': self.env.ref('base.main_company').id,
|
||||
}
|
||||
|
||||
def _getAdditionalFiltersToBeTested(self):
|
||||
return [
|
||||
{'only_posted_moves': True},
|
||||
{'show_move_line_details': True},
|
||||
{'only_posted_moves': True, 'show_move_line_details': True},
|
||||
]
|
|
@ -0,0 +1,466 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from . import abstract_test
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestGeneralLedger(abstract_test.AbstractTest):
|
||||
"""
|
||||
Technical tests for General Ledger Report.
|
||||
"""
|
||||
|
||||
def _getReportModel(self):
|
||||
return self.env['report_general_ledger']
|
||||
|
||||
def _getQwebReportName(self):
|
||||
return 'account_financial_report.report_general_ledger_qweb'
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
return 'a_f_r.report_general_ledger_xlsx'
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
return 'account_financial_report.' \
|
||||
'action_report_general_ledger_xlsx'
|
||||
|
||||
def _getReportTitle(self):
|
||||
return 'Odoo Report'
|
||||
|
||||
def _getBaseFilters(self):
|
||||
return {
|
||||
'date_from': time.strftime('%Y-01-01'),
|
||||
'date_to': time.strftime('%Y-12-31'),
|
||||
'company_id': self.env.ref('base.main_company').id,
|
||||
'fy_start_date': time.strftime('%Y-01-01'),
|
||||
}
|
||||
|
||||
def _getAdditionalFiltersToBeTested(self):
|
||||
return [
|
||||
{'only_posted_moves': True},
|
||||
{'hide_account_balance_at_0': True},
|
||||
{'centralize': True},
|
||||
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
|
||||
{'only_posted_moves': True, 'centralize': True},
|
||||
{'hide_account_balance_at_0': True, 'centralize': True},
|
||||
{
|
||||
'only_posted_moves': True,
|
||||
'hide_account_balance_at_0': True,
|
||||
'centralize': True
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class TestGeneralLedgerReport(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestGeneralLedgerReport, self).setUp()
|
||||
self.before_previous_fy_year = '2014-05-05'
|
||||
self.previous_fy_date_start = '2015-01-01'
|
||||
self.previous_fy_date_end = '2015-12-31'
|
||||
self.fy_date_start = '2016-01-01'
|
||||
self.fy_date_end = '2016-12-31'
|
||||
self.receivable_account = self.env['account.account'].search([
|
||||
('user_type_id.name', '=', 'Receivable')
|
||||
], limit=1)
|
||||
self.income_account = self.env['account.account'].search([
|
||||
('user_type_id.name', '=', 'Income')
|
||||
], limit=1)
|
||||
self.unaffected_account = self.env['account.account'].search([
|
||||
(
|
||||
'user_type_id',
|
||||
'=',
|
||||
self.env.ref('account.data_unaffected_earnings').id
|
||||
)], limit=1)
|
||||
|
||||
def _add_move(
|
||||
self,
|
||||
date,
|
||||
receivable_debit,
|
||||
receivable_credit,
|
||||
income_debit,
|
||||
income_credit,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=0
|
||||
):
|
||||
move_name = 'expense accrual'
|
||||
journal = self.env['account.journal'].search([
|
||||
('code', '=', 'MISC')])
|
||||
partner = self.env.ref('base.res_partner_12')
|
||||
move_vals = {
|
||||
'journal_id': journal.id,
|
||||
'partner_id': partner.id,
|
||||
'name': move_name,
|
||||
'date': date,
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'name': move_name,
|
||||
'debit': receivable_debit,
|
||||
'credit': receivable_credit,
|
||||
'account_id': self.receivable_account.id}),
|
||||
(0, 0, {
|
||||
'name': move_name,
|
||||
'debit': income_debit,
|
||||
'credit': income_credit,
|
||||
'account_id': self.income_account.id}),
|
||||
(0, 0, {
|
||||
'name': move_name,
|
||||
'debit': unaffected_debit,
|
||||
'credit': unaffected_credit,
|
||||
'account_id': self.unaffected_account.id}),
|
||||
]}
|
||||
move = self.env['account.move'].create(move_vals)
|
||||
move.post()
|
||||
|
||||
def _get_report_lines(self, with_partners=False):
|
||||
company = self.env.ref('base.main_company')
|
||||
general_ledger = self.env['report_general_ledger'].create({
|
||||
'date_from': self.fy_date_start,
|
||||
'date_to': self.fy_date_end,
|
||||
'only_posted_moves': True,
|
||||
'hide_account_balance_at_0': False,
|
||||
'company_id': company.id,
|
||||
'fy_start_date': self.fy_date_start,
|
||||
})
|
||||
general_ledger.compute_data_for_report(
|
||||
with_line_details=True, with_partners=with_partners
|
||||
)
|
||||
lines = {}
|
||||
report_account_model = self.env['report_general_ledger_account']
|
||||
lines['receivable'] = report_account_model.search([
|
||||
('report_id', '=', general_ledger.id),
|
||||
('account_id', '=', self.receivable_account.id),
|
||||
])
|
||||
lines['income'] = report_account_model.search([
|
||||
('report_id', '=', general_ledger.id),
|
||||
('account_id', '=', self.income_account.id),
|
||||
])
|
||||
lines['unaffected'] = report_account_model.search([
|
||||
('report_id', '=', general_ledger.id),
|
||||
('account_id', '=', self.unaffected_account.id),
|
||||
])
|
||||
if with_partners:
|
||||
report_partner_model = self.env[
|
||||
'report_general_ledger_partner'
|
||||
]
|
||||
lines['partner_receivable'] = report_partner_model.search([
|
||||
('report_account_id', '=', lines['receivable'].id),
|
||||
('partner_id', '=', self.env.ref('base.res_partner_12').id),
|
||||
])
|
||||
return lines
|
||||
|
||||
def test_01_account_balance(self):
|
||||
# Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['receivable']), 0)
|
||||
self.assertEqual(len(lines['income']), 0)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['receivable']), 1)
|
||||
self.assertEqual(len(lines['income']), 0)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].final_credit, 0)
|
||||
self.assertEqual(lines['receivable'].final_balance, 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['receivable']), 1)
|
||||
self.assertEqual(len(lines['income']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].final_credit, 1000)
|
||||
self.assertEqual(lines['receivable'].final_balance, 0)
|
||||
|
||||
self.assertEqual(lines['income'].initial_debit, 0)
|
||||
self.assertEqual(lines['income'].initial_credit, 0)
|
||||
self.assertEqual(lines['income'].initial_balance, 0)
|
||||
self.assertEqual(lines['income'].final_debit, 1000)
|
||||
self.assertEqual(lines['income'].final_credit, 0)
|
||||
self.assertEqual(lines['income'].final_balance, 1000)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['receivable']), 1)
|
||||
self.assertEqual(len(lines['income']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['receivable'].final_credit, 2000)
|
||||
self.assertEqual(lines['receivable'].final_balance, -1000)
|
||||
|
||||
self.assertEqual(lines['income'].initial_debit, 0)
|
||||
self.assertEqual(lines['income'].initial_credit, 0)
|
||||
self.assertEqual(lines['income'].initial_balance, 0)
|
||||
self.assertEqual(lines['income'].final_debit, 2000)
|
||||
self.assertEqual(lines['income'].final_credit, 0)
|
||||
self.assertEqual(lines['income'].final_balance, 2000)
|
||||
|
||||
def test_02_partner_balance(self):
|
||||
# Generate the general ledger line
|
||||
lines = self._get_report_lines(with_partners=True)
|
||||
self.assertEqual(len(lines['partner_receivable']), 0)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines(with_partners=True)
|
||||
self.assertEqual(len(lines['partner_receivable']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['partner_receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['partner_receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_credit, 0)
|
||||
self.assertEqual(lines['partner_receivable'].final_balance, 1000)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines(with_partners=True)
|
||||
self.assertEqual(len(lines['partner_receivable']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['partner_receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['partner_receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_credit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_balance, 0)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines(with_partners=True)
|
||||
self.assertEqual(len(lines['partner_receivable']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['partner_receivable'].initial_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].initial_credit, 0)
|
||||
self.assertEqual(lines['partner_receivable'].initial_balance, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_debit, 1000)
|
||||
self.assertEqual(lines['partner_receivable'].final_credit, 2000)
|
||||
self.assertEqual(lines['partner_receivable'].final_balance, -1000)
|
||||
|
||||
def test_03_unaffected_account_balance(self):
|
||||
# Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_balance, 0)
|
||||
self.assertEqual(lines['unaffected'].final_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_balance, 0)
|
||||
|
||||
# Add a move at the previous day of the first day of fiscal year
|
||||
# to check the initial balance
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_end,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
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)
|
||||
|
||||
# Add reversale move of the initial move the first day of fiscal year
|
||||
# to check the first day of fiscal year is not used
|
||||
# to compute the initial balance
|
||||
self._add_move(
|
||||
date=self.fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=1000,
|
||||
unaffected_debit=1000,
|
||||
unaffected_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_balance, -1000)
|
||||
self.assertEqual(lines['unaffected'].final_debit, 1000)
|
||||
self.assertEqual(lines['unaffected'].final_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_balance, 0)
|
||||
|
||||
# Add another move at the end day of fiscal year
|
||||
# to check that it correctly used on report
|
||||
self._add_move(
|
||||
date=self.fy_date_end,
|
||||
receivable_debit=3000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=3000
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_balance, -1000)
|
||||
self.assertEqual(lines['unaffected'].final_debit, 1000)
|
||||
self.assertEqual(lines['unaffected'].final_credit, 3000)
|
||||
self.assertEqual(lines['unaffected'].final_balance, -3000)
|
||||
|
||||
def test_04_unaffected_account_balance_2_years(self):
|
||||
# Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_balance, 0)
|
||||
self.assertEqual(lines['unaffected'].final_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_balance, 0)
|
||||
|
||||
# Add a move at any date 2 years before the balance
|
||||
# (to create an historic)
|
||||
self._add_move(
|
||||
date=self.before_previous_fy_year,
|
||||
receivable_debit=0,
|
||||
receivable_credit=1000,
|
||||
income_debit=1000,
|
||||
income_credit=0
|
||||
)
|
||||
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
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)
|
||||
|
||||
# Affect the company's result last year
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_start,
|
||||
receivable_debit=1000,
|
||||
receivable_credit=0,
|
||||
income_debit=0,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=1000
|
||||
)
|
||||
|
||||
# Add another move last year to test the initial balance this year
|
||||
self._add_move(
|
||||
date=self.previous_fy_date_start,
|
||||
receivable_debit=0,
|
||||
receivable_credit=500,
|
||||
income_debit=500,
|
||||
income_credit=0,
|
||||
unaffected_debit=0,
|
||||
unaffected_credit=0
|
||||
)
|
||||
# Re Generate the general ledger line
|
||||
lines = self._get_report_lines()
|
||||
self.assertEqual(len(lines['unaffected']), 1)
|
||||
|
||||
# Check the initial and final balance
|
||||
self.assertEqual(lines['unaffected'].initial_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].initial_balance, 500)
|
||||
self.assertEqual(lines['unaffected'].final_debit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_credit, 0)
|
||||
self.assertEqual(lines['unaffected'].final_balance, 500)
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from . import abstract_test
|
||||
|
||||
|
||||
class TestOpenItems(abstract_test.AbstractTest):
|
||||
"""
|
||||
Technical tests for Open Items Report.
|
||||
"""
|
||||
|
||||
def _getReportModel(self):
|
||||
return self.env['report_open_items']
|
||||
|
||||
def _getQwebReportName(self):
|
||||
return 'account_financial_report.report_open_items_qweb'
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
return 'a_f_r.report_open_items_xlsx'
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
return 'account_financial_report.action_report_open_items_xlsx'
|
||||
|
||||
def _getReportTitle(self):
|
||||
return 'Odoo Report'
|
||||
|
||||
def _getBaseFilters(self):
|
||||
return {
|
||||
'date_at': time.strftime('%Y-12-31'),
|
||||
'company_id': self.env.ref('base.main_company').id,
|
||||
}
|
||||
|
||||
def _getAdditionalFiltersToBeTested(self):
|
||||
return [
|
||||
{'only_posted_moves': True},
|
||||
{'hide_account_balance_at_0': True},
|
||||
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
|
||||
]
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
from . import abstract_test
|
||||
|
||||
|
||||
class TestTrialBalance(abstract_test.AbstractTest):
|
||||
"""
|
||||
Technical tests for Trial Balance Report.
|
||||
"""
|
||||
|
||||
def _getReportModel(self):
|
||||
return self.env['report_trial_balance']
|
||||
|
||||
def _getQwebReportName(self):
|
||||
return 'account_financial_report.report_trial_balance_qweb'
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
return 'a_f_r.report_trial_balance_xlsx'
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
return 'account_financial_report.action_report_trial_balance_xlsx'
|
||||
|
||||
def _getReportTitle(self):
|
||||
return 'Odoo Report'
|
||||
|
||||
def _getBaseFilters(self):
|
||||
return {
|
||||
'date_from': time.strftime('%Y-01-01'),
|
||||
'date_to': time.strftime('%Y-12-31'),
|
||||
'company_id': self.env.ref('base.main_company').id,
|
||||
'fy_start_date': time.strftime('%Y-01-01'),
|
||||
}
|
||||
|
||||
def _getAdditionalFiltersToBeTested(self):
|
||||
return [
|
||||
{'only_posted_moves': True},
|
||||
{'hide_account_balance_at_0': True},
|
||||
{'show_partner_details': True},
|
||||
{'only_posted_moves': True, 'hide_account_balance_at_0': True},
|
||||
{'only_posted_moves': True, 'show_partner_details': True},
|
||||
{'hide_account_balance_at_0': True, 'show_partner_details': True},
|
||||
{
|
||||
'only_posted_moves': True,
|
||||
'hide_account_balance_at_0': True,
|
||||
'show_partner_details': True
|
||||
},
|
||||
]
|
||||
|
||||
def _partner_test_is_possible(self, filters):
|
||||
return 'show_partner_details' in filters
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_account_specific_form">
|
||||
<field name="name">account.account.form.inherit</field>
|
||||
<field name="inherit_id" ref="account.view_account_form"/>
|
||||
<field name="model">account.account</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="deprecated" position="after">
|
||||
<field name="centralized"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_general_ledger" model="ir.actions.client">
|
||||
<field name="name">General Ledger Report</field>
|
||||
<field name="tag">report_general_ledger</field>
|
||||
<field name="context" eval="{'model': 'report_general_ledger'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_trial_balance" model="ir.actions.client">
|
||||
<field name="name">Trial Balance Report</field>
|
||||
<field name="tag">report_trial_balance</field>
|
||||
<field name="context" eval="{'model': 'report_trial_balance'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_open_items" model="ir.actions.client">
|
||||
<field name="name">Open Items Report</field>
|
||||
<field name="tag">report_open_items</field>
|
||||
<field name="context" eval="{'model': 'report_open_items'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_aged_partner_balance" model="ir.actions.client">
|
||||
<field name="name">Aged Partner Balance Report</field>
|
||||
<field name="tag">report_aged_partner_balance</field>
|
||||
<field name="context" eval="{'model': 'report_aged_partner_balance'}" />
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="report_aged_partner_balance">
|
||||
<div class="container o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons"/>
|
||||
<t t-call="account_financial_report.report_aged_partner_balance_base"/>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="report_general_ledger">
|
||||
<div class="container o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons"/>
|
||||
<t t-call="account_financial_report.report_general_ledger_base"/>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="report_open_items">
|
||||
<div class="container o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons"/>
|
||||
<t t-call="account_financial_report.report_open_items_base"/>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="account_financial_report_assets_backend"
|
||||
name="account_financial_report assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link href="/account_financial_report/static/src/css/report.css" rel="stylesheet"/>
|
||||
<script type="text/javascript"
|
||||
src="/account_financial_report/static/src/js/account_financial_report_backend.js"/>
|
||||
<script type="text/javascript"
|
||||
src="/account_financial_report/static/src/js/account_financial_report_widgets.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="report_buttons">
|
||||
<div class="button_row">
|
||||
<button class="o_account_financial_reports_print btn btn-sm oe_button"><span class="fa fa-print"/> Print</button>
|
||||
<button class="o_account_financial_reports_export btn btn-sm oe_button"><span class="fa fa-download"/> Export</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<record id="action_report_general_ledger" model="ir.actions.client">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="tag">account_financial_report_backend</field>
|
||||
<field name="context" eval="{'active_model': 'report_general_ledger'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_open_items" model="ir.actions.client">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="tag">account_financial_report_backend</field>
|
||||
<field name="context" eval="{'active_model': 'report_open_items'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_trial_balance" model="ir.actions.client">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="tag">account_financial_report_backend</field>
|
||||
<field name="context" eval="{'active_model': 'report_trial_balance'}" />
|
||||
</record>
|
||||
|
||||
<record id="action_report_aged_partner_balance" model="ir.actions.client">
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="tag">account_financial_report_backend</field>
|
||||
<field name="context" eval="{'active_model': 'report_aged_partner_balance'}" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="report_trial_balance">
|
||||
<div class="container o_account_financial_reports_page">
|
||||
<t t-call="account_financial_report.report_buttons"/>
|
||||
<t t-call="account_financial_report.report_trial_balance_base"/>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
from . import aged_partner_balance_wizard
|
||||
from . import general_ledger_wizard
|
||||
from . import open_items_wizard
|
||||
from . import trial_balance_wizard
|
|
@ -0,0 +1,103 @@
|
|||
# Author: Damien Crier, Andrea Stirpe, Kevin Graveman, Dennis Sluijk
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA, Onestein B.V.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from datetime import datetime
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class AgedPartnerBalance(models.TransientModel):
|
||||
"""Aged partner balance report wizard."""
|
||||
|
||||
_name = 'aged.partner.balance.wizard'
|
||||
_description = 'Aged Partner Balance Wizard'
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company',
|
||||
default=lambda self: self.env.user.company_id,
|
||||
string='Company'
|
||||
)
|
||||
date_at = fields.Date(required=True,
|
||||
default=fields.Date.to_string(datetime.today()))
|
||||
target_move = fields.Selection([('posted', 'All Posted Entries'),
|
||||
('all', 'All Entries')],
|
||||
string='Target Moves',
|
||||
required=True,
|
||||
default='all')
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name='account.account',
|
||||
string='Filter accounts',
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name='res.partner',
|
||||
string='Filter partners',
|
||||
)
|
||||
show_move_line_details = fields.Boolean()
|
||||
|
||||
@api.onchange('receivable_accounts_only', 'payable_accounts_only')
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = []
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [('internal_type', 'in', ('receivable', 'payable'))]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [('internal_type', '=', 'receivable')]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [('internal_type', '=', 'payable')]
|
||||
self.account_ids = self.env['account.account'].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.multi
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref(
|
||||
'account_financial_report.action_report_aged_partner_balance')
|
||||
vals = action.read()[0]
|
||||
context1 = vals.get('context', {})
|
||||
if isinstance(context1, pycompat.string_types):
|
||||
context1 = safe_eval(context1)
|
||||
model = self.env['report_aged_partner_balance']
|
||||
report = model.create(self._prepare_report_aged_partner_balance())
|
||||
report.compute_data_for_report()
|
||||
|
||||
context1['active_id'] = report.id
|
||||
context1['active_ids'] = report.ids
|
||||
vals['context'] = context1
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = 'qweb-pdf'
|
||||
return self._export(report_type)
|
||||
|
||||
@api.multi
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = 'xlsx'
|
||||
return self._export(report_type)
|
||||
|
||||
def _prepare_report_aged_partner_balance(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_at': self.date_at,
|
||||
'only_posted_moves': self.target_move == 'posted',
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
|
||||
'show_move_line_details': self.show_move_line_details,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
model = self.env['report_aged_partner_balance']
|
||||
report = model.create(self._prepare_report_aged_partner_balance())
|
||||
report.compute_data_for_report()
|
||||
return report.print_report(report_type)
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- AGED PARTNER BALANCE -->
|
||||
<record id="aged_partner_balance_wizard" model="ir.ui.view">
|
||||
<field name="name">Aged Partner Balance</field>
|
||||
<field name="model">aged.partner.balance.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_at"/>
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio"/>
|
||||
<field name="show_move_line_details"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="partner_ids"/>
|
||||
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
|
||||
<group/>
|
||||
<label for="account_ids"/>
|
||||
<group col="4">
|
||||
<field name="receivable_accounts_only"/>
|
||||
<field name="payable_accounts_only"/>
|
||||
</group>
|
||||
<field name="account_ids" widget="many2many_tags" nolabel="1" options="{'no_create': True}"/>
|
||||
<footer>
|
||||
<button name="button_export_html" string="View"
|
||||
type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
<button name="button_export_pdf" string="Export PDF" type="object"/>
|
||||
or
|
||||
<button name="button_export_xlsx" string="Export XLSX" type="object"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_aged_partner_balance_wizard"
|
||||
name="Aged Partner Balance"
|
||||
res_model="aged.partner.balance.wizard"
|
||||
view_type="form"
|
||||
view_mode="form"
|
||||
view_id="aged_partner_balance_wizard"
|
||||
target="new" />
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,163 @@
|
|||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Author: Jordi Ballester
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2017 Akretion - Alexis de Lattre
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class GeneralLedgerReportWizard(models.TransientModel):
|
||||
"""General ledger report wizard."""
|
||||
|
||||
_name = "general.ledger.report.wizard"
|
||||
_description = "General Ledger Report Wizard"
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company',
|
||||
default=lambda self: self.env.user.company_id,
|
||||
string='Company'
|
||||
)
|
||||
date_range_id = fields.Many2one(
|
||||
comodel_name='date.range',
|
||||
string='Date range'
|
||||
)
|
||||
date_from = fields.Date(required=True)
|
||||
date_to = fields.Date(required=True)
|
||||
fy_start_date = fields.Date(compute='_compute_fy_start_date')
|
||||
target_move = fields.Selection([('posted', 'All Posted Entries'),
|
||||
('all', 'All Entries')],
|
||||
string='Target Moves',
|
||||
required=True,
|
||||
default='all')
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name='account.account',
|
||||
string='Filter accounts',
|
||||
)
|
||||
centralize = fields.Boolean(string='Activate centralization',
|
||||
default=True)
|
||||
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.'
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name='res.partner',
|
||||
string='Filter partners',
|
||||
)
|
||||
cost_center_ids = fields.Many2many(
|
||||
comodel_name='account.analytic.account',
|
||||
string='Filter cost centers',
|
||||
)
|
||||
|
||||
not_only_one_unaffected_earnings_account = fields.Boolean(
|
||||
readonly=True,
|
||||
string='Not only one unaffected earnings account'
|
||||
)
|
||||
|
||||
@api.depends('date_from')
|
||||
def _compute_fy_start_date(self):
|
||||
for wiz in self.filtered('date_from'):
|
||||
date = fields.Datetime.from_string(wiz.date_from)
|
||||
res = self.company_id.compute_fiscalyear_dates(date)
|
||||
wiz.fy_start_date = res['date_from']
|
||||
|
||||
@api.onchange('company_id')
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
account_type = self.env.ref('account.data_unaffected_earnings')
|
||||
count = self.env['account.account'].search_count(
|
||||
[
|
||||
('user_type_id', '=', account_type.id),
|
||||
('company_id', '=', self.company_id.id)
|
||||
])
|
||||
self.not_only_one_unaffected_earnings_account = count != 1
|
||||
|
||||
@api.onchange('date_range_id')
|
||||
def onchange_date_range_id(self):
|
||||
"""Handle date range change."""
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
|
||||
@api.onchange('receivable_accounts_only', 'payable_accounts_only')
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = []
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [('internal_type', 'in', ('receivable', 'payable'))]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [('internal_type', '=', 'receivable')]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [('internal_type', '=', 'payable')]
|
||||
self.account_ids = self.env['account.account'].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.onchange('partner_ids')
|
||||
def onchange_partner_ids(self):
|
||||
"""Handle partners change."""
|
||||
if self.partner_ids:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = True
|
||||
else:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = False
|
||||
|
||||
@api.multi
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref(
|
||||
'account_financial_report.action_report_general_ledger')
|
||||
vals = action.read()[0]
|
||||
context1 = vals.get('context', {})
|
||||
if isinstance(context1, pycompat.string_types):
|
||||
context1 = safe_eval(context1)
|
||||
model = self.env['report_general_ledger']
|
||||
report = model.create(self._prepare_report_general_ledger())
|
||||
report.compute_data_for_report()
|
||||
context1['active_id'] = report.id
|
||||
context1['active_ids'] = report.ids
|
||||
vals['context'] = context1
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = 'qweb-pdf'
|
||||
return self._export(report_type)
|
||||
|
||||
@api.multi
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = 'xlsx'
|
||||
return self._export(report_type)
|
||||
|
||||
def _prepare_report_general_ledger(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_from': self.date_from,
|
||||
'date_to': self.date_to,
|
||||
'only_posted_moves': self.target_move == 'posted',
|
||||
'hide_account_balance_at_0': self.hide_account_balance_at_0,
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
|
||||
'filter_cost_center_ids': [(6, 0, self.cost_center_ids.ids)],
|
||||
'centralize': self.centralize,
|
||||
'fy_start_date': self.fy_start_date,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
model = self.env['report_general_ledger']
|
||||
report = model.create(self._prepare_report_general_ledger())
|
||||
report.compute_data_for_report()
|
||||
return report.print_report(report_type)
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- GENERAL LEDGER -->
|
||||
<record id="general_ledger_wizard" model="ir.ui.view">
|
||||
<field name="name">General Ledger</field>
|
||||
<field name="model">general.ledger.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', True)]}">
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_range_id" domain="['|',('company_id','=',company_id), ('company_id','=',False)]"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<field name="fy_start_date" invisible="1"/>
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio"/>
|
||||
<field name="centralize"/>
|
||||
<field name="hide_account_balance_at_0"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="cost_center_ids" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="cost_center_ids" nolabel="1" options="{'no_create': True}" groups="analytic.group_analytic_accounting"/>
|
||||
<group/>
|
||||
<label for="partner_ids"/>
|
||||
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
|
||||
<group/>
|
||||
<label for="account_ids"/>
|
||||
<group col="4">
|
||||
<field name="receivable_accounts_only"/>
|
||||
<field name="payable_accounts_only"/>
|
||||
</group>
|
||||
<field name="account_ids" widget="many2many_tags" nolabel="1" options="{'no_create': True}"/>
|
||||
</div>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}">
|
||||
<field name="not_only_one_unaffected_earnings_account" invisible="1"/>
|
||||
<group/>
|
||||
<h4>General Ledger can be computed only if selected company have only one unaffected earnings account.</h4>
|
||||
<group/>
|
||||
</div>
|
||||
<footer>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', True)]}">
|
||||
<button name="button_export_html" string="View"
|
||||
type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
<button name="button_export_pdf" string="Export PDF" type="object"/>
|
||||
or
|
||||
<button name="button_export_xlsx" string="Export XLSX" type="object"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}">
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_general_ledger_wizard"
|
||||
name="General Ledger"
|
||||
res_model="general.ledger.report.wizard"
|
||||
view_type="form"
|
||||
view_mode="form"
|
||||
view_id="general_ledger_wizard"
|
||||
target="new" />
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
# Author: Damien Crier
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# 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.tools.safe_eval import safe_eval
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class OpenItemsReportWizard(models.TransientModel):
|
||||
"""Open items report wizard."""
|
||||
|
||||
_name = "open.items.report.wizard"
|
||||
_description = "Open Items Report Wizard"
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company',
|
||||
default=lambda self: self.env.user.company_id,
|
||||
string='Company'
|
||||
)
|
||||
date_at = fields.Date(required=True,
|
||||
default=fields.Date.to_string(datetime.today()))
|
||||
target_move = fields.Selection([('posted', 'All Posted Entries'),
|
||||
('all', 'All Entries')],
|
||||
string='Target Moves',
|
||||
required=True,
|
||||
default='all')
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name='account.account',
|
||||
string='Filter accounts',
|
||||
domain=[('reconcile', '=', True)],
|
||||
)
|
||||
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.'
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name='res.partner',
|
||||
string='Filter partners',
|
||||
)
|
||||
|
||||
@api.onchange('receivable_accounts_only', 'payable_accounts_only')
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = []
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [('internal_type', 'in', ('receivable', 'payable'))]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [('internal_type', '=', 'receivable')]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [('internal_type', '=', 'payable')]
|
||||
self.account_ids = self.env['account.account'].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.multi
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref(
|
||||
'account_financial_report.action_report_open_items')
|
||||
vals = action.read()[0]
|
||||
context1 = vals.get('context', {})
|
||||
if isinstance(context1, pycompat.string_types):
|
||||
context1 = safe_eval(context1)
|
||||
model = self.env['report_open_items']
|
||||
report = model.create(self._prepare_report_open_items())
|
||||
report.compute_data_for_report()
|
||||
|
||||
context1['active_id'] = report.id
|
||||
context1['active_ids'] = report.ids
|
||||
vals['context'] = context1
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = 'qweb-pdf'
|
||||
return self._export(report_type)
|
||||
|
||||
@api.multi
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = 'xlsx'
|
||||
return self._export(report_type)
|
||||
|
||||
def _prepare_report_open_items(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_at': self.date_at,
|
||||
'only_posted_moves': self.target_move == 'posted',
|
||||
'hide_account_balance_at_0': self.hide_account_balance_at_0,
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
model = self.env['report_open_items']
|
||||
report = model.create(self._prepare_report_open_items())
|
||||
report.compute_data_for_report()
|
||||
return report.print_report(report_type)
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- OPEN ITEMS -->
|
||||
<record id="open_items_wizard" model="ir.ui.view">
|
||||
<field name="name">Open Items</field>
|
||||
<field name="model">open.items.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_at"/>
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio"/>
|
||||
<field name="hide_account_balance_at_0"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="partner_ids"/>
|
||||
<field name="partner_ids" nolabel="1" options="{'no_create': True}"/>
|
||||
<group/>
|
||||
<label for="account_ids"/>
|
||||
<group col="4">
|
||||
<field name="receivable_accounts_only"/>
|
||||
<field name="payable_accounts_only"/>
|
||||
</group>
|
||||
<field name="account_ids" widget="many2many_tags" nolabel="1" options="{'no_create': True}"/>
|
||||
<footer>
|
||||
<button name="button_export_html" string="View"
|
||||
type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
<button name="button_export_pdf" string="Export PDF" type="object"/>
|
||||
or
|
||||
<button name="button_export_xlsx" string="Export XLSX" type="object"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_open_items_wizard"
|
||||
name="Open Items"
|
||||
res_model="open.items.report.wizard"
|
||||
view_type="form"
|
||||
view_mode="form"
|
||||
view_id="open_items_wizard"
|
||||
target="new" />
|
||||
|
||||
</odoo>
|
|
@ -0,0 +1,155 @@
|
|||
|
||||
# Author: Julien Coux
|
||||
# Copyright 2016 Camptocamp SA
|
||||
# Copyright 2017 Akretion - Alexis de Lattre
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class TrialBalanceReportWizard(models.TransientModel):
|
||||
"""Trial balance report wizard."""
|
||||
|
||||
_name = "trial.balance.report.wizard"
|
||||
_description = "Trial Balance Report Wizard"
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company',
|
||||
default=lambda self: self.env.user.company_id,
|
||||
string='Company'
|
||||
)
|
||||
date_range_id = fields.Many2one(
|
||||
comodel_name='date.range',
|
||||
string='Date range'
|
||||
)
|
||||
date_from = fields.Date(required=True)
|
||||
date_to = fields.Date(required=True)
|
||||
fy_start_date = fields.Date(compute='_compute_fy_start_date')
|
||||
target_move = fields.Selection([('posted', 'All Posted Entries'),
|
||||
('all', 'All Entries')],
|
||||
string='Target Moves',
|
||||
required=True,
|
||||
default='all')
|
||||
account_ids = fields.Many2many(
|
||||
comodel_name='account.account',
|
||||
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.'
|
||||
)
|
||||
receivable_accounts_only = fields.Boolean()
|
||||
payable_accounts_only = fields.Boolean()
|
||||
show_partner_details = fields.Boolean()
|
||||
partner_ids = fields.Many2many(
|
||||
comodel_name='res.partner',
|
||||
string='Filter partners',
|
||||
)
|
||||
|
||||
not_only_one_unaffected_earnings_account = fields.Boolean(
|
||||
readonly=True,
|
||||
string='Not only one unaffected earnings account'
|
||||
)
|
||||
|
||||
@api.depends('date_from')
|
||||
def _compute_fy_start_date(self):
|
||||
for wiz in self.filtered('date_from'):
|
||||
date = fields.Datetime.from_string(wiz.date_from)
|
||||
res = self.company_id.compute_fiscalyear_dates(date)
|
||||
wiz.fy_start_date = res['date_from']
|
||||
|
||||
@api.onchange('company_id')
|
||||
def onchange_company_id(self):
|
||||
"""Handle company change."""
|
||||
account_type = self.env.ref('account.data_unaffected_earnings')
|
||||
count = self.env['account.account'].search_count(
|
||||
[
|
||||
('user_type_id', '=', account_type.id),
|
||||
('company_id', '=', self.company_id.id)
|
||||
])
|
||||
self.not_only_one_unaffected_earnings_account = count != 1
|
||||
|
||||
@api.onchange('date_range_id')
|
||||
def onchange_date_range_id(self):
|
||||
"""Handle date range change."""
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
|
||||
@api.onchange('receivable_accounts_only', 'payable_accounts_only')
|
||||
def onchange_type_accounts_only(self):
|
||||
"""Handle receivable/payable accounts only change."""
|
||||
if self.receivable_accounts_only or self.payable_accounts_only:
|
||||
domain = []
|
||||
if self.receivable_accounts_only and self.payable_accounts_only:
|
||||
domain += [('internal_type', 'in', ('receivable', 'payable'))]
|
||||
elif self.receivable_accounts_only:
|
||||
domain += [('internal_type', '=', 'receivable')]
|
||||
elif self.payable_accounts_only:
|
||||
domain += [('internal_type', '=', 'payable')]
|
||||
self.account_ids = self.env['account.account'].search(domain)
|
||||
else:
|
||||
self.account_ids = None
|
||||
|
||||
@api.onchange('show_partner_details')
|
||||
def onchange_show_partner_details(self):
|
||||
"""Handle partners change."""
|
||||
if self.show_partner_details:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = True
|
||||
else:
|
||||
self.receivable_accounts_only = self.payable_accounts_only = False
|
||||
|
||||
@api.multi
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref(
|
||||
'account_financial_report.action_report_trial_balance')
|
||||
vals = action.read()[0]
|
||||
context1 = vals.get('context', {})
|
||||
if isinstance(context1, pycompat.string_types):
|
||||
context1 = safe_eval(context1)
|
||||
model = self.env['report_trial_balance']
|
||||
report = model.create(self._prepare_report_trial_balance())
|
||||
report.compute_data_for_report()
|
||||
|
||||
context1['active_id'] = report.id
|
||||
context1['active_ids'] = report.ids
|
||||
vals['context'] = context1
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = 'qweb-pdf'
|
||||
return self._export(report_type)
|
||||
|
||||
@api.multi
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = 'xlsx'
|
||||
return self._export(report_type)
|
||||
|
||||
def _prepare_report_trial_balance(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_from': self.date_from,
|
||||
'date_to': self.date_to,
|
||||
'only_posted_moves': self.target_move == 'posted',
|
||||
'hide_account_balance_at_0': self.hide_account_balance_at_0,
|
||||
'company_id': self.company_id.id,
|
||||
'filter_account_ids': [(6, 0, self.account_ids.ids)],
|
||||
'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
|
||||
'fy_start_date': self.fy_start_date,
|
||||
'show_partner_details': self.show_partner_details,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
"""Default export is PDF."""
|
||||
model = self.env['report_trial_balance']
|
||||
report = model.create(self._prepare_report_trial_balance())
|
||||
report.compute_data_for_report()
|
||||
return report.print_report(report_type)
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- TRIAL BALANCE -->
|
||||
<record id="trial_balance_wizard" model="ir.ui.view">
|
||||
<field name="name">Trial Balance</field>
|
||||
<field name="model">trial.balance.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main_info">
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', True)]}">
|
||||
<group name="filters">
|
||||
<group name="date_range">
|
||||
<field name="date_range_id" domain="['|',('company_id','=',company_id), ('company_id','=',False)]"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<field name="fy_start_date" invisible="1"/>
|
||||
</group>
|
||||
<group name="other_filters">
|
||||
<field name="target_move" widget="radio"/>
|
||||
<field name="hide_account_balance_at_0"/>
|
||||
<field name="show_partner_details"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="partner_ids" attrs="{'invisible':[('show_partner_details','!=',True)]}"/>
|
||||
<field name="partner_ids" nolabel="1" options="{'no_create': True}" attrs="{'invisible':[('show_partner_details','!=',True)]}"/>
|
||||
<group attrs="{'invisible':[('show_partner_details','!=',True)]}"/>
|
||||
<label for="account_ids"/>
|
||||
<group col="4">
|
||||
<field name="receivable_accounts_only"/>
|
||||
<field name="payable_accounts_only"/>
|
||||
</group>
|
||||
<field name="account_ids" widget="many2many_tags" nolabel="1" options="{'no_create': True}"/>
|
||||
</div>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}">
|
||||
<field name="not_only_one_unaffected_earnings_account" invisible="1"/>
|
||||
<group/>
|
||||
<h4>Trial Balance can be computed only if selected company have only one unaffected earnings account.</h4>
|
||||
<group/>
|
||||
</div>
|
||||
<footer>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', True)]}">
|
||||
<button name="button_export_html" string="View"
|
||||
type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
<button name="button_export_pdf" string="Export PDF" type="object"/>
|
||||
or
|
||||
<button name="button_export_xlsx" string="Export XLSX" type="object"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
<div attrs="{'invisible': [('not_only_one_unaffected_earnings_account', '=', False)]}">
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_trial_balance_wizard"
|
||||
name="Trial Balance"
|
||||
res_model="trial.balance.report.wizard"
|
||||
view_type="form"
|
||||
view_mode="form"
|
||||
view_id="trial_balance_wizard"
|
||||
target="new" />
|
||||
|
||||
</odoo>
|
|
@ -39,7 +39,7 @@ class AccountTax(models.Model):
|
|||
context.get('from_date', fields.Date.context_today(self)),
|
||||
context.get('to_date', fields.Date.context_today(self)),
|
||||
context.get('company_id', self.env.user.company_id.id),
|
||||
context.get('target_move', 'posted')
|
||||
context.get('target_move', 'posted'),
|
||||
)
|
||||
|
||||
def _account_tax_ids_with_moves(self):
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
server-ux
|
||||
account-financial-tools https://github.com/Eficent/account-financial-tools 11.0-mig-account_fiscal_year
|
||||
reporting-engine https://github.com/OCA/reporting-engine
|
||||
server-ux https://github.com/OCA/server-ux
|
|
@ -0,0 +1,2 @@
|
|||
xlsxwriter
|
||||
xlrd
|
Loading…
Reference in New Issue