~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/report/custom.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
##############################################################################
 
2
#
 
3
# Copyright (c) 2004-2005 TINY SPRL. (http://tiny.be) All Rights Reserved.
 
4
#
 
5
# $Id: custom.py 1305 2005-09-08 14:39:51Z kayhman $
 
6
#
 
7
# WARNING: This program as such is intended to be used by professional
 
8
# programmers who take the whole responsability of assessing all potential
 
9
# consequences resulting from its eventual inadequacies and bugs
 
10
# End users who are looking for a ready-to-use solution with commercial
 
11
# garantees and support are strongly adviced to contract a Free Software
 
12
# Service Company
 
13
#
 
14
# This program is Free Software; you can redistribute it and/or
 
15
# modify it under the terms of the GNU General Public License
 
16
# as published by the Free Software Foundation; either version 2
 
17
# of the License, or (at your option) any later version.
 
18
#
 
19
# This program is distributed in the hope that it will be useful,
 
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
# GNU General Public License for more details.
 
23
#
 
24
# You should have received a copy of the GNU General Public License
 
25
# along with this program; if not, write to the Free Software
 
26
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
27
#
 
28
##############################################################################
 
29
 
 
30
import os, time
 
31
import netsvc
 
32
 
 
33
import tools
 
34
import print_xml
 
35
import render
 
36
from interface import report_int
 
37
import common
 
38
from osv.orm import browse_null
 
39
from osv.orm import browse_record_list
 
40
import pooler
 
41
from xml.dom import minidom
 
42
import libxml2
 
43
import libxslt
 
44
from pychart import *
 
45
import misc
 
46
import StringIO
 
47
 
 
48
class external_pdf(render.render):
 
49
        def __init__(self, pdf):
 
50
                render.render.__init__(self)
 
51
                self.pdf = pdf
 
52
                self.output_type='pdf'
 
53
        def _render(self):
 
54
                return self.pdf
 
55
 
 
56
theme.use_color = 1
 
57
 
 
58
 
 
59
#TODO: devrait heriter de report_rml a la place de report_int 
 
60
# -> pourrait overrider que create_xml a la place de tout create
 
61
# heuu, ca marche pas ds tous les cas car graphs sont generes en pdf directment
 
62
# par pychart, et on passe donc pas par du rml
 
63
class report_custom(report_int):
 
64
        def __init__(self, name):
 
65
                report_int.__init__(self, name)
 
66
        #
 
67
        # PRE:
 
68
        #    fields = [['address','city'],['name'], ['zip']]
 
69
        #    conditions = [[('zip','==','3'),(,)],(,),(,)] #same structure as fields
 
70
        #    row_canvas = ['Rue', None, None]
 
71
        # POST:
 
72
        #    [ ['ville','name','zip'] ]
 
73
        #
 
74
        def _row_get(self, cr, uid, objs, fields, conditions, row_canvas=None, group_by=None):
 
75
                result = []
 
76
                tmp = []
 
77
                for obj in objs:
 
78
                        tobreak = False
 
79
                        for cond in conditions:
 
80
                                if cond and cond[0]:
 
81
                                        c = cond[0]
 
82
                                        temp = c[0](eval('obj.'+c[1]))
 
83
                                        if not eval('\''+temp+'\''+' '+c[2]+' '+'\''+str(c[3])+'\''):
 
84
                                                tobreak = True
 
85
                        if tobreak:
 
86
                                break
 
87
                        levels = {}
 
88
                        row = []
 
89
                        for i in range(len(fields)):
 
90
                                if not fields[i]:
 
91
                                        row.append(row_canvas and row_canvas[i])
 
92
                                        if row_canvas[i]:
 
93
                                                row_canvas[i]=False
 
94
                                elif len(fields[i])==1:
 
95
                                        if not isinstance(obj, browse_null):
 
96
                                                row.append(str(eval('obj.'+fields[i][0])))
 
97
                                        else:
 
98
                                                row.append(None)
 
99
                                else:
 
100
                                        row.append(None)
 
101
                                        levels[fields[i][0]]=True
 
102
                        if not levels:
 
103
                                result.append(row)
 
104
                        else:
 
105
                                # Process group_by data first
 
106
                                key = []
 
107
                                if group_by != None and fields[group_by] != None:
 
108
                                        if fields[group_by][0] in levels.keys():
 
109
                                                key.append(fields[group_by][0])
 
110
                                        for l in levels.keys():
 
111
                                                if l != fields[group_by][0]:
 
112
                                                        key.append(l)
 
113
                                else:
 
114
                                        key = levels.keys()
 
115
                                for l in key:
 
116
                                        objs = eval('obj.'+l)
 
117
                                        if not isinstance(objs, browse_record_list) and type(objs) <> type([]):
 
118
                                                objs = [objs]
 
119
                                        field_new = []
 
120
                                        cond_new = []
 
121
                                        for f in range(len(fields)):
 
122
                                                if (fields[f] and fields[f][0])==l:
 
123
                                                        field_new.append(fields[f][1:])
 
124
                                                        cond_new.append(conditions[f][1:])
 
125
                                                else:
 
126
                                                        field_new.append(None)
 
127
                                                        cond_new.append(None)
 
128
                                        if len(objs):
 
129
                                                result += self._row_get(cr, uid, objs, field_new, cond_new, row, group_by)
 
130
                                        else:
 
131
                                                result.append(row)
 
132
                return result 
 
133
 
 
134
 
 
135
        def create(self, cr, uid, ids, datas, context={}):
 
136
                self.pool = pooler.get_pool(cr.dbname)
 
137
                report = self.pool.get('ir.report.custom').browse(cr, uid, [datas['report_id']])[0]
 
138
                datas['model'] = report.model_id.model
 
139
                if report.menu_id:
 
140
                        ids = self.pool.get(report.model_id.model).search(cr, uid, [])
 
141
                        datas['ids'] = ids
 
142
 
 
143
                service = netsvc.LocalService("object_proxy")
 
144
                report_id = datas['report_id']
 
145
                report = service.execute(cr.dbname, uid, 'ir.report.custom', 'read', [report_id], context=context)[0]
 
146
                fields = service.execute(cr.dbname, uid, 'ir.report.custom.fields', 'read', report['fields_child0'], context=context)
 
147
 
 
148
                fields.sort(lambda x,y : x['sequence'] - y['sequence'])
 
149
 
 
150
                if report['field_parent']:
 
151
                        parent_field = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [report['field_parent'][0]],['model'])
 
152
                model_name = service.execute(cr.dbname, uid, 'ir.model', 'read', [report['model_id'][0]], ['model'],context=context)[0]['model']
 
153
 
 
154
                fct = {}
 
155
                fct['id'] = lambda x : x
 
156
                fct['gety'] = lambda x: x.split('-')[0]
 
157
                fct['in'] = lambda x: x.split(',')
 
158
                new_fields = []
 
159
                new_cond = []
 
160
                for f in fields:
 
161
                        row = []
 
162
                        cond = []
 
163
                        for i in range(4):
 
164
                                if f['field_child'+str(i)]:
 
165
                                        row.append(f['field_child'+str(i)][1])
 
166
                                        if f['fc'+str(i)+'_operande']:
 
167
                                                fct_name = 'id'
 
168
                                                cond_op =  f['fc'+str(i)+'_op']
 
169
                                                if len(f['fc'+str(i)+'_op'].split(',')) == 2:
 
170
                                                        cond_op =  f['fc'+str(i)+'_op'].split(',')[1]
 
171
                                                        fct_name = f['fc'+str(i)+'_op'].split(',')[0]
 
172
                                                cond.append((fct[fct_name], f['fc'+str(i)+'_operande'][1], cond_op, f['fc'+str(i)+'_condition']))
 
173
                                        else:
 
174
                                                cond.append(None)
 
175
                        new_fields.append(row)
 
176
                        new_cond.append(cond)
 
177
                objs = self.pool.get(model_name).browse(cr, uid, ids)
 
178
 
 
179
                # Group by
 
180
                groupby = None
 
181
                idx = 0
 
182
                for f in fields:
 
183
                        if f['groupby']:
 
184
                                groupby = idx
 
185
                        idx += 1
 
186
 
 
187
 
 
188
                results = []
 
189
                if report['field_parent']:
 
190
                        level = []
 
191
                        def build_tree(obj, level, depth):
 
192
                                res = self._row_get(cr, uid,[obj], new_fields, new_cond)
 
193
                                level.append(depth)
 
194
                                new_obj = eval('obj.'+report['field_parent'][1])
 
195
                                if not isinstance(new_obj, list) :
 
196
                                        new_obj = [new_obj]
 
197
                                for o in  new_obj:
 
198
                                        if not isinstance(o, browse_null):
 
199
                                                res += build_tree(o, level, depth+1)
 
200
                                return res
 
201
 
 
202
                        for obj in objs:
 
203
                                results += build_tree(obj, level, 0)
 
204
                else:
 
205
                        results = self._row_get(cr, uid,objs, new_fields, new_cond, group_by=groupby)
 
206
 
 
207
                fct = {
 
208
                        'calc_sum': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0),
 
209
                        'calc_avg': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0) / (len(filter(None, l)) or 1.0),
 
210
                        'calc_max': lambda l: reduce(lambda x,y: max(x,y), [(i or 0.0) for i in l], 0),
 
211
                        'calc_min': lambda l: reduce(lambda x,y: min(x,y), [(i or 0.0) for i in l], 0),
 
212
                        'calc_count': lambda l: len(filter(None, l)),
 
213
                        'False': lambda l: '\r\n'.join(filter(None, l)),
 
214
                        'groupby': lambda l: reduce(lambda x,y: x or y, l)
 
215
                }
 
216
                new_res = []
 
217
 
 
218
                prev = None
 
219
                if groupby != None:
 
220
                        res_dic = {}
 
221
                        for line in results:
 
222
                                if not line[groupby] and prev in res_dic:
 
223
                                        res_dic[prev].append(line)
 
224
                                else:
 
225
                                        prev = line[groupby]
 
226
                                        if res_dic.has_key(line[groupby]):
 
227
                                                res_dic[line[groupby]].append(line)
 
228
                                        else:
 
229
                                                res_dic[line[groupby]] = []
 
230
                                                res_dic[line[groupby]].append(line)
 
231
                        #we use the keys in results since they are ordered, whereas in res_dic.heys() they aren't
 
232
                        for key in filter(None, [x[groupby] for x in results]):
 
233
                                row = []
 
234
                                for col in range(len(fields)):
 
235
                                        if col == groupby:
 
236
                                                row.append(fct['groupby'](map(lambda x: x[col], res_dic[key])))
 
237
                                        else:
 
238
                                                row.append(fct[str(fields[col]['operation'])](map(lambda x: x[col], res_dic[key])))
 
239
                                new_res.append(row)
 
240
                        results = new_res
 
241
                
 
242
                if report['type']=='table':
 
243
                        if report['field_parent']:
 
244
                                res = self._create_tree(uid, ids, report, fields, level, results, context)
 
245
                        else:
 
246
                                sort_idx = 0
 
247
                                for idx in range(len(fields)):
 
248
                                        if fields[idx]['name'] == report['sortby']:
 
249
                                                sort_idx = idx
 
250
                                                break
 
251
                                try :
 
252
                                        results.sort(lambda x,y : cmp(float(x[sort_idx]),float(y[sort_idx])))
 
253
                                except :
 
254
                                        results.sort(lambda x,y : cmp(x[sort_idx],y[sort_idx]))
 
255
                                if report['limitt']:
 
256
                                        results = results[:int(report['limitt'])]
 
257
                                res = self._create_table(uid, ids, report, fields, None, results, context)
 
258
                elif report['type'] in ('pie','bar', 'line'):
 
259
                        results2 = []
 
260
                        prev = False
 
261
                        for r in results:
 
262
                                row = []
 
263
                                for j in range(len(r)):
 
264
                                        if j == 0 and not r[j]:
 
265
                                                row.append(prev)
 
266
                                        elif j == 0 and r[j]:
 
267
                                                prev = r[j]
 
268
                                                row.append(r[j])
 
269
                                        else:
 
270
                                                try:
 
271
                                                        row.append(float(r[j]))
 
272
                                                except:
 
273
                                                        row.append(r[j])
 
