first push message
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 account_asset_report
|
||||
from . import account_bank_book
|
||||
from . import account_cash_book
|
||||
from . import account_day_book
|
||||
from . import account_report_common_account
|
||||
from . import cash_flow_report
|
||||
from . import general_ledger_report
|
||||
from . import multiple_invoice_report
|
||||
from . import report_aged_partner
|
||||
from . import report_financial
|
||||
from . import report_journal_audit
|
||||
from . import report_partner_ledger
|
||||
from . import report_tax
|
||||
from . import report_trial_balance
|
||||
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 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
|
||||
)""")
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<!-- Asset Report Pivot View -->
|
||||
<record id="asset_asset_report_view_pivot" model="ir.ui.view">
|
||||
<field name="name">asset.asset.report.view.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>
|
||||
<!-- Asset Report Graph View -->
|
||||
<record id="asset_asset_report_view_graph" model="ir.ui.view">
|
||||
<field name="name">asset.asset.report.view.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>
|
||||
<!-- Asset Report Search View -->
|
||||
<record id="asset_asset_report_view_search" model="ir.ui.view">
|
||||
<field name="name">asset.asset.report.view.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>
|
||||
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
<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>
|
||||
<!--Asset Report Action-->
|
||||
<record id="action_asset_asset_report" model="ir.actions.act_window">
|
||||
<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="asset_asset_report_view_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 depreciation's. The
|
||||
search bar can also be used to personalize your assets depreciation reporting.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<!--Assets Menuitem-->
|
||||
<menuitem name="Assets" action="action_asset_asset_report"
|
||||
id="menu_action_asset_asset_report"
|
||||
parent="account.account_reports_management_menu" sequence="21"/>
|
||||
</odoo>
|
||||
@@ -0,0 +1,175 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 api, models, _
|
||||
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:
|
||||
account_company = self.env.company
|
||||
currency = account.currency_id and \
|
||||
account.currency_id or account_company.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.default_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,
|
||||
}
|
||||
@@ -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"><br/>
|
||||
<div class="row" style="top:60px;">
|
||||
<h2><span t-esc="env.company.name"/>: Bank Book Report</h2>
|
||||
</div>
|
||||
<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-end" 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>
|
||||
@@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 api, models, _
|
||||
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}
|
||||
|
||||
# ------------------------------
|
||||
# 1. Initial Balance
|
||||
# ------------------------------
|
||||
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)
|
||||
init_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
|
||||
""" + init_filters + """
|
||||
GROUP BY l.account_id
|
||||
"""
|
||||
params = (tuple(accounts.ids) or (0,),) + tuple(init_where_params)
|
||||
cr.execute(sql, params)
|
||||
for row in cr.dictfetchall():
|
||||
move_lines[row.pop('account_id')].append(row)
|
||||
|
||||
# ------------------------------
|
||||
# 2. Sorting
|
||||
# ------------------------------
|
||||
sql_sort = 'l.date, l.move_id'
|
||||
if sortby == 'sort_journal_partner':
|
||||
sql_sort = 'j.code, p.name, l.move_id'
|
||||
|
||||
# ------------------------------
|
||||
# 3. Prepare SQL filters
|
||||
# ------------------------------
|
||||
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'
|
||||
)
|
||||
|
||||
# ------------------------------
|
||||
# 4. Accounts fallback
|
||||
# ------------------------------
|
||||
if not accounts:
|
||||
# fallback: take receivable/payable accounts if none passed
|
||||
accounts = self.env['account.account'].search([
|
||||
('account_type', 'in', ['asset_receivable', 'liability_payable'])
|
||||
])
|
||||
|
||||
if not accounts.ids:
|
||||
return [] # no accounts, no results
|
||||
|
||||
account_ids = tuple(accounts.ids) or (0,)
|
||||
params = (account_ids,) + tuple(where_params)
|
||||
|
||||
# ------------------------------
|
||||
# 5. Main SQL query
|
||||
# ------------------------------
|
||||
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
|
||||
|
||||
cr.execute(sql, params)
|
||||
|
||||
# ------------------------------
|
||||
# 6. Attach lines to accounts
|
||||
# ------------------------------
|
||||
for row in cr.dictfetchall():
|
||||
balance = 0
|
||||
for line in move_lines.get(row['account_id'], []): # ✅ safe fallback
|
||||
balance += line['debit'] - line['credit']
|
||||
row['balance'] += balance
|
||||
|
||||
acc_id = row.pop('account_id')
|
||||
if acc_id not in move_lines:
|
||||
move_lines[acc_id] = [] # ✅ ensure list exists
|
||||
move_lines[acc_id].append(row)
|
||||
|
||||
# ------------------------------
|
||||
# 7. Build account results
|
||||
# ------------------------------
|
||||
account_res = []
|
||||
for account in accounts:
|
||||
account_company = self.env.company
|
||||
currency = account.currency_id or account_company.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.get(account.id, []) # ✅ safe lookup
|
||||
|
||||
for line in res['move_lines']:
|
||||
res['debit'] += line['debit']
|
||||
res['credit'] += line['credit']
|
||||
res['balance'] = line['balance']
|
||||
|
||||
if display_account == 'all':
|
||||
account_res.append(res)
|
||||
elif display_account == 'movement' and res.get('move_lines'):
|
||||
account_res.append(res)
|
||||
elif 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.default_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,
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?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"><br/>
|
||||
<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-centre">
|
||||
<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-end">
|
||||
<span t-esc="account['debit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="account['credit']"
|
||||
t-options="{'widget':
|
||||
'monetary', 'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<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-end">
|
||||
<span t-esc="line['debit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="line['credit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="line['balance']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td t-if="line['amount_currency']"
|
||||
class="text-end"
|
||||
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>
|
||||
@@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 api, models, _
|
||||
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,
|
||||
}
|
||||
@@ -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"><br/>
|
||||
<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-end" 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>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 fields, models
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class AccountCommonAccountReport(models.TransientModel):
|
||||
_name = 'account.common.account.report'
|
||||
_description = 'Account Common Account Report'
|
||||
_inherit = "account.report"
|
||||
|
||||
section_main_report_ids = fields.Many2many(string="Section Of",
|
||||
comodel_name='account.report',
|
||||
relation="account_common_report_section_rel",
|
||||
column1="sub_report_id",
|
||||
column2="main_report_id")
|
||||
section_report_ids = fields.Many2many(string="Sections",
|
||||
comodel_name='account.report',
|
||||
relation="account_common_report_section_rel",
|
||||
column1="main_report_id",
|
||||
column2="sub_report_id")
|
||||
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')
|
||||
target_move = fields.Selection([('posted', 'All Posted Entries'),
|
||||
('all', 'All Entries'),
|
||||
], string='Target Moves', required=True, default='posted')
|
||||
date_from = fields.Date(string='Start Date')
|
||||
date_to = fields.Date(string='End Date')
|
||||
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True,
|
||||
default=lambda self: self.env.company)
|
||||
|
||||
def _build_contexts(self, data):
|
||||
result = {}
|
||||
result['journal_ids'] = 'journal_ids' in data['form'] and data['form']['journal_ids'] or False
|
||||
result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or ''
|
||||
result['date_from'] = data['form']['date_from'] or False
|
||||
result['date_to'] = data['form']['date_to'] or False
|
||||
result['strict_range'] = True if result['date_from'] else False
|
||||
result['company_id'] = data['form']['company_id'][0] or False
|
||||
return result
|
||||
|
||||
def _print_report(self, data):
|
||||
raise NotImplementedError()
|
||||
|
||||
def check_report(self):
|
||||
self.ensure_one()
|
||||
data = {}
|
||||
data['ids'] = self.env.context.get('active_ids', [])
|
||||
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
|
||||
data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move', 'company_id'])[0]
|
||||
used_context = self._build_contexts(data)
|
||||
data['form']['used_context'] = dict(used_context, lang=get_lang(self.env).code)
|
||||
return self.with_context(discard_logo_check=True)._print_report(data)
|
||||
|
||||
def pre_print_report(self, data):
|
||||
data['form'].update(self.read(['display_account'])[0])
|
||||
return data
|
||||
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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(
|
||||
[('account_type', 'in', report.account_type_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,
|
||||
}
|
||||
@@ -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') > 3">
|
||||
<t t-set="style" t-value="'font-weight: normal;'"/>
|
||||
</t>
|
||||
<t t-if="not a.get('level') > 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" t-if="data['enable_filter']">
|
||||
<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>
|
||||
@@ -0,0 +1,183 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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:
|
||||
account_company = self.env.company
|
||||
currency = account.currency_id and account.currency_id or account_company.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,
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?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"><br/>
|
||||
<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-end">
|
||||
<span t-esc="account['debit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="account['credit']" t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<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-end">
|
||||
<span t-esc="line['credit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<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-end"
|
||||
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>
|
||||
@@ -0,0 +1,645 @@
|
||||
<?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"/>
|
||||
</div>
|
||||
<!--Header-->
|
||||
<t t-if="mi_type == 'text'">
|
||||
<t t-if="txt_position == 'header'">
|
||||
<div t-if="txt_align == 'right'" class="text-right">
|
||||
<span t-esc="mi.copy_name" style="font-size: 20px;"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<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">
|
||||
<span t-if="company.company_details"
|
||||
t-field="company.company_details"></span>
|
||||
</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 {{ 'o_layout_background' if company.layout_background in ['Geometric', 'Custom'] else '' }}"
|
||||
t-attf-style="background-image: url({{ 'data:image/png;base64,%s' % company.layout_background_image.decode('utf-8') if company.layout_background_image and company.layout_background == 'Custom' else '/base/static/img/bg_background_template.jpg' if company.layout_background == 'Geometric' else ''}});"
|
||||
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-out="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">
|
||||
<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>
|
||||
|
||||
</ul>
|
||||
|
||||
<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 t-if="company.company_details"
|
||||
t-field="company.company_details"/>
|
||||
<!--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 {{ 'o_layout_background' if company.layout_background in ['Geometric', 'Custom'] else '' }}"
|
||||
t-attf-style="background-image: url({{ 'data:image/png;base64,%s' % company.layout_background_image.decode('utf-8') if company.layout_background_image and company.layout_background == 'Custom' else '/base/static/img/bg_background_template.jpg' }});"
|
||||
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-out="0"/>
|
||||
</div>
|
||||
|
||||
<div t-attf-class="footer o_boxed_footer o_company_#{company.id}_layout">
|
||||
<div class="text-center">
|
||||
<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.bold">
|
||||
<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="forced_vat or company.vat">
|
||||
<t t-esc="company.country_id.vat_label or 'Tax ID'"/>
|
||||
:
|
||||
<span t-if="forced_vat" t-esc="forced_vat"/>
|
||||
<span t-else="" 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_bold o_company_#{company.id}_layout {{ 'o_layout_background' if company.layout_background in ['Geometric', 'Custom'] else '' }}"
|
||||
t-attf-style="background-image: url({{ 'data:image/png;base64,%s' % company.layout_background_image.decode('utf-8') if company.layout_background_image and company.layout_background == 'Custom' else '/base/static/img/bg_background_template.jpg' }});"
|
||||
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-out="0"/>
|
||||
</div>
|
||||
<div t-attf-class="footer o_clean_footer o_company_#{company.id}_layout">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<span t-field="company.report_footer"/>
|
||||
<!--Footer Left-->
|
||||
<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>
|
||||
<div class="col-4">
|
||||
<span t-if="company.company_details"
|
||||
t-field="company.company_details"/>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<h5 class="mt0 mb0" 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.striped">
|
||||
<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">
|
||||
<span t-if="company.company_details"
|
||||
t-field="company.company_details"></span>
|
||||
</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_striped {{ 'o_layout_background' if company.layout_background in ['Geometric', 'Custom'] else '' }}"
|
||||
t-attf-style="background-image: url({{ 'data:image/png;base64,%s' % company.layout_background_image.decode('utf-8') if company.layout_background_image and company.layout_background == 'Custom' else '/base/static/img/bg_background_template.jpg' }});"
|
||||
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-out="0"/>
|
||||
</div>
|
||||
<div t-attf-class="o_company_#{company.id}_layout footer o_background_footer">
|
||||
<div class="text-center">
|
||||
<ul class="list-inline">
|
||||
<div t-field="company.report_footer"/>
|
||||
</ul>
|
||||
<!--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>
|
||||
@@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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, models
|
||||
|
||||
|
||||
class ReportInvoiceMultiple(models.AbstractModel):
|
||||
_name = 'report.base_accounting_kit.report_multiple_invoice'
|
||||
_inherit = 'report.account.report_invoice'
|
||||
_description = 'Report Invoice Multiple'
|
||||
|
||||
@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_bold':
|
||||
new_layout = 'base_accounting_kit.bold'
|
||||
|
||||
elif layout == 'web.external_layout_striped':
|
||||
new_layout = 'base_accounting_kit.striped'
|
||||
|
||||
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
|
||||
@@ -0,0 +1,307 @@
|
||||
<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>
|
||||
Amount
|
||||
</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="line.display_type not in ('line_section', 'line_note')"
|
||||
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"
|
||||
/>
|
||||
</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="right-elements" t-attf-class="#{'col-5' if report_type != 'html' else 'col-12 col-md-5'} ms-5 d-inline-block float-end">
|
||||
<div id="total" class="clearfix row mt-n3">
|
||||
<div class="ms-auto">
|
||||
<table class="o_total_table table table-borderless avoid-page-break-inside">
|
||||
|
||||
<!-- Tax totals summary (invoice currency) -->
|
||||
<t t-if="o.tax_totals" t-call="account.document_tax_totals">
|
||||
<t t-set="tax_totals" t-value="o.tax_totals"/>
|
||||
<t t-set="currency" t-value="o.currency_id"/>
|
||||
</t>
|
||||
|
||||
<!--Payments-->
|
||||
<t t-if="print_with_payments">
|
||||
<t t-if="o.payment_state != 'invoicing_legacy'">
|
||||
<t t-set="payments_vals" t-value="o.sudo().invoice_payments_widget and o.sudo().invoice_payments_widget['content'] or []"/>
|
||||
<t t-foreach="payments_vals" t-as="payment_vals">
|
||||
<tr t-if="payment_vals['is_exchange'] == 0">
|
||||
<td>
|
||||
<i class="oe_form_field text-end oe_payment_label">Paid on <t t-out="payment_vals['date']" t-options='{"widget": "date"}'>2021-09-19</t></i>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-out="payment_vals['amount']" t-options='{"widget": "monetary", "display_currency": o.currency_id}'>20.00</span>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<t t-if="len(payments_vals) > 0">
|
||||
<tr class="fw-bold">
|
||||
<td>Amount Due</td>
|
||||
<td class="text-end">
|
||||
<span t-field="o.amount_residual">11.05</span>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<p class="text-end lh-sm" t-if="o.company_id.display_invoice_amount_total_words">
|
||||
Total amount in words: <br/>
|
||||
<small class="text-muted lh-sm"><span t-field="o.amount_total_words">Thirty one dollar and Five cents</span></small>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Tax totals summary (company currency) -->
|
||||
<t t-if="o.tax_totals.get('display_in_company_currency')">
|
||||
<t t-set="tax_totals" t-value="o.tax_totals"/>
|
||||
<t t-call="account.document_tax_totals_company_currency_template"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="oe_structure"/>
|
||||
</t>
|
||||
</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>
|
||||
@@ -0,0 +1,97 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,297 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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.account_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.account_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._get_conversion_rate(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._get_conversion_rate(
|
||||
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._get_conversion_rate(
|
||||
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.account_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._get_conversion_rate(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._get_conversion_rate(
|
||||
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._get_conversion_rate(
|
||||
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 = ['asset_receivable']
|
||||
elif data['form']['result_selection'] == 'supplier':
|
||||
account_type = ['liability_payable']
|
||||
else:
|
||||
account_type = ['liability_payable', 'asset_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,
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?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"><br/>
|
||||
<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-start">
|
||||
<span t-esc="partner['direction']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['4']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['3']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['2']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['1']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['0']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-start">
|
||||
<span t-esc="partner['total']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,157 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 AccountTypes(models.Model):
|
||||
_name = "account.account.type"
|
||||
|
||||
name = fields.Char(string='Account Type', required=True, translate=True)
|
||||
type = fields.Selection([
|
||||
('other', 'Regular'),
|
||||
('receivable', 'Receivable'),
|
||||
('payable', 'Payable'),
|
||||
('liquidity', 'Liquidity'),
|
||||
], required=True, default='other',
|
||||
help="The 'Internal Type' is used for features available on "
|
||||
"different types of accounts: liquidity type is for cash or "
|
||||
"bank accounts" \
|
||||
", payable/receivable is for vendor/customer accounts.")
|
||||
|
||||
|
||||
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, recursive=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 Types')
|
||||
account_type_ids = fields.Selection(
|
||||
selection=[
|
||||
("asset_receivable", "Receivable"),
|
||||
("asset_cash", "Bank and Cash"),
|
||||
("asset_current", "Current Assets"),
|
||||
("asset_non_current", "Non-current Assets"),
|
||||
("asset_prepayments", "Prepayments"),
|
||||
("asset_fixed", "Fixed Assets"),
|
||||
("liability_payable", "Payable"),
|
||||
("liability_credit_card", "Credit Card"),
|
||||
("liability_current", "Current Liabilities"),
|
||||
("liability_non_current", "Non-current Liabilities"),
|
||||
("equity", "Equity"),
|
||||
("equity_unaffected", "Current Year Earnings"),
|
||||
("income", "Income"),
|
||||
("income_other", "Other Income"),
|
||||
("expense", "Expenses"),
|
||||
("expense_depreciation", "Depreciation"),
|
||||
("expense_direct_cost", "Cost of Revenue"),
|
||||
("off_balance", "Off-Balance Sheet"),
|
||||
],
|
||||
string="Type",
|
||||
help="These types are defined according to your country. The type contains more information " \
|
||||
"about the account and its specificities."
|
||||
)
|
||||
|
||||
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').")
|
||||
@@ -0,0 +1,145 @@
|
||||
<?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') > 3">
|
||||
<t t-set="style" t-value="'font-weight: normal;'"/>
|
||||
</t>
|
||||
<t t-if="not a.get('level') > 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') > 3">
|
||||
<t t-set="style" t-value="'font-weight: normal;'"/>
|
||||
</t>
|
||||
<t t-if="not a.get('level') > 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>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') > 3">
|
||||
<t t-set="style" t-value="'font-weight: normal;'"/>
|
||||
</t>
|
||||
<t t-if="not a.get('level') > 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-end">
|
||||
<span t-att-style="style"
|
||||
t-esc="a.get('balance')"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-att-style="style"
|
||||
t-esc="a.get('balance_cmp')"/>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,160 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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'
|
||||
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,
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<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>
|
||||
</odoo>
|
||||
@@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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.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()
|
||||
|
||||
# move state
|
||||
data['computed']['move_state'] = ['draft', 'posted']
|
||||
if data['form'].get('target_move', 'all') == 'posted':
|
||||
data['computed']['move_state'] = ['posted']
|
||||
|
||||
# account types
|
||||
result_selection = data['form'].get('result_selection', 'customer')
|
||||
if result_selection == 'supplier':
|
||||
data['computed']['ACCOUNT_TYPE'] = ['liability_payable']
|
||||
elif result_selection == 'customer':
|
||||
data['computed']['ACCOUNT_TYPE'] = ['asset_receivable']
|
||||
else:
|
||||
data['computed']['ACCOUNT_TYPE'] = ['liability_payable', 'asset_receivable']
|
||||
|
||||
# fetch account ids
|
||||
self.env.cr.execute("""
|
||||
SELECT a.id
|
||||
FROM account_account a
|
||||
WHERE a.account_type IN %s
|
||||
AND a.active""", # ✅ changed here
|
||||
(tuple(data['computed']['ACCOUNT_TYPE']),)
|
||||
)
|
||||
data['computed']['account_ids'] = [a for (a,) in self.env.cr.fetchall()]
|
||||
|
||||
# prevent empty tuple issue
|
||||
account_ids = tuple(data['computed']['account_ids']) or (0,)
|
||||
params = [tuple(data['computed']['move_state']), 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 account.active
|
||||
AND """ + query_get_data[1] + reconcile_clause # ✅ changed here
|
||||
|
||||
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,
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?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>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="3">
|
||||
<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-end">
|
||||
<strong t-esc="sum_partner(data, o, 'credit')"
|
||||
t-options="{'widget': 'monetary', 'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<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['displayed_name']"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="line['debit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="line['credit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-esc="line['progress']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency':
|
||||
env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end"
|
||||
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>
|
||||
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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 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 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
|
||||
@@ -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"><br/>
|
||||
<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 class="text-centre">
|
||||
<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/>
|
||||
</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>
|
||||
@@ -0,0 +1,112 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#############################################################################
|
||||
#
|
||||
# Cybrosys Technologies Pvt. Ltd.
|
||||
#
|
||||
# Copyright (C) 2025-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'])
|
||||
account_company = self.env.company
|
||||
currency = (account.currency_id and account.currency_id or
|
||||
account_company.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,
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?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"><br/>
|
||||
<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 class="text-centre">
|
||||
<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-end">
|
||||
<span t-att-style="style"
|
||||
t-esc="account['debit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-att-style="style"
|
||||
t-esc="account['credit']"
|
||||
t-options="{'widget': 'monetary',
|
||||
'display_currency': env.company.currency_id}"/>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<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>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!-- Action for statement report -->
|
||||
<record id="res_partner_action" model="ir.actions.report">
|
||||
<field name="name">Statement Report</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">base_accounting_kit.res_partner_statement_report_template</field>
|
||||
<field name="report_file">base_accounting_kit.res_partner_statement_report_template</field>
|
||||
<field name="print_report_name">'Statement Report- %s' %(object.name)</field>
|
||||
<field name="binding_model_id" ref="model_res_partner"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!-- Statement report template -->
|
||||
<template id="res_partner_statement_report_template">
|
||||
<t t-call="web.html_container">
|
||||
<t t-call="web.external_layout">
|
||||
<div page="page">
|
||||
<h3>Payment Statement Report</h3>
|
||||
</div><br/>
|
||||
<table border="0">
|
||||
<tr><t t-esc="customer"/></tr><br/><br/>
|
||||
<tr><t t-if="street"> <t t-esc="street"/></t></tr><br/>
|
||||
<tr><t t-if="street2"> <t t-esc="street2"/></t></tr><br/>
|
||||
<tr><t t-if="city"> <t t-esc="city"/></t></tr><br/>
|
||||
<tr><t t-if="state"> <t t-esc="state"/></t></tr><br/>
|
||||
</table>
|
||||
<br/><br/>
|
||||
<table class="table" style="align-items: center;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Invoice/Bill Number</th>
|
||||
<th>Due Date</th>
|
||||
<th>Invoices/Debit</th>
|
||||
<th>Balance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="my_data" t-as="line">
|
||||
<tr>
|
||||
<td align="center"><t t-esc="line['invoice_date']"/></td>
|
||||
<td align="center"><t t-esc="line['name']"/></td>
|
||||
<td align="center"><t t-esc="line['invoice_date_due']"/></td>
|
||||
<td align="center">
|
||||
<t t-esc="currency"/>
|
||||
<t t-esc="line['sub_total']"/>
|
||||
</td>
|
||||
<td align="center">
|
||||
<t t-esc="currency"/>
|
||||
<t t-esc="line['balance']"/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<t t-if="total">
|
||||
<div class="clearfix" name="so_total_summary">
|
||||
<div id="total" class="row" name="total">
|
||||
<div t-attf-class="#{'col-6' if report_type != 'html' else 'col-sm-7 col-md-6'} ms-auto">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Amount:</td>
|
||||
<td>
|
||||
<t t-esc="currency"/>
|
||||
<t t-esc="total"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Balance:</td>
|
||||
<td>
|
||||
<t t-esc="currency"/>
|
||||
<t t-esc="balance"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user