From 1ca3b3df3421961caec3b747a364071c80f5c7da Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 17:14:58 +0700 Subject: initial commit --- base_accounting_kit/report/__init__.py | 35 ++ base_accounting_kit/report/account_asset_report.py | 68 +++ .../report/account_asset_report_views.xml | 77 +++ base_accounting_kit/report/account_bank_book.py | 176 +++++++ .../report/account_bank_book_view.xml | 133 +++++ base_accounting_kit/report/account_cash_book.py | 167 +++++++ .../report/account_cash_book_view.xml | 108 ++++ base_accounting_kit/report/account_day_book.py | 125 +++++ .../report/account_day_book_view.xml | 115 +++++ .../report/account_report_common_account.py | 38 ++ base_accounting_kit/report/cash_flow_report.py | 217 ++++++++ base_accounting_kit/report/cash_flow_report.xml | 88 ++++ .../report/general_ledger_report.py | 172 +++++++ .../report/general_ledger_report.xml | 107 ++++ .../report/multiple_invoice_layouts.xml | 552 +++++++++++++++++++++ .../report/multiple_invoice_report.py | 37 ++ .../report/multiple_invoice_report.xml | 260 ++++++++++ base_accounting_kit/report/report.xml | 96 ++++ base_accounting_kit/report/report_aged_partner.py | 303 +++++++++++ base_accounting_kit/report/report_aged_partner.xml | 98 ++++ base_accounting_kit/report/report_financial.py | 119 +++++ base_accounting_kit/report/report_financial.xml | 146 ++++++ base_accounting_kit/report/report_journal_audit.py | 158 ++++++ .../report/report_journal_audit.xml | 150 ++++++ .../report/report_partner_ledger.py | 156 ++++++ .../report/report_partner_ledger.xml | 107 ++++ base_accounting_kit/report/report_tax.py | 115 +++++ base_accounting_kit/report/report_tax.xml | 75 +++ base_accounting_kit/report/report_trial_balance.py | 109 ++++ .../report/report_trial_balance.xml | 71 +++ 30 files changed, 4178 insertions(+) create mode 100644 base_accounting_kit/report/__init__.py create mode 100644 base_accounting_kit/report/account_asset_report.py create mode 100644 base_accounting_kit/report/account_asset_report_views.xml create mode 100644 base_accounting_kit/report/account_bank_book.py create mode 100644 base_accounting_kit/report/account_bank_book_view.xml create mode 100644 base_accounting_kit/report/account_cash_book.py create mode 100644 base_accounting_kit/report/account_cash_book_view.xml create mode 100644 base_accounting_kit/report/account_day_book.py create mode 100644 base_accounting_kit/report/account_day_book_view.xml create mode 100644 base_accounting_kit/report/account_report_common_account.py create mode 100644 base_accounting_kit/report/cash_flow_report.py create mode 100644 base_accounting_kit/report/cash_flow_report.xml create mode 100644 base_accounting_kit/report/general_ledger_report.py create mode 100644 base_accounting_kit/report/general_ledger_report.xml create mode 100644 base_accounting_kit/report/multiple_invoice_layouts.xml create mode 100644 base_accounting_kit/report/multiple_invoice_report.py create mode 100644 base_accounting_kit/report/multiple_invoice_report.xml create mode 100644 base_accounting_kit/report/report.xml create mode 100644 base_accounting_kit/report/report_aged_partner.py create mode 100644 base_accounting_kit/report/report_aged_partner.xml create mode 100644 base_accounting_kit/report/report_financial.py create mode 100644 base_accounting_kit/report/report_financial.xml create mode 100644 base_accounting_kit/report/report_journal_audit.py create mode 100644 base_accounting_kit/report/report_journal_audit.xml create mode 100644 base_accounting_kit/report/report_partner_ledger.py create mode 100644 base_accounting_kit/report/report_partner_ledger.xml create mode 100644 base_accounting_kit/report/report_tax.py create mode 100644 base_accounting_kit/report/report_tax.xml create mode 100644 base_accounting_kit/report/report_trial_balance.py create mode 100644 base_accounting_kit/report/report_trial_balance.xml (limited to 'base_accounting_kit/report') 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(). +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# +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 @@ + + + + + asset.asset.report.pivot + asset.asset.report + + + + + + + + + + asset.asset.report.graph + asset.asset.report + + + + + + + + + + + asset.asset.report.search + asset.asset.report + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assets Analysis + asset.asset.report + graph,pivot + + [('asset_category_id.type', '=', 'purchase')] + {'search_default_only_active': 1} + +

+ From this report, you can have an overview on all depreciations. The + search bar can also be used to personalize your assets depreciation reporting. +

+
+
+ + +
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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# +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 @@ + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# +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 @@ + + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# +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 @@ + + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + 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 @@ + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + + + + + Multiple Invoice Copies + account.move + qweb-pdf + base_accounting_kit.report_multiple_invoice + base_accounting_kit.report_multiple_invoice + + report + + + \ 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 @@ + + + + + Financial reports + financial.report + qweb-pdf + base_accounting_kit.report_financial + base_accounting_kit.report_financial + + + + General Ledger + account.report.general.ledger + qweb-pdf + base_accounting_kit.report_general_ledger + base_accounting_kit.report_general_ledger + + + + Partner Ledger + account.report.partner.ledger + qweb-pdf + base_accounting_kit.report_partnerledger + base_accounting_kit.report_partnerledger + + + + Aged Partner Balance + res.partner + qweb-pdf + base_accounting_kit.report_agedpartnerbalance + base_accounting_kit.report_agedpartnerbalance + + + + Journals Audit + account.common.journal.report + qweb-pdf + base_accounting_kit.report_journal_audit + base_accounting_kit.report_journal_audit + + + + Tax Report + kit.account.tax.report + qweb-pdf + base_accounting_kit.report_tax + base_accounting_kit.report_tax + + + + Trial Balance + account.balance.report + qweb-pdf + base_accounting_kit.report_trial_balance + base_accounting_kit.report_trial_balance + + + + Cash Flow Statement + account.financial.report + qweb-pdf + base_accounting_kit.report_cash_flow + base_accounting_kit.report_cash_flow + + + + Bank Book Report + account.bank.book.report + qweb-pdf + base_accounting_kit.report_bank_book + base_accounting_kit.report_bank_book + False + + + + + Cash Book Report + account.cash.book.report + qweb-pdf + base_accounting_kit.report_cash_book + base_accounting_kit.report_cash_book + False + + + + + Day Book PDF Report + account.day.book.report + qweb-pdf + base_accounting_kit.day_book_report_template + base_accounting_kit.day_book_report_template + True + + \ 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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] = {'': } + 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 @@ + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# +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 @@ + + + + \ 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + 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() +# Author: Cybrosys Techno Solutions() +# +# 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 . +# +############################################################################# + +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 @@ + + + + -- cgit v1.2.3