[IMP] account: new journals audit report
Improvement in two ways: - Implement a new, accounting report version of the existing journals audit pdf report, and remove the old journal audit report (PDF only). - Remove the menu items in "accounting" that opens the group by view of journal items with different filters. Now, these will be linked to actions on lines in the different reports available to the user. Also render the "journal items" menu visible without debug mode. Task id #2838182 closes odoo/odoo#92438 Related: odoo/upgrade#3560 Related: odoo/enterprise#27840 Signed-off-by: Quentin De Paoli <qdp@odoo.com>
This commit is contained in:
@@ -55,7 +55,6 @@ You could use this simplified accounting in case you work with an (external) acc
|
||||
'report/account_invoice_report_view.xml',
|
||||
'views/account_cash_rounding_view.xml',
|
||||
'wizard/account_report_common_view.xml',
|
||||
'views/report_journal.xml',
|
||||
'views/tax_adjustments.xml',
|
||||
'wizard/wizard_tax_adjustments_view.xml',
|
||||
'views/ir_module_views.xml',
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import account_invoice_report
|
||||
from . import account_journal
|
||||
from . import account_hash_integrity_templates
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import time
|
||||
from odoo import api, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ReportJournal(models.AbstractModel):
|
||||
_name = 'report.account.report_journal'
|
||||
_description = 'Account Journal Report'
|
||||
|
||||
def lines(self, target_move, journal_ids, sort_selection, data):
|
||||
if isinstance(journal_ids, int):
|
||||
journal_ids = [journal_ids]
|
||||
|
||||
move_state = ['draft', 'posted']
|
||||
if target_move == 'posted':
|
||||
move_state = ['posted']
|
||||
|
||||
query_get_clause = self._get_query_get_clause(data)
|
||||
params = [tuple(move_state), tuple(journal_ids)] + query_get_clause[2]
|
||||
query = 'SELECT "account_move_line".id FROM ' + query_get_clause[0] + ', account_move am, account_account acc WHERE "account_move_line".account_id = acc.id AND "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' ORDER BY '
|
||||
if sort_selection == 'date':
|
||||
query += '"account_move_line".date'
|
||||
else:
|
||||
query += 'am.name'
|
||||
query += ', "account_move_line".move_id, acc.code'
|
||||
self.env.cr.execute(query, tuple(params))
|
||||
ids = (x[0] for x in self.env.cr.fetchall())
|
||||
return self.env['account.move.line'].browse(ids)
|
||||
|
||||
def _sum_debit(self, data, journal_id):
|
||||
move_state = ['draft', 'posted']
|
||||
if data['form'].get('target_move', 'all') == 'posted':
|
||||
move_state = ['posted']
|
||||
|
||||
query_get_clause = self._get_query_get_clause(data)
|
||||
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[2]
|
||||
self.env.cr.execute('SELECT SUM(debit) FROM ' + query_get_clause[0] + ', account_move am '
|
||||
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' ',
|
||||
tuple(params))
|
||||
return self.env.cr.fetchone()[0] or 0.0
|
||||
|
||||
def _sum_credit(self, data, journal_id):
|
||||
move_state = ['draft', 'posted']
|
||||
if data['form'].get('target_move', 'all') == 'posted':
|
||||
move_state = ['posted']
|
||||
|
||||
query_get_clause = self._get_query_get_clause(data)
|
||||
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[2]
|
||||
self.env.cr.execute('SELECT SUM(credit) FROM ' + query_get_clause[0] + ', account_move am '
|
||||
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' ',
|
||||
tuple(params))
|
||||
return self.env.cr.fetchone()[0] or 0.0
|
||||
|
||||
def _get_taxes(self, data, journal_id):
|
||||
move_state = ['draft', 'posted']
|
||||
if data['form'].get('target_move', 'all') == 'posted':
|
||||
move_state = ['posted']
|
||||
|
||||
query_get_clause = self._get_query_get_clause(data)
|
||||
params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[2]
|
||||
query = """
|
||||
SELECT rel.account_tax_id, SUM("account_move_line".balance) AS base_amount
|
||||
FROM account_move_line_account_tax_rel rel, """ + query_get_clause[0] + """
|
||||
LEFT JOIN account_move am ON "account_move_line".move_id = am.id
|
||||
WHERE "account_move_line".id = rel.account_move_line_id
|
||||
AND am.state IN %s
|
||||
AND "account_move_line".journal_id IN %s
|
||||
AND """ + query_get_clause[1] + """
|
||||
GROUP BY rel.account_tax_id"""
|
||||
self.env.cr.execute(query, tuple(params))
|
||||
ids = []
|
||||
base_amounts = {}
|
||||
for row in self.env.cr.fetchall():
|
||||
ids.append(row[0])
|
||||
base_amounts[row[0]] = row[1]
|
||||
|
||||
|
||||
res = {}
|
||||
for tax in self.env['account.tax'].browse(ids):
|
||||
self.env.cr.execute('SELECT sum(debit - credit) FROM ' + query_get_clause[0] + ', account_move am '
|
||||
'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' AND tax_line_id = %s',
|
||||
tuple(params + [tax.id]))
|
||||
res[tax] = {
|
||||
'base_amount': base_amounts[tax.id],
|
||||
'tax_amount': self.env.cr.fetchone()[0] or 0.0,
|
||||
}
|
||||
if journal_id.type == 'sale':
|
||||
#sales operation are credits
|
||||
res[tax]['base_amount'] = res[tax]['base_amount'] * -1
|
||||
res[tax]['tax_amount'] = res[tax]['tax_amount'] * -1
|
||||
return res
|
||||
|
||||
def _get_query_get_clause(self, data):
|
||||
return self.env['account.move.line'].with_context(data['form'].get('used_context', {}))._query_get()
|
||||
|
||||
@api.model
|
||||
def _get_report_values(self, docids, data=None):
|
||||
if not data.get('form'):
|
||||
raise UserError(_("Form content is missing, this report cannot be printed."))
|
||||
|
||||
target_move = data['form'].get('target_move', 'all')
|
||||
sort_selection = data['form'].get('sort_selection', 'date')
|
||||
|
||||
res = {}
|
||||
for journal in data['form']['journal_ids']:
|
||||
res[journal] = self.with_context(data['form'].get('used_context', {})).lines(target_move, journal, sort_selection, data)
|
||||
return {
|
||||
'doc_ids': data['form']['journal_ids'],
|
||||
'doc_model': self.env['account.journal'],
|
||||
'data': data,
|
||||
'docs': self.env['account.journal'].browse(data['form']['journal_ids']),
|
||||
'time': time,
|
||||
'lines': res,
|
||||
'sum_credit': self._sum_credit,
|
||||
'sum_debit': self._sum_debit,
|
||||
'get_taxes': self._get_taxes,
|
||||
'company_id': self.env['res.company'].browse(
|
||||
data['form']['company_id'][0]),
|
||||
}
|
||||
@@ -26,17 +26,7 @@
|
||||
<menuitem id="menu_finance_entries" name="Accounting" sequence="4" groups="account.group_account_readonly">
|
||||
<menuitem id="menu_finance_entries_accounting_miscellaneous" name="Miscellaneous" sequence="1">
|
||||
<menuitem id="menu_action_move_journal_line_form" action="action_move_journal_line" groups="account.group_account_readonly" sequence="1"/>
|
||||
<menuitem id="menu_action_account_moves_all" action="action_account_moves_all" groups="base.group_no_one" sequence="10"/>
|
||||
</menuitem>
|
||||
<menuitem id="menu_finance_entries_accounting_journals" name="Journals" sequence="2">
|
||||
<menuitem id="menu_action_account_moves_journal_sales" action="action_account_moves_journal_sales" groups="account.group_account_readonly" sequence="1"/>
|
||||
<menuitem id="menu_action_account_moves_journal_purchase" action="action_account_moves_journal_purchase" groups="account.group_account_readonly" sequence="2"/>
|
||||
<menuitem id="menu_action_account_moves_journal_bank_cash" action="action_account_moves_journal_bank_cash" groups="account.group_account_readonly" sequence="3"/>
|
||||
<menuitem id="menu_action_account_moves_journal_misc" action="action_account_moves_journal_misc" groups="account.group_account_readonly" sequence="4"/>
|
||||
</menuitem>
|
||||
<menuitem id="menu_finance_entries_accounting_ledgers" name="Ledgers" sequence="3">
|
||||
<menuitem id="menu_action_account_moves_ledger_general" action="action_account_moves_ledger_general" groups="account.group_account_readonly" sequence="1"/>
|
||||
<menuitem id="menu_action_account_moves_ledger_partner" action="action_account_moves_ledger_partner" groups="account.group_account_readonly" sequence="2"/>
|
||||
<menuitem id="menu_action_account_moves_all" action="action_account_moves_all" groups="account.group_account_readonly" sequence="10"/>
|
||||
</menuitem>
|
||||
<menuitem id="menu_finance_entries_management" name="Management" sequence="10" groups="account.group_account_invoice,account.group_account_readonly"/>
|
||||
<menuitem id="menu_finance_entries_generate_entries" name="Generate Entries"/>
|
||||
|
||||
@@ -370,6 +370,9 @@
|
||||
<separator/>
|
||||
<filter string="Date" name="date" date="date"/>
|
||||
<separator/>
|
||||
<filter string="Report Dates" name="date_between" domain="[('date', '>=', context.get('date_from')), ('date', '<=', context.get('date_to'))]" invisible="1"/>
|
||||
<separator/>
|
||||
<filter string="Report Analytic Accounts" name="analytic_accounts" domain="[('analytic_account_id', 'in', context.get('analytic_ids'))]" invisible="1"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Journal Entry" name="group_by_move" domain="[]" context="{'group_by': 'move_id'}"/>
|
||||
<filter string="Account" name="group_by_account" domain="[]" context="{'group_by': 'account_id'}"/>
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="report_journal">
|
||||
<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-foreach="docs" t-as="o">
|
||||
<t t-if="lines[o.id]">
|
||||
<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 and o.company_id.sudo()">
|
||||
<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>
|
||||
|
||||
<div class="header">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</div>
|
||||
<div class="col-8 text-center">
|
||||
<span t-esc="company.name"/> - <span t-esc="o.name"/>
|
||||
(<span t-if="data['form']['target_move'] == 'all'">Posted and Draft Entries</span><span t-if="data['form']['target_move'] == 'posted'">Posted Entries only</span>)
|
||||
</div>
|
||||
<div class="col-2 text-right">
|
||||
<ul class="list-inline">
|
||||
<li class="list-inline-item"><span class="page"/></li>
|
||||
<li class="list-inline-item">/</li>
|
||||
<li class="list-inline-item"><span class="topage"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="data['form'].get('date_from') or data['form'].get('date_to')">
|
||||
<div class="row">
|
||||
<div class="col-8 offset-2 text-center">
|
||||
<t t-if="data['form'].get('date_from')">
|
||||
From : <span t-esc="data['form'].get('date_from')"/>
|
||||
</t>
|
||||
<t t-if="data['form'].get('date_from') and data['form'].get('date_to')">
|
||||
-
|
||||
</t>
|
||||
<t t-if="data['form'].get('date_to')">
|
||||
To : <span t-esc="data['form'].get('date_to')"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div class="article" 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="page">
|
||||
<h2><t t-esc="o.name"/> Journal<span t-if="data['form']['target_move'] == 'all'"> - Posted and Draft Entries</span><span t-if="data['form']['target_move'] == 'posted'"> - Posted Entries Only</span></h2>
|
||||
<table class="table table-sm table-striped mt-4" id="move_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th t-if="data['form'].get('sort_selection') == 'move_name'">Move</th>
|
||||
<th t-if="data['form'].get('sort_selection') == 'move_name'">Date</th>
|
||||
<th t-if="data['form'].get('sort_selection') == 'date'">Date</th>
|
||||
<th t-if="data['form'].get('sort_selection') == 'date'">Move</th>
|
||||
<!-- Set a minimum width for columns, otherwise the line breaks too early -->
|
||||
<th style="min-width: 150px">Partner</th>
|
||||
<th style="min-width: 250px">Account</th>
|
||||
<th style="min-width: 350px">Label</th>
|
||||
<th t-if="data['form']['amount_currency']" style="text-align: right;">Currency</th>
|
||||
<th style="text-align: right;">Debit</th>
|
||||
<th style="text-align: right;">Credit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-set="last_am" t-value=""/>
|
||||
<t t-set="last_date" t-value=""/>
|
||||
<t t-set="last_partner" t-value=""/>
|
||||
<tr t-foreach="lines[o.id]" t-as="aml">
|
||||
<t t-if="data['form'].get('sort_selection') == 'move_name'">
|
||||
<t t-set="am_name" t-value="aml.move_id.name != '/' and aml.move_id.name or ('*'+str(aml.move_id.id))"/>
|
||||
<t t-if="last_am == am_name">
|
||||
<td/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td><span t-esc="am_name" class="font-weight-bold"/></td>
|
||||
<t t-set="last_am" t-value="am_name"/>
|
||||
<!-- Reset these when changing move -->
|
||||
<t t-set="last_date" t-value=""/>
|
||||
<t t-set="last_partner" t-value=""/>
|
||||
</t>
|
||||
<t t-if="last_date == aml.date">
|
||||
<td/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td><span t-field="aml.date"/></td>
|
||||
<t t-set="last_date" t-value="aml.date"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-set="am_name" t-value="aml.move_id.name != '/' and aml.move_id.name or ('*'+str(aml.move_id.id))"/>
|
||||
<t t-if="last_date == aml.date and last_am == am_name">
|
||||
<td/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td><span t-field="aml.date" class="font-weight-bold"/></td>
|
||||
<t t-set="last_date" t-value="aml.date"/>
|
||||
<!-- Reset these when changing data -->
|
||||
<t t-set="last_am" t-value=""/>
|
||||
<t t-set="last_partner" t-value=""/>
|
||||
</t>
|
||||
<t t-if="last_am == am_name">
|
||||
<td/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td><span t-esc="am_name"/></td>
|
||||
<t t-set="last_am" t-value="am_name"/>
|
||||
<t t-set="last_partner" t-value=""/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-set="partner_name" t-value="aml.sudo().partner_id and aml.sudo().partner_id.name and aml.sudo().partner_id.name or ''"/>
|
||||
<!-- general journals always show partners, as we can have multiple != ones in a single move -->
|
||||
<t t-if="last_partner == partner_name and o.type != 'general'">
|
||||
<td/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td><span t-esc="partner_name"/></td>
|
||||
<t t-set="last_partner" t-value="partner_name"/>
|
||||
</t>
|
||||
<td><span t-field="aml.account_id.code"/> <span t-field="aml.account_id.name"/></td>
|
||||
<td><span t-esc="aml.name"/></td>
|
||||
<td t-if="data['form']['amount_currency'] and aml.amount_currency" class="pull-right">
|
||||
<span class="text-monospace"
|
||||
t-esc="aml.amount_currency"
|
||||
t-options="{'widget': 'monetary', 'display_currency': aml.currency_id}"/>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<span t-if="not (company_id or res_company).currency_id.is_zero(aml.debit)"
|
||||
t-esc="aml.debit"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="text-monospace"/>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<span t-if="not (company_id or res_company).currency_id.is_zero(aml.credit)"
|
||||
t-esc="aml.credit"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="text-monospace"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="bg-white">
|
||||
<td/>
|
||||
<td/>
|
||||
<td/>
|
||||
<td/>
|
||||
<td class="text-right"><strong>Total</strong></td>
|
||||
<td style="text-align: right;">
|
||||
<span t-esc="sum_debit(data, o)"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="font-weight-bold text-monospace"/>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<span t-esc="sum_credit(data, o)"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="font-weight-bold text-monospace"/>
|
||||
|
||||
</td>
|
||||
<td t-if="data['form']['amount_currency']"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row" style="page-break-inside: avoid" id="tax_section">
|
||||
<t t-set="taxes" t-value="get_taxes(data, o)"/>
|
||||
<div class="col-5" t-if="taxes">
|
||||
<table class="table table-sm table-striped" id="tax_table">
|
||||
<thead>
|
||||
<tr><th colspan="3">Taxes Applied</th></tr>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th style="text-align: right;">Base Amount</th>
|
||||
<th style="text-align: right;">Tax Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="taxes" t-as="tax">
|
||||
<td><span t-esc="tax.name"/></td>
|
||||
<td style="text-align: right;">
|
||||
<span t-esc="taxes[tax]['base_amount']"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="text-monospace"/>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<span t-esc="taxes[tax]['tax_amount']"
|
||||
t-options="{
|
||||
'widget': 'monetary',
|
||||
'display_currency': (company_id or res_company).currency_id
|
||||
}"
|
||||
class="text-monospace"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user