summaryrefslogtreecommitdiff
path: root/base_accounting_kit/report
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
commit1ca3b3df3421961caec3b747a364071c80f5c7da (patch)
tree6778a1f0f3f9b4c6e26d6d87ccde16e24da6c9d6 /base_accounting_kit/report
parentb57188be371d36d96caac4b8d65a40745c0e972c (diff)
initial commit
Diffstat (limited to 'base_accounting_kit/report')
-rw-r--r--base_accounting_kit/report/__init__.py35
-rw-r--r--base_accounting_kit/report/account_asset_report.py68
-rw-r--r--base_accounting_kit/report/account_asset_report_views.xml77
-rw-r--r--base_accounting_kit/report/account_bank_book.py176
-rw-r--r--base_accounting_kit/report/account_bank_book_view.xml133
-rw-r--r--base_accounting_kit/report/account_cash_book.py167
-rw-r--r--base_accounting_kit/report/account_cash_book_view.xml108
-rw-r--r--base_accounting_kit/report/account_day_book.py125
-rw-r--r--base_accounting_kit/report/account_day_book_view.xml115
-rw-r--r--base_accounting_kit/report/account_report_common_account.py38
-rw-r--r--base_accounting_kit/report/cash_flow_report.py217
-rw-r--r--base_accounting_kit/report/cash_flow_report.xml88
-rw-r--r--base_accounting_kit/report/general_ledger_report.py172
-rw-r--r--base_accounting_kit/report/general_ledger_report.xml107
-rw-r--r--base_accounting_kit/report/multiple_invoice_layouts.xml552
-rw-r--r--base_accounting_kit/report/multiple_invoice_report.py37
-rw-r--r--base_accounting_kit/report/multiple_invoice_report.xml260
-rw-r--r--base_accounting_kit/report/report.xml96
-rw-r--r--base_accounting_kit/report/report_aged_partner.py303
-rw-r--r--base_accounting_kit/report/report_aged_partner.xml98
-rw-r--r--base_accounting_kit/report/report_financial.py119
-rw-r--r--base_accounting_kit/report/report_financial.xml146
-rw-r--r--base_accounting_kit/report/report_journal_audit.py158
-rw-r--r--base_accounting_kit/report/report_journal_audit.xml150
-rw-r--r--base_accounting_kit/report/report_partner_ledger.py156
-rw-r--r--base_accounting_kit/report/report_partner_ledger.xml107
-rw-r--r--base_accounting_kit/report/report_tax.py115
-rw-r--r--base_accounting_kit/report/report_tax.xml75
-rw-r--r--base_accounting_kit/report/report_trial_balance.py109
-rw-r--r--base_accounting_kit/report/report_trial_balance.xml71
30 files changed, 4178 insertions, 0 deletions
diff --git a/base_accounting_kit/report/__init__.py b/base_accounting_kit/report/__init__.py
new file mode 100644
index 0000000..e96b59f
--- /dev/null
+++ b/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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+from . import 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
+from . import multiple_invoice_report
diff --git a/base_accounting_kit/report/account_asset_report.py b/base_accounting_kit/report/account_asset_report.py
new file mode 100644
index 0000000..7917958
--- /dev/null
+++ b/base_accounting_kit/report/account_asset_report.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, 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='# of Installment Lines', readonly=True)
+ depreciation_nbr = fields.Integer(string='# of Depreciation Lines', 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
+ )""")
diff --git a/base_accounting_kit/report/account_asset_report_views.xml b/base_accounting_kit/report/account_asset_report_views.xml
new file mode 100644
index 0000000..b9cbea4
--- /dev/null
+++ b/base_accounting_kit/report/account_asset_report_views.xml
@@ -0,0 +1,77 @@
+<?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"/>
+ <filter string="Not archived" name="only_active" domain="[('asset_id.active','=', True)]"/>
+ <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="search_view_id" ref="view_asset_asset_report_search"/>
+ <field name="domain">[('asset_category_id.type', '=', 'purchase')]</field>
+ <field name="context">{'search_default_only_active': 1}</field>
+ <field name="help" type="html">
+ <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>
diff --git a/base_accounting_kit/report/account_bank_book.py b/base_accounting_kit/report/account_bank_book.py
new file mode 100644
index 0000000..7c050c7
--- /dev/null
+++ b/base_accounting_kit/report/account_bank_book.py
@@ -0,0 +1,176 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+from 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'
+ _description = 'Bank Book Report'
+
+ 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[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)])
+ if not accounts:
+ journals = self.env['account.journal'].search([('type', '=', 'bank')])
+ accounts = []
+ for journal in journals:
+ accounts.append(journal.payment_credit_account_id.id)
+ accounts = self.env['account.account'].search([('id', 'in', accounts)])
+
+ 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': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'Accounts': accounts_res,
+ 'print_journal': codes,
+ }
diff --git a/base_accounting_kit/report/account_bank_book_view.xml b/base_accounting_kit/report/account_bank_book_view.xml
new file mode 100644
index 0000000..b4410ae
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['balance']"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['balance']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td t-if="line['amount_currency']" 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>
diff --git a/base_accounting_kit/report/account_cash_book.py b/base_accounting_kit/report/account_cash_book.py
new file mode 100644
index 0000000..2c89c52
--- /dev/null
+++ b/base_accounting_kit/report/account_cash_book.py
@@ -0,0 +1,167 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+from 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'
+ _description = 'Cash Book Report'
+
+ 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')
+ if not accounts:
+ journals = self.env['account.journal'].search([('type', '=', 'cash')])
+ accounts = []
+ for journal in journals:
+ accounts.append(journal.payment_credit_account_id.id)
+ accounts = self.env['account.account'].search([('id','in',accounts)])
+
+ # 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[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)])
+ if not accounts:
+ journals = self.env['account.journal'].search([('type', '=', 'cash')])
+ accounts = []
+ for journal in journals:
+ accounts.append(journal.payment_credit_account_id.id)
+ accounts = self.env['account.account'].search([('id', 'in', accounts)])
+ 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': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'Accounts': accounts_res,
+ 'print_journal': codes,
+ }
diff --git a/base_accounting_kit/report/account_cash_book_view.xml b/base_accounting_kit/report/account_cash_book_view.xml
new file mode 100644
index 0000000..e26ae7e
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['balance']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td t-if="line['amount_currency']" 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>
diff --git a/base_accounting_kit/report/account_day_book.py b/base_accounting_kit/report/account_day_book.py
new file mode 100644
index 0000000..fcc7e8b
--- /dev/null
+++ b/base_accounting_kit/report/account_day_book.py
@@ -0,0 +1,125 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+import 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'
+ _description = 'Day Book Report'
+
+ 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[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': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'Accounts': record,
+ 'print_journal': codes,
+ }
diff --git a/base_accounting_kit/report/account_day_book_view.xml b/base_accounting_kit/report/account_day_book_view.xml
new file mode 100644
index 0000000..8d80aad
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['balance']"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['balance']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td t-if="line['amount_currency']" 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>
+
diff --git a/base_accounting_kit/report/account_report_common_account.py b/base_accounting_kit/report/account_report_common_account.py
new file mode 100644
index 0000000..1c359e2
--- /dev/null
+++ b/base_accounting_kit/report/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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+from 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')
+
+ def pre_print_report(self, data):
+ data['form'].update(self.read(['display_account'])[0])
+ return data
diff --git a/base_accounting_kit/report/cash_flow_report.py b/base_accounting_kit/report/cash_flow_report.py
new file mode 100644
index 0000000..f4af93f
--- /dev/null
+++ b/base_accounting_kit/report/cash_flow_report.py
@@ -0,0 +1,217 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import time
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportFinancial(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_cash_flow'
+ _description = 'Cash Flow Report'
+
+ 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[model].browse(self.env.context.get('active_id'))
+ report_lines = self.get_account_lines(data.get('form'))
+ return {
+ 'doc_ids': self.ids,
+ 'doc_model': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'get_account_lines': report_lines,
+ }
diff --git a/base_accounting_kit/report/cash_flow_report.xml b/base_accounting_kit/report/cash_flow_report.xml
new file mode 100644
index 0000000..839767d
--- /dev/null
+++ b/base_accounting_kit/report/cash_flow_report.xml
@@ -0,0 +1,88 @@
+<?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">
+ <thead>
+ <tr>
+ <th>
+ <strong>Name</strong>
+ </th>
+ <th class="text-right" t-if="data['debit_credit']">
+ <strong>Debit</strong>
+ </th>
+ <th class="text-right" t-if="data['debit_credit']">
+ <strong>Credit</strong>
+ </th>
+ <th class="text-right">
+ <strong>Balance</strong>
+ </th>
+ <th class="text-right" t-if="data['enable_filter']">
+ <strong 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="'..' * a.get('level', 0)"/>
+ <span t-att-style="style" t-esc="a.get('name')"/>
+ </td>
+ <td t-if="data['debit_credit']" class="text-right" style="white-space: text-nowrap;">
+ <span t-att-style="style" t-esc="a.get('debit')" t-if="data['debit_credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td t-if="data['debit_credit']" class="text-right" style="white-space: text-nowrap;">
+ <span t-att-style="style" t-esc="a.get('credit')"
+ t-if="data['debit_credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-att-style="style" t-esc="a.get('balance_cmp')"
+ t-if="data['enable_filter']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ </t>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </t>
+ </t>
+ </t>
+ </template>
+</odoo>
diff --git a/base_accounting_kit/report/general_ledger_report.py b/base_accounting_kit/report/general_ledger_report.py
new file mode 100644
index 0000000..f4e4b4e
--- /dev/null
+++ b/base_accounting_kit/report/general_ledger_report.py
@@ -0,0 +1,172 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import time
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportGeneralLedger(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_general_ledger'
+ _description = 'General Ledger Report'
+
+ 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[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 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': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'Accounts': accounts_res,
+ 'print_journal': codes,
+ }
diff --git a/base_accounting_kit/report/general_ledger_report.xml b/base_accounting_kit/report/general_ledger_report.xml
new file mode 100644
index 0000000..ef78eba
--- /dev/null
+++ b/base_accounting_kit/report/general_ledger_report.xml
@@ -0,0 +1,107 @@
+<?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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['balance']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <t t-if="line['amount_currency']">
+ <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>
+ </t>
+ </tr>
+ </t>
+ </tbody>
+ </table>
+ </div>
+ </t>
+ </t>
+ </template>
+</odoo>
diff --git a/base_accounting_kit/report/multiple_invoice_layouts.xml b/base_accounting_kit/report/multiple_invoice_layouts.xml
new file mode 100644
index 0000000..b88c2b9
--- /dev/null
+++ b/base_accounting_kit/report/multiple_invoice_layouts.xml
@@ -0,0 +1,552 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+
+ <template id="base_accounting_kit.standard">
+ <div t-attf-class="header o_company_#{company.id}_layout" t-att-style="report_header_style">
+ <div class="row">
+ <div class="col-3 mb4">
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" style="max-height: 45px;" alt="Logo"/>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div class="row">
+ <div t-if="txt_align == 'left'" class="text-left">
+ <span t-esc="mi.copy_name" style="font-size: 20px; padding-left:25px; white-space:nowrap;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-center">
+ <span t-esc="mi.copy_name" style="font-size: 20px;
+ margin-left:340px; margin-right:340px; white-space:nowrap;"/>
+ </div>
+ </div>
+
+ </t>
+ </t>
+ </div>
+ <div class="col-9 text-right" style="margin-top:22px;" t-field="company.report_header" name="moto"/>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'right'" class="col-9 text-right">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+ </t>
+ </t>
+
+ </div>
+ <div t-if="company.logo or company.report_header" class="row zero_min_height">
+ <div class="col-12">
+ <div style="border-bottom: 1px solid black;"/>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-6" name="company_address">
+ <div t-field="company.partner_id"
+ t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}'
+ />
+ </div>
+ </div>
+<!--Watermark-->
+ <t t-if="mi_type =='watermark'">
+ <div style="opacity:0.15; font-size:100px; width:85%; text-align:center;top:500px; right:100px; position: fixed; z-index:99; -webkit-transform: rotate(-30deg);">
+ <t t-esc="mi.copy_name"/>
+ </div>
+ </t>
+ </div>
+
+ <div t-attf-class="article o_report_layout_standard o_company_#{company.id}_layout" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id" t-att-data-oe-lang="o and o.env.context.get('lang')">
+ <div class="pt-5">
+ <!-- This div ensures that the address is not cropped by the header. -->
+ <t t-call="web.address_layout"/>
+ </div>
+ <t t-raw="0"/>
+ </div>
+
+ <div t-attf-class="footer o_standard_footer o_company_#{company.id}_layout">
+ <div class="text-center" style="border-top: 1px solid black;">
+ <ul class="list-inline mb4">
+ <!-- using the list-inline-item class from bootstrap causes weird behaviours in pdf report
+ adding d-inline class fixes the problem-->
+ <li t-if="company.phone" class="list-inline-item d-inline"><span class="o_force_ltr" t-field="company.phone"/></li>
+ <li t-if="company.email" class="list-inline-item d-inline"><span t-field="company.email"/></li>
+ <li t-if="company.website" class="list-inline-item d-inline"><span t-field="company.website"/></li>
+ <li t-if="company.vat" class="list-inline-item d-inline"><t t-esc="company.country_id.vat_label or 'Tax ID'"/>: <span t-field="company.vat"/></li>
+
+<!--Footer-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'footer'">
+ <div t-if="txt_align == 'right'" class="text-right">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+ <div t-if="txt_align == 'left'" class="text-left">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-center;">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+
+ </t>
+ </t>
+
+ </ul>
+
+ <div name="financial_infos">
+ <span t-field="company.report_footer"/>
+ </div>
+
+ <div t-if="report_type == 'pdf'" class="text-muted">
+ Page: <span class="page"/> / <span class="topage"/>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ <template id="base_accounting_kit.boxed">
+ <div t-attf-class="header o_company_#{company.id}_layout" t-att-style="report_header_style">
+ <div class="o_boxed_header">
+ <div class="row mb8">
+ <div class="col-6">
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'left'">
+ <span t-esc="mi.copy_name" style="font-size: 25px; white-space:nowrap;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-align: center">
+ <span t-esc="mi.copy_name" style="font-size: 25px;
+ margin-left:340px; margin-right:340px; white-space:nowrap;"/>
+ </div>
+ </t>
+ </t>
+
+ </div>
+
+
+ <div class="col-6 text-right mb4">
+ <h4 class="mt0" t-field="company.report_header"/>
+ <div name="company_address" class="float-right mb4">
+ <span class="company_address" t-field="company.partner_id"
+ t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}'/>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'right'" class="float-right mb4">
+ <span t-esc="mi.copy_name" style="font-size: 25px;"/>
+ </div>
+
+ </t>
+ </t>
+ <br/>
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+<!--Watermark-->
+ <t t-if="mi_type =='watermark'">
+ <div style="opacity:0.15; font-size:100px; width:85%; text-align:center;top:500px; right:100px; position: fixed; z-index:99; -webkit-transform: rotate(-30deg);">
+ <t t-esc="mi.copy_name"/>
+ </div>
+ </t>
+ </div>
+
+ <div t-attf-class="article o_report_layout_boxed o_company_#{company.id}_layout" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id" t-att-data-oe-lang="o and o.env.context.get('lang')">
+ <div class="pt-5">
+ <!-- This div ensures that the address is not cropped by the header. -->
+ <t t-call="web.address_layout"/>
+ </div>
+ <t t-raw="0"/>
+ </div>
+
+ <div t-attf-class="footer o_boxed_footer o_company_#{company.id}_layout">
+ <div class="text-center">
+ <ul class="list-inline">
+ <li t-if="company.phone" class="list-inline-item"><span class="o_force_ltr" t-field="company.phone"/></li>
+ <li t-if="company.email" class="list-inline-item"><span t-field="company.email"/></li>
+ <li t-if="company.website" class="list-inline-item"><span t-field="company.website"/></li>
+ <li t-if="company.vat" class="list-inline-item"><t t-esc="company.country_id.vat_label or 'Tax ID'"/>: <span t-field="company.vat"/></li>
+ </ul>
+ <div t-field="company.report_footer"/>
+<!--Footer-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'footer'">
+ <div t-if="txt_align == 'right'" class="text-right">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+ <div t-if="txt_align == 'left'" class="text-left">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-center;">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+
+ </t>
+ </t>
+
+
+ <div t-if="report_type == 'pdf'">
+ Page: <span class="page"/> / <span class="topage"/>
+ </div>
+ </div>
+ </div>
+
+ </template>
+
+ <template id="base_accounting_kit.clean">
+ <div t-attf-class="header o_company_#{company.id}_layout" t-att-style="report_header_style">
+ <div class="o_clean_header">
+ <div class="row">
+ <div class="col-6">
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'left'">
+ <br/>
+ <span t-esc="mi.copy_name" style="font-size: 20px; padding-left:25px; white-space:nowrap;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-align: center">
+ <br/>
+ <span t-esc="mi.copy_name" style="font-size: 20px;
+ margin-left:280px; margin-right:280px; white-space:nowrap;"/>
+ </div>
+ </t>
+ </t>
+ </div>
+ <div class="col-5 offset-1" name="company_address">
+ <ul class="list-unstyled">
+ <strong><li t-if="company.name"><span t-field="company.name"/></li></strong>
+ <li t-if="company.vat"><t t-esc="company.country_id.vat_label or 'Tax ID'"/>: <span t-field="company.vat"/></li>
+ <li t-if="company.phone">Tel: <span class="o_force_ltr" t-field="company.phone"/></li>
+ <li t-if="company.email"><span t-field="company.email"/></li>
+ <li t-if="company.website"><span t-field="company.website"/></li>
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'right'">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+
+ </t>
+ </t>
+
+ </ul>
+
+ </div>
+ </div>
+ </div>
+<!--Watermark-->
+ <t t-if="mi_type =='watermark'">
+ <div style="opacity:0.15; font-size:100px; width:85%; text-align:center;top:500px; right:100px; position: fixed; z-index:99; -webkit-transform: rotate(-30deg);">
+ <t t-esc="mi.copy_name"/>
+ </div>
+ </t>
+ </div>
+
+ <div t-attf-class="article o_report_layout_clean o_company_#{company.id}_layout" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id" t-att-data-oe-lang="o and o.env.context.get('lang')">
+ <t t-call="web.address_layout"/>
+ <t t-raw="0"/>
+ </div>
+
+ <div t-attf-class="footer o_clean_footer o_company_#{company.id}_layout">
+ <div class="row mt8">
+<!--Footer-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'footer'">
+ <div t-if="txt_align == 'left'" class="text-left">
+ <span t-esc="mi.copy_name" style="font-size: 18px; padding-left:25px; white-space:nowrap;"/>
+ </div>
+ </t>
+ </t>
+ <div class="col-3">
+ <span t-field="company.report_footer"/>
+ </div>
+
+ <div class="col-4 text-right">
+ <span class="company_address" t-field="company.partner_id"
+ t-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
+ </div>
+ <div class="col-4">
+ <h4 class="mt0 mb0 text-uppercase" t-field="company.report_header"/>
+<!--Footer-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'footer'">
+ <div t-if="txt_align == 'right'" class="text-right">
+ <span t-esc="mi.copy_name" style="font-size: 18px;"/>
+ </div>
+
+ <div t-if="txt_align == 'center'" class="text-center;">
+ <span t-esc="mi.copy_name" style="font-size: 18px;"/>
+ </div>
+
+ </t>
+ </t>
+
+ </div>
+
+ <div class="col-1">
+ <ul t-if="report_type == 'pdf'" class="list-inline pagenumber float-right text-center">
+ <li class="list-inline-item"><strong><span class="page"/></strong></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ <template id="base_accounting_kit.background">
+ <div t-attf-class="o_company_#{company.id}_layout header" t-att-style="report_header_style">
+ <div class="o_background_header">
+ <div class="float-right">
+ <h3 class="mt0 text-right" t-field="company.report_header"/>
+ </div>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" class="float-left" alt="Logo"/>
+ <div class="float-left company_address">
+ <div>
+ <strong t-field="company.partner_id.name"/>
+ </div>
+ <span t-field="company.partner_id"
+ t-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
+ </div>
+
+<!--Header-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'header'">
+ <div t-if="txt_align == 'right'" class="text-right" style="position: relative; top: 50px;">
+ <span t-esc="mi.copy_name" style="font-size: 20px;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-center">
+ <br/>
+ <span t-esc="mi.copy_name" style="font-size: 20px;
+ margin-left:280px; margin-right:280px; white-space:nowrap;"/>
+ </div>
+ <div t-if="txt_align == 'left'" class="text-left" style="position: fixed; top: 70px; left:20px;">
+ <br/>
+ <span t-esc="mi.copy_name" style="font-size: 20px; white-space:nowrap;"/>
+ </div>
+
+ </t>
+ </t>
+
+ <div class="clearfix mb8"/>
+ </div>
+<!--Watermark-->
+ <t t-if="mi_type =='watermark'">
+ <div style="opacity:0.15; font-size:100px; width:85%; text-align:center;top:500px; right:100px; position: fixed; z-index:99; -webkit-transform: rotate(-30deg);">
+ <t t-esc="mi.copy_name"/>
+ </div>
+ </t>
+ </div>
+
+ <div t-attf-class="o_company_#{company.id}_layout article o_report_layout_background" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id" t-att-data-oe-lang="o and o.env.context.get('lang')">
+ <t t-call="web.address_layout"/>
+ <t t-raw="0"/>
+ </div>
+
+ <div t-attf-class="o_company_#{company.id}_layout footer o_background_footer">
+ <div class="text-center">
+ <ul class="list-inline">
+ <li t-if="company.phone" class="list-inline-item"><i class="fa fa-phone" role="img" aria-label="Phone" title="Phone"/> <span class="o_force_ltr" t-field="company.phone"/></li>
+ <li t-if="company.email" class="list-inline-item"><i class="fa fa-at" role="img" aria-label="Email" title="Email"/> <span t-field="company.email"/></li>
+ <li t-if="company.website" class="list-inline-item"><i class="fa fa-globe" role="img" aria-label="Website" title="Website"/> <span t-field="company.website"/></li>
+ <li t-if="company.vat" class="list-inline-item"><i class="fa fa-building-o" role="img" aria-label="Fiscal number"/><t t-esc="company.country_id.vat_label or 'Tax ID'"/>: <span t-field="company.vat"/></li>
+ </ul>
+ <div t-field="company.report_footer"/>
+
+<!--Footer-->
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'footer'">
+ <div t-if="txt_align == 'right'" class="text-right">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+ <div t-if="txt_align == 'left'" class="text-left">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+ <div t-if="txt_align == 'center'" class="text-center;">
+ <span t-esc="mi.copy_name" style="font-size: 15px;"/>
+ </div>
+
+ </t>
+ </t>
+ <div t-if="report_type == 'pdf'" class="text-muted">
+ Page:
+ <span class="page"/>
+ of
+ <span class="topage"/>
+ </div>
+ </div>
+ </div>
+ </template>
+
+
+ <template id="multiple_invoice_wizard_preview">
+ <t t-call="web.html_preview_container">
+ <t t-call="base_accounting_kit.new_external_layout">
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'body'">
+ <div t-if="body_txt_position == 'tr'" style="font-size:25px; text-align:right;">
+ <span>Sample Name</span>
+ </div>
+ <div t-if="body_txt_position == 'tl'" style="font-size:25px; text-align:left;">
+ <span>Sample Name</span>
+ </div>
+
+ </t>
+ </t>
+ <div class="pt-5">
+ <div class="address row">
+ <div name="address" class="col-md-5 ml-auto">
+ <address>
+ <address class="mb-0" itemscope="itemscope"
+ itemtype="http://schema.org/Organization">
+ <div>
+ <span itemprop="name">Deco Addict</span>
+ </div>
+ <div itemprop="address" itemscope="itemscope"
+ itemtype="http://schema.org/PostalAddress">
+ <div class="d-flex align-items-baseline">
+ <span class="w-100 o_force_ltr" itemprop="streetAddress">77 Santa Barbara
+ Rd<br/>Pleasant Hill CA 94523<br/>United States</span>
+ </div>
+ </div>
+ </address>
+ </address>
+ </div>
+ </div>
+ </div>
+ <div class="page">
+ <h2>
+ <span>Invoice</span>
+ <span>INV/2020/07/0003</span>
+ </h2>
+ <div id="informations" class="row mt32 mb32">
+ <div class="col-auto mw-100 mb-2" name="invoice_date">
+ <strong>Invoice Date:</strong>
+ <p class="m-0">07/08/2020</p>
+ </div>
+ <div class="col-auto mw-100 mb-2" name="due_date">
+ <strong>Due Date:</strong>
+ <p class="m-0">08/07/2020</p>
+ </div>
+ </div>
+ <table class="table table-sm o_main_table" name="invoice_line_table">
+ <thead>
+ <tr>
+ <th name="th_description" class="text-left"><span>Description</span></th>
+ <th name="th_quantity" class="text-right"><span>Quantity</span></th>
+ <th name="th_priceunit" class="text-right d-none d-md-table-cell"><span>Unit Price</span></th>
+ <th name="th_taxes" class="text-left d-none d-md-table-cell"><span>Taxes</span></th>
+ <th name="th_subtotal" class="text-right">
+ <span>Amount</span>
+ </th>
+ </tr>
+ </thead>
+ <tbody class="invoice_tbody">
+ <tr>
+ <td name="account_invoice_line_name"><span>[FURN_8999] Three-Seat Sofa<br/>
+ Three Seater Sofa with Lounger in Steel Grey Colour</span></td>
+ <td class="text-right">
+ <span>5.000</span>
+ </td>
+ <td class="text-right d-none d-md-table-cell">
+ <span class="text-nowrap">1,500.00</span>
+ </td>
+ <td class="text-left d-none d-md-table-cell">
+ <span id="line_tax_ids">15.00%</span>
+ </td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap">$ <span class="oe_currency_value">7,500.00</span></span>
+ </td>
+ </tr>
+ <tr>
+ <td name="account_invoice_line_name"><span>[FURN_8220] Four Person Desk<br/>
+ Four person modern office workstation</span></td>
+ <td class="text-right">
+ <span>5.000</span>
+ </td>
+ <td class="text-right d-none d-md-table-cell">
+ <span class="text-nowrap">23,500.00</span>
+ </td>
+ <td class="text-left d-none d-md-table-cell">
+ <span id="line_tax_ids">15.00%</span>
+ </td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap">$ <span class="oe_currency_value">117,500.00</span></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="clearfix">
+ <div id="total" class="row">
+ <div class="col-sm-7 col-md-6 ml-auto">
+ <table class="table table-sm" style="page-break-inside: avoid;">
+ <tbody><tr class="border-black o_subtotal" style="">
+ <td><strong>Subtotal</strong></td>
+ <td class="text-right">
+ <span>$ <span class="oe_currency_value">125,000.00</span></span>
+ </td>
+ </tr>
+ <tr style="">
+ <td><span class="text-nowrap">Tax 15%</span></td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap">$ 18,750.00</span>
+ </td>
+ </tr>
+ <tr class="border-black o_total">
+ <td><strong>Total</strong></td>
+ <td class="text-right">
+ <span class="text-nowrap">$ <span class="oe_currency_value">
+ 143,750.00</span></span>
+ </td>
+ </tr>
+ </tbody></table>
+ </div>
+ </div>
+ </div>
+ <p>
+ Please use the following communication for your payment : <b><span>
+ INV/2020/07/0003</span></b>
+ </p>
+ <p name="payment_term">
+ <span>Payment terms: 300 Days</span>
+ </p>
+
+ <t t-if="mi_type == 'text'">
+ <t t-if="txt_position == 'body'">
+ <div t-if="body_txt_position == 'br'" style="font-size:25px; text-align:right;">
+ <span>Sample Name</span>
+ </div>
+ <div t-if="body_txt_position == 'bl'" style="font-size:25px; text-align:left;">
+ <span>Sample Name</span>
+ </div>
+
+ </t>
+ </t>
+ </div>
+ </t>
+ </t>
+ </template>
+
+ <template id="new_external_layout">
+ <t t-if="not o" t-set="o" t-value="doc"/>
+
+ <t t-if="not company">
+ <!-- Multicompany -->
+ <t t-if="company_id">
+ <t t-set="company" t-value="company_id"/>
+ </t>
+ <t t-elif="o and 'company_id' in o">
+ <t t-set="company" t-value="o.company_id.sudo()"/>
+ </t>
+ <t t-else="else">
+ <t t-set="company" t-value="res_company"/>
+ </t>
+ </t>
+
+ <t t-if="layout" t-call="{{layout}}"><t t-raw="0"/></t>
+ <t t-else="else" t-call="base_accounting_kit.standard"><t t-raw="0"/></t>
+
+ </template>
+
+</odoo> \ No newline at end of file
diff --git a/base_accounting_kit/report/multiple_invoice_report.py b/base_accounting_kit/report/multiple_invoice_report.py
new file mode 100644
index 0000000..aa18558
--- /dev/null
+++ b/base_accounting_kit/report/multiple_invoice_report.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+from odoo import models, api
+
+
+class ReportInvoiceMultiple(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_multiple_invoice'
+ _inherit = 'report.account.report_invoice'
+
+ @api.model
+ def _get_report_values(self, docids, data=None):
+ rslt = super()._get_report_values(docids, data)
+
+ inv = rslt['docs']
+ layout = inv.journal_id.company_id.external_report_layout_id.key
+
+ if layout == 'web.external_layout_boxed':
+ new_layout = 'base_accounting_kit.boxed'
+
+ elif layout == 'web.external_layout_clean':
+ new_layout = 'base_accounting_kit.clean'
+
+ elif layout == 'web.external_layout_background':
+ new_layout = 'base_accounting_kit.background'
+
+ else:
+ new_layout = 'base_accounting_kit.standard'
+
+ rslt['mi_type'] = inv.journal_id.multiple_invoice_type
+ rslt['mi_ids'] = inv.journal_id.multiple_invoice_ids
+ rslt['txt_position'] = inv.journal_id.text_position
+ rslt['body_txt_position'] = inv.journal_id.body_text_position
+ rslt['txt_align'] = inv.journal_id.text_align
+ rslt['layout'] = new_layout
+
+ rslt['report_type'] = data.get('report_type') if data else ''
+ return rslt
diff --git a/base_accounting_kit/report/multiple_invoice_report.xml b/base_accounting_kit/report/multiple_invoice_report.xml
new file mode 100644
index 0000000..e582752
--- /dev/null
+++ b/base_accounting_kit/report/multiple_invoice_report.xml
@@ -0,0 +1,260 @@
+<odoo>
+
+ <template id="report_multiple_invoice_new">
+
+ <t t-call="base_accounting_kit.new_external_layout">
+ <t t-set="o" t-value="o.with_context(lang=lang)" />
+
+ <t t-set="address">
+ <address t-field="o.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' />
+ <div t-if="o.partner_id.vat" class="mt16">
+ <t t-if="o.company_id.country_id.vat_label" t-esc="o.company_id.country_id.vat_label" id="inv_tax_id_label"/>
+ <t t-else="">Tax ID</t>: <span t-field="o.partner_id.vat"/></div>
+ </t>
+ <div class="page">
+
+ <t t-set="txt_style" t-value="'font-size:25px; text-align:center;top:0px; left:15px; position:absolute; z-index:99;'"/>
+ <t t-if="body_txt_position == 'tr'">
+ <t t-set="txt_style" t-value="'font-size:25px; text-align:center;top:0px; right:15px; position:absolute; z-index:99;'"/>
+ </t>
+ <t t-if="body_txt_position == 'br'">
+ <t t-set="txt_style" t-value="'font-size:25px; text-align:right;'"/>
+ </t>
+ <t t-if="body_txt_position == 'bl'">
+ <t t-set="txt_style" t-value="'font-size:25px; text-align:left;'"/>
+ </t>
+
+ <h2>
+ <span t-if="o.move_type == 'out_invoice' and o.state == 'posted'">Invoice</span>
+ <span t-if="o.move_type == 'out_invoice' and o.state == 'draft'">Draft Invoice</span>
+ <span t-if="o.move_type == 'out_invoice' and o.state == 'cancel'">Cancelled Invoice</span>
+ <span t-if="o.move_type == 'out_refund'">Credit Note</span>
+ <span t-if="o.move_type == 'in_refund'">Vendor Credit Note</span>
+ <span t-if="o.move_type == 'in_invoice'">Vendor Bill</span>
+ <span t-if="o.name != '/'" t-field="o.name"/>
+ </h2>
+
+ <div id="informations" class="row mt32 mb32">
+ <div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_date" name="invoice_date">
+ <strong>Invoice Date:</strong>
+ <p class="m-0" t-field="o.invoice_date"/>
+ </div>
+ <div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_date_due and o.move_type == 'out_invoice' and o.state == 'posted'" name="due_date">
+ <strong>Due Date:</strong>
+ <p class="m-0" t-field="o.invoice_date_due"/>
+ </div>
+ <div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_origin" name="origin">
+ <strong>Source:</strong>
+ <p class="m-0" t-field="o.invoice_origin"/>
+ </div>
+ <div class="col-auto col-3 mw-100 mb-2" t-if="o.partner_id.ref" name="customer_code">
+ <strong>Customer Code:</strong>
+ <p class="m-0" t-field="o.partner_id.ref"/>
+ </div>
+ <div class="col-auto col-3 mw-100 mb-2" t-if="o.ref" name="reference">
+ <strong>Reference:</strong>
+ <p class="m-0" t-field="o.ref"/>
+ </div>
+ </div>
+
+ <t t-set="display_discount" t-value="any(l.discount for l in o.invoice_line_ids)"/>
+
+ <table class="table table-sm o_main_table" name="invoice_line_table">
+ <thead>
+ <tr>
+ <th name="th_description" class="text-left"><span>Description</span></th>
+ <th name="th_quantity" class="text-right"><span>Quantity</span></th>
+ <th name="th_priceunit" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Unit Price</span></th>
+ <th name="th_price_unit" t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
+ <span>Disc.%</span>
+ </th>
+ <th name="th_taxes" t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Taxes</span></th>
+ <th name="th_subtotal" class="text-right">
+ <span groups="account.group_show_line_subtotals_tax_excluded">Amount</span>
+ <span groups="account.group_show_line_subtotals_tax_included">Total Price</span>
+ </th>
+ </tr>
+ </thead>
+ <tbody class="invoice_tbody">
+ <t t-set="current_subtotal" t-value="0"/>
+ <t t-set="lines" t-value="o.invoice_line_ids.sorted(key=lambda l: (-l.sequence, l.date, l.move_name, -l.id), reverse=True)"/>
+
+ <t t-foreach="lines" t-as="line">
+ <t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
+ <t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
+
+ <tr t-att-class="'bg-200 font-weight-bold o_line_section' if line.display_type == 'line_section' else 'font-italic o_line_note' if line.display_type == 'line_note' else ''">
+ <t t-if="not line.display_type" name="account_invoice_line_accountable">
+ <td name="account_invoice_line_name"><span t-field="line.name" t-options="{'widget': 'text'}"/></td>
+ <td class="text-right">
+ <span t-field="line.quantity"/>
+ <span t-field="line.product_uom_id" groups="uom.group_uom"/>
+ </td>
+ <td t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
+ <span class="text-nowrap" t-field="line.price_unit"/>
+ </td>
+ <td t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
+ <span class="text-nowrap" t-field="line.discount"/>
+ </td>
+ <td t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
+ <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_ids))" id="line_tax_ids"/>
+ </td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap" t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
+ <span class="text-nowrap" t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
+ </td>
+ </t>
+ <t t-if="line.display_type == 'line_section'">
+ <td colspan="99">
+ <span t-field="line.name" t-options="{'widget': 'text'}"/>
+ </td>
+ <t t-set="current_section" t-value="line"/>
+ <t t-set="current_subtotal" t-value="0"/>
+ </t>
+ <t t-if="line.display_type == 'line_note'">
+ <td colspan="99">
+ <span t-field="line.name" t-options="{'widget': 'text'}"/>
+ </td>
+ </t>
+ </tr>
+
+ <t t-if="current_section and (line_last or lines[line_index+1].display_type == 'line_section')">
+ <tr class="is-subtotal text-right">
+ <td colspan="99">
+ <strong class="mr16">Subtotal</strong>
+ <span
+ t-esc="current_subtotal"
+ t-options='{"widget": "monetary", "display_currency": o.currency_id}'
+ />
+ </td>
+ </tr>
+ </t>
+ </t>
+ </tbody>
+ </table>
+
+ <div class="clearfix">
+ <div id="total" class="row">
+ <div t-attf-class="#{'col-6' if report_type != 'html' else 'col-sm-7 col-md-6'} ml-auto">
+ <table class="table table-sm" style="page-break-inside: avoid;">
+ <tr class="border-black o_subtotal" style="">
+ <td><strong>Subtotal</strong></td>
+ <td class="text-right">
+ <span t-field="o.amount_untaxed"/>
+ </td>
+ </tr>
+ <t t-foreach="o.amount_by_group" t-as="amount_by_group">
+ <tr style="">
+ <t t-if="len(o.line_ids.filtered(lambda line: line.tax_line_id)) in [0, 1] and o.amount_untaxed == amount_by_group[2]">
+ <td><span class="text-nowrap" t-esc="amount_by_group[0]"/></td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap" t-esc="amount_by_group[3]" />
+ </td>
+ </t>
+ <t t-else="">
+ <td>
+ <span t-esc="amount_by_group[0]"/>
+ <span class="text-nowrap"> on
+ <t t-esc="amount_by_group[4]"/>
+ </span>
+ </td>
+ <td class="text-right o_price_total">
+ <span class="text-nowrap" t-esc="amount_by_group[3]"/>
+ </td>
+ </t>
+ </tr>
+ </t>
+ <tr class="border-black o_total">
+ <td><strong>Total</strong></td>
+ <td class="text-right">
+ <span class="text-nowrap" t-field="o.amount_total"/>
+ </td>
+ </tr>
+ <t t-if="print_with_payments">
+ <t t-if="o.payment_state != 'invoicing_legacy'">
+ <t t-set="payments_vals" t-value="o.sudo()._get_reconciled_info_JSON_values()"/>
+ <t t-foreach="payments_vals" t-as="payment_vals">
+ <tr>
+ <td>
+ <i class="oe_form_field text-right oe_payment_label">Paid on <t t-esc="payment_vals['date']" t-options='{"widget": "date"}'/></i>
+ </td>
+ <td class="text-right">
+ <span t-esc="payment_vals['amount']" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
+ </td>
+ </tr>
+ </t>
+ <t t-if="len(payments_vals) > 0">
+ <tr class="border-black">
+ <td><strong>Amount Due</strong></td>
+ <td class="text-right">
+ <span t-field="o.amount_residual"/>
+ </td>
+ </tr>
+ </t>
+ </t>
+ </t>
+ </table>
+ </div>
+ </div>
+ </div>
+ <p t-if="o.move_type in ('out_invoice', 'in_refund') and o.payment_reference" name="payment_communication">
+ Please use the following communication for your payment : <b><span t-field="o.payment_reference"/></b>
+ </p>
+
+ <p t-if="o.invoice_payment_term_id" name="payment_term">
+ <span t-field="o.invoice_payment_term_id.note"/>
+ </p>
+
+ <p t-if="o.narration" name="comment">
+ <span t-field="o.narration"/>
+ </p>
+ <p t-if="o.fiscal_position_id.note" name="note">
+ <span t-field="o.fiscal_position_id.note"/>
+ </p>
+ <p t-if="o.invoice_incoterm_id" name="incoterm">
+ <strong>Incoterm: </strong><span t-field="o.invoice_incoterm_id.code"/> - <span t-field="o.invoice_incoterm_id.name"/>
+ </p>
+ <div id="qrcode" t-if="o.display_qr_code">
+ <p t-if="qr_code_urls.get(o.id)">
+ <strong class="text-center">Scan me with your banking app.</strong><br/><br/>
+ <img class="border border-dark rounded" t-att-src="qr_code_urls[o.id]"/>
+ </p>
+ </div>
+
+ <t t-if="mi_type == 'text'">
+ <div t-if="txt_position == 'body'" t-att-style="txt_style">
+ <span t-esc="mi.copy_name" />
+ </div>
+ </t>
+
+ </div>
+ </t>
+ </template>
+
+ <template id="report_multiple_invoice">
+ <t t-call="web.html_container">
+ <t t-foreach="docs" t-as="o">
+ <t t-set="lang" t-value="o.invoice_user_id.sudo().lang if o.move_type in ('in_invoice', 'in_refund') else o.partner_id.lang"/>
+ <t t-set="print_with_payments" t-value="True"/>
+ <t t-if="o._get_name_invoice_report() == 'account.report_invoice_document'"
+ t-call="account.report_invoice_document" t-lang="lang"/>
+ <t t-foreach="mi_ids" t-as="mi">
+ <t t-call="base_accounting_kit.report_multiple_invoice_new" t-lang="lang"/>
+ </t>
+
+ </t>
+ </t>
+ </template>
+
+
+ <record id="report_multiple_invoice_copies" model="ir.actions.report">
+ <field name="name">Multiple Invoice Copies</field>
+ <field name="model">account.move</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_multiple_invoice</field>
+ <field name="report_file">base_accounting_kit.report_multiple_invoice</field>
+ <field name="binding_model_id" ref="account.model_account_move"/>
+ <field name="binding_type">report</field>
+ </record>
+
+</odoo> \ No newline at end of file
diff --git a/base_accounting_kit/report/report.xml b/base_accounting_kit/report/report.xml
new file mode 100644
index 0000000..330b4f8
--- /dev/null
+++ b/base_accounting_kit/report/report.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+ <!-- # Financial report -->
+ <record id="financial_report_pdf" model="ir.actions.report">
+ <field name="name">Financial reports</field>
+ <field name="model">financial.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_financial</field>
+ <field name="report_file">base_accounting_kit.report_financial</field>
+ </record>
+ <!-- # General ledger report -->
+ <record id="action_report_general_ledger" model="ir.actions.report">
+ <field name="name">General Ledger</field>
+ <field name="model">account.report.general.ledger</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_general_ledger</field>
+ <field name="report_file">base_accounting_kit.report_general_ledger</field>
+ </record>
+ <!-- # Partner ledger report -->
+ <record id="action_report_partnerledger" model="ir.actions.report">
+ <field name="name">Partner Ledger</field>
+ <field name="model">account.report.partner.ledger</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_partnerledger</field>
+ <field name="report_file">base_accounting_kit.report_partnerledger</field>
+ </record>
+ <!-- # Ageing report -->
+ <record id="action_report_aged_partner_balance" model="ir.actions.report">
+ <field name="name">Aged Partner Balance</field>
+ <field name="model">res.partner</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_agedpartnerbalance</field>
+ <field name="report_file">base_accounting_kit.report_agedpartnerbalance</field>
+ </record>
+ <!-- # Journal audit report -->
+ <record id="action_report_journal" model="ir.actions.report">
+ <field name="name">Journals Audit</field>
+ <field name="model">account.common.journal.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_journal_audit</field>
+ <field name="report_file">base_accounting_kit.report_journal_audit</field>
+ </record>
+ <!-- # Tax report -->
+ <record id="action_report_account_tax" model="ir.actions.report">
+ <field name="name">Tax Report</field>
+ <field name="model">kit.account.tax.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_tax</field>
+ <field name="report_file">base_accounting_kit.report_tax</field>
+ </record>
+ <!-- # Trial balance report -->
+ <record id="action_report_trial_balance" model="ir.actions.report">
+ <field name="name">Trial Balance</field>
+ <field name="model">account.balance.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_trial_balance</field>
+ <field name="report_file">base_accounting_kit.report_trial_balance</field>
+ </record>
+ <!-- # CAsh flow statements -->
+ <record id="action_report_cash_flow" model="ir.actions.report">
+ <field name="name">Cash Flow Statement</field>
+ <field name="model">account.financial.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_cash_flow</field>
+ <field name="report_file">base_accounting_kit.report_cash_flow</field>
+ </record>
+ <!-- # Accounting Bank Book Report -->
+ <record id="action_report_bank_book" model="ir.actions.report">
+ <field name="name">Bank Book Report</field>
+ <field name="model">account.bank.book.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_bank_book</field>
+ <field name="report_file">base_accounting_kit.report_bank_book</field>
+ <field name="attachment_use">False</field>
+ </record>
+
+ <!-- # Accounting Cash Book Report -->
+ <record id="action_report_cash_book" model="ir.actions.report">
+ <field name="name">Cash Book Report</field>
+ <field name="model">account.cash.book.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.report_cash_book</field>
+ <field name="report_file">base_accounting_kit.report_cash_book</field>
+ <field name="attachment_use">False</field>
+ </record>
+
+ <!-- # Accounting Day Book Report -->
+ <record id="day_book_pdf_report" model="ir.actions.report">
+ <field name="name">Day Book PDF Report</field>
+ <field name="model">account.day.book.report</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">base_accounting_kit.day_book_report_template</field>
+ <field name="report_file">base_accounting_kit.day_book_report_template</field>
+ <field name="attachment_use">True</field>
+ </record>
+</odoo> \ No newline at end of file
diff --git a/base_accounting_kit/report/report_aged_partner.py b/base_accounting_kit/report/report_aged_partner.py
new file mode 100644
index 0000000..f946793
--- /dev/null
+++ b/base_accounting_kit/report/report_aged_partner.py
@@ -0,0 +1,303 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import 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'
+ _description = 'Aged Partner Balance Report'
+
+ 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.company
+ 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.company.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.company.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.company.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.company.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,
+ }
diff --git a/base_accounting_kit/report/report_aged_partner.xml b/base_accounting_kit/report/report_aged_partner.xml
new file mode 100644
index 0000000..d212692
--- /dev/null
+++ b/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': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[4]" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[3]" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[2]" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[1]" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[0]" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/></th>
+ <th class="text-right"><span t-esc="get_direction[5]" t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['4']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['3']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['2']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['1']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['0']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="partner['total']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </t>
+ </t>
+ </template>
+</odoo>
diff --git a/base_accounting_kit/report/report_financial.py b/base_accounting_kit/report/report_financial.py
new file mode 100644
index 0000000..bdf5801
--- /dev/null
+++ b/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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+from 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').")
diff --git a/base_accounting_kit/report/report_financial.xml b/base_accounting_kit/report/report_financial.xml
new file mode 100644
index 0000000..1ca5812
--- /dev/null
+++ b/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': env.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': env.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': env.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': env.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': env.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> \ No newline at end of file
diff --git a/base_accounting_kit/report/report_journal_audit.py b/base_accounting_kit/report/report_journal_audit.py
new file mode 100644
index 0000000..ea5ab3f
--- /dev/null
+++ b/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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import time
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportJournal(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_journal_audit'
+ _description = 'Journal Report'
+
+ 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,
+ }
diff --git a/base_accounting_kit/report/report_journal_audit.xml b/base_accounting_kit/report/report_journal_audit.xml
new file mode 100644
index 0000000..0ab38ac
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td>
+ <span t-esc="aml.credit"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td>
+ <span t-esc="sum_credit(data, o)"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td>
+ <span t-esc="taxes[tax]['tax_amount']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <p style="page-break-after: always;"/>
+ </div>
+ </t>
+ </t>
+ </t>
+ </template>
+ </data>
+</odoo>
diff --git a/base_accounting_kit/report/report_partner_ledger.py b/base_accounting_kit/report/report_partner_ledger.py
new file mode 100644
index 0000000..6e8951a
--- /dev/null
+++ b/base_accounting_kit/report/report_partner_ledger.py
@@ -0,0 +1,156 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import time
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportPartnerLedger(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_partnerledger'
+ _description = 'Partner Ledger Report'
+
+ 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,
+ }
diff --git a/base_accounting_kit/report/report_partner_ledger.xml b/base_accounting_kit/report/report_partner_ledger.xml
new file mode 100644
index 0000000..cd5e9fb
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <strong t-esc="sum_partner(data, o, 'credit')"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <strong t-esc="sum_partner(data, o, 'debit - credit')"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['credit']"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-esc="line['progress']"
+ t-options="{'widget': 'monetary', 'display_currency': env.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>
diff --git a/base_accounting_kit/report/report_tax.py b/base_accounting_kit/report/report_tax.py
new file mode 100644
index 0000000..61445ef
--- /dev/null
+++ b/base_accounting_kit/report/report_tax.py
@@ -0,0 +1,115 @@
+# -*- 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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+from _datetime import datetime
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportTax(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_tax'
+ _description = 'Tax Report'
+
+ @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'] and not options['date_to']:
+ self.with_context(date_from=options['date_from'],
+ strict_range=True)._compute_from_amls(options,
+ taxes)
+ elif options['date_to'] and not options['date_from']:
+ 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
diff --git a/base_accounting_kit/report/report_tax.xml b/base_accounting_kit/report/report_tax.xml
new file mode 100644
index 0000000..b648379
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td>
+ <span t-att-style="style" t-esc="line.get('tax')"
+ t-options="{'widget': 'monetary', 'display_currency': env.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': env.company.currency_id}"/>
+ </td>
+ <td>
+ <span t-att-style="style" t-esc="line.get('tax')"
+ t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </t>
+ </t>
+ </template>
+</odoo>
diff --git a/base_accounting_kit/report/report_trial_balance.py b/base_accounting_kit/report/report_trial_balance.py
new file mode 100644
index 0000000..d8bbe4d
--- /dev/null
+++ b/base_accounting_kit/report/report_trial_balance.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 LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+import time
+
+from odoo import api, models, _
+from odoo.exceptions import UserError
+
+
+class ReportTrialBalance(models.AbstractModel):
+ _name = 'report.base_accounting_kit.report_trial_balance'
+ _description = 'Trial Balance Report'
+
+ 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."))
+
+ model = self.env.context.get('active_model')
+ docs = self.env[model].browse(
+ self.env.context.get('active_ids', []))
+ display_account = data['form'].get('display_account')
+ accounts = docs if 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': model,
+ 'data': data['form'],
+ 'docs': docs,
+ 'time': time,
+ 'Accounts': account_res,
+ }
diff --git a/base_accounting_kit/report/report_trial_balance.xml b/base_accounting_kit/report/report_trial_balance.xml
new file mode 100644
index 0000000..88d8f1f
--- /dev/null
+++ b/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="env.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': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-att-style="style" t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ <td class="text-right">
+ <span t-att-style="style" t-esc="account['balance']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </t>
+ </t>
+ </template>
+</odoo>