Browse Source

[ADD] Initial Commit for 'base_accounting_kit'

pull/134/merge
Ajmalcybrosys 6 years ago
parent
commit
1ef6815468
  1. 44
      base_accounting_kit/README.rst
  2. 24
      base_accounting_kit/__init__.py
  3. 94
      base_accounting_kit/__manifest__.py
  4. 15
      base_accounting_kit/data/account_asset_data.xml
  5. 87
      base_accounting_kit/data/account_financial_report_data.xml
  6. 19
      base_accounting_kit/data/account_pdc_data.xml
  7. 73
      base_accounting_kit/data/cash_flow_data.xml
  8. 12
      base_accounting_kit/data/followup_levels.xml
  9. 34
      base_accounting_kit/models/__init__.py
  10. 51
      base_accounting_kit/models/account_account.py
  11. 656
      base_accounting_kit/models/account_asset.py
  12. 64
      base_accounting_kit/models/account_followup.py
  13. 49
      base_accounting_kit/models/account_journal.py
  14. 177
      base_accounting_kit/models/account_move.py
  15. 114
      base_accounting_kit/models/account_payment.py
  16. 148
      base_accounting_kit/models/credit_limit.py
  17. 44
      base_accounting_kit/models/product_template.py
  18. 95
      base_accounting_kit/models/recurring_payments.py
  19. 44
      base_accounting_kit/models/res_config_settings.py
  20. 109
      base_accounting_kit/models/res_partner.py
  21. 35
      base_accounting_kit/report/__init__.py
  22. 96
      base_accounting_kit/report/account_asset_report.py
  23. 80
      base_accounting_kit/report/account_asset_report_views.xml
  24. 170
      base_accounting_kit/report/account_bank_book.py
  25. 133
      base_accounting_kit/report/account_bank_book_view.xml
  26. 154
      base_accounting_kit/report/account_cash_book.py
  27. 108
      base_accounting_kit/report/account_cash_book_view.xml
  28. 124
      base_accounting_kit/report/account_day_book.py
  29. 115
      base_accounting_kit/report/account_day_book_view.xml
  30. 39
      base_accounting_kit/report/account_report_common_account.py
  31. 216
      base_accounting_kit/report/cash_flow_report.py
  32. 108
      base_accounting_kit/report/cash_flow_report.xml
  33. 171
      base_accounting_kit/report/general_ledger_report.py
  34. 105
      base_accounting_kit/report/general_ledger_report.xml
  35. 112
      base_accounting_kit/report/report.xml
  36. 302
      base_accounting_kit/report/report_aged_partner.py
  37. 98
      base_accounting_kit/report/report_aged_partner.xml
  38. 119
      base_accounting_kit/report/report_financial.py
  39. 146
      base_accounting_kit/report/report_financial.xml
  40. 158
      base_accounting_kit/report/report_journal_audit.py
  41. 150
      base_accounting_kit/report/report_journal_audit.xml
  42. 155
      base_accounting_kit/report/report_partner_ledger.py
  43. 107
      base_accounting_kit/report/report_partner_ledger.xml
  44. 114
      base_accounting_kit/report/report_tax.py
  45. 75
      base_accounting_kit/report/report_tax.xml
  46. 108
      base_accounting_kit/report/report_trial_balance.py
  47. 71
      base_accounting_kit/report/report_trial_balance.xml
  48. 26
      base_accounting_kit/security/account_asset_security.xml
  49. 21
      base_accounting_kit/security/ir.model.access.csv
  50. BIN
      base_accounting_kit/static/description/banner.png
  51. BIN
      base_accounting_kit/static/description/cybro_logo.png
  52. BIN
      base_accounting_kit/static/description/icon.png
  53. BIN
      base_accounting_kit/static/description/images/account_dynamic_report_banner.gif
  54. BIN
      base_accounting_kit/static/description/images/accounting_kit_window.png
  55. BIN
      base_accounting_kit/static/description/images/checked.png
  56. BIN
      base_accounting_kit/static/description/images/crm_dashboard_banner.gif
  57. BIN
      base_accounting_kit/static/description/images/cybrosys.png
  58. BIN
      base_accounting_kit/static/description/images/mobile_service_shop_pro_banner.jpg
  59. BIN
      base_accounting_kit/static/description/images/odoo11_magento_banner.jpg
  60. BIN
      base_accounting_kit/static/description/images/project_custome_gantt_banner.gif
  61. BIN
      base_accounting_kit/static/description/images/report_maker_banner.gif
  62. 464
      base_accounting_kit/static/description/index.html
  63. 9
      base_accounting_kit/views/account_asset_templates.xml
  64. 363
      base_accounting_kit/views/account_asset_views.xml
  65. 16
      base_accounting_kit/views/account_configuration.xml
  66. 113
      base_accounting_kit/views/account_followup.xml
  67. 17
      base_accounting_kit/views/account_invoice_views.xml
  68. 36
      base_accounting_kit/views/account_payment_view.xml
  69. 14
      base_accounting_kit/views/accounting_menu.xml
  70. 78
      base_accounting_kit/views/credit_limit_view.xml
  71. 119
      base_accounting_kit/views/followup_report.xml
  72. 17
      base_accounting_kit/views/product_template_views.xml
  73. 99
      base_accounting_kit/views/recurring_payments_view.xml
  74. 89
      base_accounting_kit/views/reports_config_view.xml
  75. 25
      base_accounting_kit/views/res_config_view.xml
  76. 39
      base_accounting_kit/wizard/__init__.py
  77. 111
      base_accounting_kit/wizard/account_bank_book_wizard.py
  78. 43
      base_accounting_kit/wizard/account_bank_book_wizard_view.xml
  79. 111
      base_accounting_kit/wizard/account_cash_book_wizard.py
  80. 43
      base_accounting_kit/wizard/account_cash_book_wizard_view.xml
  81. 77
      base_accounting_kit/wizard/account_day_book_wizard.py
  82. 40
      base_accounting_kit/wizard/account_day_book_wizard_view.xml
  83. 65
      base_accounting_kit/wizard/account_lock_date.py
  84. 36
      base_accounting_kit/wizard/account_lock_date.xml
  85. 38
      base_accounting_kit/wizard/account_report_common_account.py
  86. 40
      base_accounting_kit/wizard/account_report_common_partner.py
  87. 69
      base_accounting_kit/wizard/aged_partner.py
  88. 41
      base_accounting_kit/wizard/aged_partner.xml
  89. 54
      base_accounting_kit/wizard/asset_depreciation_confirmation_wizard.py
  90. 43
      base_accounting_kit/wizard/asset_depreciation_confirmation_wizard_views.xml
  91. 128
      base_accounting_kit/wizard/asset_modify.py
  92. 40
      base_accounting_kit/wizard/asset_modify_views.xml
  93. 91
      base_accounting_kit/wizard/cash_flow_report.py
  94. 49
      base_accounting_kit/wizard/cash_flow_report.xml
  95. 396
      base_accounting_kit/wizard/financial_report.py
  96. 65
      base_accounting_kit/wizard/financial_report.xml
  97. 55
      base_accounting_kit/wizard/general_ledger.py
  98. 40
      base_accounting_kit/wizard/general_ledger.xml
  99. 45
      base_accounting_kit/wizard/journal_audit.py
  100. 35
      base_accounting_kit/wizard/journal_audit.xml

44
base_accounting_kit/README.rst

@ -0,0 +1,44 @@
Accounting Kit
=============================
* Full accounting kit for Odoo 13 community editions
Installation
============
- www.odoo.com/documentation/12.0/setup/install.html
- Install our custom addon
- You need 'report_xlsx' module in order to get XLSX report.
- Install 'report_xlsx' from https://apps.odoo.com/apps/modules/12.0/report_xlsx/
License
-------
Odoo Proprietary License v1.0 (OPL-1)
(https://www.odoo.com/documentation/user/12.0/legal/licenses/licenses.html)
Company
-------
* 'Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developer:
(v12) Milind Mohan @ Cybrosys, Contact: milind@cybrosys.in
(v12) Mashhood K U @ Cybrosys, Contact: mashood@cybrosys.in
Contacts
--------
* Mail Contact : odoo@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
==========
This module is maintained by Cybrosys Technologies.
For support and more information, please visit https://www.cybrosys.com
Further information
===================
HTML Description: `<static/description/index.html>`__

24
base_accounting_kit/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import models
from . import report
from . import wizard

94
base_accounting_kit/__manifest__.py

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': 'Odoo 13 Accounting',
'version': '13.0.1.0.0',
'category': 'Accounting',
'summary': """ Complete accounting kit for Odoo 13 """,
'description': "This Module will bring back the accounting features such "
"as Account Reports, Asset Management, "
"Customer Credit Limit, Recurring Payment, "
"PDC Management, Customer Follow Up and "
"Lock Dates into Odoo 13 Community Edition",
'author': 'Cybrosys Techno Solutions, Odoo SA',
'website': "https://www.cybrosys.com",
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'depends': ['base', 'account', 'sale', 'account_check_printing'],
'data': [
'security/ir.model.access.csv',
'security/account_asset_security.xml',
'data/account_financial_report_data.xml',
'data/cash_flow_data.xml',
'data/account_pdc_data.xml',
'data/followup_levels.xml',
'data/account_asset_data.xml',
'views/reports_config_view.xml',
'views/accounting_menu.xml',
'views/credit_limit_view.xml',
'views/account_configuration.xml',
'views/account_payment_view.xml',
'views/res_config_view.xml',
'views/recurring_payments_view.xml',
'views/account_followup.xml',
'views/followup_report.xml',
'wizard/asset_depreciation_confirmation_wizard_views.xml',
'wizard/asset_modify_views.xml',
'views/account_asset_views.xml',
'views/account_invoice_views.xml',
'views/account_asset_templates.xml',
'views/product_template_views.xml',
'wizard/financial_report.xml',
'wizard/general_ledger.xml',
'wizard/partner_ledger.xml',
'wizard/tax_report.xml',
'wizard/account_lock_date.xml',
'wizard/trial_balance.xml',
'wizard/aged_partner.xml',
'wizard/journal_audit.xml',
'wizard/cash_flow_report.xml',
'wizard/account_bank_book_wizard_view.xml',
'wizard/account_cash_book_wizard_view.xml',
'wizard/account_day_book_wizard_view.xml',
'wizard/recurring_payments_wizard.xml',
'report/report_financial.xml',
'report/general_ledger_report.xml',
'report/report_journal_audit.xml',
'report/report_aged_partner.xml',
'report/report_trial_balance.xml',
'report/report_tax.xml',
'report/report_partner_ledger.xml',
'report/cash_flow_report.xml',
'report/account_bank_book_view.xml',
'report/account_cash_book_view.xml',
'report/account_day_book_view.xml',
'report/account_asset_report_views.xml',
'report/report.xml',
],
'qweb': ['static/src/xml/*.xml'],
'license': 'AGPL-3',
'images': ['static/description/banner.png'],
'installable': True,
'auto_install': False,
'application': False,
}

15
base_accounting_kit/data/account_asset_data.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding='UTF-8'?>
<odoo>
<record id="account_asset_cron" model="ir.cron">
<field name="name">Account Asset: Generate asset entries</field>
<field name="model_id" ref="model_account_asset_asset"/>
<field name="state">code</field>
<field name="code">model._cron_generate_entries()</field>
<field name="interval_number">1</field>
<field name="interval_type">months</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
</record>
</odoo>

87
base_accounting_kit/data/account_financial_report_data.xml

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Financial Reports -->
<record id="account_financial_report_profitandloss0"
model="account.financial.report">
<field name="name">Profit and Loss</field>
<!-- <field name="sign" eval="-1"/>-->
<field name="type">sum</field>
</record>
<record id="account_financial_report_income0"
model="account.financial.report">
<field name="name">Income</field>
<!-- <field name="sign" eval="-1"/>-->
<field name="parent_id"
ref="account_financial_report_profitandloss0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">account_type</field>
<field name="account_type_ids"
eval="[(4,ref('account.data_account_type_other_income')), (4,ref('account.data_account_type_revenue'))]"/>
</record>
<record id="account_financial_report_expense0"
model="account.financial.report">
<field name="name">Expense</field>
<!-- <field name="sign" eval="-1"/>-->
<field name="sequence">1</field>
<field name="parent_id"
ref="account_financial_report_profitandloss0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">account_type</field>
<field name="account_type_ids"
eval="[(4,ref('account.data_account_type_expenses')), (4,ref('account.data_account_type_direct_costs')), (4,ref('account.data_account_type_depreciation'))]"/>
</record>
<record id="account_financial_report_balancesheet0"
model="account.financial.report">
<field name="name">Balance Sheet</field>
<field name="type">sum</field>
</record>
<record id="account_financial_report_assets0"
model="account.financial.report">
<field name="name">Assets</field>
<field name="parent_id"
ref="account_financial_report_balancesheet0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">account_type</field>
<field name="account_type_ids"
eval="[(4,ref('account.data_account_type_receivable')), (4,ref('account.data_account_type_liquidity')), (4,ref('account.data_account_type_current_assets')), (4,ref('account.data_account_type_non_current_assets'), (4,ref('account.data_account_type_prepayments'))), (4,ref('account.data_account_type_fixed_assets'))]"/>
</record>
<record id="account_financial_report_liabilitysum0"
model="account.financial.report">
<field name="name">Liability</field>
<field name="sequence">1</field>
<field name="parent_id"
ref="account_financial_report_balancesheet0"/>
<field name="display_detail">no_detail</field>
<field name="type">sum</field>
</record>
<record id="account_financial_report_liability0"
model="account.financial.report">
<field name="name">Liability</field>
<field name="parent_id"
ref="account_financial_report_liabilitysum0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">account_type</field>
<field name="account_type_ids"
eval="[(4,ref('account.data_account_type_payable')), (4,ref('account.data_account_type_equity')), (4,ref('account.data_account_type_current_liabilities')), (4,ref('account.data_account_type_non_current_liabilities'))]"/>
</record>
<record id="account_financial_report_profitloss_toreport0"
model="account.financial.report">
<field name="name">Profit (Loss) to report</field>
<field name="parent_id"
ref="account_financial_report_liabilitysum0"/>
<field name="display_detail">no_detail</field>
<field name="type">account_report</field>
<field name="account_report_id"
ref="account_financial_report_profitandloss0"/>
</record>
</data>
</odoo>

19
base_accounting_kit/data/account_pdc_data.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="account_payment_method_pdc_in" model="account.payment.method">
<field name="name">PDC</field>
<field name="code">pdc</field>
<field name="payment_type">inbound</field>
</record>
<record id="account_payment_method_pdc_out" model="account.payment.method">
<field name="name">PDC</field>
<field name="code">pdc</field>
<field name="payment_type">outbound</field>
</record>
<!--<function model="account.journal" name="_enable_check_printing_on_bank_journals"/>-->
</data>
</odoo>

73
base_accounting_kit/data/cash_flow_data.xml

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="account_financial_report_cash_flow0" model="account.financial.report">
<field name="name">Cash Flow Statement</field>
<field name="type">sum</field>
</record>
<record id="account_financial_report_operation0" model="account.financial.report">
<field name="name">Operations</field>
<field name="sequence">1</field>
<field name="parent_id" ref="account_financial_report_cash_flow0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">sum</field>
</record>
<record id="cash_in_from_operation0" model="account.financial.report">
<field name="name">Cash In</field>
<field name="sequence">1</field>
<field name="parent_id" ref="account_financial_report_operation0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
<record id="cash_out_operation1" model="account.financial.report">
<field name="name">Cash Out</field>
<field name="sequence">2</field>
<field name="parent_id" ref="account_financial_report_operation0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
<record id="account_financial_report_investing_activity0" model="account.financial.report">
<field name="name">Investing Activities</field>
<field name="sequence">2</field>
<field name="parent_id" ref="account_financial_report_cash_flow0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">sum</field>
</record>
<record id="cash_in_investing0" model="account.financial.report">
<field name="name">Cash In</field>
<field name="parent_id" ref="account_financial_report_investing_activity0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
<record id="cash_out_investing1" model="account.financial.report">
<field name="name">Cash Out</field>
<field name="parent_id" ref="account_financial_report_investing_activity0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
<record id="account_financial_report_financing_activity1" model="account.financial.report">
<field name="name">Financing Activities</field>
<field name="sequence">3</field>
<field name="parent_id" ref="account_financial_report_cash_flow0"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">sum</field>
</record>
<record id="cash_in_financial0" model="account.financial.report">
<field name="name">Cash In</field>
<field name="parent_id" ref="account_financial_report_financing_activity1"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
<record id="cash_out_financial1" model="account.financial.report">
<field name="name">Cash Out</field>
<field name="parent_id" ref="account_financial_report_financing_activity1"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">accounts</field>
</record>
</data>
</odoo>

12
base_accounting_kit/data/followup_levels.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="followup.line" id="followup_line_id" >
<field name="name">Reminder</field>
<field name="delay">5</field>
</record>
<record model="account.followup" id="followup">
<field name="followup_line_ids" eval="[(6,0,[ref('followup_line_id')])]"/>
</record>
</data>
</odoo>

34
base_accounting_kit/models/__init__.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
#############################################################################
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import account_account
from . import account_asset
from . import account_followup
from . import account_journal
from . import account_move
from . import account_payment
from . import credit_limit
from . import product_template
from . import recurring_payments
from . import res_config_settings
from . import res_partner

51
base_accounting_kit/models/account_account.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, fields, _
from odoo.exceptions import UserError
class CashFlow(models.Model):
_inherit = 'account.account'
def get_cash_flow_ids(self):
cash_flow_id = self.env.ref('base_accounting_kit.account_financial_report_cash_flow0')
if cash_flow_id:
return [('parent_id.id', '=', cash_flow_id.id)]
cash_flow_type = fields.Many2one('account.financial.report', string="Cash Flow type", domain=get_cash_flow_ids)
@api.onchange('cash_flow_type')
def onchange_cash_flow_type(self):
for rec in self.cash_flow_type:
# update new record
rec.write({
'account_ids': [(4, self._origin.id)]
})
if self._origin.cash_flow_type.ids:
for rec in self._origin.cash_flow_type:
# remove old record
rec.write({
'account_ids': [(3, self._origin.id)]
})

656
base_accounting_kit/models/account_asset.py

