Browse Source

[FIX] partner balance webkit: hide partners with balance at 0.0

(lp:c2c-addons/6.1  rev 19.1.3)
6.1
Guewen Baconnier @ Camptocamp 12 years ago
parent
commit
d705c764ba
  1. 23
      account_financial_report_webkit/__init__.py
  2. 114
      account_financial_report_webkit/__openerp__.py
  3. 45
      account_financial_report_webkit/account.py
  4. 89
      account_financial_report_webkit/account_move_line.py
  5. 23
      account_financial_report_webkit/account_move_line_view.xml
  6. 18
      account_financial_report_webkit/account_view.xml
  7. 409
      account_financial_report_webkit/data/financial_webkit_header.xml
  8. 1154
      account_financial_report_webkit/i18n/account_financial_report_webkit.pot
  9. 1160
      account_financial_report_webkit/i18n/en_US.po
  10. 1160
      account_financial_report_webkit/i18n/fr.po
  11. BIN
      account_financial_report_webkit/images/ledger.png
  12. 11
      account_financial_report_webkit/report/__init__.py
  13. 272
      account_financial_report_webkit/report/common_balance_reports.py
  14. 275
      account_financial_report_webkit/report/common_partner_balance_reports.py
  15. 251
      account_financial_report_webkit/report/common_partner_reports.py
  16. 513
      account_financial_report_webkit/report/common_reports.py
  17. 211
      account_financial_report_webkit/report/general_ledger.py
  18. 212
      account_financial_report_webkit/report/open_invoices.py
  19. 80
      account_financial_report_webkit/report/partner_balance.py
  20. 190
      account_financial_report_webkit/report/partners_ledger.py
  21. 115
      account_financial_report_webkit/report/profit_loss.py
  22. 104
      account_financial_report_webkit/report/report.xml
  23. 226
      account_financial_report_webkit/report/templates/account_report_general_ledger.mako
  24. 251
      account_financial_report_webkit/report/templates/account_report_open_invoices.mako
  25. 275
      account_financial_report_webkit/report/templates/account_report_partner_balance.mako
  26. 281
      account_financial_report_webkit/report/templates/account_report_partners_ledger.mako
  27. 210
      account_financial_report_webkit/report/templates/account_report_profit_loss.mako
  28. 217
      account_financial_report_webkit/report/templates/account_report_trial_balance.mako
  29. 82
      account_financial_report_webkit/report/trial_balance.py
  30. 222
      account_financial_report_webkit/report/webkit_parser_header_fix.py
  31. 26
      account_financial_report_webkit/report_menus.xml
  32. 3
      account_financial_report_webkit/tests/account_move_line.yml
  33. 65
      account_financial_report_webkit/tests/general_ledger.yml
  34. 60
      account_financial_report_webkit/tests/open_invoices.yml
  35. 67
      account_financial_report_webkit/tests/partner_balance.yml
  36. 60
      account_financial_report_webkit/tests/partner_ledger.yml
  37. 67
      account_financial_report_webkit/tests/trial_balance.yml
  38. 27
      account_financial_report_webkit/wizard/__init__.py
  39. 295
      account_financial_report_webkit/wizard/balance_common.py
  40. 11
      account_financial_report_webkit/wizard/balance_common_view.xml
  41. 132
      account_financial_report_webkit/wizard/general_ledger_wizard.py
  42. 89
      account_financial_report_webkit/wizard/general_ledger_wizard_view.xml
  43. 127
      account_financial_report_webkit/wizard/open_invoices_wizard.py
  44. 72
      account_financial_report_webkit/wizard/open_invoices_wizard_view.xml
  45. 64
      account_financial_report_webkit/wizard/partner_balance_wizard.py
  46. 85
      account_financial_report_webkit/wizard/partner_balance_wizard_view.xml
  47. 116
      account_financial_report_webkit/wizard/partners_ledger_wizard.py
  48. 69
      account_financial_report_webkit/wizard/partners_ledger_wizard_view.xml
  49. 166
      account_financial_report_webkit/wizard/profit_loss_wizard.py
  50. 72
      account_financial_report_webkit/wizard/profit_loss_wizard_view.xml
  51. 41
      account_financial_report_webkit/wizard/trial_balance_wizard.py
  52. 78
      account_financial_report_webkit/wizard/trial_balance_wizard_view.xml
  53. 4
      account_financial_report_webkit/wizard/wizard.xml

23
account_financial_report_webkit/__init__.py

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import account
from . import wizard
from . import report
from . import account_move_line

114
account_financial_report_webkit/__openerp__.py

@ -0,0 +1,114 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Authors: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# TODO refactor helper in order to act more like mixin
# By using properties we will have a more simple signature in fuctions
{
'name': 'Webkit based extended report financial report',
'description': """
This module replace the following standard openerp financial reports :
- General ledger
- Trial Balance (simple or comparative view)
- Partner ledger
- Partner balance
- Open invoices report
Main improvements per report:
* The General ledger: details of all entries posted in your books sorted by account.
- Filter by account in the wizard (no need to go to the Chart of account to do this anymore) or by view account (the report will display all regular children account) ie: you can select all P&L accounts.
- The report will now print only account with movements OR with a balance not null. No more endless report with accounts with no data. (field: display account is hidden)
- initial balance calculation on the fly if no open entry posted
- Thanks to a new checkbox in account form, you will have possibility to centralize any accounts you like. ie: you do not want to see all entries posted under the account VAT on sales ; you will only see aggregated amounts by periods.
- Counterpart account displayed for each transaction (3 accounts max.) to ease searching.
- Better ergonomy on the wizard: important information at the top, filters in the middle, options at the bottom or separate tab, more specific filtering on a other tabs. No more unique wizard layout for all financial reports (ie: we have removed the journal tab for the GL report)
- improved report style
* The partner ledger: details of entries relative to payable & receivable accounts posted in your books sorted by account and partner.
- Filter by partner now possible
- Now you can see accounts then Partner with subtotals for each account allowing you to check you data with trial balance and partner balance for instance & accounts are ordered the same way than in the Chart of account
- period have been added (date only is uncompleted since date can be outside period)
- Reconciliation code added
- subtotal by account
- alpha sorting (same in partner balance)
* Open invoice report : other version of the partner ledger showing unreconciled / partially reconcies entries
(added on the 20/01/2012)
- Possibility to print unreconciled transactions only at any date in the past (thanks to the brand-new field: last_rec_date which calculated the last move line reconciled date). No more pain to get open invoices at the last closing date.
- no initial balance calculated because the report shows open invoices from previous years.
* The Trial balance: list of account with balances
- you can either see the column : Initial balance , debit, credit , end balance or compare balances over 4 periods of your choice
- You can select the filter opening to get the opening trial balance only
- If you create a extra virtual charts (using consolidated account) of account for your P&L and your balance sheet , you can print your statutory accounts (with comparision over years for ex.)
- If you compare 2 periods, you will get differences in value and % also
* The Partner balance: list of account with balances
- subtotal by account & partner
- alpha sorting (same in partner balance)
Limitations:
In order to run properly this module make sure you have installed the librairie wkhtmltopdf for the pdf rendering (this library path must be added to you company settings).
Initial balances in these reports are based either on opening entry posted in the opening period or calculated on the fly. So make sure, your past accounting opening entries are in a opening period.
Initials balances are not calculated when using date filter (since a date can be outside its logical period and IB could be different by date Vs IB by period)
The opening period is assumed to be the 01.01 of the year with an opening flag and the first period of the year must starts also the 01.01
Totals for amount in currencies are affective if the partner belong to an account with a secondary currency.
html headers and footers are deactivated for these reports because of an issue of wkhtmltopdf : http://code.google.com/p/wkhtmltopdf/issues/detail?id=656
Instead, the header and footer are created as text with arguments passed to wkhtmltopdf. The texts are defined inside the report classes.
""",
'version': '1.0',
'author': 'Camptocamp',
'category': 'Finance',
'website': 'http://www.camptocamp.com',
'images': [
'images/ledger.png',],
'depends': ['account',
'report_webkit'],
'init_xml': [],
'demo_xml' : [],
'update_xml': ['account_view.xml',
'account_move_line_view.xml',
'data/financial_webkit_header.xml',
'report/report.xml',
'wizard/wizard.xml',
'wizard/balance_common_view.xml',
'wizard/general_ledger_wizard_view.xml',
'wizard/partners_ledger_wizard_view.xml',
'wizard/trial_balance_wizard_view.xml',
'wizard/partner_balance_wizard_view.xml',
'wizard/open_invoices_wizard_view.xml',
'report_menus.xml',
# 'wizard/profit_loss_wizard_view.xml',
],
# tests order matter
'test': ['tests/general_ledger.yml',
'tests/partner_ledger.yml',
'tests/trial_balance.yml',
'tests/partner_balance.yml',
'tests/open_invoices.yml',],
#'tests/account_move_line.yml'
'active': False,
'installable': True,
}

45
account_financial_report_webkit/account.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
#
# Author : Guewen Baconnier (Camptocamp)
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import osv, fields
class AccountAccount(osv.osv):
_inherit = 'account.account'
_columns = {
'centralized': fields.boolean('Centralized', help="If flagged, no details will be displayed in the General Ledger report (the webkit one only), only centralized amounts per period.")
}
_defaults = {
'centralized': False,
}
AccountAccount()

89
account_financial_report_webkit/account_move_line.py

@ -0,0 +1,89 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi.
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields, osv
from tools.translate import _
class AccountMoveLine(osv.osv):
"""Overriding Account move line in order to add last_rec_date.
Last rec date is the date of the last reconciliation (full or partial) account move line"""
_inherit = 'account.move.line'
def init(self, cr):
##We do not want to catch error as if sql is not run it will give invalid data
cr.execute("UPDATE account_move_line as acm "
" SET last_rec_date ="
" (SELECT date from account_move_line"
" WHERE reconcile_id = acm.reconcile_id"
" AND reconcile_id IS NOT NULL"
" ORDER BY date DESC LIMIT 1)"
" WHERE last_rec_date is null;")
cr.execute("UPDATE account_move_line as acm "
" SET last_rec_date ="
" (SELECT date from account_move_line"
" WHERE reconcile_partial_id = acm.reconcile_partial_id"
" AND reconcile_partial_id IS NOT NULL"
" ORDER BY date DESC LIMIT 1)"
" WHERE last_rec_date is null;")
def _get_move_line_from_line_rec(self, cr, uid, ids, context=None):
moves = []
for reconcile in self.pool.get('account.move.reconcile').browse(cr, uid, ids, context=context):
for move_line in reconcile.line_partial_ids:
moves.append(move_line.id)
for move_line in reconcile.line_id:
moves.append(move_line.id)
return list(set(moves))
def _get_last_rec_date(self, cursor, uid, ids, name, args, context=None):
if not isinstance(ids, list):
ids = [ids]
res = {}
for line in self.browse(cursor, uid, ids, context):
res[line.id] = {'last_rec_date': False}
rec = line.reconcile_id or line.reconcile_partial_id or False
if rec:
# we use cursor in order to gain some perfs
cursor.execute('SELECT date from account_move_line where'
' reconcile_id = %s OR reconcile_partial_id = %s'
' ORDER BY date DESC LIMIT 1 ',
(rec.id, rec.id))
res_set = cursor.fetchone()
if res_set:
res[line.id] = {'last_rec_date': res_set[0]}
return res
_columns = {
'last_rec_date': fields.function(_get_last_rec_date,
method=True,
string='Last reconciliation date',
store={'account.move.line': (lambda self, cr, uid, ids, c={}: ids, ['date'], 20),
'account.move.reconcile': (_get_move_line_from_line_rec, None ,20)},
type='date',
multi='all',
help="the date of the last reconciliation (full or partial) account move line"),
}
AccountMoveLine()

23
account_financial_report_webkit/account_move_line_view.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="last_rec_date_form">
<!-- must be unique in this module. -->
<field name="name">last_rec_date_form</field>
<field name="model">account.move.line</field>
<!--parent python entity -->
<field name="inherit_id" ref="account.view_move_line_form"/>
<!-- modulename.view -->
<field name="type">form</field>
<field name="arch" type="xml">
<separator string="Narration" colspan="4" position="before">
<separator string="Misc."/>
<newline/>
<group>
<field name="last_rec_date" readonly="1"/>
</group>
</separator>
</field>
</record>
</data>
</openerp>

18
account_financial_report_webkit/account_view.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_account_form_webkit" model="ir.ui.view">
<field name="name">account.account.form.webkit</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<data>
<field name="active" position="after">
<field name="centralized" groups="base.group_extended"/>
</field>
</data>
</field>
</record>
</data>
</openerp>

409
account_financial_report_webkit/data/financial_webkit_header.xml

@ -0,0 +1,409 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<record id="financial_landscape_header" model="ir.header_webkit">
<field name="footer_html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
</head>
<% import datetime %>
<body style="border:0; margin: 0;" onload="subst()">
<table style="border-top: 1px solid black; width: 1080px">
<tr style="border-collapse:collapse;">
<td style="text-align:left;font-size:10;width:350px;">${formatLang( str(datetime.datetime.today()), date_time=True)}</td>
<td style="text-align:center;font-size:10;width:350px;">${user.name}</td>
<td style="text-align:right;font-size:10;width:350px;">Page&nbsp;<span class="page"/></td>
<td style="text-align:left;font-size:10;width:30px">&nbsp;of&nbsp;<span class="topage"/></td>
</tr>
</table>
</body>
</html>]]></field>
<field name="orientation">Landscape</field>
<field name="format">A4</field>
<field name="html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
<style type="text/css">
${css}
</style>
</head>
<body style="border:0; margin: 0;" onload="subst()">
<table class="header" style="border-bottom: 0px solid black; width: 100%">
<tr>
<td style="text-align:left; font-size:11px; font-weight: bold;"><span style="text-transform:uppercase; font-size:12px;">${report_name}</span> - ${company.partner_id.name | entity} - ${company.currency_id.name | entity}</td>
</tr>
</table> ${_debug or ''|n} </body>
</html>]]>
</field>
<field eval="0.0" name="margin_top"/>
<field name="css"><![CDATA[
body, table, td, span, div {
font-family: Helvetica, Arial;
}
.act_as_table {
display: table;
}
.act_as_row {
display: table-row;
}
.act_as_cell {
display: table-cell;
}
.act_as_thead {
display: table-header-group;
}
.act_as_tbody {
display: table-row-group;
}
.act_as_tfoot {
display: table-footer-group;
}
.act_as_caption {
display: table-caption;
}
act_as_colgroup {
display: table-column-group;
}
.list_table, .data_table {
width: 1080px;
table-layout: fixed
}
.bg, .act_as_row.labels {
background-color:#F0F0F0;
}
.list_table, .data_table, .list_table .act_as_row {
border-left:0px;
border-right:0px;
text-align:left;
font-size:9px;
padding-right:3px;
padding-left:3px;
padding-top:2px;
padding-bottom:2px;
border-collapse:collapse;
}
.list_table .act_as_row.labels, .list_table .act_as_row.initial_balance, .list_table .act_as_row.lines {
border-color:gray;
border-bottom:1px solid lightGrey;
}
.data_table .act_as_cell {
border: 1px solid lightGrey;
text-align: center;
}
.data_table .act_as_cell, .list_table .act_as_cell {
word-wrap: break-word;
}
.data_table .act_as_row.labels {
font-weight: bold;
}
.initial_balance .act_as_cell {
font-style:italic;
}
.account_title {
font-size:10px;
font-weight:bold;
page-break-after: avoid;
}
.act_as_cell.amount {
word-wrap:normal;
text-align:right;
}
.list_table .act_as_cell{
padding-left: 5px;
/* border-right:1px solid lightGrey; uncomment to active column lines */
}
.list_table .act_as_cell.first_column {
padding-left: 0px;
/* border-left:1px solid lightGrey; uncomment to active column lines */
}
.sep_left {
border-left: 1px solid lightGrey;
}
.overflow_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.open_invoice_previous_line {
font-style: italic;
}
.clearance_line {
font-style: italic;
}
]]>
</field>
<field name="name">Financial Landscape Header</field>
</record>
<record id="financial_portrait_header" model="ir.header_webkit">
<field name="footer_html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
</head>
<% import datetime %>
<body style="border:0; margin: 0;" onload="subst()">
<table style="border-top: 1px solid black; width: 1080px">
<tr style="border-collapse:collapse;">
<td style="text-align:left;font-size:10;width:350px;">${formatLang( str(datetime.datetime.today()), date_time=True)}</td>
<td style="text-align:center;font-size:10;width:350px;">${user.name}</td>
<td style="text-align:right;font-size:10;width:350px;">Page&nbsp;<span class="page"/></td>
<td style="text-align:left;font-size:10;width:30px">&nbsp;of&nbsp;<span class="topage"/></td>
</tr>
</table>
</body>
</html>]]></field>
<field name="orientation">Portrait</field>
<field name="format">A4</field>
<field name="html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
<style type="text/css">
${css}
</style>
</head>
<body style="border:0; margin: 0;" onload="subst()">
<table class="header" style="border-bottom: 0px solid black; width: 100%">
<tr>
<td style="text-align:left; font-size:11px; font-weight: bold;"><span style="text-transform:uppercase; font-size:12px;">${report_name}</span> - ${company.partner_id.name | entity} - ${company.currency_id.name | entity}</td>
</tr>
</table> ${_debug or ''|n} </body>
</html>]]>
</field>
<field eval="17.0" name="margin_top"/>
<field eval="15.0" name="margin_bottom"/>
<field name="css"><![CDATA[
body, table, td, span, div {
font-family: Helvetica, Arial;
}
.act_as_table {
display: table;
}
.act_as_row {
display: table-row;
}
.act_as_cell {
display: table-cell;
}
.act_as_thead {
display: table-header-group;
}
.act_as_tbody {
display: table-row-group;
}
.act_as_tfoot {
display: table-footer-group;
}
.act_as_caption {
display: table-caption;
}
act_as_colgroup {
display: table-column-group;
}
.list_table, .data_table {
width: 690px;
table-layout: fixed
}
.bg, .act_as_row.labels {
background-color:#F0F0F0;
}
.list_table, .data_table, .list_table .act_as_row {
border-left:0px;
border-right:0px;
text-align:left;
font-size:9px;
padding-right:3px;
padding-left:3px;
padding-top:2px;
padding-bottom:2px;
border-collapse:collapse;
}
.list_table .act_as_row.labels, .list_table .act_as_row.initial_balance, .list_table .act_as_row.lines {
border-color:gray;
border-bottom:1px solid lightGrey;
}
.data_table .act_as_cell {
border: 1px solid lightGrey;
text-align: center;
}
.data_table .act_as_cell, .list_table .act_as_cell {
word-wrap: break-word;
}
.data_table .act_as_row.labels {
font-weight: bold;
}
.initial_balance .act_as_cell {
font-style:italic;
}
.account_title {
font-size:10px;
font-weight:bold;
page-break-after: avoid;
}
.act_as_cell.amount {
word-wrap:normal;
text-align:right;
}
.list_table .act_as_cell{
padding-left: 5px;
/* border-right:1px solid lightGrey; uncomment to active column lines */
}
.list_table .act_as_cell.first_column {
padding-left: 0px;
/* border-left:1px solid lightGrey; uncomment to active column lines */
}
.sep_left {
border-left: 1px solid lightGrey;
}
.account_level_1 {
text-transform: uppercase;
/*font-weight: bold;*/
font-size: 15px;
background-color:#F0F0F0;
}
/*
.account_level_1 .act_as_cell {
height: 30px;
vertical-align: bottom;
}
*/
.account_level_2 {
/*text-transform: uppercase;
font-weight: bold;*/
font-size: 12px;
background-color:#F0F0F0;
}
/*
.account_level_2 .act_as_cell {
height: 20px;
vertical-align: bottom;
}
.account_level_3 {
text-transform: uppercase;
font-weight: bold;
font-size: 11px;
background-color:#FAFAFA;
}
.account_level_4 {
font-weight: bold;
font-size: 11px;
}
*/
.account_level_5 {
}
.regular_account_type {
font-weight: normal;
}
.view_account_type {
font-weight: bold;
.account_level_consol {
font-weight: normal;
font-style: italic;
}
.overflow_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
]]>
</field>
<field name="name">Financial Portrait Header</field>
</record>
</data>
</openerp>

1154
account_financial_report_webkit/i18n/account_financial_report_webkit.pot
File diff suppressed because it is too large
View File

1160
account_financial_report_webkit/i18n/en_US.po
File diff suppressed because it is too large
View File

1160
account_financial_report_webkit/i18n/fr.po
File diff suppressed because it is too large
View File

BIN
account_financial_report_webkit/images/ledger.png

After

Width: 1553  |  Height: 271  |  Size: 54 KiB

11
account_financial_report_webkit/report/__init__.py

@ -0,0 +1,11 @@
from . import common_reports
from . import common_partner_reports
from . import common_balance_reports
from . import common_partner_balance_reports
from . import general_ledger
from . import partners_ledger
from . import webkit_parser_header_fix
from . import trial_balance
from . import partner_balance
from . import open_invoices
#from . import account_report_profit_loss

272
account_financial_report_webkit/report/common_balance_reports.py

@ -0,0 +1,272 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
# SQL inspired from OpenERP original code
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from operator import add
from common_reports import CommonReportHeaderWebkit
class CommonBalanceReportHeaderWebkit(CommonReportHeaderWebkit):
"""Define common helper for balance (trial balance, P&L, BS oriented financial report"""
def _get_numbers_display(self, data):
return self._get_form_param('numbers_display', data)
@staticmethod
def find_key_by_value_in_list(dic, value):
return [key for key, val in dic.iteritems() if value in val][0]
def _get_account_details(self, account_ids, target_move, fiscalyear, main_filter, start, stop, initial_balance_mode, context=None):
"""
Get details of accounts to display on the report
@param account_ids: ids of accounts to get details
@param target_move: selection filter for moves (all or posted)
@param fiscalyear: browse of the fiscalyear
@param main_filter: selection filter period / date or none
@param start: start date or start period browse instance
@param stop: stop date or stop period browse instance
@param initial_balance_mode: False: no calculation, 'opening_balance': from the opening period, 'initial_balance': computed from previous year / periods
@return: dict of list containing accounts details, keys are the account ids
"""
if context is None:
context = {}
account_obj = self.pool.get('account.account')
period_obj = self.pool.get('account.period')
use_period_ids = main_filter in ('filter_no', 'filter_period', 'filter_opening')
if use_period_ids:
if main_filter == 'filter_opening':
period_ids = [start.id]
else:
period_ids = period_obj.build_ctx_periods(self.cursor, self.uid, start.id, stop.id)
# never include the opening in the debit / credit amounts
period_ids = self.exclude_opening_periods(period_ids)
init_balance = False
if initial_balance_mode == 'opening_balance':
init_balance = self._read_opening_balance(account_ids, start)
elif initial_balance_mode:
init_balance = self._compute_initial_balances(account_ids, start, fiscalyear)
ctx = context.copy()
ctx.update({'state': target_move,
'all_fiscalyear': True})
if use_period_ids:
ctx.update({'periods': period_ids,})
elif main_filter == 'filter_date':
ctx.update({'date_from': start,
'date_to': stop})
accounts = account_obj.read(self.cursor, self.uid, account_ids, ['type','code','name','debit','credit', 'balance', 'parent_id','level','child_id'], ctx)
accounts_by_id = {}
for account in accounts:
if init_balance:
# sum for top level views accounts
child_ids = account_obj._get_children_and_consol(self.cursor, self.uid, account['id'], ctx)
if child_ids:
child_init_balances = [init_bal['init_balance'] for acnt_id, init_bal in init_balance.iteritems() if acnt_id in child_ids ]
top_init_balance = reduce(add, child_init_balances)
account['init_balance'] = top_init_balance
else:
account.update(init_balance[account['id']])
account['balance'] = account['init_balance'] + account['debit'] - account['credit']
accounts_by_id[account['id']] = account
return accounts_by_id
def _get_comparison_details(self, data, account_ids, target_move, comparison_filter, index):
"""
@param data: data of the wizard form
@param account_ids: ids of the accounts to get details
@param comparison_filter: selected filter on the form for the comparison (filter_no, filter_year, filter_period, filter_date)
@param index: index of the fields to get (ie. comp1_fiscalyear_id where 1 is the index)
@return: dict of account details (key = account id)
"""
fiscalyear = self._get_info(data, "comp%s_fiscalyear_id" % (index,), 'account.fiscalyear')
start_period = self._get_info(data, "comp%s_period_from" % (index,), 'account.period')
stop_period = self._get_info(data, "comp%s_period_to" % (index,), 'account.period')
start_date = self._get_form_param("comp%s_date_from" % (index,), data)
stop_date = self._get_form_param("comp%s_date_to" % (index,), data)
init_balance = self.is_initial_balance_enabled(comparison_filter)
accounts_by_ids = {}
comp_params = {}
details_filter = comparison_filter
if comparison_filter != 'filter_no':
start_period, stop_period, start, stop = \
self._get_start_stop_for_filter(comparison_filter, fiscalyear, start_date, stop_date, start_period, stop_period)
if comparison_filter == 'filter_year':
details_filter = 'filter_no'
initial_balance_mode = init_balance and self._get_initial_balance_mode(start) or False
accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, details_filter,
start, stop, initial_balance_mode)
comp_params = {
'comparison_filter': comparison_filter,
'fiscalyear': fiscalyear,
'start': start,
'stop': stop,
'initial_balance': init_balance,
'initial_balance_mode': initial_balance_mode,
}
return accounts_by_ids, comp_params
def _get_diff(self, balance, previous_balance):
"""
@param balance: current balance
@param previous_balance: last balance
@return: dict of form {'diff': difference, 'percent_diff': diff in percentage}
"""
diff = balance - previous_balance
obj_precision = self.pool.get('decimal.precision')
precision = obj_precision.precision_get(self.cursor, self.uid, 'Account')
# round previous balance with account precision to avoid big numbers if previous
# balance is 0.0000001 or a any very small number
if round(previous_balance, precision) == 0:
percent_diff = False
else:
percent_diff = round(diff / previous_balance * 100, precision)
return {'diff': diff, 'percent_diff': percent_diff}
def _comp_filters(self, data, comparison_number):
"""
@param data: data of the report
@param comparison_number: number of comparisons
@return: list of comparison filters, nb of comparisons used and comparison mode (no_comparison, single, multiple)
"""
comp_filters = []
for index in range(comparison_number):
comp_filters.append(self._get_form_param("comp%s_filter" % (index,), data, default='filter_no'))
nb_comparisons = len([comp_filter for comp_filter in comp_filters if comp_filter != 'filter_no'])
if not nb_comparisons:
comparison_mode = 'no_comparison'
elif nb_comparisons > 1:
comparison_mode = 'multiple'
else:
comparison_mode = 'single'
return comp_filters, nb_comparisons, comparison_mode
def _get_start_stop_for_filter(self, main_filter, fiscalyear, start_date, stop_date, start_period, stop_period):
if main_filter in ('filter_no', 'filter_year'):
start_period = self.get_first_fiscalyear_period(fiscalyear)
stop_period = self.get_last_fiscalyear_period(fiscalyear)
elif main_filter == 'filter_opening':
opening_period = self._get_st_fiscalyear_period(fiscalyear, special=True)
start_period = stop_period = opening_period
if main_filter == 'filter_date':
start = start_date
stop = stop_date
else:
start = start_period
stop = stop_period
return start_period, stop_period, start, stop
def compute_balance_data(self, data, filter_report_type=None):
new_ids = data['form']['account_ids'] or data['form']['chart_account_id']
max_comparison = self._get_form_param('max_comparison', data, default=0)
main_filter = self._get_form_param('filter', data, default='filter_no')
comp_filters, nb_comparisons, comparison_mode = self._comp_filters(data, max_comparison)
fiscalyear = self.get_fiscalyear_br(data)
start_period = self.get_start_period_br(data)
stop_period = self.get_end_period_br(data)
target_move = self._get_form_param('target_move', data, default='all')
start_date = self._get_form_param('date_from', data)
stop_date = self._get_form_param('date_to', data)
chart_account = self._get_chart_account_id_br(data)
start_period, stop_period, start, stop = \
self._get_start_stop_for_filter(main_filter, fiscalyear, start_date, stop_date, start_period, stop_period)
init_balance = self.is_initial_balance_enabled(main_filter)
initial_balance_mode = init_balance and self._get_initial_balance_mode(start) or False
# Retrieving accounts
account_ids = self.get_all_accounts(new_ids, only_type=filter_report_type)
# get details for each accounts, total of debit / credit / balance
accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, main_filter, start, stop, initial_balance_mode)
comparison_params = []
comp_accounts_by_ids = []
for index in range(max_comparison):
if comp_filters[index] != 'filter_no':
comparison_result, comp_params = self._get_comparison_details(data, account_ids, target_move, comp_filters[index], index)
comparison_params.append(comp_params)
comp_accounts_by_ids.append(comparison_result)
to_display = dict.fromkeys(account_ids, True)
objects = []
for account in self.pool.get('account.account').browse(self.cursor, self.uid, account_ids):
if not account.parent_id: # hide top level account
continue
if account.type == 'consolidation':
to_display.update(dict([(a.id, False) for a in account.child_consol_ids]))
elif account.type == 'view':
to_display.update(dict([(a.id, True) for a in account.child_id]))
account.debit = accounts_by_ids[account.id]['debit']
account.credit = accounts_by_ids[account.id]['credit']
account.balance = accounts_by_ids[account.id]['balance']
account.init_balance = accounts_by_ids[account.id].get('init_balance', 0.0)
display_account = False # if any amount is != 0 in comparisons, we have to display the whole account
comp_accounts = []
for comp_account_by_id in comp_accounts_by_ids:
values = comp_account_by_id.get(account.id)
values.update(self._get_diff(account.balance, values['balance']))
display_account = any((values.get('credit', 0.0), values.get('debit', 0.0), values.get('balance', 0.0), values.get('init_balance', 0.0)))
comp_accounts.append(values)
account.comparisons = comp_accounts
# we have to display the account if a comparison as an amount or if we have an amount in the main column
# we set it as a property to let the data in the report if someone want to use it in a custom report
display_account = display_account or any((account.debit, account.credit, account.balance, account.init_balance))
to_display.update({account.id: display_account and to_display[account.id]})
objects.append(account)
for account in objects:
account.to_display = to_display[account.id]
context_report_values = {
'fiscalyear': fiscalyear,
'start_date': start_date,
'stop_date': stop_date,
'start_period': start_period,
'stop_period': stop_period,
'chart_account': chart_account,
'comparison_mode': comparison_mode,
'nb_comparison': nb_comparisons,
'initial_balance': init_balance,
'initial_balance_mode': initial_balance_mode,
'comp_params': comparison_params,
}
return objects, new_ids, context_report_values

275
account_financial_report_webkit/report/common_partner_balance_reports.py

@ -0,0 +1,275 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
# SQL inspired from OpenERP original code
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from collections import defaultdict
from operator import add
from common_balance_reports import CommonBalanceReportHeaderWebkit
from common_partner_reports import CommonPartnersReportHeaderWebkit
class CommonPartnerBalanceReportHeaderWebkit(CommonBalanceReportHeaderWebkit, CommonPartnersReportHeaderWebkit):
"""Define common helper for balance (trial balance, P&L, BS oriented financial report"""
def _get_account_partners_details(self, account_by_ids, main_filter, target_move, start,
stop, initial_balance_mode, partner_filter_ids=False):
res = {}
filter_from = False
if main_filter in ('filter_period', 'filter_no', 'filter_opening'):
filter_from = 'period'
elif main_filter == 'filter_date':
filter_from = 'date'
partners_init_balances_by_ids = {}
for account_id, account_details in account_by_ids.iteritems():
partners_init_balances_by_ids.update(self._get_partners_initial_balances(account_id,
start,
initial_balance_mode,
partner_filter_ids=partner_filter_ids,
exclude_reconcile=False)) # we'll never exclude reconciled entries in the legal reports
opening_mode = 'exclude_opening'
if main_filter == 'filter_opening':
opening_mode = 'include_opening'
# get credit and debit for partner
details = self._get_partners_totals_account(filter_from,
account_id,
start,
stop,
target_move,
partner_filter_ids=partner_filter_ids,
mode=opening_mode)
# merge initial balances in partner details
if partners_init_balances_by_ids.get(account_id):
for partner_id, initial_balances in partners_init_balances_by_ids[account_id].iteritems():
if initial_balances.get('init_balance'):
details[partner_id].update({'init_balance': initial_balances['init_balance']})
# compute balance for the partner
for partner_id, partner_details in details.iteritems():
details[partner_id]['balance'] = details[partner_id].get('init_balance', 0.0) +\
details[partner_id].get('debit', 0.0) -\
details[partner_id].get('credit', 0.0)
res[account_id] = details
return res
def _get_partners_initial_balances(self, account_ids, start_period, initial_balance_mode, partner_filter_ids=None, exclude_reconcile=False):
# we get the initial balance from the opening period (opening_balance) when the opening period is included in the start period and
# when there is at least one entry in the opening period. Otherwise we compute it from previous periods
if initial_balance_mode == 'opening_balance':
opening_period_selected = self.get_included_opening_period(start_period)
res = self._compute_partners_initial_balances(account_ids, start_period, partner_filter_ids, force_period_ids=opening_period_selected, exclude_reconcile=exclude_reconcile)
elif initial_balance_mode == 'initial_balance':
res = self._compute_partners_initial_balances(account_ids, start_period, partner_filter_ids, exclude_reconcile=exclude_reconcile)
else:
res = {}
return res
def _get_partners_totals_account(self, filter_from, account_id, start, stop, target_move, partner_filter_ids=None, mode='exclude_opening'):
final_res = defaultdict(dict)
sql_select = """
SELECT account_move_line.partner_id,
sum(account_move_line.debit) AS debit,
sum(account_move_line.credit) AS credit
FROM account_move_line"""
sql_joins = ''
sql_where = "WHERE account_move_line.account_id = %(account_id)s AND account_move_line.state = 'valid' "
sql_conditions, search_params = getattr(self, '_get_query_params_from_'+filter_from+'s')(start, stop, mode=mode)
sql_where += sql_conditions
if partner_filter_ids:
sql_where += " AND account_move_line.partner_id in %(partner_ids)s"
search_params.update({'partner_ids': tuple(partner_filter_ids),})
if target_move == 'posted':
sql_joins += "INNER JOIN account_move ON account_move_line.move_id = account_move.id"
sql_where += " AND account_move.state = %(target_move)s"
search_params.update({'target_move': target_move,})
sql_groupby = "GROUP BY account_move_line.partner_id"
search_params.update({'account_id': account_id,})
query = ' '.join((sql_select, sql_joins, sql_where, sql_groupby))
self.cursor.execute(query, search_params)
res = self.cursor.dictfetchall()
if res:
for row in res:
final_res[row['partner_id']] = row
return final_res
def _get_filter_type(self, result_selection):
filter_type = ('payable', 'receivable')
if result_selection == 'customer':
filter_type = ('receivable',)
if result_selection == 'supplier':
filter_type = ('payable',)
return filter_type
def _get_partners_comparison_details(self, data, account_ids, target_move, comparison_filter, index, partner_filter_ids=False):
"""
@param data: data of the wizard form
@param account_ids: ids of the accounts to get details
@param comparison_filter: selected filter on the form for the comparison (filter_no, filter_year, filter_period, filter_date)
@param index: index of the fields to get (ie. comp1_fiscalyear_id where 1 is the index)
@param partner_filter_ids: list of ids of partners to select
@return: dict of account details (key = account id)
"""
fiscalyear = self._get_info(data, "comp%s_fiscalyear_id" % (index,), 'account.fiscalyear')
start_period = self._get_info(data, "comp%s_period_from" % (index,), 'account.period')
stop_period = self._get_info(data, "comp%s_period_to" % (index,), 'account.period')
start_date = self._get_form_param("comp%s_date_from" % (index,), data)
stop_date = self._get_form_param("comp%s_date_to" % (index,), data)
init_balance = self.is_initial_balance_enabled(comparison_filter)
comp_params = {}
accounts_details_by_ids = defaultdict(dict)
if comparison_filter != 'filter_no':
start_period, stop_period, start, stop = \
self._get_start_stop_for_filter(comparison_filter, fiscalyear, start_date, stop_date, start_period, stop_period)
details_filter = comparison_filter
if comparison_filter == 'filter_year':
details_filter = 'filter_no'
initial_balance_mode = init_balance and self._get_initial_balance_mode(start) or False
accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, details_filter, start, stop, initial_balance_mode)
partner_details_by_ids = self._get_account_partners_details(accounts_by_ids, details_filter,
target_move, start, stop, initial_balance_mode,
partner_filter_ids=partner_filter_ids)
for account_id in account_ids:
accounts_details_by_ids[account_id]['account'] = accounts_by_ids[account_id]
accounts_details_by_ids[account_id]['partners_amounts'] = partner_details_by_ids[account_id]
comp_params = {
'comparison_filter': comparison_filter,
'fiscalyear': fiscalyear,
'start': start,
'stop': stop,
'initial_balance_mode': initial_balance_mode,
}
return accounts_details_by_ids, comp_params
def compute_partner_balance_data(self, data, filter_report_type=None):
new_ids = data['form']['account_ids'] or data['form']['chart_account_id']
max_comparison = self._get_form_param('max_comparison', data, default=0)
main_filter = self._get_form_param('filter', data, default='filter_no')
comp_filters, nb_comparisons, comparison_mode = self._comp_filters(data, max_comparison)
fiscalyear = self.get_fiscalyear_br(data)
start_period = self.get_start_period_br(data)
stop_period = self.get_end_period_br(data)
target_move = self._get_form_param('target_move', data, default='all')
start_date = self._get_form_param('date_from', data)
stop_date = self._get_form_param('date_to', data)
chart_account = self._get_chart_account_id_br(data)
result_selection = self._get_form_param('result_selection', data)
partner_ids = self._get_form_param('partner_ids', data)
filter_type = self._get_filter_type(result_selection)
start_period, stop_period, start, stop = \
self._get_start_stop_for_filter(main_filter, fiscalyear, start_date, stop_date, start_period, stop_period)
initial_balance = self.is_initial_balance_enabled(main_filter)
initial_balance_mode = initial_balance and self._get_initial_balance_mode(start) or False
# Retrieving accounts
account_ids = self.get_all_accounts(new_ids, only_type=filter_type,
filter_report_type=filter_report_type)
# get details for each accounts, total of debit / credit / balance
accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, main_filter, start, stop, initial_balance_mode)
partner_details_by_ids = self._get_account_partners_details(accounts_by_ids,
main_filter,
target_move,
start,
stop,
initial_balance_mode,
partner_filter_ids=partner_ids)
comparison_params = []
comp_accounts_by_ids = []
for index in range(max_comparison):
if comp_filters[index] != 'filter_no':
comparison_result, comp_params = self._get_partners_comparison_details(data, account_ids,
target_move, comp_filters[index],
index, partner_filter_ids=partner_ids)
comparison_params.append(comp_params)
comp_accounts_by_ids.append(comparison_result)
objects = []
for account in self.pool.get('account.account').browse(self.cursor, self.uid, account_ids):
if not account.parent_id: # hide top level account
continue
account.debit = accounts_by_ids[account.id]['debit']
account.credit = accounts_by_ids[account.id]['credit']
account.balance = accounts_by_ids[account.id]['balance']
account.init_balance = accounts_by_ids[account.id].get('init_balance', 0.0)
account.partners_amounts = partner_details_by_ids[account.id]
comp_accounts = []
for comp_account_by_id in comp_accounts_by_ids:
values = comp_account_by_id.get(account.id)
values['account'].update(self._get_diff(account.balance, values['account'].get('balance', 0.0)))
comp_accounts.append(values)
for partner_id, partner_values in values['partners_amounts'].copy().iteritems():
base_partner_balance = account.partners_amounts[partner_id]['balance'] if \
account.partners_amounts.get(partner_id) else 0.0
partner_values.update(self._get_diff(base_partner_balance,
partner_values.get('balance', 0.0)))
values['partners_amounts'][partner_id].update(partner_values)
account.comparisons = comp_accounts
all_partner_ids = reduce(add, [comp['partners_amounts'].keys() for comp in comp_accounts],
account.partners_amounts.keys())
account.partners_order = self._order_partners(all_partner_ids)
objects.append(account)
context_report_values = {
'fiscalyear': fiscalyear,
'start_date': start_date,
'stop_date': stop_date,
'start_period': start_period,
'stop_period': stop_period,
'chart_account': chart_account,
'comparison_mode': comparison_mode,
'nb_comparison': nb_comparisons,
'comp_params': comparison_params,
'initial_balance_mode': initial_balance_mode,
'compute_diff': self._get_diff,
}
return objects, new_ids, context_report_values

251
account_financial_report_webkit/report/common_partner_reports.py

@ -0,0 +1,251 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
# SQL inspired from OpenERP original code
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# TODO refactor helper in order to act more like mixin
# By using properties we will have a more simple signature in fuctions
from collections import defaultdict
from common_reports import CommonReportHeaderWebkit
class CommonPartnersReportHeaderWebkit(CommonReportHeaderWebkit):
"""Define common helper for partner oriented financial report"""
####################Account move line retrieval helper ##########################
def get_partners_move_lines_ids(self, account_id, main_filter, start, stop, target_move,
exclude_reconcile=False, partner_filter=False):
filter_from = False
if main_filter in ('filter_period', 'filter_no'):
filter_from = 'period'
elif main_filter == 'filter_date':
filter_from = 'date'
if filter_from:
return self._get_partners_move_line_ids(filter_from,
account_id,
start,
stop,
target_move,
exclude_reconcile=exclude_reconcile,
partner_filter=partner_filter)
def _get_query_params_from_periods(self, period_start, period_stop, mode='exclude_opening'):
# we do not want opening period so we exclude opening
periods = self.pool.get('account.period').build_ctx_periods(self.cr, self.uid, period_start.id, period_stop.id)
if not periods:
return []
if mode == 'exclude_opening':
periods = self.exclude_opening_periods(periods)
search_params = {'period_ids': tuple(periods),
'date_stop': period_stop.date_stop}
sql_conditions = " AND account_move_line.period_id in %(period_ids)s"
return sql_conditions, search_params
def _get_query_params_from_dates(self, date_start, date_stop, **args):
periods = self._get_opening_periods()
if not periods:
periods = (-1,)
search_params = {'period_ids': tuple(periods),
'date_start': date_start,
'date_stop': date_stop}
sql_conditions = " AND account_move_line.period_id not in %(period_ids)s" \
" AND account_move_line.date between date(%(date_start)s) and date((%(date_stop)s))"
return sql_conditions, search_params
def _get_partners_move_line_ids(self, filter_from, account_id, start, stop, target_move, opening_mode='include_opening',
exclude_reconcile=False, partner_filter=False):
final_res = defaultdict(list)
sql_select = "SELECT account_move_line.id, account_move_line.partner_id FROM account_move_line"
sql_joins = ''
sql_where = " WHERE account_move_line.account_id = %(account_ids)s " \
" AND account_move_line.state = 'valid' "
sql_conditions, search_params = getattr(self, '_get_query_params_from_'+filter_from+'s')(start, stop, mode=opening_mode)
sql_where += sql_conditions
if exclude_reconcile:
sql_where += (" AND ((account_move_line.reconcile_id IS NULL)"
" OR (account_move_line.reconcile_id IS NOT NULL AND account_move_line.last_rec_date > date(%(date_stop)s)))")
if partner_filter:
sql_where += " AND account_move_line.partner_id in %(partner_ids)s"
if target_move == 'posted':
sql_joins += "INNER JOIN account_move ON account_move_line.move_id = account_move.id"
sql_where += " AND account_move.state = %(target_move)s"
search_params.update({'target_move': target_move,})
search_params.update({
'account_ids': account_id,
'partner_ids': tuple(partner_filter),
})
sql = ' '.join((sql_select, sql_joins, sql_where))
self.cursor.execute(sql, search_params)
res = self.cursor.dictfetchall()
if res:
for row in res:
final_res[row['partner_id']].append(row['id'])
return final_res
def _get_clearance_move_line_ids(self, move_line_ids, date_stop, date_until):
if not move_line_ids:
return []
move_line_obj = self.pool.get('account.move.line')
# we do not use orm in order to gain perfo
# In this case I have to test the effective gain over an itteration
# Actually ORM does not allows distinct behavior
sql = "Select distinct reconcile_id from account_move_line where id in %s"
self.cursor.execute(sql, (tuple(move_line_ids),))
rec_ids = self.cursor.fetchall()
if rec_ids:
rec_ids = [x[0] for x in rec_ids]
l_ids = move_line_obj.search(self.cursor,
self.uid,
[('reconcile_id', 'in', rec_ids),
('date', '>=', date_stop),
('date', '<=', date_until)])
return l_ids
else:
return []
####################Initial Partner Balance helper ########################
def _tree_move_line_ids(self, move_lines_data, key=None):
"""
move_lines_data must be a list of dict which contains at least keys :
- account_id
- partner_id
- other keys with values of the line
- if param key is defined, only this key will be inserted in the tree
returns a tree like
res[account_id.1][partner_id.1][move_line.1,
move_line.2]
[partner_id.2][move_line.3]
res[account_id.2][partner_id.1][move_line.4]
"""
res = defaultdict(dict)
for row in move_lines_data[:]:
account_id = row.pop('account_id')
partner_id = row.pop('partner_id')
if key:
res[account_id].setdefault(partner_id, []).append(row[key])
else:
res[account_id][partner_id] = row
return res
def _partners_initial_balance_line_ids(self, account_ids, start_period, partner_filter, exclude_reconcile=False, force_period_ids=False, date_stop=None):
# take ALL previous periods
period_ids = force_period_ids \
if force_period_ids \
else self._get_period_range_from_start_period(start_period, fiscalyear=False, include_opening=False)
if not period_ids:
period_ids = [-1]
search_param = {'date_start': start_period.date_start,
'period_ids': tuple(period_ids),
'account_ids': tuple(account_ids),}
sql = ("SELECT ml.id, ml.account_id, ml.partner_id "
"FROM account_move_line ml "
"INNER JOIN account_account a "
"ON a.id = ml.account_id "
"WHERE ml.period_id in %(period_ids)s "
"AND ml.account_id in %(account_ids)s ")
if exclude_reconcile:
if not date_stop:
raise Exception("Missing \"date_stop\" to compute the open invoices.")
search_param.update({'date_stop': date_stop})
sql += ("AND ((ml.reconcile_id IS NULL)"
"OR (ml.reconcile_id IS NOT NULL AND ml.last_rec_date > date(%(date_stop)s))) ")
if partner_filter:
sql += "AND ml.partner_id in %(partner_ids)s "
search_param.update({'partner_ids': tuple(partner_filter)})
self.cursor.execute(sql, search_param)
return self.cursor.dictfetchall()
def _compute_partners_initial_balances(self, account_ids, start_period, partner_filter=None, exclude_reconcile=False, force_period_ids=False):
"""We compute initial balance.
If form is filtered by date all initial balance are equal to 0
This function will sum pear and apple in currency amount if account as no secondary currency"""
if isinstance(account_ids, (int, long)):
account_ids = [account_ids]
move_line_ids = self._partners_initial_balance_line_ids(account_ids, start_period, partner_filter,
exclude_reconcile=exclude_reconcile,
force_period_ids=force_period_ids)
if not move_line_ids:
move_line_ids = [{'id': -1}]
sql = ("SELECT ml.account_id, ml.partner_id,"
" sum(ml.debit) as debit, sum(ml.credit) as credit,"
" sum(ml.debit-ml.credit) as init_balance,"
" CASE WHEN a.currency_id ISNULL THEN 0.0 ELSE sum(ml.amount_currency) END as init_balance_currency, "
" c.name as currency_name "
"FROM account_move_line ml "
"INNER JOIN account_account a "
"ON a.id = ml.account_id "
"LEFT JOIN res_currency c "
"ON c.id = a.currency_id "
"WHERE ml.id in %(move_line_ids)s "
"GROUP BY ml.account_id, ml.partner_id, a.currency_id, c.name")
search_param = {'move_line_ids': tuple([move_line['id'] for move_line in move_line_ids])}
self.cursor.execute(sql, search_param)
res = self.cursor.dictfetchall()
return self._tree_move_line_ids(res)
####################Partner specific helper ################################
def _order_partners(self, *args):
"""We get the partner linked to all current accounts that are used.
We also use ensure that partner are ordered by name
args must be list"""
res = []
partner_ids = []
for arg in args:
if arg:
partner_ids += arg
if not partner_ids:
return []
existing_partner_ids = [partner_id for partner_id in partner_ids if partner_id]
if existing_partner_ids:
# We may use orm here as the performance optimization is not that big
sql = ("SELECT name|| ' ' ||CASE WHEN ref IS NOT NULL THEN '('||ref||')' ELSE '' END, id, ref, name"
" FROM res_partner WHERE id IN %s ORDER BY name, ref")
self.cursor.execute(sql, (tuple(set(existing_partner_ids)),))
res = self.cursor.fetchall()
# move lines without partners, set None for empty partner
if not all(partner_ids):
res.append((None, None, None, None))
if not res:
return []
return res

