diff --git a/trytond/ir/action.py b/trytond/ir/action.py
index 05131d0ea3..87398ea0bf 100644
--- a/trytond/ir/action.py
+++ b/trytond/ir/action.py
@@ -168,6 +168,17 @@ class ActionKeyword(OSV):
ActionKeyword()
+class ActionReportOutputFormat(OSV):
+ "Output formats for reports"
+ _name = 'ir.action.report.outputformat'
+ _description = "Report Output Format"
+ format = fields.char('Internal Format Name', required=True,
+ readonly=True, help="Used as file extension, too.")
+ name = fields.char('Name', required=True, translate=True)
+
+ActionReportOutputFormat()
+
+
class ActionReport(OSV):
"Action report"
_name = 'ir.action.report'
@@ -187,6 +198,8 @@ class ActionReport(OSV):
style_content = fields.Function('get_style_content',
type='binary', string='Style')
direct_print = fields.Boolean('Direct Print')
+ output_format = fields.Many2One('ir.action.report.outputformat',
+ 'Output format', required=True)
def __init__(self):
super(ActionReport, self).__init__()
@@ -204,6 +217,16 @@ class ActionReport(OSV):
def default_direct_print(self, cursor, user, context=None):
return False
+ def default_output_format(self, cursor, user, context=None):
+ format_obj = self.pool.get(ActionReportOutputFormat._name)
+ formats = format_obj.search(cursor, user, [
+ ('format', '=', 'odt'),
+ ], limit=1, context=context)
+ if formats:
+ return format_obj.name_get(cursor, user, formats[0],
+ context=context)[0]
+ return False
+
def get_report_content(self, cursor, user, ids, name, arg, context=None):
res = {}
for report in self.browse(cursor, user, ids, context=context):
diff --git a/trytond/ir/action.xml b/trytond/ir/action.xml
index cc86850160..c3d5dc0ab6 100644
--- a/trytond/ir/action.xml
+++ b/trytond/ir/action.xml
@@ -59,6 +59,7 @@
+
ir.action.report
form
@@ -75,6 +76,8 @@
+
+
@@ -130,6 +133,19 @@
+
+
+
+ odt
+ ODF Textdocuments (.odt)
+
+
+ pdf
+ PDF Document
+
+
ir.action.act_window
form
diff --git a/trytond/report/report.py b/trytond/report/report.py
index 386d052c09..99f7a59b67 100644
--- a/trytond/report/report.py
+++ b/trytond/report/report.py
@@ -282,7 +282,62 @@ class Report(object):
content_z.close()
data = content_io.getvalue()
content_io.close()
- return ('odt', data)
+ output_format = report.output_format.format
+ if output_format == 'pdf':
+ data = self.convert_pdf(data)
+ return (output_format, data)
+
+
+ def convert_pdf(self, data):
+ """
+ Convert report to PDF using OpenOffice.org.
+ This requires OpenOffice.org, pyuno and openoffice-python to
+ be installed.
+ """
+ import tempfile
+ try:
+ import unohelper # installs import-hook
+ import openoffice.interact
+ import openoffice.officehelper as officehelper
+ from openoffice.streams import OutputStream
+ from com.sun.star.beans import PropertyValue
+ except ImportError, exception:
+ raise ExceptOSV('ImportError', str(exception))
+ try:
+ # connect to OOo
+ desktop = openoffice.interact.Desktop()
+ except officehelper.BootstrapException:
+ raise ExceptOSV('Error', "Can't connect to (bootstrap) OpenOffice.org")
+
+ res_data = None
+ # Create temporary file (with name) and write data there.
+ # We can not use NamedTemporaryFile here, since this would be
+ # deleted as soon as we close it to allow OOo reading.
+ #TODO use an input stream here
+ fd_odt, odt_name = tempfile.mkstemp()
+ fh_odt = os.fdopen(fd_odt, 'wb+')
+ try:
+ fh_odt.write(data)
+ del data # save memory
+ fh_odt.close()
+ doc = desktop.openFile(odt_name, hidden=False)
+ # Export as PDF
+ buffer = StringIO.StringIO()
+ out_props = (
+ PropertyValue("FilterName", 0, "writer_pdf_Export", 0),
+ PropertyValue("Overwrite", 0, True, 0),
+ PropertyValue("OutputStream", 0, OutputStream(buffer), 0),
+ )
+ doc.storeToURL("private:stream", out_props)
+ res_data = buffer.getvalue()
+ del buffer
+ doc.dispose()
+ finally:
+ fh_odt.close()
+ os.remove(odt_name)
+ if not res_data:
+ ExceptOSV('Error', 'Error converting to PDF')
+ return res_data
def _parse_node(self, cursor, user, node, localcontext, context,
node_context = None):