1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
6 # Author: Guewen Baconnier (Camptocamp)
8 # WARNING: This program as such is intended to be used by professional
9 # programmers who take the whole responsability of assessing all potential
10 # consequences resulting from its eventual inadequacies and bugs
11 # End users who are looking for a ready-to-use solution with commercial
12 # garantees and support are strongly adviced to contract a Free Software
15 # This program is Free Software; you can redistribute it and/or
16 # modify it under the terms of the GNU General Public License
17 # as published by the Free Software Foundation; either version 2
18 # of the License, or (at your option) any later version.
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 ##############################################################################
34 from functools
import partial
37 from mako
import exceptions
38 from openerp
.osv
.osv
import except_osv
39 from openerp
.tools
.translate
import _
40 from openerp
import addons
41 from openerp
import pooler
42 from openerp
import tools
43 from openerp
.addons
.report_webkit
import webkit_report
44 from openerp
.addons
.report_webkit
.report_helper
import WebKitHelper
46 _logger
= logging
.getLogger('financial.reports.webkit')
48 # Class used only as a workaround to bug:
49 # http://code.google.com/p/wkhtmltopdf/issues/detail?id=656
51 # html headers and footers do not work on big files (hundreds of pages) so we
52 # replace them by text headers and footers passed as arguments to wkhtmltopdf
53 # this class has to be removed once the bug is fixed
55 # in your report class, to print headers and footers as text, you have to add
56 # them in the localcontext with a key 'additional_args'
58 # header_report_name = _('PARTNER LEDGER')
59 # footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
60 # self.localcontext.update({
61 # 'additional_args': [
62 # ('--header-font-name', 'Helvetica'),
63 # ('--footer-font-name', 'Helvetica'),
64 # ('--header-font-size', '10'),
65 # ('--footer-font-size', '7'),
66 # ('--header-left', header_report_name),
67 # ('--footer-left', footer_date_time),
68 # ('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
74 # redefine mako_template as this is overriden by jinja since saas-1
75 # from openerp.addons.report_webkit.webkit_report import mako_template
76 from mako
.template
import Template
77 from mako
.lookup
import TemplateLookup
80 def mako_template(text
):
81 """Build a Mako template.
83 This template uses UTF-8 encoding
85 tmp_lookup
= TemplateLookup() # we need it in order to allow inclusion and inheritance
86 return Template(text
, input_encoding
='utf-8', output_encoding
='utf-8', lookup
=tmp_lookup
)
89 class HeaderFooterTextWebKitParser(webkit_report
.WebKitParser
):
91 def generate_pdf(self
, comm_path
, report_xml
, header
, footer
, html_list
,
92 webkit_header
=False, parser_instance
=False):
93 """Call webkit in order to generate pdf"""
95 webkit_header
= report_xml
.webkit_header
96 fd
, out_filename
= tempfile
.mkstemp(suffix
=".pdf",
98 file_to_del
= [out_filename
]
100 command
= [comm_path
]
102 command
= ['wkhtmltopdf']
104 command
.append('--quiet')
105 # default to UTF-8 encoding. Use <meta charset="latin-1"> to override.
106 command
.extend(['--encoding', 'utf-8'])
108 if webkit_header
.margin_top
:
109 command
.extend(['--margin-top', str(webkit_header
.margin_top
).replace(',', '.')])
110 if webkit_header
.margin_bottom
:
111 command
.extend(['--margin-bottom', str(webkit_header
.margin_bottom
).replace(',', '.')])
112 if webkit_header
.margin_left
:
113 command
.extend(['--margin-left', str(webkit_header
.margin_left
).replace(',', '.')])
114 if webkit_header
.margin_right
:
115 command
.extend(['--margin-right', str(webkit_header
.margin_right
).replace(',', '.')])
116 if webkit_header
.orientation
:
117 command
.extend(['--orientation', str(webkit_header
.orientation
).replace(',', '.')])
118 if webkit_header
.format
:
119 command
.extend(['--page-size', str(webkit_header
.format
).replace(',', '.')])
121 if parser_instance
.localcontext
.get('additional_args', False):
122 for arg
in parser_instance
.localcontext
['additional_args']:
126 for html
in html_list
:
127 with tempfile
.NamedTemporaryFile(suffix
="%d.body.html" % count
,
128 delete
=False) as html_file
:
130 html_file
.write(self
._sanitize
_html
(html
))
131 file_to_del
.append(html_file
.name
)
132 command
.append(html_file
.name
)
133 command
.append(out_filename
)
134 stderr_fd
, stderr_path
= tempfile
.mkstemp(text
=True)
135 file_to_del
.append(stderr_path
)
137 status
= subprocess
.call(command
, stderr
=stderr_fd
)
138 os
.close(stderr_fd
) # ensure flush before reading
139 stderr_fd
= None # avoid closing again in finally block
140 fobj
= open(stderr_path
, 'r')
141 error_message
= fobj
.read()
143 if not error_message
:
144 error_message
= _('No diagnosis message was provided')
146 error_message
= _('The following diagnosis message was provided:\n') + error_message
148 raise except_osv(_('Webkit error'),
149 _("The command 'wkhtmltopdf' failed with error code = %s. Message: %s") % (status
, error_message
))
150 with
open(out_filename
, 'rb') as pdf_file
:
151 pdf
= pdf_file
.read()
154 if stderr_fd
is not None:
156 for f_to_del
in file_to_del
:
159 except (OSError, IOError), exc
:
160 _logger
.error('cannot remove file %s: %s', f_to_del
, exc
)
163 # override needed to keep the attachments' storing procedure
164 def create_single_pdf(self
, cursor
, uid
, ids
, data
, report_xml
, context
=None):
165 """generate the PDF"""
170 if report_xml
.report_type
!= 'webkit':
171 return super(HeaderFooterTextWebKitParser
, self
172 ).create_single_pdf(cursor
, uid
, ids
, data
,
173 report_xml
, context
=context
)
175 parser_instance
= self
.parser(cursor
,
180 self
.pool
= pooler
.get_pool(cursor
.dbname
)
181 objs
= self
.getObjects(cursor
, uid
, ids
, context
)
182 parser_instance
.set_context(objs
, data
, ids
, report_xml
.report_type
)
186 if report_xml
.report_file
:
187 path
= addons
.get_module_resource(*report_xml
.report_file
.split(os
.path
.sep
))
188 if os
.path
.exists(path
):
189 template
= file(path
).read()
190 if not template
and report_xml
.report_webkit_data
:
191 template
= report_xml
.report_webkit_data
193 raise except_osv(_('Error!'), _('Webkit Report template not found !'))
194 header
= report_xml
.webkit_header
.html
196 if not header
and report_xml
.header
:
198 _('No header defined for this Webkit report!'),
199 _('Please set a header in company settings.')
202 css
= report_xml
.webkit_header
.css
206 translate_call
= partial(self
.translate_call
, parser_instance
)
207 #default_filters=['unicode', 'entity'] can be used to set global filter
208 body_mako_tpl
= mako_template(template
)
209 helper
= WebKitHelper(cursor
, uid
, report_xml
.id, context
)
210 if report_xml
.precise_mode
:
212 parser_instance
.localcontext
['objects'] = [obj
]
214 html
= body_mako_tpl
.render(helper
=helper
,
217 **parser_instance
.localcontext
)
220 msg
= exceptions
.text_error_template().render()
222 raise except_osv(_('Webkit render'), msg
)
225 html
= body_mako_tpl
.render(helper
=helper
,
228 **parser_instance
.localcontext
)
231 msg
= exceptions
.text_error_template().render()
233 raise except_osv(_('Webkit render'), msg
)
235 # NO html footer and header because we write them as text with
239 if report_xml
.webkit_debug
:
241 deb
= body_mako_tpl
.render(helper
=helper
,
243 _debug
=tools
.ustr("\n".join(htmls
)),
245 **parser_instance
.localcontext
)
247 msg
= exceptions
.text_error_template().render()
249 raise except_osv(_('Webkit render'), msg
)
251 bin
= self
.get_lib(cursor
, uid
)
252 pdf
= self
.generate_pdf(bin
, report_xml
, head
, foot
, htmls
,
253 parser_instance
=parser_instance
)