513
account_financial_report_webkit/report/common_reports.py

@ -0,0 +1,513 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
# SQL inspired from OpenERP original code
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# TODO refactor helper in order to act more like mixin
# By using properties we will have a more simple signature in fuctions
import logging
from openerp.addons.account.report.common_report_header import common_report_header
from osv import osv
from tools.translate import _
_logger = logging.getLogger('financial.reports.webkit')
class CommonReportHeaderWebkit(common_report_header):
"""Define common helper for financial report"""
####################From getter helper #####################################
def get_start_period_br(self, data):
return self._get_info(data,'period_from', 'account.period')
def get_end_period_br(self, data):
return self._get_info(data,'period_to', 'account.period')
def get_fiscalyear_br(self, data):
return self._get_info(data,'fiscalyear_id', 'account.fiscalyear')
def _get_chart_account_id_br(self, data):
return self._get_info(data, 'chart_account_id', 'account.account')
def _get_accounts_br(self, data):
return self._get_info(data, 'account_ids', 'account.account')
def _get_info(self, data, field, model):
info = data.get('form', {}).get(field)
if info:
return self.pool.get(model).browse(self.cursor, self.uid, info)
return False
def _get_display_account(self, data):
val = self._get_form_param('display_account', data)
if val == 'bal_all':
return _('All accounts')
elif val == 'bal_mix':
return _('With transactions or non zero balance')
else:
return val
def _get_display_partner_account(self, data):
val = self._get_form_param('result_selection', data)
if val == 'customer':
return _('Receivable Accounts')
elif val == 'supplier':
return _('Payable Accounts')
elif val == 'customer_supplier':
return _('Receivable and Payable Accounts')
else:
return val
def _get_display_target_move(self, data):
val = self._get_form_param('target_move', data)
if val == 'posted':
return _('All Posted Entries')
elif val == 'all':
return _('All Entries')
else:
return val
def _get_display_account_raw(self, data):
return self._get_form_param('display_account', data)
def _get_filter(self, data):
return self._get_form_param('filter', data)
def _get_target_move(self, data):
return self._get_form_param('target_move', data)
def _get_initial_balance(self, data):
return self._get_form_param('initial_balance', data)
def _get_amount_currency(self, data):
return self._get_form_param('amount_currency', data)
def _get_date_from(self, data):
return self._get_form_param('date_from', data)
def _get_date_to(self, data):
return self._get_form_param('date_to', data)
def _get_form_param(self, param, data, default=False):
return data.get('form', {}).get(param, default)
####################Account and account line filter helper #################
def sort_accounts_with_structure(self, root_account_ids, account_ids, context=None):
"""Sort accounts by code respecting their structure"""
def recursive_sort_by_code(accounts, parent):
sorted_accounts = []
# add all accounts with same parent
level_accounts = [account for account in accounts
if account['parent_id'] and account['parent_id'][0] == parent['id']]
# add consolidation children of parent, as they are logically on the same level
if parent.get('child_consol_ids'):
level_accounts.extend([account for account in accounts
if account['id'] in parent['child_consol_ids']])
# stop recursion if no children found
if not level_accounts:
return []
level_accounts = sorted(level_accounts, key=lambda a: a['code'])
for level_account in level_accounts:
sorted_accounts.append(level_account['id'])
sorted_accounts.extend(recursive_sort_by_code(accounts, parent=level_account))
return sorted_accounts
if not account_ids:
return []
accounts_data = self.pool.get('account.account').read(self.cr, self.uid,
account_ids,
['id', 'parent_id', 'level', 'code', 'child_consol_ids'],
context=context)
sorted_accounts = []
root_accounts_data = [account_data for account_data in accounts_data
if account_data['id'] in root_account_ids]
for root_account_data in root_accounts_data:
sorted_accounts.append(root_account_data['id'])
sorted_accounts.extend(recursive_sort_by_code(accounts_data, root_account_data))
# fallback to unsorted accounts when sort failed
# sort fails when the levels are miscalculated by account.account
# check lp:783670
if len(sorted_accounts) != len(account_ids):
_logger.warn('Webkit financial reports: Sort of accounts failed.')
sorted_accounts = account_ids
return sorted_accounts
def get_all_accounts(self, account_ids, exclude_type=None, only_type=None, filter_report_type=None, context=None):
"""Get all account passed in params with their childrens
@param exclude_type: list of types to exclude (view, receivable, payable, consolidation, other)
@param only_type: list of types to filter on (view, receivable, payable, consolidation, other)
@param filter_report_type: list of report type to filter on
"""
context = context or {}
accounts = []
if not isinstance(account_ids, list):
account_ids = [account_ids]
acc_obj = self.pool.get('account.account')
for account_id in account_ids:
accounts.append(account_id)
accounts += acc_obj._get_children_and_consol(self.cursor, self.uid, account_id, context=context)
res_ids = list(set(accounts))
res_ids = self.sort_accounts_with_structure(account_ids, res_ids, context=context)
if exclude_type or only_type or filter_report_type:
sql_filters = {'ids': tuple(res_ids)}
sql_select = "SELECT a.id FROM account_account a"
sql_join = ""
sql_where = "WHERE a.id IN %(ids)s"
if exclude_type:
sql_where += " AND a.type not in %(exclude_type)s"
sql_filters.update({'exclude_type': tuple(exclude_type)})
if only_type:
sql_where += " AND a.type IN %(only_type)s"
sql_filters.update({'only_type': tuple(only_type)})
if filter_report_type:
sql_join += "INNER JOIN account_account_type t" \
" ON t.id = a.user_type"
sql_join += " AND t.report_type IN %(report_type)s"
sql_filters.update({'report_type': tuple(filter_report_type)})
sql = ' '.join((sql_select, sql_join, sql_where))
self.cursor.execute(sql, sql_filters)
fetch_only_ids = self.cursor.fetchall()
if not fetch_only_ids:
return []
only_ids = [only_id[0] for only_id in fetch_only_ids]
# keep sorting but filter ids
res_ids = [res_id for res_id in res_ids if res_id in only_ids]
return res_ids
####################Periods and fiscal years helper #######################
def _get_opening_periods(self):
"""Return the list of all journal that can be use to create opening entries
We actually filter on this instead of opening period as older version of OpenERP
did not have this notion"""
return self.pool.get('account.period').search(self.cursor, self.uid, [('special', '=', True)])
def exclude_opening_periods(self, period_ids):
period_obj = self.pool.get('account.period')
return period_obj.search(self.cr, self.uid, [['special', '=', False], ['id', 'in', period_ids]])
def get_included_opening_period(self, period):
"""Return the opening included in normal period we use the assumption
that there is only one opening period per fiscal year"""
period_obj = self.pool.get('account.period')
return period_obj.search(self.cursor, self.uid,
[('special', '=', True),
('date_start', '>=', period.date_start),
('date_stop', '<=', period.date_stop)],
limit=1)
def periods_contains_move_lines(self, period_ids):
if not period_ids:
return False
mv_line_obj = self.pool.get('account.move.line')
if isinstance(period_ids, (int, long)):
period_ids = [period_ids]
return mv_line_obj.search(self.cursor, self.uid, [('period_id', 'in', period_ids)], limit=1) and True or False
def _get_period_range_from_periods(self, start_period, stop_period, mode=None):
"""
Deprecated. We have to use now the build_ctx_periods of period_obj otherwise we'll have
inconsistencies, because build_ctx_periods does never filter on the the special
"""
period_obj = self.pool.get('account.period')
search_period = [('date_start', '>=', start_period.date_start),
('date_stop', '<=', stop_period.date_stop)]
if mode == 'exclude_opening':
search_period += [('special', '=', False)]
res = period_obj.search(self.cursor, self.uid, search_period)
return res
def _get_period_range_from_start_period(self, start_period, include_opening=False,
fiscalyear=False, stop_at_previous_opening=False):
"""We retrieve all periods before start period"""
opening_period_id = False
past_limit = []
period_obj = self.pool.get('account.period')
mv_line_obj = self.pool.get('account.move.line')
# We look for previous opening period
if stop_at_previous_opening:
opening_search = [('special', '=', True),
('date_stop', '<', start_period.date_start)]
if fiscalyear:
opening_search.append(('fiscalyear_id', '=', fiscalyear.id))
opening_periods = period_obj.search(self.cursor, self.uid, opening_search,
order='date_stop desc')
for opening_period in opening_periods:
validation_res = mv_line_obj.search(self.cursor,
self.uid,
[('period_id', '=', opening_period)],
limit=1)
if validation_res:
opening_period_id = opening_period
break
if opening_period_id:
#we also look for overlapping periods
opening_period_br = period_obj.browse(self.cursor, self.uid, opening_period_id)
past_limit = [('date_start', '>=', opening_period_br.date_stop)]
periods_search = [('date_stop', '<=', start_period.date_stop)]
periods_search += past_limit
if not include_opening:
periods_search += [('special', '=', False)]
if fiscalyear :
periods_search.append(('fiscalyear_id', '=', fiscalyear.id))
periods = period_obj.search(self.cursor, self.uid, periods_search)
if include_opening and opening_period_id:
periods.append(opening_period_id)
periods = list(set(periods))
if start_period.id in periods:
periods.remove(start_period.id)
return periods
def get_first_fiscalyear_period(self, fiscalyear):
return self._get_st_fiscalyear_period(fiscalyear)
def get_last_fiscalyear_period(self, fiscalyear):
return self._get_st_fiscalyear_period(fiscalyear, order='DESC')
def _get_st_fiscalyear_period(self, fiscalyear, special=False, order='ASC'):
period_obj = self.pool.get('account.period')
p_id = period_obj.search(self.cursor,
self.uid,
[('special','=', special),
('fiscalyear_id', '=', fiscalyear.id)],
limit=1,
order='date_start %s' % (order,))
if not p_id:
raise osv.except_osv(_('No period found'),'')
return period_obj.browse(self.cursor, self.uid, p_id[0])
####################Initial Balance helper #################################
def _compute_init_balance(self, account_id=None, period_ids=None, mode='computed', default_values=False):
if not isinstance(period_ids, list):
period_ids = [period_ids]
res = {}
if not default_values:
if not account_id or not period_ids:
raise Exception('Missing account or period_ids')
try:
self.cursor.execute("SELECT sum(debit) AS debit, "
" sum(credit) AS credit, "
" sum(debit)-sum(credit) AS balance, "
" sum(amount_currency) AS curr_balance"
" FROM account_move_line"
" WHERE period_id in %s"
" AND account_id = %s", (tuple(period_ids), account_id))
res = self.cursor.dictfetchone()
except Exception, exc:
self.cursor.rollback()
raise
return {'debit': res.get('debit') or 0.0,
'credit': res.get('credit') or 0.0,
'init_balance': res.get('balance') or 0.0,
'init_balance_currency': res.get('curr_balance') or 0.0,
'state': mode}
def _read_opening_balance(self, account_ids, start_period):
""" Read opening balances from the opening balance
"""
opening_period_selected = self.get_included_opening_period(start_period)
res = {}
for account_id in account_ids:
res[account_id] = self._compute_init_balance(account_id, opening_period_selected, mode='read')
return res
def _compute_initial_balances(self, account_ids, start_period, fiscalyear):
"""We compute initial balance.
If form is filtered by date all initial balance are equal to 0
This function will sum pear and apple in currency amount if account as no secondary currency"""
# if opening period is included in start period we do not need to compute init balance
# we just read it from opening entries
res = {}
# PNL and Balance accounts are not computed the same way look for attached doc
# We include opening period in pnl account in order to see if opening entries
# were created by error on this account
pnl_periods_ids = self._get_period_range_from_start_period(start_period, fiscalyear=fiscalyear,
include_opening=True)
bs_period_ids = self._get_period_range_from_start_period(start_period, include_opening=True,
stop_at_previous_opening=True)
opening_period_selected = self.get_included_opening_period(start_period)
for acc in self.pool.get('account.account').browse(self.cursor, self.uid, account_ids):
res[acc.id] = self._compute_init_balance(default_values=True)
if acc.user_type.close_method == 'none':
# we compute the initial balance for close_method == none only when we print a GL
# during the year, when the opening period is not included in the period selection!
if pnl_periods_ids and not opening_period_selected:
res[acc.id] = self._compute_init_balance(acc.id, pnl_periods_ids)
else:
res[acc.id] = self._compute_init_balance(acc.id, bs_period_ids)
return res
####################Account move retrieval helper ##########################
def _get_move_ids_from_periods(self, account_id, period_start, period_stop, target_move):
move_line_obj = self.pool.get('account.move.line')
period_obj = self.pool.get('account.period')
periods = period_obj.build_ctx_periods(self.cursor, self.uid, period_start.id, period_stop.id)
if not periods:
return []
search = [('period_id', 'in', periods), ('account_id', '=', account_id)]
if target_move == 'posted':
search += [('move_id.state', '=', 'posted')]
return move_line_obj.search(self.cursor, self.uid, search)
def _get_move_ids_from_dates(self, account_id, date_start, date_stop, target_move, mode='include_opening'):
# TODO imporve perfomance by setting opening period as a property
move_line_obj = self.pool.get('account.move.line')
search_period = [('date', '>=', date_start),
('date', '<=', date_stop),
('account_id', '=', account_id)]
# actually not used because OpenERP itself always include the opening when we
# get the periods from january to december
if mode == 'exclude_opening':
opening = self._get_opening_periods()
if opening:
search_period += ['period_id', 'not in', opening]
if target_move == 'posted':
search_period += [('move_id.state', '=', 'posted')]
return move_line_obj.search(self.cursor, self.uid, search_period)
def get_move_lines_ids(self, account_id, main_filter, start, stop, target_move, mode='include_opening'):
"""Get account move lines base on form data"""
if mode not in ('include_opening', 'exclude_opening'):
raise osv.except_osv(_('Invalid query mode'), _('Must be in include_opening, exclude_opening'))
if main_filter in ('filter_period', 'filter_no'):
return self._get_move_ids_from_periods(account_id, start, stop, target_move)
elif main_filter == 'filter_date':
return self._get_move_ids_from_dates(account_id, start, stop, target_move)
else:
raise osv.except_osv(_('No valid filter'), _('Please set a valid time filter'))
def _get_move_line_datas(self, move_line_ids, order='per.special DESC, l.date ASC, per.date_start ASC, m.name ASC'):
if not move_line_ids:
return []
if not isinstance(move_line_ids, list):
move_line_ids = [move_line_ids]
monster ="""
SELECT l.id AS id,
l.date AS ldate,
j.code AS jcode ,
l.currency_id,
l.account_id,
l.amount_currency,
l.ref AS lref,
l.name AS lname,
COALESCE(l.debit, 0.0) - COALESCE(l.credit, 0.0) AS balance,
l.debit,
l.credit,
l.period_id AS lperiod_id,
per.code as period_code,
per.special AS peropen,
l.partner_id AS lpartner_id,
p.name AS partner_name,
m.name AS move_name,
COALESCE(partialrec.name, fullrec.name, '') AS rec_name,
m.id AS move_id,
c.name AS currency_code,
i.id AS invoice_id,
i.type AS invoice_type,
i.number AS invoice_number,
l.date_maturity
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 account_move_reconcile partialrec on (l.reconcile_partial_id = partialrec.id)
LEFT JOIN account_move_reconcile fullrec on (l.reconcile_id = fullrec.id)
LEFT JOIN res_partner p on (l.partner_id=p.id)
LEFT JOIN account_invoice i on (m.id =i.move_id)
LEFT JOIN account_period per on (per.id=l.period_id)
JOIN account_journal j on (l.journal_id=j.id)
WHERE l.id in %s"""
monster += (" ORDER BY %s" % (order,))
try:
self.cursor.execute(monster, (tuple(move_line_ids),))
res= self.cursor.dictfetchall()
except Exception, exc:
self.cursor.rollback()
raise
return res or []
def _get_moves_counterparts(self, move_ids, account_id, limit=3):
if not move_ids:
return {}
if not isinstance(move_ids, list):
move_ids = [move_ids]
sql = """
SELECT account_move.id,
array_to_string(
ARRAY(SELECT DISTINCT a.code
FROM account_move_line m2
LEFT JOIN account_account a ON (m2.account_id=a.id)
WHERE m2.move_id =account_move_line.move_id
AND m2.account_id<>%s limit %s) , ', ')
FROM account_move
JOIN account_move_line on (account_move_line.move_id = account_move.id)
JOIN account_account on (account_move_line.account_id = account_account.id)
WHERE move_id in %s"""
try:
self.cursor.execute(sql, (account_id, limit, tuple(move_ids)))
res= self.cursor.fetchall()
except Exception, exc:
self.cursor.rollback()
raise
return res and dict(res) or {}
def is_initial_balance_enabled(self, main_filter):
if main_filter not in ('filter_no', 'filter_year', 'filter_period'):
return False
return True
def _get_initial_balance_mode(self, start_period):
opening_period_selected = self.get_included_opening_period(start_period)
opening_move_lines = self.periods_contains_move_lines(opening_period_selected)
if opening_move_lines:
return 'opening_balance'
else:
return 'initial_balance'

211
account_financial_report_webkit/report/general_ledger.py

@ -0,0 +1,211 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from report import report_sxw
from tools.translate import _
import pooler
from operator import itemgetter
from itertools import groupby
from datetime import datetime
from common_reports import CommonReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
class GeneralLedgerWebkit(report_sxw.rml_parse, CommonReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(GeneralLedgerWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('GENERAL LEDGER'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name': _('General Ledger'),
'display_account': self._get_display_account,
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'initial_balance': self._get_initial_balance,
'amount_currency': self._get_amount_currency,
'display_target_move': self._get_display_target_move,
'accounts': self._get_accounts_br,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
new_ids = data['form']['account_ids'] or data['form']['chart_account_id']
# Account initial balance memoizer
init_balance_memoizer = {}
# Reading form
main_filter = self._get_form_param('filter', data, default='filter_no')
target_move = self._get_form_param('target_move', data, default='all')
start_date = self._get_form_param('date_from', data)
stop_date = self._get_form_param('date_to', data)
do_centralize = self._get_form_param('centralize', data)
start_period = self.get_start_period_br(data)
stop_period = self.get_end_period_br(data)
fiscalyear = self.get_fiscalyear_br(data)
chart_account = self._get_chart_account_id_br(data)
if main_filter == 'filter_no':
start_period = self.get_first_fiscalyear_period(fiscalyear)
stop_period = self.get_last_fiscalyear_period(fiscalyear)
# computation of ledger lines
if main_filter == 'filter_date':
start = start_date
stop = stop_date
else:
start = start_period
stop = stop_period
initial_balance = self.is_initial_balance_enabled(main_filter)
initial_balance_mode = initial_balance and self._get_initial_balance_mode(start) or False
# Retrieving accounts
accounts = self.get_all_accounts(new_ids, exclude_type=['view'])
if initial_balance_mode == 'initial_balance':
init_balance_memoizer = self._compute_initial_balances(accounts, start, fiscalyear)
ledger_lines_memoizer = self._compute_account_ledger_lines(accounts, init_balance_memoizer,
main_filter, target_move, start, stop)
objects = []
for account in self.pool.get('account.account').browse(self.cursor, self.uid, accounts):
if do_centralize and account.centralized and ledger_lines_memoizer.get(account.id):
account.ledger_lines = self._centralize_lines(main_filter, ledger_lines_memoizer.get(account.id, []))
else:
account.ledger_lines = ledger_lines_memoizer.get(account.id, [])
account.init_balance = init_balance_memoizer.get(account.id, {})
objects.append(account)
self.localcontext.update({
'fiscalyear': fiscalyear,
'start_date': start_date,
'stop_date': stop_date,
'start_period': start_period,
'stop_period': stop_period,
'chart_account': chart_account,
'initial_balance_mode': initial_balance_mode,
})
return super(GeneralLedgerWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
def _centralize_lines(self, filter, ledger_lines, context=None):
""" Group by period in filter mode 'period' or on one line in filter mode 'date'
ledger_lines parameter is a list of dict built by _get_ledger_lines"""
def group_lines(lines):
if not lines:
return {}
sums = reduce(lambda line, memo: dict((key, value + memo[key]) for key, value
in line.iteritems() if key in ('balance', 'debit', 'credit')), lines)
res_lines = {
'balance': sums['balance'],
'debit': sums['debit'],
'credit': sums['credit'],
'lname': _('Centralized Entries'),
'account_id': lines[0]['account_id'],
}
return res_lines
centralized_lines = []
if filter == 'filter_date':
# by date we centralize all entries in only one line
centralized_lines.append(group_lines(ledger_lines))
else: # by period
# by period we centralize all entries in one line per period
period_obj = self.pool.get('account.period')
# we need to sort the lines per period in order to use groupby
# unique ids of each used period id in lines
period_ids = list(set([line['lperiod_id'] for line in ledger_lines ]))
# search on account.period in order to sort them by date_start
sorted_period_ids = period_obj.search(self.cr, self.uid,
[('id', 'in', period_ids)],
order='special desc, date_start',
context=context)
sorted_ledger_lines = sorted(ledger_lines, key=lambda x: sorted_period_ids.index(x['lperiod_id']))
for period_id, lines_per_period_iterator in groupby(sorted_ledger_lines, itemgetter('lperiod_id')):
lines_per_period = list(lines_per_period_iterator)
if not lines_per_period:
continue
group_per_period = group_lines(lines_per_period)
group_per_period.update({
'lperiod_id': period_id,
'period_code': lines_per_period[0]['period_code'], # period code is anyway the same on each line per period
})
centralized_lines.append(group_per_period)
return centralized_lines
def _compute_account_ledger_lines(self, accounts_ids, init_balance_memoizer, main_filter,
target_move, start, stop):
res = {}
for acc_id in accounts_ids:
move_line_ids = self.get_move_lines_ids(acc_id, main_filter, start, stop, target_move)
if not move_line_ids:
res[acc_id] = []
continue
lines = self._get_ledger_lines(move_line_ids, acc_id)
res[acc_id] = lines
return res
def _get_ledger_lines(self, move_line_ids, account_id):
if not move_line_ids:
return []
res = self._get_move_line_datas(move_line_ids)
## computing counter part is really heavy in term of ressouces consuption
## looking for a king of SQL to help me improve it
move_ids = [x.get('move_id') for x in res]
counter_parts = self._get_moves_counterparts(move_ids, account_id)
for line in res:
line['counterparts'] = counter_parts.get(line.get('move_id'), '')
return res
HeaderFooterTextWebKitParser('report.account.account_report_general_ledger_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_general_ledger.mako',
parser=GeneralLedgerWebkit)

212
account_financial_report_webkit/report/open_invoices.py

@ -0,0 +1,212 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import pooler
from collections import defaultdict
from report import report_sxw
from osv import osv
from tools.translate import _
from datetime import datetime
from common_partner_reports import CommonPartnersReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
class PartnersOpenInvoicesWebkit(report_sxw.rml_parse, CommonPartnersReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(PartnersOpenInvoicesWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('OPEN INVOICES REPORT'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name':_('Open Invoices Report'),
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'amount_currency': self._get_amount_currency,
'display_partner_account': self._get_display_partner_account,
'display_target_move': self._get_display_target_move,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
new_ids = data['form']['chart_account_id']
# Account initial balance memoizer
init_balance_memoizer = {}
# Reading form
main_filter = self._get_form_param('filter', data, default='filter_no')
target_move = self._get_form_param('target_move', data, default='all')
start_date = self._get_form_param('date_from', data)
stop_date = self._get_form_param('date_to', data)
start_period = self.get_start_period_br(data)
stop_period = self.get_end_period_br(data)
fiscalyear = self.get_fiscalyear_br(data)
partner_ids = self._get_form_param('partner_ids', data)
result_selection = self._get_form_param('result_selection', data)
date_until = self._get_form_param('until_date', data)
chart_account = self._get_chart_account_id_br(data)
if main_filter == 'filter_no' and fiscalyear:
start_period = self.get_first_fiscalyear_period(fiscalyear)
stop_period = self.get_last_fiscalyear_period(fiscalyear)
# Retrieving accounts
filter_type = ('payable', 'receivable')
if result_selection == 'customer':
filter_type = ('receivable',)
if result_selection == 'supplier':
filter_type = ('payable',)
account_ids = self.get_all_accounts(new_ids, exclude_type=['view'], only_type=filter_type)
if not account_ids:
raise osv.except_osv(_('Error'), _('No accounts to print.'))
# computation of ledeger lines
if main_filter == 'filter_date':
start = start_date
stop = stop_date
else:
start = start_period
stop = stop_period
ledger_lines_memoizer = self._compute_open_transactions_lines(account_ids,
main_filter,
target_move,
start,
stop,
date_until,
partner_filter=partner_ids)
objects = []
for account in self.pool.get('account.account').browse(self.cursor, self.uid, account_ids):
account.ledger_lines = ledger_lines_memoizer.get(account.id, {})
account.init_balance = init_balance_memoizer.get(account.id, {})
## we have to compute partner order based on inital balance
## and ledger line as we may have partner with init bal
## that are not in ledger line and vice versa
ledg_lines_pids = ledger_lines_memoizer.get(account.id, {}).keys()
non_null_init_balances = dict([(ib, amounts) for ib, amounts in account.init_balance.iteritems()
if amounts['init_balance'] or amounts['init_balance_currency']])
init_bal_lines_pids = non_null_init_balances.keys()
account.partners_order = self._order_partners(ledg_lines_pids, init_bal_lines_pids)
account.ledger_lines = ledger_lines_memoizer.get(account.id, {})
objects.append(account)
self.localcontext.update({
'fiscalyear': fiscalyear,
'start_date': start_date,
'stop_date': stop_date,
'start_period': start_period,
'stop_period': stop_period,
'date_until': date_until,
'partner_ids': partner_ids,
'chart_account': chart_account,
})
return super(PartnersOpenInvoicesWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
def _compute_open_transactions_lines(self, accounts_ids, main_filter, target_move, start, stop, date_until=False, partner_filter=False):
res = defaultdict(dict)
## we check if until date and date stop have the same value
if main_filter in ('filter_period', 'filter_no'):
date_stop = stop.date_stop
date_until_match = (date_stop == date_until)
elif main_filter == 'filter_date':
date_stop = stop
date_until_match = (stop == date_until)
else:
raise osv.except_osv(_('Unsuported filter'),
_('Filter has to be in filter date, period, or none'))
initial_move_lines_per_account = {}
if main_filter in ('filter_period', 'filter_no'):
initial_move_lines_per_account = self._tree_move_line_ids(
self._partners_initial_balance_line_ids(accounts_ids,
start,
partner_filter,
exclude_reconcile=True,
force_period_ids=False,
date_stop=date_stop), key='id')
for account_id in accounts_ids:
initial_move_lines_ids_per_partner = initial_move_lines_per_account.get(account_id, {})
# We get the move line ids of the account depending of the
# way the initial balance was created we include or not opening entries
move_line_ids_per_partner = self.get_partners_move_lines_ids(account_id,
main_filter,
start,
stop,
target_move,
exclude_reconcile=True,
partner_filter=partner_filter)
if not initial_move_lines_ids_per_partner and not move_line_ids_per_partner:
continue
for partner_id in list(set(initial_move_lines_ids_per_partner.keys() + move_line_ids_per_partner.keys())):
partner_line_ids = (move_line_ids_per_partner.get(partner_id, []) +
initial_move_lines_ids_per_partner.get(partner_id, []))
clearance_line_ids = []
if date_until and not date_until_match and partner_line_ids:
clearance_line_ids = self._get_clearance_move_line_ids(partner_line_ids, date_stop, date_until)
partner_line_ids += clearance_line_ids
lines = self._get_move_line_datas(list(set(partner_line_ids)))
for line in lines:
if line['id'] in initial_move_lines_ids_per_partner.get(partner_id, []):
line['is_from_previous_periods'] = True
if line['id'] in clearance_line_ids:
line['is_clearance_line'] = True
res[account_id][partner_id] = lines
return res
HeaderFooterTextWebKitParser('report.account.account_report_open_invoices_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_open_invoices.mako',
parser=PartnersOpenInvoicesWebkit)

80
account_financial_report_webkit/report/partner_balance.py

@ -0,0 +1,80 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from report import report_sxw
from tools.translate import _
import pooler
from datetime import datetime
from common_partner_balance_reports import CommonPartnerBalanceReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
class PartnerBalanceWebkit(report_sxw.rml_parse, CommonPartnerBalanceReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(PartnerBalanceWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('PARTNER BALANCE'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name': _('Partner Balance'),
'display_account': self._get_display_account,
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'display_target_move': self._get_display_target_move,
'display_partner_account': self._get_display_partner_account,
'accounts': self._get_accounts_br,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
objects, new_ids, context_report_values = self.compute_partner_balance_data(data)
self.localcontext.update(context_report_values)
return super(PartnerBalanceWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
HeaderFooterTextWebKitParser('report.account.account_report_partner_balance_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_partner_balance.mako',
parser=PartnerBalanceWebkit)

190
account_financial_report_webkit/report/partners_ledger.py

@ -0,0 +1,190 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import pooler
from collections import defaultdict
from report import report_sxw
from osv import osv
from tools.translate import _
from datetime import datetime
from common_partner_reports import CommonPartnersReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
class PartnersLedgerWebkit(report_sxw.rml_parse, CommonPartnersReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(PartnersLedgerWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('PARTNER LEDGER'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name':_('Partner Ledger'),
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'initial_balance': self._get_initial_balance,
'amount_currency': self._get_amount_currency,
'display_partner_account': self._get_display_partner_account,
'display_target_move': self._get_display_target_move,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
new_ids = data['form']['chart_account_id']
# account partner memoizer
# Reading form
main_filter = self._get_form_param('filter', data, default='filter_no')
target_move = self._get_form_param('target_move', data, default='all')
start_date = self._get_form_param('date_from', data)
stop_date = self._get_form_param('date_to', data)
start_period = self.get_start_period_br(data)
stop_period = self.get_end_period_br(data)
fiscalyear = self.get_fiscalyear_br(data)
partner_ids = self._get_form_param('partner_ids', data)
result_selection = self._get_form_param('result_selection', data)
chart_account = self._get_chart_account_id_br(data)
if main_filter == 'filter_no' and fiscalyear:
start_period = self.get_first_fiscalyear_period(fiscalyear)
stop_period = self.get_last_fiscalyear_period(fiscalyear)
# Retrieving accounts
filter_type = ('payable', 'receivable')
if result_selection == 'customer':
filter_type = ('receivable',)
if result_selection == 'supplier':
filter_type = ('payable',)
accounts = self.get_all_accounts(new_ids, exclude_type=['view'],
only_type=filter_type)
if not accounts:
raise osv.except_osv(_('Error'), _('No accounts to print.'))
if main_filter == 'filter_date':
start = start_date
stop = stop_date
else:
start = start_period
stop = stop_period
# when the opening period is included in the selected range of periods and
# the opening period contains move lines, we must not compute the initial balance from previous periods
# but only display the move lines of the opening period
# we identify them as :
# - 'initial_balance' means compute the sums of move lines from previous periods
# - 'opening_balance' means display the move lines of the opening period
init_balance = main_filter in ('filter_no', 'filter_period')
initial_balance_mode = init_balance and self._get_initial_balance_mode(start) or False
init_balance_memoizer = {}
if initial_balance_mode == 'initial_balance':
init_balance_memoizer = self._compute_partners_initial_balances(accounts,
start_period,
partner_filter=partner_ids,
exclude_reconcile=False)
ledger_lines_memoizer = self._compute_partner_ledger_lines(accounts,
main_filter,
target_move,
start,
stop,
partner_filter=partner_ids)
objects = []
for account in self.pool.get('account.account').browse(self.cursor, self.uid, accounts):
account.ledger_lines = ledger_lines_memoizer.get(account.id, {})
account.init_balance = init_balance_memoizer.get(account.id, {})
## we have to compute partner order based on inital balance
## and ledger line as we may have partner with init bal
## that are not in ledger line and vice versa
ledg_lines_pids = ledger_lines_memoizer.get(account.id, {}).keys()
if initial_balance_mode:
non_null_init_balances = dict([(ib, amounts) for ib, amounts in account.init_balance.iteritems()
if amounts['init_balance'] or amounts['init_balance_currency']])
init_bal_lines_pids = non_null_init_balances.keys()
else:
account.init_balance = {}
init_bal_lines_pids = []
account.partners_order = self._order_partners(ledg_lines_pids, init_bal_lines_pids)
account.ledger_lines = ledger_lines_memoizer.get(account.id, {})
objects.append(account)
self.localcontext.update({
'fiscalyear': fiscalyear,
'start_date': start_date,
'stop_date': stop_date,
'start_period': start_period,
'stop_period': stop_period,
'partner_ids': partner_ids,
'chart_account': chart_account,
'initial_balance_mode': initial_balance_mode,
})
return super(PartnersLedgerWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
def _compute_partner_ledger_lines(self, accounts_ids, main_filter, target_move, start, stop, partner_filter=False):
res = defaultdict(dict)
for acc_id in accounts_ids:
move_line_ids = self.get_partners_move_lines_ids(acc_id,
main_filter,
start,
stop,
target_move,
exclude_reconcile=False,
partner_filter=partner_filter)
if not move_line_ids:
continue
for partner_id in move_line_ids:
partner_line_ids = move_line_ids.get(partner_id, [])
lines = self._get_move_line_datas(list(set(partner_line_ids)))
res[acc_id][partner_id] = lines
return res
HeaderFooterTextWebKitParser('report.account.account_report_partners_ledger_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_partners_ledger.mako',
parser=PartnersLedgerWebkit)

115
account_financial_report_webkit/report/profit_loss.py

@ -0,0 +1,115 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import pooler
from report import report_sxw
from tools.translate import _
from datetime import datetime
from common_balance_reports import CommonBalanceReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
class ProfitLossWebkit(report_sxw.rml_parse, CommonBalanceReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(ProfitLossWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('PROFIT AND LOSS'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name': _('Profit and Loss'),
'display_account': self._get_display_account,
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'display_target_move': self._get_display_target_move,
'accounts': self._get_accounts_br,
'numbers_display': self._get_numbers_display,
'level_print': self._get_level_print,
'level_bold': self._get_level_bold,
'level_italic': self._get_level_italic,
'level_size': self._get_level_size,
'level_underline': self._get_level_underline,
'level_uppercase': self._get_level_uppercase,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def _get_level_print(self, data, level):
return self._get_form_param("level%s_print" % (level,), data)
def _get_level_bold(self, data, level):
return self._get_form_param("level%s_bold" % (level,), data)
def _get_level_italic(self, data, level):
return self._get_form_param("level%s_italic" % (level,), data)
def _get_level_size(self, data, level):
return self._get_form_param("level%s_size" % (level,), data)
def _get_level_underline(self, data, level):
return self._get_form_param("level%s_underline" % (level,), data)
def _get_level_uppercase(self, data, level):
return self._get_form_param("level%s_uppercase" % (level,), data)
def _update_levels(self, objects):
# start leveling from 0
levels = [account['current']['level'] for account in objects]
min_level = min(levels)
for account in objects:
account['current']['level'] -= min_level
return objects
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
objects, new_ids, context_report_values = self.compute_balance_data(data, filter_report_type=['expense', 'income'])
objects = self._update_levels(objects)
self.localcontext.update(context_report_values)
return super(ProfitLossWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
HeaderFooterTextWebKitParser('report.account.account_report_profit_loss_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_profit_loss.mako',
parser=ProfitLossWebkit)

104
account_financial_report_webkit/report/report.xml

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- we do not use report tag has we can not set header ref -->
<record id="account_report_general_ledger_webkit" model="ir.actions.report.xml">
<field name="report_type">webkit</field>
<field name="report_name">account.account_report_general_ledger_webkit</field>
<field eval="[(6,0,[])]" name="groups_id"/>
<field eval="0" name="multi"/>
<field eval="0" name="auto"/>
<field eval="1" name="header"/>
<field name="model">account.account</field>
<field name="type">ir.actions.report.xml</field>
<field name="name">General Ledger Webkit</field>
<field name="report_rml">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field>
<field name="report_file">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field>
<field name="webkit_header" ref="financial_landscape_header"/>
</record>
<!-- waiting the fix
<report auto="False"
id="account_report_partner_ledger_webkit"
model="account.account"
name="account.account_report_partner_ledger_webkit"
file="account_financial_report_webkit/report/templates/account_report_partner_ledger.mako"
string="General Ledger Webkit"
report_type="webkit"/> -->
<!-- we do not use report tag has we can not set header ref -->
<record id="account_report_partners_ledger_webkit" model="ir.actions.report.xml">
<field name="report_type">webkit</field>
<field name="report_name">account.account_report_partners_ledger_webkit</field>
<field eval="[(6,0,[])]" name="groups_id"/>
<field eval="0" name="multi"/>
<field eval="0" name="auto"/>
<field eval="1" name="header"/>
<field name="model">account.account</field>
<field name="type">ir.actions.report.xml</field>
<field name="name">Partner Ledger Webkit</field>
<field name="report_rml">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field>
<field name="report_file">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field>
<field name="webkit_header" ref="financial_landscape_header"/>
</record>
<record id="account_report_trial_balance_webkit" model="ir.actions.report.xml">
<field name="report_type">webkit</field>
<field name="report_name">account.account_report_trial_balance_webkit</field>
<field eval="[(6,0,[])]" name="groups_id"/>
<field eval="0" name="multi"/>
<field eval="0" name="auto"/>
<field eval="1" name="header"/>
<field name="model">account.account</field>
<field name="type">ir.actions.report.xml</field>
<field name="name">Trial Balance Webkit</field>
<field name="report_rml">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field>
<field name="report_file">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field>
<field name="webkit_header" ref="financial_portrait_header"/>
</record>
<record id="account_report_partner_balance_webkit" model="ir.actions.report.xml">
<field name="report_type">webkit</field>
<field name="report_name">account.account_report_partner_balance_webkit</field>
<field eval="[(6,0,[])]" name="groups_id"/>
<field eval="0" name="multi"/>
<field eval="0" name="auto"/>
<field eval="1" name="header"/>
<field name="model">account.account</field>
<field name="type">ir.actions.report.xml</field>
<field name="name">Partner Balance Webkit</field>
<field name="report_rml">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field>
<field name="report_file">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field>
<field name="webkit_header" ref="financial_portrait_header"/>
</record>
<record id="account_report_open_invoices_webkit" model="ir.actions.report.xml">
<field name="report_type">webkit</field>
<field name="report_name">account.account_report_open_invoices_webkit</field>
<field eval="[(6,0,[])]" name="groups_id"/>
<field eval="0" name="multi"/>
<field eval="0" name="auto"/>
<field eval="1" name="header"/>
<field name="model">account.account</field>
<field name="type">ir.actions.report.xml</field>
<field name="name">Open Invoices Report</field>
<field name="report_rml">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field>
<field name="report_file">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field>
<field name="webkit_header" ref="financial_landscape_header"/>
</record>
<!--<record id="account_report_profit_loss_webkit" model="ir.actions.report.xml">-->
<!--<field name="report_type">webkit</field>-->
<!--<field name="report_name">account.account_report_profit_loss_webkit</field>-->
<!--<field eval="[(6,0,[])]" name="groups_id"/>-->
<!--<field eval="0" name="multi"/>-->
<!--<field eval="0" name="auto"/>-->
<!--<field eval="1" name="header"/>-->
<!--<field name="model">account.account</field>-->
<!--<field name="type">ir.actions.report.xml</field>-->
<!--<field name="name">Profit and Loss Webkit</field>-->
<!--<field name="report_rml">account_financial_report_webkit/report/templates/account_report_profit_loss.mako</field>-->
<!--<field name="report_file">account_financial_report_webkit/report/templates/account_report_profit_loss.mako</field>-->
<!--<field name="webkit_header" ref="financial_portrait_header"/>-->
<!--</record>-->
</data>
</openerp>

226
account_financial_report_webkit/report/templates/account_report_general_ledger.mako

@ -0,0 +1,226 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
.overflow_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
${css}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
<%
initial_balance_text = {'initial_balance': _('Computed'), 'opening_balance': _('Opening Entries'), False: _('No')}
%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates Filter')}
%else:
${_('Periods Filter')}
%endif
</div>
<div class="act_as_cell">${_('Accounts Filter')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
<div class="act_as_cell">${_('Initial Balance')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">
%if accounts(data):
${', '.join([account.code for account in accounts(data)])}
%else:
${_('All')}
%endif
</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
<div class="act_as_cell">${ initial_balance_text[initial_balance_mode] }</div>
</div>
</div>
<!-- we use div with css instead of table for tabular data because div do not cut rows at half at page breaks -->
%for account in objects:
<%
display_initial_balance = account.init_balance and (account.init_balance.get('debit', 0.0) != 0.0 or account.init_balance.get('credit', 0.0) != 0.0)
display_ledger_lines = account.ledger_lines
%>
%if display_account_raw(data) == 'all' or (display_ledger_lines or display_initial_balance):
<%
cumul_debit = 0.0
cumul_credit = 0.0
cumul_balance = 0.0
cumul_balance_curr = 0.0
%>
<div class="act_as_table list_table" style="margin-top: 10px;">
<div class="act_as_caption account_title">
${account.code} - ${account.name}
</div>
<div class="act_as_thead">
<div class="act_as_row labels">
## date
<div class="act_as_cell first_column" style="width: 50px;">${_('Date')}</div>
## period
<div class="act_as_cell" style="width: 50px;">${_('Period')}</div>
## move
<div class="act_as_cell" style="width: 60px;">${_('Entry')}</div>
## journal
<div class="act_as_cell" style="width: 70px;">${_('Journal')}</div>
## partner
<div class="act_as_cell" style="width: 120px;">${_('Partner')}</div>
## label
<div class="act_as_cell" style="width: 265px;">${_('Label')}</div>
## counterpart
<div class="act_as_cell" style="width: 100px;">${_('Counter part')}</div>
## debit
<div class="act_as_cell amount" style="width: 75px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 75px;">${_('Credit')}</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 75px;">${_('Cumul. Bal.')}</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell amount sep_left" style="width: 75px;">${_('Curr. Balance')}</div>
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right;">${_('Curr.')}</div>
%endif
</div>
</div>
<div class="act_as_tbody">
%if display_initial_balance:
<%
cumul_debit = account.init_balance.get('debit') or 0.0
cumul_credit = account.init_balance.get('credit') or 0.0
cumul_balance = account.init_balance.get('init_balance') or 0.0
cumul_balance_curr = account.init_balance.get('init_balance_currency') or 0.0
%>
<div class="act_as_row initial_balance">
## date
<div class="act_as_cell first_column"></div>
## period
<div class="act_as_cell"></div>
## move
<div class="act_as_cell"></div>
## journal
<div class="act_as_cell"></div>
## partner
<div class="act_as_cell"></div>
## label
<div class="act_as_cell">${_('Initial Balance')}</div>
## counterpart
<div class="act_as_cell"></div>
## debit
<div class="act_as_cell amount">${formatLang(account.init_balance.get('debit')) | amount}</div>
## credit
<div class="act_as_cell amount">${formatLang(account.init_balance.get('credit')) | amount}</div>
## balance cumulated
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell amount sep_left">${formatLang(cumul_balance_curr) | amount }</div>
## curency code
<div class="act_as_cell amount"></div>
%endif
</div>
%endif
%for line in account.ledger_lines:
<%
cumul_debit += line.get('debit') or 0.0
cumul_credit += line.get('credit') or 0.0
cumul_balance_curr += line.get('amount_currency') or 0.0
cumul_balance += line.get('balance') or 0.0
label_elements = [line.get('lname') or '']
if line.get('invoice_number'):
label_elements.append("(%s)" % (line['invoice_number'],))
label = ' '.join(label_elements)
%>
<div class="act_as_row lines">
## date
<div class="act_as_cell first_column">${formatLang(line.get('ldate') or '', date=True)}</div>
## period
<div class="act_as_cell">${line.get('period_code') or ''}</div>
## move
<div class="act_as_cell">${line.get('move_name') or ''}</div>
## journal
<div class="act_as_cell">${line.get('jcode') or ''}</div>
## partner
<div class="act_as_cell overflow_ellipsis">${line.get('partner_name') or ''}</div>
## label
<div class="act_as_cell">${label}</div>
## counterpart
<div class="act_as_cell">${line.get('counterparts') or ''}</div>
## debit
<div class="act_as_cell amount">${ formatLang(line.get('debit', 0.0)) | amount }</div>
## credit
<div class="act_as_cell amount">${ formatLang(line.get('credit', 0.0)) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="padding-right: 1px;">${ formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell amount sep_left">${formatLang(line.get('amount_currency') or 0.0) | amount }</div>
## curency code
<div class="act_as_cell amount" style="text-align: right;">${line.get('currency_code') or ''}</div>
%endif
</div>
%endfor
</div>
<div class="act_as_table list_table">
<div class="act_as_row labels" style="font-weight: bold;">
## date
<div class="act_as_cell first_column" style="width: 350px;">${account.code} - ${account.name}</div>
<div class="act_as_cell" style="width: 365px;">${_("Cumulated Balance on Account")}</div>
## debit
<div class="act_as_cell amount" style="width: 75px;">${ formatLang(cumul_debit) | amount }</div>
## credit
<div class="act_as_cell amount" style="width: 75px;">${ formatLang(cumul_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 75px; padding-right: 1px;">${ formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
%if account.currency_id:
## currency balance
<div class="act_as_cell amount sep_left" style="width: 75px;">${formatLang(cumul_balance_curr) | amount }</div>
%else:
<div class="act_as_cell amount sep_left" style="width: 75px;">-</div>
%endif
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right;"></div>
%endif
</div>
</div>
</div>
%endif
%endfor
</body>
</html>

251
account_financial_report_webkit/report/templates/account_report_open_invoices.mako

@ -0,0 +1,251 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
.overflow_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.open_invoice_previous_line {
font-style: italic;
}
.clearance_line {
font-style: italic;
}
${css}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates Filter')}
%else:
${_('Periods Filter')}
%endif
</div>
<div class="act_as_cell">${_('Clearance Date')}</div>
<div class="act_as_cell">${_('Accounts Filter')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">${ formatLang(date_until, date=True) }</div>
<div class="act_as_cell">
%if partner_ids:
${_('Custom Filter')}
%else:
${ display_partner_account(data) }
%endif
</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
</div>
</div>
%for account in objects:
%if account.ledger_lines:
<%
if not account.partners_order:
continue
account_total_debit = 0.0
account_total_credit = 0.0
account_balance_cumul = 0.0
account_balance_cumul_curr = 0.0
%>
<div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${account.code} - ${account.name}</div>
%for partner_name, p_id, p_ref, p_name in account.partners_order:
<%
total_debit = 0.0
total_credit = 0.0
cumul_balance = 0.0
cumul_balance_curr = 0.0
part_cumul_balance = 0.0
part_cumul_balance_curr = 0.0
%>
<div class="act_as_table list_table" style="margin-top: 5px;">
<div class="act_as_caption account_title">
${partner_name or _('No Partner')}
</div>
<div class="act_as_thead">
<div class="act_as_row labels">
## date
<div class="act_as_cell first_column" style="width: 60px;">${_('Date')}</div>
## period
<div class="act_as_cell" style="width: 70px;">${_('Period')}</div>
## move
<div class="act_as_cell" style="width: 70px;">${_('Entry')}</div>
## journal
<div class="act_as_cell" style="width: 70px;">${_('Journal')}</div>
## partner
<div class="act_as_cell" style="width: 60px;">${_('Partner')}</div>
## label
<div class="act_as_cell" style="width: 255px;">${_('Label')}</div>
## reconcile
<div class="act_as_cell" style="width: 80px;">${_('Rec.')}</div>
## maturity
<div class="act_as_cell" style="width: 60px;">${_('Due Date')}</div>
## debit
<div class="act_as_cell amount" style="width: 80px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 80px;">${_('Credit')}</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 80px;">${_('Cumul. Bal.')}</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell amount sep_left" style="width: 80px;">${_('Curr. Balance')}</div>
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right;">${_('Curr.')}</div>
%endif
</div>
</div>
<div class="act_as_tbody">
<%
total_debit = 0.0
total_credit = 0.0
%>
%for line in account.ledger_lines.get(p_id, []):
<%
total_debit += line.get('debit') or 0.0
total_credit += line.get('credit') or 0.0
label_elements = [line.get('lname') or '']
if line.get('invoice_number'):
label_elements.append("(%s)" % (line['invoice_number'],))
label = ' '.join(label_elements)
%>
<div class="act_as_row lines ${line.get('is_from_previous_periods') and 'open_invoice_previous_line' or ''} ${line.get('is_clearance_line') and 'clearance_line' or ''}">
## date
<div class="act_as_cell first_column">${formatLang(line.get('ldate') or '', date=True)}</div>
## period
<div class="act_as_cell">${line.get('period_code') or ''}</div>
## move
<div class="act_as_cell">${line.get('move_name') or ''}</div>
## journal
<div class="act_as_cell">${line.get('jcode') or ''}</div>
## partner
<div class="act_as_cell overflow_ellipsis">${line.get('partner_name') or ''}</div>
## label
<div class="act_as_cell">${label}</div>
## reconcile
<div class="act_as_cell">${line.get('rec_name') or ''}</div>
## maturity date
<div class="act_as_cell">${formatLang(line.get('date_maturity') or '', date=True)}</div>
## debit
<div class="act_as_cell amount">${formatLang(line.get('debit') or 0.0) | amount }</div>
## credit
<div class="act_as_cell amount">${formatLang(line.get('credit') or 0.0) | amount }</div>
## balance cumulated
<% cumul_balance += line.get('balance') or 0.0 %>
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell sep_left amount">${formatLang(line.get('amount_currency') or 0.0) | amount }</div>
## curency code
<div class="act_as_cell" style="text-align: right; ">${line.get('currency_code') or ''}</div>
%endif
</div>
%endfor
<div class="act_as_row lines labels">
## date
<div class="act_as_cell first_column"></div>
## period
<div class="act_as_cell"></div>
## move
<div class="act_as_cell"></div>
## journal
<div class="act_as_cell"></div>
## partner
<div class="act_as_cell"></div>
## label
<div class="act_as_cell">${_('Cumulated Balance on Partner')}</div>
## reconcile
<div class="act_as_cell"></div>
## maturity date
<div class="act_as_cell"></div>
## debit
<div class="act_as_cell amount">${formatLang(total_debit) | amount }</div>
## credit
<div class="act_as_cell amount">${formatLang(total_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
%if account.currency_id:
## currency balance
<div class="act_as_cell sep_left amount" style="padding-right: 1px;">${formatLang(cumul_balance_curr) | amount }</div>
%else:
<div class="act_as_cell sep_left amount" style="padding-right: 1px;">${ u'-' }</div>
%endif
## curency code
<div class="act_as_cell" style="text-align: right; ">${ account.currency_id.name if account.currency_id else u'' }</div>
%endif
</div>
</div>
</div>
<%
account_total_debit += total_debit
account_total_credit += total_credit
account_balance_cumul += cumul_balance
account_balance_cumul_curr += cumul_balance_curr
%>
%endfor
<div class="act_as_table list_table" style="margin-top:5px;">
<div class="act_as_row labels" style="font-weight: bold; font-size: 12px;">
<div class="act_as_cell first_column" style="width: 330px;">${account.code} - ${account.name}</div>
## label
<div class="act_as_cell" style="width: 395px;">${_("Cumulated Balance on Account")}</div>
## debit
<div class="act_as_cell amount" style="width: 80px;">${ formatLang(account_total_debit) | amount }</div>
## credit
<div class="act_as_cell amount" style="width: 80px;">${ formatLang(account_total_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 80px; ">${ formatLang(account_balance_cumul) | amount }</div>
%if amount_currency(data):
## currency balance cumulated
%if account.currency_id:
<div class="act_as_cell amount sep_left" style="width: 80px;">${ formatLang(account_balance_cumul_curr) | amount }</div>
%else:
<div class="act_as_cell amount sep_left" style="width: 80px; padding-right: 1px;">${ u'-' }</div>
%endif
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right;">${ account.currency_id.name if account.currency_id else u'' }</div>
%endif
</div>
</div>
</div>
%endif
%endfor
</body>
</html>

275
account_financial_report_webkit/report/templates/account_report_partner_balance.mako

@ -0,0 +1,275 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
${css}
.list_table .act_as_row {
margin-top: 10px;
margin-bottom: 10px;
font-size:10px;
}
.account_line {
font-weight: bold;
font-size: 15px;
background-color:#F0F0F0;
}
.account_line .act_as_cell {
height: 30px;
vertical-align: bottom;
}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
<%
initial_balance_text = {'initial_balance': _('Computed'), 'opening_balance': _('Opening Entries'), False: _('No')}
%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates Filter')}
%else:
${_('Periods Filter')}
%endif
</div>
<div class="act_as_cell">${_('Accounts Filter')}</div>
<div class="act_as_cell">${_('Partners Filter')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
<div class="act_as_cell">${_('Initial Balance')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">
%if accounts(data):
${', '.join([account.code for account in accounts(data)])}
%else:
${_('All')}
%endif
</div>
<div class="act_as_cell">${display_partner_account(data)}</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
<div class="act_as_cell">${ initial_balance_text[initial_balance_mode] }</div>
</div>
</div>
%for index, params in enumerate(comp_params):
<div class="act_as_table data_table">
<div class="act_as_row">
<div class="act_as_cell">${_('Comparison %s') % (index + 1,)} (${"C%s" % (index + 1,)})</div>
<div class="act_as_cell">
%if params['comparison_filter'] == 'filter_date':
${_('Dates Filter:')}&nbsp;${formatLang(params['start'], date=True) }&nbsp;-&nbsp;${formatLang(params['stop'], date=True) }
%elif params['comparison_filter'] == 'filter_period':
${_('Periods Filter:')}&nbsp;${params['start'].name}&nbsp;-&nbsp;${params['stop'].name}
%else:
${_('Fiscal Year :')}&nbsp;${params['fiscalyear'].name}
%endif
</div>
<div class="act_as_cell">${ _('Initial Balance:')} ${ initial_balance_text[params['initial_balance_mode']] }</div>
</div>
</div>
%endfor
%for current_account in objects:
<%
partners_order = current_account.partners_order
# do not display accounts without partners
if not partners_order:
continue
comparisons = current_account.comparisons
all_comparison_lines = [comp['partners_amounts'][partner_id[1]] for partner_id in partners_order for comp in comparisons]
if not current_account.balance and not any([line.get('balance') for line in all_comparison_lines]):
continue
current_partner_amounts = current_account.partners_amounts
total_initial_balance = 0.0
total_debit = 0.0
total_credit = 0.0
total_balance = 0.0
if comparison_mode in ('single', 'multiple'):
comparison_total = {}
for i, comp in enumerate(comparisons):
comparison_total[i] = {'balance': 0.0}
%>
<div class="account_title bg" style="margin-top: 20px; font-size: 12px; width: 690px;">${current_account.code} - ${current_account.name}</div>
<div class="act_as_table list_table">
<div class="act_as_thead">
<div class="act_as_row labels">
## code
<div class="act_as_cell first_column" style="width: 20px;">${_('Code / Ref')}</div>
## account name
<div class="act_as_cell" style="width: 80px;">${_('Account / Partner Name')}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance_mode:
## initial balance
<div class="act_as_cell amount" style="width: 30px;">${_('Initial Balance')}</div>
%endif
## debit
<div class="act_as_cell amount" style="width: 30px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 30px;">${_('Credit')}</div>
%endif
## balance
<div class="act_as_cell amount" style="width: 30px;">
%if comparison_mode == 'no_comparison' or not fiscalyear:
${_('Balance')}
%else:
${_('Balance %s') % (fiscalyear.name,)}
%endif
</div>
%if comparison_mode in ('single', 'multiple'):
%for index in range(nb_comparison):
<div class="act_as_cell amount" style="width: 30px;">
%if comp_params[index]['comparison_filter'] == 'filter_year' and comp_params[index].get('fiscalyear', False):
${_('Balance %s') % (comp_params[index]['fiscalyear'].name,)}
%else:
${_('Balance C%s') % (index + 1,)}
%endif
</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount" style="width: 30px;">${_('Difference')}</div>
<div class="act_as_cell amount" style="width: 30px;">${_('% Difference')}</div>
%endif
%endfor
%endif
</div>
</div>
<div class="act_as_tbody">
%for (partner_code_name, partner_id, partner_ref, partner_name) in partners_order:
<%
partner = current_partner_amounts.get(partner_id, {})
all_comparison_lines = [comp['partners_amounts'][partner_id] for comp in comparisons if comp['partners_amounts'].get(partner_id)]
if not partner.get('balance') and not any([line.get('balance') for line in all_comparison_lines]):
continue
total_initial_balance += partner.get('init_balance', 0.0)
total_debit += partner.get('debit', 0.0)
total_credit += partner.get('credit', 0.0)
total_balance += partner.get('balance', 0.0)
%>
<div class="act_as_row lines">
<div class="act_as_cell first_column">${partner_ref if partner_ref else ''}</div>
<div class="act_as_cell">${partner_name if partner_name else _('Unallocated') }</div>
%if comparison_mode == 'no_comparison':
%if initial_balance_mode:
<div class="act_as_cell amount">${formatLang(partner.get('init_balance', 0.0)) | amount}</div>
%endif
<div class="act_as_cell amount">${formatLang(partner.get('debit', 0.0)) | amount}</div>
<div class="act_as_cell amount">${formatLang(partner.get('credit', 0.0)) | amount}</div>
%endif
<div class="act_as_cell amount">${formatLang(partner['balance'] if partner else 0.0) | amount}</div>
%if comparison_mode in ('single', 'multiple'):
%for i, comp in enumerate(comparisons):
<%
comp_partners = comp['partners_amounts']
balance = diff = percent_diff = 0
if comp_partners.get(partner_id):
balance = comp_partners[partner_id]['balance']
diff = comp_partners[partner_id]['diff']
percent_diff = comp_partners[partner_id]['percent_diff']
comparison_total[i]['balance'] += balance
%>
<div class="act_as_cell amount">${formatLang(balance) | amount}</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount">${formatLang(diff) | amount}</div>
<div class="act_as_cell amount">
%if percent_diff is False:
${ '-' }
%else:
${int(round(percent_diff)) | amount} &#37;
%endif
</div>
%endif
%endfor
%endif
</div>
%endfor
</div>
<div class="act_as_tfoot" style="margin-top:5px;">
<div class="act_as_row labels" style="font-weight: bold; font-size: 11x;">
## code
<div class="act_as_cell first_column">${current_account.code}</div>
## account name
<div class="act_as_cell">${current_account.name}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance_mode:
## opening balance
<div class="act_as_cell amount">${formatLang(total_initial_balance) | amount}</div>
%endif
## debit
<div class="act_as_cell amount">${formatLang(total_debit) | amount}</div>
## credit
<div class="act_as_cell amount">${formatLang(total_credit and total_credit * -1 or 0.0) | amount}</div>
%endif
## balance
<div class="act_as_cell amount">${formatLang(total_balance) | amount}</div>
%if comparison_mode in ('single', 'multiple'):
%for i, comp in enumerate(comparisons):
<%
comp_account = comp['account']
diffs = compute_diff(total_balance, comparison_total[i]['balance'])
%>
<div class="act_as_cell amount">${formatLang(comparison_total[i]['balance']) | amount}</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount">${formatLang(diffs['diff']) | amount}</div>
<div class="act_as_cell amount">
%if diffs['percent_diff'] is False:
${ '-' }
%else:
${int(round(diffs['percent_diff'])) | amount} &#37;
%endif
</div>
%endif
%endfor
%endif
</div>
</div>
</div>
%endfor
</body>
</html>

281
account_financial_report_webkit/report/templates/account_report_partners_ledger.mako

@ -0,0 +1,281 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
.overflow_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
${css}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
<%
initial_balance_text = {'initial_balance': _('Computed'), 'opening_balance': _('Opening Entries'), False: _('No')}
%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates Filter')}
%else:
${_('Periods Filter')}
%endif
</div>
<div class="act_as_cell">${_('Accounts Filter')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
<div class="act_as_cell">${_('Initial Balance')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">
%if partner_ids:
${_('Custom Filter')}
%else:
${ display_partner_account(data) }
%endif
</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
<div class="act_as_cell">${ initial_balance_text[initial_balance_mode] }</div>
</div>
</div>
%for account in objects:
%if account.ledger_lines or account.init_balance:
<%
if not account.partners_order:
continue
account_total_debit = 0.0
account_total_credit = 0.0
account_balance_cumul = 0.0
account_balance_cumul_curr = 0.0
%>
<div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${account.code} - ${account.name}</div>
%for partner_name, p_id, p_ref, p_name in account.partners_order:
<%
total_debit = 0.0
total_credit = 0.0
cumul_balance = 0.0
cumul_balance_curr = 0.0
part_cumul_balance = 0.0
part_cumul_balance_curr = 0.0
%>
<div class="act_as_table list_table" style="margin-top: 5px;">
<div class="act_as_caption account_title">
${partner_name or _('No Partner')}
</div>
<div class="act_as_thead">
<div class="act_as_row labels">
## date
<div class="act_as_cell first_column" style="width: 50px;">${_('Date')}</div>
## period
<div class="act_as_cell" style="width: 70px;">${_('Period')}</div>
## move
<div class="act_as_cell" style="width: 70px;">${_('Entry')}</div>
## journal
<div class="act_as_cell" style="width: 70px;">${_('Journal')}</div>
## partner
<div class="act_as_cell" style="width: 60px;">${_('Partner')}</div>
## label
<div class="act_as_cell" style="width: 310px;">${_('Label')}</div>
## reconcile
<div class="act_as_cell" style="width: 80px;">${_('Rec.')}</div>
## debit
<div class="act_as_cell amount" style="width: 80px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 80px;">${_('Credit')}</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 80px;">${_('Cumul. Bal.')}</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell amount sep_left" style="width: 80px;">${_('Curr. Balance')}</div>
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right;">${_('Curr.')}</div>
%endif
</div>
</div>
<div class="act_as_tbody">
<%
total_debit = account.init_balance.get(p_id, {}).get('debit') or 0.0
total_credit = account.init_balance.get(p_id, {}).get('credit') or 0.0
%>
%if initial_balance_mode and (total_debit or total_credit):
<%
part_cumul_balance = account.init_balance.get(p_id, {}).get('init_balance') or 0.0
part_cumul_balance_curr = account.init_balance.get(p_id, {}).get('init_balance_currency') or 0.0
balance_forward_currency = account.init_balance.get(p_id, {}).get('currency_name') or ''
cumul_balance += part_cumul_balance
cumul_balance_curr += part_cumul_balance_curr
%>
<div class="act_as_row initial_balance">
## date
<div class="act_as_cell first_column"></div>
## period
<div class="act_as_cell"></div>
## move
<div class="act_as_cell"></div>
## journal
<div class="act_as_cell"></div>
## partner
<div class="act_as_cell"></div>
## label
<div class="act_as_cell" >${_('Initial Balance')}</div>
## reconcile
<div class="act_as_cell"></div>
## debit
<div class="act_as_cell amount">${formatLang(total_debit) | amount }</div>
## credit
<div class="act_as_cell amount">${formatLang(total_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(part_cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell sep_left amount">${formatLang(part_cumul_balance_curr) | amount }</div>
## curency code
<div class="act_as_cell">${balance_forward_currency}</div>
%endif
</div>
%endif
%for line in account.ledger_lines.get(p_id, []):
<%
total_debit += line.get('debit') or 0.0
total_credit += line.get('credit') or 0.0
label_elements = [line.get('lname') or '']
if line.get('invoice_number'):
label_elements.append("(%s)" % (line['invoice_number'],))
label = ' '.join(label_elements)
%>
<div class="act_as_row lines">
## date
<div class="act_as_cell first_column">${formatLang(line.get('ldate') or '', date=True)}</div>
## period
<div class="act_as_cell">${line.get('period_code') or ''}</div>
## move
<div class="act_as_cell">${line.get('move_name') or ''}</div>
## journal
<div class="act_as_cell">${line.get('jcode') or ''}</div>
## partner
<div class="act_as_cell overflow_ellipsis">${line.get('partner_name') or ''}</div>
## label
<div class="act_as_cell">${label}</div>
## reconcile
<div class="act_as_cell">${line.get('rec_name') or ''}</div>
## debit
<div class="act_as_cell amount">${formatLang(line.get('debit') or 0.0) | amount }</div>
## credit
<div class="act_as_cell amount">${formatLang(line.get('credit') or 0.0) | amount }</div>
## balance cumulated
<% cumul_balance += line.get('balance') or 0.0 %>
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
<div class="act_as_cell sep_left amount">${formatLang(line.get('amount_currency') or 0.0) | amount }</div>
## curency code
<div class="act_as_cell" style="text-align: right; ">${line.get('currency_code') or ''}</div>
%endif
</div>
%endfor
<div class="act_as_row lines labels">
## date
<div class="act_as_cell first_column"></div>
## period
<div class="act_as_cell"></div>
## move
<div class="act_as_cell"></div>
## journal
<div class="act_as_cell"></div>
## partner
<div class="act_as_cell"></div>
## label
<div class="act_as_cell">${_('Cumulated Balance on Partner')}</div>
## reconcile
<div class="act_as_cell"></div>
## debit
<div class="act_as_cell amount">${formatLang(total_debit) | amount }</div>
## credit
<div class="act_as_cell amount">${formatLang(total_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="padding-right: 1px;">${formatLang(cumul_balance) | amount }</div>
%if amount_currency(data):
## currency balance
%if account.currency_id:
<div class="act_as_cell amount sep_left">${formatLang(cumul_balance_curr) | amount }</div>
%else:
<div class="act_as_cell sep_left amount">${ u'-' }</div>
%endif
## currency code
<div class="act_as_cell" style="text-align: right; padding-right: 1px;">${ account.currency_id.name if account.currency_id else u'' }</div>
%endif
</div>
</div>
</div>
<%
account_total_debit += total_debit
account_total_credit += total_credit
account_balance_cumul += cumul_balance
account_balance_cumul_curr += cumul_balance_curr
%>
%endfor
<div class="act_as_table list_table" style="margin-top:5px;">
<div class="act_as_row labels" style="font-weight: bold; font-size: 12px;">
<div class="act_as_cell first_column" style="width: 320px;">${account.code} - ${account.name}</div>
## label
<div class="act_as_cell" style="width: 390px;">${_("Cumulated Balance on Account")}</div>
## debit
<div class="act_as_cell amount" style="width: 80px;">${ formatLang(account_total_debit) | amount }</div>
## credit
<div class="act_as_cell amount" style="width: 80px;">${ formatLang(account_total_credit) | amount }</div>
## balance cumulated
<div class="act_as_cell amount" style="width: 80px; padding-right: 1px;">${ formatLang(account_balance_cumul) | amount }</div>
%if amount_currency(data):
## currency balance
%if account.currency_id:
<div class="act_as_cell amount sep_left" style="width: 80px;">${ formatLang(account_balance_cumul_curr) | amount }</div>
%else:
<div class="act_as_cell amount sep_left" style="width: 80px;">${ u'-' }</div>
%endif
## curency code
<div class="act_as_cell amount" style="width: 30px; text-align: right; padding-right: 1px;">${ account.currency_id.name if account.currency_id else u'' }</div>
%endif
</div>
</div>
</div>
%endif
%endfor
</body>
</html>

210
account_financial_report_webkit/report/templates/account_report_profit_loss.mako

@ -0,0 +1,210 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
${css}
.list_table .act_as_row {
margin-top: 10px;
margin-bottom: 10px;
font-size:10px;
}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%def name="format_amount(amount, display_option=None)">
<%
output = amount
if display_option == 'normal':
output = amount
elif display_option == 'round':
output = u"%.0f" % round(amount)
elif display_option == 'kilo':
if amount:
output = u"%.2fK" % (amount / 1000,)
%>
${output}
</%def>
<%setLang(user.context_lang)%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates')}
%else:
${_('Periods')}
%endif
</div>
<div class="act_as_cell">${_('Displayed Accounts')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
<div class="act_as_cell">${_('Initial Balance')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">
%if accounts(data):
${', '.join([account.code for account in accounts(data)])}
%else:
${_('All')}
%endif
</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
<div class="act_as_cell">${ _('Yes') if initial_balance else _('No') }</div>
</div>
</div>
%for index, params in enumerate(comp_params):
<div class="act_as_table data_table">
<div class="act_as_row">
<div class="act_as_cell">${_('Comparison %s') % (index + 1,)} (${"C%s" % (index + 1,)})</div>
<div class="act_as_cell">
%if params['comparison_filter'] == 'filter_date':
${_('Dates : ')}&nbsp;${formatLang(params['start'], date=True) }&nbsp;-&nbsp;${formatLang(params['stop'], date=True) }
%elif params['comparison_filter'] == 'filter_period':
${_('Periods : ')}&nbsp;${params['start'].name}&nbsp;-&nbsp;${params['stop'].name}
%else:
${_('Fiscal Year : ')}&nbsp;${params['fiscalyear'].name}
%endif
</div>
<div class="act_as_cell">${_('Initial Balance:')} ${ _('Yes') if params['initial_balance'] else _('No') }</div>
</div>
</div>
%endfor
<div class="act_as_table list_table" style="margin-top: 20px;">
<div class="act_as_thead">
<div class="act_as_row labels">
## account name
<div class="act_as_cell" style="width: 80px;">${_('Account')}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance:
## initial balance
<div class="act_as_cell amount" style="width: 30px;">${_('Initial Balance')}</div>
%endif
## debit
<div class="act_as_cell amount" style="width: 30px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 30px;">${_('Credit')}</div>
%endif
## balance
<div class="act_as_cell amount" style="width: 30px;">
%if comparison_mode == 'no_comparison' or not fiscalyear:
${_('Balance')}
%else:
${_('Balance %s') % (fiscalyear.name,)}
%endif
</div>
%if comparison_mode in ('single', 'multiple'):
%for index in range(nb_comparison):
<div class="act_as_cell amount" style="width: 30px;">
%if comp_params[index]['comparison_filter'] == 'filter_year' and comp_params[index].get('fiscalyear', False):
${_('Balance %s') % (comp_params[index]['fiscalyear'].name,)}
%else:
${_('Balance C%s') % (index + 1,)}
%endif
</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount" style="width: 30px;">${_('Difference')}</div>
<div class="act_as_cell amount" style="width: 30px;">${_('% Difference')}</div>
%endif
%endfor
%endif
</div>
</div>
<div class="act_as_tbody">
%for account_at in objects:
<%
current_account = account_at['current']
level = current_account['level']
%>
%if level_print(data, level): ## how to manage levels?
<%
styles = []
if level_bold(data, level):
styles.append('font-weight: bold;')
else:
styles.append('font-weight: normal;')
if level_italic(data, level):
styles.append('font-style: italic;')
else:
styles.append('font-style: normal;')
if level_underline(data, level):
styles.append('text-decoration: underline;')
else:
styles.append('text-decoration: none;')
if level_uppercase(data, level):
styles.append('text-transform: uppercase;')
else:
styles.append('font-decoration: none;')
styles.append("font-size: %spx;" % (level_size(data, level),))
%>
<div class="act_as_row lines ${"account_level_%s" % (current_account['level'])}" styles="${' '.join(styles)}">
## account name
<div class="act_as_cell" style="padding-left: ${current_account.get('level', 0) * 5}px; ${' '.join(styles)}">${current_account['name']}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance:
## opening balance
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(current_account['init_balance'], numbers_display(data)) | amount}</div>
%endif
## debit
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(current_account['debit'], numbers_display(data)) | amount}</div>
## credit
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(current_account['credit'] * -1, numbers_display(data)) if current_account['credit'] else 0.0 | amount}</div>
%endif
## balance
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(current_account['balance'], numbers_display(data)) | amount}</div>
%if comparison_mode in ('single', 'multiple'):
%for comp_account in account_at['comparisons']:
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(comp_account['balance'], numbers_display(data)) | amount}</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount" style="${' '.join(styles)}">${format_amount(comp_account['diff'], numbers_display(data)) | amount}</div>
<div class="act_as_cell amount" style="${' '.join(styles)}">
%if comp_account['percent_diff'] is False:
${ '-' }
%else:
${comp_account['percent_diff'] | amount} &#37;
%endif
</div>
%endif
%endfor
%endif
</div>
%endif
%endfor
</div>
</div>
</body>
</html>

217
account_financial_report_webkit/report/templates/account_report_trial_balance.mako

@ -0,0 +1,217 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
.account_level_1 {
text-transform: uppercase;
font-size: 15px;
background-color:#F0F0F0;
}
.account_level_2 {
font-size: 12px;
background-color:#F0F0F0;
}
.regular_account_type {
font-weight: normal;
}
.view_account_type {
font-weight: bold;
}
.account_level_consol {
font-weight: normal;
font-style: italic;
}
${css}
.list_table .act_as_row {
margin-top: 10px;
margin-bottom: 10px;
font-size:10px;
}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
<%
initial_balance_text = {'initial_balance': _('Computed'), 'opening_balance': _('Opening Entries'), False: _('No')}
%>
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">
%if filter_form(data) == 'filter_date':
${_('Dates Filter')}
%else:
${_('Periods Filter')}
%endif
</div>
<div class="act_as_cell">${_('Accounts Filter')}</div>
<div class="act_as_cell">${_('Target Moves')}</div>
<div class="act_as_cell">${_('Initial Balance')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ chart_account.name }</div>
<div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
${_('From:')}
%if filter_form(data) == 'filter_date':
${formatLang(start_date, date=True) if start_date else u'' }
%else:
${start_period.name if start_period else u''}
%endif
${_('To:')}
%if filter_form(data) == 'filter_date':
${ formatLang(stop_date, date=True) if stop_date else u'' }
%else:
${stop_period.name if stop_period else u'' }
%endif
</div>
<div class="act_as_cell">
%if accounts(data):
${', '.join([account.code for account in accounts(data)])}
%else:
${_('All')}
%endif
</div>
<div class="act_as_cell">${ display_target_move(data) }</div>
<div class="act_as_cell">${ initial_balance_text[initial_balance_mode] }</div>
</div>
</div>
%for index, params in enumerate(comp_params):
<div class="act_as_table data_table">
<div class="act_as_row">
<div class="act_as_cell">${_('Comparison %s') % (index + 1,)} (${"C%s" % (index + 1,)})</div>
<div class="act_as_cell">
%if params['comparison_filter'] == 'filter_date':
${_('Dates Filter:')}&nbsp;${formatLang(params['start'], date=True) }&nbsp;-&nbsp;${formatLang(params['stop'], date=True) }
%elif params['comparison_filter'] == 'filter_period':
${_('Periods Filter:')}&nbsp;${params['start'].name}&nbsp;-&nbsp;${params['stop'].name}
%else:
${_('Fiscal Year :')}&nbsp;${params['fiscalyear'].name}
%endif
</div>
<div class="act_as_cell">${_('Initial Balance:')} ${ initial_balance_text[params['initial_balance_mode']] }</div>
</div>
</div>
%endfor
<div class="act_as_table list_table" style="margin-top: 20px;">
<div class="act_as_thead">
<div class="act_as_row labels">
## code
<div class="act_as_cell first_column" style="width: 20px;">${_('Code')}</div>
## account name
<div class="act_as_cell" style="width: 80px;">${_('Account')}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance_mode:
## initial balance
<div class="act_as_cell amount" style="width: 30px;">${_('Initial Balance')}</div>
%endif
## debit
<div class="act_as_cell amount" style="width: 30px;">${_('Debit')}</div>
## credit
<div class="act_as_cell amount" style="width: 30px;">${_('Credit')}</div>
%endif
## balance
<div class="act_as_cell amount" style="width: 30px;">
%if comparison_mode == 'no_comparison' or not fiscalyear:
${_('Balance')}
%else:
${_('Balance %s') % (fiscalyear.name,)}
%endif
</div>
%if comparison_mode in ('single', 'multiple'):
%for index in range(nb_comparison):
<div class="act_as_cell amount" style="width: 30px;">
%if comp_params[index]['comparison_filter'] == 'filter_year' and comp_params[index].get('fiscalyear', False):
${_('Balance %s') % (comp_params[index]['fiscalyear'].name,)}
%else:
${_('Balance C%s') % (index + 1,)}
%endif
</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount" style="width: 30px;">${_('Difference')}</div>
<div class="act_as_cell amount" style="width: 30px;">${_('% Difference')}</div>
%endif
%endfor
%endif
</div>
</div>
<div class="act_as_tbody">
<%
last_child_consol_ids = []
last_level = False
%>
%for current_account in objects:
<%
if not current_account.to_display:
continue
comparisons = current_account.comparisons
if current_account.id in last_child_consol_ids:
# current account is a consolidation child of the last account: use the level of last account
level = last_level
level_class = "account_level_consol"
else:
# current account is a not a consolidation child: use its own level
level = current_account.level or 0
level_class = "account_level_%s" % (level,)
last_child_consol_ids = [child_consol_id.id for child_consol_id in current_account.child_consol_ids]
last_level = current_account.level
%>
<div class="act_as_row lines ${level_class} ${"%s_account_type" % (current_account.type,)}">
## code
<div class="act_as_cell first_column">${current_account.code}</div>
## account name
<div class="act_as_cell" style="padding-left: ${level * 5}px;">${current_account.name}</div>
%if comparison_mode == 'no_comparison':
%if initial_balance_mode:
## opening balance
<div class="act_as_cell amount">${formatLang(current_account.init_balance) | amount}</div>
%endif
## debit
<div class="act_as_cell amount">${formatLang(current_account.debit) | amount}</div>
## credit
<div class="act_as_cell amount">${formatLang(current_account.credit) | amount}</div>
%endif
## balance
<div class="act_as_cell amount">${formatLang(current_account.balance) | amount}</div>
%if comparison_mode in ('single', 'multiple'):
%for comp_account in comparisons:
<div class="act_as_cell amount">${formatLang(comp_account['balance']) | amount}</div>
%if comparison_mode == 'single': ## no diff in multiple comparisons because it shows too data
<div class="act_as_cell amount">${formatLang(comp_account['diff']) | amount}</div>
<div class="act_as_cell amount">
%if comp_account['percent_diff'] is False:
${ '-' }
%else:
${int(round(comp_account['percent_diff'])) | amount} &#37;
%endif
</div>
%endif
%endfor
%endif
</div>
%endfor
</div>
</div>
</body>
</html>

82
account_financial_report_webkit/report/trial_balance.py

@ -0,0 +1,82 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from report import report_sxw
from tools.translate import _
import pooler
from datetime import datetime
from common_balance_reports import CommonBalanceReportHeaderWebkit
from webkit_parser_header_fix import HeaderFooterTextWebKitParser
def sign(number):
return cmp(number, 0)
class TrialBalanceWebkit(report_sxw.rml_parse, CommonBalanceReportHeaderWebkit):
def __init__(self, cursor, uid, name, context):
super(TrialBalanceWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('TRIAL BALANCE'), company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'report_name': _('Trial Balance'),
'display_account': self._get_display_account,
'display_account_raw': self._get_display_account_raw,
'filter_form': self._get_filter,
'target_move': self._get_target_move,
'display_target_move': self._get_display_target_move,
'accounts': self._get_accounts_br,
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def set_context(self, objects, data, ids, report_type=None):
"""Populate a ledger_lines attribute on each browse record that will be used
by mako template"""
objects, new_ids, context_report_values = self.compute_balance_data(data)
self.localcontext.update(context_report_values)
return super(TrialBalanceWebkit, self).set_context(objects, data, new_ids,
report_type=report_type)
HeaderFooterTextWebKitParser('report.account.account_report_trial_balance_webkit',
'account.account',
'addons/account_financial_report_webkit/report/templates/account_report_trial_balance.mako',
parser=TrialBalanceWebkit)

222
account_financial_report_webkit/report/webkit_parser_header_fix.py

@ -0,0 +1,222 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
#
# Author : Guewen Baconnier (Camptocamp)
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import subprocess
import tempfile
import time
import pooler
import tools
import openerp.addons
from mako import exceptions
from osv.osv import except_osv
from tools.translate import _
from openerp.addons.report_webkit import webkit_report
from openerp.addons.report_webkit.webkit_report import mako_template
from openerp.addons.report_webkit.report_helper import WebKitHelper
# Class used only as a workaround to bug :
# http://code.google.com/p/wkhtmltopdf/issues/detail?id=656
# html headers and footers do not work on big files (hundreds of pages) so we replace them by
# text headers and footers passed as arguments to wkhtmltopdf
# this class has to be removed once the bug is fixed
# in your report class, to print headers and footers as text, you have to add them in the localcontext with a key 'additional_args'
# for instance :
# header_report_name = _('PARTNER LEDGER')
# footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
# self.localcontext.update({
# 'additional_args': [
# ('--header-font-name', 'Helvetica'),
# ('--footer-font-name', 'Helvetica'),
# ('--header-font-size', '10'),
# ('--footer-font-size', '7'),
# ('--header-left', header_report_name),
# ('--footer-left', footer_date_time),
# ('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
# ('--footer-line',),
# ],
# })
class HeaderFooterTextWebKitParser(webkit_report.WebKitParser):
def generate_pdf(self, comm_path, report_xml, header, footer, html_list, webkit_header=False):
"""Call webkit in order to generate pdf"""
if not webkit_header:
webkit_header = report_xml.webkit_header
tmp_dir = tempfile.gettempdir()
out_filename = tempfile.mktemp(suffix=".pdf", prefix="webkit.tmp.")
files = []
file_to_del = []
if comm_path:
command = [comm_path]
else:
command = ['wkhtmltopdf']
command.append('--quiet')
# default to UTF-8 encoding. Use <meta charset="latin-1"> to override.
command.extend(['--encoding', 'utf-8'])
if webkit_header.margin_top :
command.extend(['--margin-top', str(webkit_header.margin_top).replace(',', '.')])
if webkit_header.margin_bottom :
command.extend(['--margin-bottom', str(webkit_header.margin_bottom).replace(',', '.')])
if webkit_header.margin_left :
command.extend(['--margin-left', str(webkit_header.margin_left).replace(',', '.')])
if webkit_header.margin_right :
command.extend(['--margin-right', str(webkit_header.margin_right).replace(',', '.')])
if webkit_header.orientation :
command.extend(['--orientation', str(webkit_header.orientation).replace(',', '.')])
if webkit_header.format :
command.extend(['--page-size', str(webkit_header.format).replace(',', '.')])
if self.parser_instance.localcontext.get('additional_args', False):
for arg in self.parser_instance.localcontext['additional_args']:
command.extend(arg)
count = 0
for html in html_list :
html_file = file(os.path.join(tmp_dir, str(time.time()) + str(count) +'.body.html'), 'w')
count += 1
html_file.write(html)
html_file.close()
file_to_del.append(html_file.name)
command.append(html_file.name)
command.append(out_filename)
try:
status = subprocess.call(command, stderr=subprocess.PIPE) # ignore stderr
if status :
raise except_osv(
_('Webkit raise an error' ),
status
)
except Exception:
for f_to_del in file_to_del :
os.unlink(f_to_del)
pdf = file(out_filename, 'rb').read()
for f_to_del in file_to_del :
os.unlink(f_to_del)
os.unlink(out_filename)
return pdf
# override needed to keep the attachments' storing procedure
def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
"""generate the PDF"""
if context is None:
context={}
htmls = []
if report_xml.report_type != 'webkit':
return super(HeaderFooterTextWebKitParser,self).create_single_pdf(cursor, uid, ids, data, report_xml, context=context)
self.parser_instance = self.parser(cursor,
uid,
self.name2,
context=context)
self.pool = pooler.get_pool(cursor.dbname)
objs = self.getObjects(cursor, uid, ids, context)
self.parser_instance.set_context(objs, data, ids, report_xml.report_type)
template = False
if report_xml.report_file :
path =openerp.addons.get_module_resource(report_xml.report_file)
if os.path.exists(path) :
template = file(path).read()
if not template and report_xml.report_webkit_data :
template = report_xml.report_webkit_data
if not template :
raise except_osv(_('Error!'), _('Webkit Report template not found !'))
header = report_xml.webkit_header.html
footer = report_xml.webkit_header.footer_html
if not header and report_xml.header:
raise except_osv(
_('No header defined for this Webkit report!'),
_('Please set a header in company settings')
)
css = report_xml.webkit_header.css
if not css :
css = ''
user = self.pool.get('res.users').browse(cursor, uid, uid)
#default_filters=['unicode', 'entity'] can be used to set global filter
body_mako_tpl = mako_template(template)
helper = WebKitHelper(cursor, uid, report_xml.id, context)
if report_xml.precise_mode:
for obj in objs:
self.parser_instance.localcontext['objects'] = [obj]
try :
html = body_mako_tpl.render(helper=helper,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext)
htmls.append(html)
except Exception, e:
msg = exceptions.text_error_template().render()
logger.error(msg)
raise except_osv(_('Webkit render'), msg)
else:
try :
html = body_mako_tpl.render(helper=helper,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext)
htmls.append(html)
except Exception, e:
msg = exceptions.text_error_template().render()
logger.error(msg)
raise except_osv(_('Webkit render'), msg)
# NO html footer and header because we write them as text with wkhtmltopdf
head = foot = False
if report_xml.webkit_debug :
try :
deb = body_mako_tpl.render(helper=helper,
css=css,
_debug=tools.ustr("\n".join(htmls)),
_=self.translate_call,
**self.parser_instance.localcontext)
except Exception, e:
msg = exceptions.text_error_template().render()
logger.error(msg)
raise except_osv(_('Webkit render'), msg)
return (deb, 'html')
bin = self.get_lib(cursor, uid)
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls)
return (pdf, 'pdf')

26
account_financial_report_webkit/report_menus.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem icon="STOCK_PRINT" name="General Ledger"
parent="account.final_accounting_reports" action="action_account_general_ledger_menu_webkit"
groups="account.group_account_manager,account.group_account_user" id="account.menu_general_ledger"/>
<menuitem icon="STOCK_PRINT" name="Trial Balance"
parent="account.final_accounting_reports" action="action_account_trial_balance_menu_webkit"
groups="account.group_account_manager,account.group_account_user" id="account.menu_general_Balance_report"/>
<menuitem icon="STOCK_PRINT" name="Partner Ledger"
parent="account.next_id_22" action="action_account_partners_ledger_menu_webkit"
groups="account.group_account_manager,account.group_account_user" id="account.menu_account_partner_ledger"/>
<menuitem icon="STOCK_PRINT" name="Partner Balance"
parent="account.next_id_22" action="action_account_partner_balance_menu_webkit"
groups="account.group_account_manager,account.group_account_user" id="account.menu_account_partner_balance_report"/>
<menuitem icon="STOCK_PRINT" name="Open Invoices"
parent="account.next_id_22" action="action_account_open_invoices_menu_webkit"
groups="account.group_account_manager,account.group_account_user" id="menu_account_open_invoices"/>
</data>
</openerp>

3
account_financial_report_webkit/tests/account_move_line.yml

@ -0,0 +1,3 @@
-
In order to test the last_rec_date behavior we will create a move and reconcile it
-

65
account_financial_report_webkit/tests/general_ledger.yml

@ -0,0 +1,65 @@
-
In order to test the PDF General Ledger webkit wizard I will print report with default setting
-
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF General Ledger webkit wizard I will print report with posted move
-
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'target_move': 'posted'}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF General Ledger webkit wizard I will print report with transactions or non zero balance
-
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'display_account': 'bal_mix'}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF General Ledger webkit wizard I will print report with inital balance and currency ammount
-
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'amount_currency': 1}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
#Filter by date
-
In order to test the PDF General Ledger webkit wizard I will print report with inital balance and currency ammount and I filter by date of the first tree month
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'),'amount_currency': 1, 'chart_account_id': 1, 'date_from': '%s-01-01' %(datetime.now().year),
'date_to':'%s-04-01' %(datetime.now().year), 'display_account': 'bal_all', 'filter': 'filter_date',}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF General Ledger webkit wizard I will print report with inital balance and currency ammount and I filter by date of the first tree month
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'),'amount_currency': 1, 'chart_account_id': 1, 'date_from': '%s-01-01' %(datetime.now().year),
'date_to':'%s-04-01' %(datetime.now().year), 'display_account': 'bal_all', 'filter': 'filter_date',}
ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
# I still have to parse report content but for this I need accounting data on multiple exercises and faor all fiscal year

60
account_financial_report_webkit/tests/open_invoices.yml

@ -0,0 +1,60 @@
-
In order to test the PDF Open Invoices Report webkit wizard I will print report with default setting
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'until_date': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_open_invoices_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Open Invoices Report webkit wizard I will print report with filters and currency
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier'}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_open_invoices_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Open Invoices Report webkit wizard I will print report with filters on partners
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'partner_ids': [ref('base.res_partner_agrolait'), ref('base.res_partner_asus')]}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_open_invoices_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Open Invoices Report webkit wizard I will print report with filters on periods
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'filter': 'filter_period', 'period_from': ref('account.period_1'), 'period_to': ref('account.period_12')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_open_invoices_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Open Invoices Report webkit wizard I will print report with filters on dates
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'filter': 'filter_date', 'date_from': '%s-01-01' %(datetime.now().year), 'date_to': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_open_invoices_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')

67
account_financial_report_webkit/tests/partner_balance.yml

@ -0,0 +1,67 @@
-
In order to test the PDF Partner Balance webkit wizard I will print report with default setting
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Balance webkit wizard I will print report as if we print it from an account
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
ctx.update({'model': 'account.account','active_ids':[ref('account.assets_view'), ref('account.liabilities_view')],'active_id': ref('account.assets_view')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Balance webkit wizard I will print report with filters on period
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'filter': 'filter_period', 'period_from': ref('account.period_1'), 'period_to': ref('account.period_12')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Balance webkit wizard I will print report with filters on dates
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'filter': 'filter_date', 'date_from': '%s-01-01' %(datetime.now().year), 'date_to': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Balance webkit wizard I will print report with one comparison filtered by year
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'comp0_filter': 'filter_year', 'comp0_fiscalyear_id': ref('account.data_fiscalyear')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Balance webkit wizard I will print report with all comparisons filtered by year, period and date
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'comp0_filter': 'filter_year', 'comp0_fiscalyear_id': ref('account.data_fiscalyear'),
'comp1_filter': 'filter_period', 'comp1_period_from': ref('account.period_1'), 'comp1_period_to': ref('account.period_12'),
'comp2_filter': 'filter_date', 'comp2_date_from': '%s-01-01' %(datetime.now().year), 'comp2_date_to': '%s-12-31' %(datetime.now().year)
}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')

60
account_financial_report_webkit/tests/partner_ledger.yml

@ -0,0 +1,60 @@
-
In order to test the PDF Partner Ledger webkit wizard I will print report with default setting
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'until_date': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partners_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Ledger webkit wizard I will print report with filters and currency
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier'}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partners_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Ledger webkit wizard I will print report with filters on partners
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'partner_ids': [ref('base.res_partner_agrolait'), ref('base.res_partner_asus')]}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partners_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Ledger webkit wizard I will print report with filters on periods
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'filter': 'filter_period', 'period_from': ref('account.period_1'), 'period_to': ref('account.period_12')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partners_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Partner Ledger webkit wizard I will print report with filters on dates
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted',
'amount_currency': True, 'result_selection': 'customer_supplier',
'filter': 'filter_date', 'date_from': '%s-01-01' %(datetime.now().year), 'date_to': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partners_ledger_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')

67
account_financial_report_webkit/tests/trial_balance.yml

@ -0,0 +1,67 @@
-
In order to test the PDF Trial Balance webkit wizard I will print report with default setting
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Trial Balance webkit wizard I will print report as if we print it from an account
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
ctx.update({'model': 'account.account','active_ids':[ref('account.assets_view'), ref('account.liabilities_view')],'active_id': ref('account.assets_view')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Trial Balance webkit wizard I will print report with filters on period
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'filter': 'filter_period', 'period_from': ref('account.period_1'), 'period_to': ref('account.period_12')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Trial Balance webkit wizard I will print report with filters on dates
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'filter': 'filter_date', 'date_from': '%s-01-01' %(datetime.now().year), 'date_to': '%s-12-31' %(datetime.now().year)}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Trial Balance webkit wizard I will print report with one comparison filtered by year
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'comp0_filter': 'filter_year', 'comp0_fiscalyear_id': ref('account.data_fiscalyear')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')
-
In order to test the PDF Trial Balance webkit wizard I will print report with all comparisons filtered by year, period and date
-
!python {model: account.account}: |
from datetime import datetime
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'),
'comp0_filter': 'filter_year', 'comp0_fiscalyear_id': ref('account.data_fiscalyear'),
'comp1_filter': 'filter_period', 'comp1_period_from': ref('account.period_1'), 'comp1_period_to': ref('account.period_12'),
'comp2_filter': 'filter_date', 'comp2_date_from': '%s-01-01' %(datetime.now().year), 'comp2_date_to': '%s-12-31' %(datetime.now().year)
}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit')

27
account_financial_report_webkit/wizard/__init__.py

@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import balance_common
from . import general_ledger_wizard
from . import partners_ledger_wizard
from . import trial_balance_wizard
from . import partner_balance_wizard
from . import open_invoices_wizard
#from . import account_report_profit_loss_wizard

295
account_financial_report_webkit/wizard/balance_common.py

@ -0,0 +1,295 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
#
# Author : Guewen Baconnier (Camptocamp)
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time
from osv import fields, osv
from lxml import etree
from tools.translate import _
from datetime import datetime
def previous_year_date(date, nb_prev=1):
if not date:
return False
parsed_date = datetime.strptime(date, '%Y-%m-%d')
previous_date = datetime(year=parsed_date.year - nb_prev,
month=parsed_date.month,
day=parsed_date.day)
return previous_date
class AccountBalanceCommonWizard(osv.osv_memory):
"""Will launch trial balance report and pass required args"""
_inherit = "account.common.account.report"
_name = "account.common.balance.report"
_description = "Common Balance Report"
# an update module should be done if changed
# in order to create fields in db
COMPARISON_LEVEL = 3
COMPARE_SELECTION = [('filter_no', 'No Comparison'),
('filter_year', 'Fiscal Year'),
('filter_date', 'Date'),
('filter_period', 'Periods'),
('filter_opening', 'Opening Only')]
M2O_DYNAMIC_FIELDS = [f % index for f in ["comp%s_fiscalyear_id",
"comp%s_period_from",
"comp%s_period_to",]
for index in range(COMPARISON_LEVEL)]
SIMPLE_DYNAMIC_FIELDS = [f % index for f in ["comp%s_filter",
"comp%s_date_from",
"comp%s_date_to"]
for index in range(COMPARISON_LEVEL)]
DYNAMIC_FIELDS = M2O_DYNAMIC_FIELDS + SIMPLE_DYNAMIC_FIELDS
def _get_account_ids(self, cr, uid, context=None):
res = False
if context.get('active_model', False) == 'account.account' and context.get('active_ids', False):
res = context['active_ids']
return res
_columns = {
'account_ids': fields.many2many('account.account', string='Filter on accounts',
help="Only selected accounts will be printed. Leave empty to print all accounts."),
'filter': fields.selection([('filter_no', 'No Filters'),
('filter_date', 'Date'),
('filter_period', 'Periods'),
('filter_opening', 'Opening Only')], "Filter by", required=True, help='Filter by date : no opening balance will be displayed. (opening balance can only be calculated based on period to be correct).'),
}
for index in range(COMPARISON_LEVEL):
_columns.update(
{"comp%s_filter" % (index,): fields.selection(COMPARE_SELECTION, string='Compare By', required=True),
"comp%s_fiscalyear_id" % (index,): fields.many2one('account.fiscalyear', 'Fiscal Year'),
"comp%s_period_from" % (index,): fields.many2one('account.period', 'Start Period'),
"comp%s_period_to" % (index,): fields.many2one('account.period', 'End Period'),
"comp%s_date_from" % (index,): fields.date("Start Date"),
"comp%s_date_to" % (index,): fields.date("End Date"),})
_defaults = {
'account_ids': _get_account_ids,
}
def _check_fiscalyear(self, cr, uid, ids, context=None):
obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
return False
return True
_constraints = [
(_check_fiscalyear, 'When no Fiscal year is selected, you must choose to filter by periods or by date.', ['filter']),
]
def default_get(self, cr, uid, fields, context=None):
"""
To get default values for the object.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for which we want default values
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
res = super(AccountBalanceCommonWizard, self).default_get(cr, uid, fields, context=context)
for index in range(self.COMPARISON_LEVEL):
field = "comp%s_filter" % (index,)
if not res.get(field, False):
res[field] = 'filter_no'
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
res = super(AccountBalanceCommonWizard, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
res['fields'].update(self.fields_get(cr, uid,
allfields=self.DYNAMIC_FIELDS,
context=context, write_access=True))
eview = etree.fromstring(res['arch'])
placeholder = eview.xpath("//page[@name='placeholder']")
if placeholder:
placeholder = placeholder[0]
for index in range(self.COMPARISON_LEVEL):
page = etree.Element('page', {'name': "comp%s" % (index,), 'string': _("Comparison %s") % (index+1,)})
page.append(etree.Element('field', {'name': "comp%s_filter" % (index,),
'colspan': '4',
'on_change': "onchange_comp_filter(%(index)s, filter, comp%(index)s_filter, fiscalyear_id, date_from, date_to)" % {'index': index}}))
page.append(etree.Element('field', {'name': "comp%s_fiscalyear_id" % (index,),
'colspan': '4',
'attrs': "{'required': [('comp%(index)s_filter','in',('filter_year','filter_opening'))], 'readonly':[('comp%(index)s_filter','not in',('filter_year','filter_opening'))]}" % {'index': index}}))
page.append(etree.Element('separator', {'string': _('Dates'), 'colspan':'4'}))
page.append(etree.Element('field', {'name': "comp%s_date_from" % (index,), 'colspan':'4',
'attrs': "{'required': [('comp%(index)s_filter','=','filter_date')], 'readonly':[('comp%(index)s_filter','!=','filter_date')]}" % {'index': index}}))
page.append(etree.Element('field', {'name': "comp%s_date_to" % (index,), 'colspan':'4',
'attrs': "{'required': [('comp%(index)s_filter','=','filter_date')], 'readonly':[('comp%(index)s_filter','!=','filter_date')]}" % {'index': index}}))
page.append(etree.Element('separator', {'string': _('Periods'), 'colspan':'4'}))
page.append(etree.Element('field', {'name': "comp%s_period_from" % (index,),
'colspan': '4',
'attrs': "{'required': [('comp%(index)s_filter','=','filter_period')], 'readonly':[('comp%(index)s_filter','!=','filter_period')]}" % {'index': index},
'domain': "[('special', '=', False)]"}))
page.append(etree.Element('field', {'name': "comp%s_period_to" % (index,),
'colspan': '4',
'attrs': "{'required': [('comp%(index)s_filter','=','filter_period')], 'readonly':[('comp%(index)s_filter','!=','filter_period')]}" % {'index': index},
'domain': "[('special', '=', False)]"}))
placeholder.addprevious(page)
placeholder.getparent().remove(placeholder)
res['arch'] = etree.tostring(eview)
return res
def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
res = {}
if filter == 'filter_no':
res['value'] = {'period_from': False, 'period_to': False, 'date_from': False ,'date_to': False}
if filter == 'filter_date':
if fiscalyear_id:
fyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id, context=context)
date_from = fyear.date_start
date_to = fyear.date_stop > time.strftime('%Y-%m-%d') and time.strftime('%Y-%m-%d') or fyear.date_stop
else:
date_from, date_to = time.strftime('%Y-01-01'), time.strftime('%Y-%m-%d')
res['value'] = {'period_from': False, 'period_to': False, 'date_from': date_from, 'date_to': date_to}
if filter == 'filter_period' and fiscalyear_id:
start_period = end_period = False
cr.execute('''
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_start ASC
LIMIT 1) AS period_start
UNION
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND p.date_start < NOW()
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_stop DESC
LIMIT 1) AS period_stop''', (fiscalyear_id, fiscalyear_id))
periods = [i[0] for i in cr.fetchall()]
if periods:
start_period = end_period = periods[0]
if len(periods) > 1:
end_period = periods[1]
res['value'] = {'period_from': start_period, 'period_to': end_period, 'date_from': False, 'date_to': False}
return res
def onchange_comp_filter(self, cr, uid, ids, index, main_filter='filter_no', comp_filter='filter_no', fiscalyear_id=False, start_date=False, stop_date=False, context=None):
res = {}
fy_obj = self.pool.get('account.fiscalyear')
last_fiscalyear_id = False
if fiscalyear_id:
fiscalyear = fy_obj.browse(cr, uid, fiscalyear_id, context=context)
last_fiscalyear_ids = fy_obj.search(cr, uid, [('date_stop', '<', fiscalyear.date_start)],
limit=self.COMPARISON_LEVEL, order='date_start desc', context=context)
if last_fiscalyear_ids:
if len(last_fiscalyear_ids) > index:
last_fiscalyear_id = last_fiscalyear_ids[index] # first element for the comparison 1, second element for the comparison 2
fy_id_field = "comp%s_fiscalyear_id" % (index,)
period_from_field = "comp%s_period_from" % (index,)
period_to_field = "comp%s_period_to" % (index,)
date_from_field = "comp%s_date_from" % (index,)
date_to_field = "comp%s_date_to" % (index,)
if comp_filter == 'filter_no':
res['value'] = {fy_id_field: False, period_from_field: False, period_to_field: False, date_from_field: False ,date_to_field: False}
if comp_filter in ('filter_year', 'filter_opening'):
res['value'] = {fy_id_field: last_fiscalyear_id, period_from_field: False, period_to_field: False, date_from_field: False ,date_to_field: False}
if comp_filter == 'filter_date':
dates = {}
if main_filter == 'filter_date':
dates = {
'date_start': previous_year_date(start_date, index + 1).strftime('%Y-%m-%d'),
'date_stop': previous_year_date(stop_date, index + 1).strftime('%Y-%m-%d'),}
elif last_fiscalyear_id:
dates = fy_obj.read(cr, uid, last_fiscalyear_id, ['date_start', 'date_stop'], context=context)
res['value'] = {fy_id_field: False, period_from_field: False, period_to_field: False, date_from_field: dates.get('date_start', False), date_to_field: dates.get('date_stop', False)}
if comp_filter == 'filter_period' and last_fiscalyear_id:
start_period = end_period = False
cr.execute('''
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %(fiscalyear)s
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_start ASC
LIMIT 1) AS period_start
UNION
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %(fiscalyear)s
AND p.date_start < NOW()
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_stop DESC
LIMIT 1) AS period_stop''', {'fiscalyear': last_fiscalyear_id})
periods = [i[0] for i in cr.fetchall()]
if periods and len(periods) > 1:
start_period = end_period = periods[0]
if len(periods) > 1:
end_period = periods[1]
res['value'] = {fy_id_field: False,
period_from_field: start_period,
period_to_field: end_period,
date_from_field: False,
date_to_field: False}
return res
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountBalanceCommonWizard, self).pre_print_report(
cr, uid, ids, data, context)
if context is None:
context = {}
# will be used to attach the report on the main account
data['ids'] = [data['form']['chart_account_id']]
fields_to_read = ['account_ids',]
fields_to_read += self.DYNAMIC_FIELDS
vals = self.read(cr, uid, ids, fields_to_read, context=context)[0]
# extract the id from the m2o tuple (id, name)
for field in self.M2O_DYNAMIC_FIELDS:
if isinstance(vals[field], tuple):
vals[field] = vals[field][0]
vals['max_comparison'] = self.COMPARISON_LEVEL
data['form'].update(vals)
return data
AccountBalanceCommonWizard()

11
account_financial_report_webkit/wizard/balance_common_view.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- inheriting views from more than 2 differents inherited models like
trial.balance.webkit -> account.common.balance.report -> account.common.account.report
is not supported so we have to copy paste the same view for trial balance, balance sheet, profit & loss
-->
</data>
</openerp>

132
account_financial_report_webkit/wizard/general_ledger_wizard.py

@ -0,0 +1,132 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from osv import fields, osv
class AccountReportGeneralLedgerWizard(osv.osv_memory):
"""Will launch general ledger report and pass requiered args"""
_inherit = "account.common.account.report"
_name = "general.ledger.webkit"
_description = "General Ledger Report"
def _get_account_ids(self, cr, uid, context=None):
res = False
if context.get('active_model', False) == 'account.account' and context.get('active_ids', False):
res = context['active_ids']
return res
_columns = {
'amount_currency': fields.boolean("With Currency",
help="It adds the currency column"),
'display_account': fields.selection([('bal_all', 'All'),
('bal_mix', 'With transactions or non zero balance')],
'Display accounts',
required=True),
'account_ids': fields.many2many('account.account', string='Filter on accounts',
help="""Only selected accounts will be printed. Leave empty to print all accounts."""),
'centralize': fields.boolean('Activate Centralization', help='Uncheck to display all the details of centralized accounts.')
}
_defaults = {
'amount_currency': False,
'display_account': 'bal_mix',
'account_ids': _get_account_ids,
'centralize': True,
}
def _check_fiscalyear(self, cr, uid, ids, context=None):
obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
return False
return True
_constraints = [
(_check_fiscalyear, 'When no Fiscal year is selected, you must choose to filter by periods or by date.', ['filter']),
]
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountReportGeneralLedgerWizard, self).pre_print_report(cr, uid, ids, data, context)
if context is None:
context = {}
# will be used to attach the report on the main account
data['ids'] = [data['form']['chart_account_id']]
vals = self.read(cr, uid, ids,
['amount_currency',
'display_account',
'account_ids',
'centralize'],
context=context)[0]
data['form'].update(vals)
return data
def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
res = {}
if filter == 'filter_no':
res['value'] = {'period_from': False, 'period_to': False, 'date_from': False ,'date_to': False}
if filter == 'filter_date':
if fiscalyear_id:
fyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id, context=context)
date_from = fyear.date_start
date_to = fyear.date_stop > time.strftime('%Y-%m-%d') and time.strftime('%Y-%m-%d') or fyear.date_stop
else:
date_from, date_to = time.strftime('%Y-01-01'), time.strftime('%Y-%m-%d')
res['value'] = {'period_from': False, 'period_to': False, 'date_from': date_from, 'date_to': date_to}
if filter == 'filter_period' and fiscalyear_id:
start_period = end_period = False
cr.execute('''
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_start ASC
LIMIT 1) AS period_start
UNION
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND p.date_start < NOW()
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_stop DESC
LIMIT 1) AS period_stop''', (fiscalyear_id, fiscalyear_id))
periods = [i[0] for i in cr.fetchall()]
if periods:
start_period = end_period = periods[0]
if len(periods) > 1:
end_period = periods[1]
res['value'] = {'period_from': start_period, 'period_to': end_period, 'date_from': False, 'date_to': False}
return res
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_general_ledger_webkit',
'datas': data}
AccountReportGeneralLedgerWizard()

89
account_financial_report_webkit/wizard/general_ledger_wizard_view.xml

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_report_general_ledger_view_webkit" model="ir.ui.view">
<field name="name">General Ledger</field>
<field name="model">general.ledger.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="General Ledger" colspan="4"/>
<label nolabel="1" colspan="4" string="This report allows you to print or generate a pdf of your general ledger with details of all your account journals"/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<form position="inside">
<field name="display_account" invisible="True"/>
</form>
<page name="filters" position="after">
<page string="Accounts Filters" name="accounts">
<separator string="Print only" colspan="4"/>
<field name="account_ids" colspan="4" nolabel="1">
<tree>
<field name="code"/>
<field name="name"/>
<field name="type"/>
<field name="company_id"/>
</tree>
</field>
</page>
<page string="Layout Options" name="layout_options">
<field name="amount_currency"/>
<field name="centralize"/>
</page>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
<page name="filters" position="attributes">
<attribute name="string">Time Filters</attribute>
</page>
<field name="period_from" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
</data>
</field>
</record>
<record id="account_report_general_ledger_view_inherit" model="ir.ui.view">
<field name="name">General Ledger</field>
<field name="model">general.ledger.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_report_general_ledger_view"/>
<field name="arch" type="xml">
<field name="fiscalyear_id" position="replace">
<field name="fiscalyear_id" on_change="onchange_fiscalyear(fiscalyear_id)"/>
</field>
</field>
</record>
<record id="action_account_general_ledger_menu_webkit" model="ir.actions.act_window">
<field name="name">General Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">general.ledger.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_general_ledger_view_webkit"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_general_ledger_values_webkit">
<field name="model_id" ref="account.model_account_account"/>
<field name="object" eval="1"/>
<field name="name">General Ledger</field>
<field name="key2">client_print_multi</field>
<field name="value"
eval="'ir.actions.act_window,' +str(ref('action_account_general_ledger_menu_webkit'))"/>
<field name="key">action</field>
<field name="model">account.account</field>
</record>
</data>
</openerp>

127
account_financial_report_webkit/wizard/open_invoices_wizard.py

@ -0,0 +1,127 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2012
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields, osv
class AccountReportOpenInvoicesWizard(osv.osv_memory):
"""Will launch partner ledger report and pass required args"""
_inherit = "partners.ledger.webkit"
_name = "open.invoices.webkit"
_description = "Open Invoices Report"
_columns = {
'until_date': fields.date("Clearance date",
required=True,
help="""The clearance date is essentially a tool used for debtors provisionning calculation.
By default, this date is equal to the the end date (ie: 31/12/2011 if you select fy 2011).
By amending the clearance date, you will be, for instance, able to answer the question : 'based on my last year end debtors open invoices, which invoices are still unpaid today (today is my clearance date)?'
"""),
}
def _check_until_date(self, cr, uid, ids, context=None):
def get_key_id(obj, field):
return obj.get(field) and obj[field][0] or False
obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'period_to', 'date_to', 'until_date'], context=context)
min_date = self.default_until_date(cr, uid, ids,
get_key_id(obj, 'fiscalyear_id'),
get_key_id(obj, 'period_to'),
obj['date_to'],
context=context)
if min_date and obj['until_date'] < min_date:
return False
return True
_constraints = [
(_check_until_date, 'Clearance date must be the very last date of the last period or later.', ['until_date']),
]
def default_until_date(self, cursor, uid, ids, fiscalyear_id=False, period_id=False, date_to=False, context=None):
res_date = False
# first priority: period or date filters
if period_id:
res_date = self.pool.get('account.period').read(cursor, uid, period_id, ['date_stop'], context=context)['date_stop']
elif date_to:
res_date = date_to
elif fiscalyear_id:
res_date = self.pool.get('account.fiscalyear').read(cursor, uid, fiscalyear_id, ['date_stop'], context=context)['date_stop']
return res_date
def onchange_fiscalyear(self, cursor, uid, ids, fiscalyear=False, period_id=False, date_to=False, until_date=False, context=None):
res = {'value': {}}
res['value']['until_date'] = self.default_until_date(cursor, uid, ids,
fiscalyear_id=fiscalyear,
period_id=period_id,
date_to=date_to,
context=context)
return res
def onchange_date_to(self, cursor, uid, ids, fiscalyear=False, period_id=False, date_to=False, until_date=False, context=None):
res = {'value': {}}
res['value']['until_date'] = self.default_until_date(cursor, uid, ids,
fiscalyear_id=fiscalyear,
period_id=period_id,
date_to=date_to,
context=context)
return res
def onchange_period_to(self, cursor, uid, ids, fiscalyear=False, period_id=False, date_to=False, until_date=False, context=None):
res = {'value': {}}
res['value']['until_date'] = self.default_until_date(cursor, uid, ids,
fiscalyear_id=fiscalyear,
period_id=period_id,
date_to=date_to,
context=context)
return res
def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
res = super(AccountReportOpenInvoicesWizard, self).onchange_filter(cr, uid, ids, filter=filter, fiscalyear_id=fiscalyear_id, context=context)
if res.get('value', False):
res['value']['until_date'] = self.default_until_date(cr, uid, ids,
fiscalyear_id=fiscalyear_id,
period_id=res['value'].get('period_to', False),
date_to=res['value'].get('date_to', False),
context=context)
return res
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountReportOpenInvoicesWizard, self).pre_print_report(cr, uid, ids, data, context)
if context is None:
context = {}
vals = self.read(cr, uid, ids,
['until_date',],
context=context)[0]
data['form'].update(vals)
return data
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_open_invoices_webkit',
'datas': data}
AccountReportOpenInvoicesWizard()

72
account_financial_report_webkit/wizard/open_invoices_wizard_view.xml

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_open_invoices_view_webkit" model="ir.ui.view">
<field name="name">Open Invoices Report</field>
<field name="model">open.invoices.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="Open Invoices" colspan="4"/>
<label nolabel="1" colspan="4" string="This report allows you to print or generate a pdf of your open invoices per partner with details of all your payable/receivable account. Exclude full reconciled journal items."/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<xpath expr="//field[@name='target_move']" position="after">
<field name="result_selection" colspan="4"/>
</xpath>
<xpath expr="/form/notebook[1]" position="after">
<separator string="Clearance Analysis Options" colspan="4"/>
<newline/>
<field name="until_date"/>
</xpath>
<page name="filters" position="after">
<page string="Partners Filters" name="partners">
<separator string="Print only" colspan="4"/>
<field name="partner_ids" colspan="4" nolabel="1"/>
</page>
<page string="Layout Options" name="layout_options">
<field name="amount_currency"/>
</page>
</page>
<page name="filters" position="attributes">
<attribute name="string">Time Filters</attribute>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
<field name="fiscalyear_id" position="attributes">
<attribute name="on_change">onchange_fiscalyear(fiscalyear_id, period_to, date_to, until_date)</attribute>
</field>
<field name="date_to" position="attributes">
<attribute name="on_change">onchange_date_to(fiscalyear_id, period_to, date_to, until_date)</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="on_change">onchange_period_to(fiscalyear_id, period_to, date_to, until_date)</attribute>
</field>
<field name="period_from" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
</data>
</field>
</record>
<record id="action_account_open_invoices_menu_webkit" model="ir.actions.act_window">
<field name="name">Open Invoices Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">open.invoices.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_open_invoices_view_webkit"/>
<field name="target">new</field>
</record>
</data>
</openerp>

64
account_financial_report_webkit/wizard/partner_balance_wizard.py

@ -0,0 +1,64 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields, osv
class AccountPartnerBalanceWizard(osv.osv_memory):
"""Will launch partner balance report and pass required args"""
_inherit = "account.common.balance.report"
_name = "partner.balance.webkit"
_description = "Partner Balance Report"
_columns = {
'result_selection': fields.selection([('customer','Receivable Accounts'),
('supplier','Payable Accounts'),
('customer_supplier','Receivable and Payable Accounts')],
"Partner's", required=True),
'partner_ids': fields.many2many('res.partner', string='Filter on partner',
help="Only selected partners will be printed. Leave empty to print all partners."),
}
_defaults = {
'result_selection': 'customer_supplier',
}
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountPartnerBalanceWizard, self).pre_print_report(cr, uid, ids, data, context)
if context is None:
context = {}
vals = self.read(cr, uid, ids,
['result_selection', 'partner_ids'],
context=context)[0]
data['form'].update(vals)
return data
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_partner_balance_webkit',
'datas': data}
AccountPartnerBalanceWizard()

85
account_financial_report_webkit/wizard/partner_balance_wizard_view.xml

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- inheriting views from more than 2 differents inherited models like
partner.balance.webkit -> account.common.balance.report -> account.common.account.report
is not supported so we have to copy paste the same view for partner balance, balance sheet, profit & loss
-->
<record id="account_partner_balance_view_webkit" model="ir.ui.view">
<field name="name">Partner Balance</field>
<field name="model">partner.balance.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="Partner Balance" colspan="4"/>
<label nolabel="1" colspan="4" string="This report is an analysis done by a partner, It is a PDF report containing one line per partner representing the cumulative credit balance"/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<field name="target_move" position="after">
<field name="result_selection" colspan="4"/>
</field>
<page name="filters" position="after">
<page string="Accounts Filters" name="accounts">
<separator string="Print only" colspan="4"/>
<field name="account_ids" colspan="4" nolabel="1" domain="[('type', 'in', ['receivable', 'payable'])]">
<tree>
<field name="code"/>
<field name="name"/>
<field name="type"/>
<field name="company_id"/>
</tree>
</field>
</page>
<page string="Partners Filters" name="accounts">
<separator string="Print only" colspan="4"/>
<field name="partner_ids" colspan="4" nolabel="1"/>
</page>
<page name="placeholder"/>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
<page name="filters" position="attributes">
<attribute name="string">Time Filters</attribute>
</page>
<field name="period_from" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="fiscalyear_id" position="attributes">
<attribute name="attrs">{'required': [('filter', '=', 'filter_opening')]}</attribute>
</field>
</data>
</field>
</record>
<record id="action_account_partner_balance_menu_webkit" model="ir.actions.act_window">
<field name="name">Partner Balance</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">partner.balance.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_partner_balance_view_webkit"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_partner_balance_values_webkit">
<field name="model_id" ref="account.model_account_account"/>
<field name="object" eval="1"/>
<field name="name">Partner Balance</field>
<field name="key2">client_print_multi</field>
<field name="value"
eval="'ir.actions.act_window,' +str(ref('action_account_partner_balance_menu_webkit'))"/>
<field name="key">action</field>
<field name="model">account.account</field>
</record>
</data>
</openerp>

116
account_financial_report_webkit/wizard/partners_ledger_wizard.py

@ -0,0 +1,116 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from osv import fields, osv
class AccountReportPartnersLedgerWizard(osv.osv_memory):
"""Will launch partner ledger report and pass required args"""
_inherit = "account.common.partner.report"
_name = "partners.ledger.webkit"
_description = "Partner Ledger Report"
_columns = {
'amount_currency': fields.boolean("With Currency",
help="It adds the currency column"),
'partner_ids': fields.many2many('res.partner', string='Filter on partner',
help="Only selected partners will be printed. Leave empty to print all partners."),
'filter': fields.selection([('filter_no', 'No Filters'),
('filter_date', 'Date'),
('filter_period', 'Periods')], "Filter by", required=True, help='Filter by date : no opening balance will be displayed. (opening balance can only be calculated based on period to be correct).'),
}
_defaults = {
'amount_currency': False,
'result_selection': 'customer_supplier',
}
def _check_fiscalyear(self, cr, uid, ids, context=None):
obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
return False
return True
_constraints = [
(_check_fiscalyear, 'When no Fiscal year is selected, you must choose to filter by periods or by date.', ['filter']),
]
def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
res = {}
if filter == 'filter_no':
res['value'] = {'period_from': False, 'period_to': False, 'date_from': False ,'date_to': False}
if filter == 'filter_date':
if fiscalyear_id:
fyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id, context=context)
date_from = fyear.date_start
date_to = fyear.date_stop > time.strftime('%Y-%m-%d') and time.strftime('%Y-%m-%d') or fyear.date_stop
else:
date_from, date_to = time.strftime('%Y-01-01'), time.strftime('%Y-%m-%d')
res['value'] = {'period_from': False, 'period_to': False, 'date_from': date_from, 'date_to': date_to}
if filter == 'filter_period' and fiscalyear_id:
start_period = end_period = False
cr.execute('''
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_start ASC
LIMIT 1) AS period_start
UNION
SELECT * FROM (SELECT p.id
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
AND p.date_start < NOW()
AND COALESCE(p.special, FALSE) = FALSE
ORDER BY p.date_stop DESC
LIMIT 1) AS period_stop''', (fiscalyear_id, fiscalyear_id))
periods = [i[0] for i in cr.fetchall()]
if periods:
start_period = end_period = periods[0]
if len(periods) > 1:
end_period = periods[1]
res['value'] = {'period_from': start_period, 'period_to': end_period, 'date_from': False, 'date_to': False}
return res
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountReportPartnersLedgerWizard, self).pre_print_report(cr, uid, ids, data, context)
if context is None:
context = {}
# will be used to attach the report on the main account
data['ids'] = [data['form']['chart_account_id']]
vals = self.read(cr, uid, ids,
['amount_currency', 'partner_ids',],
context=context)[0]
data['form'].update(vals)
return data
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_partners_ledger_webkit',
'datas': data}
AccountReportPartnersLedgerWizard()

69
account_financial_report_webkit/wizard/partners_ledger_wizard_view.xml

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_partner_ledger_view_webkit" model="ir.ui.view">
<field name="name">Partner Ledger</field>
<field name="model">partners.ledger.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="Partner Ledger" colspan="4"/>
<label nolabel="1" colspan="4" string="This report allows you to print or generate a pdf of your partner ledger with details of all your payable/receivable account"/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<xpath expr="//field[@name='target_move']" position="after">
<field name="result_selection" colspan="4"/>
</xpath>
<page name="filters" position="after">
<page string="Partners Filters" name="partners">
<separator string="Print only" colspan="4"/>
<field name="partner_ids" colspan="4" nolabel="1"/>
</page>
<page string="Layout Options" name="layout_options">
<field name="amount_currency"/>
</page>
</page>
<page name="filters" position="attributes">
<attribute name="string">Time Filters</attribute>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
<field name="period_from" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
</data>
</field>
</record>
<record id="action_account_partners_ledger_menu_webkit" model="ir.actions.act_window">
<field name="name">Partner Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">partners.ledger.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_partner_ledger_view_webkit"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_partners_ledger_values_webkit">
<field name="model_id" ref="account.model_account_account"/>
<field name="object" eval="1"/>
<field name="name">Partner Ledger</field>
<field name="key2">client_print_multi</field>
<field name="value"
eval="'ir.actions.act_window,' +str(ref('action_account_partners_ledger_menu_webkit'))"/>
<field name="key">action</field>
<field name="model">account.account</field>
</record>
</data>
</openerp>

166
account_financial_report_webkit/wizard/profit_loss_wizard.py

@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
#
# Author : Guewen Baconnier (Camptocamp)
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from lxml import etree
from tools.translate import _
from osv import fields, osv
LEVEL_STYLES = 6
DEFAULT_STYLES = {
'print': [True, True, True, True, True, True],
'size': [12, 11, 10, 9, 9, 9],
'bold': [True, True, True, False, False, False],
'italic': [False, False, False, False, False, False],
'underline': [False, False, False, False, False, False],
'uppercase': [True, True, False, False, False, False],
}
class AccountProfitAndLossLedgerWizard(osv.osv_memory):
"""Will launch trial balance report and pass required args"""
_inherit = "account.common.balance.report"
_name = "profit.loss.webkit"
_description = "Profit and Loss Report"
_columns = {
'numbers_display': fields.selection([('normal', 'Normal'), ('round', 'Round (No decimal)'), ('kilo', 'Kilo')], 'Numbers Display', required=True)
}
_defaults = {
'numbers_display': 'normal',
}
def view_init(self, cr, uid, fields_list, context=None):
"""
Creates view dynamically and adding fields at runtime.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return: New arch of view with new columns.
"""
res = super(AccountProfitAndLossLedgerWizard, self).view_init(cr, uid, fields_list, context=context)
for index in range(LEVEL_STYLES):
# create columns for each comparison page
self._columns.update({
"level%s_print" % (index,):
fields.boolean('Print'),
"level%s_size" % (index,):
fields.integer('Size', required=True),
"level%s_bold" % (index,):
fields.boolean('Bold'),
"level%s_italic" % (index,):
fields.boolean('Italic'),
"level%s_underline" % (index,):
fields.boolean('Underline'),
"level%s_uppercase" % (index,):
fields.boolean('Uppercase'),
})
return res
def default_get(self, cr, uid, fields, context=None):
"""
To get default values for the object.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for which we want default values
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
res = super(AccountProfitAndLossLedgerWizard, self).default_get(cr, uid, fields, context=context)
for key, values in DEFAULT_STYLES.iteritems():
for index in range(LEVEL_STYLES):
field = "level%s_%s" % (index, key)
if not res.get(field, False):
res[field] = values[index]
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
res = super(AccountProfitAndLossLedgerWizard, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
eview = etree.fromstring(res['arch'])
placeholder = eview.xpath("//group[@name='levels']")
if placeholder:
placeholder = placeholder[0]
for index in range(LEVEL_STYLES):
# add fields
res['fields']["level%s_print" % (index,)] = {'string': "Print", 'type': 'boolean'}
res['fields']["level%s_size" % (index,)] = {'string': "Size", 'type': 'integer', 'required': True}
res['fields']["level%s_bold" % (index,)] = {'string': "Bold", 'type': 'boolean',}
res['fields']["level%s_italic" % (index,)] = {'string': "Italic", 'type': 'boolean',}
res['fields']["level%s_underline" % (index,)] = {'string': "Underline", 'type': 'boolean',}
res['fields']["level%s_uppercase" % (index,)] = {'string': "Uppercase", 'type': 'boolean'}
common_attrs = "{'readonly': [('level%(index)s_print', '=', False)]}" % {'index': index}
group = etree.Element('group', {'name': "group_level_%s" % (index,), 'colspan':'4', 'col': '10'})
group.append(etree.Element('separator', {'string': _('Level %s') % (index+1,), 'colspan':'2'}))
group.append(etree.Element('field', {'name': "level%s_print" % (index,), 'colspan': '8'}))
group.append(etree.Element('field', {'name': "level%s_size" % (index,), 'attrs': common_attrs}))
group.append(etree.Element('field', {'name': "level%s_bold" % (index,), 'attrs': common_attrs}))
group.append(etree.Element('field', {'name': "level%s_italic" % (index,), 'attrs': common_attrs}))
group.append(etree.Element('field', {'name': "level%s_underline" % (index,), 'attrs': common_attrs}))
group.append(etree.Element('field', {'name': "level%s_uppercase" % (index,), 'attrs': common_attrs}))
placeholder.append(group)
res['arch'] = etree.tostring(eview)
return res
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
fields_to_read = ['numbers_display',]
# comparison fields
for index in range(LEVEL_STYLES):
fields_to_read.extend([
"level%s_print" % (index,),
"level%s_size" % (index,),
"level%s_bold" % (index,),
"level%s_italic" % (index,),
"level%s_underline" % (index,),
"level%s_uppercase" % (index,),
])
vals = self.read(cursor, uid, ids, fields_to_read,context=context)[0]
data['form'].update(vals)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_profit_loss_webkit',
'datas': data}
AccountProfitAndLossLedgerWizard()

72
account_financial_report_webkit/wizard/profit_loss_wizard_view.xml

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_profit_loss_view_webkit" model="ir.ui.view">
<field name="name">Profit and Loss Webkit</field>
<field name="model">profit.loss.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="Profit and Loss" colspan="4"/>
<label nolabel="1" colspan="4" string="The Profit and Loss report gives you an overview of your company profit and loss in a single document"/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<page name="filters" position="after">
<page string="Display Options" name="display">
<field name="numbers_display" colspan="4"/>
<group name="levels" colspan="4"/>
</page>
<page string="Accounts Filters" name="accounts">
<separator string="Print only" colspan="4"/>
<field name="account_ids" colspan="4" nolabel="1" domain="[('type', '=', 'view'), ('user_type.report_type', 'in', ('expense', 'income'))]">
<tree>
<field name="code"/>
<field name="name"/>
<field name="type"/>
<field name="company_id"/>
</tree>
</field>
</page>
<page name="placeholder"/>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
</data>
</field>
</record>
<record id="action_account_profit_loss_menu_webkit" model="ir.actions.act_window">
<field name="name">Profit and Loss Webkit</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">profit.loss.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_profit_loss_view_webkit"/>
<field name="target">new</field>
</record>
<!-- Profit & Loss report has not been tested, work in progress -->
<!--<record model="ir.values" id="action_account_profit_loss_values_webkit">-->
<!--<field name="model_id" ref="account.model_account_account"/>-->
<!--<field name="object" eval="1"/>-->
<!--<field name="name">Profit and Loss Webkit</field>-->
<!--<field name="key2">client_print_multi</field>-->
<!--<field name="value"-->
<!--eval="'ir.actions.act_window,' +str(ref('action_account_profit_loss_menu_webkit'))"/>-->
<!--<field name="key">action</field>-->
<!--<field name="model">account.account</field>-->
<!--</record>-->
<!--<menuitem icon="STOCK_PRINT" name="Profit and Loss Webkit"-->
<!--parent="account.final_accounting_reports" action="action_account_profit_loss_menu_webkit"-->
<!--groups="account.group_account_manager,account.group_account_user" id="menu_profit_loss_webkit"/>-->
</data>
</openerp>

41
account_financial_report_webkit/wizard/trial_balance_wizard.py

@ -0,0 +1,41 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright Camptocamp SA 2011
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv
class AccountTrialBalanceWizard(osv.osv_memory):
"""Will launch trial balance report and pass required args"""
_inherit = "account.common.balance.report"
_name = "trial.balance.webkit"
_description = "Trial Balance Report"
def _print_report(self, cursor, uid, ids, data, context=None):
context = context or {}
# we update form with display account value
data = self.pre_print_report(cursor, uid, ids, data, context=context)
return {'type': 'ir.actions.report.xml',
'report_name': 'account.account_report_trial_balance_webkit',
'datas': data}
AccountTrialBalanceWizard()

78
account_financial_report_webkit/wizard/trial_balance_wizard_view.xml

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- inheriting views from more than 2 differents inherited models like
trial.balance.webkit -> account.common.balance.report -> account.common.account.report
is not supported so we have to copy paste the same view for trial balance, balance sheet, profit & loss
-->
<record id="account_trial_balance_view_webkit" model="ir.ui.view">
<field name="name">Trial Balance</field>
<field name="model">trial.balance.webkit</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.account_common_report_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/label[@string='']" position="replace">
<separator string="Trial Balance" colspan="4"/>
<label nolabel="1" colspan="4" string="This report allows you to print or generate a pdf of your trial balance allowing you to quickly check the balance of each of your accounts in a single report"/>
</xpath>
<field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute>
</field>
<page name="filters" position="after">
<page string="Accounts Filters" name="accounts">
<separator string="Print only" colspan="4"/>
<field name="account_ids" colspan="4" nolabel="1" domain="[('type', '=', 'view')]">
<tree>
<field name="code"/>
<field name="name"/>
<field name="type"/>
<field name="company_id"/>
</tree>
</field>
</page>
<page name="placeholder"/>
</page>
<page name="journal_ids" position="attributes">
<attribute name="invisible">True</attribute>
</page>
<page name="filters" position="attributes">
<attribute name="string">Time Filters</attribute>
</page>
<field name="period_from" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="period_to" position="attributes">
<attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
</field>
<field name="fiscalyear_id" position="attributes">
<attribute name="attrs">{'required': [('filter', '=', 'filter_opening')]}</attribute>
</field>
</data>
</field>
</record>
<record id="action_account_trial_balance_menu_webkit" model="ir.actions.act_window">
<field name="name">Trial Balance</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">trial.balance.webkit</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_trial_balance_view_webkit"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_trial_balance_values_webkit">
<field name="model_id" ref="account.model_account_account"/>
<field name="object" eval="1"/>
<field name="name">Trial Balance</field>
<field name="key2">client_print_multi</field>
<field name="value"
eval="'ir.actions.act_window,' +str(ref('action_account_trial_balance_menu_webkit'))"/>
<field name="key">action</field>
<field name="model">account.account</field>
</record>
</data>
</openerp>

4
account_financial_report_webkit/wizard/wizard.xml

@ -0,0 +1,4 @@
<?xml version="1.0" ?>
<openerp>
<data> </data>
</openerp>
Loading…
Cancel
Save