274
                                results2.append(row)
 
275
                        if report['type']=='pie':
 
276
                                res = self._create_pie(cr,uid, ids, report, fields, results2, context)
 
277
                        elif report['type']=='bar':
 
278
                                res = self._create_bars(cr,uid, ids, report, fields, results2, context)
 
279
                        elif report['type']=='line':
 
280
                                res = self._create_lines(cr,uid, ids, report, fields, results2, context)
 
281
                return (self.obj.get(), 'pdf')
 
282
 
 
283
        def _create_tree(self, uid, ids, report, fields, level, results, context):
 
284
                pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
 
285
                if report['print_orientation']=='landscape':
 
286
                        pageSize=[pageSize[1],pageSize[0]]
 
287
 
 
288
                impl = minidom.getDOMImplementation()
 
289
                new_doc = impl.createDocument(None, "report", None)
 
290
                
 
291
                # build header
 
292
                config = new_doc.createElement("config")
 
293
 
 
294
                def _append_node(name, text):
 
295
                        n = new_doc.createElement(name)
 
296
                        t = new_doc.createTextNode(text)
 
297
                        n.appendChild(t)
 
298
                        config.appendChild(n)
 
299
 
 
300
                _append_node('date', time.strftime('%d/%m/%Y'))
 
301
                _append_node('PageFormat', '%s' % report['print_format'])
 
302
                _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
 
303
                _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
 
304
                _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
 
305
 
 
306
                length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
 
307
                count = 0
 
308
                for f in fields:
 
309
                        if not f['width']: count+=1
 
310
                for f in fields:
 
311
                        if not f['width']:
 
312
                                f['width']=round((float(length)/count)-0.5)
 
313
 
 
314
                _append_node('tableSize', '%s' %  ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
 
315
                _append_node('report-header', '%s' % (report['title'],))
 
316
                _append_node('report-footer', '%s' % (report['footer'],))
 
317
 
 
318
                new_doc.childNodes[0].appendChild(config)
 
319
                header = new_doc.createElement("header")
 
320
                
 
321
                for f in fields:
 
322
                        field = new_doc.createElement("field")
 
323
                        field_txt = new_doc.createTextNode('%s' % (f['name'],))
 
324
                        field.appendChild(field_txt)
 
325
                        header.appendChild(field)
 
326
                
 
327
                new_doc.childNodes[0].appendChild(header)
 
328
 
 
329
                lines = new_doc.createElement("lines")
 
330
                level.reverse()
 
331
                for line in results:
 
332
                        shift = level.pop()
 
333
                        node_line = new_doc.createElement("row")
 
334
                        prefix = '+'
 
335
                        for f in range(len(fields)):
 
336
                                col = new_doc.createElement("col")
 
337
                                if f == 0:
 
338
                                        col.setAttribute('para','yes')
 
339
                                        col.setAttribute('tree','yes')
 
340
                                        col.setAttribute('space',str(3*shift)+'mm')
 
341
                                if line[f] != None:
 
342
                                        txt = new_doc.createTextNode(prefix+str(line[f]) or '')
 
343
                                else:
 
344
                                        txt = new_doc.createTextNode('/')
 
345
                                col.appendChild(txt)
 
346
                                node_line.appendChild(col)
 
347
                                prefix = ''
 
348
                        lines.appendChild(node_line)
 
349
                        
 
350
                new_doc.childNodes[0].appendChild(lines)
 
351
 
 
352
                styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
 
353
                style = libxslt.parseStylesheetDoc(styledoc)
 
354
                doc = libxml2.parseDoc(new_doc.toxml())
 
355
                rml_obj = style.applyStylesheet(doc, None)
 
356
                rml = style.saveResultToString(rml_obj) 
 
357
 
 
358
                self.obj = render.rml(rml)
 
359
                self.obj.render()
 
360
                return True
 
361
 
 
362
 
 
363
        def _create_lines(self, cr, uid, ids, report, fields, results, context):
 
364
                service = netsvc.LocalService("object_proxy")
 
365
                pdf_string = StringIO.StringIO()
 
366
                can = canvas.init(fname=pdf_string, format='pdf')
 
367
                
 
368
                can.show(80,380,'/16/H'+report['title'])
 
369
                
 
370
                ar = area.T(size=(350,350),
 
371
                #x_coord = category_coord.T(['2005-09-01','2005-10-22'],0),
 
372
                x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
 
373
                y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
 
374
                
 
375
                process_date = {}
 
376
                process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
 
377
                process_date['M'] = lambda x : x.split('-')[1]
 
378
                process_date['Y'] = lambda x : x.split('-')[0]
 
379
 
 
380
                order_date = {}
 
381
                order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
 
382
                order_date['M'] = lambda x : x
 
383
                order_date['Y'] = lambda x : x
 
384
 
 
385
                abscissa = []
 
386
                tmp = {}
 
387
                
 
388
                idx = 0 
 
389
                date_idx = None
 
390
                fct = {}
 
391
                for f in fields:
 
392
                        field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
 
393
                        if field_id:
 
394
                                type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
 
395
                                if type[0]['ttype'] == 'date':
 
396
                                        date_idx = idx
 
397
                                        fct[idx] = process_date[report['frequency']] 
 
398
                                else:
 
399
                                        fct[idx] = lambda x : x
 
400
                        else:
 
401
                                fct[idx] = lambda x : x
 
402
                        idx+=1
 
403
 
 
404
                # plots are usually displayed year by year
 
405
                # so we do so if the first field is a date
 
406
                data_by_year = {}
 
407
                if date_idx != None:
 
408
                        for r in results:
 
409
                                key = process_date['Y'](r[date_idx])
 
410
                                if not data_by_year.has_key(key):
 
411
                                        data_by_year[key] = []
 
412
                                for i in range(len(r)):
 
413
                                        r[i] = fct[i](r[i])
 
414
                                data_by_year[key].append(r)
 
415
                else:
 
416
                        data_by_year[''] = results
 
417
 
 
418
                idx0 = 0
 
419
                nb_bar = len(data_by_year)*(len(fields)-1)
 
420
                colors = map(lambda x:line_style.T(color=x), misc.choice_colors(nb_bar))
 
421
                abscissa = {}
 
422
                for line in data_by_year.keys():
 
423
                        fields_bar = []
 
424
                        # sum data and save it in a list. An item for a fields
 
425
                        for d in data_by_year[line]:
 
426
                                for idx in range(len(fields)-1):
 
427
                                        fields_bar.append({})
 
428
                                        if fields_bar[idx].has_key(d[0]):
 
429
                                                fields_bar[idx][d[0]] += d[idx+1]
 
430
                                        else:
 
431
                                                fields_bar[idx][d[0]] = d[idx+1]
 
432
                        for idx  in range(len(fields)-1):
 
433
                                data = {}
 
434
                                for k in fields_bar[idx].keys():
 
435
                                        if data.has_key(k):
 
436
                                                data[k] += fields_bar[idx][k]
 
437
                                        else:
 
438
                                                data[k] = fields_bar[idx][k]
 
439
                                data_cum = []
 
440
                                prev = 0.0
 
441
                                keys = data.keys()
 
442
                                keys.sort()
 
443
                                # cumulate if necessary
 
444
                                for k in keys:
 
445
                                        data_cum.append([k, float(data[k])+float(prev)])
 
446
                                        if fields[idx+1]['cumulate']:
 
447
                                                prev += data[k]
 
448
                                idx0 = 0
 
449
                                plot = line_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, line_style=colors[idx0*(len(fields)-1)+idx])
 
450
                                ar.add_plot(plot)
 
451
                                abscissa.update(fields_bar[idx])
 
452
                                idx0 += 1
 
453
                
 
454
                abscissa = map(lambda x : [x, None], abscissa)
 
455
                ar.x_coord = category_coord.T(abscissa,0)
 
456
                ar.draw(can)
 
457
 
 
458
                can.close()
 
459
                self.obj = external_pdf(pdf_string.getvalue())
 
460
                self.obj.render()
 
461
                pdf_string.close()
 
462
                return True
 
463
 
 
464
 
 
465
 
 
466
        def _create_bars(self, cr, uid, ids, report, fields, results, context):
 
467
                service = netsvc.LocalService("object_proxy")
 
468
                pdf_string = StringIO.StringIO()
 
469
                can = canvas.init(fname=pdf_string, format='pdf')
 
470
                
 
471
                can.show(80,380,'/16/H'+report['title'])
 
472
                
 
473
                process_date = {}
 
474
                process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
 
475
                process_date['M'] = lambda x : x.split('-')[1]
 
476
                process_date['Y'] = lambda x : x.split('-')[0]
 
477
 
 
478
                order_date = {}
 
479
                order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
 
480
                order_date['M'] = lambda x : x
 
481
                order_date['Y'] = lambda x : x
 
482
 
 
483
                ar = area.T(size=(350,350),
 
484
                        x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
 
485
                        y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
 
486
 
 
487
                idx = 0 
 
488
                date_idx = None
 
489
                fct = {}
 
490
                for f in fields:
 
491
                        field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
 
492
                        if field_id:
 
493
                                type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
 
494
                                if type[0]['ttype'] == 'date':
 
495
                                        date_idx = idx
 
496
                                        fct[idx] = process_date[report['frequency']] 
 
497
                                else:
 
498
                                        fct[idx] = lambda x : x
 
499
                        else:
 
500
                                fct[idx] = lambda x : x
 
501
                        idx+=1
 
502
                
 
503
                # plot are usually displayed year by year
 
504
                # so we do so if the first field is a date
 
505
                data_by_year = {}
 
506
                if date_idx != None:
 
507
                        for r in results:
 
508
                                key = process_date['Y'](r[date_idx])
 
509
                                if not data_by_year.has_key(key):
 
510
                                        data_by_year[key] = []
 
511
                                for i in range(len(r)):
 
512
                                        r[i] = fct[i](r[i])
 
513
                                data_by_year[key].append(r)
 
514
                else:
 
515
                        data_by_year[''] = results
 
516
 
 
517
 
 
518
                nb_bar = len(data_by_year)*(len(fields)-1)
 
519
                colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(nb_bar))
 
520
                
 
521
                abscissa = {}
 
522
                for line in data_by_year.keys():
 
523
                        fields_bar = []
 
524
                        # sum data and save it in a list. An item for a fields
 
525
                        for d in data_by_year[line]:
 
526
                                for idx in range(len(fields)-1):
 
527
                                        fields_bar.append({})
 
528
                                        if fields_bar[idx].has_key(d[0]):
 
529
                                                fields_bar[idx][d[0]] += d[idx+1]
 
530
                                        else:
 
531
                                                fields_bar[idx][d[0]] = d[idx+1]
 
532
                        for idx  in range(len(fields)-1):
 
533
                                data = {}
 
534
                                for k in fields_bar[idx].keys():
 
535
                                        if data.has_key(k):
 
536
                                                data[k] += fields_bar[idx][k]
 
537
                                        else:
 
538
                                                data[k] = fields_bar[idx][k]
 
539
                                data_cum = []
 
540
                                prev = 0.0
 
541
                                keys = data.keys()
 
542
                                keys.sort()
 
543
                                # cumulate if necessary
 
544
                                for k in keys:
 
545
                                        data_cum.append([k, float(data[k])+float(prev)])
 
546
                                        if fields[idx+1]['cumulate']:
 
547
                                                prev += data[k]
 
548
                                                
 
549
                                idx0 = 0
 
550
                                plot = bar_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, cluster=(idx0*(len(fields)-1)+idx,nb_bar), fill_style=colors[idx0*(len(fields)-1)+idx])
 
