Browse Source

Dec 13 : [ADD] Initial Commit 'dynamic_accounts_report'

pull/313/head
AjmalCybro 2 years ago
parent
commit
ac306fd4b2
  1. 50
      dynamic_accounts_report/README.rst
  2. 24
      dynamic_accounts_report/__init__.py
  3. 81
      dynamic_accounts_report/__manifest__.py
  4. 22
      dynamic_accounts_report/controllers/__init__.py
  5. 69
      dynamic_accounts_report/controllers/controllers.py
  6. 6
      dynamic_accounts_report/doc/RELEASE_NOTES.md
  7. 2312
      dynamic_accounts_report/i18n/ar_001.po
  8. 2324
      dynamic_accounts_report/i18n/de_CH.po
  9. 2312
      dynamic_accounts_report/i18n/es_AR.po
  10. 2312
      dynamic_accounts_report/i18n/fr_BE.po
  11. 2312
      dynamic_accounts_report/i18n/id.po
  12. 2312
      dynamic_accounts_report/i18n/uk_UA.po
  13. 31
      dynamic_accounts_report/models/__init__.py
  14. 329
      dynamic_accounts_report/models/account_general_ledger.py
  15. 370
      dynamic_accounts_report/models/account_partner_ledger.py
  16. 449
      dynamic_accounts_report/models/account_trial_balance.py
  17. 305
      dynamic_accounts_report/models/aged_payable_report.py
  18. 322
      dynamic_accounts_report/models/aged_receivable_report.py
  19. 321
      dynamic_accounts_report/models/bank_book_report.py
  20. 345
      dynamic_accounts_report/models/cash_book_report.py
  21. 1104
      dynamic_accounts_report/models/dynamic_balance_sheet_report.py
  22. 760
      dynamic_accounts_report/models/tax_report.py
  23. 21
      dynamic_accounts_report/report/__init__.py
  24. 278
      dynamic_accounts_report/report/aged_payable_templates.xml
  25. 279
      dynamic_accounts_report/report/aged_receivable_templates.xml
  26. 942
      dynamic_accounts_report/report/balance_sheet_report_templates.xml
  27. 231
      dynamic_accounts_report/report/bank_book_templates.xml
  28. 209
      dynamic_accounts_report/report/financial_report_template.xml
  29. 74
      dynamic_accounts_report/report/financial_reports_views.xml
  30. 219
      dynamic_accounts_report/report/general_ledger_templates.xml
  31. 237
      dynamic_accounts_report/report/partner_ledger_templates.xml
  32. 308
      dynamic_accounts_report/report/tax_report_templates.xml
  33. 171
      dynamic_accounts_report/report/trial_balance.xml
  34. 6
      dynamic_accounts_report/security/ir.model.access.csv
  35. BIN
      dynamic_accounts_report/static/description/assets/icons/capture (1).png
  36. BIN
      dynamic_accounts_report/static/description/assets/icons/check.png
  37. BIN
      dynamic_accounts_report/static/description/assets/icons/chevron.png
  38. BIN
      dynamic_accounts_report/static/description/assets/icons/cogs.png
  39. BIN
      dynamic_accounts_report/static/description/assets/icons/consultation.png
  40. BIN
      dynamic_accounts_report/static/description/assets/icons/ecom-black.png
  41. BIN
      dynamic_accounts_report/static/description/assets/icons/education-black.png
  42. BIN
      dynamic_accounts_report/static/description/assets/icons/hotel-black.png
  43. BIN
      dynamic_accounts_report/static/description/assets/icons/img.png
  44. BIN
      dynamic_accounts_report/static/description/assets/icons/license.png
  45. BIN
      dynamic_accounts_report/static/description/assets/icons/lifebuoy.png
  46. BIN
      dynamic_accounts_report/static/description/assets/icons/manufacturing-black.png
  47. BIN
      dynamic_accounts_report/static/description/assets/icons/photo-capture.png
  48. BIN
      dynamic_accounts_report/static/description/assets/icons/pos-black.png
  49. BIN
      dynamic_accounts_report/static/description/assets/icons/puzzle.png
  50. BIN
      dynamic_accounts_report/static/description/assets/icons/restaurant-black.png
  51. BIN
      dynamic_accounts_report/static/description/assets/icons/service-black.png
  52. BIN
      dynamic_accounts_report/static/description/assets/icons/trading-black.png
  53. BIN
      dynamic_accounts_report/static/description/assets/icons/training.png
  54. BIN
      dynamic_accounts_report/static/description/assets/icons/update.png
  55. BIN
      dynamic_accounts_report/static/description/assets/icons/user.png
  56. BIN
      dynamic_accounts_report/static/description/assets/icons/wrench.png
  57. BIN
      dynamic_accounts_report/static/description/assets/misc/Cybrosys R.png
  58. 33
      dynamic_accounts_report/static/description/assets/misc/email.svg
  59. 3
      dynamic_accounts_report/static/description/assets/misc/phone.svg
  60. 9
      dynamic_accounts_report/static/description/assets/misc/star (1) 2.svg
  61. 9
      dynamic_accounts_report/static/description/assets/misc/support (1) 1.svg
  62. 6
      dynamic_accounts_report/static/description/assets/misc/support-email.svg
  63. 17
      dynamic_accounts_report/static/description/assets/misc/tick-mark.svg
  64. 9
      dynamic_accounts_report/static/description/assets/misc/whatsapp 1.svg
  65. 33
      dynamic_accounts_report/static/description/assets/misc/whatsapp.svg
  66. BIN
      dynamic_accounts_report/static/description/assets/modules/1.png
  67. BIN
      dynamic_accounts_report/static/description/assets/modules/2.png
  68. BIN
      dynamic_accounts_report/static/description/assets/modules/3.png
  69. BIN
      dynamic_accounts_report/static/description/assets/modules/4.png
  70. BIN
      dynamic_accounts_report/static/description/assets/modules/5.png
  71. BIN
      dynamic_accounts_report/static/description/assets/modules/6.png
  72. BIN
      dynamic_accounts_report/static/description/assets/screenshots/1.png
  73. BIN
      dynamic_accounts_report/static/description/assets/screenshots/10.png
  74. BIN
      dynamic_accounts_report/static/description/assets/screenshots/11.png
  75. BIN
      dynamic_accounts_report/static/description/assets/screenshots/12.png
  76. BIN
      dynamic_accounts_report/static/description/assets/screenshots/13.png
  77. BIN
      dynamic_accounts_report/static/description/assets/screenshots/14.png
  78. BIN
      dynamic_accounts_report/static/description/assets/screenshots/15.png
  79. BIN
      dynamic_accounts_report/static/description/assets/screenshots/16.png
  80. BIN
      dynamic_accounts_report/static/description/assets/screenshots/17.png
  81. BIN
      dynamic_accounts_report/static/description/assets/screenshots/18.png
  82. BIN
      dynamic_accounts_report/static/description/assets/screenshots/19.png
  83. BIN
      dynamic_accounts_report/static/description/assets/screenshots/2.png
  84. BIN
      dynamic_accounts_report/static/description/assets/screenshots/20.png
  85. BIN
      dynamic_accounts_report/static/description/assets/screenshots/21.png
  86. BIN
      dynamic_accounts_report/static/description/assets/screenshots/22.png
  87. BIN
      dynamic_accounts_report/static/description/assets/screenshots/23.png
  88. BIN
      dynamic_accounts_report/static/description/assets/screenshots/24.png
  89. BIN
      dynamic_accounts_report/static/description/assets/screenshots/25.png
  90. BIN
      dynamic_accounts_report/static/description/assets/screenshots/26.png
  91. BIN
      dynamic_accounts_report/static/description/assets/screenshots/27.png
  92. BIN
      dynamic_accounts_report/static/description/assets/screenshots/28.png
  93. BIN
      dynamic_accounts_report/static/description/assets/screenshots/29.png
  94. BIN
      dynamic_accounts_report/static/description/assets/screenshots/3.png
  95. BIN
      dynamic_accounts_report/static/description/assets/screenshots/30.png
  96. BIN
      dynamic_accounts_report/static/description/assets/screenshots/31.png
  97. BIN
      dynamic_accounts_report/static/description/assets/screenshots/32.png
  98. BIN
      dynamic_accounts_report/static/description/assets/screenshots/33.png
  99. BIN
      dynamic_accounts_report/static/description/assets/screenshots/34.png
  100. BIN
      dynamic_accounts_report/static/description/assets/screenshots/35.png

50
dynamic_accounts_report/README.rst

@ -0,0 +1,50 @@
.. image:: https://img.shields.io/badge/licence-LGPL--3-green.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
Dynamic Financial Reports
=========================
* Dynamic financial reports for Odoo 17 community editions
Configuration
=============
* No need of additional configuration.
License
-------
Lesser General Public License, Version 3 (LGPL-3).
(https://www.gnu.org/licenses/lgpl-3.0.en.html)
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
=======
* Developer: (v15) Jibin @ Cybrosys,
(v15) Mehjabin @ Cybrosys,
(v15) Mily @ Cybrosys,
(v16) Aneesh @ Cybrosys,
(v17) Ammu Raj @ Cybrosys, Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

24
dynamic_accounts_report/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from . import controllers
from . import models
from . import report

81
dynamic_accounts_report/__manifest__.py

@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
{
'name': 'Dynamic Accounts Reports',
'version': '17.0.1.0.0',
'category': 'Accounting',
'summary': "Dynamic Financial Reports with drill down and filters–"
"Community Edition",
'description': "This module creates dynamic Accounting General Ledger, Trial"
"Balance, Balance Sheet, Proft and Loss, Cash Book, Partner"
"Ledger, Aged Payable, Aged Receivable, Bank book and Tax"
"Reports in Odoo 17 community edition, Reporting, Odoo17 Accounting, odoo17 reporting, odoo17, odoo17 accounts reports",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['base_accounting_kit'],
'data': [
'security/ir.model.access.csv',
'views/accounting_report_views.xml',
'report/trial_balance.xml',
'report/general_ledger_templates.xml',
'report/financial_report_template.xml',
'report/partner_ledger_templates.xml',
'report/financial_reports_views.xml',
'report/balance_sheet_report_templates.xml',
'report/bank_book_templates.xml',
'report/aged_payable_templates.xml',
'report/aged_receivable_templates.xml',
'report/tax_report_templates.xml',
],
'assets': {
'web.assets_backend': [
'dynamic_accounts_report/static/src/xml/general_ledger_view.xml',
'dynamic_accounts_report/static/src/xml/trial_balance_view.xml',
'dynamic_accounts_report/static/src/xml/cash_flow_templates.xml',
'dynamic_accounts_report/static/src/xml/bank_flow_templates.xml',
'dynamic_accounts_report/static/src/xml/profit_and_loss_templates.xml',
'dynamic_accounts_report/static/src/xml/balance_sheet_template.xml',
'dynamic_accounts_report/static/src/xml/partner_ledger_view.xml',
'dynamic_accounts_report/static/src/xml/aged_payable_report_views.xml',
'dynamic_accounts_report/static/src/xml/aged_receivable_report_views.xml',
'dynamic_accounts_report/static/src/xml/tax_report_views.xml',
'dynamic_accounts_report/static/src/css/accounts_report.css',
'dynamic_accounts_report/static/src/js/general_ledger.js',
'dynamic_accounts_report/static/src/js/trial_balance.js',
'dynamic_accounts_report/static/src/js/cash_flow.js',
'dynamic_accounts_report/static/src/js/bank_flow.js',
'dynamic_accounts_report/static/src/js/profit_and_loss.js',
'dynamic_accounts_report/static/src/js/balance_sheet.js',
'dynamic_accounts_report/static/src/js/partner_ledger.js',
'dynamic_accounts_report/static/src/js/aged_payable_report.js',
'dynamic_accounts_report/static/src/js/aged_receivable_report.js',
'dynamic_accounts_report/static/src/js/tax_report.js',
],
},
'images': ['static/description/banner.png'],
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

22
dynamic_accounts_report/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import controllers

69
dynamic_accounts_report/controllers/controllers.py

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import json
from odoo import http
from odoo.http import content_disposition, request
from odoo.tools import html_escape
class XLSXReportController(http.Controller):
@http.route('/xlsx_report', type='http', auth='user', methods=['POST'],
csrf=False)
def get_report_xlsx(self, model, data, output_format, report_name):
"""Generate an XLSX report based on the provided data and return it as
a response.
Args:
model (str): The name of the model on which the report is based.
data (str): The data required for generating the report.
output_format (str): The desired output format for the report
(e.g., 'xlsx').
report_name (str): The name to be given to the generated report
file.
Returns:
Response: The generated report file as a response.
Raises:
Exception: If an error occurs during report generation.
"""
uid = request.session.uid
report_obj = request.env[model].with_user(uid)
token = 'dummy-because-api-expects-one'
try:
if output_format == 'xlsx':
response = request.make_response(
None,
headers=[
('Content-Type', 'application/vnd.ms-excel'),
('Content-Disposition',
content_disposition(report_name + '.xlsx'))
]
)
report_obj.get_xlsx_report(data, response, report_name)
response.set_cookie('fileToken', token)
return response
except Exception as e:
se = http.serialize_exception(e)
error = {
'code': 200,
'message': 'Odoo Server Error',
'data': se
}
return request.make_response(html_escape(json.dumps(error)))

6
dynamic_accounts_report/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <dynamic_accounts_report>
#### 12.12.2023
#### Version 17.0.1.0.0
#### ADD
- Initial commit for Dynamic Accounts Reports

2312
dynamic_accounts_report/i18n/ar_001.po

File diff suppressed because it is too large

2324
dynamic_accounts_report/i18n/de_CH.po

File diff suppressed because it is too large

2312
dynamic_accounts_report/i18n/es_AR.po

File diff suppressed because it is too large

2312
dynamic_accounts_report/i18n/fr_BE.po

File diff suppressed because it is too large

2312
dynamic_accounts_report/i18n/id.po

File diff suppressed because it is too large

2312
dynamic_accounts_report/i18n/uk_UA.po

File diff suppressed because it is too large

31
dynamic_accounts_report/models/__init__.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from . import account_general_ledger
from . import account_partner_ledger
from . import account_trial_balance
from . import aged_payable_report
from . import aged_receivable_report
from . import bank_book_report
from . import cash_book_report
from . import dynamic_balance_sheet_report
from . import tax_report

329
dynamic_accounts_report/models/account_general_ledger.py

@ -0,0 +1,329 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
import calendar
from dateutil.relativedelta import relativedelta
import xlsxwriter
from odoo import api, fields, models
from datetime import datetime
from odoo.tools import date_utils
class AccountGeneralLedger(models.TransientModel):
"""For creating General Ledger report"""
_name = 'account.general.ledger'
_description = 'General Ledger Report'
@api.model
def view_report(self, option, tag):
"""
Retrieve partner ledger report data based on options and tags.
:param option: The options to filter the report data.
:type option: str
:param tag: The tag to filter the report data.
:type tag: str
:return: A dictionary containing the partner ledger report data.
:rtype: dict
"""
account_dict = {}
account_totals = {}
move_line_ids = self.env['account.move.line'].search(
[('parent_state', '=', 'posted')])
account_ids = move_line_ids.mapped('account_id')
account_dict['journal_ids'] = self.env['account.journal'].search_read(
[], ['name'])
account_dict['analytic_ids'] = self.env[
'account.analytic.account'].search_read(
[], ['name'])
for account in account_ids:
move_line_id = move_line_ids.filtered(
lambda x: x.account_id == account)
move_line_list = []
for move_line in move_line_id:
move_line_data = move_line.read(
['date', 'name', 'move_name', 'debit', 'credit',
'partner_id', 'account_id', 'journal_id', 'move_id',
'analytic_line_ids'])
move_line_list.append(move_line_data)
account_dict[account.display_name] = move_line_list
currency_id = self.env.company.currency_id.symbol
account_totals[account.display_name] = {
'total_debit': round(sum(move_line_id.mapped('debit')), 2),
'total_credit': round(sum(move_line_id.mapped('credit')), 2),
'currency_id': currency_id,
'account_id': account.id}
account_dict['account_totals'] = account_totals
return account_dict
@api.model
def get_filter_values(self, journal_id, date_range, options, analytic,
method):
"""
Retrieve filtered values for the partner ledger report.
:param journal_id: The journal IDs to filter the report data.
:type journal_id: list
:param date_range: The date range option to filter the report data.
:type date_range: str or dict
:param options: The additional options to filter the report data.
:type options: dict
:param method: Find the method
:type options: dict
:param analytic: The analytic IDs to filter the report data.
:type analytic: list
:return: A dictionary containing the filtered values for the partner
ledger report.
:rtype: dict
"""
account_dict = {}
account_totals = {}
today = fields.Date.today()
quarter_start, quarter_end = date_utils.get_quarter(today)
previous_quarter_start = quarter_start - relativedelta(months=3)
previous_quarter_end = quarter_start - relativedelta(days=1)
if options == {}:
options = None
if options is None:
option_domain = ['posted']
elif 'draft' in options:
option_domain = ['posted', 'draft']
domain = [('journal_id', 'in', journal_id),
('parent_state', 'in', option_domain), ] if journal_id else [
('parent_state', 'in', option_domain), ]
if method == {}:
method = None
if method is not None and 'cash' in method:
domain += [('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids), ]
if analytic:
analytic_line = self.env['account.analytic.line'].search(
[('account_id', 'in', analytic)]).mapped('id')
domain += [('analytic_line_ids', 'in', analytic_line)]
if date_range:
if date_range == 'month':
domain += [('date', '>=', today.replace(day=1)),
('date', '<=', today)]
elif date_range == 'year':
domain += [('date', '>=', today.replace(month=1, day=1)),
('date', '<=', today)]
elif date_range == 'quarter':
domain += [('date', '>=', quarter_start),
('date', '<=', quarter_end)]
elif date_range == 'last-month':
last_month_start = today.replace(day=1) - relativedelta(
months=1)
last_month_end = last_month_start + relativedelta(
day=calendar.monthrange(last_month_start.year,
last_month_start.month)[
1])
domain += [('date', '>=', last_month_start),
('date', '<=', last_month_end)]
elif date_range == 'last-year':
last_year_start = today.replace(month=1,
day=1) - relativedelta(years=1)
last_year_end = last_year_start.replace(month=12, day=31)
domain += [('date', '>=', last_year_start),
('date', '<=', last_year_end)]
elif date_range == 'last-quarter':
domain += [('date', '>=', previous_quarter_start),
('date', '<=', previous_quarter_end)]
elif 'start_date' in date_range and 'end_date' in date_range:
start_date = datetime.strptime(date_range['start_date'],
'%Y-%m-%d').date()
end_date = datetime.strptime(date_range['end_date'],
'%Y-%m-%d').date()
domain += [('date', '>=', start_date),
('date', '<=', end_date)]
elif 'start_date' in date_range:
start_date = datetime.strptime(date_range['start_date'],
'%Y-%m-%d').date()
domain += [('date', '>=', start_date)]
elif 'end_date' in date_range:
end_date = datetime.strptime(date_range['end_date'],
'%Y-%m-%d').date()
domain += [('date', '<=', end_date)]
move_line_ids = self.env['account.move.line'].search(domain)
account_ids = move_line_ids.mapped('account_id')
account_dict['journal_ids'] = self.env['account.journal'].search_read(
[], ['name'])
account_dict['analytic_ids'] = self.env[
'account.analytic.account'].search_read(
[], ['name'])
for account in account_ids:
move_line_id = move_line_ids.filtered(
lambda x: x.account_id == account)
move_line_list = []
for move_line in move_line_id:
move_line_data = move_line.read(
['date', 'name', 'move_name', 'debit', 'credit',
'partner_id', 'account_id', 'journal_id', 'move_id',
'analytic_line_ids'])
move_line_list.append(move_line_data)
account_dict[account.display_name] = move_line_list
currency_id = self.env.company.currency_id.symbol
account_totals[account.display_name] = {
'total_debit': round(sum(move_line_id.mapped('debit')), 2),
'total_credit': round(sum(move_line_id.mapped('credit')), 2),
'currency_id': currency_id,
'account_id': account.id}
account_dict['account_totals'] = account_totals
return account_dict
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an XLSX report based on the provided data and write it to the
response stream.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the generated report to.
:type response: werkzeug.wrappers.Response
:param report_name: The name of the report.
:type report_name: str
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
start_date = data['filters']['start_date'] if \
data['filters']['start_date'] else ''
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '15px'})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Journals', filter_head)
sheet.write('B5:b4', 'Analytic', filter_head)
sheet.write('B6:b4', 'Options', filter_head)
if start_date or end_date:
sheet.merge_range('C3:G3', f"{start_date} to {end_date}",
filter_body)
if data['filters']['journal']:
display_names = [journal for
journal in data['filters']['journal']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data['filters']['analytic']:
display_names = [analytic for
analytic in data['filters']['analytic']]
account_keys_str = ', '.join(display_names)
sheet.merge_range('C5:G5', account_keys_str, filter_body)
if data['filters']['options']:
option_keys = list(data['filters']['options'].keys())
option_keys_str = ', '.join(option_keys)
sheet.merge_range('C6:G6', option_keys_str, filter_body)
if data:
if report_name == 'General Ledger':
sheet.write(8, col, ' ', sub_heading)
sheet.write(8, col + 1, 'Date', sub_heading)
sheet.merge_range('C9:E9', 'Communication', sub_heading)
sheet.merge_range('F9:G9', 'Partner', sub_heading)
sheet.merge_range('H9:I9', 'Debit', sub_heading)
sheet.merge_range('J9:K9', 'Credit', sub_heading)
sheet.merge_range('L9:M9', 'Balance', sub_heading)
row = 8
for account in data['account']:
row += 1
sheet.write(row, col, account, txt_name)
sheet.write(row, col + 1, ' ', txt_name)
sheet.merge_range(row, col + 2, row, col + 4, ' ', txt_name)
sheet.merge_range(row, col + 5, row, col + 6, ' ',
txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
data['total'][account]['total_debit'],
txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
data['total'][account]['total_credit'],
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
data['total'][account]['total_debit'] -
data['total'][account]['total_credit'],
txt_name)
for rec in data['data'][account]:
row += 1
partner = rec[0]['partner_id']
name = partner[1] if partner else None
sheet.write(row, col, rec[0]['move_name'], txt_name)
sheet.write(row, col + 1, rec[0]['date'], txt_name)
sheet.merge_range(row, col + 2, row, col + 4,
rec[0]['name'], txt_name)
sheet.merge_range(row, col + 5, row, col + 6, name,
txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
rec[0]['debit'],
txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
rec[0]['credit'], txt_name)
sheet.merge_range(row, col + 11, row, col + 12, ' ',
txt_name)
row += 1
sheet.merge_range(row, col, row, col + 6, 'Total',
filter_head)
sheet.merge_range(row, col + 7, row, col + 8,
data['grand_total']['total_debit'],
filter_head)
sheet.merge_range(row, col + 9, row, col + 10,
data['grand_total']['total_credit'],
filter_head)
sheet.merge_range(row, col + 11, row, col + 12,
float(data['grand_total']['total_debit']) -
float(data['grand_total']['total_credit']),
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

370
dynamic_accounts_report/models/account_partner_ledger.py

@ -0,0 +1,370 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
from dateutil.relativedelta import relativedelta
import xlsxwriter
from odoo import api, fields, models
from datetime import datetime
from odoo.tools import date_utils
class AccountPartnerLedger(models.TransientModel):
"""For creating Partner Ledger report"""
_name = 'account.partner.ledger'
_description = 'Partner Ledger Report'
@api.model
def view_report(self, option, tag):
"""
Retrieve partner-related data for generating a report.
:param option: The option for filtering the data.
:type option: str
:param tag: The tag used for filtering the data.
:type tag: str
:return: A dictionary containing the partner data for the report.
:rtype: dict
"""
partner_dict = {}
partner_totals = {}
move_line_ids = self.env['account.move.line'].search(
[('account_type', 'in',
['liability_payable', 'asset_receivable']),
('parent_state', '=', 'posted')])
partner_ids = move_line_ids.mapped('partner_id')
for partner in partner_ids:
move_line_id = move_line_ids.filtered(
lambda x: x.partner_id == partner)
move_line_list = []
for move_line in move_line_id:
move_line_data = move_line.read(
['date', 'move_name', 'account_type', 'debit', 'credit',
'date_maturity', 'account_id', 'journal_id', 'move_id',
'matching_number', 'amount_currency'])
account_code = self.env['account.account'].browse(
move_line.account_id.id).code
journal_code = self.env['account.journal'].browse(
move_line.journal_id.id).code
if account_code:
move_line_data[0]['jrnl'] = journal_code
move_line_data[0]['code'] = account_code
move_line_list.append(move_line_data)
partner_dict[partner.name] = move_line_list
currency_id = self.env.company.currency_id.symbol
partner_totals[partner.name] = {
'total_debit': round(sum(move_line_id.mapped('debit')), 2),
'total_credit': round(sum(move_line_id.mapped('credit')), 2),
'currency_id': currency_id,
'partner_id': partner.id}
partner_dict['partner_totals'] = partner_totals
return partner_dict
@api.model
def get_filter_values(self, partner_id, data_range, account, options):
"""
Retrieve filtered partner-related data for generating a report.
:param partner_id: The ID(s) of the partner(s) to filter by.
:type partner_id: list or int
:param data_range: The date range option for filtering the data.
:type data_range: str
:param account: The account type(s) to filter by.
:type account: list or str
:param options: Additional options for filtering the data.
:type options: dict
:return: A dictionary containing the filtered partner data.
:rtype: dict
"""
if options == {}:
options = None
if account == {}:
account = None
account_type_domain = []
if options is None:
option_domain = ['posted']
elif 'draft' in options:
option_domain = ['posted', 'draft']
if account is None or (
'Receivable' in account and 'Payable' in account):
account_type_domain.append('liability_payable')
account_type_domain.append('asset_receivable')
elif 'Receivable' in account:
account_type_domain.append('asset_receivable')
elif 'Payable' in account:
account_type_domain.append('liability_payable')
partner_dict = {}
partner_totals = {}
today = fields.Date.today()
quarter_start, quarter_end = date_utils.get_quarter(today)
previous_quarter_start = quarter_start - relativedelta(months=3)
previous_quarter_end = quarter_start - relativedelta(days=1)
if not partner_id:
partner_id = self.env['account.move.line'].search([(
'account_type', 'in', account_type_domain),
('parent_state', 'in', option_domain)]).mapped(
'partner_id').ids
for partners in partner_id:
partner = self.env['res.partner'].browse(partners).name
if data_range:
if data_range == 'month':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('parent_state', 'in', option_domain)]).filtered(
lambda x: x.date.month == fields.Date.today().month)
elif data_range == 'year':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('parent_state', 'in', option_domain)]).filtered(
lambda x: x.date.year == fields.Date.today().year)
elif data_range == 'quarter':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('date', '>=', quarter_start),
('date', '<=', quarter_end),
('parent_state', 'in', option_domain)])
elif data_range == 'last-month':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('parent_state', 'in', option_domain)]).filtered(
lambda x: x.date.month == fields.Date.today().month - 1)
elif data_range == 'last-year':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('parent_state', 'in', option_domain)]).filtered(
lambda x: x.date.year == fields.Date.today().year - 1)
elif data_range == 'last-quarter':
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('date', '>=', previous_quarter_start),
('date', '<=', previous_quarter_end),
('parent_state', 'in', option_domain)])
elif 'start_date' in data_range and 'end_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('date', '>=', start_date),
('date', '<=', end_date),
('parent_state', 'in', option_domain)])
elif 'start_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('date', '>=', start_date),
('parent_state', 'in', option_domain)])
elif 'end_date' in data_range:
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('date', '<=', end_date),
('parent_state', 'in', option_domain)])
else:
move_line_ids = self.env['account.move.line'].search(
[('partner_id', '=', partners), (
'account_type', 'in',
account_type_domain),
('parent_state', 'in', option_domain)])
move_line_list = []
for move_line in move_line_ids:
move_line_data = move_line.read(
['date', 'move_name', 'account_type', 'debit', 'credit',
'date_maturity', 'account_id', 'journal_id', 'move_id',
'matching_number', 'amount_currency'])
account_code = self.env['account.account'].browse(
move_line.account_id.id).code
journal_code = self.env['account.journal'].browse(
move_line.journal_id.id).code
if account_code:
move_line_data[0]['jrnl'] = journal_code
move_line_data[0]['code'] = account_code
move_line_list.append(move_line_data)
partner_dict[partner] = move_line_list
currency_id = self.env.company.currency_id.symbol
partner_totals[partner] = {
'total_debit': round(sum(move_line_ids.mapped('debit')), 2),
'total_credit': round(sum(move_line_ids.mapped('credit')), 2),
'currency_id': currency_id,
'partner_id': partners}
partner_dict['partner_totals'] = partner_totals
return partner_dict
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an Excel report based on the provided data.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the report to.
:type response: object
:param report_name: The name of the report.
:type report_name: str
:return: None
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
start_date = data['filters']['start_date'] if \
data['filters']['start_date'] else ''
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'font_size': 15, 'align': 'center', 'bold': True})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Partners', filter_head)
sheet.write('B5:b4', 'Accounts', filter_head)
sheet.write('B6:b4', 'Options', filter_head)
if start_date or end_date:
sheet.merge_range('C3:G3', f"{start_date} to {end_date}",
filter_body)
if data['filters']['partner']:
display_names = [partner.get('display_name', 'undefined') for
partner in data['filters']['partner']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data['filters']['account']:
account_keys = list(data['filters']['account'].keys())
account_keys_str = ', '.join(account_keys)
sheet.merge_range('C5:G5', account_keys_str, filter_body)
if data['filters']['options']:
option_keys = list(data['filters']['options'].keys())
option_keys_str = ', '.join(option_keys)
sheet.merge_range('C6:G6', option_keys_str, filter_body)
if data:
if report_name == 'Partner Ledger':
sheet.write(8, col, ' ', sub_heading)
sheet.write(8, col + 1, 'JNRL', sub_heading)
sheet.write(8, col + 2, 'Account', sub_heading)
sheet.merge_range('D9:E9', 'Ref', sub_heading)
sheet.merge_range('F9:G9', 'Due Date', sub_heading)
sheet.merge_range('H9:I9', 'Debit', sub_heading)
sheet.merge_range('J9:K9', 'Credit', sub_heading)
sheet.merge_range('L9:M9', 'Balance', sub_heading)
row = 8
for partner in data['partners']:
row += 1
sheet.write(row, col, partner, txt_name)
sheet.write(row, col + 1, ' ', txt_name)
sheet.write(row, col + 2, ' ', txt_name)
sheet.merge_range(row, col + 3, row, col + 4, ' ',
txt_name)
sheet.merge_range(row, col + 5, row, col + 6, ' ',
txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
data['total'][partner]['total_debit'],
txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
data['total'][partner]['total_credit'],
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
data['total'][partner]['total_debit'] -
data['total'][partner]['total_credit'],
txt_name)
for rec in data['data'][partner]:
row += 1
sheet.write(row, col, rec[0]['date'], txt_name)
sheet.write(row, col + 1, rec[0]['jrnl'], txt_name)
sheet.write(row, col + 2, rec[0]['code'], txt_name)
sheet.merge_range(row, col + 3, row, col + 4,
rec[0]['move_name'],
txt_name)
sheet.merge_range(row, col + 5, row, col + 6,
rec[0]['date_maturity'],
txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
rec[0]['debit'], txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
rec[0]['credit'], txt_name)
sheet.merge_range(row, col + 11, row, col + 12, ' ',
txt_name)
row += 1
sheet.merge_range(row, col, row, col + 6, 'Total', filter_head)
sheet.merge_range(row, col + 7, row, col + 8,
data['grand_total']['total_debit'],
filter_head)
sheet.merge_range(row, col + 9, row, col + 10,
data['grand_total']['total_credit'],
filter_head)
sheet.merge_range(row, col + 11, row, col + 12,
data['grand_total']['total_debit'] -
data['grand_total']['total_credit'],
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

449
dynamic_accounts_report/models/account_trial_balance.py

@ -0,0 +1,449 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import calendar
import io
import json
from datetime import datetime
import xlsxwriter
from odoo import api, fields, models
from odoo.tools.date_utils import get_month, get_fiscal_year, \
get_quarter_number, subtract
class AccountTrialBalance(models.TransientModel):
"""For creating Trial Balance report"""
_name = 'account.trial.balance'
_description = 'Trial Balance Report'
@api.model
def view_report(self):
"""
Generates a trial balance report for multiple accounts.
Retrieves account information and calculates total debit and credit
amounts for each account within the specified date range. Returns a list
of dictionaries containing account details and transaction totals.
:return: List of dictionaries representing the trial balance report.
:rtype: list
"""
account_ids = self.env['account.move.line'].search([]).mapped(
'account_id')
today = fields.Date.today()
move_line_list = []
for account_id in account_ids:
initial_move_line_ids = self.env['account.move.line'].search(
[('date', '<', get_month(today)[0]),
('account_id', '=', account_id.id),
('parent_state', '=', 'posted')])
initial_total_debit = round(
sum(initial_move_line_ids.mapped('debit')), 2)
initial_total_credit = round(
sum(initial_move_line_ids.mapped('credit')), 2)
move_line_ids = self.env['account.move.line'].search(
[('date', '>=', get_month(today)[0]),
('account_id', '=', account_id.id),
('date', '<=', get_month(today)[1]),
('parent_state', '=', 'posted')])
total_debit = round(sum(move_line_ids.mapped('debit')), 2)
total_credit = round(sum(move_line_ids.mapped('credit')), 2)
sum_debit = initial_total_debit + total_debit
sum_credit = initial_total_credit + total_credit
diff_credit_debit = sum_debit - sum_credit
if diff_credit_debit > 0:
end_total_debit = diff_credit_debit
end_total_credit = 0.0
else:
end_total_debit = 0.0
end_total_credit = abs(diff_credit_debit)
data = {
'account': account_id.display_name,
'account_id': account_id.id,
'journal_ids': self.env['account.journal'].search_read([], [
'name']),
'initial_total_debit': initial_total_debit,
'initial_total_credit': initial_total_credit,
'total_debit': total_debit,
'total_credit': total_credit,
'end_total_debit': end_total_debit,
'end_total_credit': end_total_credit
}
move_line_list.append(data)
return move_line_list
@api.model
def get_filter_values(self, start_date, end_date, comparison_number,
comparison_type, journal_list, analytic, options,
method):
"""
Retrieves and calculates filtered values for generating a financial
report.
Retrieves and processes account movement data based on the provided
filters. Calculates initial, dynamic, and end total debit and credit
amounts for each account,considering date range, comparison type, and
other filter criteria.
:param str start_date: Start date of the reporting period.
:param str end_date: End date of the reporting period.
:param int comparison_number: Number of periods for comparison.
:param str comparison_type: Type of comparison (month, year, quarter).
:param list[int] journal_list: List of selected journal IDs.
:param list[int] analytic: List of selected analytic line IDs.
:param dict options: Additional filtering options (e.g., 'draft').
:param dict method: Find the method.
:return: List of dictionaries representing the financial report.
:rtype: list
"""
if options == {}:
options = None
if options is None:
option_domain = ['posted']
elif 'draft' in options:
option_domain = ['posted', 'draft']
if method == {}:
method = None
dynamic_total_debit = {}
dynamic_date_num = {}
dynamic_total_credit = {}
account_ids = self.env['account.move.line'].search([]).mapped(
'account_id')
move_line_list = []
start_date_first = \
get_fiscal_year(datetime.strptime(start_date, "%Y-%m-%d").date())[
0] if comparison_type == 'year' else datetime.strptime(
start_date, "%Y-%m-%d").date()
end_date_first = \
get_fiscal_year(datetime.strptime(end_date, "%Y-%m-%d").date())[
1] if comparison_type == 'year' else datetime.strptime(end_date,
"%Y-%m-%d").date()
for account_id in account_ids:
start_date = start_date_first
end_date = end_date_first
if comparison_number:
if comparison_type == 'month':
initial_start_date = subtract(start_date, months=eval(
comparison_number))
elif comparison_type == 'year':
initial_start_date = subtract(start_date, years=eval(
comparison_number))
else:
initial_start_date = subtract(start_date, months=eval(
comparison_number) * 3)
else:
initial_start_date = start_date
domain = [('date', '<', initial_start_date),
('account_id', '=', account_id.id),
('parent_state', 'in', option_domain), ]
if journal_list:
domain.append(
('journal_id', 'in', journal_list), )
if analytic:
domain.append(
('analytic_line_ids', 'in', analytic))
if method is not None and 'cash' in method:
domain.append(('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids))
initial_move_line_ids = self.env['account.move.line'].search(
domain)
initial_total_debit = round(
sum(initial_move_line_ids.mapped('debit')), 2)
initial_total_credit = round(
sum(initial_move_line_ids.mapped('credit')), 2)
if comparison_number:
if comparison_type == 'year':
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date, years=i)
com_end_date = subtract(end_date, years=i)
domain = [('date', '>=', com_start_date),
('account_id', '=', account_id.id),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain), ]
if journal_list:
domain.append(
('journal_id', 'in', journal_list), )
if analytic:
domain.append(
('analytic_line_ids', 'in', analytic))
if method is not None and 'cash' in method:
domain.append(('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids))
move_lines = self.env['account.move.line'].search(
domain)
dynamic_total_debit[
f"dynamic_total_debit_{i}"] = round(
sum(move_lines.mapped('debit')), 2)
dynamic_total_credit[
f"dynamic_total_credit_{i}"] = round(
sum(move_lines.mapped('credit')), 2)
if comparison_type == 'month':
dynamic_date_num[
f"dynamic_date_num{0}"] = self.get_month_name(
start_date) + ' ' + str(
start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date, months=i)
com_end_date = subtract(end_date, months=i)
domain = [('date', '>=', com_start_date),
('account_id', '=', account_id.id),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain), ]
if journal_list:
domain.append(
('journal_id', 'in', journal_list), )
if analytic:
domain.append(
('analytic_line_ids', 'in', analytic))
if method is not None and 'cash' in method:
domain.append(('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids), )
move_lines = self.env['account.move.line'].search(
domain)
dynamic_date_num[
f"dynamic_date_num{i}"] = self.get_month_name(
com_start_date) + ' ' + str(
com_start_date.year)
dynamic_total_debit[
f"dynamic_total_debit_{i}"] = round(
sum(move_lines.mapped('debit')), 2)
dynamic_total_credit[
f"dynamic_total_credit_{i}"] = round(
sum(move_lines.mapped('credit')), 2)
if comparison_type == 'quarter':
dynamic_date_num[
f"dynamic_date_num{0}"] = 'Q' + ' ' + str(
get_quarter_number(start_date)) + ' ' + str(
start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date, months=i * 3)
com_end_date = subtract(end_date, months=i * 3)
domain = [('date', '>=', com_start_date),
('account_id', '=', account_id.id),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain), ]
if journal_list:
domain.append(
('journal_id', 'in', journal_list), )
if analytic:
domain.append(
('analytic_line_ids', 'in', analytic))
if method is not None and 'cash' in method:
domain.append(('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids))
move_lines = self.env['account.move.line'].search(
domain)
dynamic_date_num[
f"dynamic_date_num{i}"] = 'Q' + ' ' + str(
get_quarter_number(com_start_date)) + ' ' + str(
com_start_date.year)
dynamic_total_debit[
f"dynamic_total_debit_{i}"] = round(
sum(move_lines.mapped('debit')), 2)
dynamic_total_credit[
f"dynamic_total_credit_{i}"] = round(
sum(move_lines.mapped('credit')), 2)
domain = [('date', '>=', start_date),
('account_id', '=', account_id.id),
('date', '<=', end_date),
('parent_state', 'in', option_domain), ]
if journal_list:
domain.append(
('journal_id', 'in', journal_list), )
if analytic:
domain.append(
('analytic_line_ids', 'in', analytic))
if method is not None and 'cash' in method:
domain.append(('journal_id', 'in',
self.env.company.tax_cash_basis_journal_id.ids))
move_line_ids = self.env['account.move.line'].search(domain)
total_debit = round(sum(move_line_ids.mapped('debit')), 2)
total_credit = round(sum(move_line_ids.mapped('credit')), 2)
sum_debit = initial_total_debit + sum(
dynamic_total_debit.values()) + total_debit
sum_credit = initial_total_credit + sum(
dynamic_total_credit.values()) + total_credit
diff_credit_debit = sum_debit - sum_credit
if diff_credit_debit > 0:
end_total_debit = diff_credit_debit
end_total_credit = 0.0
else:
end_total_debit = 0.0
end_total_credit = abs(diff_credit_debit)
data = {
'account': account_id.display_name,
'account_id': account_id.id,
'journal_ids': self.env['account.journal'].search_read([], [
'name']),
'initial_total_debit': initial_total_debit,
'initial_total_credit': initial_total_credit,
'total_debit': total_debit,
'total_credit': total_credit,
'end_total_debit': end_total_debit,
'end_total_credit': end_total_credit
}
if comparison_number:
if dynamic_date_num:
data['dynamic_date_num'] = dynamic_date_num
for i in range(1, eval(comparison_number) + 1):
data[f'dynamic_total_debit_{i}'] = dynamic_total_debit.get(
f"dynamic_total_debit_{eval(comparison_number) + 1 - i}",
0.0)
data[
f'dynamic_total_credit_{i}'] = dynamic_total_credit.get(
f"dynamic_total_credit_{eval(comparison_number) + 1 - i}",
0.0)
move_line_list.append(data)
return move_line_list
@api.model
def get_month_name(self, date):
"""
Retrieve the abbreviated name of the month for a given date.
:param date: The date for which to retrieve the month's abbreviated name.
:type date: datetime.date
:return: Abbreviated name of the month (e.g., 'Jan', 'Feb', ..., 'Dec').
:rtype: str
"""
month_names = calendar.month_abbr
return month_names[date.month]
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an XLSX report based on provided data and response stream.
Generates an Excel workbook with specified report format, including
subheadings,column headers, and row data for the given financial report
data.
:param str data: JSON-encoded data for the report.
:param response: Response object to stream the generated report.
:param str report_name: Name of the financial report.
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
start_date = data['filters']['start_date'] if \
data['filters']['start_date'] else ''
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
head = workbook.add_format(
{'font_size': 15, 'align': 'center', 'bold': True})
sheet = workbook.add_worksheet()
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Comparison', filter_head)
sheet.write('B5:b4', 'Journal', filter_head)
sheet.write('B6:b4', 'Account', filter_head)
sheet.write('B7:b4', 'Option', filter_head)
if start_date or end_date:
sheet.merge_range('C3:G3', f"{start_date} to {end_date}",
filter_body)
if data['filters']['comparison_number_range']:
sheet.merge_range('C4:G4',
f"{data['filters']['comparison_type']} : {data['filters']['comparison_number_range']}",
filter_body)
if data['filters']['journal']:
display_names = [journal for
journal in data['filters']['journal']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C5:G5', display_names_str, filter_body)
if data['filters']['account']:
account_keys = [account.get('display_name', 'undefined') for
account in data['filters']['account']]
account_keys_str = ', '.join(account_keys)
sheet.merge_range('C6:G6', account_keys_str, filter_body)
if data['filters']['options']:
option_keys = list(data['filters']['options'].keys())
option_keys_str = ', '.join(option_keys)
sheet.merge_range('C7:G7', option_keys_str, filter_body)
sheet.write(9, col, '', sub_heading)
sheet.merge_range(9, col + 1, 9, col + 2, 'Initial Balance',
sub_heading)
i = 3
for date_view in data['date_viewed']:
sheet.merge_range(9, col + i, 9, col + i + 1, date_view,
sub_heading)
i += 2
sheet.merge_range(9, col + i, 9, col + i + 1, 'End Balance',
sub_heading)
sheet.write(10, col, '', sub_heading)
sheet.write(10, col + 1, 'Debit', sub_heading)
sheet.write(10, col + 2, 'Credit', sub_heading)
i = 3
for date_views in data['date_viewed']:
sheet.write(10, col + i, 'Debit', sub_heading)
i += 1
sheet.write(10, col + i, 'Credit', sub_heading)
i += 1
sheet.write(10, col + i, 'Debit', sub_heading)
sheet.write(10, col + (i + 1), 'Credit', sub_heading)
if data:
if report_name == 'Trial Balance':
row = 11
for move_line in data['data']:
sheet.write(row, col, move_line['account'],
side_heading_sub)
sheet.write(row, col + 1, move_line['initial_total_debit'],
txt_name)
sheet.write(row, col + 2,
move_line['initial_total_credit'], txt_name)
j = 3
if data['apply_comparison']:
number_of_periods = data['comparison_number_range']
for num in number_of_periods:
sheet.write(row, col + j, move_line[
'dynamic_total_debit_' + str(num)], txt_name)
sheet.write(row, col + j + 1, move_line[
'dynamic_total_credit_' + str(num)], txt_name)
j += 2
sheet.write(row, col + j, move_line['total_debit'],
txt_name)
sheet.write(row, col + j + 1, move_line['total_credit'],
txt_name)
sheet.write(row, col + j + 2, move_line['end_total_debit'],
txt_name)
sheet.write(row, col + j + 3,
move_line['end_total_credit'], txt_name)
row += 1
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

305
dynamic_accounts_report/models/aged_payable_report.py

@ -0,0 +1,305 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
import xlsxwriter
from odoo import api, fields, models
class AgePayableReport(models.TransientModel):
"""For creating Age Payable report"""
_name = 'age.payable.report'
_description = 'Aged Payable Report'
@api.model
def view_report(self):
"""
Generate a report with move line data categorized by partner and credit
difference.
Returns:
dict: Dictionary containing move line data categorized by partner
names. Each partner's data includes credit amounts and credit
differences based on days between maturity date and today. The
'partner_totals' key contains summary data for each partner.
"""
partner_total = {}
move_line_list = {}
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'liability_payable'),
('reconciled', '=', False)])
currency_id = self.env.company.currency_id.symbol
partner_ids = paid.mapped('partner_id')
today = fields.Date.today()
for partner_id in partner_ids:
move_line_ids = paid.filtered(
lambda rec: rec.partner_id in partner_id)
move_line_data = move_line_ids.read(
['name', 'move_name', 'date', 'amount_currency', 'account_id',
'date_maturity', 'currency_id', 'credit', 'move_id'])
for val in move_line_data:
diffrence = (today - val['date_maturity']).days
val['diff0'] = val['credit'] if diffrence <= 0 else 0.0
val['diff1'] = val['credit'] if 0 < diffrence <= 30 else 0.0
val['diff2'] = val['credit'] if 30 < diffrence <= 60 else 0.0
val['diff3'] = val['credit'] if 60 < diffrence <= 90 else 0.0
val['diff4'] = val['credit'] if 90 < diffrence <= 120 else 0.0
val['diff5'] = val['credit'] if diffrence > 120 else 0.0
move_line_list[partner_id.name] = move_line_data
partner_total[partner_id.name] = {
'credit_sum': sum(val['credit'] for val in move_line_data),
'diff0_sum': round(sum(val['diff0'] for val in move_line_data),
2),
'diff1_sum': round(sum(val['diff1'] for val in move_line_data),
2),
'diff2_sum': round(sum(val['diff2'] for val in move_line_data),
2),
'diff3_sum': round(sum(val['diff3'] for val in move_line_data),
2),
'diff4_sum': round(sum(val['diff4'] for val in move_line_data),
2),
'diff5_sum': round(sum(val['diff5'] for val in move_line_data),
2),
'currency_id': currency_id,
'partner_id': partner_id.id
}
move_line_list['partner_totals'] = partner_total
return move_line_list
@api.model
def get_filter_values(self, date, partner):
"""
Retrieve filtered move line data based on date and partner(s).
Parameters:
date (str): Date for filtering move lines (format: 'YYYY-MM-DD').
partner (list): List of partner IDs to filter move lines for.
Returns:
dict: Dictionary with filtered move line data organized by partner
names. Includes credit amount categorization based on days
difference. Contains partner-wise summary under
'partner_totals' key.
"""
partner_total = {}
move_line_list = {}
if date:
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'liability_payable'),
('reconciled', '=', False), ('date', '<=', date)])
else:
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'liability_payable'),
('reconciled', '=', False)])
currency_id = self.env.company.currency_id.symbol
if partner:
partner_ids = self.env['res.partner'].search(
[('id', 'in', partner)])
else:
partner_ids = paid.mapped('partner_id')
today = fields.Date.today()
for partner_id in partner_ids:
move_line_ids = paid.filtered(
lambda rec: rec.partner_id in partner_id)
move_line_data = move_line_ids.read(
['name', 'move_name', 'date', 'amount_currency', 'account_id',
'date_maturity', 'currency_id', 'credit', 'move_id'])
for val in move_line_data:
diffrence = (today - val['date_maturity']).days
val['diff0'] = val['credit'] if diffrence <= 0 else 0.0
val['diff1'] = val['credit'] if 0 < diffrence <= 30 else 0.0
val['diff2'] = val['credit'] if 30 < diffrence <= 60 else 0.0
val['diff3'] = val['credit'] if 60 < diffrence <= 90 else 0.0
val['diff4'] = val['credit'] if 90 < diffrence <= 120 else 0.0
val['diff5'] = val['credit'] if diffrence > 120 else 0.0
move_line_list[partner_id.name] = move_line_data
partner_total[partner_id.name] = {
'credit_sum': sum(val['credit'] for val in move_line_data),
'diff0_sum': round(sum(val['diff0'] for val in move_line_data),
2),
'diff1_sum': round(sum(val['diff1'] for val in move_line_data),
2),
'diff2_sum': round(sum(val['diff2'] for val in move_line_data),
2),
'diff3_sum': round(sum(val['diff3'] for val in move_line_data),
2),
'diff4_sum': round(sum(val['diff4'] for val in move_line_data),
2),
'diff5_sum': round(sum(val['diff5'] for val in move_line_data),
2),
'currency_id': currency_id,
'partner_id': partner_id.id
}
move_line_list['partner_totals'] = partner_total
return move_line_list
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an Excel report based on the provided data.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the report to.
:type response: object
:param report_name: The name of the report.
:type report_name: str
:return: None
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '15px'})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Partners', filter_head)
if end_date:
sheet.merge_range('C3:G3', f"{end_date}", filter_body)
if data['filters']['partner']:
display_names = [partner.get('display_name', 'undefined') for
partner in data['filters']['partner']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data:
if report_name == 'Aged Payable':
sheet.write(6, col, ' ', sub_heading)
sheet.write(6, col + 1, 'Invoice Date', sub_heading)
sheet.write(6, col + 2, 'Amount Currency', sub_heading)
sheet.write(6, col + 3, 'Currency', sub_heading)
sheet.merge_range(6, col + 4, 6, col + 5, 'Account',
sub_heading)
sheet.merge_range(6, col + 6, 6, col + 7, 'Expected Date',
sub_heading)
sheet.write(6, col + 8, 'At Date', sub_heading)
sheet.write(6, col + 9, '1-30', sub_heading)
sheet.write(6, col + 10, '31-60', sub_heading)
sheet.write(6, col + 11, '61-90', sub_heading)
sheet.write(6, col + 12, '91-120', sub_heading)
sheet.write(6, col + 13, 'Older', sub_heading)
sheet.write(6, col + 14, 'Total', sub_heading)
row = 6
for move_line in data['move_lines']:
row += 1
sheet.write(row, col, move_line, txt_name)
sheet.write(row, col + 1, ' ', txt_name)
sheet.write(row, col + 2, ' ', txt_name)
sheet.write(row, col + 3, ' ', txt_name)
sheet.merge_range(row, col + 4, row, col + 5, ' ',
txt_name)
sheet.merge_range(row, col + 6, row, col + 7, ' ',
txt_name)
sheet.write(row, col + 8,
data['total'][move_line]['diff0_sum'],
txt_name)
sheet.write(row, col + 9,
data['total'][move_line]['diff1_sum'],
txt_name)
sheet.write(row, col + 10,
data['total'][move_line]['diff2_sum'],
txt_name)
sheet.write(row, col + 11,
data['total'][move_line]['diff3_sum'],
txt_name)
sheet.write(row, col + 12,
data['total'][move_line]['diff4_sum'],
txt_name)
sheet.write(row, col + 13,
data['total'][move_line]['diff5_sum'],
txt_name)
sheet.write(row, col + 14,
data['total'][move_line]['credit_sum'],
txt_name)
for rec in data['data'][move_line]:
row += 1
sheet.write(row, col, rec['move_name'] + rec['name'],
txt_name)
sheet.write(row, col + 1, rec['date'],
txt_name)
sheet.write(row, col + 2, rec['amount_currency'],
txt_name)
sheet.write(row, col + 3, rec['currency_id'][1],
txt_name)
sheet.merge_range(row, col + 4, row, col + 5,
rec['account_id'][1],
txt_name)
sheet.merge_range(row, col + 6, row, col + 7,
rec['date_maturity'],
txt_name)
sheet.write(row, col + 8, rec['diff0'], txt_name)
sheet.write(row, col + 9, rec['diff1'], txt_name)
sheet.write(row, col + 10, rec['diff2'], txt_name)
sheet.write(row, col + 11, rec['diff3'], txt_name)
sheet.write(row, col + 12, rec['diff4'], txt_name)
sheet.write(row, col + 13, rec['diff5'], txt_name)
sheet.write(row, col + 14, ' ', txt_name)
sheet.merge_range(row + 1, col, row + 1, col + 7, 'Total',
filter_head)
sheet.write(row + 1, col + 8,
data['grand_total']['diff0_sum'],
filter_head)
sheet.write(row + 1, col + 9,
data['grand_total']['diff1_sum'],
filter_head)
sheet.write(row + 1, col + 10,
data['grand_total']['diff2_sum'],
filter_head)
sheet.write(row + 1, col + 11,
data['grand_total']['diff3_sum'],
filter_head)
sheet.write(row + 1, col + 12,
data['grand_total']['diff4_sum'],
filter_head)
sheet.write(row + 1, col + 13,
data['grand_total']['diff5_sum'],
filter_head)
sheet.write(row + 1, col + 14,
data['grand_total']['total_credit'],
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

322
dynamic_accounts_report/models/aged_receivable_report.py

@ -0,0 +1,322 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
import xlsxwriter
from odoo import models, fields, api
class AgeReceivableReport(models.TransientModel):
"""For creating Age Receivable report"""
_name = 'age.receivable.report'
_description = 'Aged Receivable Report'
@api.model
def view_report(self):
"""
Generate a report with move line data categorized by partner and debit
difference.This method retrieves move line data from the
'account.move.line' model, filters the records based on specific
criteria (parent_state, account_type, reconciled),and categorizes the
data by each partner's name. For each move line, it calculates the debit
difference based on the number of days between today's date and the
maturity date of the move line.
Returns:
dict: Dictionary containing move line data categorized by partner names.
Each partner's data includes debit amounts and debit differences
based on days between maturity date and today.
The 'partner_totals' key contains summary data for each partner.
"""
partner_total = {}
move_line_list = {}
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'asset_receivable'),
('reconciled', '=', False)])
currency_id = self.env.company.currency_id.symbol
partner_ids = paid.mapped('partner_id')
today = fields.Date.today()
for partner_id in partner_ids:
move_line_ids = paid.filtered(
lambda rec: rec.partner_id in partner_id)
move_line_data = move_line_ids.read(
['name', 'move_name', 'date', 'amount_currency', 'account_id',
'date_maturity', 'currency_id', 'debit', 'move_id'])
for val in move_line_data:
if val['date_maturity']:
diffrence = (today - val['date_maturity']).days
val['diff0'] = val['debit'] if diffrence <= 0 else 0.0
val['diff1'] = val['debit'] if 0 < diffrence <= 30 else 0.0
val['diff2'] = val['debit'] if 30 < diffrence <= 60 else 0.0
val['diff3'] = val['debit'] if 60 < diffrence <= 90 else 0.0
val['diff4'] = val['debit'] if 90 < diffrence <= 120 else 0.0
val['diff5'] = val['debit'] if diffrence > 120 else 0.0
move_line_list[partner_id.name] = move_line_data
partner_total[partner_id.name] = {
'debit_sum': sum(val['debit'] for val in move_line_data),
'diff0_sum': round(sum(val['diff0'] for val in move_line_data),
2),
'diff1_sum': round(sum(val['diff1'] for val in move_line_data),
2),
'diff2_sum': round(sum(val['diff2'] for val in move_line_data),
2),
'diff3_sum': round(sum(val['diff3'] for val in move_line_data),
2),
'diff4_sum': round(sum(val['diff4'] for val in move_line_data),
2),
'diff5_sum': round(sum(val['diff5'] for val in move_line_data),
2),
'currency_id': currency_id,
'partner_id': partner_id.id
}
move_line_list['partner_totals'] = partner_total
return move_line_list
@api.model
def get_filter_values(self, date, partner):
"""
Retrieve move line data categorized by partner and debit difference.
Parameters:
date (str): Date for filtering move lines (format: 'YYYY-MM-DD').
partner (list): List of partner IDs to filter move lines for.
Returns:
dict: Dictionary containing move line data categorized by partner
names.Includes debit amount categorization based on days
difference.Contains partner-wise summary under
'partner_totals' key.
"""
partner_total = {}
move_line_list = {}
if date:
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'asset_receivable'),
('reconciled', '=', False), ('date', '<=', date)])
else:
paid = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('account_type', '=', 'asset_receivable'),
('reconciled', '=', False)])
currency_id = self.env.company.currency_id.symbol
if partner:
partner_ids = self.env['res.partner'].search(
[('id', 'in', partner)])
else:
partner_ids = paid.mapped('partner_id')
today = fields.Date.today()
for partner_id in partner_ids:
move_line_ids = paid.filtered(
lambda rec: rec.partner_id in partner_id)
move_line_data = move_line_ids.read(
['name', 'move_name', 'date', 'amount_currency', 'account_id',
'date_maturity', 'currency_id', 'debit', 'move_id'])
for val in move_line_data:
if val['date_maturity']:
diffrence = (today - val['date_maturity']).days
val['diff0'] = val['debit'] if diffrence <= 0 else 0.0
val['diff1'] = val['debit'] if 0 < diffrence <= 30 else 0.0
val['diff2'] = val['debit'] if 30 < diffrence <= 60 else 0.0
val['diff3'] = val['debit'] if 60 < diffrence <= 90 else 0.0
val['diff4'] = val['debit'] if 90 < diffrence <= 120 else 0.0
val['diff5'] = val['debit'] if diffrence > 120 else 0.0
move_line_list[partner_id.name] = move_line_data
partner_total[partner_id.name] = {
'debit_sum': sum(val['debit'] for val in move_line_data),
'diff0_sum': round(sum(val['diff0'] for val in move_line_data),
2),
'diff1_sum': round(sum(val['diff1'] for val in move_line_data),
2),
'diff2_sum': round(sum(val['diff2'] for val in move_line_data),
2),
'diff3_sum': round(sum(val['diff3'] for val in move_line_data),
2),
'diff4_sum': round(sum(val['diff4'] for val in move_line_data),
2),
'diff5_sum': round(sum(val['diff5'] for val in move_line_data),
2),
'currency_id': currency_id,
'partner_id': partner_id.id
}
move_line_list['partner_totals'] = partner_total
return move_line_list
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an Excel report based on the provided data.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the report to.
:type response: object
:param report_name: The name of the report.
:type report_name: str
:return: None
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '15px'})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Partners', filter_head)
if end_date:
sheet.merge_range('C3:G3', f"{end_date}", filter_body)
if data['filters']['partner']:
display_names = [partner.get('display_name', 'undefined') for
partner in data['filters']['partner']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data:
if report_name == 'Aged Receivable':
sheet.write(6, col, ' ', sub_heading)
sheet.write(6, col + 1, 'Invoice Date', sub_heading)
sheet.write(6, col + 2, 'Amount Currency', sub_heading)
sheet.write(6, col + 3, 'Currency', sub_heading)
sheet.merge_range(6, col + 4, 6, col + 5, 'Account',
sub_heading)
sheet.merge_range(6, col + 6, 6, col + 7, 'Expected Date',
sub_heading)
sheet.write(6, col + 8, 'At Date', sub_heading)
sheet.write(6, col + 9, '1-30', sub_heading)
sheet.write(6, col + 10, '31-60', sub_heading)
sheet.write(6, col + 11, '61-90', sub_heading)
sheet.write(6, col + 12, '91-120', sub_heading)
sheet.write(6, col + 13, 'Older', sub_heading)
sheet.write(6, col + 14, 'Total', sub_heading)
row = 6
for move_line in data['move_lines']:
row += 1
sheet.write(row, col, move_line, txt_name)
sheet.write(row, col + 1, ' ', txt_name)
sheet.write(row, col + 2, ' ', txt_name)
sheet.write(row, col + 3, ' ', txt_name)
sheet.merge_range(row, col + 4, row, col + 5, ' ',
txt_name)
sheet.merge_range(row, col + 6, row, col + 7, ' ',
txt_name)
sheet.write(row, col + 8,
data['total'][move_line]['diff0_sum'],
txt_name)
sheet.write(row, col + 9,
data['total'][move_line]['diff1_sum'],
txt_name)
sheet.write(row, col + 10,
data['total'][move_line]['diff2_sum'],
txt_name)
sheet.write(row, col + 11,
data['total'][move_line]['diff3_sum'],
txt_name)
sheet.write(row, col + 12,
data['total'][move_line]['diff4_sum'],
txt_name)
sheet.write(row, col + 13,
data['total'][move_line]['diff5_sum'],
txt_name)
sheet.write(row, col + 14,
data['total'][move_line]['debit_sum'],
txt_name)
for rec in data['data'][move_line]:
row += 1
if not rec['name']:
rec['name'] = ' '
sheet.write(row, col, rec['move_name'] + rec['name'],
txt_name)
sheet.write(row, col + 1, rec['date'],
txt_name)
sheet.write(row, col + 2, rec['amount_currency'],
txt_name)
sheet.write(row, col + 3, rec['currency_id'][1],
txt_name)
sheet.merge_range(row, col + 4, row, col + 5,
rec['account_id'][1],
txt_name)
sheet.merge_range(row, col + 6, row, col + 7,
rec['date_maturity'],
txt_name)
sheet.write(row, col + 8, rec['diff0'], txt_name)
sheet.write(row, col + 9, rec['diff1'], txt_name)
sheet.write(row, col + 10, rec['diff2'], txt_name)
sheet.write(row, col + 11, rec['diff3'], txt_name)
sheet.write(row, col + 12, rec['diff4'], txt_name)
sheet.write(row, col + 13, rec['diff5'], txt_name)
sheet.write(row, col + 14, ' ', txt_name)
sheet.merge_range(row + 1, col, row + 1, col + 7, 'Total',
filter_head)
sheet.write(row + 1, col + 8,
data['grand_total']['diff0_sum'],
filter_head)
sheet.write(row + 1, col + 9,
data['grand_total']['diff1_sum'],
filter_head)
sheet.write(row + 1, col + 10,
data['grand_total']['diff2_sum'],
filter_head)
sheet.write(row + 1, col + 11,
data['grand_total']['diff3_sum'],
filter_head)
sheet.write(row + 1, col + 12,
data['grand_total']['diff4_sum'],
filter_head)
sheet.write(row + 1, col + 13,
data['grand_total']['diff5_sum'],
filter_head)
sheet.write(row + 1, col + 14,
data['grand_total']['total_debit'],
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

321
dynamic_accounts_report/models/bank_book_report.py

@ -0,0 +1,321 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
from dateutil.relativedelta import relativedelta
import xlsxwriter
from datetime import datetime
from odoo.tools import date_utils
from odoo import api, fields, models
class BankBookReport(models.TransientModel):
"""For creating Bank Book report"""
_name = 'bank.book.report'
_description = 'Account Bank Book Report'
@api.model
def view_report(self):
"""
This method retrieves and returns the necessary data for the partner
ledger report.It fetches account move lines, grouped by accounts, and
calculates total debit and credit amounts.The resulting data includes
move lines for each account and the total debit and credit amounts for
each account.
"""
data = {}
move_lines_total = {}
journals = self.env['account.journal'].search(
[('type', '=', 'bank')])
account_move_lines = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('journal_id', 'in', journals.ids)])
accounts = account_move_lines.mapped('account_id').read(
['display_name', 'name'])
for account in accounts:
move_lines = account_move_lines.filtered(
lambda x: x.account_id.id == account['id'])
move_line_data = move_lines.read(
['date', 'journal_id', 'partner_id', 'move_name', 'debit',
'move_id',
'credit', 'name', 'ref'])
data[move_lines.mapped('account_id').display_name] = move_line_data
currency_id = self.env.company.currency_id.symbol
move_lines_total[move_lines.mapped('account_id').display_name] = {
'total_debit': round(sum(move_lines.mapped('debit')), 2),
'total_credit': round(sum(move_lines.mapped('credit')), 2),
'currency_id': currency_id}
data['move_lines_total'] = move_lines_total
data['accounts'] = accounts
return data
@api.model
def get_filter_values(self, partner_id, data_range, account_list, options):
"""
Retrieve filtered data for the partner ledger report.
Args:
partner_id (list or None): List of partner IDs for filtering by
partner. If None, all partners will be
included.
data_range (str or dict): Range of data to filter the account move
lines. Can be a string ('month', 'year',
'quarter','last-month', 'last-year',
'last-quarter') or a dictionary with
'start_date' and 'end_date'.
account_list (list or None): List of account IDs for filtering by
account. If None, all accounts will be
included.
options (dict or None): Additional filtering options with 'draft'
key (boolean) to include draft moves if
True.
Returns:
dict: Filtered data for the partner ledger report, grouped by
accounts and summary of total debit and credit amounts.
"""
data = {}
move_lines_total = {}
today = fields.Date.today()
quarter_start, quarter_end = date_utils.get_quarter(today)
previous_quarter_start = quarter_start - relativedelta(months=3)
previous_quarter_end = quarter_start - relativedelta(days=1)
journals = self.env['account.journal'].search([('type', '=', 'bank')])
option_domain = ['posted']
if options is not None:
if 'draft' in options:
option_domain = ['posted', 'draft']
if partner_id:
domain = [('parent_state', 'in', option_domain),
('journal_id', 'in', journals.ids),
('partner_id', 'in', partner_id), ]
else:
domain = [('parent_state', 'in', option_domain),
('journal_id', 'in', journals.ids), ]
if account_list:
domain += ('account_id', 'in', account_list),
if data_range:
if data_range == 'month':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.month == fields.Date.today().month)
elif data_range == 'year':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.year == fields.Date.today().year)
elif data_range == 'quarter':
domain += ('date', '>=', quarter_start), (
'date', '<=', quarter_end)
account_move_lines = self.env['account.move.line'].search(
domain)
elif data_range == 'last-month':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.month == fields.Date.today().month - 1)
elif data_range == 'last-year':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.year == fields.Date.today().year - 1)
elif data_range == 'last-quarter':
domain += ('date', '>=', previous_quarter_start), (
'date', '<=', previous_quarter_end)
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'start_date' in data_range and 'end_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
domain += ('date', '>=', start_date), ('date', '<=', end_date),
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'start_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
domain.append(('date', '>=', start_date))
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'end_date' in data_range:
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
domain.append(('date', '<=', end_date))
account_move_lines = self.env['account.move.line'].search(
domain)
else:
account_move_lines = self.env['account.move.line'].search(domain)
accounts = account_move_lines.mapped('account_id').read(
['display_name'])
for account in accounts:
move_lines = account_move_lines.filtered(
lambda x: x.account_id.id == account['id'])
move_line_data = move_lines.read(
['date', 'journal_id', 'partner_id', 'move_name', 'debit',
'move_id',
'credit', 'name', 'ref'])
data[move_lines.mapped('account_id').display_name] = move_line_data
currency_id = self.env.company.currency_id.symbol
move_lines_total[move_lines.mapped('account_id').display_name] = {
'total_debit': round(sum(move_lines.mapped('debit')), 2),
'total_credit': round(sum(move_lines.mapped('credit')), 2),
'currency_id': currency_id}
data['move_lines_total'] = move_lines_total
return data
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an Excel report based on the provided data.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the report to.
:type response: object
:param report_name: The name of the report.
:type report_name: str
:return: None
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
start_date = data['filters']['start_date'] if \
data['filters']['start_date'] else ''
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '15px'})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Partners', filter_head)
sheet.write('B5:b4', 'Accounts', filter_head)
sheet.write('B6:b4', 'Options', filter_head)
if start_date or end_date:
sheet.merge_range('C3:G3', f"{start_date} to {end_date}",
filter_body)
if data['filters']['partner']:
display_names = [partner.get('display_name', 'undefined') for
partner in data['filters']['partner']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data['filters']['account']:
account_keys_str = ', '.join(data['filters']['account'])
sheet.merge_range('C5:G5', account_keys_str, filter_body)
if data['filters']['options']:
option_keys = list(data['filters']['options'].keys())
option_keys_str = ', '.join(option_keys)
sheet.merge_range('C6:G6', option_keys_str, filter_body)
if data:
if report_name == 'Bank Book':
sheet.write(8, col, ' ', sub_heading)
sheet.merge_range('B9:C9', 'Journal', sub_heading)
sheet.merge_range('D9:E9', 'Partner', sub_heading)
sheet.merge_range('F9:G9', 'Ref', sub_heading)
sheet.merge_range('H9:I9', 'Move', sub_heading)
sheet.merge_range('J9:K9', 'Entry Label', sub_heading)
sheet.merge_range('L9:M9', 'Debit', sub_heading)
sheet.merge_range('N9:O9', 'Credit', sub_heading)
sheet.merge_range('P9:Q9', 'Balance', sub_heading)
row = 8
for move_line in data['move_lines']:
row += 1
sheet.write(row, col, move_line, txt_name)
sheet.merge_range(row, col + 1, row, col + 2, ' ',
txt_name)
sheet.merge_range(row, col + 3, row, col + 4, ' ',
txt_name)
sheet.merge_range(row, col + 5, row, col + 6, ' ',
txt_name)
sheet.merge_range(row, col + 7, row, col + 8, ' ',
txt_name)
sheet.merge_range(row, col + 9, row, col + 10, ' ',
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
data['total'][move_line]['total_debit'],
txt_name)
sheet.merge_range(row, col + 13, row, col + 14,
data['total'][move_line]['total_credit'],
txt_name)
sheet.merge_range(row, col + 15, row, col + 16,
data['total'][move_line]['total_debit'] -
data['total'][move_line]['total_credit'],
txt_name)
for rec in data['data'][move_line]:
row += 1
if rec['partner_id']:
partner = rec['partner_id'][1]
else:
partner = ' '
sheet.write(row, col, rec['date'], txt_name)
sheet.merge_range(row, col + 1, row, col + 2,
rec['journal_id'][1],
txt_name)
sheet.merge_range(row, col + 3, row, col + 4, partner,
txt_name)
sheet.merge_range(row, col + 5, row, col + 6,
rec['ref'], txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
rec['move_name'],
txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
rec['name'],
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
rec['debit'], txt_name)
sheet.merge_range(row, col + 13, row, col + 14,
rec['credit'], txt_name)
sheet.merge_range(row, col + 15, row, col + 16, ' ',
txt_name)
sheet.merge_range(row + 1, col, row + 1, col + 10, 'Total',
filter_head)
sheet.merge_range(row + 1, col + 11, row + 1, col + 12,
data['grand_total']['total_debit'],
filter_head)
sheet.merge_range(row + 1, col + 13, row + 1, col + 14,
data['grand_total']['total_credit'],
filter_head)
sheet.merge_range(row + 1, col + 15, row + 1, col + 16,
float(data['grand_total']['total_debit']) -
float(data['grand_total']['total_credit']),
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

345
dynamic_accounts_report/models/cash_book_report.py

@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import io
import json
from dateutil.relativedelta import relativedelta
import xlsxwriter
from datetime import datetime
from odoo.tools import date_utils
from odoo import api, fields, models
class CashBookReport(models.TransientModel):
"""For creating Cash Book report"""
_name = 'cash.book.report'
_description = 'Account Cash Book Report'
@api.model
def view_report(self):
"""
Retrieves and formats data for the cash book report.
Returns a dictionary containing the following data:
- 'move_lines_total': A dictionary containing the total debit, total
credit, and currency symbol for each account in
the cash journal.
- 'accounts': A list of dictionaries, each representing an account
in the cash journal. Each dictionary contains the
'display_name' and 'name' of the account.
- Additional data for each account: The key is the 'display_name' of the
account, and the value is a list of
dictionaries, each representing a
move line for that account. Each
move line dictionary contains the
following
data: 'date', 'journal_id', 'partner_id', 'move_name', 'debit',
'move_id', 'credit', 'name', and 'ref'.
"""
data = {}
move_lines_total = {}
journals = self.env['account.journal'].search(
[('type', '=', 'cash')])
account_move_lines = self.env['account.move.line'].search(
[('parent_state', '=', 'posted'),
('journal_id', 'in', journals.ids)])
accounts = account_move_lines.mapped('account_id').read(
['display_name', 'name'])
for account in accounts:
move_lines = account_move_lines.filtered(
lambda x: x.account_id.id == account['id'])
move_line_data = move_lines.read(
['date', 'journal_id', 'partner_id', 'move_name', 'debit',
'move_id',
'credit', 'name', 'ref'])
data[move_lines.mapped('account_id').display_name] = move_line_data
currency_id = self.env.company.currency_id.symbol
move_lines_total[move_lines.mapped('account_id').display_name] = {
'total_debit': round(sum(move_lines.mapped('debit')), 2),
'total_credit': round(sum(move_lines.mapped('credit')), 2),
'currency_id': currency_id}
data['move_lines_total'] = move_lines_total
data['accounts'] = accounts
return data
@api.model
def get_filter_values(self, partner_id, data_range, account_list, options):
"""
Retrieves and formats filtered data for the cash book report based on
the provided filter criteria.
:param partner_id: List of partner IDs to filter the data by.
:type partner_id: list
:param data_range: Specifies the date range filter. Possible values are
'month', 'year', 'quarter', 'last-month',
'last-year', 'last-quarter', or a dictionary
containing 'start_date' and/or 'end_date' fields.
:type data_range: str or dict
:param account_list: List of account IDs to filter the data by.
:type account_list: list
:param options: Dictionary containing additional options for filtering
the data. The 'draft' option indicates
whether to include draft journal entries in the data.
:type options: dict
:return: A dictionary containing the following data:
- 'move_lines_total': A dictionary containing the total debit,
total credit, and currency symbol
for each account in the cash journal.
- Additional data for each account: The key is the
'display_name' of account,
and the value is a list of
dictionaries, each
representing a move line for
that account. Each move line
dictionary contains the
following
data: 'date', 'journal_id', 'partner_id', 'move_name',
debit', 'move_id', 'credit', 'name', and 'ref'.
:rtype: dict
"""
data = {}
move_lines_total = {}
today = fields.Date.today()
quarter_start, quarter_end = date_utils.get_quarter(today)
previous_quarter_start = quarter_start - relativedelta(months=3)
previous_quarter_end = quarter_start - relativedelta(days=1)
journals = self.env['account.journal'].search([('type', '=', 'cash')])
option_domain = ['posted']
if options is not None:
if 'draft' in options:
option_domain = ['posted', 'draft']
if partner_id:
domain = [('parent_state', 'in', option_domain),
('journal_id', 'in', journals.ids),
('partner_id', 'in', partner_id), ]
else:
domain = [('parent_state', 'in', option_domain),
('journal_id', 'in', journals.ids), ]
if account_list:
domain += ('account_id', 'in', account_list),
if data_range:
if data_range == 'month':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.month == fields.Date.today().month)
elif data_range == 'year':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.year == fields.Date.today().year)
elif data_range == 'quarter':
domain += ('date', '>=', quarter_start), (
'date', '<=', quarter_end)
account_move_lines = self.env['account.move.line'].search(
domain)
elif data_range == 'last-month':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.month == fields.Date.today().month - 1)
elif data_range == 'last-year':
account_move_lines = self.env['account.move.line'].search(
domain).filtered(
lambda x: x.date.year == fields.Date.today().year - 1)
elif data_range == 'last-quarter':
domain += ('date', '>=', previous_quarter_start), (
'date', '<=', previous_quarter_end)
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'start_date' in data_range and 'end_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
domain += ('date', '>=', start_date), ('date', '<=', end_date),
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'start_date' in data_range:
start_date = datetime.strptime(data_range['start_date'],
'%Y-%m-%d').date()
domain.append(('date', '>=', start_date))
account_move_lines = self.env['account.move.line'].search(
domain)
elif 'end_date' in data_range:
end_date = datetime.strptime(data_range['end_date'],
'%Y-%m-%d').date()
domain.append(('date', '<=', end_date))
account_move_lines = self.env['account.move.line'].search(
domain)
else:
account_move_lines = self.env['account.move.line'].search(domain)
accounts = account_move_lines.mapped('account_id').read(
['display_name'])
for account in accounts:
move_lines = account_move_lines.filtered(
lambda x: x.account_id.id == account['id'])
move_line_data = move_lines.read(
['date', 'journal_id', 'partner_id', 'move_name', 'debit',
'move_id',
'credit', 'name', 'ref'])
data[move_lines.mapped('account_id').display_name] = move_line_data
currency_id = self.env.company.currency_id.symbol
move_lines_total[move_lines.mapped('account_id').display_name] = {
'total_debit': round(sum(move_lines.mapped('debit')), 2),
'total_credit': round(sum(move_lines.mapped('credit')), 2),
'currency_id': currency_id}
data['move_lines_total'] = move_lines_total
return data
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an Excel report based on the provided data.
:param data: The data used to generate the report.
:type data: str (JSON format)
:param response: The response object to write the report to.
:type response: object
:param report_name: The name of the report.
:type report_name: str
:return: None
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
start_date = data['filters']['start_date'] if \
data['filters']['start_date'] else ''
end_date = data['filters']['end_date'] if \
data['filters']['end_date'] else ''
sheet = workbook.add_worksheet()
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '15px'})
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1, 'bg_color': '#D3D3D3',
'border_color': 'black'})
filter_body = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A1:b1', report_name, head)
sheet.write('B3:b4', 'Date Range', filter_head)
sheet.write('B4:b4', 'Partners', filter_head)
sheet.write('B5:b4', 'Accounts', filter_head)
sheet.write('B6:b4', 'Options', filter_head)
if start_date or end_date:
sheet.merge_range('C3:G3', f"{start_date} to {end_date}",
filter_body)
if data['filters']['partner']:
display_names = [partner.get('display_name', 'undefined') for
partner in data['filters']['partner']]
display_names_str = ', '.join(display_names)
sheet.merge_range('C4:G4', display_names_str, filter_body)
if data['filters']['account']:
account_keys_str = ', '.join(data['filters']['account'])
sheet.merge_range('C5:G5', account_keys_str, filter_body)
if data['filters']['options']:
option_keys = list(data['filters']['options'].keys())
option_keys_str = ', '.join(option_keys)
sheet.merge_range('C6:G6', option_keys_str, filter_body)
if data:
if report_name == 'Cash Book':
sheet.write(8, col, ' ', sub_heading)
sheet.merge_range('B9:C9', 'Journal', sub_heading)
sheet.merge_range('D9:E9', 'Partner', sub_heading)
sheet.merge_range('F9:G9', 'Ref', sub_heading)
sheet.merge_range('H9:I9', 'Move', sub_heading)
sheet.merge_range('J9:K9', 'Entry Label', sub_heading)
sheet.merge_range('L9:M9', 'Debit', sub_heading)
sheet.merge_range('N9:O9', 'Credit', sub_heading)
sheet.merge_range('P9:Q9', 'Balance', sub_heading)
row = 8
for move_line in data['move_lines']:
row += 1
sheet.write(row, col, move_line, txt_name)
sheet.merge_range(row, col + 1, row, col + 2, ' ',
txt_name)
sheet.merge_range(row, col + 3, row, col + 4, ' ',
txt_name)
sheet.merge_range(row, col + 5, row, col + 6, ' ',
txt_name)
sheet.merge_range(row, col + 7, row, col + 8, ' ',
txt_name)
sheet.merge_range(row, col + 9, row, col + 10, ' ',
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
data['total'][move_line]['total_debit'],
txt_name)
sheet.merge_range(row, col + 13, row, col + 14,
data['total'][move_line]['total_credit'],
txt_name)
sheet.merge_range(row, col + 15, row, col + 16,
data['total'][move_line]['total_debit'] -
data['total'][move_line]['total_credit'],
txt_name)
for rec in data['data'][move_line]:
row += 1
if rec['partner_id']:
partner = rec['partner_id'][1]
else:
partner = ' '
sheet.write(row, col, rec['date'], txt_name)
sheet.merge_range(row, col + 1, row, col + 2,
rec['journal_id'][1],
txt_name)
sheet.merge_range(row, col + 3, row, col + 4, partner,
txt_name)
sheet.merge_range(row, col + 5, row, col + 6,
rec['ref'], txt_name)
sheet.merge_range(row, col + 7, row, col + 8,
rec['move_name'],
txt_name)
sheet.merge_range(row, col + 9, row, col + 10,
rec['name'],
txt_name)
sheet.merge_range(row, col + 11, row, col + 12,
rec['debit'], txt_name)
sheet.merge_range(row, col + 13, row, col + 14,
rec['credit'], txt_name)
sheet.merge_range(row, col + 15, row, col + 16, ' ',
txt_name)
sheet.merge_range(row + 1, col, row + 1, col + 10, 'Total',
filter_head)
sheet.merge_range(row + 1, col + 11, row + 1, col + 12,
data['grand_total']['total_debit'],
filter_head)
sheet.merge_range(row + 1, col + 13, row + 1, col + 14,
data['grand_total']['total_credit'],
filter_head)
sheet.merge_range(row + 1, col + 15, row + 1, col + 16,
float(data['grand_total']['total_debit']) -
float(data['grand_total']['total_credit']),
filter_head)
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

1104
dynamic_accounts_report/models/dynamic_balance_sheet_report.py

File diff suppressed because it is too large

760
dynamic_accounts_report/models/tax_report.py

@ -0,0 +1,760 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import calendar
import io
import json
from datetime import datetime
import xlsxwriter
from odoo import models, fields, api
from odoo.tools.date_utils import get_month, get_fiscal_year, \
get_quarter_number, subtract
class TaxReport(models.TransientModel):
"""For creating Tax report."""
_name = 'tax.report'
_description = 'Tax Report'
@api.model
def view_report(self):
"""
View a tax report for the current month. This function retrieves
tax-related information for the current month. It calculates the net
amount and tax amount for both sales and purchases based on the tax
information associated with account move lines.
:return: Dictionary containing sale and purchase data for the
current month.
"""
sale = []
purchase = []
tax_ids = self.env['account.move.line'].search([]).mapped(
'tax_ids')
today = fields.Date.today()
for tax in tax_ids:
tax_id = self.env['account.move.line'].search(
[('tax_ids', '=', tax.id), ('parent_state', '=', 'posted'),
('date', '>=', get_month(today)[0]),
('date', '<=', get_month(today)[1])]).read(
['debit', 'credit'])
tax_debit_sums = sum(record['debit'] for record in tax_id)
tax_credit_sums = sum(record['credit'] for record in tax_id)
if tax.type_tax_use == 'sale':
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2)
})
elif tax.type_tax_use == 'purchase':
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2)
})
return {
'sale': sale,
'purchase': purchase
}
@api.model
def get_filter_values(self, start_date, end_date, comparison_number,
comparison_type, options, report_type):
"""
Get filtered tax values based on various criteria.
:param start_date: Start date of the filter period.
:param end_date: End date of the filter period.
:param comparison_number: Number of comparison periods.
:param comparison_type: Type of comparison (year, month, quarter).
:param options: Filter options.
:param report_type: Type of report (account, tax).
:return: Dictionary containing dynamic_date_num, sale, and purchase
data.
"""
sale = []
purchase = []
dynamic_date_num = {}
if options == {}:
options = None
if options is None:
option_domain = ['posted']
elif 'draft' in options:
option_domain = ['posted', 'draft']
tax_ids = self.env['account.move.line'].search([]).mapped(
'tax_ids')
start_date_first = \
get_fiscal_year(datetime.strptime(start_date, "%Y-%m-%d").date())[
0] if comparison_type == 'year' else datetime.strptime(
start_date, "%Y-%m-%d").date()
end_date_first = \
get_fiscal_year(datetime.strptime(end_date, "%Y-%m-%d").date())[
1] if comparison_type == 'year' else datetime.strptime(
end_date, "%Y-%m-%d").date()
if report_type is not None and 'account' in report_type:
start_date = start_date_first
end_date = end_date_first
account_ids = self.env['account.move.line'].search([]).mapped(
'account_id')
for account in account_ids:
tax_ids = self.env['account.move.line'].search(
[('account_id', '=', account.id)]).mapped('tax_ids')
if tax_ids:
for tax in tax_ids:
dynamic_total_tax_sum = {}
dynamic_total_net_sum = {}
if comparison_number:
if comparison_type == 'year':
start_date = start_date_first
end_date = end_date_first
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
years=i)
com_end_date = subtract(end_date, years=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('account_id', '=', account.id),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
elif comparison_type == 'month':
dynamic_date_num[
f"dynamic_date_num{0}"] = self.get_month_name(
start_date) + ' ' + str(start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
months=i)
com_end_date = subtract(end_date, months=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('account_id', '=', account.id),
('date', '<=', com_end_date),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = self.get_month_name(
com_start_date) + ' ' + str(
com_start_date.year)
elif comparison_type == 'quarter':
dynamic_date_num[
f"dynamic_date_num{0}"] = 'Q' + ' ' + str(
get_quarter_number(
start_date)) + ' ' + str(
start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
months=i * 3)
com_end_date = subtract(end_date,
months=i * 3)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('account_id', '=', account.id),
('date', '<=', com_end_date),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = 'Q' + ' ' + str(
get_quarter_number(
com_start_date)) + ' ' + str(
com_start_date.year)
tax_id = self.env['account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', start_date_first),
('date', '<=', end_date_first),
('parent_state', 'in', option_domain),
('account_id', '=', account.id)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
if tax_id and tax.type_tax_use == 'sale':
if comparison_number:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(
tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
'account': account.display_name,
})
else:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(
tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'account': account.display_name,
})
elif tax_id and tax.type_tax_use == 'purchase':
if comparison_number:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(
tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
'account': account.display_name,
})
else:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(
tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'account': account.display_name,
})
elif report_type is not None and 'tax' in report_type:
start_date = start_date_first
end_date = end_date_first
for tax in tax_ids:
account_ids = self.env['account.move.line'].search(
[('tax_ids', '=', tax.id)]).mapped('account_id')
for account in account_ids:
dynamic_total_tax_sum = {}
dynamic_total_net_sum = {}
if comparison_number:
if comparison_type == 'year':
start_date = start_date_first
end_date = end_date_first
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
years=i)
com_end_date = subtract(end_date, years=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('account_id', '=', account.id),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
elif comparison_type == 'month':
dynamic_date_num[
f"dynamic_date_num{0}"] = self.get_month_name(
start_date) + ' ' + str(start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date, months=i)
com_end_date = subtract(end_date, months=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('account_id', '=', account.id),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = self.get_month_name(
com_start_date) + ' ' + str(
com_start_date.year)
elif comparison_type == 'quarter':
dynamic_date_num[
f"dynamic_date_num{0}"] = 'Q' + ' ' + str(
get_quarter_number(start_date)) + ' ' + str(
start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
months=i * 3)
com_end_date = subtract(end_date,
months=i * 3)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('account_id', '=', account.id),
('parent_state', 'in',
option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = 'Q' + ' ' + str(
get_quarter_number(
com_start_date)) + ' ' + str(
com_start_date.year)
tax_id = self.env['account.move.line'].search(
[('tax_ids', '=', tax.id),
('parent_state', 'in', option_domain),
('date', '>=', start_date_first),
('date', '<=', end_date_first),
('account_id', '=', account.id)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
if tax_id and tax.type_tax_use == 'sale':
if comparison_number:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
'account': account.display_name,
})
else:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'account': account.display_name,
})
elif tax_id and tax.type_tax_use == 'purchase':
if comparison_number:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
'account': account.display_name,
})
else:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums,
2),
'tax': round(
(tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'account': account.display_name,
})
else:
start_date = start_date_first
end_date = end_date_first
for tax in tax_ids:
dynamic_total_tax_sum = {}
dynamic_total_net_sum = {}
if comparison_number:
if comparison_type == 'year':
start_date = start_date_first
end_date = end_date_first
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
years=i)
com_end_date = subtract(end_date, years=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
elif comparison_type == 'month':
dynamic_date_num[
f"dynamic_date_num{0}"] = self.get_month_name(
start_date) + ' ' + str(start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date, months=i)
com_end_date = subtract(end_date, months=i)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = self.get_month_name(
com_start_date) + ' ' + str(
com_start_date.year)
elif comparison_type == 'quarter':
dynamic_date_num[
f"dynamic_date_num{0}"] = 'Q' + ' ' + str(
get_quarter_number(start_date)) + ' ' + str(
start_date.year)
for i in range(1, eval(comparison_number) + 1):
com_start_date = subtract(start_date,
months=i * 3)
com_end_date = subtract(end_date,
months=i * 3)
tax_id = self.env[
'account.move.line'].search(
[('tax_ids', '=', tax.id),
('date', '>=', com_start_date),
('date', '<=', com_end_date),
('parent_state', 'in', option_domain)]).read(
['debit', 'credit'])
tax_debit_sums = sum(
record['debit'] for record in tax_id)
tax_credit_sums = sum(
record['credit'] for record in tax_id)
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] = tax_debit_sums + tax_credit_sums
dynamic_total_tax_sum[
f"dynamic_total_tax_sum{i}"] = \
dynamic_total_net_sum[
f"dynamic_total_net_sum{i}"] * (
tax.amount / 100)
dynamic_date_num[
f"dynamic_date_num{i}"] = 'Q' + ' ' + str(
get_quarter_number(
com_start_date)) + ' ' + str(
com_start_date.year)
tax_id = self.env['account.move.line'].search(
[('tax_ids', '=', tax.id),
('parent_state', 'in', option_domain),
('date', '>=', start_date_first),
('date', '<=', end_date_first)]).read(['debit', 'credit'])
tax_debit_sums = sum(record['debit'] for record in tax_id)
tax_credit_sums = sum(record['credit'] for record in tax_id)
if tax.type_tax_use == 'sale':
if comparison_number:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
})
else:
sale.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
})
elif tax.type_tax_use == 'purchase':
if comparison_number:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
'dynamic net': dynamic_total_net_sum,
'dynamic tax': dynamic_total_tax_sum,
})
else:
purchase.append({
'name': tax.name,
'amount': tax.amount,
'net': round(tax_debit_sums + tax_credit_sums, 2),
'tax': round((tax_debit_sums + tax_credit_sums) * (
tax.amount / 100), 2),
})
return {
'dynamic_date_num': dynamic_date_num,
'sale': sale,
'purchase': purchase
}
@api.model
def get_month_name(self, date):
"""
Retrieve the abbreviated name of the month for a given date.
:param date: The date for which to retrieve the month's abbreviated
name.
:type date: datetime.date
:return: Abbreviated name of the month (e.g., 'Jan', 'Feb', ..., 'Dec').
:rtype: str
"""
month_names = calendar.month_abbr
return month_names[date.month]
@api.model
def get_xlsx_report(self, data, response, report_name):
"""
Generate an XLSX report based on provided data and response stream.
Generates an Excel workbook with specified report format, including
subheadings,column headers, and row data for the given financial report
data.
:param str data: JSON-encoded data for the report.
:param response: Response object to stream the generated report.
:param str report_name: Name of the financial report.
"""
data = json.loads(data)
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
sheet = workbook.add_worksheet()
sub_heading = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub = workbook.add_format(
{'align': 'left', 'bold': True, 'font_size': '10px',
'border': 1,
'border_color': 'black'})
side_heading_sub.set_indent(1)
txt_name = workbook.add_format({'font_size': '10px', 'border': 1})
txt_name.set_indent(2)
sheet.set_column(0, 0, 30)
sheet.set_column(1, 1, 20)
sheet.set_column(2, 2, 15)
sheet.set_column(3, 3, 15)
col = 0
sheet.write('A3:b4', report_name, sub_heading)
sheet.write(5, col, '', sub_heading)
i = 1
for date_view in data['date_viewed']:
sheet.merge_range(5, col + i, 5, col + i + 1, date_view,
sub_heading)
i += 2
j = 1
prev_account = None
prev_tax = None
sheet.write(6, col, '', sub_heading)
for date in data['date_viewed']:
sheet.write(6, col + j, 'NET', sub_heading)
sheet.write(6, col + j + 1, 'TAX', sub_heading)
j += 1
sheet.write(7, col, 'Sales', sub_heading)
sheet.write(7, col + 1, ' ', sub_heading)
sheet.write(7, col + 2, data['sale_total'], sub_heading)
row = 8
for sale in data['data']['sale']:
if data['report_type']:
if list(data['report_type'].keys())[0] == 'account':
if prev_account != sale['account']:
prev_account = sale['account']
sheet.write(row, col, sale['account'], txt_name)
sheet.write(row, col + 1, '', txt_name)
sheet.write(row, col + 2, '', txt_name)
elif list(data['report_type'].keys())[0] == 'tax':
if prev_tax != sale['name']:
prev_tax = sale['name']
sheet.write(row, col, sale['name'] + '(' + str(
sale['amount']) + '%)', txt_name)
sheet.write(row, col + 1, '', txt_name)
sheet.write(row, col + 2, '', txt_name)
row += 1
if data['apply_comparison']:
if sale['dynamic net']:
periods = data['comparison_number_range']
for num in periods:
if sale['dynamic net'][
'dynamic_total_net_sum' + str(num)]:
sheet.write(row, col + j, sale['dynamic net'][
'dynamic_total_net_sum' + str(num)],
txt_name)
if sale['dynamic tax'][
'dynamic_total_tax_sum' + str(num)]:
sheet.write(row, col, sale['dynamic tax'][
'dynamic_total_tax_sum' + str(num)],
txt_name)
j += 1
j = 0
sheet.write(row, col + j, sale['name'], txt_name)
sheet.write(row, col + j + 1, sale['net'], txt_name)
sheet.write(row, col + j + 2, sale['tax'], txt_name)
else:
j = 0
sheet.write(row, col + j, sale['name'], txt_name)
sheet.write(row, col + j + 1, sale['net'], txt_name)
sheet.write(row, col + j + 2, sale['tax'], txt_name)
row += 1
row += 1
sheet.write(row, col, 'Purchase', sub_heading)
sheet.write(row, col + 1, ' ', sub_heading)
sheet.write(row, col + 2, data['purchase_total'], sub_heading)
row += 1
for purchase in data['data']['purchase']:
if data['report_type']:
if list(data['report_type'].keys())[0] == 'account':
if prev_account != purchase['account']:
prev_account = purchase['account']
sheet.write(row, col, purchase['account'], txt_name)
sheet.write(row, col + 1, '', txt_name)
sheet.write(row, col + 2, '', txt_name)
elif list(data['report_type'].keys())[0] == 'tax':
if prev_tax != purchase['name']:
prev_tax = purchase['name']
sheet.write(row, col, purchase['name'] + '(' + str(
purchase['amount']) + '%)', txt_name)
sheet.write(row, col + 1, '', txt_name)
sheet.write(row, col + 2, '', txt_name)
row += 1
if data['apply_comparison']:
if purchase['dynamic net']:
periods = data['comparison_number_range']
for num in periods:
if purchase['dynamic net'][
'dynamic_total_net_sum' + str(num)]:
sheet.write(row, col + j,
purchase['dynamic net'][
'dynamic_total_net_sum' + str(
num)],
txt_name)
if purchase['dynamic tax'][
'dynamic_total_tax_sum' + str(num)]:
sheet.write(row, col, purchase['dynamic tax'][
'dynamic_total_tax_sum' + str(num)],
txt_name)
j += 1
j = 0
sheet.write(row, col + j, purchase['name'], txt_name)
sheet.write(row, col + j + 1, purchase['net'], txt_name)
sheet.write(row, col + j + 2, purchase['tax'], txt_name)
else:
j = 0
sheet.write(row, col + j, purchase['name'], txt_name)
sheet.write(row, col + j + 1, purchase['net'], txt_name)
sheet.write(row, col + j + 2, purchase['tax'], txt_name)
row += 1
row += 1
sheet.write(row, col, 'Purchase', sub_heading)
sheet.write(row, col + 1, ' ', sub_heading)
sheet.write(row, col + 2, data['purchase_total'], sub_heading)
row += 1
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

21
dynamic_accounts_report/report/__init__.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ammu Raj (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################

278
dynamic_accounts_report/report/aged_payable_templates.xml

@ -0,0 +1,278 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report template for Aged Payable Report.-->
<template id="aged_payable">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Partner</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['end_date']">
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-foreach="filters['partner']"
t-as="selected_partner"
t-key="partner_index">
<t t-out="selected_partner['display_name']"/>
,
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<t t-if="move_lines">
<t t-foreach="move_lines"
t-as="move_line"
t-key="partner_index">
<table class="table table-sm table-reports">
<thead style="background:#808080;">
<tr>
<th style="width:10%" colspan="6"/>
<th style="width:10%">Invoice Date</th>
<th style="width:10%">Amount Currency
</th>
<th style="width:10%">Currency</th>
<th style="width:10%">Account</th>
<th style="width:10%">Expected Date</th>
<th style="width:10%">At Date</th>
<th style="width:10%">1-30</th>
<th style="width:10%">31-60</th>
<th style="width:10%">61-90</th>
<th style="width:10%">91-120</th>
<th style="width:10%">Older</th>
<th style="width:10%">Total</th>
</tr>
</thead>
<tbody>
<tr class="border-bottom"
style="background:#D3D3D3;">
<th colspan="6"
style="border:0px solid transparent;border-left: thin solid #dee2e6;">
<div>
<span class="fw-bolder">
<t t-esc="move_line"/>
</span>
</div>
</th>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff0_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff0_sum']"
t-esc="total[move_line]['diff0_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff1_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff1_sum']"
t-esc="total[move_line]['diff1_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff2_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff2_sum']"
t-esc="total[move_line]['diff2_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff3_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff3_sum']"
t-esc="total[move_line]['diff3_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff4_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff4_sum']"
t-esc="total[move_line]['diff4_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff5_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff5_sum']"
t-esc="total[move_line]['diff5_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;border-right: thin solid #dee2e6;font-size:11px;font-weight:100;">
<span class="fw-bolder">
<t t-if="total[move_line]['credit_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['credit_sum']"
t-esc="total[move_line]['credit_sum']"/>
</span>
</th>
</tr>
<t t-foreach="data[move_line]"
t-as="valuelist"
t-key="valuelist_index">
<tr class="border-bottom"
style="font-size:11px;font-weight:100;">
<th colspan="6">
<span>
<t t-esc="valuelist['move_name']"/>
<t t-esc="valuelist['name']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['date']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['amount_currency']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['currency_id'][1]"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['account_id'][1]"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['date_maturity']"
t-esc="valuelist['date_maturity']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff0']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff0']"
t-esc="valuelist['diff0']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff1']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff1']"
t-esc="valuelist['diff1']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff2']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff2']"
t-esc="valuelist['diff2']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff3']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff3']"
t-esc="valuelist['diff3']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff4']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff4']"
t-esc="valuelist['diff4']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff5']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff5']"
t-esc="valuelist['diff5']"/>
</span>
</th>
<th/>
</tr>
</t>
</tbody>
</table>
</t>
</t>
<table class="table table-sm table-reports">
<tbody>
<tr>
<th style="width:60%;">Total</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff0_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff1_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff2_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff3_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff4_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff5_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_credit']"/>
</th>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

279
dynamic_accounts_report/report/aged_receivable_templates.xml

@ -0,0 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report template for Aged Receivable Report.-->
<template id="aged_receivable">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Partner</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['end_date']">
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-foreach="filters['partner']"
t-as="selected_partner"
t-key="partner_index">
<t t-out="selected_partner['display_name']"/>
,
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<t t-if="move_lines">
<t t-foreach="move_lines"
t-as="move_line"
t-key="partner_index">
<table class="table table-sm table-reports">
<thead style="background:#808080;">
<tr>
<th style="width:10%" colspan="6"/>
<th style="width:10%">Invoice Date</th>
<th style="width:10%">Amount Currency
</th>
<th style="width:10%">Currency</th>
<th style="width:10%">Account</th>
<th style="width:10%">Expected Date
</th>
<th style="width:10%">At Date</th>
<th style="width:10%">1-30</th>
<th style="width:10%">31-60</th>
<th style="width:10%">61-90</th>
<th style="width:10%">91-120</th>
<th style="width:10%">Older</th>
<th style="width:10%">Total</th>
</tr>
</thead>
<tbody>
<tr class="border-bottom"
style="background:#D3D3D3;">
<th colspan="6"
style="border:0px solid transparent;border-left: thin solid #dee2e6;">
<div>
<span class="fw-bolder">
<t t-esc="move_line"/>
</span>
</div>
</th>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;"/>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff0_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff0_sum']"
t-esc="total[move_line]['diff0_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff1_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff1_sum']"
t-esc="total[move_line]['diff1_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff2_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff2_sum']"
t-esc="total[move_line]['diff2_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff3_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff3_sum']"
t-esc="total[move_line]['diff3_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff4_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff4_sum']"
t-esc="total[move_line]['diff4_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;font-size:11px;font-weight:100;">
<span>
<t t-if="total[move_line]['diff5_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['diff5_sum']"
t-esc="total[move_line]['diff5_sum']"/>
</span>
</th>
<th style="border:0px solid transparent;border-right: thin solid #dee2e6;font-size:11px;font-weight:100;">
<span class="fw-bolder">
<t t-if="total[move_line]['debit_sum']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['debit_sum']"
t-esc="total[move_line]['debit_sum']"/>
</span>
</th>
</tr>
<t t-foreach="data[move_line]"
t-as="valuelist"
t-key="valuelist_index">
<tr class="border-bottom"
style="font-size:11px;font-weight:100;">
<th colspan="6">
<span>
<t t-esc="valuelist['move_name']"/>
<t t-esc="valuelist['name']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['date']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['amount_currency']"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['currency_id'][1]"/>
</span>
</th>
<th>
<span>
<t t-esc="valuelist['account_id'][1]"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['date_maturity']"
t-esc="valuelist['date_maturity']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff0']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff0']"
t-esc="valuelist['diff0']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff1']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff1']"
t-esc="valuelist['diff1']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff2']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff2']"
t-esc="valuelist['diff2']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff3']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff3']"
t-esc="valuelist['diff3']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff4']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff4']"
t-esc="valuelist['diff4']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['diff5']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['diff5']"
t-esc="valuelist['diff5']"/>
</span>
</th>
<th/>
</tr>
</t>
</tbody>
</table>
</t>
</t>
<table class="table table-sm table-reports">
<tbody>
<tr>
<th style="width:60%;">Total</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff0_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff1_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff2_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff3_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff4_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['diff5_sum']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_debit']"/>
</th>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

942
dynamic_accounts_report/report/balance_sheet_report_templates.xml

@ -0,0 +1,942 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Balance Sheet Template -->
<!-- This template defines the structure and layout of a balance sheet
report -->
<template id="dynamic_accounts_report.balance_sheet">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<span t-esc="report_name"/><!-- Report title -->
</h3>
<br/>
<table cellspacing="0" width="100%"
style="border: 1px solid white; text-align: left;">
<thead>
<!-- Table header -->
<tr class="o_heading">
<th colspan="6"/>
<t t-if="data['year']">
<t t-foreach="data['year']"
t-as="periodData"
t-key="periodData_index">
<th class="text-end">
<t t-esc="periodData"/>
</th>
</t>
</t>
</tr>
<tr class="o_heading">
<th colspan="6"/>
<t t-if="data['year']">
<t t-foreach="data['year']"
t-as="periodData"
t-key="periodData_index">
<th class="text-end">Balance</th>
</t>
</t>
</tr>
</thead>
<tbody>
<!-- Table body -->
<tr style="border-bottom: 1.5px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 2%;">
ASSETS
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Current Assets
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Bank and Cash
Accounts
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_cash'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_cash'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_cash'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_cash'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Receivables
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_receivable'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_receivable'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_receivable'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_receivable'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Current
Assets
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_current'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_current'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_current'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_current'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Prepayments
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_prepayments'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_prepayments'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_prepayments'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_prepayments'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total Current Assets
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_current_asset']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Plus Fixed
Assets
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_fixed'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_fixed'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_fixed'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_fixed'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Plus
Non-current Assets
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['asset_non_current'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['asset_non_current'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_non_current'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['asset_non_current'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total Assets
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_assets']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1.5px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 2%;">
LIABILITIES
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Current Liabilities
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Current
Liabilities
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['liability_current'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['liability_current'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_current'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_current'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Payables
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['liability_payable'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['liability_payable'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_payable'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_payable'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total Current Liabilities
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_current_liability']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Plus
Non-current Liabilities
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['liability_non_current'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['liability_non_current'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_non_current'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['liability_non_current'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total LIABILITIES
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_liability']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1.5px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 2%;">
EQUITY
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Unallocated Earnings
</span>
</th>
<th colspan="3"/>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Current
Earnings
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['total_earnings']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Current
Allocated Earnings
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['equity_unaffected'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['equity_unaffected'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['equity_unaffected'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['equity_unaffected'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total Unallocated Earnings
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_unallocated_earning']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6" style="font-weight: normal;">
<span style="margin-left: 6%;">Retained
Earnings
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['equity'][1]"/>
</span>
</th>
</t>
</tr>
<t t-foreach="data['datas']" t-as="value"
t-key="value_index">
<t t-if="value_index == 0">
<t t-foreach="value['equity'][0]"
t-as="datas" t-key="datas_index">
<t t-set="account_name"
t-value="datas['name']"/>
<t t-set="account_value" t-value="0"/>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['equity'][0]"
t-as="datas" t-key="datas_index">
<t t-if="account_name == datas['name']">
<t t-if="datas['amount'] != '0.00'">
<t t-set="account_value"
t-value="1"/>
</t>
</t>
</t>
</t>
<t t-if="account_value == 1">
<tr style="border-bottom: 1px solid gainsboro;">
<th colspan="6"
style="font-weight: normal;">
<span style="margin-left: 8%;">
<t t-esc="datas['name']"/>
</span>
</th>
<t t-foreach="data['datas']"
t-as="values"
t-key="values_index">
<t t-foreach="values['equity'][0]"
t-as="datas"
t-key="datas_index">
<t t-if="account_name == datas['name']">
<th class="text-end"
style="font-weight: normal;">
<span>
<t t-esc="datas['amount']"/>
</span>
</th>
</t>
</t>
</t>
</tr>
</t>
</t>
</t>
</t>
<tr style="border-bottom: 1px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
Total EQUITY
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_equity']"/>
</span>
</th>
</t>
</tr>
<tr style="border-bottom: 1px solid black;">
<th colspan="6" style="font-weight: normal;">
<span style="font-weight: bolder; margin-left: 4%;">
LIABILITIES + EQUITY
</span>
</th>
<t t-foreach="data['datas']" t-as="datas"
t-key="datas_index">
<th class="text-end">
<span style="font-weight: bolder; margin-left: 4%;">
<t t-esc="datas['total_balance']"/>
</span>
</th>
</t>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

231
dynamic_accounts_report/report/bank_book_templates.xml

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Template for Bank Book.-->
<template id="bank_book">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Partner</th>
<th>Account</th>
<th>Options</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['start_date']"
t-out="filters['start_date']"/>
<t t-if="filters['end_date']">
to
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-foreach="filters['partner']"
t-as="selected_partner"
t-key="partner_index">
<t t-out="selected_partner['display_name']"/>
,
</t>
</th>
<th>
<t t-set="first_account" t-value="True"/>
<t t-foreach="filters['account']" t-as="selected_account">
<t t-if="not first_account">,</t>
<t t-out="selected_account"/>
<t t-set="first_account" t-value="False"/>
</t>
</th>
<th>
Posted,
<t t-foreach="filters['options']"
t-as="selected_options"
t-key="options_index">
<t t-out="selected_options"/>,
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<t t-if="move_lines">
<t t-foreach="move_lines"
t-as="move_line"
t-key="move_lines_index">
<table class="table table-sm table-reports">
<thead style="background:#808080;">
<tr>
<th style="width:10%" colspan="6"/>
<th style="width:10%">Journal</th>
<th style="width:10%">Partner</th>
<th style="width:10%">Reference</th>
<th style="width:10%">Move</th>
<th style="width:10%">Entry label</th>
<th class="text-right"
style="padding-right:6px;width:10%;">
Debit
</th>
<th class="text-right"
style="padding-right:6px;width:10%;">
Credit
</th>
<th class="text-right"
style="padding-right:6px;width:10%;">
Balance
</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr class="border-bottom"
style="background:#D3D3D3;">
<th colspan="8"
style="border:0px solid transparent;">
<div class="ms-3">
<span class="fw-bolder">
<strong>
<b>
<t t-esc="move_line"/>
</b>
</strong>
</span>
</div>
</th>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[move_line]['total_debit']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['total_debit']"
t-esc="total[move_line]['total_debit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[move_line]['total_credit']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="total[move_line]['total_credit']"
t-esc="total[move_line]['total_credit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;">
<strong>
<span class="fw-bolder">
<t t-esc="total[move_line]['currency_id']"/>
<t t-esc="total[move_line]['total_debit'] - total[move_line]['total_credit']"/>
</span>
</strong>
</th>
</tr>
<t t-foreach="data[move_line]"
t-as="valuelist"
t-key="valuelist_index">
<tr class="border-bottom">
<th colspan="6" style="width:10%">
<span>
<t t-esc="valuelist['date']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-esc="valuelist['journal_id'][1]"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist['partner_id']">
<t t-esc="valuelist['partner_id'][1]"/>
</t>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist['ref']"
t-esc="valuelist['ref']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist['move_name']"
t-esc="valuelist['move_name']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist['name']"
t-esc="valuelist['name']"/>
</span>
</th>
<th>
<span>
<t t-if="valuelist['debit']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['debit']"
t-esc="valuelist['debit']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist['credit']"
t-esc="total[move_line]['currency_id']"/>
<t t-if="valuelist['credit']"
t-esc="valuelist['credit']"/>
</span>
</th>
<th style="width:10%"/>
</tr>
</t>
</tbody>
</table>
</t>
</t>
<table class="table table-sm table-reports">
<tbody>
<tr>
<th style="width:60%;">Total</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_debit']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_credit']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="float(grand_total['total_debit']) - float(grand_total['total_credit'])"/>
</th>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

209
dynamic_accounts_report/report/financial_report_template.xml

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Template for Profit and Book.-->
<template id="profit_loss">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Comparison</th>
<th>Account</th>
<th>Journal</th>
<th>Analytic Account</th>
<th>Target move</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<table cellspacing="0" width="100%" style="border: 1px solid white; text-align: left;">
<thead>
<tr class="o_heading">
<th colspan="6"/>
<t t-if="data['year']">
<t t-foreach="data['year']"
t-as="periodData"
t-key="periodData_index">
<th class="text-end">
<t t-esc="periodData"/>
</th>
</t>
</t>
</tr>
<tr class="o_heading">
<th colspan="6"/>
<t t-if="data['year']">
<t t-foreach="data['year']"
t-as="periodData"
t-key="periodData_index">
<th class="text-end">Balance</th>
</t>
</t>
</tr>
</thead>
<tbody>
<tr>
<th colspan="6">
<span class="fw-bolder">
Net Profit
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span class="fw-bolder">
<t t-if="total['total']"
t-esc="total['total']"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom border-dark" style="border-right:0px solid transparent;">
<th colspan="9">
<span class="fw-bolder ms-2">
Income
</span>
</th>
</tr>
<tr class="border-bottom border-gainsboro">
<th colspan="9">
<span class="fw-bolder ms-3">
Gross Profit
</span>
</th>
</tr>
<tr class="border-bottom border-gainsboro">
<th colspan="6">
<span class="ms-3">Operating Income</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span>
<t t-esc="total['income'][1]"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom border-gainsboro">
<th colspan="6">
<span class="ms-3">Cost of
Revenue
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span>
<t t-esc="total['expense_direct_cost'][1]"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom">
<th colspan="6">
<span class="ms-3">Other Income
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span>
<t t-esc="total['income_other'][1]"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom">
<th colspan="6">
<span class="fw-bolder ms-2">
Total Income
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span class="fw-bolder">
<t t-esc="total['total_income']"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom border-dark" style="border-right:0px solid transparent;">
<th colspan="9">
<span class="fw-bolder ms-1">
Expenses
</span>
</th>
</tr>
<tr class="border-bottom" style="border-right:0px solid transparent;">
<th colspan="6">
<span class="ms-3">Expenses</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span>
<t t-esc="total['expense'][1]"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom border-gainsboro">
<th colspan="6">
<span class="ms-3">Depreciation
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span>
<t t-esc="total['expense_depreciation'][1]"/>
</span>
</th>
</t>
</tr>
<tr class="border-bottom">
<th colspan="6">
<span class="fw-bolder ms-2">Total Expenses
</span>
</th>
<t t-foreach="data['datas']" t-as="total"
t-key="total_index">
<th class="text-end">
<span class="fw-bolder">
<t t-esc="total['total_expense']"/>
</span>
</th>
</t>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

74
dynamic_accounts_report/report/financial_reports_views.xml

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Action record for Profit and Loss report -->
<record id="action_print_profit_loss" model="ir.actions.report">
<field name="name">Profit And Loss</field>
<field name="model">dynamic.balance.sheet.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.profit_loss</field>
<field name="report_file">dynamic_accounts_report.profit_loss</field>
</record>
<!-- Action record for Balance Sheet report -->
<record id="action_print_balance_sheet" model="ir.actions.report">
<field name="name">Balance Sheet</field>
<field name="model">dynamic.balance.sheet.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.balance_sheet</field>
<field name="report_file">dynamic_accounts_report.balance_sheet</field>
</record>
<!-- Action record for Partner Ledger report -->
<record id="action_print_partner_ledger" model="ir.actions.report">
<field name="name">Partner Ledger</field>
<field name="model">account.partner.ledger</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.partner_ledger</field>
<field name="report_file">dynamic_accounts_report.partner_ledger</field>
</record>
<!-- Action record for General Ledger report -->
<record id="action_print_general_ledger" model="ir.actions.report">
<field name="name">General Ledger</field>
<field name="model">account.general.ledger</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.general_ledger</field>
<field name="report_file">dynamic_accounts_report.general_ledger</field>
</record>
<!-- Action record for Bank Book report -->
<record id="action_print_bank_book" model="ir.actions.report">
<field name="name">Bank Book</field>
<field name="model">bank.book.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.bank_book</field>
<field name="report_file">dynamic_accounts_report.bank_book</field>
</record>
<!-- Action record for Age Receivable report -->
<record id="action_print_aged_receivable" model="ir.actions.report">
<field name="name">Age Receivable</field>
<field name="model">age.receivable.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.aged_receivable</field>
<field name="report_file">dynamic_accounts_report.aged_receivable</field>
</record>
<!-- Action record for Age Payable report -->
<record id="action_print_aged_payable" model="ir.actions.report">
<field name="name">Age Payable</field>
<field name="model">age.payable.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.aged_payable</field>
<field name="report_file">dynamic_accounts_report.aged_payable</field>
</record>
<!-- Action record for Age Payable report -->
<record id="action_print_trial_balance" model="ir.actions.report">
<field name="name">Trial Balance</field>
<field name="model">account.trial.balance</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.trial_balance</field>
<field name="report_file">dynamic_accounts_report.trial_balance</field>
</record>
<record id="action_print_tax_report" model="ir.actions.report">
<field name="name">Tax Report</field>
<field name="model">tax.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.tax_report</field>
<field name="report_file">dynamic_accounts_report.tax_report</field>
</record>
</odoo>

219
dynamic_accounts_report/report/general_ledger_templates.xml

@ -0,0 +1,219 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Template for General Ledger-->
<template id="general_ledger">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Journal</th>
<th>Analytic</th>
<th>Options</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['start_date']"
t-out="filters['start_date']"/>
<t t-if="filters['end_date']">
to
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-set="first_journal" t-value="True"/>
<t t-foreach="filters['journal']" t-as="selected_journal">
<t t-if="not first_journal">,</t>
<t t-out="selected_journal"/>
<t t-set="first_journal" t-value="False"/>
</t>
</th>
<th>
<t t-set="first_account" t-value="True"/>
<t t-foreach="filters['analytic']" t-as="selected_analytic_account">
<t t-if="not first_account">,</t>
<t t-out="selected_analytic_account"/>
<t t-set="first_account" t-value="False"/>
</t>
</th>
<th>
<t t-if="filters['options']">
Posted ,
</t>
<t t-else="">
Posted
</t>
<t t-set="first_option" t-value="True"/>
<t t-foreach="filters['options']" t-as="selected_options">
<t t-if="not first_option">,</t>
<t t-out="selected_options"/>
<t t-set="first_option" t-value="False"/>
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<t t-if="account">
<t t-foreach="account"
t-as="accounts"
t-key="accounts_index">
<table class="table table-sm table-reports">
<thead style="background:#808080;">
<tr>
<th style="width:10%" colspan="6"/>
<th style="width:10%">Date</th>
<th style="width:10%">Communication
</th>
<th style="width:10%">Partner</th>
<th style="width:10%">Debit</th>
<th style="width:10%">Credit</th>
<th style="width:10%">Balance</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr class="border-bottom"
style="background:#D3D3D3;">
<th colspan="6">
<div class="ms-3">
<span class="fw-bolder">
<t t-if="accounts != 'false'">
<strong>
<b>
<t t-esc="accounts"/>
</b>
</strong>
</t>
<t t-else="">
<span>Unknown
Account
</span>
</t>
</span>
</div>
</th>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[accounts]['total_debit']"
t-esc="total[accounts]['currency_id']"/>
<t t-if="total[accounts]['total_debit']"
t-esc="total[accounts]['total_debit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[accounts]['total_credit']"
t-esc="total[accounts]['currency_id']"/>
<t t-if="total[accounts]['total_credit']"
t-esc="total[accounts]['total_credit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;border-right: thin solid #dee2e6;">
<strong>
<span class="fw-bolder">
<t t-esc="total[accounts]['currency_id']"/>
<t t-esc="total[accounts]['total_debit'] - total[accounts]['total_credit']"/>
</span>
</strong>
</th>
</tr>
<t t-foreach="data[accounts]"
t-as="valuelist"
t-key="valuelist_index">
<tr class="border-bottom">
<th colspan="6" style="width:10%">
<span>
<t t-esc="valuelist[0]['move_name']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-esc="valuelist[0]['date']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-esc="valuelist[0]['name']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['partner_id']"
t-esc="valuelist[0]['partner_id'][1]"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['debit']"
t-esc="total[accounts]['currency_id']"/>
<t t-if="valuelist[0]['debit']"
t-esc="valuelist[0]['debit']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['credit']"
t-esc="total[accounts]['currency_id']"/>
<t t-if="valuelist[0]['credit']"
t-esc="valuelist[0]['credit']"/>
</span>
</th>
<th style="width:10%"/>
</tr>
</t>
</tbody>
</table>
</t>
</t>
<table class="table table-sm table-reports">
<tbody>
<tr>
<th style="width:45%;">Total</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_debit']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_credit']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="float(grand_total['total_debit']) - float(grand_total['total_credit'])"/>
</th>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

237
dynamic_accounts_report/report/partner_ledger_templates.xml

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Template for Partner Ledger.-->
<template id="partner_ledger">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Partner</th>
<th>Account</th>
<th>Options</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['start_date']"
t-out="filters['start_date']"/>
<t t-if="filters['end_date']">
to
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-foreach="filters['partner']"
t-as="selected_partner"
t-key="partner_index">
<t t-out="selected_partner['display_name']"/>
,
</t>
</th>
<th>
<t t-foreach="filters['account']"
t-as="selected_account"
t-key="account_index">
<t t-out="selected_account"/>,
</t>
</th>
<th>
<t t-foreach="filters['options']"
t-as="selected_options"
t-key="options_index">
<t t-out="selected_options"/>,
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<t t-if="partners">
<t t-foreach="partners"
t-as="partner"
t-key="partner_index">
<table class="table table-sm table-reports">
<thead style="background:#808080;">
<tr>
<th style="width:10%" colspan="6"/>
<th style="width:10%">JRNL</th>
<th style="width:10%">Account</th>
<th style="width:10%">Ref</th>
<th style="width:10%">Due Date</th>
<th style="width:10%">Matching Number
</th>
<th style="width:10%">Debit</th>
<th style="width:10%">Credit</th>
<th style="width:10%">Amount Currency
</th>
<th style="width:10%">Balance</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr class="border-bottom"
style="background:#D3D3D3;">
<th colspan="9"
style="border:0px solid transparent;border-left: thin solid #dee2e6;">
<div class="ms-3">
<span class="fw-bolder">
<t t-if="partner != 'false'">
<strong>
<b>
<t t-esc="partner"/>
</b>
</strong>
</t>
<t t-else="">
<span>Unknown
Partner
</span>
</t>
</span>
</div>
</th>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[partner]['total_debit']"
t-esc="total[partner]['currency_id']"/>
<t t-if="total[partner]['total_debit']"
t-esc="total[partner]['total_debit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;">
<strong>
<span>
<t t-if="total[partner]['total_credit']"
t-esc="total[partner]['currency_id']"/>
<t t-if="total[partner]['total_credit']"
t-esc="total[partner]['total_credit']"/>
</span>
</strong>
</th>
<th style="width:10% border:0px solid transparent;"/>
<th style="width:10% border:0px solid transparent;border-right: thin solid #dee2e6;">
<strong>
<span class="fw-bolder">
<t t-esc="total[partner]['currency_id']"/>
<t t-esc="total[partner]['total_debit'] - total[partner]['total_credit']"/>
</span>
</strong>
</th>
</tr>
<t t-foreach="data[partner]"
t-as="valuelist"
t-key="valuelist_index">
<tr class="border-bottom">
<th colspan="6" style="width:10%">
<span>
<t t-esc="valuelist[0]['date']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-esc="valuelist[0]['jrnl']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-esc="valuelist[0]['code']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['move_name']"
t-esc="valuelist[0]['move_name']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['date_maturity']"
t-esc="valuelist[0]['date_maturity']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['matching_number']"
t-esc="valuelist[0]['matching_number']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['debit']"
t-esc="total[partner]['currency_id']"/>
<t t-if="valuelist[0]['debit']"
t-esc="valuelist[0]['debit']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['credit']"
t-esc="total[partner]['currency_id']"/>
<t t-if="valuelist[0]['credit']"
t-esc="valuelist[0]['credit']"/>
</span>
</th>
<th style="width:10%">
<span>
<t t-if="valuelist[0]['amount_currency']"
t-esc="total[partner]['currency_id']"/>
<t t-if="valuelist[0]['amount_currency']"
t-esc="valuelist[0]['amount_currency']"/>
</span>
</th>
<th style="width:10%"/>
</tr>
</t>
</tbody>
</table>
</t>
</t>
<table class="table table-sm table-reports">
<tbody>
<tr>
<th style="width:60%;">Total</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_debit']"/>
</th>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_credit']"/>
</th>
<th style="width:10%"/>
<th style="width:10%">
<t t-out="grand_total['currency']"/>
<t t-out="grand_total['total_debit'] - grand_total['total_credit']"/>
</th>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

308
dynamic_accounts_report/report/tax_report_templates.xml

@ -0,0 +1,308 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Template for Tax-->
<template id="tax_report">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Comparison</th>
<th>Options</th>
<th>Report</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['start_date']"
t-out="filters['start_date']"/>
<t t-if="filters['end_date']">
to
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-if="filters['comparison_number_range']">
<t t-out="filters['comparison_type']"/>
:
<t t-out="filters['comparison_number_range']"/>
</t>
</th>
<th>
<t t-foreach="filters['options']"
t-as="selected_options"
t-key="options_index">
<t t-out="selected_options"/>,
</t>
</th>
<th>
<t t-if="report_type and list(report_type.keys())[0] == 'account'">
<span>Account</span>
</t>
<t t-elif="report_type and list(report_type.keys())[0] == 'tax'">
<span>Tax</span>
</t>
<t t-else="">
<t t-out="report_type"/>
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<table class="table table-sm table-reports"
style="width: fit-content;">
<thead style="background:#808080;">
<tr>
<th colspan="6"/>
<t t-foreach="date_viewed" t-as="date_view">
<th colspan="2">
<t t-esc="date_view"/>
</th>
</t>
</tr>
<tr class="o_heading" style="text-align:center;">
<th colspan="6"/>
<th>NET</th>
<th>TAX</th>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="number">
<th>NET</th>
<th>TAX</th>
</t>
</t>
</tr>
</thead>
<tbody>
<t t-if="data">
<t t-set="prev_account" t-value="None"/>
<t t-set="prev_tax" t-value="None"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;background:#dfdfdf;">
<th colspan="6">
<span style="font-weight: 700;">Sales
</span>
</th>
<th/>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="no">
<th/>
<th/>
</t>
</t>
<th style="text-align:center;font-weight: 700;">
<t t-esc="sale_total"/>
</th>
</tr>
<t t-set="i" t-value="0"/>
<t t-foreach="data['sale']"
t-as="sale_tax_line">
<t t-set="i" t-value="i + 1"/>
<t t-if="report_type">
<t t-if="report_type == 'account'">
<t t-if="prev_account != sale_tax_line['account']">
<t t-set="prev_account"
t-value="sale_tax_line['account']"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="12">
<span>
<t t-esc="sale_tax_line['account']"/>
</span>
</th>
</tr>
</t>
</t>
<t t-else="list(report_type.keys())[0] == 'tax'">
<t t-if="prev_tax != sale_tax_line['name']">
<t t-set="prev_tax"
t-value=" sale_tax_line['name']"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="12">
<span>
<t t-esc="sale_tax_line['name']"/>
(
<t t-esc="sale_tax_line['amount']"/>
%)
</span>
</th>
</tr>
</t>
</t>
</t>
<tr class="border-bottom"
style="border-spacing: 0 10px;font-weight: 400;">
<th colspan="6">
<span style="font-weight: 400;">
<t t-if="report_type and list(report_type.keys())[0] == 'tax'">
<t t-esc="sale_tax_line['account']"/>
</t>
<t t-else="">
<t t-esc="sale_tax_line['name']"/>
(
<t t-esc="sale_tax_line['amount']"/>
%)
</t>
</span>
</th>
<t t-if="apply_comparison == true">
<t t-if="sale_tax_line['dynamic net']">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="num">
<th style="text-align:center;font-weight: 400;">
<t t-if="sale_tax_line['dynamic net']['dynamic_total_net_sum' + str(num)]"
t-esc="sale_tax_line['dynamic net']['dynamic_total_net_sum' + str(num)]"/>
</th>
<th style="text-align:center;font-weight: 400;">
<t t-if="sale_tax_line['dynamic tax']['dynamic_total_tax_sum' + str(num)]"
t-esc="sale_tax_line['dynamic tax']['dynamic_total_tax_sum' + str(num)]"/>
</th>
</t>
</t>
</t>
<th style="text-align:center;">
<span style="font-weight: 400;">
<t t-esc="sale_tax_line['net']"/>
</span>
</th>
<th style="text-align:center;">
<span style="font-weight: 400;">
<t t-esc="sale_tax_line['tax']"/>
</span>
</th>
</tr>
</t>
<tr style="height: 2rem;"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;background:#dfdfdf;">
<th colspan="6">
<span style="font-weight: 700;">
Purchase
</span>
</th>
<th/>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="numb">
<th/>
<th/>
</t>
</t>
<th style="text-align:center;font-weight: 700;">
<t t-esc="purchase_total"/>
</th>
</tr>
<t t-set="i" t-value="0"/>
<t t-foreach="data['purchase']"
t-as="purchase_tax_line">
<t t-set="i" t-value="i + 1"/>
<t t-if="report_type">
<t t-if="list(report_type.keys())[0] == 'account'">
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="12">
<span>
<t t-esc="purchase_tax_line['account']"/>
</span>
</th>
</tr>
</t>
<t t-else="list(report_type.keys())[0] == 'tax'">
<t t-set="prev_account"
t-value="purchase_tax_line['name']"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="12">
<span>
<t t-esc="purchase_tax_line['name']"/>
(
<t t-esc="purchase_tax_line['amount']"/>
%)
</span>
</th>
</tr>
</t>
</t>
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="6">
<span style="font-weight: 400;">
<t t-if="report_type and list(report_type.keys())[0] == 'tax'">
<t t-esc="purchase_tax_line['account']"/>
</t>
<t t-else="">
<t t-esc="purchase_tax_line['name']"/>
(
<t t-esc="purchase_tax_line['amount']"/>
%)
</t>
</span>
</th>
<t t-if="apply_comparison == true">
<t t-if="purchase_tax_line['dynamic net']">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="period">
<th style="text-align:center;font-weight: 400;">
<t t-if="purchase_tax_line['dynamic net']['dynamic_total_net_sum' + str(period)]"
t-esc="purchase_tax_line['dynamic net']['dynamic_total_net_sum' + str(period)]"/>
</th>
<th style="text-align:center;font-weight: 400;">
<t t-if="purchase_tax_line['dynamic net']['dynamic_total_net_sum' + str(period)]"
t-esc="purchase_tax_line['dynamic net']['dynamic_total_net_sum' + str(period)]"/>
</th>
</t>
</t>
</t>
<th style="text-align:center;">
<span style="font-weight: 400;">
<t t-esc="purchase_tax_line['net']"/>
</span>
</th>
<th style="text-align:center;">
<span style="font-weight: 400;">
<t t-esc="purchase_tax_line['tax']"/>
</span>
</th>
</tr>
</t>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

171
dynamic_accounts_report/report/trial_balance.xml

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="trial_balance">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<div class="page">
<h3>
<center>
<b>
<span t-esc="report_name"/>
</b>
</center>
</h3>
<br/>
<br/>
<div class="filters">
<table class="table table-sm table-reports">
<thead class="filter_table"
style="background:#808080;">
<tr>
<th>Date Range</th>
<th>Comparison</th>
<th>Account</th>
<th>Journal</th>
<th>Options</th>
</tr>
</thead>
<tbody style="font-size:11px;font-weight:100;">
<tr>
<th>
<t t-if="filters['start_date']"
t-out="filters['start_date']"/>
<t t-if="filters['end_date']">
to
<t t-out="filters['end_date']"/>
</t>
</th>
<th>
<t t-if="filters['comparison_number_range']">
<t t-out="filters['comparison_type']"/>
:
<t t-out="filters['comparison_number_range']"/>
</t>
</th>
<th>
<t t-foreach="filters['journal']"
t-as="selected_journal"
t-key="journal_index">
<t t-out="selected_journal"/>
,
</t>
</th>
<th>
<t t-foreach="filters['account']"
t-as="selected_account"
t-key="account_index">
<t t-out="selected_account['display_name']"/>
,
</t>
</th>
<th>
<t t-foreach="filters['options']"
t-as="selected_options"
t-key="options_index">
<t t-out="selected_options"/>,
</t>
</th>
</tr>
</tbody>
</table>
</div>
<br/>
<br/>
<br/>
<table class="table table-sm table-reports"
style="width: fit-content;">
<thead style="background:#808080;">
<tr>
<th colspan="6"/>
<th colspan="2">Initial Balance</th>
<t t-foreach="date_viewed" t-as="date_view"
t-key="date_view_index">
<th colspan="2">
<t t-esc="date_view"/>
</th>
</t>
<th colspan="2">End Balance</th>
</tr>
<tr class="o_heading" style="text-align:center;background:#D3D3D3;">
<th colspan="6"/>
<th>Debit</th>
<th>Credit</th>
<th>Debit</th>
<th>Credit</th>
<th>Debit</th>
<th>Credit</th>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="number" t-key="number">
<th>Debit</th>
<th>Credit</th>
</t>
</t>
</tr>
</thead>
<tbody>
<t t-if="data">
<t t-set="i" t-value="0"/>
<t t-foreach="data"
t-as="move_line"
t-key="move_line_index">
<t t-set="i" t-value="i + 1"/>
<tr class="border-bottom"
style="border-spacing: 0 10px;">
<th colspan="6">
<t t-esc="move_line['account']"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['initial_total_debit']"
t-esc="move_line['initial_total_debit']"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['initial_total_credit']"
t-esc="move_line['initial_total_credit']"/>
</th>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="num" t-key="num">
<th style="text-align:center;">
<t t-if="move_line['dynamic_total_debit_' + str(num)]"
t-esc="move_line['dynamic_total_debit_' + str(num)]"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['dynamic_total_credit_' + str(num)]"
t-esc="move_line['dynamic_total_credit_' + str(num)]"/>
</th>
</t>
</t>
<th style="text-align:center;">
<t t-if="move_line['total_debit']"
t-esc="move_line['total_debit']"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['total_credit']"
t-esc="move_line['total_credit']"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['end_total_debit']"
t-esc="move_line['end_total_debit']"/>
</th>
<th style="text-align:center;">
<t t-if="move_line['end_total_credit']"
t-esc="move_line['end_total_credit']"/>
</th>
</tr>
</t>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

6
dynamic_accounts_report/security/ir.model.access.csv

@ -0,0 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_general_ledger,access.account.general.ledger,model_account_general_ledger,account.group_account_user,1,1,1,1
access_account_trial_balance,access.account.trial.balance,model_account_trial_balance,account.group_account_user,1,1,1,1
access_cash_book_report,access.cash.book.report,model_cash_book_report,account.group_account_user,1,1,1,1
access_dynamic_balance_sheet_report,access.dynamic.balance.sheet.report,model_dynamic_balance_sheet_report,account.group_account_user,1,1,1,1
access_account_partner_ledger,access.account.partner.ledger,model_account_partner_ledger,account.group_account_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_general_ledger access.account.general.ledger model_account_general_ledger account.group_account_user 1 1 1 1
3 access_account_trial_balance access.account.trial.balance model_account_trial_balance account.group_account_user 1 1 1 1
4 access_cash_book_report access.cash.book.report model_cash_book_report account.group_account_user 1 1 1 1
5 access_dynamic_balance_sheet_report access.dynamic.balance.sheet.report model_dynamic_balance_sheet_report account.group_account_user 1 1 1 1
6 access_account_partner_ledger access.account.partner.ledger model_account_partner_ledger account.group_account_user 1 1 1 1

BIN
dynamic_accounts_report/static/description/assets/icons/capture (1).png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
dynamic_accounts_report/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
dynamic_accounts_report/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
dynamic_accounts_report/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
dynamic_accounts_report/static/description/assets/icons/img.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
dynamic_accounts_report/static/description/assets/icons/photo-capture.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
dynamic_accounts_report/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
dynamic_accounts_report/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
dynamic_accounts_report/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
dynamic_accounts_report/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
dynamic_accounts_report/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
dynamic_accounts_report/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dynamic_accounts_report/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
dynamic_accounts_report/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dynamic_accounts_report/static/description/assets/misc/Cybrosys R.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

33
dynamic_accounts_report/static/description/assets/misc/email.svg

@ -0,0 +1,33 @@
<svg width="80" height="81" viewBox="0 0 80 81" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="3116889_design_email_material_communication_mail_icon 1" clip-path="url(#clip0_81_366)">
<g id="layer1">
<path id="rect3851" d="M74.6067 0.730957H5.5424C2.75742 0.730957 0.499756 3.01685 0.499756 5.83664V75.7642C0.499756 78.584 2.75742 80.8699 5.5424 80.8699H74.6067C77.3916 80.8699 79.6493 78.584 79.6493 75.7642V5.83664C79.6493 3.01685 77.3916 0.730957 74.6067 0.730957Z" fill="#DB534B"/>
<g id="Clip path group">
<mask id="mask0_81_366" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="5" width="78" height="76">
<g id="clipPath4206">
<path id="rect4208" d="M73.6244 5.2915H6.62595C3.92428 5.2915 1.73413 7.4473 1.73413 10.1066V76.0546C1.73413 78.7139 3.92428 80.8697 6.62595 80.8697H73.6244C76.3261 80.8697 78.5162 78.7139 78.5162 76.0546V10.1066C78.5162 7.4473 76.3261 5.2915 73.6244 5.2915Z" fill="white"/>
</g>
</mask>
<g mask="url(#mask0_81_366)">
<g id="g4145" opacity="0.489612">
<g id="g4147">
<path id="path4149" d="M65.8115 41.5171C65.8115 54.9863 54.4292 65.9053 40.3884 65.9053L198.828 221.861C212.869 221.861 224.251 210.942 224.251 197.472L65.8115 41.5171Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4151" d="M40.3884 65.9051C33.2495 65.9051 26.7979 63.0825 22.1802 58.5371L180.62 214.492C185.237 219.038 191.689 221.86 198.828 221.86L40.3884 65.9051Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4153" d="M22.1802 58.5373C17.7157 54.1428 14.9653 48.1381 14.9653 41.5171L173.405 197.472C173.405 204.093 176.155 210.098 180.62 214.493L22.1802 58.5373Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4155" d="M14.9653 41.5171C14.9653 28.0479 26.3476 17.1289 40.3884 17.1289L198.828 173.084C184.787 173.084 173.405 184.003 173.405 197.472L14.9653 41.5171Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4157" d="M40.3884 17.1289C47.5273 17.1289 53.9789 19.9516 58.5966 24.4969L217.036 180.452C212.418 175.907 205.967 173.084 198.828 173.084L40.3884 17.1289Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4159" d="M58.5964 24.4971C63.0609 28.8916 65.8113 34.8963 65.8113 41.5173L224.251 197.473C224.251 190.852 221.5 184.847 217.036 180.452L58.5964 24.4971Z" fill="black" fill-opacity="0.0588235"/>
</g>
<path id="path4111" d="M65.8114 41.5171C65.8114 54.9863 54.4291 65.9053 40.3884 65.9053C26.3476 65.9053 14.9653 54.9863 14.9653 41.5171C14.9653 28.0479 26.3476 17.1289 40.3884 17.1289C54.4291 17.1289 65.8114 28.0479 65.8114 41.5171Z" fill="black" fill-opacity="0.0588235"/>
</g>
</g>
</g>
<path id="path3864" d="M17.506 17.5386H62.9018C64.4068 17.5386 65.8501 18.1439 66.9143 19.2214C67.9784 20.2988 68.5763 21.7602 68.5763 23.284V57.7564C68.5763 58.5109 68.4295 59.258 68.1443 59.9551C67.8592 60.6521 67.4412 61.2855 66.9143 61.819C66.3873 62.3525 65.7618 62.7757 65.0733 63.0645C64.3849 63.3532 63.647 63.5018 62.9018 63.5018H17.506C14.3567 63.5018 11.8315 60.9164 11.8315 57.7564V23.284C11.8315 20.0953 14.3567 17.5386 17.506 17.5386ZM40.2039 37.6475L62.9018 23.284H17.506L40.2039 37.6475ZM17.506 57.7564H62.9018V30.0923L40.2039 44.4271L17.506 30.0923V57.7564Z" fill="white"/>
</g>
</g>
<defs>
<clipPath id="clip0_81_366">
<rect width="80" height="81" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

3
dynamic_accounts_report/static/description/assets/misc/phone.svg

@ -0,0 +1,3 @@
<svg width="36" height="44" viewBox="0 0 36 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M7.25 19.3903C10.13 26.0689 14.76 31.5322 20.43 34.9305L24.83 29.7268C25.38 29.0778 26.17 28.889 26.86 29.1486C29.1 30.0218 31.51 30.4938 34 30.4938C35.11 30.4938 36 31.544 36 32.8537V41.1135C36 42.4233 35.11 43.4734 34 43.4734C15.22 43.4734 0 25.5143 0 3.35456C0 2.0448 0.9 0.994629 2 0.994629H9C10.11 0.994629 11 2.0448 11 3.35456C11 6.29268 11.4 9.1364 12.14 11.7795C12.36 12.5937 12.2 13.5259 11.65 14.1749L7.25 19.3903Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 565 B

9
dynamic_accounts_report/static/description/assets/misc/star (1) 2.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

9
dynamic_accounts_report/static/description/assets/misc/support (1) 1.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 43 KiB

6
dynamic_accounts_report/static/description/assets/misc/support-email.svg

@ -0,0 +1,6 @@
<svg width="49" height="37" viewBox="0 0 49 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<path id="Vector" d="M2.23798 3.59132C3.53363 4.39742 21.5313 15.9748 22.2027 16.3917C22.8741 16.8087 23.5573 17.0032 24.6173 17.0032C25.6774 17.0032 26.3606 16.8087 27.0319 16.3917C27.7033 15.9748 45.701 4.39742 46.9967 3.59132C47.4796 3.29945 48.2923 2.77131 48.469 2.17368C48.7753 1.11741 48.4455 0.714355 47.138 0.714355H24.6173H2.09664C0.789214 0.714355 0.459412 1.13131 0.765656 2.17368C0.942335 2.78521 1.75506 3.29945 2.23798 3.59132Z" fill="white"/>
<path id="Vector_2" d="M48.0214 4.21664C47.0555 4.80037 38.3865 12.0831 32.6503 16.4611L42.3323 29.3171C42.5679 29.5951 42.6739 29.9286 42.5443 30.0954C42.403 30.2483 42.0967 30.1649 41.8494 29.9008L30.2357 18.3374C28.4807 19.6716 27.2439 20.5889 27.0319 20.7279C26.1249 21.2699 25.4889 21.3394 24.6173 21.3394C23.7457 21.3394 23.1096 21.2699 22.2027 20.7279C21.9789 20.5889 20.7539 19.6716 18.9989 18.3374L7.38519 29.9008C7.14961 30.1788 6.83159 30.2622 6.69025 30.0954C6.54891 29.9425 6.65491 29.5951 6.89048 29.3171L16.5607 16.4611C10.8245 12.0831 2.06126 4.80037 1.09541 4.21664C0.0588929 3.59121 0 4.32783 0 4.89766C0 5.46749 0 33.3893 0 33.3893C0 34.6819 1.61367 36.2941 2.76797 36.2941H24.6173H46.4666C47.6209 36.2941 48.999 34.668 48.999 33.3893C48.999 33.3893 48.999 5.4536 48.999 4.89766C48.999 4.31393 49.0697 3.59121 48.0214 4.21664Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

17
dynamic_accounts_report/static/description/assets/misc/tick-mark.svg

@ -0,0 +1,17 @@
<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="52" height="52" fill="#F5F5F5"/>
<g clip-path="url(#clip0_0_1)">
<rect width="1440" height="7504" transform="translate(-107 -1660)" fill="white"/>
<rect x="-45" y="-203" width="1305" height="937" rx="19" fill="#FFF5FC"/>
<rect width="52" height="52" fill="url(#pattern0)"/>
</g>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_0_1" transform="scale(0.00387597)"/>
</pattern>
<clipPath id="clip0_0_1">
<rect width="1440" height="7504" fill="white" transform="translate(-107 -1660)"/>
</clipPath>
<image id="image0_0_1" width="258" height="258" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQIAAAECCAYAAAAVT9lQAAAACXBIWXMAAAsTAAALEwEAmpwYAAAJJ0lEQVR4nO3dYZXjNhQGUDEohEAohEAohEAYCIawEAxhIQRCIQTCQmhX202bTWcmcWzpSda953y/J9JYL5EsyykBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1/f49f37PXwXztVprgMXeUtkCkDNXaw2wyOF7zql8EXir1SBgmTw4v6XyReBUq0HA835L/8zVSxeAXGSOldoELPBHqvMrIP+N3yu1CXhS/hXwJZUvAIoANKrGbcFr8t/5rU6zgGfVWhBUBKBBtRYEFQFoVJ4KXJIiAMOqsUNQEYBG1Z4K/PXz7ykC0IjaU4GcuUrLgKecUt0CoAhAQ/JP8jwgFQEY1CHV2yCkCECDaj0rcJ8/azQOeGxK9QvAtQi4OwDBIm4NKgLQkJoPDCkC0KCo9QBFABpRe6uwIgANidofcM23pAhAqDwAo9YDrkXAyUIQKA/AqPUARQAacEqxRSBHEYBAkYuC15yKtxL40JwUARhWXhQ8p/gi4DVkEOSQYu8MXDOXbijwvug7A4oABIvcLnwbuwYhyCnFFwBFAALVet/go+RfI4fCbQXekefi0QXgWgRsGILKWrk9eM0fZZsL3It+cOg+p7LNBe5Fnib0XuayzQXutbJHQBGAIK0VAbcJobI8B2+pCDhhCCrLRSB64N8XAbcJoaLWikCO24RQ0ZTiB/19PFIMFc0pftDfZy7aYuAXLRYBLyeFilosApfkDgFU02IRcIcAKmnt4aHbuEMAFbT28NBtpoLtBn5quQh8Ldhu4KeWi4BnCKCClouAo8aggpaLQM6xXNOBrPUiYPswFNZ6EZjLNR3IWi8CFgehsNaLgMVBKKz1IpBj5yAU1EMRmIq1HuiiCNg5CAX1UAQuyeIgFNNDEfBYMRTUQxHIOZXqAKDd8wRuMxdrPdDkyUL3ceYgFNRDEbBpCArqoQjk2DQEhfRSBKZSHQCj+5LiB/gzOZfqABjdKcUP8GfibcVQSC9FIOdYqA9gaD0VgalQH8DQ8rdr9OB+NudCfQBDy/vy83w7eoA/E+sCUEBPRSDnWKYbYFz5m7WnIjCV6QYYVy9PEl5zLtMNMK7eioB1ASggf7tGD+4lOZbpBhjXnOIH9pJ8KdMNMK5enh+4xvkCsLFTih/YS+J8AdhYb0Ugx/kCsKG8YSh6UC/NXKQnaFb+h+d5oJ+AZfS2azDHy0oHk4vA9Z+fL9ZT7MfZnTyYLil+YC+N9xEM5LYI3Ca/osq3wXq9bRi65q1EZ9Cmj4rANflb7Bj26fYhF9ToQb003lM4kEdF4DZT0Gfs3ZI+biW2EA/klQvUQuIy+ad19KB+JccSnUF71nxLWUh8Tu6j6AH9SmwhHsSaInAbC4kf6/E2YY4txIPYqghcc0l+Rt47pD6LgFeXD2LrInCbqWI7WtbrbcIctwoHULIIXGMhsb9zBa5xq3AANYrANSMvJNbs563/Z9Z6di7q4hxtITEXv+gB/Wo8Vbhz0d9QlzTGQmJuY/RgfjVuFe5cdBG4zVS4rZF6vU2Yc0lj/WobTktF4Jo9LiT2fIcgx63CnWv14tzbQuI5xffpq5kK9AeNaf3n6h4WEucU34+vxu7BgZxS/AX3WS6p34XE1vv2sziAdEA9PAM/FWt9Gbl4RffZmtg9OKBejsbqZSExf8aWp1yPct6+S+hFLyfmtr6Q2PsdArsH6epwjFYXEucU3zdrYvcgP/SwXnDNJbW1kNhTIX0vHijiX72sF9xmKtITy+SCFN0Pa2JKwP/0eFFHLiTmv9vz4mDOcfNeYRemFH9xLk3EQmLvi4M5HijiU+cUf5G+kpoLiXOlNpXKJZkS8EC+QHr9yZsv8OP2XfKL3hcHc0r3ETuRL5Toi3VNpu275Ife+yXHlIBF8gUTfdGuydYLiT3/UrrtE1MCFut9QWzLhcTe+yLHGQO85JD6/xbMWbuQ2Puvo5xpRfvhx/bT6It4i1zSa4tke2i/MwbYxJziL+atMi1o9yHt4xeRKQGb2MMGmts8s5C4lzZPD9oJi/TyyPKzebSQODfwGdfGlIAi9rCZ5j7vLSTuYV0gx5SAYnp6ZPnZXNJ/C4mHtI91gend/x5sZA8baz4bPHtYFzAloIpjir/Y5eOYElDNlOIvePl/ps/+aVDCHn5G7ymmBIQ4pP2uF/QYUwLCnFL8ABBTAhowp/iBMHIuyePFNKDHU5D3lOPjfxHUsbctyL3EiUM0Z0rxA2OkXJIpAY06p/gBMkqOT/5PoLpDckuxRkwJaN5ent5rNV5VRjf2cM5fq/H2YrqxlxN+Wou3F9MdtxS3jSkB3drjqUZROS3se2jKOcUPot5zXtzr0JhDcktxTb6lbV/fBmHcUnw90wv9Dc2aU/yg6i0OG2F3PKW4PA4bYZfcUnw+04t9DF3IF3j0IGs9l2TPAAOw6/DzHF/vWujHIbml+FHmFf0K3Tml+EHXWmwjZkh7fJfimpzWdSf0ac/vUlya88q+hK4dU/wgjI5txJAcZDKt70Lo38gHmdhGDDdG3XV43KLzYE/yT+TogVkzTiOGD5xT/ACtEXsG4BOHNMYtRacRwwN7P+vwvF1Xwb7tedfhYcN+gl3b667DactOghHs7azDy7bdA+OYU/wA3irHjfsGhrGXsw7nrTsGRpO/SaMH8prYMwAb6fnBpLcC/QFD6nWK4KEi2FiPDyZ5NwEUMKX4wf1sPFQEBfVwdoEFQiishynCqVjrgX+1PEU4F2w3cKfVKcKhZKOBX7U4RZiKthh4V0tThEuyQAhhWpkiOHUIArUwRTgXbyXwUPQU4VC+icAzoqYIU43GAc+JmCJckgVCaE7tKYIFQmhUrSnCuVaDgOVqTREOtRoEvKb0FGGq1xRgjVJTBAuE0JFSU4RTzUYA6209RbBACB3a+tBTZxBCp45pmyLgDELo3Nr3IjiDEHZg7RTBAiHsxKtvV/aSEtiZr2l5ITiGfFKgmDxFyPP9Z4vAHPMxgdLyS0mfXSA8BH1GoIK8MehRIZjCPh1QxaPtx5e4jwbUlL/xPyoEDhyBQXy0t+Ac+aGA+t7bW+B5AhjQ7d4CzxPAoPItwm/J8wQwvLxw+Bb9IQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4DV/A/Mf3+pWEmbtAAAAAElFTkSuQmCC"/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

9
dynamic_accounts_report/static/description/assets/misc/whatsapp 1.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 38 KiB

33
dynamic_accounts_report/static/description/assets/misc/whatsapp.svg

@ -0,0 +1,33 @@
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="3116884_whatsapp_square_chat_design_message_icon 1" clip-path="url(#clip0_81_382)">
<g id="layer1">
<path id="rect3851" d="M74.6066 0.72168H5.5424C2.75742 0.72168 0.499756 2.97935 0.499756 5.76433V74.8286C0.499756 77.6135 2.75742 79.8712 5.5424 79.8712H74.6066C77.3916 79.8712 79.6492 77.6135 79.6492 74.8286V5.76433C79.6492 2.97935 77.3916 0.72168 74.6066 0.72168Z" fill="#39BB59"/>
<g id="Clip path group">
<mask id="mask0_81_382" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="6" y="9" width="75" height="72">
<g id="clipPath4206">
<path id="rect4208" d="M75.7716 9.01709H11.1629C8.55758 9.01709 6.44556 11.0471 6.44556 13.5512V75.6502C6.44556 78.1543 8.55758 80.1843 11.1629 80.1843H75.7716C78.3769 80.1843 80.4889 78.1543 80.4889 75.6502V13.5512C80.4889 11.0471 78.3769 9.01709 75.7716 9.01709Z" fill="white"/>
</g>
</mask>
<g mask="url(#mask0_81_382)">
<g id="g4145" opacity="0.489612">
<g id="g4147">
<path id="path4149" d="M68.2374 43.1284C68.2374 55.8115 57.2611 66.0932 43.7212 66.0932L196.51 212.946C210.049 212.946 221.026 202.665 221.026 189.982L68.2374 43.1284Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4151" d="M43.7211 66.0932C36.8369 66.0932 30.6154 63.4353 26.1624 59.1553L178.951 206.008C183.404 210.289 189.625 212.946 196.51 212.946L43.7211 66.0932Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4153" d="M26.1623 59.1553C21.8571 55.0173 19.2048 49.363 19.2048 43.1284L171.993 189.982C171.993 196.216 174.645 201.87 178.951 206.008L26.1623 59.1553Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4155" d="M19.2048 43.1284C19.2048 30.4453 30.1811 20.1636 43.7211 20.1636L196.509 167.017C182.969 167.017 171.993 177.299 171.993 189.982L19.2048 43.1284Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4157" d="M43.7212 20.1636C50.6054 20.1636 56.8269 22.8215 61.2799 27.1015L214.068 173.955C209.615 169.675 203.394 167.017 196.51 167.017L43.7212 20.1636Z" fill="black" fill-opacity="0.0588235"/>
<path id="path4159" d="M61.2798 27.1016C65.585 31.2396 68.2373 36.8939 68.2373 43.1284L221.026 189.982C221.026 183.747 218.373 178.093 214.068 173.955L61.2798 27.1016Z" fill="black" fill-opacity="0.0588235"/>
</g>
<path id="path4111" d="M68.2373 43.1284C68.2373 55.8115 57.261 66.0932 43.7211 66.0932C30.1811 66.0932 19.2048 55.8115 19.2048 43.1284C19.2048 30.4453 30.1811 20.1636 43.7211 20.1636C57.261 20.1636 68.2373 30.4453 68.2373 43.1284Z" fill="black" fill-opacity="0.0588235"/>
</g>
</g>
</g>
<path id="path4074" d="M51.3896 43.6875C51.9673 43.9879 52.337 44.1497 52.4526 44.3808C52.5912 44.635 52.545 45.7904 51.9673 47.1076C51.5051 48.4017 49.1018 49.6496 48.0388 49.6958C46.9758 49.7421 46.9527 50.5277 41.1985 48.0089C35.4444 45.49 31.9781 39.3431 31.7008 38.9502C31.4235 38.5574 29.4823 35.7612 29.5748 32.9188C29.6903 30.0995 31.1693 28.7592 31.7701 28.2046C32.3247 27.6037 32.9487 27.5344 33.3415 27.6037H34.4276C34.7743 27.6037 35.2596 27.4651 35.6986 28.6437L37.2931 32.965C37.4318 33.2654 37.5242 33.6121 37.3163 33.9818L36.6923 34.9293L35.7911 35.8998C35.5138 36.1771 35.1902 36.4776 35.5138 37.0553C35.7911 37.6561 36.9465 39.5741 38.5641 41.1687C40.667 43.2022 42.5158 43.8724 43.0704 44.1728C43.625 44.4963 43.9716 44.4501 44.3182 44.0804L46.1901 41.9081C46.6291 41.3304 46.9989 41.4691 47.5304 41.6539L51.3896 43.6875ZM40.4128 16.0493C46.5417 16.0493 52.4195 18.484 56.7533 22.8178C61.0871 27.1515 63.5217 33.0293 63.5217 39.1582C63.5217 45.287 61.0871 51.1649 56.7533 55.4986C52.4195 59.8324 46.5417 62.2671 40.4128 62.2671C35.8604 62.2671 31.6315 60.9498 28.0496 58.6852L17.304 62.2671L20.8858 51.5214C18.6212 47.9396 17.304 43.7106 17.304 39.1582C17.304 33.0293 19.7386 27.1515 24.0724 22.8178C28.4061 18.484 34.284 16.0493 40.4128 16.0493ZM40.4128 20.6711C35.5098 20.6711 30.8075 22.6188 27.3405 26.0858C23.8735 29.5528 21.9257 34.2551 21.9257 39.1582C21.9257 43.1329 23.1736 46.8072 25.2996 49.8114L23.0812 56.4898L29.7596 54.2714C32.7638 56.3974 36.4381 57.6453 40.4128 57.6453C45.3159 57.6453 50.0182 55.6975 53.4852 52.2305C56.9522 48.7635 58.9 44.0613 58.9 39.1582C58.9 34.2551 56.9522 29.5528 53.4852 26.0858C50.0182 22.6188 45.3159 20.6711 40.4128 20.6711Z" fill="white"/>
</g>
</g>
<defs>
<clipPath id="clip0_81_382">
<rect width="80" height="80" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
dynamic_accounts_report/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/18.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/19.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/21.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/22.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/23.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/24.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/25.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/26.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/27.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/28.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/29.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/30.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/31.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/33.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/34.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
dynamic_accounts_report/static/description/assets/screenshots/35.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save