@ -0,0 +1,656 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import calendar
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_is_zero
class AccountAssetCategory(models.Model):
_name = 'account.asset.category'
_description = 'Asset category'
active = fields.Boolean(default=True)
name = fields.Char(required=True, index=True, string="Asset Type")
account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tag')
account_asset_id = fields.Many2one('account.account', string='Asset Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], help="Account used to record the purchase of the asset at its original price.")
account_depreciation_id = fields.Many2one('account.account', string='Depreciation Entries: Asset Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], help="Account used in the depreciation entries, to decrease the asset value.")
account_depreciation_expense_id = fields.Many2one('account.account', string='Depreciation Entries: Expense Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], oldname='account_income_recognition_id', help="Account used in the periodical entries, to record a part of the asset as expense.")
journal_id = fields.Many2one('account.journal', string='Journal', required=True)
company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env['res.company']._company_default_get('account.asset.category'))
method = fields.Selection([('linear', 'Linear'), ('degressive', 'Degressive')], string='Computation Method', required=True, default='linear',
help="Choose the method to use to compute the amount of depreciation lines.\n"
" * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
method_number = fields.Integer(string='Number of Depreciations', default=5, help="The number of depreciations needed to depreciate your asset")
method_period = fields.Integer(string='Period Length', default=1, help="State here the time between 2 depreciations, in months", required=True)
method_progress_factor = fields.Float('Degressive Factor', default=0.3)
method_time = fields.Selection([('number', 'Number of Entries'), ('end', 'Ending Date')], string='Time Method', required=True, default='number',
help="Choose the method to use to compute the dates and number of entries.\n"
" * Number of Entries: Fix the number of entries and the time between 2 depreciations.\n"
" * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
method_end = fields.Date('Ending date')
prorata = fields.Boolean(string='Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first of January')
open_asset = fields.Boolean(string='Auto-Confirm Assets', help="Check this if you want to automatically confirm the assets of this category when created by invoices.")
group_entries = fields.Boolean(string='Group Journal Entries', help="Check this if you want to group the generated entries by categories.")
type = fields.Selection([('sale', 'Sale: Revenue Recognition'), ('purchase', 'Purchase: Asset')], required=True, index=True, default='purchase')
date_first_depreciation = fields.Selection([
('last_day_period', 'Based on Last Day of Purchase Period'),
('manual', 'Manual (Defaulted on Purchase Date)')],
string='Depreciation Dates', default='manual', required=True,
help='The way to compute the date of the first depreciation.\n'
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations).\n'
' * Based on purchase date: The depreciation dates will be based on the purchase date.')
@api.onchange('account_asset_id')
def onchange_account_asset(self):
if self.type == "purchase":
self.account_depreciation_id = self.account_asset_id
elif self.type == "sale":
self.account_depreciation_expense_id = self.account_asset_id
@api.onchange('type')
def onchange_type(self):
if self.type == 'sale':
self.prorata = True
self.method_period = 1
else:
self.method_period = 12
@api.onchange('method_time')
def _onchange_method_time(self):
if self.method_time != 'number':
self.prorata = False
class AccountAssetAsset(models.Model):
_name = 'account.asset.asset'
_description = 'Asset/Revenue Recognition'
_inherit = ['mail.thread']
entry_count = fields.Integer(compute='_entry_count', string='# Asset Entries')
name = fields.Char(string='Asset Name', required=True, readonly=True, states={'draft': [('readonly', False)]})
code = fields.Char(string='Reference', size=32, readonly=True, states={'draft': [('readonly', False)]})
value = fields.Float(string='Gross Value', required=True, readonly=True, digits=0, states={'draft': [('readonly', False)]}, oldname='purchase_value')
currency_id = fields.Many2one('res.currency', string='Currency', required=True, readonly=True, states={'draft': [('readonly', False)]},
default=lambda self: self.env.user.company_id.currency_id.id)
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, states={'draft': [('readonly', False)]},
default=lambda self: self.env['res.company']._company_default_get('account.asset.asset'))
note = fields.Text()
category_id = fields.Many2one('account.asset.category', string='Category', required=True, change_default=True, readonly=True, states={'draft': [('readonly', False)]})
date = fields.Date(string='Date', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=fields.Date.context_today, oldname="purchase_date")
state = fields.Selection([('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')], 'Status', required=True, copy=False, default='draft',
help="When an asset is created, the status is 'Draft'.\n"
"If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n"
"You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status.")
active = fields.Boolean(default=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True, states={'draft': [('readonly', False)]})
method = fields.Selection([('linear', 'Linear'), ('degressive', 'Degressive')], string='Computation Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, default='linear',
help="Choose the method to use to compute the amount of depreciation lines.\n * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
method_number = fields.Integer(string='Number of Depreciations', readonly=True, states={'draft': [('readonly', False)]}, default=5, help="The number of depreciations needed to depreciate your asset")
method_period = fields.Integer(string='Number of Months in a Period', required=True, readonly=True, default=12, states={'draft': [('readonly', False)]},
help="The amount of time between two depreciations, in months")
method_end = fields.Date(string='Ending Date', readonly=True, states={'draft': [('readonly', False)]})
method_progress_factor = fields.Float(string='Degressive Factor', readonly=True, default=0.3, states={'draft': [('readonly', False)]})
value_residual = fields.Float(compute='_amount_residual', method=True, digits=0, string='Residual Value')
method_time = fields.Selection([('number', 'Number of Entries'), ('end', 'Ending Date')], string='Time Method', required=True, readonly=True, default='number', states={'draft': [('readonly', False)]},
help="Choose the method to use to compute the dates and number of entries.\n"
" * Number of Entries: Fix the number of entries and the time between 2 depreciations.\n"
" * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
prorata = fields.Boolean(string='Prorata Temporis', readonly=True, states={'draft': [('readonly', False)]},
help='Indicates that the first depreciation entry for this asset have to be done from the asset date (purchase date) instead of the first January / Start date of fiscal year')
depreciation_line_ids = fields.One2many('account.asset.depreciation.line', 'asset_id', string='Depreciation Lines', readonly=True, states={'draft': [('readonly', False)], 'open': [('readonly', False)]})
salvage_value = fields.Float(string='Salvage Value', digits=0, readonly=True, states={'draft': [('readonly', False)]},
help="It is the amount you plan to have that you cannot depreciate.")
invoice_id = fields.Many2one('account.move', string='Invoice', states={'draft': [('readonly', False)]}, copy=False)
type = fields.Selection(related="category_id.type", string='Type', required=True)
account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tag')
date_first_depreciation = fields.Selection([
('last_day_period', 'Based on Last Day of Purchase Period'),
('manual', 'Manual')],
string='Depreciation Dates', default='manual',
readonly=True, states={'draft': [('readonly', False)]}, required=True,
help='The way to compute the date of the first depreciation.\n'
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations).\n'
' * Based on purchase date: The depreciation dates will be based on the purchase date.\n')
first_depreciation_manual_date = fields.Date(
string='First Depreciation Date',
readonly=True, states={'draft': [('readonly', False)]},
help='Note that this date does not alter the computation of the first journal entry in case of prorata temporis assets. It simply changes its accounting date'
)
def unlink(self):
for asset in self:
if asset.state in ['open', 'close']:
raise UserError(_('You cannot delete a document that is in %s state.') % (asset.state,))
for depreciation_line in asset.depreciation_line_ids:
if depreciation_line.move_id:
raise UserError(_('You cannot delete a document that contains posted entries.'))
return super(AccountAssetAsset, self).unlink()
@api.model
def _cron_generate_entries(self):
self.compute_generated_entries(datetime.today())
@api.model
def compute_generated_entries(self, date, asset_type=None):
# Entries generated : one by grouped category and one by asset from ungrouped category
created_move_ids = []
type_domain = []
if asset_type:
type_domain = [('type', '=', asset_type)]
ungrouped_assets = self.env['account.asset.asset'].search(type_domain + [('state', '=', 'open'), ('category_id.group_entries', '=', False)])
created_move_ids += ungrouped_assets._compute_entries(date, group_entries=False)
for grouped_category in self.env['account.asset.category'].search(type_domain + [('group_entries', '=', True)]):
assets = self.env['account.asset.asset'].search([('state', '=', 'open'), ('category_id', '=', grouped_category.id)])
created_move_ids += assets._compute_entries(date, group_entries=True)
return created_move_ids
def _compute_board_amount(self, sequence, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date):
for record in self:
amount = 0
if sequence == undone_dotation_number:
amount = residual_amount
else:
if record.method == 'linear':
amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
if record.prorata:
amount = amount_to_depr / record.method_number
if sequence == 1:
date = record.date
if record.method_period % 12 != 0:
month_days = calendar.monthrange(date.year, date.month)[1]
days = month_days - date.day + 1
amount = (amount_to_depr / record.method_number) / month_days * days
else:
days = (record.company_id.compute_fiscalyear_dates(date)['date_to'] - date).days + 1
amount = (amount_to_depr / record.method_number) / total_days * days
elif record.method == 'degressive':
amount = residual_amount * record.method_progress_factor
if record.prorata:
if sequence == 1:
date = record.date
if record.method_period % 12 != 0:
month_days = calendar.monthrange(date.year, date.month)[1]
days = month_days - date.day + 1
amount = (residual_amount * record.method_progress_factor) / month_days * days
else:
days = (record.company_id.compute_fiscalyear_dates(date)['date_to'] - date).days + 1
amount = (residual_amount * record.method_progress_factor) / total_days * days
return amount
def _compute_board_undone_dotation_nb(self, depreciation_date, total_days):
for record in self:
undone_dotation_number = record.method_number
if record.method_time == 'end':
end_date = record.method_end
undone_dotation_number = 0
while depreciation_date <= end_date:
depreciation_date = date(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+record.method_period)
undone_dotation_number += 1
if record.prorata:
undone_dotation_number += 1
return undone_dotation_number
def compute_depreciation_board(self):
self.ensure_one()
for record in self:
posted_depreciation_line_ids = record.depreciation_line_ids.filtered(lambda x: x.move_check).sorted(key=lambda l: l.depreciation_date)
unposted_depreciation_line_ids = record.depreciation_line_ids.filtered(lambda x: not x.move_check)
# Remove old unposted depreciation lines. We cannot use unlink() with One2many field
commands = [(2, line_id.id, False) for line_id in unposted_depreciation_line_ids]
if record.value_residual != 0.0:
amount_to_depr = residual_amount = record.value_residual
# if we already have some previous validated entries, starting date is last entry + method period
if posted_depreciation_line_ids and posted_depreciation_line_ids[-1].depreciation_date:
last_depreciation_date = fields.Date.from_string(posted_depreciation_line_ids[-1].depreciation_date)
depreciation_date = last_depreciation_date + relativedelta(months=+record.method_period)
else:
# depreciation_date computed from the purchase date
depreciation_date = record.date
if record.date_first_depreciation == 'last_day_period':
# depreciation_date = the last day of the month
depreciation_date = depreciation_date + relativedelta(day=31)
# ... or fiscalyear depending the number of period
if record.method_period == 12:
depreciation_date = depreciation_date + relativedelta(month=record.company_id.fiscalyear_last_month)
depreciation_date = depreciation_date + relativedelta(day=record.company_id.fiscalyear_last_day)
if depreciation_date < record.date:
depreciation_date = depreciation_date + relativedelta(years=1)
elif record.first_depreciation_manual_date and record.first_depreciation_manual_date != record.date:
# depreciation_date set manually from the 'first_depreciation_manual_date' field
depreciation_date = record.first_depreciation_manual_date
total_days = (depreciation_date.year % 4) and 365 or 366
month_day = depreciation_date.day
undone_dotation_number = record._compute_board_undone_dotation_nb(depreciation_date, total_days)
for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
sequence = x + 1
amount = record._compute_board_amount(sequence, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date)
amount = record.currency_id.round(amount)
if float_is_zero(amount, precision_rounding=record.currency_id.rounding):
continue
residual_amount -= amount
vals = {
'amount': amount,
'asset_id': record.id,
'sequence': sequence,
'name': (record.code or '') + '/' + str(sequence),
'remaining_value': residual_amount,
'depreciated_value': record.value - (record.salvage_value + residual_amount),
'depreciation_date': depreciation_date,
}
commands.append((0, False, vals))
depreciation_date = depreciation_date + relativedelta(months=+record.method_period)
if month_day > 28 and record.date_first_depreciation == 'manual':
max_day_in_month = calendar.monthrange(depreciation_date.year, depreciation_date.month)[1]
depreciation_date = depreciation_date.replace(day=min(max_day_in_month, month_day))
# datetime doesn't take into account that the number of days is not the same for each month
if not record.prorata and record.method_period % 12 != 0 and record.date_first_depreciation == 'last_day_period':
max_day_in_month = calendar.monthrange(depreciation_date.year, depreciation_date.month)[1]
depreciation_date = depreciation_date.replace(day=max_day_in_month)
record.write({'depreciation_line_ids': commands})
return True
def validate(self):
self.write({'state': 'open'})
fields = [
'method',
'method_number',
'method_period',
'method_end',
'method_progress_factor',
'method_time',
'salvage_value',
'invoice_id',
]
ref_tracked_fields = self.env['account.asset.asset'].fields_get(fields)
for asset in self:
tracked_fields = ref_tracked_fields.copy()
if asset.method == 'linear':
del(tracked_fields['method_progress_factor'])
if asset.method_time != 'end':
del(tracked_fields['method_end'])
else:
del(tracked_fields['method_number'])
dummy, tracking_value_ids = asset._message_track(tracked_fields, dict.fromkeys(fields))
asset.message_post(subject=_('Asset created'), tracking_value_ids=tracking_value_ids)
def _return_disposal_view(self, move_ids):
name = _('Disposal Move')
view_mode = 'form'
if len(move_ids) > 1:
name = _('Disposal Moves')
view_mode = 'tree,form'
return {
'name': name,
'view_type': 'form',
'view_mode': view_mode,
'res_model': 'account.move',
'type': 'ir.actions.act_window',
'target': 'current',
'res_id': move_ids[0],
}
def _get_disposal_moves(self):
move_ids = []
for asset in self:
unposted_depreciation_line_ids = asset.depreciation_line_ids.filtered(lambda x: not x.move_check)
if unposted_depreciation_line_ids:
old_values = {
'method_end': asset.method_end,
'method_number': asset.method_number,
}
# Remove all unposted depr. lines
commands = [(2, line_id.id, False) for line_id in unposted_depreciation_line_ids]
# Create a new depr. line with the residual amount and post it
sequence = len(asset.depreciation_line_ids) - len(unposted_depreciation_line_ids) + 1
today = fields.Datetime.today()
vals = {
'amount': asset.value_residual,
'asset_id': asset.id,
'sequence': sequence,
'name': (asset.code or '') + '/' + str(sequence),
'remaining_value': 0,
'depreciated_value': asset.value - asset.salvage_value, # the asset is completely depreciated
'depreciation_date': today,
}
commands.append((0, False, vals))
asset.write({'depreciation_line_ids': commands, 'method_end': today, 'method_number': sequence})
tracked_fields = self.env['account.asset.asset'].fields_get(['method_number', 'method_end'])
changes, tracking_value_ids = asset._message_track(tracked_fields, old_values)
if changes:
asset.message_post(subject=_('Asset sold or disposed. Accounting entry awaiting for validation.'), tracking_value_ids=tracking_value_ids)
move_ids += asset.depreciation_line_ids[-1].create_move(post_move=False)
return move_ids
def set_to_close(self):
move_ids = self._get_disposal_moves()
if move_ids:
return self._return_disposal_view(move_ids)
# Fallback, as if we just clicked on the smartbutton
return self.open_entries()
def set_to_draft(self):
self.write({'state': 'draft'})
@api.depends('value', 'salvage_value', 'depreciation_line_ids.move_check', 'depreciation_line_ids.amount')
def _amount_residual(self):
for record in self:
total_amount = 0.0
for line in record.depreciation_line_ids:
if line.move_check:
total_amount += line.amount
record.value_residual = record.value - total_amount - record.salvage_value
@api.onchange('company_id')
def onchange_company_id(self):
self.currency_id = self.company_id.currency_id.id
@api.onchange('date_first_depreciation')
def onchange_date_first_depreciation(self):
if self.date_first_depreciation == 'manual':
self.first_depreciation_manual_date = self.date
@api.depends('depreciation_line_ids.move_id')
def _entry_count(self):
for asset in self:
res = self.env['account.asset.depreciation.line'].search_count([('asset_id', '=', asset.id), ('move_id', '!=', False)])
asset.entry_count = res or 0
@api.constrains('prorata', 'method_time')
def _check_prorata(self):
if self.prorata and self.method_time != 'number':
raise ValidationError(_('Prorata temporis can be applied only for the "number of depreciations" time method.'))
@api.onchange('category_id')
def onchange_category_id(self):
vals = self.onchange_category_id_values(self.category_id.id)
# We cannot use 'write' on an object that doesn't exist yet
if vals:
for k, v in vals['value'].items():
setattr(self, k, v)
def onchange_category_id_values(self, category_id):
if category_id:
category = self.env['account.asset.category'].browse(category_id)
return {
'value': {
'method': category.method,
'method_number': category.method_number,
'method_time': category.method_time,
'method_period': category.method_period,
'method_progress_factor': category.method_progress_factor,
'method_end': category.method_end,
'prorata': category.prorata,
'date_first_depreciation': category.date_first_depreciation,
'account_analytic_id': category.account_analytic_id.id,
'analytic_tag_ids': [(6, 0, category.analytic_tag_ids.ids)],
}
}
@api.onchange('method_time')
def onchange_method_time(self):
if self.method_time != 'number':
self.prorata = False
def copy_data(self, default=None):
if default is None:
default = {}
default['name'] = self.name + _(' (copy)')
return super(AccountAssetAsset, self).copy_data(default)
def _compute_entries(self, date, group_entries=False):
depreciation_ids = self.env['account.asset.depreciation.line'].search([
('asset_id', 'in', self.ids), ('depreciation_date', '<=', date),
('move_check', '=', False)])
if group_entries:
return depreciation_ids.create_grouped_move()
return depreciation_ids.create_move()
@api.model
def create(self, vals):
asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals)
asset.sudo().compute_depreciation_board()
return asset
def write(self, vals):
for record in self:
res = super(AccountAssetAsset, record).write(vals)
if 'depreciation_line_ids' not in vals and 'state' not in vals:
for rec in record:
rec.compute_depreciation_board()
return res
def open_entries(self):
move_ids = []
for asset in self:
for depreciation_line in asset.depreciation_line_ids:
if depreciation_line.move_id:
move_ids.append(depreciation_line.move_id.id)
return {
'name': _('Journal Entries'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'type': 'ir.actions.act_window',
'domain': [('id', 'in', move_ids)],
}
class AccountAssetDepreciationLine(models.Model):
_name = 'account.asset.depreciation.line'
_description = 'Asset depreciation line'
name = fields.Char(string='Depreciation Name', required=True, index=True)
sequence = fields.Integer(required=True)
asset_id = fields.Many2one('account.asset.asset', string='Asset', required=True, ondelete='cascade')
parent_state = fields.Selection(related='asset_id.state', string='State of Asset')
amount = fields.Float(string='Current Depreciation', digits=0, required=True)
remaining_value = fields.Float(string='Next Period Depreciation', digits=0, required=True)
depreciated_value = fields.Float(string='Cumulative Depreciation', required=True)
depreciation_date = fields.Date('Depreciation Date', index=True)
move_id = fields.Many2one('account.move', string='Depreciation Entry')
move_check = fields.Boolean(compute='_get_move_check', string='Linked', track_visibility='always', store=True)
move_posted_check = fields.Boolean(compute='_get_move_posted_check', string='Posted', track_visibility='always', store=True)
@api.depends('move_id')
def _get_move_check(self):
for line in self:
line.move_check = bool(line.move_id)
@api.depends('move_id.state')
def _get_move_posted_check(self):
for line in self:
line.move_posted_check = True if line.move_id and line.move_id.state == 'posted' else False
def create_move(self, post_move=True):
created_moves = self.env['account.move']
for line in self:
if line.move_id:
raise UserError(_('This depreciation is already linked to a journal entry. Please post or delete it.'))
move_vals = self._prepare_move(line)
move = self.env['account.move'].create(move_vals)
line.write({'move_id': move.id, 'move_check': True})
created_moves |= move
if post_move and created_moves:
created_moves.filtered(lambda m: any(m.asset_depreciation_ids.mapped('asset_id.category_id.open_asset'))).post()
return [x.id for x in created_moves]
def _prepare_move(self, line):
category_id = line.asset_id.category_id
account_analytic_id = line.asset_id.account_analytic_id
analytic_tag_ids = line.asset_id.analytic_tag_ids
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
prec = company_currency.decimal_places
amount = current_currency._convert(
line.amount, company_currency, line.asset_id.company_id, depreciation_date)
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
move_line_1 = {
'name': asset_name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'sale' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'purchase' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'purchase' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and line.amount or 0.0,
}
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
return move_vals
def _prepare_move_grouped(self):
asset_id = self[0].asset_id
category_id = asset_id.category_id # we can suppose that all lines have the same category
account_analytic_id = asset_id.account_analytic_id
analytic_tag_ids = asset_id.analytic_tag_ids
depreciation_date = self.env.context.get('depreciation_date') or fields.Date.context_today(self)
amount = 0.0
for line in self:
# Sum amount of all depreciation lines
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
company = line.asset_id.company_id
amount += current_currency._convert(line.amount, company_currency, company, fields.Date.today())
name = category_id.name + _(' (grouped)')
move_line_1 = {
'name': name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0,
'credit': amount,
'journal_id': category_id.journal_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'sale' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'sale' else False,
}
move_line_2 = {
'name': name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0,
'debit': amount,
'journal_id': category_id.journal_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'purchase' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] if category_id.type == 'purchase' else False,
}
move_vals = {
'ref': category_id.name,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
return move_vals
def create_grouped_move(self, post_move=True):
if not self.exists():
return []
created_moves = self.env['account.move']
move = self.env['account.move'].create(self._prepare_move_grouped())
self.write({'move_id': move.id, 'move_check': True})
created_moves |= move
if post_move and created_moves:
self.post_lines_and_close_asset()
created_moves.post()
return [x.id for x in created_moves]
def post_lines_and_close_asset(self):
# we re-evaluate the assets to determine whether we can close them
for line in self:
line.log_message_when_posted()
asset = line.asset_id
if asset.currency_id.is_zero(asset.value_residual):
asset.message_post(body=_("Document closed."))
asset.write({'state': 'close'})
def log_message_when_posted(self):
def _format_message(message_description, tracked_values):
message = ''
if message_description:
message = '<span>%s</span>' % message_description
for name, values in tracked_values.items():
message += '<div> &nbsp; &nbsp; &bull; <b>%s</b>: ' % name
message += '%s</div>' % values
return message
for line in self:
if line.move_id and line.move_id.state == 'draft':
partner_name = line.asset_id.partner_id.name
currency_name = line.asset_id.currency_id.name
msg_values = {_('Currency'): currency_name, _('Amount'): line.amount}
if partner_name:
msg_values[_('Partner')] = partner_name
msg = _format_message(_('Depreciation line posted.'), msg_values)
line.asset_id.message_post(body=msg)
def unlink(self):
for record in self:
if record.move_check:
if record.asset_id.category_id.type == 'purchase':
msg = _("You cannot delete posted depreciation lines.")
else:
msg = _("You cannot delete posted installment lines.")
raise UserError(msg)
return super(AccountAssetDepreciationLine, self).unlink()

64
base_accounting_kit/models/account_followup.py

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, api, models, _
class Followup(models.Model):
_name = 'account.followup'
_description = 'Account Follow-up'
_rec_name = 'name'
followup_line_ids = fields.One2many('followup.line', 'followup_id', 'Follow-up', copy=True)
company_id = fields.Many2one('res.company', 'Company',
default=lambda self: self.env['res.company']._company_default_get(
'account_followup.followup'))
name = fields.Char(related='company_id.name', readonly=True)
_sql_constraints = [('company_uniq', 'unique(company_id)', 'Only one follow-up per company is allowed')]
class FollowupLine(models.Model):
_name = 'followup.line'
_description = 'Follow-up Criteria'
_order = 'delay'
name = fields.Char('Follow-Up Action', required=True, translate=True)
sequence = fields.Integer(help="Gives the sequence order when displaying a list of follow-up lines.")
delay = fields.Integer('Due Days', required=True,
help="The number of days after the due date of the invoice"
" to wait before sending the reminder."
" Could be negative if you want to send a polite alert beforehand.")
followup_id = fields.Many2one('account.followup', 'Follow Ups', ondelete="cascade")
_sql_constraints = [('days_uniq', 'unique(followup_id, delay)', 'Days of the follow-up levels must be different')]
@api.constrains('description')
def _check_description(self):
for line in self:
if line.description:
try:
line.description % {'partner_name': '', 'date': '', 'user_signature': '', 'company_name': ''}
except:
raise Warning(_(
'Your description is invalid, use the right legend'
' or %% if you want to use the percent character.'))

49
base_accounting_kit/models/account_journal.py

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, api
class AccountJournal(models.Model):
_inherit = "account.journal"
@api.depends('outbound_payment_method_ids')
def _compute_check_printing_payment_method_selected(self):
self.check_printing_payment_method_selected = any(
pm.code in ['check_printing', 'pdc'] for pm in
self.outbound_payment_method_ids)
@api.model
def _enable_pdc_on_bank_journals(self):
""" Enables check printing payment method and add a check
sequence on bank journals. Called upon module installation
via data file.
"""
pdcin = self.env.ref('base_accounting_kit.account_payment_method_pdc_in')
pdcout = self.env.ref('base_accounting_kit.account_payment_method_pdc_out')
bank_journals = self.search([('type', '=', 'bank')])
for bank_journal in bank_journals:
# bank_journal._create_check_sequence()
bank_journal.write({
'inbound_payment_method_ids': [(4, pdcin.id, None)],
'outbound_payment_method_ids': [(4, pdcout.id, None)],
})

177
base_accounting_kit/models/account_move.py

@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.addons.base.models import decimal_precision as dp
from odoo.exceptions import UserError
class AccountMove(models.Model):
_inherit = 'account.move'
asset_depreciation_ids = fields.One2many('account.asset.depreciation.line',
'move_id',
string='Assets Depreciation Lines',
ondelete="restrict")
@api.model
def _refund_cleanup_lines(self, lines):
result = super(AccountMove, self)._refund_cleanup_lines(lines)
for i, line in enumerate(lines):
for name, field in line._fields.items():
if name == 'asset_category_id':
result[i][2][name] = False
break
return result
def action_cancel(self):
res = super(AccountMove, self).action_cancel()
self.env['account.asset.asset'].sudo().search(
[('invoice_id', 'in', self.ids)]).write({'active': False})
return res
def action_post(self):
result = super(AccountMove, self).action_post()
for inv in self:
context = dict(self.env.context)
# Within the context of an invoice,
# this default value is for the type of the invoice, not the type of the asset.
# This has to be cleaned from the context before creating the asset,
# otherwise it tries to create the asset with the type of the invoice.
context.pop('default_type', None)
inv.invoice_line_ids.with_context(context).asset_create()
return result
def button_cancel(self):
for move in self:
for line in move.asset_depreciation_ids:
line.move_posted_check = False
return super(AccountMove, self).button_cancel()
def post(self):
for move in self:
for depreciation_line in move.asset_depreciation_ids:
depreciation_line.post_lines_and_close_asset()
return super(AccountMove, self).post()
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
asset_category_id = fields.Many2one('account.asset.category',
string='Asset Category')
type_rel = fields.Selection(related='move_id.type')
move_asset_category_id = fields.Many2one('account.move')
asset_start_date = fields.Date(string='Asset Start Date',
compute='_get_asset_date', readonly=True,
store=True)
asset_end_date = fields.Date(string='Asset End Date',
compute='_get_asset_date', readonly=True,
store=True)
asset_mrr = fields.Float(string='Monthly Recurring Revenue',
compute='_get_asset_date', readonly=True,
digits=dp.get_precision('Account'), store=True)
@api.depends('asset_category_id', 'move_id.invoice_date')
def _get_asset_date(self):
for record in self:
record.asset_mrr = 0
record.asset_start_date = False
record.asset_end_date = False
cat = record.asset_category_id
if cat:
if cat.method_number == 0 or cat.method_period == 0:
raise UserError(_('The number of depreciations or '
'the period length of your asset category cannot be 0.'))
months = cat.method_number * cat.method_period
if record.move_id.type in ['out_invoice', 'out_refund']:
record.asset_mrr = record.price_subtotal / months
if record.move_id.invoice_date:
start_date = record.move_id.invoice_date.replace(day=1)
end_date = (start_date + relativedelta(months=months,
days=-1))
record.asset_start_date = start_date
record.asset_end_date = end_date
def asset_create(self):
for record in self:
if record.asset_category_id:
vals = {
'name': record.name,
'code': record.move_id.name or False,
'category_id': record.asset_category_id.id,
'value': record.price_subtotal,
'partner_id': record.move_id.partner_id.id,
'company_id': record.move_id.company_id.id,
'currency_id': record.move_id.company_currency_id.id,
'date': record.move_id.invoice_date,
'invoice_id': record.move_id.id,
}
changed_vals = record.env[
'account.asset.asset'].onchange_category_id_values(
vals['category_id'])
vals.update(changed_vals['value'])
asset = record.env['account.asset.asset'].create(vals)
if record.asset_category_id.open_asset:
asset.validate()
return True
@api.onchange('asset_category_id')
def onchange_asset_category_id(self):
if self.move_id.type == 'out_invoice' and self.asset_category_id:
self.account_id = self.asset_category_id.account_asset_id.id
elif self.move_id.type == 'in_invoice' and self.asset_category_id:
self.account_id = self.asset_category_id.account_asset_id.id
@api.onchange('uom_id')
def _onchange_uom_id(self):
result = super(AccountMoveLine, self)._onchange_uom_id()
self.onchange_asset_category_id()
return result
@api.onchange('product_id')
def _onchange_product_id(self):
vals = super(AccountMoveLine, self)._onchange_product_id()
if self.product_id:
if self.move_id.type == 'out_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id
elif self.move_id.type == 'in_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id
return vals
def _set_additional_fields(self, invoice):
if not self.asset_category_id:
if invoice.type == 'out_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id
elif invoice.type == 'in_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id
self.onchange_asset_category_id()
super(AccountMoveLine, self)._set_additional_fields(invoice)
def get_invoice_line_account(self, type, product, fpos, company):
return product.asset_category_id.account_asset_id or super(
AccountMoveLine, self).get_invoice_line_account(type,
product,
fpos,
company)

114
base_accounting_kit/models/account_payment.py

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields, _
from odoo.exceptions import UserError
class AccountRegisterPayments(models.TransientModel):
_inherit = "account.payment.register"
bank_reference = fields.Char(copy=False)
cheque_reference = fields.Char(copy=False)
effective_date = fields.Date('Effective Date',
help='Effective date of PDC', copy=False,
default=False)
def get_payments_vals(self):
res = super(AccountRegisterPayments, self).get_payment_vals()
if self.payment_method_id == self.env.ref(
'account_check_printing.account_payment_method_check'):
res.update({
'check_amount_in_words': self.check_amount_in_words,
'check_manual_sequencing': self.check_manual_sequencing,
'effective_date': self.effective_date,
})
return res
class AccountPayment(models.Model):
_inherit = "account.payment"
bank_reference = fields.Char(copy=False)
cheque_reference = fields.Char(copy=False)
effective_date = fields.Date('Effective Date',
help='Effective date of PDC', copy=False,
default=False)
def print_checks(self):
""" Check that the recordset is valid, set the payments state to
sent and call print_checks() """
# Since this method can be called via a client_action_multi, we
# need to make sure the received records are what we expect
self = self.filtered(lambda r:
r.payment_method_id.code
in ['check_printing', 'pdc']
and r.state != 'reconciled')
if len(self) == 0:
raise UserError(_(
"Payments to print as a checks must have 'Check' "
"or 'PDC' selected as payment method and "
"not have already been reconciled"))
if any(payment.journal_id != self[0].journal_id for payment in self):
raise UserError(_(
"In order to print multiple checks at once, they "
"must belong to the same bank journal."))
if not self[0].journal_id.check_manual_sequencing:
# The wizard asks for the number printed on the first
# pre-printed check so payments are attributed the
# number of the check the'll be printed on.
last_printed_check = self.search([
('journal_id', '=', self[0].journal_id.id),
('check_number', '!=', "0")], order="check_number desc",
limit=1)
next_check_number = last_printed_check and int(
last_printed_check.check_number) + 1 or 1
return {
'name': _('Print Pre-numbered Checks'),
'type': 'ir.actions.act_window',
'res_model': 'print.prenumbered.checks',
'view_mode': 'form',
'target': 'new',
'context': {
'payment_ids': self.ids,
'default_next_check_number': next_check_number,
}
}
else:
self.filtered(lambda r: r.state == 'draft').post()
self.write({'state': 'sent'})
return self.do_print_checks()
def _prepare_payment_moves(self):
""" supered function to set effective date """
res = super(AccountPayment, self)._prepare_payment_moves()
inbound_pdc_id = self.env.ref(
'base_accounting_kit.account_payment_method_pdc_in').id
outbound_pdc_id = self.env.ref(
'base_accounting_kit.account_payment_method_pdc_out').id
if self.payment_method_id.id == inbound_pdc_id or \
self.payment_method_id.id == outbound_pdc_id \
and self.effective_date:
res[0]['date'] = self.effective_date
for line in res[0]['line_ids']:
line[2]['date_maturity'] = self.effective_date
return res

148
base_accounting_kit/models/credit_limit.py

@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.tools.translate import _
class ResPartner(models.Model):
_inherit = 'res.partner'
warning_stage = fields.Float(string='Warning Amount',
help="A warning message will appear once the "
"selected customer is crossed warning "
"amount. Set its value to 0.00 to"
" disable this feature")
blocking_stage = fields.Float(string='Blocking Amount',
help="Cannot make sales once the selected "
"customer is crossed blocking amount."
"Set its value to 0.00 to disable "
"this feature")
due_amount = fields.Float(string="Total Sale",
compute="compute_due_amount")
active_limit = fields.Boolean("Active Credit Limit", default=False)
enable_credit_limit = fields.Boolean(string="Credit Limit Enabled",
compute="_compute_enable_credit_limit")
def compute_due_amount(self):
for rec in self:
if not rec.id:
continue
rec.due_amount = rec.credit - rec.debit
def _compute_enable_credit_limit(self):
""" Check credit limit is enabled in account settings """
params = self.env['ir.config_parameter'].sudo()
customer_credit_limit = params.get_param('customer_credit_limit',
default=False)
for rec in self:
rec.enable_credit_limit = True if customer_credit_limit else False
@api.constrains('warning_stage', 'blocking_stage')
def constrains_warning_stage(self):
if self.active_limit and self.enable_credit_limit:
if self.warning_stage >= self.blocking_stage:
if self.blocking_stage > 0:
raise UserError(_(
"Warning amount should be less than Blocking amount"))
class SaleOrder(models.Model):
_inherit = 'sale.order'
has_due = fields.Boolean()
is_warning = fields.Boolean()
due_amount = fields.Float(related='partner_id.due_amount')
def _action_confirm(self):
"""To check the selected customers due amount is exceed than
blocking stage"""
pay_type = ['out_invoice', 'out_refund', 'out_receipt']
if self.partner_id.active_limit and self.type in pay_type \
and self.partner_id.enable_credit_limit:
if self.due_amount >= self.partner_id.blocking_stage:
if self.partner_id.blocking_stage != 0:
raise UserError(_(
"%s is in Blocking Stage and "
"has a due amount of %s %s to pay") % (
self.partner_id.name, self.due_amount,
self.currency_id.symbol))
return super(SaleOrder, self)._action_confirm()
@api.onchange('partner_id')
def check_due(self):
"""To show the due amount and warning stage"""
if self.partner_id and self.partner_id.due_amount > 0 \
and self.partner_id.active_limit \
and self.partner_id.enable_credit_limit:
self.has_due = True
else:
self.has_due = False
if self.partner_id and self.partner_id.active_limit\
and self.partner_id.enable_credit_limit:
if self.due_amount >= self.partner_id.warning_stage:
if self.partner_id.warning_stage != 0:
self.is_warning = True
else:
self.is_warning = False
class AccountMove(models.Model):
_inherit = 'account.move'
has_due = fields.Boolean()
is_warning = fields.Boolean()
due_amount = fields.Float(related='partner_id.due_amount')
def action_post(self):
"""To check the selected customers due amount is exceed than
blocking stage"""
pay_type = ['out_invoice', 'out_refund', 'out_receipt']
if self.partner_id.active_limit and self.type in pay_type \
and self.partner_id.enable_credit_limit:
if self.due_amount >= self.partner_id.blocking_stage:
if self.partner_id.blocking_stage != 0:
raise UserError(_(
"%s is in Blocking Stage and "
"has a due amount of %s %s to pay") % (
self.partner_id.name, self.due_amount,
self.currency_id.symbol))
return super(AccountMove, self).action_post()
@api.onchange('partner_id')
def check_due(self):
"""To show the due amount and warning stage"""
if self.partner_id and self.partner_id.due_amount > 0 \
and self.partner_id.active_limit \
and self.partner_id.enable_credit_limit:
self.has_due = True
else:
self.has_due = False
if self.partner_id and self.partner_id.active_limit \
and self.partner_id.enable_credit_limit:
if self.due_amount >= self.partner_id.warning_stage:
if self.partner_id.warning_stage != 0:
self.is_warning = True
else:
self.is_warning = False

44
base_accounting_kit/models/product_template.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
asset_category_id = fields.Many2one('account.asset.category',
string='Asset Type',
company_dependent=True,
ondelete="restrict")
deferred_revenue_category_id = fields.Many2one('account.asset.category',
string='Deferred Revenue Type',
company_dependent=True,
ondelete="restrict")
def _get_asset_accounts(self):
res = super(ProductTemplate, self)._get_asset_accounts()
if self.asset_category_id:
res['stock_input'] = self.property_account_expense_id
if self.deferred_revenue_category_id:
res['stock_output'] = self.property_account_income_id
return res

95
base_accounting_kit/models/recurring_payments.py

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import datetime, date
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api
class FilterRecurringEntries(models.Model):
_inherit = 'account.move'
recurring_ref = fields.Char()
class RecurringPayments(models.Model):
_name = 'account.recurring.payments'
def _get_next_schedule(self):
if self.date:
recurr_dates = []
today = datetime.today()
start_date = datetime.strptime(str(self.date), '%Y-%m-%d')
while start_date <= today:
recurr_dates.append(str(start_date.date()))
if self.recurring_period == 'days':
start_date += relativedelta(days=self.recurring_interval)
elif self.recurring_period == 'weeks':
start_date += relativedelta(weeks=self.recurring_interval)
elif self.recurring_period == 'months':
start_date += relativedelta(months=self.recurring_interval)
else:
start_date += relativedelta(years=self.recurring_interval)
self.next_date = start_date.date()
name = fields.Char('Name')
debit_account = fields.Many2one('account.account', 'Debit Account',
required=True,
domain="['|', ('company_id', '=', False), "
"('company_id', '=', company_id)]")
credit_account = fields.Many2one('account.account', 'Credit Account',
required=True,
domain="['|', ('company_id', '=', False), "
"('company_id', '=', company_id)]")
journal_id = fields.Many2one('account.journal', 'Journal', required=True)
analytic_account_id = fields.Many2one('account.analytic.account',
'Analytic Account')
date = fields.Date('Starting Date', required=True, default=date.today())
next_date = fields.Date('Next Schedule', compute=_get_next_schedule,
readonly=True, copy=False)
recurring_period = fields.Selection(selection=[('days', 'Days'),
('weeks', 'Weeks'),
('months', 'Months'),
('years', 'Years')],
store=True, required=True)
amount = fields.Float('Amount')
description = fields.Text('Description')
state = fields.Selection(selection=[('draft', 'Draft'),
('running', 'Running')],
default='draft', string='Status')
journal_state = fields.Selection(selection=[('draft', 'Unposted'),
('posted', 'Posted')],
required=True, default='draft',
string='Generate Journal As')
recurring_interval = fields.Integer('Recurring Interval', default=1)
partner_id = fields.Many2one('res.partner', 'Partner')
pay_time = fields.Selection(selection=[('pay_now', 'Pay Directly'),
('pay_later', 'Pay Later')],
store=True, required=True)
company_id = fields.Many2one('res.company',
default=lambda l: l.env.user.company_id.id)
@api.onchange('partner_id')
def onchange_partner_id(self):
if self.partner_id.property_account_receivable_id:
self.credit_account = self.partner_id.property_account_payable_id

44
base_accounting_kit/models/res_config_settings.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields, api
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
customer_credit_limit = fields.Boolean(string="Customer Credit Limit")
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
params = self.env['ir.config_parameter'].sudo()
customer_credit_limit = params.get_param('customer_credit_limit',
default=False)
res.update(customer_credit_limit=customer_credit_limit)
return res
def set_values(self):
super(ResConfigSettings, self).set_values()
self.env['ir.config_parameter'].sudo().set_param(
"customer_credit_limit",
self.customer_credit_limit)

109
base_accounting_kit/models/res_partner.py

@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import date, timedelta
from odoo import fields, models
class ResPartner(models.Model):
_inherit = "res.partner"
invoice_list = fields.One2many('account.move', 'partner_id',
string="Invoice Details",
readonly=True,
domain=(
[('invoice_payment_state', '=', 'not_paid'),
('type', '=', 'out_invoice')]))
total_due = fields.Monetary(compute='_compute_for_followup', store=False,
readonly=True)
next_reminder_date = fields.Date(compute='_compute_for_followup',
store=False, readonly=True)
total_overdue = fields.Monetary(compute='_compute_for_followup',
store=False, readonly=True)
followup_status = fields.Selection(
[('in_need_of_action', 'In need of action'),
('with_overdue_invoices', 'With overdue invoices'),
('no_action_needed', 'No action needed')],
string='Followup status',
)
def _compute_for_followup(self):
"""
Compute the fields 'total_due', 'total_overdue' , 'next_reminder_date' and 'followup_status'
"""
for record in self:
total_due = 0
total_overdue = 0
today = fields.Date.today()
for am in record.invoice_list:
if am.company_id == self.env.user.company_id:
amount = am.amount_residual
total_due += amount
is_overdue = today > am.invoice_date_due if am.invoice_date_due else today > am.date
if is_overdue:
total_overdue += not am.invoice_sent and amount or 0
min_date = record.get_min_date()
action = record.action_after()
if min_date:
date_reminder = min_date + timedelta(days=action)
if date_reminder:
record.next_reminder_date = date_reminder
else:
date_reminder = today
record.next_reminder_date = date_reminder
if total_overdue > 0 and date_reminder > today:
followup_status = "with_overdue_invoices"
elif total_due > 0 and date_reminder <= today:
followup_status = "in_need_of_action"
else:
followup_status = "no_action_needed"
record.total_due = total_due
record.total_overdue = total_overdue
record.followup_status = followup_status
def get_min_date(self):
today = date.today()
for this in self:
if this.invoice_list:
min_list = this.invoice_list.mapped('invoice_date_due')
while False in min_list:
min_list.remove(False)
return min(min_list)
else:
return today
def get_delay(self):
delay = """select id,delay from followup_line where followup_id =
(select id from account_followup where company_id = %s)
order by delay limit 1"""
self._cr.execute(delay, [self.env.user.company_id.id])
record = self.env.cr.dictfetchall()
return record
def action_after(self):
lines = self.env['followup.line'].search([(
'followup_id.company_id', '=', self.env.user.company_id.id)])
if lines:
record = self.get_delay()
for i in record:
return i['delay']

35
base_accounting_kit/report/__init__.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import general_ledger_report
from . import account_report_common_account
from . import report_partner_ledger
from . import report_tax
from . import report_trial_balance
from . import report_aged_partner
from . import report_journal_audit
from . import report_financial
from . import cash_flow_report
from . import account_bank_book
from . import account_cash_book
from . import account_day_book
from . import account_asset_report

96
base_accounting_kit/report/account_asset_report.py

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models, tools
class AssetAssetReport(models.Model):
_name = "asset.asset.report"
_description = "Assets Analysis"
_auto = False
name = fields.Char(string='Year', required=False, readonly=True)
date = fields.Date(readonly=True)
depreciation_date = fields.Date(string='Depreciation Date', readonly=True)
asset_id = fields.Many2one('account.asset.asset', string='Asset',
readonly=True)
asset_category_id = fields.Many2one('account.asset.category',
string='Asset category', readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner',
readonly=True)
state = fields.Selection(
[('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')],
string='Status', readonly=True)
depreciation_value = fields.Float(string='Amount of Depreciation Lines',
readonly=True)
installment_value = fields.Float(string='Amount of Installment Lines',
readonly=True)
move_check = fields.Boolean(string='Posted', readonly=True)
installment_nbr = fields.Integer(string='Installment Count', readonly=True)
depreciation_nbr = fields.Integer(string='Depreciation Count',
readonly=True)
gross_value = fields.Float(string='Gross Amount', readonly=True)
posted_value = fields.Float(string='Posted Amount', readonly=True)
unposted_value = fields.Float(string='Unposted Amount', readonly=True)
company_id = fields.Many2one('res.company', string='Company',
readonly=True)
def init(self):
tools.drop_view_if_exists(self._cr, 'asset_asset_report')
self._cr.execute("""
create or replace view asset_asset_report as (
select
min(dl.id) as id,
dl.name as name,
dl.depreciation_date as depreciation_date,
a.date as date,
(CASE WHEN dlmin.id = min(dl.id)
THEN a.value
ELSE 0
END) as gross_value,
dl.amount as depreciation_value,
dl.amount as installment_value,
(CASE WHEN dl.move_check
THEN dl.amount
ELSE 0
END) as posted_value,
(CASE WHEN NOT dl.move_check
THEN dl.amount
ELSE 0
END) as unposted_value,
dl.asset_id as asset_id,
dl.move_check as move_check,
a.category_id as asset_category_id,
a.partner_id as partner_id,
a.state as state,
count(dl.*) as installment_nbr,
count(dl.*) as depreciation_nbr,
a.company_id as company_id
from account_asset_depreciation_line dl
left join account_asset_asset a on (dl.asset_id=a.id)
left join (select min(d.id) as id,ac.id as ac_id from account_asset_depreciation_line as d inner join account_asset_asset as ac ON (ac.id=d.asset_id) group by ac_id) as dlmin on dlmin.ac_id=a.id
where a.active is true
group by
dl.amount,dl.asset_id,dl.depreciation_date,dl.name,
a.date, dl.move_check, a.state, a.category_id, a.partner_id, a.company_id,
a.value, a.id, a.salvage_value, dlmin.id
)""")

80
base_accounting_kit/report/account_asset_report_views.xml

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="action_account_asset_report_pivot">
<field name="name">asset.asset.report.pivot</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<pivot string="Assets Analysis" disable_linking="True">
<field name="asset_category_id" type="row"/>
<field name="gross_value" type="measure"/>
<field name="unposted_value" type="measure"/>
</pivot>
</field>
</record>
<record model="ir.ui.view" id="action_account_asset_report_graph">
<field name="name">asset.asset.report.graph</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<graph string="Assets Analysis">
<field name="asset_category_id" type="row"/>
<field name="gross_value" type="measure"/>
<field name="unposted_value" type="measure"/>
</graph>
</field>
</record>
<record id="view_asset_asset_report_search" model="ir.ui.view">
<field name="name">asset.asset.report.search</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<search string="Assets Analysis">
<field name="date"/>
<field name="depreciation_date"/>
<filter string="Draft" name="draft" domain="[('state','=','draft')]" help="Assets in draft state"/>
<filter string="Running" name="running" domain="[('state','=','open')]" help="Assets in running state"/>
<separator/>
<filter string="Posted" name="posted" domain="[('move_check','=',True)]" help="Posted depreciation lines" context="{'unposted_value_visible': 0}"/>
<field name="asset_id"/>
<field name="asset_category_id"/>
<group expand="0" string="Extended Filters...">
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group expand="1" string="Group By">
<filter string="Asset" name="asset" context="{'group_by':'asset_id'}"/>
<filter string="Asset Category" name="asset_category" context="{'group_by':'asset_category_id'}"/>
<filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
<separator/>
<filter string="Purchase Month" name="purchase_month" help="Date of asset purchase"
context="{'group_by':'date:month'}"/>
<filter string="Depreciation Month" name="deprecation_month" help="Date of depreciation"
context="{'group_by':'depreciation_date:month'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_asset_asset_report">
<field name="name">Assets Analysis</field>
<field name="res_model">asset.asset.report</field>
<field name="view_mode">graph,pivot</field>
<field name="domain">[('asset_category_id.type', '=', 'purchase')]</field>
<field name="context">{}</field> <!-- force empty -->
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No content
</p><p>
From this report, you can have an overview on all depreciations. The
search bar can also be used to personalize your assets depreciation reporting.
</p>
</field>
</record>
<menuitem name="Assets"
action="action_asset_asset_report"
id="menu_action_asset_asset_report"
parent="account.account_reports_management_menu"
sequence="21"/>
</odoo>

170
base_accounting_kit/report/account_bank_book.py

@ -0,0 +1,170 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import time
from odoo import models, api, _
from odoo.exceptions import UserError
class ReportBankBook(models.AbstractModel):
_name = 'report.base_accounting_kit.report_bank_book'
def _get_account_move_entry(self, accounts, init_balance, sortby,
display_account):
cr = self.env.cr
move_line = self.env['account.move.line']
move_lines = {x: [] for x in accounts.ids}
# Prepare initial sql query and Get the initial move lines
if init_balance:
init_tables, init_where_clause, init_where_params = move_line.with_context(
date_from=self.env.context.get('date_from'), date_to=False,
initial_bal=True)._query_get()
init_wheres = [""]
if init_where_clause.strip():
init_wheres.append(init_where_clause.strip())
init_filters = " AND ".join(init_wheres)
filters = init_filters.replace('account_move_line__move_id',
'm').replace('account_move_line',
'l')
sql = ("""SELECT 0 AS lid, l.account_id AS account_id, \
'' AS ldate, '' AS lcode, 0.0 AS amount_currency, \
'' AS lref, 'Initial Balance' AS lname, \
COALESCE(SUM(l.debit),0.0) AS debit, \
COALESCE(SUM(l.credit),0.0) AS credit, \
COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance, \
'' AS lpartner_id,\
'' AS move_name, '' AS mmove_id, '' AS currency_code,\
NULL AS currency_id,\
'' AS invoice_id, '' AS invoice_type, '' AS invoice_number,\
'' AS partner_name\
FROM account_move_line l\
LEFT JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
WHERE l.account_id IN %s""" + filters + ' GROUP BY l.account_id')
params = (tuple(accounts.ids),) + tuple(init_where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
move_lines[row.pop('account_id')].append(row)
sql_sort = 'l.date, l.move_id'
if sortby == 'sort_journal_partner':
sql_sort = 'j.code, p.name, l.move_id'
# Prepare sql query base on selected parameters from wizard
tables, where_clause, where_params = move_line._query_get()
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
filters = filters.replace('account_move_line__move_id', 'm').replace(
'account_move_line', 'l')
# Get move lines base on sql query and Calculate the total
# balance of move lines
sql = ('''SELECT l.id AS lid, l.account_id \
AS account_id, l.date AS ldate, j.code AS lcode,\
l.currency_id, l.amount_currency, l.ref AS lref, l.name AS lname,\
COALESCE(l.debit,0) AS debit, \
COALESCE(l.credit,0) AS credit, \
COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,\
m.name AS move_name, c.symbol AS \
currency_code, p.name AS partner_name\
FROM account_move_line l\
JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
JOIN account_account acc ON (l.account_id = acc.id) \
WHERE l.account_id IN %s ''' + filters + ''' GROUP BY \
l.id, l.account_id, l.date, j.code, l.currency_id, \
l.amount_currency, l.ref, l.name, m.name, \
c.symbol, p.name ORDER BY ''' + sql_sort)
params = (tuple(accounts.ids),) + tuple(where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
balance = 0
for line in move_lines.get(row['account_id']):
balance += line['debit'] - line['credit']
row['balance'] += balance
move_lines[row.pop('account_id')].append(row)
# Calculate the debit, credit and balance for Accounts
account_res = []
for account in accounts:
currency = account.currency_id and \
account.currency_id or account.company_id.currency_id
res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance'])
res['code'] = account.code
res['name'] = account.name
res['move_lines'] = move_lines[account.id]
for line in res.get('move_lines'):
res['debit'] += line['debit']
res['credit'] += line['credit']
res['balance'] = line['balance']
if display_account == 'all':
account_res.append(res)
if display_account == 'movement' and res.get('move_lines'):
account_res.append(res)
if display_account == 'not_zero' and not currency.is_zero(
res['balance']):
account_res.append(res)
return account_res
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get('active_model'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(
self.env.context.get('active_ids', []))
init_balance = data['form'].get('initial_balance', True)
sortby = data['form'].get('sortby', 'sort_date')
display_account = 'movement'
codes = []
if data['form'].get('journal_ids', False):
codes = [journal.code for journal in
self.env['account.journal'].search(
[('id', 'in', data['form']['journal_ids'])])]
account_ids = data['form']['account_ids']
accounts = self.env['account.account'].search(
[('id', 'in', account_ids)])
accounts_res = self.with_context(
data['form'].get('used_context', {}))._get_account_move_entry(
accounts,
init_balance,
sortby,
display_account)
return {
'doc_ids': docids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'Accounts': accounts_res,
'print_journal': codes,
}

133
base_accounting_kit/report/account_bank_book_view.xml

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_bank_book">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2><span t-esc="res_company.name"/>: Bank Book Report
</h2>
<div class="row">
<div class="col-xs-4" style="width:40%;">
<strong>Journals:</strong>
<p t-esc="', '.join([ lt or '' for lt in print_journal ])"/>
</div>
<div class="col-xs-4" style="width:30%;">
<strong>Display Account</strong>
<p>
<span t-if="data['display_account'] == 'all'">All accounts'</span>
<span t-if="data['display_account'] == 'movement'">With movements</span>
<span t-if="data['display_account'] == 'not_zero'">With balance not equal to zero</span>
</p>
</div>
<div class="col-xs-4" style="width:30%;">
<strong>Target Moves:</strong>
<p t-if="data['target_move'] == 'all'">All Entries</p>
<p t-if="data['target_move'] == 'posted'">All Posted Entries</p>
</div>
</div>
<br/>
<div class="row">
<div style="width:70%;">
<strong>Sorted By:</strong>
<p t-if="data['sortby'] == 'sort_date'">Date</p>
<p t-if="data['sortby'] == 'sort_journal_partner'">Journal and Partner</p>
</div>
<div style="width:30%;">
<t t-if="data['date_from']">
<strong>Date from :</strong>
<span t-esc="data['date_from']"/>
<br/>
</t>
<t t-if="data['date_to']">
<strong>Date to :</strong>
<span t-esc="data['date_to']"/>
</t>
</div>
</div>
<br/>
<table class="table table-condensed">
<thead>
<tr class="text-center">
<th>Date</th>
<th>JRNL</th>
<th>Partner</th>
<th>Ref</th>
<th>Move</th>
<th>Entry Label</th>
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th groups="base.group_multi_currency">Currency</th>
</tr>
</thead>
<tbody>
<t t-foreach="Accounts" t-as="account">
<tr style="font-weight: bold;">
<td colspan="6">
<span style="color: white;" t-esc="'..'"/>
<span t-esc="account['code']"/>
<span t-esc="account['name']"/>
</td>
<td class="text-right">
<span t-esc="account['debit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['credit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['balance']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td groups="base.group_multi_currency"/>
</tr>
<tr t-foreach="account['move_lines']" t-as="line">
<td>
<span t-esc="line['ldate']"/>
</td>
<td>
<span t-esc="line['lcode']"/>
</td>
<td>
<span t-esc="line['partner_name']"/>
</td>
<td>
<span t-if="line['lref']" t-esc="line['lref']"/>
</td>
<td>
<span t-esc="line['move_name']"/>
</td>
<td>
<span t-esc="line['lname']"/>
</td>
<td class="text-right">
<span t-esc="line['debit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['credit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['balance']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" groups="base.group_multi_currency">
<span t-esc="line['amount_currency'] if line['amount_currency'] > 0.00 else ''"/>
<span t-esc="line['currency_code'] if line['amount_currency'] > 0.00 else ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

154
base_accounting_kit/report/account_cash_book.py

@ -0,0 +1,154 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import time
from odoo import models, api, _
from odoo.exceptions import UserError
class ReportCashBook(models.AbstractModel):
_name = 'report.base_accounting_kit.report_cash_book'
def _get_account_move_entry(self, accounts, init_balance, sortby,
display_account):
cr = self.env.cr
move_line = self.env['account.move.line']
move_lines = {x: [] for x in accounts.ids}
# Prepare initial sql query and Get the initial move lines
if init_balance:
init_tables, init_where_clause, init_where_params = move_line.with_context(
date_from=self.env.context.get('date_from'), date_to=False,
initial_bal=True)._query_get()
init_wheres = [""]
if init_where_clause.strip():
init_wheres.append(init_where_clause.strip())
init_filters = " AND ".join(init_wheres)
filters = init_filters.replace('account_move_line__move_id',
'm').replace('account_move_line',
'l')
sql = ("""SELECT 0 AS lid, l.account_id AS account_id, '' AS ldate, '' AS lcode, 0.0 AS amount_currency, '' AS lref, 'Initial Balance' AS lname, COALESCE(SUM(l.debit),0.0) AS debit, COALESCE(SUM(l.credit),0.0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance, '' AS lpartner_id,\
'' AS move_name, '' AS mmove_id, '' AS currency_code,\
NULL AS currency_id,\
'' AS invoice_id, '' AS invoice_type, '' AS invoice_number,\
'' AS partner_name\
FROM account_move_line l\
LEFT JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
WHERE l.account_id IN %s""" + filters + ' GROUP BY l.account_id')
params = (tuple(accounts.ids),) + tuple(init_where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
move_lines[row.pop('account_id')].append(row)
sql_sort = 'l.date, l.move_id'
if sortby == 'sort_journal_partner':
sql_sort = 'j.code, p.name, l.move_id'
# Prepare sql query base on selected parameters from wizard
tables, where_clause, where_params = move_line._query_get()
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
filters = filters.replace('account_move_line__move_id', 'm').replace(
'account_move_line', 'l')
# Get move lines base on sql query and Calculate the total balance of move lines
sql = ('''SELECT l.id AS lid, l.account_id AS account_id, l.date AS ldate, j.code AS lcode, l.currency_id, l.amount_currency, l.ref AS lref, l.name AS lname, COALESCE(l.debit,0) AS debit, COALESCE(l.credit,0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,\
m.name AS move_name, c.symbol AS currency_code, p.name AS partner_name\
FROM account_move_line l\
JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
JOIN account_account acc ON (l.account_id = acc.id) \
WHERE l.account_id IN %s ''' + filters + ''' GROUP BY l.id, l.account_id, l.date, j.code, l.currency_id, l.amount_currency, l.ref, l.name, m.name, c.symbol, p.name ORDER BY ''' + sql_sort)
params = (tuple(accounts.ids),) + tuple(where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
balance = 0
for line in move_lines.get(row['account_id']):
balance += line['debit'] - line['credit']
row['balance'] += balance
move_lines[row.pop('account_id')].append(row)
# Calculate the debit, credit and balance for Accounts
account_res = []
for account in accounts:
currency = account.currency_id and account.currency_id or account.company_id.currency_id
res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance'])
res['code'] = account.code
res['name'] = account.name
res['move_lines'] = move_lines[account.id]
for line in res.get('move_lines'):
res['debit'] += line['debit']
res['credit'] += line['credit']
res['balance'] = line['balance']
if display_account == 'all':
account_res.append(res)
if display_account == 'movement' and res.get('move_lines'):
account_res.append(res)
if display_account == 'not_zero' and not currency.is_zero(
res['balance']):
account_res.append(res)
return account_res
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get('active_model'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(
self.env.context.get('active_ids', []))
init_balance = data['form'].get('initial_balance', True)
sortby = data['form'].get('sortby', 'sort_date')
display_account = 'movement'
codes = []
if data['form'].get('journal_ids', False):
codes = [journal.code for journal in
self.env['account.journal'].search(
[('id', 'in', data['form']['journal_ids'])])]
account_ids = data['form']['account_ids']
accounts = self.env['account.account'].search(
[('id', 'in', account_ids)])
accounts_res = self.with_context(
data['form'].get('used_context', {}))._get_account_move_entry(
accounts,
init_balance,
sortby,
display_account)
return {
'doc_ids': docids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'Accounts': accounts_res,
'print_journal': codes,
}

108
base_accounting_kit/report/account_cash_book_view.xml

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_cash_book">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2><span t-esc="res_company.name"/>: Cash Book Report</h2>
<div class="row">
<div class="col-xs-4" style="width:40%;">
<strong>Journals:</strong>
<p t-esc="', '.join([ lt or '' for lt in print_journal ])"/>
</div>
<div class="col-xs-4" style="width:30%;">
<strong>Display Account</strong>
<p>
<span t-if="data['display_account'] == 'all'">All accounts'</span>
<span t-if="data['display_account'] == 'movement'">With movements</span>
<span t-if="data['display_account'] == 'not_zero'">With balance not equal to zero</span>
</p>
</div>
<div class="col-xs-4" style="width:30%;">
<strong>Target Moves:</strong>
<p t-if="data['target_move'] == 'all'">All Entries</p>
<p t-if="data['target_move'] == 'posted'">All Posted Entries</p>
</div>
</div>
<br/>
<div class="row">
<div style="width:70%;">
<strong>Sorted By:</strong>
<p t-if="data['sortby'] == 'sort_date'">Date</p>
<p t-if="data['sortby'] == 'sort_journal_partner'">Journal and Partner</p>
</div>
<div style="width:30%;">
<t t-if="data['date_from']"><strong>Date from :</strong> <span t-esc="data['date_from']"/><br/></t>
<t t-if="data['date_to']"><strong>Date to :</strong> <span t-esc="data['date_to']"/></t>
</div>
</div>
<br/>
<table class="table table-condensed">
<thead>
<tr class="text-center">
<th>Date</th>
<th>JRNL</th>
<th>Partner</th>
<th>Ref</th>
<th>Move</th>
<th>Entry Label</th>
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th groups="base.group_multi_currency">Currency</th>
</tr>
</thead>
<tbody>
<t t-foreach="Accounts" t-as="account">
<tr style="font-weight: bold;">
<td colspan="6">
<span style="color: white;" t-esc="'..'"/>
<span t-esc="account['code']"/>
<span t-esc="account['name']"/>
</td>
<td class="text-right">
<span t-esc="account['debit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td groups="base.group_multi_currency"/>
</tr>
<tr t-foreach="account['move_lines']" t-as="line">
<td><span t-esc="line['ldate']"/></td>
<td><span t-esc="line['lcode']"/></td>
<td><span t-esc="line['partner_name']"/></td>
<td><span t-if="line['lref']" t-esc="line['lref']"/></td>
<td><span t-esc="line['move_name']"/></td>
<td><span t-esc="line['lname']"/></td>
<td class="text-right">
<span t-esc="line['debit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['credit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['balance']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" groups="base.group_multi_currency">
<span t-esc="line['amount_currency'] if line['amount_currency'] > 0.00 else ''"/>
<span t-esc="line['currency_code'] if line['amount_currency'] > 0.00 else ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

124
base_accounting_kit/report/account_day_book.py

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from datetime import timedelta, datetime
from odoo import models, api, _
from odoo.exceptions import UserError
class DayBookPdfReport(models.AbstractModel):
_name = 'report.base_accounting_kit.day_book_report_template'
def _get_account_move_entry(self, accounts, form_data, pass_date):
cr = self.env.cr
move_line = self.env['account.move.line']
tables, where_clause, where_params = move_line._query_get()
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
if form_data['target_move'] == 'posted':
target_move = "AND m.state = 'posted'"
else:
target_move = ''
sql = ('''
SELECT l.id AS lid, acc.name as accname, l.account_id AS account_id, l.date AS ldate, j.code AS lcode, l.currency_id,
l.amount_currency, l.ref AS lref, l.name AS lname, COALESCE(l.debit,0) AS debit, COALESCE(l.credit,0) AS credit,
COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,
m.name AS move_name, c.symbol AS currency_code, p.name AS partner_name
FROM account_move_line l
JOIN account_move m ON (l.move_id=m.id)
LEFT JOIN res_currency c ON (l.currency_id=c.id)
LEFT JOIN res_partner p ON (l.partner_id=p.id)
JOIN account_journal j ON (l.journal_id=j.id)
JOIN account_account acc ON (l.account_id = acc.id)
WHERE l.account_id IN %s AND l.journal_id IN %s ''' + target_move + ''' AND l.date = %s
GROUP BY l.id, l.account_id, l.date,
j.code, l.currency_id, l.amount_currency, l.ref, l.name, m.name, c.symbol, p.name , acc.name
ORDER BY l.date DESC
''')
params = (
tuple(accounts.ids), tuple(form_data['journal_ids']), pass_date)
cr.execute(sql, params)
data = cr.dictfetchall()
res = {}
debit = credit = balance = 0.00
for line in data:
debit += line['debit']
credit += line['credit']
balance += line['balance']
res['debit'] = debit
res['credit'] = credit
res['balance'] = balance
res['lines'] = data
return res
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get('active_model'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(
self.env.context.get('active_ids', []))
form_data = data['form']
codes = []
if data['form'].get('journal_ids', False):
codes = [journal.code for journal in
self.env['account.journal'].search(
[('id', 'in', data['form']['journal_ids'])])]
active_acc = data['form']['account_ids']
accounts = self.env['account.account'].search(
[('id', 'in', active_acc)]) if data['form']['account_ids'] else \
self.env['account.account'].search([])
date_start = datetime.strptime(form_data['date_from'],
'%Y-%m-%d').date()
date_end = datetime.strptime(form_data['date_to'], '%Y-%m-%d').date()
days = date_end - date_start
dates = []
record = []
for i in range(days.days + 1):
dates.append(date_start + timedelta(days=i))
for head in dates:
pass_date = str(head)
accounts_res = self.with_context(
data['form'].get('used_context', {}))._get_account_move_entry(
accounts, form_data, pass_date)
if accounts_res['lines']:
record.append({
'date': head,
'debit': accounts_res['debit'],
'credit': accounts_res['credit'],
'balance': accounts_res['balance'],
'child_lines': accounts_res['lines']
})
return {
'doc_ids': docids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'Accounts': record,
'print_journal': codes,
}

115
base_accounting_kit/report/account_day_book_view.xml

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="day_book_report_template">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2><span t-esc="res_company.name"/>: Day Book Report
</h2>
<div class="row mt32" style="margin-bottom:3%;">
<div class="col-7">
<strong>Journals:</strong>
<p t-esc="', '.join([ lt or '' for lt in print_journal ])"/>
</div>
<div class="col-2">
<strong>Target Moves:</strong>
<p t-if="data['target_move'] == 'all'">All Entries</p>
<p t-if="data['target_move'] == 'posted'">All Posted Entries</p>
</div>
<div class="col-3">
<t t-if="data['date_from']">
<strong>Date from :</strong>
<span t-esc="data['date_from']"/>
<br/>
</t>
<t t-if="data['date_to']">
<strong>Date to :</strong>
<span t-esc="data['date_to']"/>
</t>
</div>
</div>
<table class="table table-condensed">
<thead>
<tr class="text-center">
<th>Date</th>
<th>JRNL</th>
<th>Partner</th>
<th>Ref</th>
<th>Move</th>
<th>Entry Label</th>
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th groups="base.group_multi_currency">Currency</th>
</tr>
</thead>
<tbody>
<t t-foreach="Accounts" t-as="account">
<tr style="font-weight: bold;background: #ededed;">
<td colspan="6">
<span style="color: white;" t-esc="'..'"/>
<span t-esc="account['date']"/>
</td>
<td class="text-right">
<span t-esc="account['debit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['credit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['balance']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td groups="base.group_multi_currency"/>
</tr>
<tr t-foreach="account['child_lines']" t-as="line">
<td>
<span t-esc="line['ldate']"/>
</td>
<td>
<span t-esc="line['lcode']"/>
</td>
<td>
<span t-esc="line['partner_name']"/>
</td>
<td>
<span t-if="line['lref']" t-esc="line['lref']"/>
</td>
<td>
<span t-esc="line['move_name']"/>
</td>
<td>
<span t-esc="line['lname']"/>
</td>
<td class="text-right">
<span t-esc="line['debit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['credit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['balance']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" groups="base.group_multi_currency">
<span t-esc="line['amount_currency'] if line['amount_currency'] > 0.00 else ''"/>
<span t-esc="line['currency_code'] if line['amount_currency'] > 0.00 else ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

39
base_accounting_kit/report/account_report_common_account.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models
class AccountCommonAccountReport(models.TransientModel):
_name = 'account.common.account.report'
_description = 'Account Common Account Report'
_inherit = "account.common.report"
display_account = fields.Selection(
[('all', 'All'), ('movement', 'With movements'),
('not_zero', 'With balance is not equal to 0'), ],
string='Display Accounts', required=True, default='movement')
@api.model
def pre_print_report(self, data):
data['form'].update(self.read(['display_account'])[0])
return data

216
base_accounting_kit/report/cash_flow_report.py

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportFinancial(models.AbstractModel):
_name = 'report.base_accounting_kit.report_cash_flow'
def _compute_account_balance(self, accounts):
mapping = {
'balance': "COALESCE(SUM(debit),0) - COALESCE(SUM(credit), 0) as balance",
'debit': "COALESCE(SUM(debit), 0) as debit",
'credit': "COALESCE(SUM(credit), 0) as credit",
}
res = {}
for account in accounts:
res[account.id] = dict.fromkeys(mapping, 0.0)
if accounts:
tables, where_clause, where_params = self.env[
'account.move.line']._query_get()
tables = tables.replace('"', '') if tables else "account_move_line"
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
request = "SELECT account_id as id, " + ', '.join(
mapping.values()) + \
" FROM " + tables + \
" WHERE account_id IN %s " \
+ filters + \
" GROUP BY account_id"
params = (tuple(accounts._ids),) + tuple(where_params)
self.env.cr.execute(request, params)
for row in self.env.cr.dictfetchall():
res[row['id']] = row
return res
def _compute_report_balance(self, reports):
res = {}
fields = ['credit', 'debit', 'balance']
for report in reports:
if report.id in res:
continue
res[report.id] = dict((fn, 0.0) for fn in fields)
if report.type == 'accounts':
# it's the sum of credit or debit
res2 = self._compute_report_balance(report.parent_id)
for key, value in res2.items():
cash_in_operation = self.env.ref(
'base_accounting_kit.cash_in_from_operation0')
cash_out_operation = self.env.ref(
'base_accounting_kit.cash_out_operation1')
cash_in_financial = self.env.ref(
'base_accounting_kit.cash_in_financial0')
cash_out_financial = self.env.ref(
'base_accounting_kit.cash_out_financial1')
cash_in_investing = self.env.ref(
'base_accounting_kit.cash_in_investing0')
cash_out_investing = self.env.ref(
'base_accounting_kit.cash_out_investing1')
if report == cash_in_operation or report == cash_in_financial or report == cash_in_investing:
res[report.id]['debit'] += value['debit']
res[report.id]['balance'] += value['debit']
elif report == cash_out_operation or report == cash_out_financial or report == cash_out_investing:
res[report.id]['credit'] += value['credit']
res[report.id]['balance'] += -(value['credit'])
elif report.type == 'account_type':
# it's the sum the leaf accounts with such an account type
accounts = self.env['account.account'].search(
[('user_type_id', 'in', report.account_type_ids.ids)])
res[report.id]['account'] = self._compute_account_balance(
accounts)
for value in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'account_report' and report.account_report_id:
# it's the amount of the linked
res[report.id]['account'] = self._compute_account_balance(
report.account_ids)
for value in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'sum':
# it's the sum of the linked accounts
res[report.id]['account'] = self._compute_account_balance(
report.account_ids)
for values in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += values.get(field)
return res
def get_account_lines(self, data):
lines = []
account_report = self.env['account.financial.report'].search(
[('id', '=', data['account_report_id'][0])])
child_reports = account_report._get_children_by_order()
res = self.with_context(
data.get('used_context'))._compute_report_balance(child_reports)
if data['enable_filter']:
comparison_res = self.with_context(
data.get('comparison_context'))._compute_report_balance(
child_reports)
for report_id, value in comparison_res.items():
res[report_id]['comp_bal'] = value['balance']
report_acc = res[report_id].get('account')
if report_acc:
for account_id, val in comparison_res[report_id].get(
'account').items():
report_acc[account_id]['comp_bal'] = val['balance']
for report in child_reports:
vals = {
'name': report.name,
'balance': res[report.id]['balance'] * int(report.sign),
'type': 'report',
'level': bool(report.style_overwrite) and int(
report.style_overwrite) or report.level,
'account_type': report.type or False,
# used to underline the financial report balances
}
if data['debit_credit']:
vals['debit'] = res[report.id]['debit']
vals['credit'] = res[report.id]['credit']
if data['enable_filter']:
vals['balance_cmp'] = res[report.id]['comp_bal'] * int(
report.sign)
lines.append(vals)
if report.display_detail == 'no_detail':
# the rest of the loop is used to display the details of the financial report, so it's not needed here.
continue
if res[report.id].get('account'):
# if res[report.id].get('debit'):
sub_lines = []
for account_id, value in res[report.id]['account'].items():
# if there are accounts to display, we add them to the lines with a level equals to their level in
# the COA + 1 (to avoid having them with a too low level that would conflicts with the level of data
# financial reports for Assets, liabilities...)
flag = False
account = self.env['account.account'].browse(account_id)
vals = {
'name': account.code + ' ' + account.name,
'balance': value['balance'] * int(report.sign) or 0.0,
'type': 'account',
'level': report.display_detail == 'detail_with_hierarchy' and 4,
'account_type': account.internal_type,
}
if data['debit_credit']:
vals['debit'] = value['debit']
vals['credit'] = value['credit']
if not account.company_id.currency_id.is_zero(
vals[
'debit']) or not account.company_id.currency_id.is_zero(
vals['credit']):
flag = True
if not account.company_id.currency_id.is_zero(
vals['balance']):
flag = True
if data['enable_filter']:
vals['balance_cmp'] = value['comp_bal'] * int(
report.sign)
if not account.company_id.currency_id.is_zero(
vals['balance_cmp']):
flag = True
if flag:
sub_lines.append(vals)
lines += sorted(sub_lines,
key=lambda sub_line: sub_line['name'])
return lines
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get(
'active_model') or not self.env.context.get('active_id'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(self.env.context.get('active_id'))
report_lines = self.get_account_lines(data.get('form'))
return {
'doc_ids': self.ids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'get_account_lines': report_lines,
}

108
base_accounting_kit/report/cash_flow_report.xml

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_cash_flow">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="web.internal_layout">
<div class="page">
<h2 t-esc="data['account_report_id'][1]"/>
<div class="row mt32 mb32">
<div class="col-4">
<strong>Target Moves:</strong>
<p>
<span t-if="data['target_move'] == 'all'">All Entries</span>
<span t-if="data['target_move'] == 'posted'">All Posted Entries</span>
</p>
</div>
<div class="col-4">
<p>
<strong>Date from :</strong> <span t-esc="data['date_from']"/><br/>
<strong>Date to :</strong> <span t-esc="data['date_to']"/>
</p>
</div>
</div>
<table class="table table-sm table-reports" t-if="data['debit_credit'] == 1">
<thead>
<tr>
<th><strong>Name</strong></th>
<th class="text-right"><strong>Debit</strong></th>
<th class="text-right"><strong>Credit</strong></th>
<th class="text-right"><strong>Balance</strong></th>
</tr>
</thead>
<tbody>
<tr t-foreach="get_account_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: normal;'"/></t>
<t t-if="not a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: bold;'"/></t>
<td>
<span style="color: white;" t-esc="'..' * a.get('level', 0)"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('debit')" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('credit')" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('balance')" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</t>
</tr>
</tbody>
</table>
<table class="table table-sm table-reports" t-if="not data['enable_filter'] and not data['debit_credit']">
<thead>
<tr>
<th><strong>Name</strong></th>
<th class="text-right"><strong>Balance</strong></th>
</tr>
</thead>
<tbody>
<tr t-foreach="get_account_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: normal;'"/></t>
<t t-if="not a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: bold;'"/></t>
<td>
<span style="color: white;" t-esc="'..' * a.get('level', 0)"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right"><span t-att-style="style" t-esc="a.get('balance')" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></td>
</t>
</tr>
</tbody>
</table>
<table class="table table-sm table-reports" t-if="data['enable_filter'] == 1 and not data['debit_credit']">
<thead>
<tr>
<th><strong>Name</strong></th>
<th class="text-right"><strong>Balance</strong></th>
<th class="text-right"><span t-esc="data['label_filter']"/></th>
</tr>
</thead>
<tbody>
<tr t-foreach="get_account_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: normal;'"/></t>
<t t-if="not a.get('level') &gt; 3"><t t-set="style" t-value="'font-weight: bold;'"/></t>
<td>
<span style="color: white;" t-esc="'..'"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right"><span t-att-style="style" t-esc="a.get('balance')" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></td>
<td class="text-right"><span t-att-style="style" t-esc="a.get('balance_cmp')"/></td>
</t>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</t>
</template>
</odoo>

171
base_accounting_kit/report/general_ledger_report.py

@ -0,0 +1,171 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportGeneralLedger(models.AbstractModel):
_name = 'report.base_accounting_kit.report_general_ledger'
def _get_account_move_entry(self, accounts, init_balance, sortby,
display_account):
"""
:param:
accounts: the recordset of accounts
init_balance: boolean value of initial_balance
sortby: sorting by date or partner and journal
display_account: type of account(receivable, payable and both)
Returns a dictionary of accounts with following key and value {
'code': account code,
'name': account name,
'debit': sum of total debit amount,
'credit': sum of total credit amount,
'balance': total balance,
'amount_currency': sum of amount_currency,
'move_lines': list of move line
}
"""
cr = self.env.cr
MoveLine = self.env['account.move.line']
move_lines = {x: [] for x in accounts.ids}
# Prepare initial sql query and Get the initial move lines
if init_balance:
init_tables, init_where_clause, init_where_params = MoveLine.with_context(
date_from=self.env.context.get('date_from'), date_to=False,
initial_bal=True)._query_get()
init_wheres = [""]
if init_where_clause.strip():
init_wheres.append(init_where_clause.strip())
init_filters = " AND ".join(init_wheres)
filters = init_filters.replace('account_move_line__move_id',
'm').replace('account_move_line',
'l')
sql = ("""SELECT 0 AS lid, l.account_id AS account_id, '' AS ldate, '' AS lcode, 0.0 AS amount_currency, '' AS lref, 'Initial Balance' AS lname, COALESCE(SUM(l.debit),0.0) AS debit, COALESCE(SUM(l.credit),0.0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance, '' AS lpartner_id,\
'' AS move_name, '' AS mmove_id, '' AS currency_code,\
NULL AS currency_id,\
'' AS invoice_id, '' AS invoice_type, '' AS invoice_number,\
'' AS partner_name\
FROM account_move_line l\
LEFT JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
LEFT JOIN account_move i ON (m.id =i.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
WHERE l.account_id IN %s""" + filters + ' GROUP BY l.account_id')
params = (tuple(accounts.ids),) + tuple(init_where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
move_lines[row.pop('account_id')].append(row)
sql_sort = 'l.date, l.move_id'
if sortby == 'sort_journal_partner':
sql_sort = 'j.code, p.name, l.move_id'
# Prepare sql query base on selected parameters from wizard
tables, where_clause, where_params = MoveLine._query_get()
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
filters = filters.replace('account_move_line__move_id', 'm').replace(
'account_move_line', 'l')
# Get move lines base on sql query and Calculate the total balance of move lines
sql = ('''SELECT l.id AS lid, l.account_id AS account_id, l.date AS ldate, j.code AS lcode, l.currency_id, l.amount_currency, l.ref AS lref, l.name AS lname, COALESCE(l.debit,0) AS debit, COALESCE(l.credit,0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,\
m.name AS move_name, c.symbol AS currency_code, p.name AS partner_name\
FROM account_move_line l\
JOIN account_move m ON (l.move_id=m.id)\
LEFT JOIN res_currency c ON (l.currency_id=c.id)\
LEFT JOIN res_partner p ON (l.partner_id=p.id)\
JOIN account_journal j ON (l.journal_id=j.id)\
JOIN account_account acc ON (l.account_id = acc.id) \
WHERE l.account_id IN %s ''' + filters + ''' GROUP BY l.id, l.account_id, l.date, j.code, l.currency_id, l.amount_currency, l.ref, l.name, m.name, c.symbol, p.name ORDER BY ''' + sql_sort)
params = (tuple(accounts.ids),) + tuple(where_params)
cr.execute(sql, params)
for row in cr.dictfetchall():
balance = 0
for line in move_lines.get(row['account_id']):
balance += line['debit'] - line['credit']
row['balance'] += balance
move_lines[row.pop('account_id')].append(row)
# Calculate the debit, credit and balance for Accounts
account_res = []
for account in accounts:
currency = account.currency_id and account.currency_id or account.company_id.currency_id
res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance'])
res['code'] = account.code
res['name'] = account.name
res['move_lines'] = move_lines[account.id]
for line in res.get('move_lines'):
res['debit'] += line['debit']
res['credit'] += line['credit']
res['balance'] = line['balance']
if display_account == 'all':
account_res.append(res)
if display_account == 'movement' and res.get('move_lines'):
account_res.append(res)
if display_account == 'not_zero' and not currency.is_zero(
res['balance']):
account_res.append(res)
return account_res
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get('active_model'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(
self.env.context.get('active_ids', []))
init_balance = data['form'].get('initial_balance', True)
sortby = data['form'].get('sortby', 'sort_date')
display_account = data['form']['display_account']
codes = []
if data['form'].get('journal_ids', False):
codes = [journal.code for journal in
self.env['account.journal'].search(
[('id', 'in', data['form']['journal_ids'])])]
accounts = docs if self.model == 'account.account' else self.env[
'account.account'].search([])
accounts_res = self.with_context(
data['form'].get('used_context', {}))._get_account_move_entry(
accounts, init_balance, sortby, display_account)
return {
'doc_ids': docids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'Accounts': accounts_res,
'print_journal': codes,
}

105
base_accounting_kit/report/general_ledger_report.xml

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_general_ledger">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2><span t-esc="res_company.name"/>: General ledger</h2>
<div class="row mt32">
<div class="col-4">
<strong>Journals:</strong>
<p t-esc="', '.join([ lt or '' for lt in print_journal ])"/>
</div>
<div class="col-4">
<strong>Display Account</strong>
<p>
<span t-if="data['display_account'] == 'all'">All accounts'</span>
<span t-if="data['display_account'] == 'movement'">With movements</span>
<span t-if="data['display_account'] == 'not_zero'">With balance not equal to zero</span>
</p>
</div>
<div class="col-4">
<strong>Target Moves:</strong>
<p t-if="data['target_move'] == 'all'">All Entries</p>
<p t-if="data['target_move'] == 'posted'">All Posted Entries</p>
</div>
</div>
<div class="row mb32">
<div class="col-4">
<strong>Sorted By:</strong>
<p t-if="data['sortby'] == 'sort_date'">Date</p>
<p t-if="data['sortby'] == 'sort_journal_partner'">Journal and Partner</p>
</div>
<div class="col-4">
<t t-if="data['date_from']"><strong>Date from :</strong> <span t-esc="data['date_from']"/><br/></t>
<t t-if="data['date_to']"><strong>Date to :</strong> <span t-esc="data['date_to']"/></t>
</div>
</div>
<table class="table table-sm table-reports">
<thead>
<tr class="text-center">
<th>Date</th>
<th>JRNL</th>
<th>Partner</th>
<th>Ref</th>
<th>Move</th>
<th>Entry Label</th>
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th groups="base.group_multi_currency">Currency</th>
</tr>
</thead>
<tbody>
<t t-foreach="Accounts" t-as="account">
<tr style="font-weight: bold;">
<td colspan="6">
<span style="color: white;" t-esc="'..'"/>
<span t-esc="account['code']"/>
<span t-esc="account['name']"/>
</td>
<td class="text-right">
<span t-esc="account['debit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td groups="base.group_multi_currency"/>
</tr>
<tr t-foreach="account['move_lines']" t-as="line">
<td><span t-esc="line['ldate']"/></td>
<td><span t-esc="line['lcode']"/></td>
<td><span t-esc="line['partner_name']"/></td>
<td><span t-if="line['lref']" t-esc="line['lref']"/></td>
<td><span t-esc="line['move_name']"/></td>
<td><span t-esc="line['lname']"/></td>
<td class="text-right">
<span t-esc="line['debit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['credit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['balance']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" groups="base.group_multi_currency">
<span t-esc="line['amount_currency'] if line['amount_currency'] > 0.00 else ''"/>
<span t-esc="line['currency_code'] if line['amount_currency'] > 0.00 else ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

112
base_accounting_kit/report/report.xml

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- # Financial report -->
<report
id="financial_report_pdf"
model="financial.report"
string="Financial reports"
report_type="qweb-pdf"
name="base_accounting_kit.report_financial"
file="base_accounting_kit.report_financial"
/>
<!-- # General ledger report -->
<report
id="action_report_general_ledger"
model="account.report.general.ledger"
string="General Ledger"
report_type="qweb-pdf"
name="base_accounting_kit.report_general_ledger"
file="base_accounting_kit.report_general_ledger"
/>
<!-- # Partner ledger report -->
<report
id="action_report_partnerledger"
model="account.report.partner.ledger"
string="Partner Ledger"
report_type="qweb-pdf"
name="base_accounting_kit.report_partnerledger"
file="base_accounting_kit.report_partnerledger"
/>
<!-- # Ageing report -->
<report
id="action_report_aged_partner_balance"
model="res.partner"
string="Aged Partner Balance"
menu="False"
report_type="qweb-pdf"
name="base_accounting_kit.report_agedpartnerbalance"
file="base_accounting_kit.report_agedpartnerbalance"
/>
<!-- # Journal audit report -->
<report
id="action_report_journal"
model="account.common.journal.report"
string="Journals Audit"
report_type="qweb-pdf"
name="base_accounting_kit.report_journal_audit"
file="base_accounting_kit.report_journal_audit"
/>
<!-- # Tax report -->
<report
id="action_report_account_tax"
model="account.tax.report"
string="Tax Report"
report_type="qweb-pdf"
name="base_accounting_kit.report_tax"
file="base_accounting_kit.report_tax"
/>
<!-- # Trial balance report -->
<report
id="action_report_trial_balance"
model="account.balance.report"
string="Trial Balance"
report_type="qweb-pdf"
name="base_accounting_kit.report_trial_balance"
file="base_accounting_kit.report_trial_balance"
/>
<!-- # CAsh flow statements -->
<report
id="action_report_cash_flow"
model="account.financial.report"
string="Cash Flow Statement"
menu="False"
report_type="qweb-pdf"
name="base_accounting_kit.report_cash_flow"
file="base_accounting_kit.report_cash_flow"
/>
<!-- # Accounting Bank Book Report -->
<report
id="action_report_bank_book"
model="account.bank.book.report"
string="Bank Book Report"
print_report_name="Bank Book Report"
report_type="qweb-pdf"
name="base_accounting_kit.report_bank_book"
file="base_accounting_kit.report_bank_book"
attachment_use="False"
/>
<!-- # Accounting Cash Book Report -->
<report
id="action_report_cash_book"
model="account.cash.book.report"
string="Cash Book Report"
print_report_name="Cash Book Report"
report_type="qweb-pdf"
name="base_accounting_kit.report_cash_book"
file="base_accounting_kit.report_cash_book"
attachment_use="False"
/>
<!-- # Accounting Day Book Report -->
<report
id="day_book_pdf_report"
model="account.day.book.report"
string="Day Book PDF Report"
report_type="qweb-pdf"
name="base_accounting_kit.day_book_report_template"
file="base_accounting_kit.day_book_report_template"
attachment_use="True"
/>
</odoo>

302
base_accounting_kit/report/report_aged_partner.py

@ -0,0 +1,302 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, models, _
from odoo.exceptions import UserError
from odoo.tools import float_is_zero
class ReportAgedPartnerBalance(models.AbstractModel):
_name = 'report.base_accounting_kit.report_agedpartnerbalance'
def _get_partner_move_lines(self, account_type, date_from, target_move,
period_length):
# This method can receive the context key 'include_nullified_amount' {Boolean}
# Do an invoice and a payment and unreconcile. The amount will be nullified
# By default, the partner wouldn't appear in this report.
# The context key allow it to appear
# In case of a period_length of 30 days as of 2019-02-08, we want the following periods:
# Name Stop Start
# 1 - 30 : 2019-02-07 - 2019-01-09
# 31 - 60 : 2019-01-08 - 2018-12-10
# 61 - 90 : 2018-12-09 - 2018-11-10
# 91 - 120 : 2018-11-09 - 2018-10-11
# +120 : 2018-10-10
periods = {}
start = datetime.strptime(date_from, "%Y-%m-%d")
date_from = datetime.strptime(date_from, "%Y-%m-%d").date()
for i in range(5)[::-1]:
stop = start - relativedelta(days=period_length)
period_name = str((5 - (i + 1)) * period_length + 1) + '-' + str(
(5 - i) * period_length)
period_stop = (start - relativedelta(days=1)).strftime('%Y-%m-%d')
if i == 0:
period_name = '+' + str(4 * period_length)
periods[str(i)] = {
'name': period_name,
'stop': period_stop,
'start': (i != 0 and stop.strftime('%Y-%m-%d') or False),
}
start = stop
res = []
total = []
cr = self.env.cr
user_company = self.env.user.company_id
user_currency = user_company.currency_id
ResCurrency = self.env['res.currency'].with_context(date=date_from)
company_ids = self._context.get('company_ids') or [user_company.id]
move_state = ['draft', 'posted']
if target_move == 'posted':
move_state = ['posted']
arg_list = (tuple(move_state), tuple(account_type))
# build the reconciliation clause to see what partner needs to be printed
reconciliation_clause = '(l.reconciled IS FALSE)'
cr.execute(
'SELECT debit_move_id, credit_move_id FROM account_partial_reconcile where max_date > %s',
(date_from,))
reconciled_after_date = []
for row in cr.fetchall():
reconciled_after_date += [row[0], row[1]]
if reconciled_after_date:
reconciliation_clause = '(l.reconciled IS FALSE OR l.id IN %s)'
arg_list += (tuple(reconciled_after_date),)
arg_list += (date_from, tuple(company_ids))
query = '''
SELECT DISTINCT l.partner_id, UPPER(res_partner.name)
FROM account_move_line AS l left join res_partner on l.partner_id = res_partner.id, account_account, account_move am
WHERE (l.account_id = account_account.id)
AND (l.move_id = am.id)
AND (am.state IN %s)
AND (account_account.internal_type IN %s)
AND ''' + reconciliation_clause + '''
AND (l.date <= %s)
AND l.company_id IN %s
ORDER BY UPPER(res_partner.name)'''
cr.execute(query, arg_list)
partners = cr.dictfetchall()
# put a total of 0
for i in range(7):
total.append(0)
# Build a string like (1,2,3) for easy use in SQL query
partner_ids = [partner['partner_id'] for partner in partners if
partner['partner_id']]
lines = dict(
(partner['partner_id'] or False, []) for partner in partners)
if not partner_ids:
return [], [], {}
# This dictionary will store the not due amount of all partners
undue_amounts = {}
query = '''SELECT l.id
FROM account_move_line AS l, account_account, account_move am
WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)
AND (am.state IN %s)
AND (account_account.internal_type IN %s)
AND (COALESCE(l.date_maturity,l.date) >= %s)\
AND ((l.partner_id IN %s) OR (l.partner_id IS NULL))
AND (l.date <= %s)
AND l.company_id IN %s'''
cr.execute(query, (
tuple(move_state), tuple(account_type), date_from,
tuple(partner_ids), date_from, tuple(company_ids)))
aml_ids = cr.fetchall()
aml_ids = aml_ids and [x[0] for x in aml_ids] or []
for line in self.env['account.move.line'].browse(aml_ids):
partner_id = line.partner_id.id or False
if partner_id not in undue_amounts:
undue_amounts[partner_id] = 0.0
line_amount = ResCurrency._compute(line.company_id.currency_id,
user_currency, line.balance)
if user_currency.is_zero(line_amount):
continue
for partial_line in line.matched_debit_ids:
if partial_line.max_date <= date_from:
line_amount += ResCurrency._compute(
partial_line.company_id.currency_id, user_currency,
partial_line.amount)
for partial_line in line.matched_credit_ids:
if partial_line.max_date <= date_from:
line_amount -= ResCurrency._compute(
partial_line.company_id.currency_id, user_currency,
partial_line.amount)
if not self.env.user.company_id.currency_id.is_zero(line_amount):
undue_amounts[partner_id] += line_amount
lines[partner_id].append({
'line': line,
'amount': line_amount,
'period': 6,
})
# Use one query per period and store results in history (a list variable)
# Each history will contain: history[1] = {'<partner_id>': <partner_debit-credit>}
history = []
for i in range(5):
args_list = (
tuple(move_state), tuple(account_type), tuple(partner_ids),)
dates_query = '(COALESCE(l.date_maturity,l.date)'
if periods[str(i)]['start'] and periods[str(i)]['stop']:
dates_query += ' BETWEEN %s AND %s)'
args_list += (
periods[str(i)]['start'], periods[str(i)]['stop'])
elif periods[str(i)]['start']:
dates_query += ' >= %s)'
args_list += (periods[str(i)]['start'],)
else:
dates_query += ' <= %s)'
args_list += (periods[str(i)]['stop'],)
args_list += (date_from, tuple(company_ids))
query = '''SELECT l.id
FROM account_move_line AS l, account_account, account_move am
WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)
AND (am.state IN %s)
AND (account_account.internal_type IN %s)
AND ((l.partner_id IN %s) OR (l.partner_id IS NULL))
AND ''' + dates_query + '''
AND (l.date <= %s)
AND l.company_id IN %s'''
cr.execute(query, args_list)
partners_amount = {}
aml_ids = cr.fetchall()
aml_ids = aml_ids and [x[0] for x in aml_ids] or []
for line in self.env['account.move.line'].browse(aml_ids):
partner_id = line.partner_id.id or False
if partner_id not in partners_amount:
partners_amount[partner_id] = 0.0
line_amount = ResCurrency._compute(line.company_id.currency_id,
user_currency, line.balance)
if user_currency.is_zero(line_amount):
continue
for partial_line in line.matched_debit_ids:
if partial_line.max_date <= date_from:
line_amount += ResCurrency._compute(
partial_line.company_id.currency_id, user_currency,
partial_line.amount)
for partial_line in line.matched_credit_ids:
if partial_line.max_date <= date_from:
line_amount -= ResCurrency._compute(
partial_line.company_id.currency_id, user_currency,
partial_line.amount)
if not self.env.user.company_id.currency_id.is_zero(
line_amount):
partners_amount[partner_id] += line_amount
lines[partner_id].append({
'line': line,
'amount': line_amount,
'period': i + 1,
})
history.append(partners_amount)
for partner in partners:
if partner['partner_id'] is None:
partner['partner_id'] = False
at_least_one_amount = False
values = {}
undue_amt = 0.0
if partner[
'partner_id'] in undue_amounts: # Making sure this partner actually was found by the query
undue_amt = undue_amounts[partner['partner_id']]
total[6] = total[6] + undue_amt
values['direction'] = undue_amt
if not float_is_zero(values['direction'],
precision_rounding=self.env.user.company_id.currency_id.rounding):
at_least_one_amount = True
for i in range(5):
during = False
if partner['partner_id'] in history[i]:
during = [history[i][partner['partner_id']]]
# Adding counter
total[(i)] = total[(i)] + (during and during[0] or 0)
values[str(i)] = during and during[0] or 0.0
if not float_is_zero(values[str(i)],
precision_rounding=self.env.user.company_id.currency_id.rounding):
at_least_one_amount = True
values['total'] = sum(
[values['direction']] + [values[str(i)] for i in range(5)])
## Add for total
total[(i + 1)] += values['total']
values['partner_id'] = partner['partner_id']
if partner['partner_id']:
browsed_partner = self.env['res.partner'].browse(
partner['partner_id'])
values['name'] = browsed_partner.name and len(
browsed_partner.name) >= 45 and browsed_partner.name[
0:40] + '...' or browsed_partner.name
values['trust'] = browsed_partner.trust
else:
values['name'] = _('Unknown Partner')
values['trust'] = False
if at_least_one_amount or (
self._context.get('include_nullified_amount') and lines[
partner['partner_id']]):
res.append(values)
return res, total, lines
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get(
'active_model') or not self.env.context.get('active_id'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
total = []
model = self.env.context.get('active_model')
docs = self.env[model].browse(self.env.context.get('active_id'))
target_move = data['form'].get('target_move', 'all')
date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d'))
if data['form']['result_selection'] == 'customer':
account_type = ['receivable']
elif data['form']['result_selection'] == 'supplier':
account_type = ['payable']
else:
account_type = ['payable', 'receivable']
movelines, total, dummy = self._get_partner_move_lines(account_type,
date_from,
target_move,
data['form'][
'period_length'])
return {
'doc_ids': self.ids,
'doc_model': model,
'data': data['form'],
'docs': docs,
'time': time,
'get_partner_lines': movelines,
'get_direction': total,
}

98
base_accounting_kit/report/report_aged_partner.xml

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_agedpartnerbalance">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2>Aged Partner Balance</h2>
<div class="row mt32">
<div class="col-3">
<strong>Start Date:</strong>
<p t-esc="data['date_from']"/>
</div>
<div class="col-3">
<strong>Period Length (days)</strong>
<p t-esc="data['period_length']"/>
</div>
</div>
<div class="row mb32">
<div class="col-3">
<strong>Partner's:</strong>
<p>
<span t-if="data['result_selection'] == 'customer'">Receivable Accounts</span>
<span t-if="data['result_selection'] == 'supplier'">Payable Accounts</span>
<span t-if="data['result_selection'] == 'customer_supplier'">Receivable and Payable Accounts</span>
</p>
</div>
<div class="col-3">
<strong>Target Moves:</strong>
<p>
<span t-if="data['target_move'] == 'all'">All Entries</span>
<span t-if="data['target_move'] == 'posted'">All Posted Entries</span>
</p>
</div>
</div>
<table class="table table-sm table-reports">
<thead>
<tr>
<th>Partners</th>
<th class="text-right">
<span>Not due</span>
</th>
<th class="text-right"><span t-esc="data['4']['name']"/></th>
<th class="text-right"><span t-esc="data['3']['name']"/></th>
<th class="text-right"><span t-esc="data['2']['name']"/></th>
<th class="text-right"><span t-esc="data['1']['name']"/></th>
<th class="text-right"><span t-esc="data['0']['name']"/></th>
<th class="text-right">Total</th>
</tr>
<tr t-if="get_partner_lines">
<th>Account Total</th>
<th class="text-right"><span t-esc="get_direction[6]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[4]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[3]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[2]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[1]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[0]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
<th class="text-right"><span t-esc="get_direction[5]" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></th>
</tr>
</thead>
<tbody>
<tr t-foreach="get_partner_lines" t-as="partner">
<td>
<span t-esc="partner['name']"/>
</td>
<td class="text-right">
<span t-esc="partner['direction']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['4']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['3']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['2']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['1']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['0']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="partner['total']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

119
base_accounting_kit/report/report_financial.py

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models
# ---------------------------------------------------------
# Account Financial Report
# ---------------------------------------------------------
class AccountFinancialReport(models.Model):
_name = "account.financial.report"
_description = "Account Report"
_rec_name = 'name'
@api.depends('parent_id', 'parent_id.level')
def _get_level(self):
"""Returns a dictionary with key=the ID of a record and
value = the level of this
record in the tree structure."""
for report in self:
level = 0
if report.parent_id:
level = report.parent_id.level + 1
report.level = level
def _get_children_by_order(self):
"""returns a recordset of all the children computed recursively,
and sorted by sequence. Ready for the printing"""
res = self
children = self.search([('parent_id', 'in', self.ids)],
order='sequence ASC')
if children:
for child in children:
res += child._get_children_by_order()
return res
name = fields.Char('Report Name', required=True, translate=True)
parent_id = fields.Many2one('account.financial.report', 'Parent')
children_ids = fields.One2many(
'account.financial.report',
'parent_id',
'Account Report')
sequence = fields.Integer('Sequence')
level = fields.Integer(compute='_get_level', string='Level', store=True)
type = fields.Selection(
[('sum', 'View'),
('accounts', 'Accounts'),
('account_type', 'Account Type'),
('account_report', 'Report Value')],
'Type',
default='sum')
account_ids = fields.Many2many(
'account.account',
'account_account_financial_report',
'report_line_id',
'account_id',
'Accounts')
account_report_id = fields.Many2one(
'account.financial.report',
'Report Value')
account_type_ids = fields.Many2many(
'account.account.type',
'account_account_financial_report_type',
'report_id', 'account_type_id',
'Account Types')
sign = fields.Selection(
[("1", 'Reverse balance sign'), ("-1", 'Preserve balance sign')],
'Sign on Reports', required=True, default="1",
help='For accounts that are typically more'
' debited than credited and that you'
' would like to print as negative'
' amounts in your reports, you should'
' reverse the sign of the balance;'
' e.g.: Expense account. The same applies'
' for accounts that are typically more'
' credited than debited and that you would'
' like to print as positive amounts in'
' your reports; e.g.: Income account.')
display_detail = fields.Selection(
[('no_detail', 'No detail'),
('detail_flat', 'Display children flat'),
('detail_with_hierarchy', 'Display children with hierarchy')],
'Display details',
default='detail_flat')
style_overwrite = fields.Selection(
[('0', 'Automatic formatting'),
('1', 'Main Title 1 (bold, underlined)'),
('2', 'Title 2 (bold)'),
('3', 'Title 3 (bold, smaller)'),
('4', 'Normal Text'),
('5', 'Italic Text (smaller)'),
('6', 'Smallest Text')],
'Financial Report Style',
default='0',
help="You can set up here the format you want this"
" record to be displayed. If you leave the"
" automatic formatting, it will be computed"
" based on the financial reports hierarchy "
"(auto-computed field 'level').")

146
base_accounting_kit/report/report_financial.xml

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template id="report_financial">
<t t-call="web.html_container">
<t t-call="web.internal_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">
<h2 t-esc="data['form']['account_report_id'][1]"/>
<div class="row mt32 mb32">
<div class="col-4">
<strong>Target Moves:</strong>
<p>
<span t-if="data['form']['target_move'] == 'all'">All Entries</span>
<span t-if="data['form']['target_move'] == 'posted'">All Posted Entries</span>
</p>
</div>
<div class="col-4">
<p>
<t t-if="data['form']['date_from']">
<strong>Date from :</strong>
<span t-esc="data['form']['date_from']"/>
<br/>
</t>
<t t-if="data['form']['date_to']">
<strong>Date to :</strong>
<span t-esc="data['form']['date_to']"/>
</t>
</p>
</div>
</div>
<table class="table table-sm table-reports" t-if="data['form']['debit_credit'] == 1">
<thead>
<tr>
<th>Name</th>
<th class="text-right">Debit</th>
<th class="text-right">Credit</th>
<th class="text-right">Balance</th>
</tr>
</thead>
<tbody>
<tr t-foreach="report_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: normal;'"/>
</t>
<t t-if="not a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: bold;'"/>
</t>
<td>
<span style="color: white;" t-esc="'..' * a.get('level', 0)"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('debit')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('credit')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" style="white-space: text-nowrap;">
<span t-att-style="style" t-esc="a.get('balance')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</t>
</tr>
</tbody>
</table>
<table class="table table-sm table-reports"
t-if="not data['form']['enable_filter'] and not data['form']['debit_credit']">
<thead>
<tr>
<th>Name</th>
<th class="text-right">Balance</th>
</tr>
</thead>
<tbody>
<tr t-foreach="report_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: normal;'"/>
</t>
<t t-if="not a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: bold;'"/>
</t>
<td>
<span style="color: white;" t-esc="'..' * a.get('level', 0)"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="a.get('balance')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</t>
</tr>
</tbody>
</table>
<table class="table table-sm table-reports"
t-if="data['form']['enable_filter'] == 1 and not data['form']['debit_credit']">
<thead>
<tr>
<th>Name</th>
<th class="text-right">Balance</th>
<th class="text-right">
<!-- <span t-esc="data['form']['label_filter']"/>-->
<span>Comp</span>
</th>
</tr>
</thead>
<tbody>
<tr t-foreach="report_lines" t-as="a">
<t t-if="a['level'] != 0">
<t t-if="a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: normal;'"/>
</t>
<t t-if="not a.get('level') &gt; 3">
<t t-set="style" t-value="'font-weight: bold;'"/>
</t>
<td>
<span style="color: white;" t-esc="'..'"/>
<span t-att-style="style" t-esc="a.get('name')"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="a.get('balance')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="a.get('balance_cmp')"/>
</td>
</t>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

158
base_accounting_kit/report/report_journal_audit.py

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportJournal(models.AbstractModel):
_name = 'report.base_accounting_kit.report_journal_audit'
def lines(self, target_move, journal_ids, sort_selection, data):
if isinstance(journal_ids, int):
journal_ids = [journal_ids]
move_state = ['draft', 'posted']
if target_move == 'posted':
move_state = ['posted']
query_get_clause = self._get_query_get_clause(data)
params = [tuple(move_state), tuple(journal_ids)] + query_get_clause[2]
query = 'SELECT "account_move_line".id FROM ' + query_get_clause[
0] + ', account_move am, account_account acc WHERE "account_move_line".account_id = acc.id AND "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + \
query_get_clause[1] + ' ORDER BY '
if sort_selection == 'date':
query += '"account_move_line".date'
else:
query += 'am.name'
query += ', "account_move_line".move_id, acc.code'
self.env.cr.execute(query, tuple(params))
ids = (x[0] for x in self.env.cr.fetchall())
return self.env['account.move.line'].browse(ids)
def _sum_debit(self, data, journal_id):
move_state = ['draft', 'posted']
if data['form'].get('target_move', 'all') == 'posted':
move_state = ['posted']
query_get_clause = self._get_query_get_clause(data)
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[
2]
self.env.cr.execute('SELECT SUM(debit) FROM ' + query_get_clause[
0] + ', account_move am '
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' +
query_get_clause[1] + ' ',
tuple(params))
return self.env.cr.fetchone()[0] or 0.0
def _sum_credit(self, data, journal_id):
move_state = ['draft', 'posted']
if data['form'].get('target_move', 'all') == 'posted':
move_state = ['posted']
query_get_clause = self._get_query_get_clause(data)
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[
2]
self.env.cr.execute('SELECT SUM(credit) FROM ' + query_get_clause[
0] + ', account_move am '
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' +
query_get_clause[1] + ' ',
tuple(params))
return self.env.cr.fetchone()[0] or 0.0
def _get_taxes(self, data, journal_id):
move_state = ['draft', 'posted']
if data['form'].get('target_move', 'all') == 'posted':
move_state = ['posted']
query_get_clause = self._get_query_get_clause(data)
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[
2]
query = """
SELECT rel.account_tax_id, SUM("account_move_line".balance) AS base_amount
FROM account_move_line_account_tax_rel rel, """ + query_get_clause[
0] + """
LEFT JOIN account_move am ON "account_move_line".move_id = am.id
WHERE "account_move_line".id = rel.account_move_line_id
AND am.state IN %s
AND "account_move_line".journal_id IN %s
AND """ + query_get_clause[1] + """
GROUP BY rel.account_tax_id"""
self.env.cr.execute(query, tuple(params))
ids = []
base_amounts = {}
for row in self.env.cr.fetchall():
ids.append(row[0])
base_amounts[row[0]] = row[1]
res = {}
for tax in self.env['account.tax'].browse(ids):
self.env.cr.execute(
'SELECT sum(debit - credit) FROM ' + query_get_clause[
0] + ', account_move am '
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' +
query_get_clause[1] + ' AND tax_line_id = %s',
tuple(params + [tax.id]))
res[tax] = {
'base_amount': base_amounts[tax.id],
'tax_amount': self.env.cr.fetchone()[0] or 0.0,
}
if journal_id.type == 'sale':
# sales operation are credits
res[tax]['base_amount'] = res[tax]['base_amount'] * -1
res[tax]['tax_amount'] = res[tax]['tax_amount'] * -1
return res
def _get_query_get_clause(self, data):
return self.env['account.move.line'].with_context(
data['form'].get('used_context', {}))._query_get()
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
target_move = data['form'].get('target_move', 'all')
sort_selection = data['form'].get('sort_selection', 'date')
res = {}
for journal in data['form']['journal_ids']:
res[journal] = self.with_context(
data['form'].get('used_context', {})).lines(target_move,
journal,
sort_selection,
data)
return {
'doc_ids': data['form']['journal_ids'],
'doc_model': self.env['account.journal'],
'data': data,
'docs': self.env['account.journal'].browse(
data['form']['journal_ids']),
'time': time,
'lines': res,
'sum_credit': self._sum_credit,
'sum_debit': self._sum_debit,
'get_taxes': self._get_taxes,
}

150
base_accounting_kit/report/report_journal_audit.xml

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="report_journal_audit">
<t t-call="web.html_container">
<t t-call="web.internal_layout">
<t t-foreach="docs" t-as="o">
<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">
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
<h2>
<t t-esc="o.name"/>
Journal
</h2>
<div class="row mt32">
<div class="col-3">
<strong>Company:</strong>
<p t-esc="res_company.name"/>
</div>
<div class="col-3">
<strong>Journal:</strong>
<p t-esc="o.name"/>
</div>
<div class="col-3">
<strong>Entries Sorted By:</strong>
<p t-if="data['form'].get('sort_selection') != 'l.date'">Journal Entry Number</p>
<p t-if="data['form'].get('sort_selection') == 'l.date'">Date</p>
</div>
<div class="col-3">
<strong>Target Moves:</strong>
<p t-if="data['form']['target_move'] == 'all'">All Entries</p>
<p t-if="data['form']['target_move'] == 'posted'">All Posted Entries</p>
</div>
</div>
<table class="table table-sm">
<thead>
<tr>
<th>Move</th>
<th>Date</th>
<th>Account</th>
<th>Partner</th>
<th>Label</th>
<th>Debit</th>
<th>Credit</th>
<th t-if="data['form']['amount_currency']">Currency</th>
</tr>
</thead>
<tbody>
<tr t-foreach="lines[o.id]" t-as="aml">
<td>
<span t-esc="aml.move_id.name != '/' and aml.move_id.name or ('*'+str(aml.move_id.id))"/>
</td>
<td>
<span t-field="aml.date"/>
</td>
<td>
<span t-field="aml.account_id.code"/>
</td>
<td>
<span t-esc="aml.sudo().partner_id and aml.sudo().partner_id.name and aml.sudo().partner_id.name[:23] or ''"/>
</td>
<td>
<span t-esc="aml.name and aml.name[:35]"/>
</td>
<td>
<span t-esc="aml.debit"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td>
<span t-esc="aml.credit"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td t-if="data['form']['amount_currency'] and aml.amount_currency">
<span t-esc="aml.amount_currency"
t-options="{'widget': 'monetary', 'display_currency': aml.currency_id}"/>
</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-4 pull-right">
<table class="table table-sm">
<tr>
<td>
<strong>Total</strong>
</td>
<td>
<span t-esc="sum_debit(data, o)"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td>
<span t-esc="sum_credit(data, o)"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
</table>
</div>
</div>
<div class="row">
<div class="col-4">
<table class="table table-sm table-reports">
<thead>
<tr>
<th colspan="3">Tax Declaration</th>
</tr>
<tr>
<th>Name</th>
<th>Base Amount</th>
<th>Tax Amount</th>
</tr>
</thead>
<tbody>
<t t-set="taxes" t-value="get_taxes(data, o)"/>
<tr t-foreach="taxes" t-as="tax">
<td>
<span t-esc="tax.name"/>
</td>
<td>
<span t-esc="taxes[tax]['base_amount']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td>
<span t-esc="taxes[tax]['tax_amount']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p style="page-break-after: always;"/>
</div>
</t>
</t>
</t>
</template>
</data>
</odoo>

155
base_accounting_kit/report/report_partner_ledger.py

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportPartnerLedger(models.AbstractModel):
_name = 'report.base_accounting_kit.report_partnerledger'
def _lines(self, data, partner):
full_account = []
currency = self.env['res.currency']
query_get_data = self.env['account.move.line'].with_context(
data['form'].get('used_context', {}))._query_get()
reconcile_clause = "" if data['form'][
'reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
params = [partner.id, tuple(data['computed']['move_state']),
tuple(data['computed']['account_ids'])] + \
query_get_data[2]
query = """
SELECT "account_move_line".id, "account_move_line".date, j.code, acc.code as a_code, acc.name as a_name, "account_move_line".ref, m.name as move_name, "account_move_line".name, "account_move_line".debit, "account_move_line".credit, "account_move_line".amount_currency,"account_move_line".currency_id, c.symbol AS currency_code
FROM """ + query_get_data[0] + """
LEFT JOIN account_journal j ON ("account_move_line".journal_id = j.id)
LEFT JOIN account_account acc ON ("account_move_line".account_id = acc.id)
LEFT JOIN res_currency c ON ("account_move_line".currency_id=c.id)
LEFT JOIN account_move m ON (m.id="account_move_line".move_id)
WHERE "account_move_line".partner_id = %s
AND m.state IN %s
AND "account_move_line".account_id IN %s AND """ + \
query_get_data[1] + reconcile_clause + """
ORDER BY "account_move_line".date"""
self.env.cr.execute(query, tuple(params))
res = self.env.cr.dictfetchall()
sum = 0.0
lang_code = self.env.context.get('lang') or 'en_US'
lang = self.env['res.lang']
lang_id = lang._lang_get(lang_code)
date_format = lang_id.date_format
for r in res:
r['date'] = r['date']
r['displayed_name'] = '-'.join(
r[field_name] for field_name in ('move_name', 'ref', 'name')
if r[field_name] not in (None, '', '/')
)
sum += r['debit'] - r['credit']
r['progress'] = sum
r['currency_id'] = currency.browse(r.get('currency_id'))
full_account.append(r)
return full_account
def _sum_partner(self, data, partner, field):
if field not in ['debit', 'credit', 'debit - credit']:
return
result = 0.0
query_get_data = self.env['account.move.line'].with_context(
data['form'].get('used_context', {}))._query_get()
reconcile_clause = "" if data['form'][
'reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
params = [partner.id, tuple(data['computed']['move_state']),
tuple(data['computed']['account_ids'])] + \
query_get_data[2]
query = """SELECT sum(""" + field + """)
FROM """ + query_get_data[0] + """, account_move AS m
WHERE "account_move_line".partner_id = %s
AND m.id = "account_move_line".move_id
AND m.state IN %s
AND account_id IN %s
AND """ + query_get_data[1] + reconcile_clause
self.env.cr.execute(query, tuple(params))
contemp = self.env.cr.fetchone()
if contemp is not None:
result = contemp[0] or 0.0
return result
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
data['computed'] = {}
obj_partner = self.env['res.partner']
query_get_data = self.env['account.move.line'].with_context(
data['form'].get('used_context', {}))._query_get()
data['computed']['move_state'] = ['draft', 'posted']
if data['form'].get('target_move', 'all') == 'posted':
data['computed']['move_state'] = ['posted']
result_selection = data['form'].get('result_selection', 'customer')
if result_selection == 'supplier':
data['computed']['ACCOUNT_TYPE'] = ['payable']
elif result_selection == 'customer':
data['computed']['ACCOUNT_TYPE'] = ['receivable']
else:
data['computed']['ACCOUNT_TYPE'] = ['payable', 'receivable']
self.env.cr.execute("""
SELECT a.id
FROM account_account a
WHERE a.internal_type IN %s
AND NOT a.deprecated""",
(tuple(data['computed']['ACCOUNT_TYPE']),))
data['computed']['account_ids'] = [a for (a,) in
self.env.cr.fetchall()]
params = [tuple(data['computed']['move_state']),
tuple(data['computed']['account_ids'])] + query_get_data[2]
reconcile_clause = "" if data['form'][
'reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
query = """
SELECT DISTINCT "account_move_line".partner_id
FROM """ + query_get_data[0] + """, account_account AS account, account_move AS am
WHERE "account_move_line".partner_id IS NOT NULL
AND "account_move_line".account_id = account.id
AND am.id = "account_move_line".move_id
AND am.state IN %s
AND "account_move_line".account_id IN %s
AND NOT account.deprecated
AND """ + query_get_data[1] + reconcile_clause
self.env.cr.execute(query, tuple(params))
partner_ids = [res['partner_id'] for res in self.env.cr.dictfetchall()]
partners = obj_partner.browse(partner_ids)
partners = sorted(partners, key=lambda x: (x.ref or '', x.name or ''))
return {
'doc_ids': partner_ids,
'doc_model': self.env['res.partner'],
'data': data,
'docs': partners,
'time': time,
'lines': self._lines,
'sum_partner': self._sum_partner,
}

107
base_accounting_kit/report/report_partner_ledger.xml

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_partnerledger">
<t t-call="web.html_container">
<t t-call="web.internal_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">
<h2>Partner Ledger</h2>
<div class="row">
<div class="col-3">
<strong>Company:</strong>
<p t-esc="res_company.name"/>
</div>
<div class="col-3">
<t t-if="data['form']['date_from']">
<strong>Date from :</strong>
<span t-esc="data['form']['date_from']"/>
<br/>
</t>
<t t-if="data['form']['date_to']">
<strong>Date to :</strong>
<span t-esc="data['form']['date_to']"/>
</t>
</div>
<div class="col-3">
<strong>Target Moves:</strong>
<p t-if="data['form']['target_move'] == 'all'">All Entries</p>
<p t-if="data['form']['target_move'] == 'posted'">All Posted Entries</p>
</div>
</div>
<table class="table table-sm table-reports">
<thead>
<tr>
<th>Date</th>
<th>JRNL</th>
<th>Account</th>
<th>Ref</th>
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th t-if="data['form']['amount_currency']">Currency</th>
</tr>
</thead>
<t t-foreach="docs" t-as="o">
<tbody>
<tr>
<td colspan="4">
<strong t-esc="o.ref"/>
-
<strong t-esc="o.name"/>
</td>
<td class="text-right">
<strong t-esc="sum_partner(data, o, 'debit')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<strong t-esc="sum_partner(data, o, 'credit')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<strong t-esc="sum_partner(data, o, 'debit - credit')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
<tr t-foreach="lines(data, o)" t-as="line">
<td>
<span t-esc="line['date']"/>
</td>
<td>
<span t-esc="line['code']"/>
</td>
<td>
<span t-esc="line['a_code']"/>
</td>
<td>
<span t-esc="line['displayed_name']"/>
</td>
<td class="text-right">
<span t-esc="line['debit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['credit']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-esc="line['progress']"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right" t-if="data['form']['amount_currency']">
<t t-if="line['currency_id']">
<span t-esc="line['amount_currency']"
t-options="{'widget': 'monetary', 'display_currency': line['currency_id']}"/>
</t>
</td>
</tr>
</tbody>
</t>
</table>
</div>
</t>
</t>
</template>
</odoo>

114
base_accounting_kit/report/report_tax.py

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from _datetime import datetime
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportTax(models.AbstractModel):
_name = 'report.base_accounting_kit.report_tax'
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
return {
'data': data['form'],
'lines': self.get_lines(data.get('form')),
}
def _sql_from_amls_one(self):
sql = """SELECT "account_move_line".tax_line_id, COALESCE(SUM("account_move_line".debit-"account_move_line".credit), 0)
FROM %s
WHERE %s AND "account_move_line".tax_exigible GROUP BY "account_move_line".tax_line_id"""
return sql
def _sql_from_amls_two(self):
sql = """SELECT r.account_tax_id, COALESCE(SUM("account_move_line".debit-"account_move_line".credit), 0)
FROM %s
INNER JOIN account_move_line_account_tax_rel r ON ("account_move_line".id = r.account_move_line_id)
INNER JOIN account_tax t ON (r.account_tax_id = t.id)
WHERE %s AND "account_move_line".tax_exigible GROUP BY r.account_tax_id"""
return sql
def _compute_from_amls(self, options, taxes):
# compute the tax amount
sql = self._sql_from_amls_one()
tables, where_clause, where_params = self.env[
'account.move.line']._query_get()
query = sql % (tables, where_clause)
self.env.cr.execute(query, where_params)
results = self.env.cr.fetchall()
for result in results:
if result[0] in taxes:
taxes[result[0]]['tax'] = abs(result[1])
# compute the net amount
sql2 = self._sql_from_amls_two()
query = sql2 % (tables, where_clause)
self.env.cr.execute(query, where_params)
results = self.env.cr.fetchall()
for result in results:
if result[0] in taxes:
taxes[result[0]]['net'] = abs(result[1])
@api.model
def get_lines(self, options):
taxes = {}
for tax in self.env['account.tax'].search(
[('type_tax_use', '!=', 'none')]):
if tax.children_tax_ids:
for child in tax.children_tax_ids:
if child.type_tax_use != 'none':
continue
taxes[child.id] = {'tax': 0, 'net': 0, 'name': child.name,
'type': tax.type_tax_use}
else:
taxes[tax.id] = {'tax': 0, 'net': 0, 'name': tax.name,
'type': tax.type_tax_use}
if options['date_from']:
self.with_context(date_from=options['date_from'],
strict_range=True)._compute_from_amls(options,
taxes)
elif options['date_to']:
self.with_context(date_to=options['date_to'],
strict_range=True)._compute_from_amls(options,
taxes)
elif options['date_from'] and options['date_to']:
self.with_context(date_from=options['date_from'],
date_to=options['date_to'],
strict_range=True)._compute_from_amls(options,
taxes)
else:
date_to = str(datetime.today().date())
self.with_context(date_to=date_to,
strict_range=True)._compute_from_amls(options,
taxes)
groups = dict((tp, []) for tp in ['sale', 'purchase'])
for tax in taxes.values():
if tax['tax']:
groups[tax['type']].append(tax)
return groups

75
base_accounting_kit/report/report_tax.xml

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_tax">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h3>Tax Report</h3>
<div class="row">
<div class="col-3">
<strong>Company:</strong>
<p t-esc="res_company.name"/>
</div>
<div>
<t t-if="data['date_from']">
<strong>Date from :</strong>
<span t-esc="data['date_from']"/>
</t>
<br/>
<t t-if="data['date_to']">
<strong>Date to :</strong>
<span t-esc="data['date_to']"/>
</t>
</div>
</div>
<table class="table table-sm table-reports">
<thead>
<tr align="left">
<th>Sale</th>
<th>Net</th>
<th>Tax</th>
</tr>
</thead>
<tr align="left" t-foreach="lines['sale']" t-as="line">
<td>
<span t-esc="line.get('name')"/>
</td>
<td>
<span t-att-style="style" t-esc="line.get('net')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td>
<span t-att-style="style" t-esc="line.get('tax')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
<br/>
<tr align="left">
<td>
<strong>Purchase</strong>
</td>
<td></td>
<td></td>
</tr>
<tr align="left" t-foreach="lines['purchase']" t-as="line">
<td>
<span t-esc="line.get('name')"/>
</td>
<td>
<span t-att-style="style" t-esc="line.get('net')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td>
<span t-att-style="style" t-esc="line.get('tax')"
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
</table>
</div>
</t>
</t>
</template>
</odoo>

108
base_accounting_kit/report/report_trial_balance.py

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportTrialBalance(models.AbstractModel):
_name = 'report.base_accounting_kit.report_trial_balance'
def _get_accounts(self, accounts, display_account):
""" compute the balance, debit and credit for the provided accounts
:Arguments:
`accounts`: list of accounts record,
`display_account`: it's used to display either all accounts or those accounts which balance is > 0
:Returns a list of dictionary of Accounts with following key and value
`name`: Account name,
`code`: Account code,
`credit`: total amount of credit,
`debit`: total amount of debit,
`balance`: total amount of balance,
"""
account_result = {}
# Prepare sql query base on selected parameters from wizard
tables, where_clause, where_params = self.env[
'account.move.line']._query_get()
tables = tables.replace('"', '')
if not tables:
tables = 'account_move_line'
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
# compute the balance, debit and credit for the provided accounts
request = (
"SELECT account_id AS id, SUM(debit) AS debit, SUM(credit) AS credit, (SUM(debit) - SUM(credit)) AS balance" + \
" FROM " + tables + " WHERE account_id IN %s " + filters + " GROUP BY account_id")
params = (tuple(accounts.ids),) + tuple(where_params)
self.env.cr.execute(request, params)
for row in self.env.cr.dictfetchall():
account_result[row.pop('id')] = row
account_res = []
for account in accounts:
res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance'])
currency = account.currency_id and account.currency_id or account.company_id.currency_id
res['code'] = account.code
res['name'] = account.name
if account.id in account_result:
res['debit'] = account_result[account.id].get('debit')
res['credit'] = account_result[account.id].get('credit')
res['balance'] = account_result[account.id].get('balance')
if display_account == 'all':
account_res.append(res)
if display_account == 'not_zero' and not currency.is_zero(
res['balance']):
account_res.append(res)
if display_account == 'movement' and (
not currency.is_zero(res['debit']) or not currency.is_zero(
res['credit'])):
account_res.append(res)
return account_res
@api.model
def _get_report_values(self, docids, data=None):
if not data.get('form') or not self.env.context.get('active_model'):
raise UserError(
_("Form content is missing, this report cannot be printed."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(
self.env.context.get('active_ids', []))
display_account = data['form'].get('display_account')
accounts = docs if self.model == 'account.account' else self.env[
'account.account'].search([])
account_res = self.with_context(
data['form'].get('used_context'))._get_accounts(accounts,
display_account)
return {
'doc_ids': self.ids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'Accounts': account_res,
}

71
base_accounting_kit/report/report_trial_balance.xml

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_trial_balance">
<t t-call="web.html_container">
<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"/>
<t t-call="web.internal_layout">
<div class="page">
<h2><span t-esc="res_company.name"/>: Trial Balance</h2>
<div class="row mt32">
<div class="col-4">
<strong>Display Account:</strong>
<p>
<span t-if="data['display_account'] == 'all'">All accounts</span>
<span t-if="data['display_account'] == 'movement'">With movements</span>
<span t-if="data['display_account'] == 'not_zero'">With balance not equal to zero</span>
</p>
</div>
<div class="col-4">
<p>
<t t-if="data['date_from']"><strong>Date from :</strong> <span t-esc="data['date_from']"/><br/></t>
<t t-if="data['date_to']"><strong>Date to :</strong> <span t-esc="data['date_to']"/></t>
</p>
</div>
<div class="col-4">
<strong>Target Moves:</strong>
<p>
<span t-if="data['target_move'] == 'all'">All Entries</span>
<span t-if="data['target_move'] == 'posted'">All Posted Entries</span>
</p>
</div>
</div>
<table class="table table-sm table-reports">
<thead>
<tr>
<th>Code</th>
<th>Account</th>
<th class="text-right">Debit</th>
<th class="text-right">Credit</th>
<th class="text-right">Balance</th>
</tr>
</thead>
<tbody>
<tr t-foreach="Accounts" t-as="account">
<td>
<span t-att-style="style" t-esc="account['code']"/>
</td>
<td>
<span style="color: white;" t-esc="'..'"/>
<span t-att-style="style" t-esc="account['name']"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="account['debit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td class="text-right">
<span t-att-style="style" t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>

26
base_accounting_kit/security/account_asset_security.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="account_asset_category_multi_company_rule" model="ir.rule">
<field name="name">Account Asset Category multi-company</field>
<field ref="model_account_asset_category" name="model_id"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="account_asset_asset_multi_company_rule" model="ir.rule">
<field name="name">Account Asset multi-company</field>
<field ref="model_account_asset_asset" name="model_id"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="account.group_account_user" model="res.groups">
<field name="name">Accountant</field>
<field name="implied_ids" eval="[(4, ref('account.group_account_invoice'))]"/>
<!-- <field name="category_id" ref="base.module_category_accounting_invoicing"/>-->
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>

21
base_accounting_kit/security/ir.model.access.csv

@ -0,0 +1,21 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_financial_report_user,account_fin_rep_name_user,model_account_financial_report,account.group_account_user,1,1,1,1
access_financial_report_manager,account_fin_rep_name_manager,model_account_financial_report,account.group_account_manager,1,1,1,1
access_account_report_general_ledger_user,account_account_report_general_ledger_id_user,model_account_report_general_ledger,account.group_account_user,1,1,1,1
access_account_report_general_ledger_manager,account_account_report_general_ledger_id_manager,model_account_report_general_ledger,account.group_account_manager,1,1,1,1
access_generate_recurring_entries,generate.recurring.entries.user,model_account_recurring_payments,account.group_account_user,1,1,1,1
access_generate_recurring_entries_wizard,generate.recurring.entries.user.wizard,model_recurring_payments_wizard,account.group_account_user,1,1,1,1
access_account_followup,account.followup,model_account_followup,account.group_account_manager,1,1,1,1
access_followup_line,followup.line,model_followup_line,account.group_account_manager,1,1,0,0
access_account_asset_category,account.asset.category,model_account_asset_category,account.group_account_user,1,0,0,0
access_account_asset_asset,account.asset.asset,model_account_asset_asset,account.group_account_user,1,0,0,0
access_account_asset_category_manager,account.asset.category,model_account_asset_category,account.group_account_manager,1,1,1,1
access_account_asset_asset_manager,account.asset.asset,model_account_asset_asset,account.group_account_manager,1,1,1,1
access_account_asset_depreciation_line,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_user,1,0,0,0
access_account_asset_depreciation_line_manager,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_manager,1,1,1,1
access_asset_asset_report,asset.asset.report,model_asset_asset_report,account.group_account_user,1,0,0,0
access_asset_asset_report_manager,asset.asset.report,model_asset_asset_report,account.group_account_manager,1,1,1,1
access_account_asset_category_invoicing_payment,account.asset.category,model_account_asset_category,account.group_account_invoice,1,0,0,0
access_account_asset_asset_invoicing_payment,account.asset.asset,model_account_asset_asset,account.group_account_invoice,1,0,1,0
access_account_asset_depreciation_line_invoicing_payment,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_invoice,1,0,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_financial_report_user account_fin_rep_name_user model_account_financial_report account.group_account_user 1 1 1 1
3 access_financial_report_manager account_fin_rep_name_manager model_account_financial_report account.group_account_manager 1 1 1 1
4 access_account_report_general_ledger_user account_account_report_general_ledger_id_user model_account_report_general_ledger account.group_account_user 1 1 1 1
5 access_account_report_general_ledger_manager account_account_report_general_ledger_id_manager model_account_report_general_ledger account.group_account_manager 1 1 1 1
6 access_generate_recurring_entries generate.recurring.entries.user model_account_recurring_payments account.group_account_user 1 1 1 1
7 access_generate_recurring_entries_wizard generate.recurring.entries.user.wizard model_recurring_payments_wizard account.group_account_user 1 1 1 1
8 access_account_followup account.followup model_account_followup account.group_account_manager 1 1 1 1
9 access_followup_line followup.line model_followup_line account.group_account_manager 1 1 0 0
10 access_account_asset_category account.asset.category model_account_asset_category account.group_account_user 1 0 0 0
11 access_account_asset_asset account.asset.asset model_account_asset_asset account.group_account_user 1 0 0 0
12 access_account_asset_category_manager account.asset.category model_account_asset_category account.group_account_manager 1 1 1 1
13 access_account_asset_asset_manager account.asset.asset model_account_asset_asset account.group_account_manager 1 1 1 1
14 access_account_asset_depreciation_line account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_user 1 0 0 0
15 access_account_asset_depreciation_line_manager account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_manager 1 1 1 1
16 access_asset_asset_report asset.asset.report model_asset_asset_report account.group_account_user 1 0 0 0
17 access_asset_asset_report_manager asset.asset.report model_asset_asset_report account.group_account_manager 1 1 1 1
18 access_account_asset_category_invoicing_payment account.asset.category model_account_asset_category account.group_account_invoice 1 0 0 0
19 access_account_asset_asset_invoicing_payment account.asset.asset model_account_asset_asset account.group_account_invoice 1 0 1 0
20 access_account_asset_depreciation_line_invoicing_payment account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_invoice 1 0 1 0

BIN
base_accounting_kit/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
base_accounting_kit/static/description/cybro_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
base_accounting_kit/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
base_accounting_kit/static/description/images/account_dynamic_report_banner.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

BIN
base_accounting_kit/static/description/images/accounting_kit_window.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

BIN
base_accounting_kit/static/description/images/checked.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
base_accounting_kit/static/description/images/crm_dashboard_banner.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
base_accounting_kit/static/description/images/cybrosys.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
base_accounting_kit/static/description/images/mobile_service_shop_pro_banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
base_accounting_kit/static/description/images/odoo11_magento_banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
base_accounting_kit/static/description/images/project_custome_gantt_banner.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

BIN
base_accounting_kit/static/description/images/report_maker_banner.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

464
base_accounting_kit/static/description/index.html

@ -0,0 +1,464 @@
<div class="row"
style="margin: 0;position: relative;color: #000;background-position: center;background: #ffffff;border-bottom: 1px solid #e4e4e4;text-align: center; margin: auto; display: flex;justify-content: center;">
<a href="https://www.cybrosys.com/" target="_blank"><img src="images/cybrosys.png"
style=" width: 293px; padding: 1rem 0rem; margin: auto"
alt="cybrosys-logo"></a></div>
<div class="row"
style="margin:75px 0;position: relative;color: #000;background-position: center;background: #ffffff;border-bottom: 1px solid #e4e4e4; padding-bottom: 30px;">
<div class="col-md-7 col-sm-12 col-xs-12" style="padding: 0px">
<div style=" margin: 0 0 0px;padding: 20px 0 10;font-size: 23px;line-height: 35px;font-weight: 400;color: #000;border-top: 1px solid rgba(255,255,255,0.1);border-bottom: 1px solid rgba(255,255,255,0.11);text-align: left;">
<h1 style="font-size: 39px;font-weight: 600;margin: 0px !important;">Odoo 13 Accounting</h1>
<h3 style="font-size: 21px;margin-top: 8px;position: relative;">A complete accounting kit for Odoo 13.</h3>
</div>
<h2 style="font-weight: 600;font-size: 1.8rem;margin-top: 15px;">Key Highlights</h2>
<ul style=" padding: 0 1px; list-style: none; ">
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Asset management.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
PDC management.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Accounting lock dates.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Customer credit limit.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Recurring payments.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Day book, Bank book and Cash book reports.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Customer follow up.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Financial reports.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Trial balance report.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Journal audit report.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Cash flow statements.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Partner ledger.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Aged partner balance.
</li>
<li style="display: flex;align-items: center;padding: 8px 0;font-size: 18px;">
<img src="images/checked.png" style=" width: 22px; margin-right: 6px; " alt="check">
Tax reports.
</li>
</ul>
</div>
<div class="col-md-5 col-sm-12 col-xs-12"><img src="images/accounting_kit_window.png" class="img-responsive" alt="">
</div>
</div>
<div>
<section class="oe_container" style="padding: 1rem 0rem 1rem; background-color: #ffffff !important;">
<div class="row py-4 px-3">
<div class="w-100" style="padding-top:30px;padding-bottom:45px;border-radius: 10px;">
<ul role="tablist" class="nav nav-pills justify-content-center" data-tabs="tabs" id="pills-tab"
style="border: none;background: unset;">
<li class="nav-item mr-1 mb-3"
style="font-size: 1.05rem;font-weight: 400;transition: all .15s ease;color: #d31c22;background-color: #d31c22;box-shadow: 0 4px 6px rgba(50,50,93,.11), 0 1px 3px rgba(0,0,0,.08);border: 0;font-family: 'Open Sans',sans-serif;width: 140px;border-radius: 0.30rem;">
<a id="pills-home-tab1" data-toggle="pill" href="#pills-home"
role="tab" aria-controls="pills-home" aria-selected="true"
class="nav-link active show"
style="color: #000000;line-height: 33px;border: 0;border-radius: .25rem;font-weight: 400;">Overview </a>
</li>
</ul>
<div class="tab-content" id="pills-tabContent"
style="padding-top: 30px; padding-bottom: 30px; padding: 30px;">
<div class="px-3 pt-1 tab-pane fade active show" id="pills-home" role="tabpanel" aria-labelledby="
pills-home-tab">
<!-- Overview-->
<h2 style="font-weight: 600;text-align: center;width: 100%;">Overview</h2>
<hr style="margin-top: 0px;margin-bottom: 2%;border: 0;text-align: center;border-top: 3px solid #d21c22;width: 5%;">
<h3 class="oe_slogan"
style="text-align: center;font-size: 19px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 31px;font-weight: 400;letter-spacing: .5px;margin-bottom: 21px;">
This Module will bring back the accounting features such as Account Reports, Asset Management
and Customer Follow Up into Odoo 13 Community Edition. Also new features are added to the
accounting module such as Customer Credit Limit, Recurring Payment, PDC Management and Lock Dates
are introduced into Odoo 13 Community Edition.
</h3>
</div>
<!-- faq tab-->
<div class="px-2 px-lg-4 pt-3 tab-pane fade" id="pills-contact" role="tabpanel"
aria-labelledby="pills-contact-tab">
<ul class="list-unstyled"></ul>
</div>
</div>
</div>
</div>
</section>
<section class="oe_container" style="padding: 2rem 3rem 1rem;">
<h2 style="font-weight: 600;text-align: center;margin-bottom: 25px;width: 100%;">Suggested Products</h2>
<hr style="margin-top: 0px;margin-bottom: 2%;border: 0;text-align: center;border-top: 3px solid #d21c22;width: 5%;">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height: 0px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/11.0/mobile_service_shop_pro/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/mobile_service_shop_pro_banner.jpg"></div>
</a></div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/12.0/crm_dashboard/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/crm_dashboard_banner.gif"></div>
</a></div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/12.0/accounting_dynamic_reports/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/account_dynamic_report_banner.gif"></div>
</a></div>
</div>
<div class="carousel-item" style="min-height: 0px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/11.0/odoo11_magento2/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/odoo11_magento_banner.jpg"></div>
</a></div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/12.0/project_custom_gantt/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/project_custome_gantt_banner.gif"></div>
</a></div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;"><a
href="https://apps.odoo.com/apps/modules/12.0/report_maker/" target="_blank">
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
<img class="img img-responsive center-block"
style="border-top-left-radius: 10px;border-top-right-radius: 10px;"
src="images/report_maker_banner.gif"></div>
</a></div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="left:-25px;width: 35px;color: #000;"> <span class="carousel-control-prev-icon"><i
class="fa fa-chevron-left" style="font-size:24px"></i></span> </a> <a class="carousel-control-next"
href="#demo1"
data-slide="next"
style="right:-25px;width: 35px;color: #000;">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span>
</a></div>
</section>
<section class="row" style="padding: 2rem 3rem 1rem;margin:0px">
<h2 style="font-weight: 600;margin-bottom: 20px;text-align: center;width: 100%;">Our Service</h2>
<hr style="margin-top: 0px;margin-bottom: 2%;border: 0;text-align: center;border-top: 3px solid #d21c22;width: 5%;">
<div class="row" style=" display: flex; justify-content: center; flex-wrap: wrap;width: 100%; ">
<!-- <div style="display:flex;padding-top: 20px;justify-content: space-between;"> -->
<div class="col-md-2 col-sm-6 col-xs-12">
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"><a
href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-customization.png"
style="width: 100%;border-radius: 100%;"/> </a></div>
<h3 class="oe_slogan"
style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;">
<a href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Odoo Customization </a></h3>
</div>
<div class="col-md-2 col-sm-6 col-xs-12">
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"><a
href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-erp-implementation.png"
style="width: 100%;border-radius: 100%;"/> </a></div>
<h3 class="oe_slogan"
style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;">
<a href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Odoo Implementation </a></h3>
</div>
<div class="col-md-2 col-sm-6 col-xs-12">
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"><a
href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-erp-integration.png"
style="width: 100%;border-radius: 100%;"/> </a></div>
<h3 class="oe_slogan"
style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;">
<a href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Odoo Integration </a></h3>
</div>
<div class="col-md-2 col-sm-6 col-xs-12">
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"><a
href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-erp-support.png"
style="width: 100%;border-radius: 100%;"/> </a></div>
<h3 class="oe_slogan"
style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;">
<a href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Odoo Support</a></h3>
</div>
<div class="col-md-2 col-sm-6 col-xs-12">
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"><a
href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"> <img
src="https://www.cybrosys.com/images/hire-odoo-developer.png"
style="width: 100%;border-radius: 100%;"/> </a></div>
<h3 class="oe_slogan"
style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;">
<a href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Hire Odoo Developers</a></h3>
<!-- </a> -->
</div>
<!-- </div> -->
</div>
</section>
<section class="row" style="padding: 2rem 3rem 1rem;margin:0px">
<div class="row" style="margin: 0">
<h2 style="font-weight: 600;margin-bottom: 20px;text-align: center;width: 100%;">Our Industries</h2>
<hr style="margin-top: 0px;margin-bottom: 2%;border: 0;text-align: center;border-top: 3px solid #d21c22;width: 5%;">
<!-- <div style="display:flex;justify-content: space-between;flex-wrap:wrap;"> -->
<div class="row" style="width: 100%">
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-index-industry-1.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"
style="list-style: none; color:#000; text-decoration: none;font-family: 'Montserrat',sans-serif;">
Trading </a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px; font-family: 'Montserrat',sans-serif;">
Easily procure and sell your products. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/"
target="_blank"> <img src="https://www.cybrosys.com/images/odoo-index-industry-2.png"
alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/>
</a></div>
</div>
<div style="width:70%;float:left;margin-bottom: 10px;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/"
target="_blank"
style="list-style: none; color:#000; text-decoration: none;font-family: 'Montserrat',sans-serif;">
Manufacturing</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;font-family: 'Montserrat',sans-serif;">
Plan, track and schedule your operations. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank">
<img src="https://www.cybrosys.com/images/odoo-index-industry-3.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank"
style="list-style: none; color:#000; text-decoration: none;font-family: 'Montserrat',sans-serif;">
Restaurant</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;font-family: 'Montserrat',sans-serif;">
Run your bar or restaurant methodical. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-index-industry-4.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"
style="list-style: none; color:#000; text-decoration: none;font-family: 'Montserrat',sans-serif;">
POS</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;font-family: 'Montserrat',sans-serif;">
Easy configuring and convivial selling. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-index-industry-5.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 0px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
E-commerce & Website</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px; font-family: 'Montserrat',sans-serif;">
Mobile friendly, awe-inspiring product pages. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank">
<img src="https://www.cybrosys.com/images/odoo-index-industry-6.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Hotel Management</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px; font-family: 'Montserrat',sans-serif;">
An all-inclusive hotel management application. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank">
<img src="https://www.cybrosys.com/images/odoo-index-industry-7.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Education</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px; font-family: 'Montserrat',sans-serif;">
A Collaborative platform for educational management. </h3>
</div>
</div>
<div class="col-md-4 col-sm-6 col-xs-12" style=" margin-bottom: 10px; ">
<div>
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;">
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"> <img
src="https://www.cybrosys.com/images/odoo-index-industry-8.png" alt="Odoo Industry"
style=" border-radius: 100%;width:100%;"/> </a></div>
</div>
<div style="width:70%;float:left;">
<h3 class="oe_slogan"
style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;">
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"
style="list-style: none; color:#000; text-decoration: none; font-family: 'Montserrat',sans-serif;">
Service Management</a></h3>
<h3 class="oe_slogan"
style=" text-align: left;font-size: 12px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px; font-family: 'Montserrat',sans-serif;">
Keep track of services and invoice accordingly. </h3>
</div>
</div>
</div>
</div>
<!-- </div>-->
</section>
<section class="oe_container" style="padding: 0% 0% 6% 0%;">
<center>
<div class="col-md-12" style="margin: auto !important;
width: 70%;
padding: 30px;">
<h2 style="font-weight: 600;text-align: center;width: 100%;">Need Any Help?</h2>
<hr style="margin-top: 0px;margin-bottom: 2%;border: 0;text-align: center;border-top: 3px solid #d21c22;width: 5%;">
<h4 style="font-size:16px;"> If you have anything to share with us based on your use of this module,
please let us know. We are ready to offer our support. </h4>
<div class="col-md-6" style="float:left; padding:20px;">
<h4><i class="fa fa-envelope"></i>Email us </h4>
<p>odoo@cybrosys.com / info@cybrosys.com</p>
</div>
<div class="col-md-6" style="float:left; padding:20px;">
<h4><i class="fa fa-phone"></i> Contact Us </h4>
<a href="https://www.cybrosys.com/contact/" target="_blank"> www.cybrosys.com</a>
</div>
</div>
</center>
</section>
<section class="oe_container" style="padding: 0% 0% 6% 0%;">
<div class="oe_slogan" style="margin-bottom: 0px;">
<div style=" display: flex; justify-content: center; flex-wrap: wrap; ">
</div>
<br>
<img src="https://www.cybrosys.com/images/logo.png"
style="width: 190px; margin-bottom: 25px;margin-top: 30px;" class="center-block">
<div style=" display: flex; justify-content: center; flex-wrap: wrap; "><a
href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter"
style="color:white;background: #00a0d1;width:35px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a>
<!-- </td>-->
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i
class="fa fa-2x fa-linkedin"
style="color:white;background: #31a3d6;width:35px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a>
<!-- </td>-->
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook"
style="color:white;background: #3b5998;width:35px; height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a>
<!-- </td>-->
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest"
style="color:white;background: #ac0f18;width:35px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a>
<!-- </td>-->
</div>
</div>
</section>
</div>

9
base_accounting_kit/views/account_asset_templates.xml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="account assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" type="text/scss" href="/om_account_asset/static/src/scss/account_asset.scss"/>
<script type="text/javascript" src="/om_account_asset/static/src/js/account_asset.js"/>
</xpath>
</template>
</odoo>

363
base_accounting_kit/views/account_asset_views.xml

@ -0,0 +1,363 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="view_account_asset_category_form">
<field name="name">account.asset.category.form</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<form string="Asset category">
<sheet>
<group>
<div class="oe_title">
<label for="name" string="Asset Type" class="oe_edit_only" attrs="{'invisible': [('type','!=','purchase')]}"/>
<label for="name" string="Deferred Revenue Type" class="oe_edit_only" attrs="{'invisible': [('type','==','purchase')]}"/>
<h1>
<field name="name" placeholder="e.g. Computers"/>
</h1>
</div>
<group>
<field name="type" attrs="{'invisible': 1}"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
<group string="Journal Entries">
<field name="journal_id"/>
<div>
<label for="account_asset_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_asset_id" string="Deferred Revenue Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_asset_id" nolabel="1" attrs="{'invisible': [('type','=', False)]}"/>
<div>
<label for="account_depreciation_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_depreciation_id" string="Recognition Income Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_depreciation_id" nolabel="1"/>
<div>
<label for="account_depreciation_expense_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_depreciation_expense_id" string="Recognition Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_depreciation_expense_id" nolabel="1"/>
<field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</group>
<group string="Periodicity">
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
<field name="method_number" string="Number of Entries" attrs="{'invisible':['|',('method_time','!=','number'),'&amp;',('type','=', False)], 'required':[('method_time','=','number')]}"/>
<label for="method_period" string="One Entry Every"/>
<div>
<field name="method_period" nolabel="1" attrs="{'invisible': [('type','=', False)]}" class="oe_inline"/>
months
</div>
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','!=','end')]}"/>
</group>
<group string="Additional Options">
<field name="open_asset"/>
<field name="group_entries"/>
<field name="date_first_depreciation"/>
</group>
<group attrs="{'invisible': [('type','=','sale')]}" string="Depreciation Method">
<field name="method" widget="radio"/>
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_account_asset_asset_category_kanban" model="ir.ui.view">
<field name="name">account.asset.category.kanban</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<field name="name"/>
<field name="journal_id"/>
<field name="method"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="row mb4">
<div class="col-6">
<strong><span><t t-esc="record.name.value"/></span></strong>
</div>
<div class="col-6 text-right">
<span class="badge badge-pill"><strong><t t-esc="record.method.value"/></strong></span>
</div>
</div>
<div> <t t-esc="record.journal_id.value"/></div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_category_tree">
<field name="name">account.asset.category.tree</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<tree string="Asset category">
<field name="name"/>
<field name="journal_id"/>
<field name="method"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_category_search">
<field name="name">account.asset.category.search</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<search string="Search Asset Category">
<filter string="Sales" name="sales" domain="[('type','=', 'sale')]" help="Deferred Revenues"/>
<filter string="Purchase" name="purchase" domain="[('type','=', 'purchase')]" help="Assets"/>
<field name="name" string="Category"/>
<field name="journal_id"/>
<group expand="0" string="Group By...">
<filter string="Type" name="type" domain="[]" context="{'group_by':'type'}"/>
</group>
</search>
</field>
</record>
<record id="view_account_asset_asset_form" model="ir.ui.view">
<field name="name">account_asset_asset_form</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<form string="Asset">
<header>
<button name="validate" states="draft" string="Confirm" type="object" class="oe_highlight"/>
<button type="object" name="compute_depreciation_board" string="Compute Depreciation" states="draft"/>
<button name="set_to_close" states="open" string="Sell or Dispose" type="object" class="oe_highlight"/>
<button name="set_to_draft" string="Set to Draft" type="object" attrs="{'invisible': ['|', ('entry_count', '!=', 0), ('state', '!=', 'open')]}"/>
<button name="%(action_asset_modify)d" states="open" string="Modify Depreciation" type="action"/>
<field name="state" widget="statusbar" statusbar_visible="draft,open"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" name="open_entries" type="object" icon="fa-pencil">
<field string="Items" name="entry_count" widget="statinfo" />
</button>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" placeholder="e.g. Laptop iBook"/>
</h1>
</div>
<group>
<group>
<field name="category_id" string="Asset Category" domain="[('type', '=', 'purchase')]" context="{'default_type': 'purchase'}" help="Category of asset"/>
<field name="code"/>
<field name="date" help="Date of asset"/>
<field name="date_first_depreciation"/>
<field name="first_depreciation_manual_date"
attrs="{'invisible': [('date_first_depreciation', '!=', 'manual')], 'required': [('date_first_depreciation', '=', 'manual')]}"/>
<field name="type" invisible="1"/>
<field name="account_analytic_id" groups="analytic.group_analytic_accounting" />
</group>
<group>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="value" widget="monetary" options="{'currency_field': 'currency_id'}" help="Gross value of asset"/>
<field name="salvage_value" widget="monetary" options="{'currency_field': 'currency_id'}" attrs="{'invisible': [('type','=','sale')]}"/>
<field name="value_residual" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="partner_id" string="Vendor" domain="[('supplier', '=', True)]"/>
<field name="invoice_id" string="Invoice" options="{'no_create': True}"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</group>
</group>
<notebook colspan="4">
<page string="Depreciation Board">
<field name="depreciation_line_ids" mode="tree" options="{'reload_whole_on_button': true}">
<tree string="Depreciation Lines" decoration-info="(move_check == False)" create="false">
<field name="depreciation_date"/>
<field name="amount" widget="monetary" string="Depreciation"/>
<field name="depreciated_value" readonly="1"/>
<field name="remaining_value" readonly="1" widget="monetary" string="Residual"/>
<field name="move_check" widget="deprec_lines_toggler" attrs="{'invisible': [('parent_state', '!=', 'open')]}"/>
<field name="move_posted_check" invisible="1"/>
<field name="parent_state" invisible="1"/>
</tree>
<form string="Depreciation Lines" create="false">
<group>
<group>
<field name="parent_state" invisible="1"/>
<field name="name"/>
<field name="sequence"/>
<field name="move_id"/>
<field name="move_check"/>
<field name="parent_state" invisible="1"/>
</group>
<group>
<field name="amount" widget="monetary"/>
<field name="depreciation_date"/>
<field name="depreciated_value"/>
<field name="remaining_value"/>
</group>
</group>
</form>
</field>
</page>
<page string="Depreciation Information">
<group>
<field name="method" widget="radio" attrs="{'invisible': [('type','=','sale')]}"/>
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
</group>
<group>
<field name="method_number" attrs="{'invisible':[('method_time','=','end')], 'required':[('method_time','=','number')]}"/>
<field name="method_period"/>
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','=','number')]}"/>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="view_account_asset_asset_kanban" model="ir.ui.view">
<field name="name">account.asset.asset.kanban</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<field name="name"/>
<field name="category_id"/>
<field name="date"/>
<field name="state"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="row mb4">
<div class="col-6">
<strong><span><t t-esc="record.name.value"/></span></strong>
</div>
<div class="col-6 text-right">
<strong><t t-esc="record.date.value"/></strong>
</div>
</div>
<div class="row">
<div class="col-6 text-muted">
<span><t t-esc="record.category_id.value"/></span>
</div>
<div class="col-6">
<span class="float-right text-right">
<field name="state" widget="kanban_label_selection" options="{'classes': {'draft': 'primary', 'open': 'success', 'close': 'default'}}"/>
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_asset_purchase_tree">
<field name="name">account.asset.asset.purchase.tree</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<tree string="Assets" decoration-info="(state == 'draft')" decoration-muted="(state == 'close')">
<field name="name"/>
<field name="category_id" string="Asset Category"/>
<field name="date"/>
<field name="partner_id" string="Vendor"/>
<field name="value"/>
<field name="value_residual" widget="monetary"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_account_asset_search" model="ir.ui.view">
<field name="name">account.asset.asset.search</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<search string="Asset Account">
<field name="name" string="Asset"/>
<field name="date"/>
<filter string="Current" name="current" domain="[('state','in', ('draft','open'))]" help="Assets in draft and open states"/>
<filter string="Closed" name="closed" domain="[('state','=', 'close')]" help="Assets in closed state"/>
<field name="category_id" string="Asset Category"/>
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
<group expand="0" string="Group By...">
<filter string="Date" name="month" domain="[]" context="{'group_by':'date'}"/>
<filter string="Asset Category" name="category" domain="[]" context="{'group_by':'category_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_account_asset_asset_form">
<field name="name">Assets</field>
<field name="res_model">account.asset.asset</field>
<!-- <field name="view_type">form</field>-->
<field name="view_mode">tree,kanban,form</field>
<!-- <field name="view_id" ref="view_account_asset_asset_purchase_tree"/>-->
<field name="domain">[('category_id.type', '=', 'purchase')]</field>
</record>
<menuitem parent="account.menu_finance_entries_management" id="menu_action_account_asset_asset_form" action="action_account_asset_asset_form" sequence="101" groups="account.group_account_manager"/>
<!-- Configuration -->
<menuitem id="menu_finance_config_assets" name="Assets and Revenues" parent="account.menu_finance_configuration" sequence="25"/>
<record model="ir.actions.act_window" id="action_account_asset_asset_list_normal_purchase">
<field name="name">Asset Types</field>
<field name="res_model">account.asset.category</field>
<field name="domain">[('type', '=', 'purchase')]</field>
<!-- <field name="view_type">form</field>-->
<field name="view_mode">tree,kanban,form</field>
<field name="context">{'default_type': 'purchase'}</field>
</record>
<menuitem parent="account.account_management_menu"
id="menu_action_account_asset_asset_list_normal_purchase"
action="action_account_asset_asset_list_normal_purchase"
sequence="6"/>
<!-- <record id="stock_scrap_tree_view" model="ir.ui.view">-->
<!-- <field name="name">stock.scrap.tree</field>-->
<!-- <field name="model">stock.scrap</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <tree decoration-danger="state == 'draft'">-->
<!-- <field name="name"/>-->
<!-- <field name="date_done"/>-->
<!-- <field name="product_id"/>-->
<!-- <field name="scrap_qty"/>-->
<!-- <field name="product_uom_id" groups="uom.group_uom"/>-->
<!-- <field name="location_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>-->
<!-- <field name="scrap_location_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>-->
<!-- <field name="state"/>-->
<!-- <field name="company_id" groups="base.group_multi_company"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </record>-->
</odoo>

16
base_accounting_kit/views/account_configuration.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_cash_flow_view" model="ir.ui.view">
<field name="name">Cash Flow</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='deprecated']" position="after">
<field name="cash_flow_type" widget="selection"/>
</xpath>
</data>
</field>
</record>
</odoo>

113
base_accounting_kit/views/account_followup.xml

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="view_account_followup_followup_line_tree" model="ir.ui.view">
<field name="name">followup.line.tree</field>
<field name="model">followup.line</field>
<field name="arch" type="xml">
<tree string="Follow-up Steps" >
<field name="name"/>
<field name="delay"/>
</tree>
</field>
</record>
<record id="view_account_followup_followup_line_form" model="ir.ui.view">
<field name="name">followup.line.form</field>
<field name="model">followup.line</field>
<field name="arch" type="xml">
<form string="Follow-up Steps">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<div class="oe_inline">
After <field name="delay" class="oe_inline"/> days overdue, do the following actions:
</div>
</form>
</field>
</record>
<record id="view_account_followup_followup_form" model="ir.ui.view">
<field name="name">account.followup.form</field>
<field name="model">account.followup</field>
<field name="arch" type="xml">
<form string="Follow-up">
<h1><field name="name"/></h1>
<label for="company_id" groups="base.group_multi_company"/>
<field name="company_id" options="{'no_create': True}" class="oe_inline" groups="base.group_multi_company"/>
<p class="oe_grey">
To remind customers of paying their invoices, you can
define different actions depending on how severely
overdue the customer is. These actions are bundled
into follow-up levels that are triggered when the due
date of an invoice has passed a certain
number of days. If there are other overdue invoices for the
same customer, the actions of the most
overdue invoice will be executed.
</p>
<field name="followup_line_ids"/>
</form>
</field>
</record>
<record id="view_account_followup_followup_tree" model="ir.ui.view">
<field name="name">account.followup.tree</field>
<field name="model">account.followup</field>
<field name="arch" type="xml">
<tree string="Follow-up">
<field name="company_id" />
</tree>
</field>
</record>
<record id="view_account_followup_filter" model="ir.ui.view">
<field name="name">account.followup.select</field>
<field name="model">account.followup</field>
<field name="arch" type="xml">
<search string="Search Follow-up">
<field name="company_id" groups="base.group_multi_company"/>
</search>
</field>
</record>
<record id="view_account_followup_followup_kanban" model="ir.ui.view">
<field name="name">account.followup.kanban</field>
<field name="model">account.followup</field>
<field name="arch" type="xml">
<kanban>
<field name="name"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div>
<strong><i class="fa fa-building" role="img" aria-label="Enterprise"/> <t t-esc="record.name.value"/></strong>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="action_account_followup_definition_form" model="ir.actions.act_window">
<field name="name">Payment Follow-ups</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.followup</field>
<field name="search_view_id" ref="view_account_followup_filter"/>
<field name="view_mode">tree,kanban,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define follow-up levels and their related actions
</p><p>
For each step, specify the actions to be taken and delay in days. It is
possible to use print and e-mail templates to send specific messages to
the customer.
</p>
</field>
</record>
<menuitem action="action_account_followup_definition_form" id="account_followup_menu"
parent="account.account_management_menu" name="Follow-up Levels"
groups="account.group_account_manager" sequence="2"/>
</data>
</odoo>

17
base_accounting_kit/views/account_invoice_views.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="view_invoice_asset_category">
<field name="name">account.move.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='account_id']" position="before">
<field string="Asset Category" name="asset_category_id" attrs="{'column_invisible': [('parent.type', '!=', 'in_invoice')]}" optional="show"/>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='account_id']" position="after">
<field string="Asset Category" name="asset_category_id" invisible="1"/>
</xpath>
</field>
</record>
</odoo>

36
base_accounting_kit/views/account_payment_view.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_check_printing.view_account_payment_form_inherited" model="ir.ui.view">
<field name="name">account.payment.form.inherited</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='post']" position="before">
<button name="print_checks" class="oe_highlight"
attrs="{'invisible': ['|', ('payment_method_code', 'not in', ['check_printing','pdc']), ('state', '!=', 'posted')]}"
string="Print Check" type="object"/>
<button name="unmark_sent"
attrs="{'invisible': ['|', ('payment_method_code', 'not in', ['check_printing','pdc']), ('state', '!=', 'sent')]}"
string="Unmark Sent" type="object"/>
</xpath>
<xpath expr="//div[@name='amount_div']" position="after">
<field name="check_amount_in_words"
attrs="{'invisible': [('payment_method_code', 'not in', ['check_printing','pdc'])], 'readonly': [('state', '!=', 'draft')]}"
groups="base.group_no_one"/>
</xpath>
<xpath expr="//field[@name='communication']" position="after">
<field name="check_manual_sequencing" invisible="1"/>
<field name="check_number"
attrs="{'invisible': ['|', ('payment_method_code', 'not in', ['check_printing','pdc']), ('check_number', '=', 0)]}"/>
</xpath>
<xpath expr="//field[@name='payment_date']" position="after">
<field name="effective_date"
attrs="{'invisible': [('payment_method_code', '!=', 'pdc')],
'required': [('payment_method_code', '=', 'pdc')],
'readonly': [('state', 'not in', ('draft'))]}"/>
<field name="bank_reference" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="cheque_reference" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</xpath>
</field>
</record>
</odoo>

14
base_accounting_kit/views/accounting_menu.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record model="ir.ui.menu" id="account.menu_finance">
<field name="name">Accounting</field>
</record>
<menuitem id="account_reports_generic_statements" sequence="2"
name="Generic Statements" parent="account.menu_finance_reports"/>
<menuitem id="account_reports_partner" sequence="2"
name="Partner Reports" parent="account.menu_finance_reports"/>
<menuitem id="account_reports_audit" sequence="3"
name="Audit Reports" parent="account.menu_finance_reports"/>
</data>
</odoo>

78
base_accounting_kit/views/credit_limit_view.xml

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="view_customer_form" model="ir.ui.view">
<field name="name">Credit Limit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='accounting']" position="inside">
<group string="Credit Limit" attrs="{'invisible':[('enable_credit_limit','=',False)]}">
<group>
<field name="active_limit"/>
<field name="enable_credit_limit" invisible="1"/>
<field name="warning_stage" attrs="{'invisible':[('active_limit','=',False)]}"/>
<field name="blocking_stage" attrs="{'invisible':[('active_limit','=',False)]}"/>
</group>
</group>
</xpath>
</field>
</record>
<record id="header_view" model="ir.ui.view">
<field name="name">Credit Limit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="has_due" invisible="1"/>
<field name="is_warning" invisible="1"/>
</xpath>
<xpath expr="//header" position="after">
<div class="alert alert-info" role="alert" style="height: 40px; margin-bottom:0px;"
attrs="{'invisible':[('has_due','=',False)]}">
This Customer's due amount is
<strong>
<field name="due_amount"/>
</strong>
.
</div>
</xpath>
<xpath expr="//sheet/div[@name='button_box']" position="after">
<div class="alert alert-danger" style="height: 40px; width: 350px; margin-bottom:0px;"
attrs="{'invisible':[('is_warning','=',False)]}">
This customer's <strong>warning limit</strong> has been crossed.
</div>
</xpath>
</field>
</record>
<record id="account_move_form_inherited" model="ir.ui.view">
<field name="name">Account Move</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='ref']" position="after">
<field name="has_due" invisible="1"/>
<field name="is_warning" invisible="1"/>
</xpath>
<xpath expr="//header" position="after">
<div class="alert alert-info" role="alert" style="height: 40px; margin-bottom:0px;"
attrs="{'invisible':['|',('has_due','=',False),('type','not in',('out_invoice','out_refund','out_receipt'))]}">
This Customer's due amount is
<strong>
<field name="due_amount"/>
</strong>
.
</div>
</xpath>
<xpath expr="//sheet/div[@name='button_box']" position="after">
<div class="alert alert-danger" style="height: 40px; width: 350px; margin-bottom:0px;"
attrs="{'invisible':['|',('is_warning','=',False),('type','not in',('out_invoice','out_refund','out_receipt'))]}">
This customer's <strong>warning limit</strong> has been crossed.
</div>
</xpath>
</field>
</record>
</data>
</odoo>

119
base_accounting_kit/views/followup_report.xml

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="customer_statements_form_view" model="ir.ui.view">
<field name="name">customer.statements.followup</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<form string="report">
<header>
<field name="followup_status" widget="statusbar"/>
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="name" readonly="1"/>
</h1>
</div>
<br/>
<div class="alert alert-warning o_account_reports_followup-no-action"
attrs="{'invisible': [('invoice_list', '!=', [])]}"
id='no-action' role="alert">
<p>
<strong>
<field name="name"/>
</strong>
has no due amount.
</p>
</div>
<div attrs="{'invisible': [('invoice_list', '=', [])]}">
<group>
<field name="next_reminder_date"/>
</group>
<notebook colspan="4">
<page string="Invoice Details">
<field name="invoice_list"/>
</page>
</notebook>
</div>
<group class="oe_subtotal_footer oe_right" colspan="2" name="sale_total">
<field name="total_due" class="oe_subtotal_footer_separator" widget="monetary"
options="{'currency_field': 'currency_id'}"/>
<div class="oe_subtotal_footer_separator oe_inline o_td_label">
<label for="total_overdue"/>
</div>
<field name="total_overdue" nolabel="1" class="oe_subtotal_footer_separator"
widget="monetary" options="{'currency_field': 'currency_id'}"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="customer_statements_tree_view" model="ir.ui.view">
<field name="name">customer.statements.tree</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<tree string="Follow-up Reports Tree View" create="false" import="false" delete="false">
<field name="currency_id" invisible="1"/>
<field name="name"/>
<field name="total_due" widget="monetary" options="{'currency_field': 'currency_id'}" sum="Total"/>
<field name="total_overdue" widget="monetary" options="{'currency_field': 'currency_id'}"
sum="Total"/>
<field name="followup_status"/>
</tree>
</field>
</record>
<record id="customer_statements_search_view" model="ir.ui.view">
<field name="name">customer.statements.search</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_res_partner_filter"/>
<field name="arch" type="xml">
<filter name="supplier" position="after">
<separator/>
<filter string="Overdue Invoices"
name="filter_with_overdue_invoices"
domain="[('followup_status', '=', 'with_overdue_invoices')]"/>
<filter string="In need of action"
name="filter_in_need_of_action"
domain="[('followup_status', '=', 'in_need_of_action')]"/>
<filter string="No action needed"
name="filter_no_action_needed"
domain="[('followup_status', '=', 'no_action_needed')]"/>
<separator/>
</filter>
</field>
</record>
<record id="action_view_list_customer_statements" model="ir.actions.act_window">
<field name="name">Follow-up Reports</field>
<field name="res_model">res.partner</field>
<field name="view_mode">tree,form</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('customer_statements_tree_view')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('customer_statements_form_view')})]"/>
<field name="context">{'search_default_filter_in_need_of_action':1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No follow-up to send!
</p>
</field>
</record>
<menuitem id="customer_statements_menu" name="Follow-up Reports"
parent="account.menu_finance_receivables"
action="action_view_list_customer_statements" sequence="20"
groups="account.group_account_manager"/>
</data>
</odoo>

17
base_accounting_kit/views/product_template_views.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Product Template -->
<record id="view_product_template_form_inherit" model="ir.ui.view">
<field name="name">Product Template (form)</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<field name="property_account_expense_id" position="after">
<field name="asset_category_id"
domain="[('type', '=', 'purchase')]"
context="{'default_type': 'purchase'}"
groups="account.group_account_user"/>
</field>
</field>
</record>
</odoo>

99
base_accounting_kit/views/recurring_payments_view.xml

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<!--Recurring Templates Form view-->
<record id="account_recurring_payments_form_view" model="ir.ui.view">
<field name="name">Recurring Payments</field>
<field name="model">account.recurring.payments</field>
<field name="arch" type="xml">
<form string="Recurring Payments">
<header>
<field name="state" widget="statusbar" clickable="1"/>
</header>
<sheet>
<group>
<group>
<field name="name"/>
<field name="pay_time"/>
</group>
<group>
<field name="recurring_period"/>
<field name="recurring_interval" class="o_address_zip"/>
</group>
<group>
<field name="partner_id" attrs="{'invisible':[('pay_time','!=','pay_later')]}"/>
<field name="company_id" invisible="1"/>
</group>
<group>
<field name="date"/>
<field name="next_date"/>
<field name="amount"/>
</group>
</group>
<notebook>
<page name="accounting_info" string="Accounting Info">
<group>
<group>
<field name="credit_account"/>
<field name="debit_account"/>
</group>
<group>
<field name="journal_id"/>
<field name="journal_state"/>
</group>
</group>
<group>
<group>
<field name="analytic_account_id"/>
</group>
</group>
</page>
<page name="other_info" string="Other Info">
<group>
<field name="description" placeholder="Description..." nolabel="1" colspan="4"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!--Recurring Templates Tree View-->
<record id="account_recurring_payments_tree_view" model="ir.ui.view">
<field name="name">Recurring Payments</field>
<field name="model">account.recurring.payments</field>
<field name="arch" type="xml">
<tree string="Recurring Payments">
<field name="name"/>
<field name="partner_id"/>
<field name="debit_account"/>
<field name="credit_account"/>
<field name="journal_id"/>
<field name="date"/>
<field name="amount"/>
<field name="state"/>
</tree>
</field>
</record>
<!--Action for Recurring Templates-->
<record id="action_account_recurring_payments_view" model="ir.actions.act_window">
<field name="name">Recurring Payments</field>
<field name="res_model">account.recurring.payments</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="account_recurring_payments_tree_view"/>
<field name="target">current</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Click to create new recurring payment template</p>
</field>
</record>
<menuitem id="account_recurring_payments_child1" name="Recurring Templates" groups="account.group_account_user"
action="action_account_recurring_payments_view" parent="account.root_payment_menu"/>
</data>
</odoo>

89
base_accounting_kit/views/reports_config_view.xml

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Account Financial Report -->
<record id="view_account_financial_report_form" model="ir.ui.view">
<field name="name">account.financial.report.form</field>
<field name="model">account.financial.report</field>
<field name="arch" type="xml">
<form string="Account Report">
<group col="4">
<field name="name"/>
<field name="parent_id"/>
<field name="sequence"/>
<field name="type"/>
<field name="sign"/>
<field name="style_overwrite"/>
</group>
<notebook
attrs="{'invisible': [('type','not in',['accounts','account_type', 'account_report'])]}">
<page string="Report">
<group>
<field name="display_detail"
attrs="{'invisible': [('type','not in',['accounts','account_type'])]}"/>
<field name="account_report_id"
attrs="{'invisible': [('type', '!=', 'account_report')]}"/>
</group>
<field name="account_ids"
attrs="{'invisible': [('type', '!=', 'accounts')]}"/>
<field name="account_type_ids"
attrs="{'invisible': [('type', '!=', 'account_type')]}"/>
</page>
</notebook>
</form>
</field>
</record>
<record id="view_account_financial_report_tree" model="ir.ui.view">
<field name="name">account.financial.report.tree</field>
<field name="model">account.financial.report</field>
<field name="arch" type="xml">
<tree string="Account Report">
<field name="name"/>
<field name="parent_id" invisible="1"/>
<field name="type"/>
<field name="account_report_id"/>
</tree>
</field>
</record>
<record id="view_account_financial_report_search" model="ir.ui.view">
<field name="name">account.financial.report.search</field>
<field name="model">account.financial.report</field>
<field name="arch" type="xml">
<search string="Account Report">
<field name="name" string="Account Report"/>
<field name="type"/>
<field name="account_report_id"/>
<group expand="0" string="Group By">
<filter string="Parent Report"
name="filter_parent_rep"
domain=""
context="{'group_by':'parent_id'}"/>
<filter string="Report Type"
name="filter_rep_type"
domain="[]"
context="{'group_by':'type'}"/>
</group>
</search>
</field>
</record>
<record id="action_account_financial_report_tree"
model="ir.actions.act_window">
<field name="name">Financial Reports</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.financial.report</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id"
ref="view_account_financial_report_search"/>
<field name="view_id" ref="view_account_financial_report_tree"/>
</record>
<menuitem id="menu_account_financial_reports_tree"
name="Account Reports" parent="account.account_account_menu"
action="action_account_financial_report_tree"
/>
</data>
</odoo>

25
base_accounting_kit/views/res_config_view.xml

@ -0,0 +1,25 @@
<odoo>
<data>
<record id="es_config_settings_view_form_base_accounting_kit" model="ir.ui.view">
<field name="name">res.config.view.inherited.base.accounting.kit</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="30"/>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='invoicing_settings']" position="inside">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="customer_credit_limit" on_change="1"/>
</div>
<div class="o_setting_right_pane" id="snailmail_settings">
<label for="customer_credit_limit" />
<div class="text-muted">
Enable credit limit for customers
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

39
base_accounting_kit/wizard/__init__.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import account_bank_book_wizard
from . import account_cash_book_wizard
from . import account_day_book_wizard
from . import account_lock_date
from . import account_report_common_account
from . import account_report_common_partner
from . import aged_partner
from . import asset_depreciation_confirmation_wizard
from . import asset_modify
from . import cash_flow_report
from . import financial_report
from . import general_ledger
from . import journal_audit
from . import partner_ledger
from . import recurring_payments
from . import tax_report
from . import trial_balance

111
base_accounting_kit/wizard/account_bank_book_wizard.py

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import date
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class BankBookWizard(models.TransientModel):
_name = 'account.bank.book.report'
company_id = fields.Many2one('res.company', string='Company',
readonly=True,
default=lambda self: self.env.user.company_id)
target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries'),
], string='Target Moves', required=True,
default='posted')
date_from = fields.Date(string='Start Date', default=date.today(),
requred=True)
date_to = fields.Date(string='End Date', default=date.today(),
requred=True)
display_account = fields.Selection(
[('all', 'All'), ('movement', 'With movements'),
('not_zero', 'With balance is not equal to 0'), ],
string='Display Accounts', required=True, default='movement')
sortby = fields.Selection(
[('sort_date', 'Date'), ('sort_journal_partner', 'Journal & Partner')],
string='Sort by',
required=True, default='sort_date')
initial_balance = fields.Boolean(string='Include Initial Balances',
help='If you selected date, this field allow you to add a row to display the amount of debit/credit/balance that precedes the filter you\'ve set.')
def _get_default_account_ids(self):
journals = self.env['account.journal'].search([('type', '=', 'bank')])
accounts = []
for journal in journals:
accounts.append(journal.default_credit_account_id.id)
return accounts
account_ids = fields.Many2many('account.account',
'account_report_bankbook_account_rel',
'report_id', 'account_id',
'Accounts',
default=_get_default_account_ids)
journal_ids = fields.Many2many('account.journal',
'account_report_bankbook_journal_rel',
'account_id', 'journal_id',
string='Journals', required=True,
default=lambda self: self.env[
'account.journal'].search([]))
@api.onchange('account_ids')
def onchange_account_ids(self):
if self.account_ids:
journals = self.env['account.journal'].search(
[('type', '=', 'bank')])
accounts = []
for journal in journals:
accounts.append(journal.default_credit_account_id.id)
domain = {'account_ids': [('id', 'in', accounts)]}
return {'domain': domain}
def _build_contexts(self, data):
result = {}
result['journal_ids'] = 'journal_ids' in data['form'] and data['form'][
'journal_ids'] or False
result['state'] = 'target_move' in data['form'] and data['form'][
'target_move'] or ''
result['date_from'] = data['form']['date_from'] or False
result['date_to'] = data['form']['date_to'] or False
result['strict_range'] = True if result['date_from'] else False
return result
def check_report(self):
self.ensure_one()
if self.initial_balance and not self.date_from:
raise UserError(_("You must choose a Start Date"))
data = {}
data['ids'] = self.env.context.get('active_ids', [])
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(
['date_from', 'date_to', 'journal_ids', 'target_move',
'display_account',
'account_ids', 'sortby', 'initial_balance'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(used_context,
lang=self.env.context.get(
'lang') or 'en_US')
return self.env.ref(
'base_accounting_kit.action_report_bank_book').report_action(self,
data=data)

43
base_accounting_kit/wizard/account_bank_book_wizard_view.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="account_bank_book_form_view" model="ir.ui.view">
<field name="name">account.bank.book.form.view</field>
<field name="model">account.bank.book.report</field>
<field name="arch" type="xml">
<form string="Bank Book Report">
<field name="company_id" invisible="1"/>
<group col="4">
<field name="target_move" widget="radio"/>
<field name="sortby" widget="radio"/>
<field name="initial_balance"/>
<newline/>
<newline/>
<field name="date_from"/>
<field name="date_to"/>
</group>
<group>
<field name="account_ids" widget="many2many_tags"/>
<field name="journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
<footer>
<button name="check_report" string="Print" type="object" default_focus="1" class="oe_highlight"/>
<button string="Cancel" class="btn btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_account_bank_book_view" model="ir.actions.act_window">
<field name="name">Bank Book Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.bank.book.report</field>
<field name="view_id" ref="account_bank_book_form_view"/>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_bank_book_menu" name="Bank Book" action="action_account_bank_book_view"
parent="base_accounting_kit.account_reports_generic_statements"/>
</data>
</odoo>

111
base_accounting_kit/wizard/account_cash_book_wizard.py

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import date
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class CashBookWizard(models.TransientModel):
_name = 'account.cash.book.report'
company_id = fields.Many2one('res.company', string='Company',
readonly=True,
default=lambda self: self.env.user.company_id)
target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries'),
], string='Target Moves', required=True,
default='posted')
date_from = fields.Date(string='Start Date', default=date.today(),
requred=True)
date_to = fields.Date(string='End Date', default=date.today(),
requred=True)
display_account = fields.Selection(
[('all', 'All'), ('movement', 'With movements'),
('not_zero', 'With balance is not equal to 0'), ],
string='Display Accounts', required=True, default='movement')
sortby = fields.Selection(
[('sort_date', 'Date'), ('sort_journal_partner', 'Journal & Partner')],
string='Sort by',
required=True, default='sort_date')
initial_balance = fields.Boolean(string='Include Initial Balances',
help='If you selected date, this field allow you to add a row to display the amount of debit/credit/balance that precedes the filter you\'ve set.')
def _get_default_account_ids(self):
journals = self.env['account.journal'].search([('type', '=', 'cash')])
accounts = []
for journal in journals:
accounts.append(journal.default_credit_account_id.id)
return accounts
account_ids = fields.Many2many('account.account',
'account_report_cashbook_account_rel',
'report_id', 'account_id',
'Accounts',
default=_get_default_account_ids)
journal_ids = fields.Many2many('account.journal',
'account_report_cashbook_journal_rel',
'account_id', 'journal_id',
string='Journals', required=True,
default=lambda self: self.env[
'account.journal'].search([]))
@api.onchange('account_ids')
def onchange_account_ids(self):
if self.account_ids:
journals = self.env['account.journal'].search(
[('type', '=', 'cash')])
accounts = []
for journal in journals:
accounts.append(journal.default_credit_account_id.id)
domain = {'account_ids': [('id', 'in', accounts)]}
return {'domain': domain}
def _build_contexts(self, data):
result = {}
result['journal_ids'] = 'journal_ids' in data['form'] and data['form'][
'journal_ids'] or False
result['state'] = 'target_move' in data['form'] and data['form'][
'target_move'] or ''
result['date_from'] = data['form']['date_from'] or False
result['date_to'] = data['form']['date_to'] or False
result['strict_range'] = True if result['date_from'] else False
return result
def check_report(self):
self.ensure_one()
if self.initial_balance and not self.date_from:
raise UserError(_("You must choose a Start Date"))
data = {}
data['ids'] = self.env.context.get('active_ids', [])
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(
['date_from', 'date_to', 'journal_ids', 'target_move',
'display_account',
'account_ids', 'sortby', 'initial_balance'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(used_context,
lang=self.env.context.get(
'lang') or 'en_US')
return self.env.ref(
'base_accounting_kit.action_report_cash_book').report_action(self,
data=data)

43
base_accounting_kit/wizard/account_cash_book_wizard_view.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="account_cash_book_form_view" model="ir.ui.view">
<field name="name">account.cash.book.form.view</field>
<field name="model">account.cash.book.report</field>
<field name="arch" type="xml">
<form string="Cash Book Report">
<field name="company_id" invisible="1"/>
<group col="4">
<field name="target_move" widget="radio"/>
<field name="sortby" widget="radio"/>
<field name="initial_balance"/>
<newline/>
<newline/>
<field name="date_from"/>
<field name="date_to"/>
</group>
<group>
<field name="account_ids" widget="many2many_tags"/>
<field name="journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
<footer>
<button name="check_report" string="Print" type="object" default_focus="1" class="oe_highlight"/>
<button string="Cancel" class="btn btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_account_cash_book_view" model="ir.actions.act_window">
<field name="name">Cash Book Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.cash.book.report</field>
<field name="view_id" ref="account_cash_book_form_view"/>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_cash_book_menu" name="Cash Book" action="action_account_cash_book_view"
parent="base_accounting_kit.account_reports_generic_statements"/>
</data>
</odoo>

77
base_accounting_kit/wizard/account_day_book_wizard.py

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import date
from odoo import models, fields
class DayBookWizard(models.TransientModel):
_name = 'account.day.book.report'
company_id = fields.Many2one('res.company', string='Company',
readonly=True,
default=lambda self: self.env.user.company_id)
journal_ids = fields.Many2many('account.journal', string='Journals',
required=True,
default=lambda self: self.env[
'account.journal'].search([]))
target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries'),
], string='Target Moves', required=True,
default='posted')
account_ids = fields.Many2many('account.account',
'account_report_daybook_account_rel',
'report_id', 'account_id',
'Accounts')
date_from = fields.Date(string='Start Date', default=date.today(),
requred=True)
date_to = fields.Date(string='End Date', default=date.today(),
requred=True)
def _build_contexts(self, data):
result = {}
result['journal_ids'] = 'journal_ids' in data['form'] and data['form'][
'journal_ids'] or False
result['state'] = 'target_move' in data['form'] and data['form'][
'target_move'] or ''
result['date_from'] = data['form']['date_from'] or False
result['date_to'] = data['form']['date_to'] or False
result['strict_range'] = True if result['date_from'] else False
return result
def check_report(self):
self.ensure_one()
data = {}
data['ids'] = self.env.context.get('active_ids', [])
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = \
self.read(['date_from', 'date_to', 'journal_ids', 'target_move',
'account_ids'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(used_context,
lang=self.env.context.get(
'lang') or 'en_US')
return self.env.ref(
'base_accounting_kit.day_book_pdf_report').report_action(self,
data=data)

40
base_accounting_kit/wizard/account_day_book_wizard_view.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="account_day_book_form_view" model="ir.ui.view">
<field name="name">account.day.book.form.view</field>
<field name="model">account.day.book.report</field>
<field name="arch" type="xml">
<form string="Cash Book Report">
<field name="company_id" invisible="1"/>
<group col="4">
<field name="target_move" widget="radio"/>
<newline/>
<field name="date_from"/>
<field name="date_to"/>
</group>
<group>
<field name="account_ids" widget="many2many_tags"/>
<field name="journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
<footer>
<button name="check_report" string="Print" type="object" default_focus="1" class="oe_highlight"/>
<button string="Cancel" class="btn btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_account_day_book_view" model="ir.actions.act_window">
<field name="name">Day Book Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.day.book.report</field>
<field name="view_id" ref="account_day_book_form_view"/>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_day_book_menu" name="Day Book" action="action_account_day_book_view"
parent="base_accounting_kit.account_reports_generic_statements"/>
</data>
</odoo>

65
base_accounting_kit/wizard/account_lock_date.py

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError
class AccountUpdateLockDate(models.TransientModel):
_name = 'account.lock.date'
_description = 'Lock date for accounting'
company_id = fields.Many2one(comodel_name='res.company', string="Company",
required=True)
period_lock_date = fields.Date(string="Lock Date for Non-Advisers",
help="Only users with the 'Adviser' role can edit accounts prior to "
"and inclusive of this date. Use it for period locking inside an "
"open fiscal year, for example.")
fiscalyear_lock_date = fields.Date(string="Lock Date",
help="No users, including Advisers, can edit accounts prior to and "
"inclusive of this date. Use it for fiscal year locking for "
"example.")
@api.model
def default_get(self, field_list):
res = super(AccountUpdateLockDate, self).default_get(field_list)
company = self.env.user.company_id
res.update({
'company_id': company.id,
'period_lock_date': company.period_lock_date,
'fiscalyear_lock_date': company.fiscalyear_lock_date,
})
return res
def _check_execute_allowed(self):
self.ensure_one()
has_adviser_group = self.env.user.has_group(
'account.group_account_manager')
if not (has_adviser_group or self.env.uid == SUPERUSER_ID):
raise UserError(_("You are not allowed to execute this action."))
def execute(self):
self.ensure_one()
self._check_execute_allowed()
self.company_id.sudo().write({
'period_lock_date': self.period_lock_date,
'fiscalyear_lock_date': self.fiscalyear_lock_date,
})

36
base_accounting_kit/wizard/account_lock_date.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="account_update_lock_date_form_view">
<field name="name">account.lock.date.form</field>
<field name="model">account.lock.date</field>
<field name="arch" type="xml">
<form>
<group>
<field name="company_id" invisible="1"/>
<field name="period_lock_date"/>
<field name="fiscalyear_lock_date"/>
</group>
<footer>
<button string="Update" name="execute" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="account_update_lock_date_act_window">
<field name="name">Lock your Fiscal Period</field>
<field name="res_model">account.lock.date</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="menu_lock_dates"
name="Lock Dates"
action="account_update_lock_date_act_window"
parent="account.menu_finance_entries_actions"
groups="account.group_account_manager"/>
</odoo>

38
base_accounting_kit/wizard/account_report_common_account.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class AccountCommonAccountReport(models.TransientModel):
_name = 'account.common.account.report'
_description = 'Account Common Account Report'
_inherit = "account.common.report"
display_account = fields.Selection(
[('all', 'All'), ('movement', 'With movements'),
('not_zero', 'With balance is not equal to 0'), ],
string='Display Accounts', required=True, default='movement')
def pre_print_report(self, data):
data['form'].update(self.read(['display_account'])[0])
return data

40
base_accounting_kit/wizard/account_report_common_partner.py

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class AccountingCommonPartnerReport(models.TransientModel):
_name = 'account.common.partner.report'
_description = 'Account Common Partner Report'
_inherit = "account.common.report"
result_selection = fields.Selection([('customer', 'Receivable Accounts'),
('supplier', 'Payable Accounts'),
('customer_supplier',
'Receivable and Payable Accounts')
], string="Partner's", required=True,
default='customer')
def pre_print_report(self, data):
data['form'].update(self.read(['result_selection'])[0])
return data

69
base_accounting_kit/wizard/aged_partner.py

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import time
from dateutil.relativedelta import relativedelta
from odoo import fields, models, _
from odoo.exceptions import UserError
class AccountAgedTrialBalance(models.TransientModel):
_name = 'account.aged.trial.balance'
_inherit = 'account.common.partner.report'
_description = 'Account Aged Trial balance Report'
journal_ids = fields.Many2many('account.journal', string='Journals',
required=True)
period_length = fields.Integer(string='Period Length (days)',
required=True, default=30)
date_from = fields.Date(default=lambda *a: time.strftime('%Y-%m-%d'))
def _print_report(self, data):
res = {}
data = self.pre_print_report(data)
data['form'].update(self.read(['period_length'])[0])
period_length = data['form']['period_length']
if period_length <= 0:
raise UserError(_('You must set a period length greater than 0.'))
if not data['form']['date_from']:
raise UserError(_('You must set a start date.'))
start = data['form']['date_from']
for i in range(5)[::-1]:
stop = start - relativedelta(days=period_length - 1)
res[str(i)] = {
'name': (i != 0 and (
str((5 - (i + 1)) * period_length) + '-' + str(
(5 - i) * period_length)) or (
'+' + str(4 * period_length))),
'stop': start.strftime('%Y-%m-%d'),
'start': (i != 0 and stop.strftime('%Y-%m-%d') or False),
}
start = stop - relativedelta(days=1)
data['form'].update(res)
return self.env.ref(
'base_accounting_kit.action_report_aged_partner_balance').with_context(
landscape=True).report_action(self, data=data)

41
base_accounting_kit/wizard/aged_partner.xml

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_aged_balance_view" model="ir.ui.view">
<field name="name">Aged Partner Balance</field>
<field name="model">account.aged.trial.balance</field>
<field name="arch" type="xml">
<form string="Report Options">
<group col="4">
<field name="date_from"/>
<field name="period_length"/>
<newline/>
<field name="result_selection" widget="radio"/>
<field name="target_move" widget="radio"/>
</group>
<field name="journal_ids" required="0" invisible="1"/>
<footer>
<button name="check_report" string="Print" type="object" default_focus="1" class="oe_highlight"/>
<button string="Cancel" class="btn btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_account_aged_balance_view" model="ir.actions.act_window">
<field name="name">Aged Partner Balance</field>
<field name="res_model">account.aged.trial.balance</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="account_aged_balance_view"/>
<field name="context">{}</field>
<field name="target">new</field>
</record>
<menuitem id="menu_aged_trial_balance"
name="Aged Partner Balance"
sequence="2"
action="action_account_aged_balance_view"
parent="base_accounting_kit.account_reports_partner"/>
</odoo>

54
base_accounting_kit/wizard/asset_depreciation_confirmation_wizard.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models, _
class AssetDepreciationConfirmationWizard(models.TransientModel):
_name = "asset.depreciation.confirmation.wizard"
_description = "asset.depreciation.confirmation.wizard"
date = fields.Date('Account Date', required=True,
help="Choose the period for which you want to "
"automatically post the depreciation "
"lines of running assets",
default=fields.Date.context_today)
def asset_compute(self):
self.ensure_one()
context = self._context
created_move_ids = self.env[
'account.asset.asset'].compute_generated_entries(self.date,
asset_type=context.get(
'asset_type'))
return {
'name': _('Created Asset Moves') if context.get(
'asset_type') == 'purchase' else _('Created Revenue Moves'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'domain': "[('id','in',[" + ','.join(
str(id) for id in created_move_ids) + "])]",
'type': 'ir.actions.act_window',
}

43
base_accounting_kit/wizard/asset_depreciation_confirmation_wizard_views.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_asset_depreciation_confirmation_wizard" model="ir.ui.view">
<field name="name">asset.depreciation.confirmation.wizard</field>
<field name="model">asset.depreciation.confirmation.wizard</field>
<field name="arch" type="xml">
<form string="Compute Asset">
<div>
<p>
This wizard will post installment/depreciation lines for the selected month.<br/>
This will generate journal entries for all related installment lines on this period of asset/revenue recognition as well.
</p>
</div>
<group>
<field name="date"/>
</group>
<footer>
<button string="Generate Entries" name="asset_compute" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_asset_depreciation_confirmation_wizard" model="ir.actions.act_window">
<field name="name">Post Depreciation Lines</field>
<field name="res_model">asset.depreciation.confirmation.wizard</field>
<!-- <field name="view_type">form</field>-->
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_asset_depreciation_confirmation_wizard"/>
<field name="target">new</field>
<field name="context">{'asset_type': 'purchase'}</field>
</record>
<menuitem name="Generate Assets Entries"
action="action_asset_depreciation_confirmation_wizard"
id="menu_asset_depreciation_confirmation_wizard"
parent="account.menu_finance_entries_generate_entries"
sequence="111"
groups="account.group_account_manager"/>
</odoo>

128
base_accounting_kit/wizard/asset_modify.py

@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from lxml import etree
from odoo import api, fields, models, _
from odoo.addons.base.models.ir_ui_view import (
transfer_field_to_modifiers, transfer_node_to_modifiers,
transfer_modifiers_to_node,
)
class AssetModify(models.TransientModel):
_name = 'asset.modify'
_description = 'Modify Asset'
name = fields.Text(string='Reason', required=True)
method_number = fields.Integer(string='Number of Depreciations',
required=True)
method_period = fields.Integer(string='Period Length')
method_end = fields.Date(string='Ending date')
asset_method_time = fields.Char(compute='_get_asset_method_time',
string='Asset Method Time', readonly=True)
def _get_asset_method_time(self):
if self.env.context.get('active_id'):
asset = self.env['account.asset.asset'].browse(
self.env.context.get('active_id'))
self.asset_method_time = asset.method_time
def setup_modifiers(node, field=None, context=None, in_tree_view=False):
modifiers = {}
if field is not None:
transfer_field_to_modifiers(field, modifiers)
transfer_node_to_modifiers(
node, modifiers, context=context, in_tree_view=in_tree_view)
transfer_modifiers_to_node(modifiers, node)
@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False,
submenu=False):
result = super(AssetModify, self).fields_view_get(view_id, view_type,
toolbar=toolbar,
submenu=submenu)
asset_id = self.env.context.get('active_id')
active_model = self.env.context.get('active_model')
if active_model == 'account.asset.asset' and asset_id:
asset = self.env['account.asset.asset'].browse(asset_id)
doc = etree.XML(result['arch'])
if asset.method_time == 'number' and doc.xpath(
"//field[@name='method_end']"):
node = doc.xpath("//field[@name='method_end']")[0]
node.set('invisible', '1')
self.setup_modifiers(node, result['fields']['method_end'])
elif asset.method_time == 'end' and doc.xpath(
"//field[@name='method_number']"):
node = doc.xpath("//field[@name='method_number']")[0]
node.set('invisible', '1')
self.setup_modifiers(node, result['fields']['method_number'])
result['arch'] = etree.tostring(doc, encoding='unicode')
return result
@api.model
def default_get(self, fields):
res = super(AssetModify, self).default_get(fields)
asset_id = self.env.context.get('active_id')
asset = self.env['account.asset.asset'].browse(asset_id)
if 'name' in fields:
res.update({'name': asset.name})
if 'method_number' in fields and asset.method_time == 'number':
res.update({'method_number': asset.method_number})
if 'method_period' in fields:
res.update({'method_period': asset.method_period})
if 'method_end' in fields and asset.method_time == 'end':
res.update({'method_end': asset.method_end})
if self.env.context.get('active_id'):
active_asset = self.env['account.asset.asset'].browse(
self.env.context.get('active_id'))
res['asset_method_time'] = active_asset.method_time
return res
def modify(self):
""" Modifies the duration of asset for calculating depreciation
and maintains the history of old values, in the chatter.
"""
asset_id = self.env.context.get('active_id', False)
asset = self.env['account.asset.asset'].browse(asset_id)
old_values = {
'method_number': asset.method_number,
'method_period': asset.method_period,
'method_end': asset.method_end,
}
asset_vals = {
'method_number': self.method_number,
'method_period': self.method_period,
'method_end': self.method_end,
}
asset.write(asset_vals)
asset.compute_depreciation_board()
tracked_fields = self.env['account.asset.asset'].fields_get(
['method_number', 'method_period', 'method_end'])
changes, tracking_value_ids = asset._message_track(tracked_fields,
old_values)
if changes:
asset.message_post(subject=_('Depreciation board modified'),
body=self.name,
tracking_value_ids=tracking_value_ids)
return {'type': 'ir.actions.act_window_close'}

40
base_accounting_kit/wizard/asset_modify_views.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="asset_modify_form">
<field name="name">wizard.asset.modify.form</field>
<field name="model">asset.modify</field>
<field name="arch" type="xml">
<form string="Modify Asset">
<field name="asset_method_time" invisible="1"/>
<group string="Asset Durations to Modify" col="4">
<group colspan="2" col="2">
<field name="name"/>
<field name="method_number" attrs="{'invisible': [('asset_method_time', '=', 'end')]}"/>
</group>
<group colspan="2" col="2">
<field name="method_end" attrs="{'invisible': [('asset_method_time', '=', 'number')]}"/>
<label for="method_period"/>
<div>
<field name="method_period" class="oe_inline"/> months
</div>
</group>
</group>
<footer>
<button name="modify" string="Modify" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_asset_modify" model="ir.actions.act_window">
<field name="name">Modify Asset</field>
<field name="res_model">asset.modify</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="asset_modify_form"/>
<field name="target">new</field>
</record>
</odoo>

91
base_accounting_kit/wizard/cash_flow_report.py

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models
class AccountingReport(models.TransientModel):
_name = "cash.flow.report"
_inherit = "account.common.report"
_description = "Cash Flow Report"
@api.model
def _get_account_report(self):
reports = []
if self._context.get('active_id'):
menu = self.env['ir.ui.menu'].browse(
self._context.get('active_id')).name
reports = self.env['account.financial.report'].search(
[('name', 'ilike', menu)])
return reports and reports[0] or False
enable_filter = fields.Boolean(string='Enable Comparison')
account_report_id = fields.Many2one('account.financial.report',
string='Account Reports',
required=True,
default=_get_account_report)
label_filter = fields.Char(string='Column Label',
help="This label will be displayed on report to show the balance"
" computed for the given comparison filter.")
filter_cmp = fields.Selection(
[('filter_no', 'No Filters'), ('filter_date', 'Date')],
string='Filter by', required=True, default='filter_no')
date_from_cmp = fields.Date(string='Start Date')
date_to_cmp = fields.Date(string='End Date')
debit_credit = fields.Boolean(string='Display Debit/Credit Columns',
help="This option allows you to get more details about the way your balances are computed. Because it is space consuming, we do not allow to use it while doing a comparison.")
def _build_comparison_context(self, data):
result = {}
result['journal_ids'] = 'journal_ids' in data['form'] and data['form'][
'journal_ids'] or False
result['state'] = 'target_move' in data['form'] and data['form'][
'target_move'] or ''
if data['form']['filter_cmp'] == 'filter_date':
result['date_from'] = data['form']['date_from_cmp']
result['date_to'] = data['form']['date_to_cmp']
result['strict_range'] = True
return result
# @api.multi
def check_report(self):
res = super(AccountingReport, self).check_report()
data = {}
data['form'] = self.read(
['account_report_id', 'date_from_cmp', 'date_to_cmp',
'journal_ids', 'filter_cmp', 'target_move'])[0]
for field in ['account_report_id']:
if isinstance(data['form'][field], tuple):
data['form'][field] = data['form'][field][0]
comparison_context = self._build_comparison_context(data)
res['data']['form']['comparison_context'] = comparison_context
return res
def _print_report(self, data):
data['form'].update(self.read(
['date_from_cmp', 'debit_credit', 'date_to_cmp', 'filter_cmp',
'account_report_id', 'enable_filter', 'label_filter',
'target_move'])[0])
return self.env.ref(
'base_accounting_kit.action_report_cash_flow').report_action(self,
data=data,
config=False)

49
base_accounting_kit/wizard/cash_flow_report.xml

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="cash_flow_report_view" model="ir.ui.view">
<field name="name">Cash Flow Statement</field>
<field name="model">cash.flow.report</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<field name="target_move" position="before">
<field name="account_report_id" domain="[('parent_id','=',False)]" readonly="1"/>
</field>
<field name="target_move" position="after">
<field name="enable_filter" invisible="1"/>
<field name="debit_credit" attrs="{'invisible': [('enable_filter','=',True)]}"/>
</field>
<field name="journal_ids" position="after">
<notebook tabpos="up" colspan="4">
<page string="Comparison" name="comparison" attrs="{'invisible': [('enable_filter','=',False)]}">
<group>
<field name="label_filter" attrs="{'required': [('enable_filter', '=', True)]}"/>
<field name="filter_cmp"/>
</group>
<group string="Dates" attrs="{'invisible':[('filter_cmp', '!=', 'filter_date')]}">
<field name="date_from_cmp" attrs="{'required':[('filter_cmp', '=', 'filter_date')]}"/>
<field name="date_to_cmp" attrs="{'required':[('filter_cmp', '=', 'filter_date')]}"/>
</group>
</page>
</notebook>
</field>
<field name="journal_ids" position="replace"/>
</field>
</record>
<record id="action_cash_flow_report" model="ir.actions.act_window">
<field name="name">Cash Flow Statement</field>
<field name="res_model">cash.flow.report</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">form</field>
<field name="view_id" ref="cash_flow_report_view"/>
<field name="target">new</field>
<field name="context"
eval="{'default_account_report_id':ref('base_accounting_kit.account_financial_report_cash_flow0')}"/>
</record>
<menuitem id="menu_account_cash_flow_report"
name="Cash Flow Statement"
sequence="5"
action="action_cash_flow_report"
parent="base_accounting_kit.account_reports_generic_statements"/>
</odoo>

396
base_accounting_kit/wizard/financial_report.py

@ -0,0 +1,396 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import re
from odoo import api, models, fields
class FinancialReport(models.TransientModel):
_name = "financial.report"
_inherit = "account.common.report"
_description = "Financial Reports"
view_format = fields.Selection([
('vertical', 'Vertical'),
('horizontal', 'Horizontal')],
default='vertical',
string="Format")
@api.model
def _get_account_report(self):
reports = []
if self._context.get('active_id'):
menu = self.env['ir.ui.menu'].browse(
self._context.get('active_id')).name
reports = self.env['account.financial.report'].search([
('name', 'ilike', menu)])
return reports and reports[0] or False
enable_filter = fields.Boolean(
string='Enable Comparison',
default=False)
target_move = fields.Selection([
('all', 'All'),
('posted', 'Posted')],
string="Type",
default='all')
account_report_id = fields.Many2one(
'account.financial.report',
string='Account Reports',
required=True)
date_from = fields.Date(string='Start Date')
date_to = fields.Date(string='End Date')
debit_credit = fields.Boolean(
string='Display Debit/Credit Columns',
default=True,
help="This option allows you to"
" get more details about the "
"way your balances are computed."
" Because it is space consuming,"
" we do not allow to use it "
"while doing a comparison.")
company_id = fields.Many2one(
'res.company',
string='Company',
index=True,
default=lambda self: self.env.user.company_id.id)
def view_report_pdf(self):
"""This function will be executed when we click the view button
from the wizard. Based on the values provided in the wizard, this
function will print pdf report"""
self.ensure_one()
data = dict()
data['ids'] = self.env.context.get('active_ids', [])
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(
['date_from', 'enable_filter', 'debit_credit', 'date_to',
'account_report_id', 'target_move', 'view_format',
'company_id'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(
used_context,
lang=self.env.context.get('lang') or 'en_US')
report_lines = self.get_account_lines(data['form'])
# find the journal items of these accounts
journal_items = self.find_journal_items(report_lines, data['form'])
def set_report_level(rec):
"""This function is used to set the level of each item.
This level will be used to set the alignment in the dynamic reports."""
level = 1
if not rec['parent']:
return level
else:
for line in report_lines:
key = 'a_id' if line['type'] == 'account' else 'id'
if line[key] == rec['parent']:
return level + set_report_level(line)
# finding the root
for item in report_lines:
item['balance'] = round(item['balance'], 2)
if not item['parent']:
item['level'] = 1
parent = item
report_name = item['name']
id = item['id']
report_id = item['r_id']
else:
item['level'] = set_report_level(item)
currency = self._get_currency()
data['currency'] = currency
data['journal_items'] = journal_items
data['report_lines'] = report_lines
# checking view type
return self.env.ref(
'base_accounting_kit.financial_report_pdf').report_action(self,
data)
def _compute_account_balance(self, accounts):
""" compute the balance, debit
and credit for the provided accounts
"""
mapping = {
'balance':
"COALESCE(SUM(debit),0) - COALESCE(SUM(credit), 0)"
" as balance",
'debit': "COALESCE(SUM(debit), 0) as debit",
'credit': "COALESCE(SUM(credit), 0) as credit",
}
res = {}
for account in accounts:
res[account.id] = dict((fn, 0.0)
for fn in mapping.keys())
if accounts:
tables, where_clause, where_params = (
self.env['account.move.line']._query_get())
tables = tables.replace(
'"', '') if tables else "account_move_line"
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
request = ("SELECT account_id as id, " +
', '.join(mapping.values()) +
" FROM " + tables +
" WHERE account_id IN %s " +
filters +
" GROUP BY account_id")
params = (tuple(accounts._ids),) + tuple(where_params)
self.env.cr.execute(request, params)
for row in self.env.cr.dictfetchall():
res[row['id']] = row
return res
def _compute_report_balance(self, reports):
"""returns a dictionary with key=the ID of a record and
value=the credit, debit and balance amount
computed for this record. If the record is of type :
'accounts' : it's the sum of the linked accounts
'account_type' : it's the sum of leaf accounts with
such an account_type
'account_report' : it's the amount of the related report
'sum' : it's the sum of the children of this record
(aka a 'view' record)"""
res = {}
fields = ['credit', 'debit', 'balance']
for report in reports:
if report.id in res:
continue
res[report.id] = dict((fn, 0.0) for fn in fields)
if report.type == 'accounts':
# it's the sum of the linked accounts
res[report.id]['account'] = self._compute_account_balance(
report.account_ids
)
for value in \
res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'account_type':
# it's the sum the leaf accounts
# with such an account type
accounts = self.env['account.account'].search([
('user_type_id', 'in', report.account_type_ids.ids)
])
res[report.id]['account'] = self._compute_account_balance(
accounts)
for value in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'account_report' and report.account_report_id:
# it's the amount of the linked report
res2 = self._compute_report_balance(report.account_report_id)
for key, value in res2.items():
for field in fields:
res[report.id][field] += value[field]
elif report.type == 'sum':
# it's the sum of the children of this account.report
res2 = self._compute_report_balance(report.children_ids)
for key, value in res2.items():
for field in fields:
res[report.id][field] += value[field]
return res
def get_account_lines(self, data):
lines = []
account_report = self.env['account.financial.report'].search([
('id', '=', data['account_report_id'][0])
])
child_reports = account_report._get_children_by_order()
res = self.with_context(
data.get('used_context'))._compute_report_balance(child_reports)
if data['enable_filter']:
comparison_res = self._compute_report_balance(child_reports)
for report_id, value in comparison_res.items():
res[report_id]['comp_bal'] = value['balance']
report_acc = res[report_id].get('account')
if report_acc:
for account_id, val in \
comparison_res[report_id].get('account').items():
report_acc[account_id]['comp_bal'] = val['balance']
for report in child_reports:
r_name = str(report.name)
# r_name = r_name.replace(" ", "-") + "-"
r_name = re.sub('[^0-9a-zA-Z]+', '', r_name)
if report.parent_id:
p_name = str(report.parent_id.name)
p_name = re.sub('[^0-9a-zA-Z]+', '', p_name) + str(
report.parent_id.id)
# p_name = p_name.replace(" ", "-") +
# "-" + str(report.parent_id.id)
else:
p_name = False
vals = {
'r_id': report.id,
'id': r_name + str(report.id),
'sequence': report.sequence,
'parent': p_name,
'name': report.name,
'balance': res[report.id]['balance'] * int(report.sign),
'type': 'report',
'level': bool(
report.style_overwrite) and report.style_overwrite or
report.level,
'account_type': report.type or False,
# used to underline the financial report balances
}
if data['debit_credit']:
vals['debit'] = res[report.id]['debit']
vals['credit'] = res[report.id]['credit']
if data['enable_filter']:
vals['balance_cmp'] = res[report.id]['comp_bal'] * int(
report.sign)
lines.append(vals)
if report.display_detail == 'no_detail':
# the rest of the loop is
# used to display the details of the
# financial report, so it's not needed here.
continue
if res[report.id].get('account'):
sub_lines = []
for account_id, value \
in res[report.id]['account'].items():
# if there are accounts to display,
# we add them to the lines with a level equals
# to their level in
# the COA + 1 (to avoid having them with a too low level
# that would conflicts with the level of data
# financial reports for Assets, liabilities...)
flag = False
account = self.env['account.account'].browse(account_id)
# new_r_name = str(report.name)
# new_r_name = new_r_name.replace(" ", "-") + "-"
vals = {
'account': account.id,
'a_id': account.code + re.sub('[^0-9a-zA-Z]+', 'acnt',
account.name) + str(
account.id),
'name': account.code + '-' + account.name,
'balance': value['balance'] * int(report.sign) or 0.0,
'type': 'account',
'parent': r_name + str(report.id),
'level': (
report.display_detail == 'detail_with_hierarchy' and
4),
'account_type': account.internal_type,
}
if data['debit_credit']:
vals['debit'] = value['debit']
vals['credit'] = value['credit']
if not account.company_id.currency_id.is_zero(
vals['debit']) or \
not account.company_id.currency_id.is_zero(
vals['credit']):
flag = True
if not account.company_id.currency_id.is_zero(
vals['balance']):
flag = True
if data['enable_filter']:
vals['balance_cmp'] = value['comp_bal'] * int(
report.sign)
if not account.company_id.currency_id.is_zero(
vals['balance_cmp']):
flag = True
if flag:
sub_lines.append(vals)
lines += sorted(sub_lines,
key=lambda sub_line: sub_line['name'])
return lines
def find_journal_items(self, report_lines, form):
cr = self.env.cr
journal_items = []
for i in report_lines:
if i['type'] == 'account':
account = i['account']
if form['target_move'] == 'posted':
search_query = "select aml.id, am.id as j_id, aml.account_id, aml.date," \
" aml.name as label, am.name, " \
+ "(aml.debit-aml.credit) as balance, aml.debit, aml.credit, aml.partner_id " \
+ " from account_move_line aml join account_move am " \
"on (aml.move_id=am.id and am.state=%s) " \
+ " where aml.account_id=%s"
vals = [form['target_move']]
else:
search_query = "select aml.id, am.id as j_id, aml.account_id, aml.date, " \
"aml.name as label, am.name, " \
+ "(aml.debit-aml.credit) as balance, aml.debit, aml.credit, aml.partner_id " \
+ " from account_move_line aml join account_move am on (aml.move_id=am.id) " \
+ " where aml.account_id=%s"
vals = []
if form['date_from'] and form['date_to']:
search_query += " and aml.date>=%s and aml.date<=%s"
vals += [account, form['date_from'], form['date_to']]
elif form['date_from']:
search_query += " and aml.date>=%s"
vals += [account, form['date_from']]
elif form['date_to']:
search_query += " and aml.date<=%s"
vals += [account, form['date_to']]
else:
vals += [account]
cr.execute(search_query, tuple(vals))
items = cr.dictfetchall()
for j in items:
temp = j['id']
j['id'] = re.sub('[^0-9a-zA-Z]+', '', i['name']) + str(
temp)
j['p_id'] = str(i['a_id'])
j['type'] = 'journal_item'
journal_items.append(j)
return journal_items
@api.model
def _get_currency(self):
journal = self.env['account.journal'].browse(
self.env.context.get('default_journal_id', False))
if journal.currency_id:
return journal.currency_id.id
return self.env.user.company_id.currency_id.symbol
class ProfitLossPdf(models.AbstractModel):
""" Abstract model for generating PDF report value and send to template """
_name = 'report.base_accounting_kit.report_financial'
@api.model
def _get_report_values(self, docids, data=None):
""" Provide report values to template """
ctx = {
'data': data,
'journal_items': data['journal_items'],
'report_lines': data['report_lines'],
'account_report': data['form']['account_report_id'][1],
'currency': data['currency'],
}
return ctx

65
base_accounting_kit/wizard/financial_report.xml

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<!-- Financial report common form view -->
<record id="financial_report_wiz_modified" model="ir.ui.view">
<field name="name">financial.report.extended.wiz</field>
<field name="model">financial.report</field>
<field name="arch" type="xml">
<form>
<group>
<group string="Dates">
<field name="date_from"/>
<field name="date_to"/>
</group>
<group>
<field name="target_move" widget="radio"/>
<field name="view_format" widget="radio" invisible="1"/>
<field name="enable_filter" invisible="1"/>
<field name="debit_credit"/>
<field name="company_id" invisible="1"/>
</group>
</group>
<footer>
<button string="Print" name="view_report_pdf" type="object"
class="btn-primary"/>
<button string="Discard" class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for profit and loss -->
<record id="action_profit_and_loss_report" model="ir.actions.act_window">
<field name="name">Profit and Loss</field>
<field name="res_model">financial.report</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">form</field>
<field name="view_id" ref="financial_report_wiz_modified"/>
<field name="target">new</field>
<field name="context"
eval="{'default_account_report_id':ref('base_accounting_kit.account_financial_report_profitandloss0')}"/>
</record>
<!-- Action for balance sheet -->
<record id="action_balance_sheet_report" model="ir.actions.act_window">
<field name="name">Balance Sheet</field>
<field name="res_model">financial.report</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">form</field>
<field name="view_id" ref="financial_report_wiz_modified"/>
<field name="target">new</field>
<field name="context"
eval="{'default_account_report_id':ref('base_accounting_kit.account_financial_report_balancesheet0')}"/>
</record>
<menuitem id="account_financial_reports_profit_loss" sequence="1"
name="Profit and Loss" parent="base_accounting_kit.account_reports_generic_statements"
action="action_profit_and_loss_report"/>
<menuitem id="_account_financial_reports_balance_sheet" sequence="2"
name="Balance Sheet" parent="base_accounting_kit.account_reports_generic_statements"
action="action_balance_sheet_report"/>
</data>
</odoo>

55
base_accounting_kit/wizard/general_ledger.py

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models, _
from odoo.exceptions import UserError
class AccountReportGeneralLedger(models.TransientModel):
_inherit = "account.common.account.report"
_name = "account.report.general.ledger"
_description = "General Ledger Report"
initial_balance = fields.Boolean(string='Include Initial Balances',
help='If you selected date, this field '
'allow you to add a row to display '
'the amount of debit/credit/balance '
'that precedes the filter you\'ve '
'set.')
sortby = fields.Selection(
[('sort_date', 'Date'), ('sort_journal_partner', 'Journal & Partner')],
string='Sort by', required=True, default='sort_date')
journal_ids = fields.Many2many('account.journal',
'account_report_general_ledger_journal_rel',
'account_id', 'journal_id',
string='Journals', required=True)
def _print_report(self, data):
data = self.pre_print_report(data)
data['form'].update(self.read(['initial_balance', 'sortby'])[0])
if data['form'].get('initial_balance') and not data['form'].get(
'date_from'):
raise UserError(_("You must define a Start Date"))
records = self.env[data['model']].browse(data.get('ids', []))
return self.env.ref(
'base_accounting_kit.action_report_general_ledger').with_context(
landscape=True).report_action(records, data=data)

40
base_accounting_kit/wizard/general_ledger.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_report_general_ledger_view" model="ir.ui.view">
<field name="name">General Ledger</field>
<field name="model">account.report.general.ledger</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='target_move']" position="after">
<field name="sortby" widget="radio"/>
<field name="display_account" widget="radio"/>
<field name="initial_balance"/>
<newline/>
</xpath>
</data>
</field>
</record>
<record id="action_account_general_ledger_menu" model="ir.actions.act_window">
<field name="name">General Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.report.general.ledger</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_general_ledger_view"/>
<field name="target">new</field>
<field name="binding_model_id" ref="account.model_account_account" />
<field name="binding_type">report</field>
</record>
<menuitem
id="menu_general_ledger"
name="General Ledger"
sequence="3"
parent="base_accounting_kit.account_reports_audit"
action="action_account_general_ledger_menu"
groups="account.group_account_user,account.group_account_manager"
/>
</odoo>

45
base_accounting_kit/wizard/journal_audit.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2019-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 AFFERO
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class AccountPrintJournal(models.TransientModel):
_inherit = "account.common.journal.report"
_name = "account.print.journal"
_description = "Account Print Journal"
sort_selection = fields.Selection(
[('date', 'Date'), ('move_name', 'Journal Entry Number'), ],
'Entries Sorted by', required=True, default='move_name')
journal_ids = fields.Many2many('account.journal', string='Journals',
required=True,
default=lambda self: self.env[
'account.journal'].search(
[('type', 'in', ['sale', 'purchase'])]))
def _print_report(self, data):
data = self.pre_print_report(data)
data['form'].update({'sort_selection': self.sort_selection})
return self.env.ref(
'base_accounting_kit.action_report_journal').with_context(
landscape=True).report_action(self, data=data)

35
base_accounting_kit/wizard/journal_audit.xml

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_report_print_journal_view" model="ir.ui.view">
<field name="name">Journals Audit</field>
<field name="model">account.print.journal</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='target_move']" position="after">
<field name="amount_currency" groups="base.group_multi_currency"/>
<field name="sort_selection" widget="radio"/>
<newline/>
</xpath>
</data>
</field>
</record>
<record id="action_account_print_journal_menu" model="ir.actions.act_window">
<field name="name">Journals Audit</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.print.journal</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_print_journal_view"/>
<field name="target">new</field>
</record>
<menuitem id="menu_print_journal"
name="Journals Audit"
sequence="9"
action="action_account_print_journal_menu"
parent="base_accounting_kit.account_reports_audit"
groups="account.group_account_manager,account.group_account_user"/>
</odoo>

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

Loading…
Cancel
Save