551
                                ar.add_plot(plot)
 
552
                                abscissa.update(fields_bar[idx])
 
553
                        idx0 += 1
 
554
                abscissa = map(lambda x : [x, None], abscissa)
 
555
                ar.x_coord = category_coord.T(abscissa,0)
 
556
                ar.draw(can)
 
557
 
 
558
                can.close()
 
559
                self.obj = external_pdf(pdf_string.getvalue())
 
560
                self.obj.render()
 
561
                pdf_string.close()
 
562
                return True
 
563
 
 
564
        def _create_pie(self, cr, uid, ids, report, fields, results, context):
 
565
                pdf_string = StringIO.StringIO()
 
566
                can = canvas.init(fname=pdf_string, format='pdf')
 
567
                ar = area.T(size=(350,350), legend=legend.T(),
 
568
                                        x_grid_style = None, y_grid_style = None)
 
569
                colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(len(results)))
 
570
 
 
571
                if reduce(lambda x,y : x+y, map(lambda x : x[1],results)) == 0.0:
 
572
                        raise('The sum of the data (2nd field) is null. \nWe can draw a pie chart !')
 
573
 
 
574
                plot = pie_plot.T(data=results, arc_offsets=[0,10,0,10],
 
575
                                                  shadow = (2, -2, fill_style.gray50),
 
576
                                                  label_offset = 25,
 
577
                                                  arrow_style = arrow.a3,
 
578
                                                  fill_styles=colors)
 
