Account_Report:Tree-structured report content for Indicators.
[odoo/odoo.git] / addons / account_report / account.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22 import time
23 import netsvc
24 from osv import fields, osv
25 import pooler
26 from tools.misc import currency
27
28 import mx.DateTime
29 from mx.DateTime import RelativeDateTime, now, DateTime, localtime
30
31
32 class account_report(osv.osv):
33     _name = "account.report.report"
34     _description = "Account reporting"
35 #    _color = [
36 #            ('', ''),
37 #            ('green','Green'),
38 #            ('red','Red'),
39 #            ('pink','Pink'),
40 #            ('blue','Blue'),
41 #            ('yellow','Yellow'),
42 #            ('cyan','Cyan'),
43 #            ('lightblue','Light Blue'),
44 #            ('orange','Orange'),
45 #            ]
46 #    _style = [
47 #            ('1','Header 1'),
48 #            ('2','Header 2'),
49 #            ('3','Header 3'),
50 #            ('4','Header 4'),
51 #            ('5','Normal'),
52 #            ('6', 'Small'),
53 #            ]
54
55     def _amount_get(self, cr, uid, ids, field_name, arg, context={}):
56         obj_fy=self.pool.get('account.fiscalyear')
57         obj_period=self.pool.get('account.period')
58
59         def _calc_context(key,obj):
60             if key==0:
61                 return obj.find(cr,uid)
62             else:
63                 obj_key=obj.browse(cr,uid,obj.find(cr,uid))
64                 if isinstance(obj_key,list):
65                     obj_key=obj_key[0]
66                 key_ids=obj.search(cr,uid,[('date_stop','<',obj_key.date_start)])
67                 if len(key_ids)<abs(key):
68                     return False
69                 return key_ids[key]
70
71         def _calc_credit(code,year=0):
72             context['fiscalyear']=_calc_context(year,obj_fy)
73             if not context['fiscalyear']:
74                 del context['fiscalyear']
75             acc = self.pool.get('account.account')
76             acc_id = acc.search(cr, uid, [('code','in',code)])
77             return reduce(lambda y,x=0: x.credit+y, acc.browse(cr, uid, acc_id, context),0.0)
78
79         def _calc_debit(code,year=0):
80             context['fiscalyear']=_calc_context(year,obj_fy)
81             if not context['fiscalyear']:
82                 del context['fiscalyear']
83             acc = self.pool.get('account.account')
84             acc_id = acc.search(cr, uid, [('code','in',code)])
85             return reduce(lambda y,x=0: x.debit+y, acc.browse(cr, uid, acc_id, context),0.0)
86
87         def _calc_balance(code,year=0):
88             context['fiscalyear']=_calc_context(year,obj_fy)
89             if not context['fiscalyear']:
90                 del context['fiscalyear']
91             acc = self.pool.get('account.account')
92             acc_id = acc.search(cr, uid, [('code','in',code)])
93             return reduce(lambda y,x=0: x.balance+y, acc.browse(cr, uid, acc_id, context),0.0)
94
95         def _calc_report(*code):
96             acc = self.pool.get('account.report.report')
97             acc_id = acc.search(cr, uid, [('code','in',code)])
98             return reduce(lambda y,x=0: x.amount+y, acc.browse(cr, uid, acc_id, context),0.0)
99
100         def _calc_tax_code(code,period=0):
101             context['period_id']=_calc_context(period,obj_period)
102             if not context['period_id']:
103                 return 0.00
104             context['period_id']=context['period_id'][0]
105             acc = self.pool.get('account.tax.code')
106             acc_id = acc.search(cr, uid, [('code','in',code)])
107             return reduce(lambda y,x=0: x.sum_period+y, acc.browse(cr, uid, acc_id, context),0.0)
108         result = {}
109         for rep in self.browse(cr, uid, ids, context):
110             objdict = {
111                 'debit': _calc_debit,
112                 'credit': _calc_credit,
113                 'balance': _calc_balance,
114                 'report': _calc_report,
115                 'tax_code': _calc_tax_code,
116             }
117 #            if field_name=='status':
118 #                fld_name = 'expression_status'
119 #            else:
120 #                fld_name = 'expression'
121             try:
122                 val = eval(getattr(rep,'expression'), objdict)
123             except:
124                 val = 0.0
125
126             if field_name=='status':
127                 if val<rep.badness_limit:
128                     result[rep.id] = 'very bad'
129                 elif val==rep.badness_limit:
130                     result[rep.id] = 'bad'
131                 elif val<rep.goodness_limit:
132                     result[rep.id] = 'normal'
133                 elif val==rep.goodness_limit:
134                     result[rep.id] = 'good'
135                 else:
136                     result[rep.id] = 'very good'
137             else:
138                 result[rep.id] =  val
139         return result
140
141     def onchange_parent_id(self, cr, uid, ids, parent_id):
142         v={}
143         if parent_id:
144             acc=self.pool.get('account.report.report').browse(cr,uid,parent_id)
145             v['type']=acc.type
146 #            if int(acc.style) < 6:
147 #                v['style'] = str(int(acc.style)+1)
148         return {'value': v}
149
150     _columns = {
151         'name': fields.char('Name', size=64, required=True),
152         'active': fields.boolean('Active'),
153         'sequence': fields.integer('Sequence'),
154         'code': fields.char('Code', size=64, required=True),
155         'type': fields.selection([
156             ('fiscal', 'Fiscal statement'),
157             ('indicator','Indicator'),
158             ('view','View'),
159             ('other','Others')],
160             'Type', required=True),
161         'expression': fields.char('Expression', size=240, required=True),
162 #        'expression_status': fields.char('Status expression', size=240, required=True),
163         'badness_limit' :fields.float('Badness Indicator Limit', digits=(16,2),help='This Value depicts the limit of badness.'),
164         'goodness_limit' :fields.float('Goodness Indicator Limit', digits=(16,2),help='This Value depicts the limit of goodness.'),
165         'parent_id': fields.many2one('account.report.report', 'Parent'),
166         'child_ids': fields.one2many('account.report.report', 'parent_id', 'Childs'),
167         'note': fields.text('Note'),
168         'amount': fields.function(_amount_get, method=True, string='Value'),
169         'status': fields.function(_amount_get,
170             method=True,
171             type="selection",
172             selection=[
173                 ('very bad', 'Very Bad'),
174                 ('bad', 'Bad'),
175                 ('normal', 'Normal'),
176                 ('good', 'Good'),
177                 ('very good', 'Very Good')
178             ],
179             string='Status'),
180          'disp_tree':fields.boolean('Display Tree',help='When the indicators will be printed, if one indicator is set with this field to True, then it will display one more graph with all its children in tree'),
181          'disp_graph':fields.boolean('Display as a Graph',help='If the field is set to True,information will be printed as a Graph; as an array otherwise.'),
182 #        'style': fields.selection(_style, 'Style', required=True),
183 #        'color_font' : fields.selection(_color, 'Font Color', help="Font Color for the report"),
184 #        'color_back' : fields.selection(_color, 'Back Color')
185     }
186     _defaults = {
187 #        'style': lambda *args: '5',
188         'active': lambda *args: True,
189         'type': lambda *args: 'indicator',
190     }
191
192     def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
193         if not args:
194             args=[]
195         if not context:
196             context={}
197         ids = []
198         if name:
199             ids = self.search(cr, user, [('code','=',name)]+ args, limit=limit, context=context)
200             if not ids:
201                 ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit, context=context)
202         else:
203             ids = self.search(cr, user, args, limit=limit, context=context)
204         return self.name_get(cr, user, ids, context=context)
205
206     _constraints = [
207     #TODO Put an expression to valid expression and expression_status
208     ]
209     _sql_constraints = [
210         ('code_uniq', 'unique (code)', 'The code of the report entry must be unique !')
211     ]
212
213 account_report()
214
215 class account_report_history(osv.osv):
216
217     def _calc_value(self, cr, uid, ids, name, args, context):
218         acc_report_id=self.read(cr,uid,ids,['tmp','period_id'])
219         tmp_ids={}
220         for a in acc_report_id:
221             period_val=pooler.get_pool(cr.dbname).get('account.period').read(cr,uid,[a['period_id'][0]])[0]
222             period_id=pooler.get_pool(cr.dbname).get('account.period').search(cr,uid,[('date_start','<=',period_val['date_start']),('fiscalyear_id','=',period_val['fiscalyear_id'][0])])
223             tmp_ids[a['id']] = pooler.get_pool(cr.dbname).get('account.report.report').read(cr,uid,[a['tmp']],context={'periods':period_id})[0]['amount']
224         return tmp_ids
225
226     _name = "account.report.history"
227     _description = "Indicator"
228     _table = "account_report"
229     _auto = False
230     _order='name'
231     _columns = {
232         'period_id': fields.many2one('account.period','Period', readonly=True, select=True),
233         'fiscalyear_id': fields.many2one('account.fiscalyear','Fiscal Year', readonly=True, select=True),
234         'name': fields.many2one('account.report.report','Indicator', readonly=True, select=True),
235         'val': fields.function(_calc_value, method=True, string='Value', readonly=True),
236         'tmp' : fields.integer(string='temp',readonly=True)
237     }
238
239     def init(self, cr):
240         cr.execute('''create or replace view account_report as (select ar.id as tmp,((pr.id*100000)+ar.id) as id,ar.id as name,pr.id as period_id,pr.fiscalyear_id as fiscalyear_id from account_report_report as ar cross join account_period as pr group by ar.id,pr.id,pr.fiscalyear_id)''')
241
242     def unlink(self, cr, uid, ids, context={}):
243         raise osv.except_osv(_('Error !'), _('You can not delete an indicator history record. You may have to delete the concerned Indicator!'))
244
245 account_report_history()
246
247 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
248