1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
7 # Author : Nicolas Bessi (Camptocamp)
9 # WARNING: This program as such is intended to be used by professional
10 # programmers who take the whole responsability of assessing all potential
11 # consequences resulting from its eventual inadequacies and bugs
12 # End users who are looking for a ready-to-use solution with commercial
13 # garantees and support are strongly adviced to contract a Free Software
16 # This program is Free Software; you can redistribute it and/or
17 # modify it under the terms of the GNU General Public License
18 # as published by the Free Software Foundation; either version 2
19 # of the License, or (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 ##############################################################################
37 from mako.template import Template
41 from report_helper import WebKitHelper
42 from report.report_sxw import *
44 from tools.translate import _
45 from osv.osv import except_osv
47 class WebKitParser(report_sxw):
48 """Custom class that use webkit to render HTML reports
49 Code partially taken from report openoffice. Thanks guys :)
52 def __init__(self, name, table, rml=False, parser=False,
53 header=True, store=False):
54 self.parser_instance = False
56 report_sxw.__init__(self, name, table, rml, parser,
59 def get_lib(self, cursor, uid, company) :
60 """Return the lib wkhtml path"""
61 #TODO Detect lib in system first
62 path = self.pool.get('res.company').read(cursor, uid, company, ['lib_path',])
63 path = path['lib_path']
66 _('Wkhtmltopdf library path is not set in company'),
67 _('Please install executable on your system'+
68 ' (sudo apt-get install wkhtmltopdf) or download it from here:'+
69 ' http://code.google.com/p/wkhtmltopdf/downloads/list and set the'+
70 ' path to the executable on the Company form.')
72 if os.path.isabs(path) :
73 if (os.path.exists(path) and os.access(path, os.X_OK)\
74 and os.path.basename(path).startswith('wkhtmltopdf')):
78 _('Wrong Wkhtmltopdf path set in company'+
79 'Given path is not executable or path is wrong'),
84 _('path to Wkhtmltopdf is not absolute'),
87 def generate_pdf(self, comm_path, report_xml, header, footer, html_list):
88 """Call webkit in order to generate pdf"""
89 tmp_dir = tempfile.gettempdir()
90 out = report_xml.name+str(time.time())+'.pdf'
91 out = os.path.join(tmp_dir, out.replace(' ',''))
97 command = ['wkhtmltopdf']
101 head_file = file( os.path.join(
103 str(time.time()) + '.head.html'
107 head_file.write(header)
109 file_to_del.append(head_file.name)
110 command.append("--header-html '%s'"%(head_file.name))
112 foot_file = file( os.path.join(
114 str(time.time()) + '.foot.html'
118 foot_file.write(footer)
120 file_to_del.append(foot_file.name)
121 command.append("--footer-html '%s'"%(foot_file.name))
123 if report_xml.webkit_header.margin_top :
124 command.append('--margin-top %s'%(report_xml.webkit_header.margin_top))
125 if report_xml.webkit_header.margin_bottom :
126 command.append('--margin-bottom %s'%(report_xml.webkit_header.margin_bottom))
127 if report_xml.webkit_header.margin_left :
128 command.append('--margin-left %s'%(report_xml.webkit_header.margin_left))
129 if report_xml.webkit_header.margin_right :
130 command.append('--margin-right %s'%(report_xml.webkit_header.margin_right))
131 if report_xml.webkit_header.orientation :
132 command.append("--orientation '%s'"%(report_xml.webkit_header.orientation))
133 if report_xml.webkit_header.format :
134 command.append(" --page-size '%s'"%(report_xml.webkit_header.format))
135 for html in html_list :
136 html_file = file(os.path.join(tmp_dir, str(time.time()) + '.body.html'), 'w')
137 html_file.write(html)
139 file_to_del.append(html_file.name)
140 command.append(html_file.name)
142 generate_command = ' '.join(command)
144 status = commands.getstatusoutput(generate_command)
147 _('Webkit raise an error' ),
151 for f_to_del in file_to_del :
154 pdf = file(out).read()
155 for f_to_del in file_to_del :
162 def setLang(self, lang):
165 self.localcontext['lang'] = lang
167 def translate_call(self, src):
168 """Translate String."""
169 ir_translation = self.pool.get('ir.translation')
170 res = ir_translation._get_source(self.parser_instance.cr, self.parser_instance.uid, self.name, 'report', self.localcontext.get('lang', 'en_US'), src)
173 def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False):
174 """format using the know cursor, language from localcontext"""
176 digits = self.parser_instance.get_digits(value)
177 if isinstance(value, (str, unicode)) and not value:
179 pool_lang = self.pool.get('res.lang')
180 lang = self.localcontext['lang']
182 lang_ids = pool_lang.search(self.parser_instance.cr, self.parser_instance.uid, [('code','=',lang)])[0]
183 lang_obj = pool_lang.browse(self.parser_instance.cr, self.parser_instance.uid, lang_ids)
185 if date or date_time:
189 date_format = lang_obj.date_format
190 parse_format = '%Y-%m-%d'
192 value=value.split('.')[0]
193 date_format = date_format + " " + lang_obj.time_format
194 parse_format = '%Y-%m-%d %H:%M:%S'
195 if not isinstance(value, time.struct_time):
196 return time.strftime(date_format, time.strptime(value, parse_format))
199 date = datetime(*value.timetuple()[:6])
200 return date.strftime(date_format)
202 return lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
204 # override needed to keep the attachments' storing procedure
205 def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
206 """generate the PDF"""
211 if report_xml.report_type != 'webkit':
212 return super(WebKitParser,self).create_single_pdf(cursor, uid, ids, data, report_xml, context=context)
214 self.parser_instance = self.parser(
221 self.pool = pooler.get_pool(cursor.dbname)
222 objs = self.getObjects(cursor, uid, ids, context)
223 self.parser_instance.set_context(objs, data, ids, report_xml.report_type)
227 if report_xml.report_file :
228 path = addons.get_module_resource(report_xml.report_file)
229 if os.path.exists(path) :
230 template = file(path).read()
231 if not template and report_xml.report_webkit_data :
232 template = report_xml.report_webkit_data
234 raise except_osv(_('Webkit Report template not found !'), _(''))
235 header = report_xml.webkit_header.html
236 footer = report_xml.webkit_header.footer_html
237 if not header and report_xml.header:
239 _('No header defined for this Webkit report!'),
240 _('Please set a header in company settings')
242 if not report_xml.header :
243 #I know it could be cleaner ...
247 <style type="text/css">
253 var x=document.location.search.substring(1).split('&');
254 for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
255 var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
257 var y = document.getElementsByClassName(x[i]);
258 for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
263 <body style="border:0; margin: 0;" onload="subst()">
266 css = report_xml.webkit_header.css
269 user = self.pool.get('res.users').browse(cursor, uid, uid)
270 company= user.company_id
272 #default_filters=['unicode', 'entity'] can be used to set global filter
273 body_mako_tpl = Template(template ,input_encoding='utf-8')
274 helper = WebKitHelper(cursor, uid, report_xml.id, context)
275 html = body_mako_tpl.render( helper=helper,
277 _=self.translate_call,
278 **self.parser_instance.localcontext
280 head_mako_tpl = Template(header, input_encoding='utf-8')
281 head = head_mako_tpl.render(
286 formatLang=self.formatLang,
287 setLang=self.setLang,
288 _=self.translate_call,
293 foot_mako_tpl = Template(footer ,input_encoding='utf-8')
294 foot = foot_mako_tpl.render(
299 formatLang=self.formatLang,
300 setLang=self.setLang,
301 _=self.translate_call,
303 if report_xml.webkit_debug :
304 deb = head_mako_tpl.render(
310 formatLang=self.formatLang,
311 setLang=self.setLang,
312 _=self.translate_call,
315 bin = self.get_lib(cursor, uid, company.id)
316 pdf = self.generate_pdf(bin, report_xml, head, foot, [html])
320 def create(self, cursor, uid, ids, data, context=None):
321 """We override the create function in order to handle generator
322 Code taken from report openoffice. Thanks guys :) """
323 pool = pooler.get_pool(cursor.dbname)
324 ir_obj = pool.get('ir.actions.report.xml')
325 report_xml_ids = ir_obj.search(cursor, uid,
326 [('report_name', '=', self.name[7:])], context=context)
329 report_xml = ir_obj.browse(
335 report_xml.report_rml = None
336 report_xml.report_rml_content = None
337 report_xml.report_sxw_content_data = None
338 report_rml.report_sxw_content = None
339 report_rml.report_sxw = None
341 return super(WebKitParser, self).create(cursor, uid, ids, data, context)
342 if report_xml.report_type != 'webkit' :
343 return super(WebKitParser, self).create(cursor, uid, ids, data, context)
344 result = self.create_source_pdf(cursor, uid, ids, data, report_xml, context)