579
                ar.add_plot(plot)
 
580
                ar.draw(can)
 
581
                can.close()
 
582
                self.obj = external_pdf(pdf_string.getvalue())
 
583
                self.obj.render()
 
584
                pdf_string.close()
 
585
                return True
 
586
 
 
587
        def _create_table(self, uid, ids, report, fields, tree, results, context):
 
588
                pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
 
589
                if report['print_orientation']=='landscape':
 
590
                        pageSize=[pageSize[1],pageSize[0]]
 
591
 
 
592
                impl = minidom.getDOMImplementation()
 
593
                new_doc = impl.createDocument(None, "report", None)
 
594
                
 
595
                # build header
 
596
                config = new_doc.createElement("config")
 
597
 
 
598
                def _append_node(name, text):
 
599
                        n = new_doc.createElement(name)
 
600
                        t = new_doc.createTextNode(text)
 
601
                        n.appendChild(t)
 
602
                        config.appendChild(n)
 
603
 
 
604
                _append_node('date', time.strftime('%d/%m/%Y'))
 
605
                _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
 
606
                _append_node('PageFormat', '%s' % report['print_format'])
 
607
                _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
 
608
                _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
 
609
 
 
610
                length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
 
611
                count = 0
 
612
                for f in fields:
 
613
                        if not f['width']: count+=1
 
614
                for f in fields:
 
615
                        if not f['width']:
 
616
                                f['width']=round((float(length)/count)-0.5)
 
617
 
 
618
                _append_node('tableSize', '%s' %  ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
 
619
                _append_node('report-header', '%s' % (report['title'],))
 
620
                _append_node('report-footer', '%s' % (report['footer'],))
 
621
 
 
622
                new_doc.childNodes[0].appendChild(config)
 
623
                header = new_doc.createElement("header")
 
624
                
 
625
                for f in fields:
 
626
                        field = new_doc.createElement("field")
 
627
                        field_txt = new_doc.createTextNode('%s' % (f['name'],))
 
628
                        field.appendChild(field_txt)
 
629
                        header.appendChild(field)
 
630
                
 
631
                new_doc.childNodes[0].appendChild(header)
 
632
 
 
633
                lines = new_doc.createElement("lines")
 
634
                for line in results:
 
635
                        node_line = new_doc.createElement("row")
 
636
                        for f in range(len(fields)):
 
637
                                col = new_doc.createElement("col")
 
638
                                col.setAttribute('tree','no')
 
639
                                if line[f] != None:
 
640
                                        txt = new_doc.createTextNode(str(line[f] or ''))
 
641
                                else:
 
642
                                        txt = new_doc.createTextNode('/')
 
643
                                col.appendChild(txt)
 
644
                                node_line.appendChild(col)
 
645
                        lines.appendChild(node_line)    
 
646
                        
 
647
                new_doc.childNodes[0].appendChild(lines)
 
648
 
 
649
#               file('/tmp/terp.xml','w+').write(new_doc.toxml())
 
650
 
 
651
                styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
 
652
                style = libxslt.parseStylesheetDoc(styledoc)
 
653
                doc = libxml2.parseDoc(new_doc.toxml())
 
654
                rml_obj = style.applyStylesheet(doc, None)
 
655
                rml = style.saveResultToString(rml_obj) 
 
656
 
 
657
                self.obj = render.rml(rml)
 
658
                self.obj.render()
 
659
                return True
 
660
report_custom('report.custom')
 
661