[FIX] account: several fixes on the new bank statement reconciliation widget
[odoo/odoo.git] / addons / account / account_financial_report.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 import time
23 from datetime import datetime
24 from dateutil.relativedelta import relativedelta
25 from operator import itemgetter
26
27 from openerp.osv import fields, osv
28 import openerp.addons.decimal_precision as dp
29 from openerp.tools.translate import _
30
31 # ---------------------------------------------------------
32 # Account Financial Report
33 # ---------------------------------------------------------
34
35 class account_financial_report(osv.osv):
36     _name = "account.financial.report"
37     _description = "Account Report"
38
39     def _get_level(self, cr, uid, ids, field_name, arg, context=None):
40         '''Returns a dictionary with key=the ID of a record and value = the level of this  
41             record in the tree structure.'''
42         res = {}
43         for report in self.browse(cr, uid, ids, context=context):
44             level = 0
45             if report.parent_id:
46                 level = report.parent_id.level + 1
47             res[report.id] = level
48         return res
49
50     def _get_children_by_order(self, cr, uid, ids, context=None):
51         '''returns a dictionary with the key= the ID of a record and value = all its children,
52            computed recursively, and sorted by sequence. Ready for the printing'''
53         res = []
54         for id in ids:
55             res.append(id)
56             ids2 = self.search(cr, uid, [('parent_id', '=', id)], order='sequence ASC', context=context)
57             res += self._get_children_by_order(cr, uid, ids2, context=context)
58         return res
59
60     def _get_balance(self, cr, uid, ids, field_names, args, context=None):
61         '''returns a dictionary with key=the ID of a record and value=the balance amount 
62            computed for this record. If the record is of type :
63                'accounts' : it's the sum of the linked accounts
64                'account_type' : it's the sum of leaf accoutns with such an account_type
65                'account_report' : it's the amount of the related report
66                'sum' : it's the sum of the children of this record (aka a 'view' record)'''
67         account_obj = self.pool.get('account.account')
68         res = {}
69         for report in self.browse(cr, uid, ids, context=context):
70             if report.id in res:
71                 continue
72             res[report.id] = dict((fn, 0.0) for fn in field_names)
73             if report.type == 'accounts':
74                 # it's the sum of the linked accounts
75                 for a in report.account_ids:
76                     for field in field_names:
77                         res[report.id][field] += getattr(a, field)
78             elif report.type == 'account_type':
79                 # it's the sum the leaf accounts with such an account type
80                 report_types = [x.id for x in report.account_type_ids]
81                 account_ids = account_obj.search(cr, uid, [('user_type','in', report_types), ('type','!=','view')], context=context)
82                 for a in account_obj.browse(cr, uid, account_ids, context=context):
83                     for field in field_names:
84                         res[report.id][field] += getattr(a, field)
85             elif report.type == 'account_report' and report.account_report_id:
86                 # it's the amount of the linked report
87                 res2 = self._get_balance(cr, uid, [report.account_report_id.id], field_names, False, context=context)
88                 for key, value in res2.items():
89                     for field in field_names:
90                         res[report.id][field] += value[field]
91             elif report.type == 'sum':
92                 # it's the sum of the children of this account.report
93                 res2 = self._get_balance(cr, uid, [rec.id for rec in report.children_ids], field_names, False, context=context)
94                 for key, value in res2.items():
95                     for field in field_names:
96                         res[report.id][field] += value[field]
97         return res
98
99     _columns = {
100         'name': fields.char('Report Name', required=True, translate=True),
101         'parent_id': fields.many2one('account.financial.report', 'Parent'),
102         'children_ids':  fields.one2many('account.financial.report', 'parent_id', 'Account Report'),
103         'sequence': fields.integer('Sequence'),
104         'balance': fields.function(_get_balance, 'Balance', multi='balance'),
105         'debit': fields.function(_get_balance, 'Debit', multi='balance'),
106         'credit': fields.function(_get_balance, 'Credit', multi="balance"),
107         'level': fields.function(_get_level, string='Level', store=True, type='integer'),
108         'type': fields.selection([
109             ('sum','View'),
110             ('accounts','Accounts'),
111             ('account_type','Account Type'),
112             ('account_report','Report Value'),
113             ],'Type'),
114         'account_ids': fields.many2many('account.account', 'account_account_financial_report', 'report_line_id', 'account_id', 'Accounts'),
115         'account_report_id':  fields.many2one('account.financial.report', 'Report Value'),
116         'account_type_ids': fields.many2many('account.account.type', 'account_account_financial_report_type', 'report_id', 'account_type_id', 'Account Types'),
117         'sign': fields.selection([(-1, 'Reverse balance sign'), (1, 'Preserve balance sign')], 'Sign on Reports', required=True, help='For accounts that are typically more debited than credited and that you would like to print as negative amounts in your reports, you should reverse the sign of the balance; e.g.: Expense account. The same applies for accounts that are typically more credited than debited and that you would like to print as positive amounts in your reports; e.g.: Income account.'),
118         'display_detail': fields.selection([
119             ('no_detail','No detail'),
120             ('detail_flat','Display children flat'),
121             ('detail_with_hierarchy','Display children with hierarchy')
122             ], 'Display details'),
123         'style_overwrite': fields.selection([
124             (0, 'Automatic formatting'),
125             (1,'Main Title 1 (bold, underlined)'),
126             (2,'Title 2 (bold)'),
127             (3,'Title 3 (bold, smaller)'),
128             (4,'Normal Text'),
129             (5,'Italic Text (smaller)'),
130             (6,'Smallest Text'),
131             ],'Financial Report Style', help="You can set up here the format you want this record to be displayed. If you leave the automatic formatting, it will be computed based on the financial reports hierarchy (auto-computed field 'level')."),
132     }
133
134     _defaults = {
135         'type': 'sum',
136         'display_detail': 'detail_flat',
137         'sign': 1,
138         'style_overwrite': 0,
139     }
140
141
142 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: