[FIX] Report: get the wkhtmltopdf version in a cleaner way with a simple regex
[odoo/odoo.git] / openerp / report / printscreen / ps_list.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 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 openerp
23 from openerp.report.interface import report_int
24 import openerp.tools as tools
25 from openerp.tools.safe_eval import safe_eval as eval
26 from lxml  import etree
27 from openerp.report import render, report_sxw
28 import locale
29
30 import time, os
31 from operator import itemgetter
32 from datetime import datetime
33
34
35 class report_printscreen_list(report_int):
36     def __init__(self, name):
37         report_int.__init__(self, name)
38         self.context = {}
39         self.groupby = []
40         self.cr=''
41
42     def _parse_node(self, root_node):
43         result = []
44         for node in root_node:
45             field_name = node.get('name')
46             if not eval(str(node.attrib.get('invisible',False)),{'context':self.context}):
47                 if node.tag == 'field':
48                     if field_name in self.groupby:
49                         continue
50                     result.append(field_name)
51                 else:
52                     result.extend(self._parse_node(node))
53         return result
54
55     def _parse_string(self, view):
56         try:
57             dom = etree.XML(view.encode('utf-8'))
58         except Exception:
59             dom = etree.XML(view)
60         return self._parse_node(dom)
61
62     def create(self, cr, uid, ids, datas, context=None):
63         if not context:
64             context={}
65         self.cr=cr
66         self.context = context
67         self.groupby = context.get('group_by',[])
68         self.groupby_no_leaf = context.get('group_by_no_leaf',False)
69         registry = openerp.registry(cr.dbname)
70         model = registry[datas['model']]
71         model_id = registry['ir.model'].search(cr, uid, [('model','=',model._name)])
72         model_desc = model._description
73         if model_id:
74             model_desc = registry['ir.model'].browse(cr, uid, model_id[0], context).name
75         self.title = model_desc
76         datas['ids'] = ids
77         result = model.fields_view_get(cr, uid, view_type='tree', context=context)
78         fields_order =  self.groupby + self._parse_string(result['arch'])
79         if self.groupby:
80             rows = []
81             def get_groupby_data(groupby = [], domain = []):
82                 records =  model.read_group(cr, uid, domain, fields_order, groupby , 0, None, context)
83                 for rec in records:
84                     rec['__group'] = True
85                     rec['__no_leaf'] = self.groupby_no_leaf
86                     rec['__grouped_by'] = groupby[0] if (isinstance(groupby, list) and groupby) else groupby
87                     for f in fields_order:
88                         if f not in rec:
89                             rec.update({f:False})
90                         elif isinstance(rec[f], tuple):
91                             rec[f] = rec[f][1]
92                     rows.append(rec)
93                     inner_groupby = (rec.get('__context', {})).get('group_by',[])
94                     inner_domain = rec.get('__domain', [])
95                     if inner_groupby:
96                         get_groupby_data(inner_groupby, inner_domain)
97                     else:
98                         if self.groupby_no_leaf:
99                             continue
100                         child_ids = model.search(cr, uid, inner_domain)
101                         res = model.read(cr, uid, child_ids, result['fields'].keys(), context)
102                         res.sort(lambda x,y: cmp(ids.index(x['id']), ids.index(y['id'])))
103                         rows.extend(res)
104             dom = [('id','in',ids)]
105             if self.groupby_no_leaf and len(ids) and not ids[0]:
106                 dom = datas.get('_domain',[])
107             get_groupby_data(self.groupby, dom)
108         else:
109             rows = model.read(cr, uid, datas['ids'], result['fields'].keys(), context)
110             ids2 = map(itemgetter('id'), rows) # getting the ids from read result
111             if datas['ids'] != ids2: # sorted ids were not taken into consideration for print screen
112                 rows_new = []
113                 for id in datas['ids']:
114                     rows_new += [elem for elem in rows if elem['id'] == id]
115                 rows = rows_new
116         res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model_desc)
117         return self.obj.get(), 'pdf'
118
119
120     def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
121         pageSize=[297.0, 210.0]
122
123         new_doc = etree.Element("report")
124         config = etree.SubElement(new_doc, 'config')
125
126         def _append_node(name, text):
127             n = etree.SubElement(config, name)
128             n.text = text
129
130         #_append_node('date', time.strftime('%d/%m/%Y'))
131         _append_node('date', time.strftime(str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'))))
132         _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
133         _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
134         _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
135         _append_node('report-header', title)
136
137         registry = openerp.registry(self.cr.dbname)
138         _append_node('company', registry['res.users'].browse(self.cr,uid,uid).company_id.name)
139         rpt_obj = registry['res.users']
140         rml_obj=report_sxw.rml_parse(self.cr, uid, rpt_obj._name,context)
141         _append_node('header-date', str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")))
142         l = []
143         t = 0
144         strmax = (pageSize[0]-40) * 2.8346
145         temp = []
146         tsum = []
147         for i in range(0, len(fields_order)):
148             temp.append(0)
149             tsum.append(0)
150         ince = -1
151         for f in fields_order:
152             s = 0
153             ince += 1
154             if fields[f]['type'] in ('date','time','datetime','float','integer'):
155                 s = 60
156                 strmax -= s
157                 if fields[f]['type'] in ('float','integer'):
158                     temp[ince] = 1
159             else:
160                 t += fields[f].get('size', 80) / 28 + 1
161
162             l.append(s)
163         for pos in range(len(l)):
164             if not l[pos]:
165                 s = fields[fields_order[pos]].get('size', 80) / 28 + 1
166                 l[pos] = strmax * s / t
167
168         _append_node('tableSize', ','.join(map(str,l)) )
169
170         header = etree.SubElement(new_doc, 'header')
171         for f in fields_order:
172             field = etree.SubElement(header, 'field')
173             field.text = tools.ustr(fields[f]['string'] or '')
174
175         lines = etree.SubElement(new_doc, 'lines')
176         for line in results:
177             node_line = etree.SubElement(lines, 'row')
178             count = -1
179             for f in fields_order:
180                 float_flag = 0
181                 count += 1
182                 if fields[f]['type']=='many2one' and line[f]:
183                     if not line.get('__group'):
184                         line[f] = line[f][1]
185                 if fields[f]['type']=='selection' and line[f]:
186                     for key, value in fields[f]['selection']:
187                         if key == line[f]:
188                             line[f] = value
189                             break
190                 if fields[f]['type'] in ('one2many','many2many') and line[f]:
191                     line[f] = '( '+tools.ustr(len(line[f])) + ' )'
192                 if fields[f]['type'] == 'float' and line[f]:
193                     precision=(('digits' in fields[f]) and fields[f]['digits'][1]) or 2
194                     prec ='%.' + str(precision) +'f'
195                     line[f]=prec%(line[f])
196                     float_flag = 1
197
198                 if fields[f]['type'] == 'date' and line[f]:
199                     new_d1 = line[f]
200                     if not line.get('__group'):
201                         format = str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'))
202                         d1 = datetime.strptime(line[f],'%Y-%m-%d')
203                         new_d1 = d1.strftime(format)
204                     line[f] = new_d1
205
206                 if fields[f]['type'] == 'time' and line[f]:
207                     new_d1 = line[f]
208                     if not line.get('__group'):
209                         format = str(locale.nl_langinfo(locale.T_FMT))
210                         d1 = datetime.strptime(line[f], '%H:%M:%S')
211                         new_d1 = d1.strftime(format)
212                     line[f] = new_d1
213
214                 if fields[f]['type'] == 'datetime' and line[f]:
215                     new_d1 = line[f]
216                     if not line.get('__group'):
217                         format = str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'))+' '+str(locale.nl_langinfo(locale.T_FMT))
218                         d1 = datetime.strptime(line[f], '%Y-%m-%d %H:%M:%S')
219                         new_d1 = d1.strftime(format)
220                     line[f] = new_d1
221
222
223                 if line.get('__group'):
224                     col = etree.SubElement(node_line, 'col', para='group', tree='no')
225                 else:
226                     col = etree.SubElement(node_line, 'col', para='yes', tree='no')
227
228                 # Prevent empty labels in groups
229                 if f == line.get('__grouped_by') and line.get('__group') and not line[f] and not float_flag and not temp[count]:
230                     col.text = line[f] = 'Undefined'
231                     col.set('tree', 'undefined')
232
233                 if line[f] is not None:
234                     col.text = tools.ustr(line[f] or '')
235                     if float_flag:
236                         col.set('tree','float')
237                     if line.get('__no_leaf') and temp[count] == 1 and f != 'id' and not line['__context']['group_by']:
238                         tsum[count] = float(tsum[count]) + float(line[f])
239                     if not line.get('__group') and f != 'id' and temp[count] == 1:
240                         tsum[count] = float(tsum[count])  + float(line[f])
241                 else:
242                     col.text = '/'
243
244         node_line = etree.SubElement(lines, 'row')
245         for f in range(0, len(fields_order)):
246             col = etree.SubElement(node_line, 'col', para='group', tree='no')
247             col.set('tree', 'float')
248             if tsum[f] is not None:
249                 if tsum[f] != 0.0:
250                     digits = fields[fields_order[f]].get('digits', (16, 2))
251                     prec = '%%.%sf' % (digits[1], )
252                     total = prec % (tsum[f], )
253                     txt = str(total or '')
254                 else:
255                     txt = str(tsum[f] or '')
256             else:
257                 txt = '/'
258             if f == 0:
259                 txt ='Total'
260                 col.set('tree','no')
261             col.text = tools.ustr(txt or '')
262
263         transform = etree.XSLT(
264             etree.parse(os.path.join(tools.config['root_path'],
265                                      'addons/base/report/custom_new.xsl')))
266         rml = etree.tostring(transform(new_doc))
267         self.obj = render.rml(rml, title=self.title)
268         self.obj.render()
269         return True
270 report_printscreen_list('report.printscreen.list')
271
272
273 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: