|
|
@ -30,8 +30,8 @@ |
|
|
|
import os |
|
|
|
import subprocess |
|
|
|
import tempfile |
|
|
|
import time |
|
|
|
import logging |
|
|
|
from functools import partial |
|
|
|
|
|
|
|
|
|
|
|
from mako import exceptions |
|
|
@ -48,11 +48,12 @@ _logger = logging.getLogger('financial.reports.webkit') |
|
|
|
# Class used only as a workaround to bug: |
|
|
|
# http://code.google.com/p/wkhtmltopdf/issues/detail?id=656 |
|
|
|
|
|
|
|
# html headers and footers do not work on big files (hundreds of pages) so we replace them by |
|
|
|
# text headers and footers passed as arguments to wkhtmltopdf |
|
|
|
# html headers and footers do not work on big files (hundreds of pages) so we |
|
|
|
# replace them by text headers and footers passed as arguments to wkhtmltopdf |
|
|
|
# this class has to be removed once the bug is fixed |
|
|
|
|
|
|
|
# in your report class, to print headers and footers as text, you have to add them in the localcontext with a key 'additional_args' |
|
|
|
# in your report class, to print headers and footers as text, you have to add |
|
|
|
# them in the localcontext with a key 'additional_args' |
|
|
|
# for instance: |
|
|
|
# header_report_name = _('PARTNER LEDGER') |
|
|
|
# footer_date_time = self.formatLang(str(datetime.today()), date_time=True) |
|
|
@ -75,23 +76,25 @@ _logger = logging.getLogger('financial.reports.webkit') |
|
|
|
from mako.template import Template |
|
|
|
from mako.lookup import TemplateLookup |
|
|
|
|
|
|
|
|
|
|
|
def mako_template(text): |
|
|
|
"""Build a Mako template. |
|
|
|
|
|
|
|
This template uses UTF-8 encoding |
|
|
|
""" |
|
|
|
tmp_lookup = TemplateLookup() #we need it in order to allow inclusion and inheritance |
|
|
|
tmp_lookup = TemplateLookup() # we need it in order to allow inclusion and inheritance |
|
|
|
return Template(text, input_encoding='utf-8', output_encoding='utf-8', lookup=tmp_lookup) |
|
|
|
|
|
|
|
|
|
|
|
class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
|
|
|
|
def generate_pdf(self, comm_path, report_xml, header, footer, html_list, webkit_header=False): |
|
|
|
def generate_pdf(self, comm_path, report_xml, header, footer, html_list, |
|
|
|
webkit_header=False, parser_instance=False): |
|
|
|
"""Call webkit in order to generate pdf""" |
|
|
|
if not webkit_header: |
|
|
|
webkit_header = report_xml.webkit_header |
|
|
|
tmp_dir = tempfile.gettempdir() |
|
|
|
out_filename = tempfile.mktemp(suffix=".pdf", prefix="webkit.tmp.") |
|
|
|
fd, out_filename = tempfile.mkstemp(suffix=".pdf", |
|
|
|
prefix="webkit.tmp.") |
|
|
|
file_to_del = [out_filename] |
|
|
|
if comm_path: |
|
|
|
command = [comm_path] |
|
|
@ -115,16 +118,16 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
if webkit_header.format: |
|
|
|
command.extend(['--page-size', str(webkit_header.format).replace(',', '.')]) |
|
|
|
|
|
|
|
if self.parser_instance.localcontext.get('additional_args', False): |
|
|
|
for arg in self.parser_instance.localcontext['additional_args']: |
|
|
|
if parser_instance.localcontext.get('additional_args', False): |
|
|
|
for arg in parser_instance.localcontext['additional_args']: |
|
|
|
command.extend(arg) |
|
|
|
|
|
|
|
count = 0 |
|
|
|
for html in html_list: |
|
|
|
html_file = file(os.path.join(tmp_dir, str(time.time()) + str(count) +'.body.html'), 'w') |
|
|
|
count += 1 |
|
|
|
html_file.write(html) |
|
|
|
html_file.close() |
|
|
|
with tempfile.NamedTemporaryFile(suffix="%d.body.html" % count, |
|
|
|
delete=False) as html_file: |
|
|
|
count += 1 |
|
|
|
html_file.write(self._sanitize_html(html)) |
|
|
|
file_to_del.append(html_file.name) |
|
|
|
command.append(html_file.name) |
|
|
|
command.append(out_filename) |
|
|
@ -132,8 +135,8 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
file_to_del.append(stderr_path) |
|
|
|
try: |
|
|
|
status = subprocess.call(command, stderr=stderr_fd) |
|
|
|
os.close(stderr_fd) # ensure flush before reading |
|
|
|
stderr_fd = None # avoid closing again in finally block |
|
|
|
os.close(stderr_fd) # ensure flush before reading |
|
|
|
stderr_fd = None # avoid closing again in finally block |
|
|
|
fobj = open(stderr_path, 'r') |
|
|
|
error_message = fobj.read() |
|
|
|
fobj.close() |
|
|
@ -142,11 +145,11 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
else: |
|
|
|
error_message = _('The following diagnosis message was provided:\n') + error_message |
|
|
|
if status: |
|
|
|
raise except_osv(_('Webkit error' ), |
|
|
|
raise except_osv(_('Webkit error'), |
|
|
|
_("The command 'wkhtmltopdf' failed with error code = %s. Message: %s") % (status, error_message)) |
|
|
|
pdf_file = open(out_filename, 'rb') |
|
|
|
pdf = pdf_file.read() |
|
|
|
pdf_file.close() |
|
|
|
with open(out_filename, 'rb') as pdf_file: |
|
|
|
pdf = pdf_file.read() |
|
|
|
os.close(fd) |
|
|
|
finally: |
|
|
|
if stderr_fd is not None: |
|
|
|
os.close(stderr_fd) |
|
|
@ -160,57 +163,60 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
# override needed to keep the attachments' storing procedure |
|
|
|
def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None): |
|
|
|
"""generate the PDF""" |
|
|
|
|
|
|
|
if context is None: |
|
|
|
context={} |
|
|
|
context = {} |
|
|
|
htmls = [] |
|
|
|
if report_xml.report_type != 'webkit': |
|
|
|
return super(HeaderFooterTextWebKitParser,self).create_single_pdf(cursor, uid, ids, data, report_xml, context=context) |
|
|
|
return super(HeaderFooterTextWebKitParser, self |
|
|
|
).create_single_pdf(cursor, uid, ids, data, |
|
|
|
report_xml, context=context) |
|
|
|
|
|
|
|
self.parser_instance = self.parser(cursor, |
|
|
|
uid, |
|
|
|
self.name2, |
|
|
|
context=context) |
|
|
|
parser_instance = self.parser(cursor, |
|
|
|
uid, |
|
|
|
self.name2, |
|
|
|
context=context) |
|
|
|
|
|
|
|
self.pool = pooler.get_pool(cursor.dbname) |
|
|
|
objs = self.getObjects(cursor, uid, ids, context) |
|
|
|
self.parser_instance.set_context(objs, data, ids, report_xml.report_type) |
|
|
|
parser_instance.set_context(objs, data, ids, report_xml.report_type) |
|
|
|
|
|
|
|
template = False |
|
|
|
template = False |
|
|
|
|
|
|
|
if report_xml.report_file: |
|
|
|
path = addons.get_module_resource(*report_xml.report_file.split(os.path.sep)) |
|
|
|
if os.path.exists(path): |
|
|
|
template = file(path).read() |
|
|
|
if not template and report_xml.report_webkit_data: |
|
|
|
template = report_xml.report_webkit_data |
|
|
|
template = report_xml.report_webkit_data |
|
|
|
if not template: |
|
|
|
raise except_osv(_('Error!'), _('Webkit Report template not found !')) |
|
|
|
header = report_xml.webkit_header.html |
|
|
|
footer = report_xml.webkit_header.footer_html |
|
|
|
|
|
|
|
if not header and report_xml.header: |
|
|
|
raise except_osv( |
|
|
|
_('No header defined for this Webkit report!'), |
|
|
|
_('Please set a header in company settings') |
|
|
|
_('Please set a header in company settings.') |
|
|
|
) |
|
|
|
|
|
|
|
css = report_xml.webkit_header.css |
|
|
|
if not css: |
|
|
|
css = '' |
|
|
|
user = self.pool.get('res.users').browse(cursor, uid, uid) |
|
|
|
|
|
|
|
translate_call = partial(self.translate_call, parser_instance) |
|
|
|
#default_filters=['unicode', 'entity'] can be used to set global filter |
|
|
|
body_mako_tpl = mako_template(template) |
|
|
|
helper = WebKitHelper(cursor, uid, report_xml.id, context) |
|
|
|
if report_xml.precise_mode: |
|
|
|
for obj in objs: |
|
|
|
self.parser_instance.localcontext['objects'] = [obj] |
|
|
|
parser_instance.localcontext['objects'] = [obj] |
|
|
|
try: |
|
|
|
html = body_mako_tpl.render(helper=helper, |
|
|
|
css=css, |
|
|
|
_=self.translate_call, |
|
|
|
**self.parser_instance.localcontext) |
|
|
|
_=translate_call, |
|
|
|
**parser_instance.localcontext) |
|
|
|
htmls.append(html) |
|
|
|
except Exception, e: |
|
|
|
except Exception: |
|
|
|
msg = exceptions.text_error_template().render() |
|
|
|
_logger.error(msg) |
|
|
|
raise except_osv(_('Webkit render'), msg) |
|
|
@ -218,15 +224,16 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
try: |
|
|
|
html = body_mako_tpl.render(helper=helper, |
|
|
|
css=css, |
|
|
|
_=self.translate_call, |
|
|
|
**self.parser_instance.localcontext) |
|
|
|
_=translate_call, |
|
|
|
**parser_instance.localcontext) |
|
|
|
htmls.append(html) |
|
|
|
except Exception, e: |
|
|
|
except Exception: |
|
|
|
msg = exceptions.text_error_template().render() |
|
|
|
_logger.error(msg) |
|
|
|
raise except_osv(_('Webkit render'), msg) |
|
|
|
|
|
|
|
# NO html footer and header because we write them as text with wkhtmltopdf |
|
|
|
# NO html footer and header because we write them as text with |
|
|
|
# wkhtmltopdf |
|
|
|
head = foot = False |
|
|
|
|
|
|
|
if report_xml.webkit_debug: |
|
|
@ -234,13 +241,14 @@ class HeaderFooterTextWebKitParser(webkit_report.WebKitParser): |
|
|
|
deb = body_mako_tpl.render(helper=helper, |
|
|
|
css=css, |
|
|
|
_debug=tools.ustr("\n".join(htmls)), |
|
|
|
_=self.translate_call, |
|
|
|
**self.parser_instance.localcontext) |
|
|
|
except Exception, e: |
|
|
|
_=translate_call, |
|
|
|
**parser_instance.localcontext) |
|
|
|
except Exception: |
|
|
|
msg = exceptions.text_error_template().render() |
|
|
|
_logger.error(msg) |
|
|
|
raise except_osv(_('Webkit render'), msg) |
|
|
|
return (deb, 'html') |
|
|
|
bin = self.get_lib(cursor, uid) |
|
|
|
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls) |
|
|
|
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls, |
|
|
|
parser_instance=parser_instance) |
|
|
|
return (pdf, 'pdf') |