From f768863a2ee210bdbf782ffb30ad33691e9ab50f Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Thu, 24 Oct 2013 17:28:44 +0200 Subject: [PATCH 01/78] Init - Print the odt template without modification (empty values) --- .hgignore | 19 +++++++++++++++++++ __init__.py | 2 ++ __openerp__.py | 22 ++++++++++++++++++++++ py3o_report.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 .hgignore create mode 100644 __init__.py create mode 100644 __openerp__.py create mode 100644 py3o_report.py diff --git a/.hgignore b/.hgignore new file mode 100644 index 00000000..457a8ba9 --- /dev/null +++ b/.hgignore @@ -0,0 +1,19 @@ +syntax: glob +**/*.pyc +*.pyc +*.swp +.tmp* +*.egg-info +dist/* +build/* +lib/* +*.orig +*.log +.settings/* +data/* +storage/* +.project +.idea +.pydevproject +*.db +.ropeproject/* diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000..a6cf5076 --- /dev/null +++ b/__init__.py @@ -0,0 +1,2 @@ +import py3o_report +# import wizard diff --git a/__openerp__.py b/__openerp__.py new file mode 100644 index 00000000..62589b5e --- /dev/null +++ b/__openerp__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'LibreOffice Report Engine', + 'description': ''' +Generation of LibreOffice/OpenOffice reports using LibreOffice/OpenOffice +templates. + +py3o.template is used internally; install it with: + pip install py3o.template + pip install pyjon.utils +''', + 'version': '0.1', + 'category': 'Reporting', + 'author': 'XCG Consulting', + 'website': 'http://www.openerp-experts.com/', + 'depends': [ + 'base' + ], + 'data': [ + ], + 'installable': True, +} diff --git a/py3o_report.py b/py3o_report.py new file mode 100644 index 00000000..e792633b --- /dev/null +++ b/py3o_report.py @@ -0,0 +1,44 @@ +from tempfile import NamedTemporaryFile + +from openerp import addons, pooler +from openerp.report.report_sxw import * +from openerp.tools.translate import _ +from openerp.osv.osv import except_osv + +from py3o.template import Template + + +class py3o_report(report_sxw): +# def __init__(self, name, table): +# super(py3o_report, self).__init__(name, table) + + def create(self, cr, uid, ids, data, context=None): + # Find the report definition to get its settings. + pool = pooler.get_pool(cr.dbname) + report_xml_obj = pool.get('ir.actions.report.xml') + report_xml_ids = report_xml_obj.search(cr, uid, + [('report_name', '=', self.name[7:])], # Ignore "report." + context=context) + if not report_xml_ids: + return super(py3o_report, self).create(cr, uid, ids, data, + context=context) + report_xml = report_xml_obj.browse(cr, uid, + report_xml_ids[0], + context=context) + + # Get the template file. + template_path = addons.get_module_resource( + *report_xml.report_file.split('/')) + + # py3o.template operates on filenames so create a temporary file. + with NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ + temp_file: + + template = Template(template_path, temp_file.name) + + template.render({}) + + temp_file.seek(0) + return temp_file.read(), 'odt' + + return (False, False) From b6a148fdbe72ca78edee019569b0de1519582d8a Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Thu, 24 Oct 2013 17:58:00 +0200 Subject: [PATCH 02/78] Overridable function to customize the values sent to the py3o renderer --- py3o_report.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/py3o_report.py b/py3o_report.py index e792633b..d80f981b 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -12,6 +12,14 @@ class py3o_report(report_sxw): # def __init__(self, name, table): # super(py3o_report, self).__init__(name, table) + def get_values(self, cr, uid, ids, data, context): + ''' Override this function to customize the dictionary given to the + py3o.template renderer. ''' + + return { + 'objects': self.getObjects(cr, uid, ids, context), + } + def create(self, cr, uid, ids, data, context=None): # Find the report definition to get its settings. pool = pooler.get_pool(cr.dbname) @@ -36,9 +44,9 @@ class py3o_report(report_sxw): template = Template(template_path, temp_file.name) - template.render({}) + template.render(self.get_values(cr, uid, ids, data, context)) temp_file.seek(0) return temp_file.read(), 'odt' - return (False, False) + return False, False From 1bf8c307038b1711130199a7d130f2ee1c9c2dd9 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Fri, 25 Oct 2013 17:39:49 +0200 Subject: [PATCH 03/78] Update .hgignore --- .hgignore | 43 ++++++++++++++++++++++++------------------- __init__.py | 1 - 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.hgignore b/.hgignore index 457a8ba9..ca621bc4 100644 --- a/.hgignore +++ b/.hgignore @@ -1,19 +1,24 @@ -syntax: glob -**/*.pyc -*.pyc -*.swp -.tmp* -*.egg-info -dist/* -build/* -lib/* -*.orig -*.log -.settings/* -data/* -storage/* -.project -.idea -.pydevproject -*.db -.ropeproject/* +syntax: glob +**/*.pyc +*.pyc +*.pyo +*.swp +.tmp* +*~ +*.egg-info +dist/* +build/* +lib/* +output/* +*.orig +*.log +.settings/* +storage/* +.project +.idea +.pydevproject +*.db +.ropeproject/* +.mob + + diff --git a/__init__.py b/__init__.py index a6cf5076..739a4843 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2 +1 @@ import py3o_report -# import wizard From 379f3d467f9a14cdbd65f7445a1fc6e73df23c38 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 28 Oct 2013 11:29:57 +0100 Subject: [PATCH 04/78] Provide a lang object --- py3o_report.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/py3o_report.py b/py3o_report.py index d80f981b..51b9eaa8 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -17,9 +17,21 @@ class py3o_report(report_sxw): py3o.template renderer. ''' return { + 'lang': self.get_lang(cr, uid, context), 'objects': self.getObjects(cr, uid, ids, context), } + def get_lang(self, cr, uid, context): + pool = pooler.get_pool(cr.dbname) + lang_obj = pool.get('res.lang') + user_obj = pool.get('res.users') + + lang_code = user_obj.browse(cr, uid, uid, context=context).lang + lang = lang_obj.search(cr, uid, + [('code', '=', lang_code)], + context=context)[0] + return lang_obj.browse(cr, uid, lang, context=context) + def create(self, cr, uid, ids, data, context=None): # Find the report definition to get its settings. pool = pooler.get_pool(cr.dbname) From b23860efa6a48c7a06514cb1eb938a9811757271 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 28 Oct 2013 11:34:01 +0100 Subject: [PATCH 05/78] py3o.template now knows about the pyjon req --- __openerp__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/__openerp__.py b/__openerp__.py index 62589b5e..654f7e82 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -5,9 +5,8 @@ Generation of LibreOffice/OpenOffice reports using LibreOffice/OpenOffice templates. -py3o.template is used internally; install it with: +The py3o.template package is required; install it with: pip install py3o.template - pip install pyjon.utils ''', 'version': '0.1', 'category': 'Reporting', From e9c4d7c40be3ed8d109614940204ae27f03a645e Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 28 Oct 2013 17:20:01 +0100 Subject: [PATCH 06/78] Customization of report templates with a field to download/upload --- __init__.py | 1 + __openerp__.py | 1 + ir_report.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ ir_report.xml | 26 ++++++++++++++++++++++++++ py3o_report.py | 22 ++++++++++++---------- 5 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 ir_report.py create mode 100644 ir_report.xml diff --git a/__init__.py b/__init__.py index 739a4843..a6aad7f2 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1,2 @@ +import ir_report import py3o_report diff --git a/__openerp__.py b/__openerp__.py index 654f7e82..cacc7deb 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -16,6 +16,7 @@ The py3o.template package is required; install it with: 'base' ], 'data': [ + 'ir_report.xml', ], 'installable': True, } diff --git a/ir_report.py b/ir_report.py new file mode 100644 index 00000000..aedfb01c --- /dev/null +++ b/ir_report.py @@ -0,0 +1,46 @@ +from base64 import b64encode + +from openerp import addons +from openerp.osv import fields, osv +from openerp.tools.translate import _ + + +class report_xml(osv.osv): + ''' Inherit from ir.actions.report.xml to allow customizing the template + file. By default, the file defined when registering the report is used; + but the user can download / upload a new one. ''' + + _inherit = 'ir.actions.report.xml' + + def _get_filename(self, cr, uid, ids, field_name, arg, context): + return { + br.id: br.name + '.odt' + for br in self.browse(cr, uid, ids, context=context) + if br.report_type == 'py3o' + } + + def _get_template_data(self, cr, uid, ids, field_name, arg, context): + ''' Just return the data stored in the binary field, unless it is + empty; in that case, read the template file. ''' + + return { + br.id: (br.py3o_template_data if br.py3o_template_data + else b64encode(file(addons.get_module_resource( + *br.report_file.split('/')), 'rb').read())) + for br in self.browse(cr, uid, ids, context=context) + if br.report_type == 'py3o' + } + + _columns = { + 'py3o_filename': fields.function(_get_filename, + type='char', + method=True, + readonly=True), + + 'py3o_template': fields.function(_get_template_data, + type='binary', + method=True, + readonly=True), + + 'py3o_template_data': fields.binary(_('LibreOffice template')), + } diff --git a/ir_report.xml b/ir_report.xml new file mode 100644 index 00000000..fad7ceab --- /dev/null +++ b/ir_report.xml @@ -0,0 +1,26 @@ + + + + + + + py3o_report_view + ir.actions.report.xml + + + + + + + + + + + + + + + + + diff --git a/py3o_report.py b/py3o_report.py index 51b9eaa8..f84578ad 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -1,6 +1,7 @@ +from base64 import b64decode from tempfile import NamedTemporaryFile -from openerp import addons, pooler +from openerp import pooler from openerp.report.report_sxw import * from openerp.tools.translate import _ from openerp.osv.osv import except_osv @@ -46,19 +47,20 @@ class py3o_report(report_sxw): report_xml_ids[0], context=context) - # Get the template file. - template_path = addons.get_module_resource( - *report_xml.report_file.split('/')) + # py3o.template operates on filenames so create temporary files. + with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as \ + in_temp, \ + NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ + out_temp: - # py3o.template operates on filenames so create a temporary file. - with NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ - temp_file: + in_temp.write(b64decode(report_xml.py3o_template)) + in_temp.flush() - template = Template(template_path, temp_file.name) + template = Template(in_temp.name, out_temp.name) template.render(self.get_values(cr, uid, ids, data, context)) - temp_file.seek(0) - return temp_file.read(), 'odt' + out_temp.seek(0) + return out_temp.read(), 'odt' return False, False From 6df4a8469c8e51cde8e1f9f023fe1688cb5de206 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 28 Oct 2013 17:45:53 +0100 Subject: [PATCH 07/78] Hide the function field when the binary field is filled --- ir_report.py | 4 ++-- ir_report.xml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ir_report.py b/ir_report.py index aedfb01c..c4bd8595 100644 --- a/ir_report.py +++ b/ir_report.py @@ -24,8 +24,8 @@ class report_xml(osv.osv): empty; in that case, read the template file. ''' return { - br.id: (br.py3o_template_data if br.py3o_template_data - else b64encode(file(addons.get_module_resource( + br.id: (br.py3o_template_data or + b64encode(file(addons.get_module_resource( *br.report_file.split('/')), 'rb').read())) for br in self.browse(cr, uid, ids, context=context) if br.report_type == 'py3o' diff --git a/ir_report.xml b/ir_report.xml index fad7ceab..5810a745 100644 --- a/ir_report.xml +++ b/ir_report.xml @@ -14,7 +14,8 @@ attrs="{'invisible': [('report_type', '!=', 'py3o')]}"> - + From 1a84a036596327a4a6f22aa5643df4d70d86acfe Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Tue, 29 Oct 2013 11:03:33 +0100 Subject: [PATCH 08/78] Add a function to format dates --- py3o_report.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/py3o_report.py b/py3o_report.py index f84578ad..73391661 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -32,6 +32,11 @@ class py3o_report(report_sxw): [('code', '=', lang_code)], context=context)[0] return lang_obj.browse(cr, uid, lang, context=context) + + def format_date(self, date, values): + ''' Return a date formatted according to the language extracted from + the "values" argument (which should be the result of get_values). ''' + return date.strftime(values['lang'].date_format) def create(self, cr, uid, ids, data, context=None): # Find the report definition to get its settings. From a55a474b54d688ceef58721c1bdce940571c1e17 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Fri, 29 Nov 2013 17:17:03 +0100 Subject: [PATCH 09/78] Version 1.0 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index cacc7deb..eb7eddd5 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '0.1', + 'version': '1.0', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 1337a670a96a3ae6ea37513a9773da420da4aafb Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Fri, 29 Nov 2013 17:17:08 +0100 Subject: [PATCH 10/78] Added tag TAG_1.0 for changeset ae59b92cb6bd --- .hgtags | 1 + 1 file changed, 1 insertion(+) create mode 100644 .hgtags diff --git a/.hgtags b/.hgtags new file mode 100644 index 00000000..026cad0b --- /dev/null +++ b/.hgtags @@ -0,0 +1 @@ +ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 From 2b26a5f2c811943a9af1e10c6ae809f213a9be83 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 16 Dec 2013 17:16:10 +0100 Subject: [PATCH 11/78] Declare the dependency on py3o.template - fix #3 --- __openerp__.py | 3 +++ py3o_report.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index eb7eddd5..206e5709 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -15,6 +15,9 @@ The py3o.template package is required; install it with: 'depends': [ 'base' ], + 'external_dependencies': { + 'python': ['py3o.template'] + }, 'data': [ 'ir_report.xml', ], diff --git a/py3o_report.py b/py3o_report.py index 73391661..0ff89e1f 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -32,7 +32,7 @@ class py3o_report(report_sxw): [('code', '=', lang_code)], context=context)[0] return lang_obj.browse(cr, uid, lang, context=context) - + def format_date(self, date, values): ''' Return a date formatted according to the language extracted from the "values" argument (which should be the result of get_values). ''' From c5d69269d528f271a881b9b535b149cd1d62c11d Mon Sep 17 00:00:00 2001 From: Alexandre Allouche Date: Wed, 5 Feb 2014 20:09:42 +0100 Subject: [PATCH 12/78] bumped version to 1.1 (stable) --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 206e5709..37737e2f 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.0', + 'version': '1.1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From e3dcf11a1ebfa17f653d3398d7de561a0a3213df Mon Sep 17 00:00:00 2001 From: Alexandre Allouche Date: Wed, 5 Feb 2014 20:09:52 +0100 Subject: [PATCH 13/78] Added tag TAG_1.1 for changeset 392758bf61eb --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 026cad0b..5d707ef9 100644 --- a/.hgtags +++ b/.hgtags @@ -1 +1,2 @@ ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 +392758bf61eb33256bc3a46e16ca15d6195bc8a8 TAG_1.1 From 09542c7248caad23057b483c89c1c8ccfb6d9b9b Mon Sep 17 00:00:00 2001 From: Alexandre Allouche Date: Wed, 5 Feb 2014 20:10:18 +0100 Subject: [PATCH 14/78] bumped version to 1.1.1 (dev) --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 37737e2f..d44ab36b 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.1', + 'version': '1.1.1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 483dbe7accd45fed592763a3ebf8a1cdc1bbca91 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:19:12 +0200 Subject: [PATCH 15/78] Now we call fusion server just to convert reports into the right format --- __init__.py | 3 +++ __openerp__.py | 6 +++++- ir_report.py | 49 ++++++++++++------------------------------------- ir_report.xml | 8 ++++---- py3o_report.py | 35 ++++++++++++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/__init__.py b/__init__.py index a6aad7f2..9071ae81 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2 +1,5 @@ import ir_report import py3o_report +import py3o_template +import py3o_server +import py3o_fusion_filetype diff --git a/__openerp__.py b/__openerp__.py index d44ab36b..07c12921 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -16,10 +16,14 @@ The py3o.template package is required; install it with: 'base' ], 'external_dependencies': { - 'python': ['py3o.template'] + 'python': ['py3o.template', 'oe_json_serializer'] }, 'data': [ + 'menu.xml', 'ir_report.xml', + 'py3o_template.xml', + 'py3o_server.xml', + 'data/py3o.fusion.filetype.csv', ], 'installable': True, } diff --git a/ir_report.py b/ir_report.py index c4bd8595..2e545bbf 100644 --- a/ir_report.py +++ b/ir_report.py @@ -1,46 +1,21 @@ -from base64 import b64encode - -from openerp import addons from openerp.osv import fields, osv -from openerp.tools.translate import _ -class report_xml(osv.osv): +class report_xml(osv.Model): ''' Inherit from ir.actions.report.xml to allow customizing the template - file. By default, the file defined when registering the report is used; - but the user can download / upload a new one. ''' + file. The user cam chose a template from a list. + The list is configurable in the configuration tab, see py3o_template.py + ''' _inherit = 'ir.actions.report.xml' - def _get_filename(self, cr, uid, ids, field_name, arg, context): - return { - br.id: br.name + '.odt' - for br in self.browse(cr, uid, ids, context=context) - if br.report_type == 'py3o' - } - - def _get_template_data(self, cr, uid, ids, field_name, arg, context): - ''' Just return the data stored in the binary field, unless it is - empty; in that case, read the template file. ''' - - return { - br.id: (br.py3o_template_data or - b64encode(file(addons.get_module_resource( - *br.report_file.split('/')), 'rb').read())) - for br in self.browse(cr, uid, ids, context=context) - if br.report_type == 'py3o' - } - _columns = { - 'py3o_filename': fields.function(_get_filename, - type='char', - method=True, - readonly=True), - - 'py3o_template': fields.function(_get_template_data, - type='binary', - method=True, - readonly=True), - - 'py3o_template_data': fields.binary(_('LibreOffice template')), + 'py3o_fusion_filetype': fields.many2one( + 'py3o.fusion.filetype', + u"Output Format", + ), + 'py3o_template_id': fields.many2one( + 'py3o.template', + u"Template", + ), } diff --git a/ir_report.xml b/ir_report.xml index 5810a745..d4521c76 100644 --- a/ir_report.xml +++ b/ir_report.xml @@ -13,10 +13,10 @@ - - - + + + + diff --git a/py3o_report.py b/py3o_report.py index 0ff89e1f..9b3fecb1 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -8,6 +8,8 @@ from openerp.osv.osv import except_osv from py3o.template import Template +import requests + class py3o_report(report_sxw): # def __init__(self, name, table): @@ -52,13 +54,16 @@ class py3o_report(report_sxw): report_xml_ids[0], context=context) + template = report_xml.py3o_template_id + filetype = report_xml.py3o_fusion_filetype + # py3o.template operates on filenames so create temporary files. with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as \ in_temp, \ NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ out_temp: - in_temp.write(b64decode(report_xml.py3o_template)) + in_temp.write(b64decode(template.py3o_template_data)) in_temp.flush() template = Template(in_temp.name, out_temp.name) @@ -66,6 +71,34 @@ class py3o_report(report_sxw): template.render(self.get_values(cr, uid, ids, data, context)) out_temp.seek(0) + + if filetype.human_ext != 'odt': + # Now we ask fusion server to convert our template + fusion_server_obj = pool['py3o.server'] + fusion_server_id = fusion_server_obj.search( + cr, uid, [], context=context + )[0] + fusion_server = fusion_server_obj.browse( + cr, uid, fusion_server_id, context=context + ) + files = { + 'tmpl_file': out_temp, + } + fields = { + "targetformat": filetype.fusion_ext, + "datadict": "{}", + "image_mapping": "{}", + } + r = requests.post(fusion_server.url, data=fields, files=files) + chunk_size = 1024 + with NamedTemporaryFile( + suffix=filetype.human_ext, + prefix='py3o-template-') as fd: + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + return fd.read(), filetype.human_ext + return out_temp.read(), 'odt' return False, False From 0dff6d20d123de29aa30931c6f8d38b67be8bc61 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:34:59 +0200 Subject: [PATCH 16/78] 1.2 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 07c12921..435fc70c 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.1.1', + 'version': '1.2', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 1ff6d8e1c87dca7b64f516c235b81e76f4078639 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:35:05 +0200 Subject: [PATCH 17/78] Added tag TAG_1.2 for changeset b6c64ac6e399 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 5d707ef9..116edf55 100644 --- a/.hgtags +++ b/.hgtags @@ -1,2 +1,3 @@ ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 392758bf61eb33256bc3a46e16ca15d6195bc8a8 TAG_1.1 +b6c64ac6e39936d1ee13c58c14bf62b04c5b5202 TAG_1.2 From 81e37f966da5b9788a12b969e70c2529a5f7c6fa Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:54:23 +0200 Subject: [PATCH 18/78] Remove deps --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 435fc70c..a8a6b9de 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -16,7 +16,7 @@ The py3o.template package is required; install it with: 'base' ], 'external_dependencies': { - 'python': ['py3o.template', 'oe_json_serializer'] + 'python': ['py3o.template'] }, 'data': [ 'menu.xml', From 872d3d3087fdc439fdfa13c5f44cdb93e52e7900 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:54:37 +0200 Subject: [PATCH 19/78] 1.2.1 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index a8a6b9de..dfe5fe88 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2', + 'version': '1.2.1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 54d831ec47e2cd469c14df1659b6fb5647cc9d0e Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 10:54:44 +0200 Subject: [PATCH 20/78] Added tag TAG_1.2.1 for changeset cd840bda3fa0 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 116edf55..4a7a84bc 100644 --- a/.hgtags +++ b/.hgtags @@ -1,3 +1,4 @@ ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 392758bf61eb33256bc3a46e16ca15d6195bc8a8 TAG_1.1 b6c64ac6e39936d1ee13c58c14bf62b04c5b5202 TAG_1.2 +cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 From 487ed707773b9e7fcf1898e65989f82799662e76 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 14 Oct 2014 13:06:38 +0200 Subject: [PATCH 21/78] Add missing files --- data/py3o.fusion.filetype.csv | 6 ++ menu.xml | 8 ++ py3o_fusion_filetype.py | 18 +++++ py3o_report_modif.py | 144 ++++++++++++++++++++++++++++++++++ py3o_server.py | 12 +++ py3o_server.xml | 40 ++++++++++ py3o_template.py | 14 ++++ py3o_template.xml | 41 ++++++++++ 8 files changed, 283 insertions(+) create mode 100644 data/py3o.fusion.filetype.csv create mode 100644 menu.xml create mode 100644 py3o_fusion_filetype.py create mode 100644 py3o_report_modif.py create mode 100644 py3o_server.py create mode 100644 py3o_server.xml create mode 100644 py3o_template.py create mode 100644 py3o_template.xml diff --git a/data/py3o.fusion.filetype.csv b/data/py3o.fusion.filetype.csv new file mode 100644 index 00000000..f0e11e8b --- /dev/null +++ b/data/py3o.fusion.filetype.csv @@ -0,0 +1,6 @@ +id,fusion_ext,human_ext +py3o_fusion_filetype_odt,ODT,odt +py3o_fusion_filetype_ods,ODS,ods +py3o_fusion_filetype_doc,DOC,doc +py3o_fusion_filetype_docx,DOCX,docx +py3o_fusion_filetype_pdf,PDF,pdf diff --git a/menu.xml b/menu.xml new file mode 100644 index 00000000..23589c9e --- /dev/null +++ b/menu.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/py3o_fusion_filetype.py b/py3o_fusion_filetype.py new file mode 100644 index 00000000..570ca474 --- /dev/null +++ b/py3o_fusion_filetype.py @@ -0,0 +1,18 @@ +from openerp.osv import fields, osv + + +class py3o_fusion_filetype(osv.Model): + _name = 'py3o.fusion.filetype' + + _rec_name = 'human_ext' + + _columns = { + 'fusion_ext': fields.char( + u"Fusion Extension", + size=8, + ), + 'human_ext': fields.char( + u"Human readble extension", + size=8, + ), + } diff --git a/py3o_report_modif.py b/py3o_report_modif.py new file mode 100644 index 00000000..5c474835 --- /dev/null +++ b/py3o_report_modif.py @@ -0,0 +1,144 @@ +from base64 import b64decode +from tempfile import NamedTemporaryFile as tempfile + +from openerp import pooler +from openerp.report.report_sxw import * +from openerp.tools.translate import _ +from openerp.osv.osv import except_osv + +from py3o.template import Template + +from oe_json_serializer import OESerializer + +import json +import requests +import os + + +class py3o_report(report_sxw): +# def __init__(self, name, table): +# super(py3o_report, self).__init__(name, table) + + def get_values(self, cr, uid, ids, data, context): + ''' Override this function to customize the dictionary given to the + py3o.template renderer. ''' + + return { + 'lang': self.get_lang(cr, uid, context), + 'objects': self.getObjects(cr, uid, ids, context), + } + + def get_lang(self, cr, uid, context): + pool = pooler.get_pool(cr.dbname) + lang_obj = pool.get('res.lang') + user_obj = pool.get('res.users') + + lang_code = user_obj.browse(cr, uid, uid, context=context).lang + lang = lang_obj.search(cr, uid, + [('code', '=', lang_code)], + context=context)[0] + return lang_obj.browse(cr, uid, lang, context=context) + + def format_date(self, date, values): + ''' Return a date formatted according to the language extracted from + the "values" argument (which should be the result of get_values). ''' + return date.strftime(values['lang'].date_format) + + def create(self, cr, uid, ids, data, context=None): + # Find the report definition to get its settings. + pool = pooler.get_pool(cr.dbname) + report_xml_obj = pool.get('ir.actions.report.xml') + report_xml_ids = report_xml_obj.search(cr, uid, + [('report_name', '=', self.name[7:])], # Ignore "report." + context=context) + if not report_xml_ids: + return super(py3o_report, self).create(cr, uid, ids, data, + context=context) + report_xml = report_xml_obj.browse(cr, uid, + report_xml_ids[0], + context=context) + + template = report_xml.py3o_template_id + filetype = report_xml.py3o_fusion_filetype + + + #Try to request fusion server: + + fusion_server_obj = pool['py3o.server'] + #TODO: Raise a message if no config found + fusion_server_id = fusion_server_obj.search( + cr, uid, [], context=context + )[0] + fusion_server = fusion_server_obj.browse(cr, uid, fusion_server_id) + + # py3o.template operates on filenames so create temporary files. + in_temp = tempfile(suffix='.odt', prefix='py3o-template-') + + in_temp.write(b64decode(template.py3o_template_data)) + in_temp.seek(0) + out_temp = tempfile(suffix='.odt', prefix='py3o-report-') + + # We need to get the variables used in the template + #TODO: Find a way to avoid calling Template + t = Template(in_temp.name, out_temp.name) + # Remove 'py3o.' + user_variable = [x[5:] for x in t.get_user_variable()] + print user_variable + + values = self.get_values(cr, uid, ids, data, context) + print values + + #WARNING: We rely on the fact that there is a for loop on the report + # on objects (for object in objects) due to lack of time + val_dict = {} + for val in values: + if val == 'objects': + o = [] + for obj in values[val]: + x = OESerializer.serialize( + obj, + [ + v[len('object') + 1:] + for v in user_variable + if v.startswith('object') + ] + ) + o.append(x) + val_dict.update({val: o}) + continue + + x = OESerializer.serialize( + values[val], + [ + v[len(val) + 1:] + for v in user_variable + if v.startswith(val) + ] + ) + val_dict.update({val: x}) + + import pprint + pprint.pprint(val_dict) + val_json = json.dumps(val_dict) + + fields = { + 'targetformat': filetype.fusion_ext, + 'datadict': val_json, + 'image_mapping': '{}', + } + print fields + + r = requests.post( + fusion_server.url, data=fields, files={'tmpl_file': in_temp} + ) + in_temp.close() + if r.status_code == 400: + raise Exception("Problem with fusion server: %s" % r.json()) + + chunk_size = 1024 + + ext = filetype.human_ext + for chunk in r.iter_content(chunk_size): + out_temp.write(chunk) + out_temp.seek(0) + return out_temp.read(), ext diff --git a/py3o_server.py b/py3o_server.py new file mode 100644 index 00000000..957e7b81 --- /dev/null +++ b/py3o_server.py @@ -0,0 +1,12 @@ +from openerp.osv import fields, osv + + +class py3o_server(osv.Model): + _name = 'py3o.server' + + _columns = { + 'url': fields.char( + u"URL", + size=256, + ), + } diff --git a/py3o_server.xml b/py3o_server.xml new file mode 100644 index 00000000..ba3456a9 --- /dev/null +++ b/py3o_server.xml @@ -0,0 +1,40 @@ + + + + + py3o.server.configuration.form.view + py3o.server + +
+ + + + + +
+
+
+ + + py3o.server.configuration.tree.view + py3o.server + + + + + + + + + py3o.server.configuration.action + py3o.server + form + tree,form + + + +
+
diff --git a/py3o_template.py b/py3o_template.py new file mode 100644 index 00000000..c5392922 --- /dev/null +++ b/py3o_template.py @@ -0,0 +1,14 @@ +from openerp.osv import fields, osv + + +class py3o_template(osv.Model): + _name = 'py3o.template' + + _columns = { + 'name': fields.char( + u"Name", + ), + 'py3o_template_data': fields.binary( + u"LibreOffice template", + ), + } diff --git a/py3o_template.xml b/py3o_template.xml new file mode 100644 index 00000000..62625b52 --- /dev/null +++ b/py3o_template.xml @@ -0,0 +1,41 @@ + + + + + py3o.template.configuration.form.view + py3o.template + +
+ + + + + + +
+
+
+ + + py3o.template.configuration.tree.view + py3o.template + + + + + + + + + Py3o Templates Configuration + py3o.template + form + tree,form + + + +
+
From b04cef9434a3cf571c4cd4f51323c34235fdd766 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 09:43:45 +0200 Subject: [PATCH 22/78] 1.2.2 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index dfe5fe88..c69a12f7 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.1', + 'version': '1.2.2', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From b62f55bd47fa919303ef83650ff805a4b4b2df42 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 09:43:51 +0200 Subject: [PATCH 23/78] Added tag TAG_1.2.2 for changeset 092018f8f6ca --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 4a7a84bc..05df8599 100644 --- a/.hgtags +++ b/.hgtags @@ -2,3 +2,4 @@ ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 392758bf61eb33256bc3a46e16ca15d6195bc8a8 TAG_1.1 b6c64ac6e39936d1ee13c58c14bf62b04c5b5202 TAG_1.2 cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 +092018f8f6cab00d7198e0fdd2489e0d41c33f9f TAG_1.2.2 From 313e64a340700d3735f20537807ddc3d080be1e9 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 09:49:31 +0200 Subject: [PATCH 24/78] move py3o menu --- menu.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.xml b/menu.xml index 23589c9e..10a682cf 100644 --- a/menu.xml +++ b/menu.xml @@ -3,6 +3,6 @@ + parent="base.menu_config" /> From a8add8986edef0b8b2eee2b64e4c4ee70be963eb Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 09:50:14 +0200 Subject: [PATCH 25/78] 1.2.3 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index c69a12f7..575cf1d8 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.2', + 'version': '1.2.3', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 7ef42df4564d01695a7267b9752904d6d792a131 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 09:50:18 +0200 Subject: [PATCH 26/78] Added tag TAG_1.2.3 for changeset 2203f0ccc2e2 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 05df8599..e4699af3 100644 --- a/.hgtags +++ b/.hgtags @@ -3,3 +3,4 @@ ae59b92cb6bda5ada7fffd01d9006c800a6da9f4 TAG_1.0 b6c64ac6e39936d1ee13c58c14bf62b04c5b5202 TAG_1.2 cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 092018f8f6cab00d7198e0fdd2489e0d41c33f9f TAG_1.2.2 +2203f0ccc2e2d728c81080d37cba4559d705917e TAG_1.2.3 From 9163a2a2f821796670277d549fac6be3fb7c7d54 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 16:48:34 +0200 Subject: [PATCH 27/78] Add skipfusion flag to post --- __openerp__.py | 1 + py3o_report.py | 1 + 2 files changed, 2 insertions(+) diff --git a/__openerp__.py b/__openerp__.py index 575cf1d8..246ab1ba 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -24,6 +24,7 @@ The py3o.template package is required; install it with: 'py3o_template.xml', 'py3o_server.xml', 'data/py3o.fusion.filetype.csv', + 'security/ir.model.access.csv', ], 'installable': True, } diff --git a/py3o_report.py b/py3o_report.py index 9b3fecb1..76f075f2 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -88,6 +88,7 @@ class py3o_report(report_sxw): "targetformat": filetype.fusion_ext, "datadict": "{}", "image_mapping": "{}", + "skipfusion": True, } r = requests.post(fusion_server.url, data=fields, files=files) chunk_size = 1024 From 75e7cb8ca35b87fb53211709e32e6e6f0b2aecf9 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 16:48:47 +0200 Subject: [PATCH 28/78] 1.2.4 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 246ab1ba..a76ac72c 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.3', + 'version': '1.2.4', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 754442322de50497108f895b8a9d8a40b537fb1d Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 16:48:51 +0200 Subject: [PATCH 29/78] Added tag TAG_1.2.4 for changeset d6fa2a1477bc --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index e4699af3..4a1f512a 100644 --- a/.hgtags +++ b/.hgtags @@ -4,3 +4,4 @@ b6c64ac6e39936d1ee13c58c14bf62b04c5b5202 TAG_1.2 cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 092018f8f6cab00d7198e0fdd2489e0d41c33f9f TAG_1.2.2 2203f0ccc2e2d728c81080d37cba4559d705917e TAG_1.2.3 +d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 From 246b6ab13030b1089e48b932ed7740885b9f25f9 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 17:05:48 +0200 Subject: [PATCH 30/78] Add security rules --- security/ir.model.access.csv | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 security/ir.model.access.csv diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv new file mode 100644 index 00000000..9ac0d796 --- /dev/null +++ b/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_py3o_template_admin,access_py3o_template_admin,model_py3o_template,base.group_no_one,1,1,1,1 +access_py3o_template_user,access_py3o_template_user,model_py3o_template,base.group_user,1,0,0,0 +access_py3o_server_admin,access_py3o_server_admin,model_py3o_server,base.group_no_one,1,1,1,1 +access_py3o_server_user,access_py3o_server_user,model_py3o_server,base.group_user,1,0,0,0 +access_py3o_fusion_filetype_admin,access_py3o_fusion_filetype_admin,model_py3o_fusion_filetype,base.group_no_one,1,1,1,1 +access_py3o_fusion_filetype_user,access_py3o_fusion_filetype_user,model_py3o_fusion_filetype,base.group_user,1,0,0,0 From fb5b0c6a9c534e06e45ec9620ee87e9a1616c4eb Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 17:07:40 +0200 Subject: [PATCH 31/78] 1.2.5 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index a76ac72c..60b4f347 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.4', + 'version': '1.2.5', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From 174203aefd4d59a43acfcd9e0bb82e939b91f7a0 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 15 Oct 2014 17:07:45 +0200 Subject: [PATCH 32/78] Added tag TAG_1.2.5 for changeset 067b603cc82e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 4a1f512a..71f34974 100644 --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 092018f8f6cab00d7198e0fdd2489e0d41c33f9f TAG_1.2.2 2203f0ccc2e2d728c81080d37cba4559d705917e TAG_1.2.3 d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 +067b603cc82e6403b66fedd1636f50ff104c3fee TAG_1.2.5 From 5bd73ea1f021e5a7ba1b633c7db5f74a7c6df291 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Fri, 7 Nov 2014 10:23:53 +0100 Subject: [PATCH 33/78] Call new methods from py3o.template to easily jsonify our datastruct --- py3o_report.py | 90 +++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/py3o_report.py b/py3o_report.py index 76f075f2..5429263a 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -9,15 +9,17 @@ from openerp.osv.osv import except_osv from py3o.template import Template import requests +from collections import defaultdict +import json class py3o_report(report_sxw): -# def __init__(self, name, table): -# super(py3o_report, self).__init__(name, table) + # def __init__(self, name, table): + # super(py3o_report, self).__init__(name, table) def get_values(self, cr, uid, ids, data, context): - ''' Override this function to customize the dictionary given to the - py3o.template renderer. ''' + """ Override this function to customize the dictionary given to the + py3o.template renderer. """ return { 'lang': self.get_lang(cr, uid, context), @@ -36,8 +38,8 @@ class py3o_report(report_sxw): return lang_obj.browse(cr, uid, lang, context=context) def format_date(self, date, values): - ''' Return a date formatted according to the language extracted from - the "values" argument (which should be the result of get_values). ''' + """ Return a date formatted according to the language extracted from + the "values" argument (which should be the result of get_values). """ return date.strftime(values['lang'].date_format) def create(self, cr, uid, ids, data, context=None): @@ -45,8 +47,8 @@ class py3o_report(report_sxw): pool = pooler.get_pool(cr.dbname) report_xml_obj = pool.get('ir.actions.report.xml') report_xml_ids = report_xml_obj.search(cr, uid, - [('report_name', '=', self.name[7:])], # Ignore "report." - context=context) + [('report_name', '=', self.name[7:])], # Ignore "report." + context=context) if not report_xml_ids: return super(py3o_report, self).create(cr, uid, ids, data, context=context) @@ -58,48 +60,40 @@ class py3o_report(report_sxw): filetype = report_xml.py3o_fusion_filetype # py3o.template operates on filenames so create temporary files. - with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as \ - in_temp, \ - NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ - out_temp: + with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as in_temp: in_temp.write(b64decode(template.py3o_template_data)) in_temp.flush() - - template = Template(in_temp.name, out_temp.name) - - template.render(self.get_values(cr, uid, ids, data, context)) - - out_temp.seek(0) - - if filetype.human_ext != 'odt': - # Now we ask fusion server to convert our template - fusion_server_obj = pool['py3o.server'] - fusion_server_id = fusion_server_obj.search( - cr, uid, [], context=context - )[0] - fusion_server = fusion_server_obj.browse( - cr, uid, fusion_server_id, context=context - ) - files = { - 'tmpl_file': out_temp, - } - fields = { - "targetformat": filetype.fusion_ext, - "datadict": "{}", - "image_mapping": "{}", - "skipfusion": True, - } - r = requests.post(fusion_server.url, data=fields, files=files) - chunk_size = 1024 - with NamedTemporaryFile( + in_temp.seek(0) + + template = Template(in_temp.name, None) + + user_instruction_mapping = template.get_user_instructions_mapping() + values = user_instruction_mapping.jsonify( + self.get_values(cr, uid, ids, data, context) + ) + + fusion_server_obj = pool['py3o.server'] + fusion_server_id = fusion_server_obj.search( + cr, uid, [], context=context + )[0] + fusion_server = fusion_server_obj.browse( + cr, uid, fusion_server_id, context=context + ) + files = { + 'tmpl_file': in_temp, + } + fields = { + "targetformat": filetype.fusion_ext, + "datadict": values, + "image_mapping": "{}", + } + r = requests.post(fusion_server.url, data=fields, files=files) + chunk_size = 1024 + with NamedTemporaryFile( suffix=filetype.human_ext, prefix='py3o-template-') as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) - fd.seek(0) - return fd.read(), filetype.human_ext - - return out_temp.read(), 'odt' - - return False, False + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + return fd.read(), filetype.human_ext From 9d99f39c1c160b18a8c089dd92734dcbcbb50841 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Fri, 7 Nov 2014 10:25:59 +0100 Subject: [PATCH 34/78] Remove useless stuff --- py3o_report.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/py3o_report.py b/py3o_report.py index 5429263a..61b1d2ac 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -1,16 +1,11 @@ from base64 import b64decode from tempfile import NamedTemporaryFile -from openerp import pooler from openerp.report.report_sxw import * -from openerp.tools.translate import _ -from openerp.osv.osv import except_osv from py3o.template import Template import requests -from collections import defaultdict -import json class py3o_report(report_sxw): @@ -26,7 +21,8 @@ class py3o_report(report_sxw): 'objects': self.getObjects(cr, uid, ids, context), } - def get_lang(self, cr, uid, context): + @staticmethod + def get_lang(cr, uid, context): pool = pooler.get_pool(cr.dbname) lang_obj = pool.get('res.lang') user_obj = pool.get('res.users') @@ -37,7 +33,8 @@ class py3o_report(report_sxw): context=context)[0] return lang_obj.browse(cr, uid, lang, context=context) - def format_date(self, date, values): + @staticmethod + def format_date(date, values): """ Return a date formatted according to the language extracted from the "values" argument (which should be the result of get_values). """ return date.strftime(values['lang'].date_format) From 95a4f0fff23edd933e951decb68df894bc1f3de0 Mon Sep 17 00:00:00 2001 From: Vincent Lhote-Hatakeyama Date: Mon, 22 Dec 2014 11:57:46 +0100 Subject: [PATCH 35/78] 1.3 production release --- NEWS | 4 ++++ __openerp__.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..f993a6ca --- /dev/null +++ b/NEWS @@ -0,0 +1,4 @@ +report_py3o 1.3 + +Production release + diff --git a/__openerp__.py b/__openerp__.py index 60b4f347..45bed0e5 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,10 +8,10 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.5', + 'version': '1.3', 'category': 'Reporting', 'author': 'XCG Consulting', - 'website': 'http://www.openerp-experts.com/', + 'website': 'http://odoo.consulting/', 'depends': [ 'base' ], From 460ae07b3016206dc63f05cf1fc5aa18b9a9d57d Mon Sep 17 00:00:00 2001 From: Vincent Lhote-Hatakeyama Date: Mon, 22 Dec 2014 12:21:50 +0100 Subject: [PATCH 36/78] Added tag TAG_1.3 for changeset f1771be362a2 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 71f34974..4256d4ff 100644 --- a/.hgtags +++ b/.hgtags @@ -6,3 +6,4 @@ cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 2203f0ccc2e2d728c81080d37cba4559d705917e TAG_1.2.3 d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 067b603cc82e6403b66fedd1636f50ff104c3fee TAG_1.2.5 +f1771be362a22fc55eb1ab9103fbf81f1f303d33 TAG_1.3 From 30404a7a4b07e9bc2135b42e36e02ef4102f882f Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 22 Dec 2014 14:07:51 +0100 Subject: [PATCH 37/78] Version 1.3 --HG-- branch : 1.2 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 60b4f347..6f4f8fa5 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.2.5', + 'version': '1.3', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://www.openerp-experts.com/', From d4edd466f246a6fbd28d7cada2025e8d04bce5c2 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 22 Dec 2014 14:07:57 +0100 Subject: [PATCH 38/78] Added tag TAG_1.3 for changeset ce6b34e12517 --HG-- branch : 1.2 --- .hgtags | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgtags b/.hgtags index 4a1f512a..302fc6c0 100644 --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,5 @@ cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 092018f8f6cab00d7198e0fdd2489e0d41c33f9f TAG_1.2.2 2203f0ccc2e2d728c81080d37cba4559d705917e TAG_1.2.3 d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 +f1771be362a22fc55eb1ab9103fbf81f1f303d33 TAG_1.3 +ce6b34e125174856e86c108399dfbb0eb84a7418 TAG_1.3 From e38bd9cf70141394a28376c77070a31fb2a2dcd8 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 22 Dec 2014 14:10:49 +0100 Subject: [PATCH 39/78] Version 1.3.1 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 45bed0e5..847e51dd 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -8,7 +8,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.3', + 'version': '1.3.1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', From 95f4ce97f704a3c684727fe19d492e206c8e4752 Mon Sep 17 00:00:00 2001 From: Houzefa Abbasbhay Date: Mon, 22 Dec 2014 14:10:58 +0100 Subject: [PATCH 40/78] Added tag TAG_1.3.1 for changeset a9d3f3747769 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index fb3df2ec..6eed60f8 100644 --- a/.hgtags +++ b/.hgtags @@ -7,3 +7,4 @@ cd840bda3fa0d8cd4290700b299a8bad2c99606d TAG_1.2.1 d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 067b603cc82e6403b66fedd1636f50ff104c3fee TAG_1.2.5 ce6b34e125174856e86c108399dfbb0eb84a7418 TAG_1.3 +a9d3f37477695c6255e7f603fa47defcfbd3a2af TAG_1.3.1 From 07d87078fe7da11770f3cfd20e24abc5a80d5e58 Mon Sep 17 00:00:00 2001 From: Alexandre Brun Date: Thu, 15 Jan 2015 17:59:19 +0100 Subject: [PATCH 41/78] Update and Add License (AGPL) and (XCG) --- LICENSE | 661 +++++++++++++++++++++++++++++++++++++++++++++++++ __openerp__.py | 22 ++ 2 files changed, 683 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..dba13ed2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/__openerp__.py b/__openerp__.py index 847e51dd..afff8ecb 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -1,4 +1,26 @@ # -*- coding: utf-8 -*- +############################################################################## +# +# LibreOffice Report Engine, for OpenERP +# Copyright (C) 2013 XCG Consulting (http://odoo.consulting) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Author: Anael LORIMIER +# Vincent Lhote-Hatakeyama +# +############################################################################## { 'name': 'LibreOffice Report Engine', 'description': ''' From ef92dfd429e006dbaba33ed7d3910351a2926ff7 Mon Sep 17 00:00:00 2001 From: Alexandre Brun Date: Fri, 16 Jan 2015 16:08:57 +0100 Subject: [PATCH 42/78] Add README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..a5aa113a --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +### README ### + + +### LibreOffice Report Engine for Odoo/OpenERP ### + + +This module allows you to convert any type of report into LibreOffice/OpenOffice. +The benefits is that you have control over your documents and you can +modify them as needed. + + +Requirements +============ + +The py3o.template package is required; install it with: + pip install py3o.template + + From b54dd2b9658c180554ed19393c22ceb057625d6c Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 18 Feb 2015 12:24:32 +0100 Subject: [PATCH 43/78] Odoo 8 fixes --HG-- branch : odoo8 --- ir_report.py | 18 ++++++++++++++++++ menu.xml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ir_report.py b/ir_report.py index 2e545bbf..7ae4c52f 100644 --- a/ir_report.py +++ b/ir_report.py @@ -18,4 +18,22 @@ class report_xml(osv.Model): 'py3o.template', u"Template", ), + 'report_type': fields.selection( + [ + ('qweb-pdf', u"PDF"), + ('qweb-html', u"HTML"), + ('controller', u"Controller"), + ('pdf', u"RML pdf (deprecated)"), + ('sxw', u"RML sxw (deprecated)"), + ('webkit', u"Webkit (deprecated)"), + ('py3o', u"Py3o"), + ], + string=u"Report Type", + required=True, + help=u"HTML will open the report directly in your browser, " + u"PDF will use wkhtmltopdf to render the HTML into a PDF " + u"file and let you download it, Controller allows you to " + u"define the url of a custom controller outputting " + u"any kind of report.", + ) } diff --git a/menu.xml b/menu.xml index 10a682cf..23589c9e 100644 --- a/menu.xml +++ b/menu.xml @@ -3,6 +3,6 @@ + parent="base.menu_custom" /> From c74ba0ed358e4648828c6c2c3275ed101e495de9 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Mon, 23 Feb 2015 17:17:04 +0100 Subject: [PATCH 44/78] Development of Py3o Parser to reproduce the behaviour of WebKit Report but using py3o engines --HG-- branch : odoo8 --- __init__.py | 4 -- __openerp__.py | 3 -- ir_report.py | 50 +++++++++++++++++++++++- py3o_parser.py | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 py3o_parser.py diff --git a/__init__.py b/__init__.py index 9071ae81..e75b483b 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1 @@ import ir_report -import py3o_report -import py3o_template -import py3o_server -import py3o_fusion_filetype diff --git a/__openerp__.py b/__openerp__.py index afff8ecb..49cb56cb 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -43,9 +43,6 @@ The py3o.template package is required; install it with: 'data': [ 'menu.xml', 'ir_report.xml', - 'py3o_template.xml', - 'py3o_server.xml', - 'data/py3o.fusion.filetype.csv', 'security/ir.model.access.csv', ], 'installable': True, diff --git a/ir_report.py b/ir_report.py index 7ae4c52f..7cc5458e 100644 --- a/ir_report.py +++ b/ir_report.py @@ -1,11 +1,15 @@ +import os from openerp.osv import fields, osv +from openerp.report.interface import report_int +from .py3o_parser import Py3oParser +from openerp import addons class report_xml(osv.Model): - ''' Inherit from ir.actions.report.xml to allow customizing the template + """ Inherit from ir.actions.report.xml to allow customizing the template file. The user cam chose a template from a list. The list is configurable in the configuration tab, see py3o_template.py - ''' + """ _inherit = 'ir.actions.report.xml' @@ -37,3 +41,45 @@ class report_xml(osv.Model): u"any kind of report.", ) } + + def _lookup_report(self, cr, name): + """ + Look up a report definition. + """ + + # First lookup in the deprecated place, because if the report + # definition has not been updated, it is more likely the correct + # definition is there. Only reports with custom parser + # specified in Python are still there. + if 'report.' + name in report_int._reports: + new_report = report_int._reports['report.' + name] + if not isinstance(new_report, Py3oParser): + new_report = None + else: + cr.execute( + 'SELECT * ' + 'FROM ir_act_report_xml ' + 'WHERE report_name=%s AND report_type=%s', + (name, 'py3o') + ) + r = cr.dictfetchone() + if r: + kwargs = {} + if r['parser']: + kwargs['parser'] = getattr(addons, r['parser']) + + new_report = Py3oParser( + 'report.' + r['report_name'], + r['model'], + os.path.join('addons', r['report_rml'] or '/'), + header=r['header'], + register=False, + **kwargs + ) + else: + new_report = None + + if new_report: + return new_report + else: + return super(report_xml, self)._lookup_report(cr, name) diff --git a/py3o_parser.py b/py3o_parser.py new file mode 100644 index 00000000..9e6e3aa5 --- /dev/null +++ b/py3o_parser.py @@ -0,0 +1,102 @@ +from openerp.report.report_sxw import report_sxw, rml_parse +from openerp import registry + + +_extender_functions = {} + + +def py3o_report_extender(report_name): + """ + A decorator to define function to extend the context sent to a template. + This will be called at the creation of the report. + The following arguments will be passed to it: + - pool: the model pool + - cr: the database cursor + - uid: the id of the user that call the renderer + - localcontext: The context that will be passed to the report engine + - context: the Odoo context + + Method copied from CampToCamp report_webkit module. + + :param report_name: xml id of the report + :return: + """ + def fct1(fct): + lst = _extender_functions.get(report_name) + if not lst: + lst = [] + _extender_functions[report_name] = lst + lst.append(fct) + return fct + return fct1 + + +class Py3oParser(report_sxw): + """Custom class that use Py3o to render libroffice reports. + Code partially taken from CampToCamp.""" + + def __init__(self, name, table, rml=False, parser=rml_parse, + header=False, store=False, register=True): + self.localcontext = {} + super(Py3oParser, self).__init__( + name, table, rml=rml, parser=parser, + header=header, store=store, register=register + ) + + def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None): + """ Overide this function to generate our py3o report + """ + if report_xml.report_type != 'py3o': + return super(Py3oParser, self).create_single_pdf( + cr, uid, ids, data, report_xml, context=context + ) + + pool = registry(cr.dbname) + model_data_ids = pool['ir.model.data'].search( + cr, uid, [ + ('model', '=', 'ir.actions.report.xml'), + ('res_id', '=', report_xml.id), + ] + ) + + xml_id = None + if model_data_ids: + model_data = pool['ir.model.data'].browse( + cr, uid, model_data_ids[0], context=context + ) + xml_id = '%s,%s' % (model_data.module, model_data.name) + + parser_instance = self.parser(cr, uid, self.name2, context=context) + parser_instance.set_context( + self.getObjects(cr, uid, ids, context), + data, ids, report_xml.report_type + ) + + if xml_id in _extender_functions: + for fct in _extender_functions[xml_id]: + pass + + def create(self, cr, uid, ids, data, context=None): + """ Override this function to handle our py3o report + """ + pool = registry(cr.dbname) + ir_action_report_obj = pool['ir.actions.report.xml'] + report_xml_ids = ir_action_report_obj.search( + cr, uid, [('report_name', '=', self.name[7:])], context=context + ) + if not report_xml_ids: + return super(Py3oParser, self).create( + cr, uid, ids, data, context=context + ) + + report_xml = ir_action_report_obj.browse( + cr, uid, report_xml_ids[0], context=context + ) + + result = self.create_source_pdf( + cr, uid, ids, data, report_xml, context + ) + + if not result: + return False, False + return result \ No newline at end of file From 59ab08e17933aecd7a8e96d127bab90f84e18533 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 24 Feb 2015 17:39:09 +0100 Subject: [PATCH 45/78] Py3o update for odoo 8 --HG-- branch : odoo8 --- __init__.py | 2 +- __openerp__.py | 7 ++- models/__init__.py | 4 ++ ir_report.py => models/ir_report.py | 2 +- .../py3o_fusion_filetype.py | 0 py3o_server.py => models/py3o_server.py | 0 py3o_template.py => models/py3o_template.py | 0 py3o_parser.py | 58 ++++++++++++++++++- ir_report.xml => views/ir_report.xml | 0 menu.xml => views/menu.xml | 4 +- py3o_server.xml => views/py3o_server.xml | 0 py3o_template.xml => views/py3o_template.xml | 0 12 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 models/__init__.py rename ir_report.py => models/ir_report.py (98%) rename py3o_fusion_filetype.py => models/py3o_fusion_filetype.py (100%) rename py3o_server.py => models/py3o_server.py (100%) rename py3o_template.py => models/py3o_template.py (100%) rename ir_report.xml => views/ir_report.xml (100%) rename menu.xml => views/menu.xml (60%) rename py3o_server.xml => views/py3o_server.xml (100%) rename py3o_template.xml => views/py3o_template.xml (100%) diff --git a/__init__.py b/__init__.py index e75b483b..2c4eac3f 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -import ir_report +import models \ No newline at end of file diff --git a/__openerp__.py b/__openerp__.py index 49cb56cb..40958720 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -41,9 +41,12 @@ The py3o.template package is required; install it with: 'python': ['py3o.template'] }, 'data': [ - 'menu.xml', - 'ir_report.xml', 'security/ir.model.access.csv', + + 'views/py3o_template.xml', + 'views/py3o_server.xml', + 'views/ir_report.xml', + 'views/menu.xml', ], 'installable': True, } diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 00000000..28989d9f --- /dev/null +++ b/models/__init__.py @@ -0,0 +1,4 @@ +import ir_report +import py3o_fusion_filetype +import py3o_template +import py3o_server \ No newline at end of file diff --git a/ir_report.py b/models/ir_report.py similarity index 98% rename from ir_report.py rename to models/ir_report.py index 7cc5458e..8ad1f999 100644 --- a/ir_report.py +++ b/models/ir_report.py @@ -1,7 +1,7 @@ import os from openerp.osv import fields, osv from openerp.report.interface import report_int -from .py3o_parser import Py3oParser +from ..py3o_parser import Py3oParser from openerp import addons diff --git a/py3o_fusion_filetype.py b/models/py3o_fusion_filetype.py similarity index 100% rename from py3o_fusion_filetype.py rename to models/py3o_fusion_filetype.py diff --git a/py3o_server.py b/models/py3o_server.py similarity index 100% rename from py3o_server.py rename to models/py3o_server.py diff --git a/py3o_template.py b/models/py3o_template.py similarity index 100% rename from py3o_template.py rename to models/py3o_template.py diff --git a/py3o_parser.py b/py3o_parser.py index 9e6e3aa5..8f1d6de1 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -1,5 +1,9 @@ +from base64 import b64decode +import requests +from tempfile import NamedTemporaryFile from openerp.report.report_sxw import report_sxw, rml_parse from openerp import registry +from py3o.template import Template _extender_functions = {} @@ -64,7 +68,7 @@ class Py3oParser(report_sxw): model_data = pool['ir.model.data'].browse( cr, uid, model_data_ids[0], context=context ) - xml_id = '%s,%s' % (model_data.module, model_data.name) + xml_id = '%s.%s' % (model_data.module, model_data.name) parser_instance = self.parser(cr, uid, self.name2, context=context) parser_instance.set_context( @@ -74,7 +78,57 @@ class Py3oParser(report_sxw): if xml_id in _extender_functions: for fct in _extender_functions[xml_id]: - pass + fct(pool, cr, uid, parser_instance.localcontext, context) + + template = report_xml.py3o_template_id + filetype = report_xml.py3o_fusion_filetype + +# py3o.template operates on filenames so create temporary files. + with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as \ + in_temp, \ + NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ + out_temp: + + in_temp.write(b64decode(template.py3o_template_data)) + in_temp.flush() + + template = Template(in_temp.name, out_temp.name) + + print parser_instance.localcontext + template.render(parser_instance.localcontext) + + out_temp.seek(0) + + if filetype.human_ext != 'odt': + # Now we ask fusion server to convert our template + fusion_server_obj = pool['py3o.server'] + fusion_server_id = fusion_server_obj.search( + cr, uid, [], context=context + )[0] + fusion_server = fusion_server_obj.browse( + cr, uid, fusion_server_id, context=context + ) + files = { + 'tmpl_file': out_temp, + } + fields = { + "targetformat": filetype.fusion_ext, + "datadict": "{}", + "image_mapping": "{}", + "skipfusion": True, + } + r = requests.post(fusion_server.url, data=fields, files=files) + chunk_size = 1024 + with NamedTemporaryFile( + suffix=filetype.human_ext, + prefix='py3o-template-' + ) as fd: + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + return fd.read(), filetype.human_ext + + return out_temp.read(), 'odt' def create(self, cr, uid, ids, data, context=None): """ Override this function to handle our py3o report diff --git a/ir_report.xml b/views/ir_report.xml similarity index 100% rename from ir_report.xml rename to views/ir_report.xml diff --git a/menu.xml b/views/menu.xml similarity index 60% rename from menu.xml rename to views/menu.xml index 23589c9e..4f26473f 100644 --- a/menu.xml +++ b/views/menu.xml @@ -2,7 +2,7 @@ + name="Py3o" + parent="report.reporting_menuitem" /> diff --git a/py3o_server.xml b/views/py3o_server.xml similarity index 100% rename from py3o_server.xml rename to views/py3o_server.xml diff --git a/py3o_template.xml b/views/py3o_template.xml similarity index 100% rename from py3o_template.xml rename to views/py3o_template.xml From f7f01b90317a6dce86935a46e37bd23331a69147 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Wed, 1 Apr 2015 15:26:12 +0200 Subject: [PATCH 46/78] Fix openerp.py xml order --HG-- branch : odoo8 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 40958720..02ad5516 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -43,10 +43,10 @@ The py3o.template package is required; install it with: 'data': [ 'security/ir.model.access.csv', + 'views/menu.xml', 'views/py3o_template.xml', 'views/py3o_server.xml', 'views/ir_report.xml', - 'views/menu.xml', ], 'installable': True, } From 9cbc9b233f5626affceee81f51828389fe1fdc83 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Fri, 22 May 2015 18:59:59 +0200 Subject: [PATCH 47/78] we depend on report --HG-- branch : odoo8 --- __openerp__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 02ad5516..6f4b12f8 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -35,7 +35,8 @@ The py3o.template package is required; install it with: 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', 'depends': [ - 'base' + 'base', + 'report' ], 'external_dependencies': { 'python': ['py3o.template'] From 0da8532800c10568a9bf0c7b2f20cd216e8a3d2f Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Thu, 28 May 2015 19:38:17 +0200 Subject: [PATCH 48/78] Fix some pep8 and mistakes --HG-- branch : odoo8 --- py3o_report.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/py3o_report.py b/py3o_report.py index 61b1d2ac..f79db301 100644 --- a/py3o_report.py +++ b/py3o_report.py @@ -1,9 +1,12 @@ from base64 import b64decode +import json from tempfile import NamedTemporaryFile from openerp.report.report_sxw import * +from openerp import pooler from py3o.template import Template +from py3o.template.helpers import Py3oConvertor import requests @@ -43,21 +46,26 @@ class py3o_report(report_sxw): # Find the report definition to get its settings. pool = pooler.get_pool(cr.dbname) report_xml_obj = pool.get('ir.actions.report.xml') - report_xml_ids = report_xml_obj.search(cr, uid, - [('report_name', '=', self.name[7:])], # Ignore "report." - context=context) + report_xml_ids = report_xml_obj.search( + cr, uid, [('report_name', '=', self.name[7:])], # Ignore "report." + context=context + ) if not report_xml_ids: - return super(py3o_report, self).create(cr, uid, ids, data, - context=context) - report_xml = report_xml_obj.browse(cr, uid, - report_xml_ids[0], - context=context) + return super(py3o_report, self).create( + cr, uid, ids, data, context=context + ) + report_xml = report_xml_obj.browse( + cr, uid, report_xml_ids[0], context=context + ) template = report_xml.py3o_template_id filetype = report_xml.py3o_fusion_filetype # py3o.template operates on filenames so create temporary files. - with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as in_temp: + with NamedTemporaryFile( + suffix='.odt', + prefix='py3o-template-', + ) as in_temp: in_temp.write(b64decode(template.py3o_template_data)) in_temp.flush() @@ -65,10 +73,14 @@ class py3o_report(report_sxw): template = Template(in_temp.name, None) - user_instruction_mapping = template.get_user_instructions_mapping() - values = user_instruction_mapping.jsonify( + expressions = template.get_all_user_python_expression() + py_expr = template.convert_py3o_to_python_ast(expressions) + p = Py3oConvertor() + res = p(py_expr) + + values = json.dumps(res.jsonify( self.get_values(cr, uid, ids, data, context) - ) + )) fusion_server_obj = pool['py3o.server'] fusion_server_id = fusion_server_obj.search( @@ -89,7 +101,8 @@ class py3o_report(report_sxw): chunk_size = 1024 with NamedTemporaryFile( suffix=filetype.human_ext, - prefix='py3o-template-') as fd: + prefix='py3o-template-' + ) as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) fd.seek(0) From d85f5ed292f32e86b06063149c8ee57b9c146224 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Fri, 29 May 2015 14:42:59 +0200 Subject: [PATCH 49/78] Real instructions to allow odoo to find the py3o.template module --HG-- branch : odoo8 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5aa113a..51709d3d 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,6 @@ Requirements ============ The py3o.template package is required; install it with: - pip install py3o.template + easy_install -UZ py3o.template From 7ac78667e13af9c02e7987a1ed06435b22819d19 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Fri, 29 May 2015 15:01:38 +0200 Subject: [PATCH 50/78] Just add the CSV to the data section --HG-- branch : odoo8 --- __openerp__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/__openerp__.py b/__openerp__.py index 6f4b12f8..d6bf976b 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -48,6 +48,8 @@ The py3o.template package is required; install it with: 'views/py3o_template.xml', 'views/py3o_server.xml', 'views/ir_report.xml', + + 'data/py3o.fusion.filetype.csv', ], 'installable': True, } From 8afaac709a63882dfb46e4555c405f4f67f1cfca Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Mon, 1 Jun 2015 15:20:12 +0200 Subject: [PATCH 51/78] pep ftw --HG-- branch : odoo8 --- py3o_parser.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/py3o_parser.py b/py3o_parser.py index 8f1d6de1..6414071b 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -37,7 +37,7 @@ def py3o_report_extender(report_name): class Py3oParser(report_sxw): """Custom class that use Py3o to render libroffice reports. - Code partially taken from CampToCamp.""" + Code partially taken from CampToCamp's webkit_report.""" def __init__(self, name, table, rml=False, parser=rml_parse, header=False, store=False, register=True): @@ -84,10 +84,11 @@ class Py3oParser(report_sxw): filetype = report_xml.py3o_fusion_filetype # py3o.template operates on filenames so create temporary files. - with NamedTemporaryFile(suffix='.odt', prefix='py3o-template-') as \ - in_temp, \ - NamedTemporaryFile(suffix='.odt', prefix='py3o-report-') as \ - out_temp: + with NamedTemporaryFile( + suffix='.odt', + prefix='py3o-template-') as in_temp, NamedTemporaryFile( + suffix='.odt', + prefix='py3o-report-') as out_temp: in_temp.write(b64decode(template.py3o_template_data)) in_temp.flush() @@ -153,4 +154,4 @@ class Py3oParser(report_sxw): if not result: return False, False - return result \ No newline at end of file + return result From c99b682cf48d9266df2140d58833f71521c57d76 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Tue, 2 Jun 2015 09:50:06 +0200 Subject: [PATCH 52/78] Output format is MANDATORY... if you don't give it will fail horribly (ie: fusion running at 100% cpu without traceback or info..) This is clearly a bug in fusion, but better fix it here too --HG-- branch : odoo8 --- models/ir_report.py | 1 + 1 file changed, 1 insertion(+) diff --git a/models/ir_report.py b/models/ir_report.py index 8ad1f999..6c53a8e4 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -17,6 +17,7 @@ class report_xml(osv.Model): 'py3o_fusion_filetype': fields.many2one( 'py3o.fusion.filetype', u"Output Format", + required=True, ), 'py3o_template_id': fields.many2one( 'py3o.template', From 2c47a47082083456fa49c61dd1b947d8ec534d55 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Tue, 2 Jun 2015 09:50:22 +0200 Subject: [PATCH 53/78] better docstring --HG-- branch : odoo8 --- models/ir_report.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/ir_report.py b/models/ir_report.py index 6c53a8e4..d0feb2af 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -44,8 +44,7 @@ class report_xml(osv.Model): } def _lookup_report(self, cr, name): - """ - Look up a report definition. + """Look up a report definition. """ # First lookup in the deprecated place, because if the report From ef01166fdf3bce931c4e914eff0af2fbbda07059 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Tue, 2 Jun 2015 09:51:15 +0200 Subject: [PATCH 54/78] Adding a fallback system so that you own implementer module can define its default template --HG-- branch : odoo8 --- models/ir_report.py | 12 ++++++++ py3o_parser.py | 68 ++++++++++++++++++++++++++++++++++++++++++--- views/ir_report.xml | 2 ++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/models/ir_report.py b/models/ir_report.py index d0feb2af..eb43ebe9 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -23,6 +23,18 @@ class report_xml(osv.Model): 'py3o.template', u"Template", ), + 'module': fields.char( + u"Module", + size=64, + help=u"The implementer module that provides this report", + ), + 'py3o_template_fallback': fields.char( + u"Fallback", + size=128, + help=(u"If the user does not provide a template this will be used " + u"it should be a relattive path to root of YOUR module", + ), + ), 'report_type': fields.selection( [ ('qweb-pdf', u"PDF"), diff --git a/py3o_parser.py b/py3o_parser.py index 6414071b..06dafc98 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -1,14 +1,25 @@ +# -*- encoding: utf-8 -*- +import pkg_resources +import os +import sys from base64 import b64decode import requests from tempfile import NamedTemporaryFile +from openerp import _ from openerp.report.report_sxw import report_sxw, rml_parse from openerp import registry +from openerp.exceptions import DeferredException + from py3o.template import Template _extender_functions = {} +class TemplateNotFound(DeferredException): + pass + + def py3o_report_extender(report_name): """ A decorator to define function to extend the context sent to a template. @@ -23,7 +34,7 @@ def py3o_report_extender(report_name): Method copied from CampToCamp report_webkit module. :param report_name: xml id of the report - :return: + :return: a decorated class """ def fct1(fct): lst = _extender_functions.get(report_name) @@ -47,6 +58,55 @@ class Py3oParser(report_sxw): header=header, store=store, register=register ) + def get_template(self, report_obj): + """private helper to fetch the template data either from the database + or from the default template file provided by the implementer. + + ATM this method takes a report definition recordset + to try and fetch the report template from database. If not found it will + fallback to the template file referenced in the report definition. + + @param report_obj: a recordset representing the report defintion + @type report_obj: openerp.model.recordset instance + + @returns: string or buffer containing the template data + + @raises: TemplateNotFound which is a subclass of + openerp.exceptions.DeferredException + """ + + tmpl_data = None + + if report_obj.py3o_template_id and report_obj.py3o_template_id.id: + # if a user gave a report template + tmpl_data = b64decode( + report_obj.py3o_template_id.py3o_template_data + ) + + elif report_obj.py3o_template_fallback and report_obj.module: + # if the default is defined + flbk_filename = pkg_resources.resource_filename( + "openerp.addons.%s" % report_obj.module, + report_obj.py3o_template_fallback, + ) + if os.path.exists(flbk_filename): + # and it exists on the fileystem + with open(flbk_filename, 'r') as tmpl: + tmpl_data = tmpl.read() + + if tmpl_data is None: + # if for any reason the template is not found + print("*"*35) + print("Template filename: %s" % flbk_filename) + print("*"*35) + + raise TemplateNotFound( + _(u'No template found. Aborting.'), + sys.exc_info(), + ) + + return tmpl_data + def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None): """ Overide this function to generate our py3o report """ @@ -83,6 +143,8 @@ class Py3oParser(report_sxw): template = report_xml.py3o_template_id filetype = report_xml.py3o_fusion_filetype + tmpl_data = self.get_template(report_xml) + # py3o.template operates on filenames so create temporary files. with NamedTemporaryFile( suffix='.odt', @@ -90,12 +152,10 @@ class Py3oParser(report_sxw): suffix='.odt', prefix='py3o-report-') as out_temp: - in_temp.write(b64decode(template.py3o_template_data)) + in_temp.write(tmpl_data) in_temp.flush() template = Template(in_temp.name, out_temp.name) - - print parser_instance.localcontext template.render(parser_instance.localcontext) out_temp.seek(0) diff --git a/views/ir_report.xml b/views/ir_report.xml index d4521c76..a5586aa4 100644 --- a/views/ir_report.xml +++ b/views/ir_report.xml @@ -16,6 +16,8 @@ + + From f71cbbb92de560c6e99e8558b7dd450048a35af0 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Tue, 2 Jun 2015 10:19:55 +0200 Subject: [PATCH 55/78] removed unused file --HG-- branch : odoo8 --- py3o_report.py | 109 ------------------------------------------------- 1 file changed, 109 deletions(-) delete mode 100644 py3o_report.py diff --git a/py3o_report.py b/py3o_report.py deleted file mode 100644 index f79db301..00000000 --- a/py3o_report.py +++ /dev/null @@ -1,109 +0,0 @@ -from base64 import b64decode -import json -from tempfile import NamedTemporaryFile - -from openerp.report.report_sxw import * -from openerp import pooler - -from py3o.template import Template -from py3o.template.helpers import Py3oConvertor - -import requests - - -class py3o_report(report_sxw): - # def __init__(self, name, table): - # super(py3o_report, self).__init__(name, table) - - def get_values(self, cr, uid, ids, data, context): - """ Override this function to customize the dictionary given to the - py3o.template renderer. """ - - return { - 'lang': self.get_lang(cr, uid, context), - 'objects': self.getObjects(cr, uid, ids, context), - } - - @staticmethod - def get_lang(cr, uid, context): - pool = pooler.get_pool(cr.dbname) - lang_obj = pool.get('res.lang') - user_obj = pool.get('res.users') - - lang_code = user_obj.browse(cr, uid, uid, context=context).lang - lang = lang_obj.search(cr, uid, - [('code', '=', lang_code)], - context=context)[0] - return lang_obj.browse(cr, uid, lang, context=context) - - @staticmethod - def format_date(date, values): - """ Return a date formatted according to the language extracted from - the "values" argument (which should be the result of get_values). """ - return date.strftime(values['lang'].date_format) - - def create(self, cr, uid, ids, data, context=None): - # Find the report definition to get its settings. - pool = pooler.get_pool(cr.dbname) - report_xml_obj = pool.get('ir.actions.report.xml') - report_xml_ids = report_xml_obj.search( - cr, uid, [('report_name', '=', self.name[7:])], # Ignore "report." - context=context - ) - if not report_xml_ids: - return super(py3o_report, self).create( - cr, uid, ids, data, context=context - ) - report_xml = report_xml_obj.browse( - cr, uid, report_xml_ids[0], context=context - ) - - template = report_xml.py3o_template_id - filetype = report_xml.py3o_fusion_filetype - - # py3o.template operates on filenames so create temporary files. - with NamedTemporaryFile( - suffix='.odt', - prefix='py3o-template-', - ) as in_temp: - - in_temp.write(b64decode(template.py3o_template_data)) - in_temp.flush() - in_temp.seek(0) - - template = Template(in_temp.name, None) - - expressions = template.get_all_user_python_expression() - py_expr = template.convert_py3o_to_python_ast(expressions) - p = Py3oConvertor() - res = p(py_expr) - - values = json.dumps(res.jsonify( - self.get_values(cr, uid, ids, data, context) - )) - - fusion_server_obj = pool['py3o.server'] - fusion_server_id = fusion_server_obj.search( - cr, uid, [], context=context - )[0] - fusion_server = fusion_server_obj.browse( - cr, uid, fusion_server_id, context=context - ) - files = { - 'tmpl_file': in_temp, - } - fields = { - "targetformat": filetype.fusion_ext, - "datadict": values, - "image_mapping": "{}", - } - r = requests.post(fusion_server.url, data=fields, files=files) - chunk_size = 1024 - with NamedTemporaryFile( - suffix=filetype.human_ext, - prefix='py3o-template-' - ) as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) - fd.seek(0) - return fd.read(), filetype.human_ext From 1dee92362fdb5b42f4b46bca578456929204b766 Mon Sep 17 00:00:00 2001 From: Florent Aide Date: Thu, 4 Jun 2015 00:52:59 +0200 Subject: [PATCH 56/78] Now support latest fusion server & better error reporting --HG-- branch : odoo8 --- data/py3o.fusion.filetype.csv | 10 ++++----- py3o_parser.py | 40 ++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/data/py3o.fusion.filetype.csv b/data/py3o.fusion.filetype.csv index f0e11e8b..503c6da1 100644 --- a/data/py3o.fusion.filetype.csv +++ b/data/py3o.fusion.filetype.csv @@ -1,6 +1,6 @@ id,fusion_ext,human_ext -py3o_fusion_filetype_odt,ODT,odt -py3o_fusion_filetype_ods,ODS,ods -py3o_fusion_filetype_doc,DOC,doc -py3o_fusion_filetype_docx,DOCX,docx -py3o_fusion_filetype_pdf,PDF,pdf +py3o_fusion_filetype_odt,odt,odt +py3o_fusion_filetype_ods,ods,ods +py3o_fusion_filetype_doc,doc,doc +py3o_fusion_filetype_docx,docx,docx +py3o_fusion_filetype_pdf,pdf,pdf diff --git a/py3o_parser.py b/py3o_parser.py index 06dafc98..77611eb4 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -8,7 +8,7 @@ from tempfile import NamedTemporaryFile from openerp import _ from openerp.report.report_sxw import report_sxw, rml_parse from openerp import registry -from openerp.exceptions import DeferredException +from openerp.exceptions import ValidationError from py3o.template import Template @@ -16,7 +16,7 @@ from py3o.template import Template _extender_functions = {} -class TemplateNotFound(DeferredException): +class TemplateNotFound(Exception): pass @@ -96,10 +96,6 @@ class Py3oParser(report_sxw): if tmpl_data is None: # if for any reason the template is not found - print("*"*35) - print("Template filename: %s" % flbk_filename) - print("*"*35) - raise TemplateNotFound( _(u'No template found. Aborting.'), sys.exc_info(), @@ -160,6 +156,10 @@ class Py3oParser(report_sxw): out_temp.seek(0) + # TODO: use py3o.formats to know native formats instead + # of hardcoding this value + # TODO: why use the human readable form when you're a machine? + # this is non-sense AND dangerous... please use technical name if filetype.human_ext != 'odt': # Now we ask fusion server to convert our template fusion_server_obj = pool['py3o.server'] @@ -178,16 +178,26 @@ class Py3oParser(report_sxw): "image_mapping": "{}", "skipfusion": True, } + # Here is a little joke about Odoo + # we do nice chunked reading from the network... r = requests.post(fusion_server.url, data=fields, files=files) - chunk_size = 1024 - with NamedTemporaryFile( - suffix=filetype.human_ext, - prefix='py3o-template-' - ) as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) - fd.seek(0) - return fd.read(), filetype.human_ext + if r.status_code == 400: + # server says we have an issue... let's to that + raise ValidationError( + r.json(), + ) + + else: + chunk_size = 1024 + with NamedTemporaryFile( + suffix=filetype.human_ext, + prefix='py3o-template-' + ) as fd: + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + # ... but odoo wants the whole data in memory anyways :) + return fd.read(), filetype.human_ext return out_temp.read(), 'odt' From 214e25c63e93b77caa4bbbd9f670602ae63ccc5c Mon Sep 17 00:00:00 2001 From: Brendan Masson Date: Thu, 4 Jun 2015 19:03:14 +0200 Subject: [PATCH 57/78] removed "required" constraint; --HG-- branch : odoo8 --- models/ir_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/ir_report.py b/models/ir_report.py index eb43ebe9..b8d85eb1 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -14,10 +14,10 @@ class report_xml(osv.Model): _inherit = 'ir.actions.report.xml' _columns = { + # TODO required when report_type type is py3o, add python constraint 'py3o_fusion_filetype': fields.many2one( 'py3o.fusion.filetype', u"Output Format", - required=True, ), 'py3o_template_id': fields.many2one( 'py3o.template', From 6439ca8d62d02d6144b3cd9048579f5616851678 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 1 Sep 2015 12:42:50 +0200 Subject: [PATCH 58/78] 2.0b1 --HG-- branch : odoo8 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index d6bf976b..b2e40c2e 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -30,7 +30,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '1.3.1', + 'version': '2.0b1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', From 87f8fac08a7c93c834d0bdd230a1ddec30d7e6ab Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 1 Sep 2015 12:42:58 +0200 Subject: [PATCH 59/78] Added tag TAG_2.0b1 for changeset 801e4bf837a2 --HG-- branch : odoo8 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6eed60f8..1269f5e7 100644 --- a/.hgtags +++ b/.hgtags @@ -8,3 +8,4 @@ d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 067b603cc82e6403b66fedd1636f50ff104c3fee TAG_1.2.5 ce6b34e125174856e86c108399dfbb0eb84a7418 TAG_1.3 a9d3f37477695c6255e7f603fa47defcfbd3a2af TAG_1.3.1 +801e4bf837a28a824637570ec19bd6bc148c6837 TAG_2.0b1 From e30b1ba5160530b0c014e8201a63a0deda2edc2c Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Mon, 9 Nov 2015 15:24:10 +0100 Subject: [PATCH 60/78] Use the latest features of py3o.template with odoo8 --HG-- branch : odoo8 --- py3o_parser.py | 129 +++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/py3o_parser.py b/py3o_parser.py index 77611eb4..793bfcb3 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -1,4 +1,6 @@ # -*- encoding: utf-8 -*- +from cStringIO import StringIO +import json import pkg_resources import os import sys @@ -6,10 +8,12 @@ from base64 import b64decode import requests from tempfile import NamedTemporaryFile from openerp import _ +from openerp import exceptions from openerp.report.report_sxw import report_sxw, rml_parse from openerp import registry from openerp.exceptions import ValidationError +from py3o.template.helpers import Py3oConvertor from py3o.template import Template @@ -120,11 +124,14 @@ class Py3oParser(report_sxw): ) xml_id = None - if model_data_ids: - model_data = pool['ir.model.data'].browse( - cr, uid, model_data_ids[0], context=context + if not model_data_ids: + raise exceptions.MissingError( + _(u"Report %s not found" % report_xml) ) - xml_id = '%s.%s' % (model_data.module, model_data.name) + model_data = pool['ir.model.data'].browse( + cr, uid, model_data_ids[0], context=context + ) + xml_id = '%s.%s' % (model_data.module, model_data.name) parser_instance = self.parser(cr, uid, self.name2, context=context) parser_instance.set_context( @@ -136,70 +143,64 @@ class Py3oParser(report_sxw): for fct in _extender_functions[xml_id]: fct(pool, cr, uid, parser_instance.localcontext, context) - template = report_xml.py3o_template_id + tmpl_data = self.get_template(report_xml) + + in_stream = StringIO(tmpl_data) + out_stream = StringIO() + template = Template(in_stream, out_stream) + expressions = template.get_all_user_python_expression() + py_expression = template.convert_py3o_to_python_ast(expressions) + convertor = Py3oConvertor() + data_struct = convertor(py_expression) + filetype = report_xml.py3o_fusion_filetype - tmpl_data = self.get_template(report_xml) + datadict = parser_instance.localcontext + + res = data_struct.render(datadict) + + fusion_server_obj = pool.get('py3o.server') + fusion_server_ids = fusion_server_obj.search( + cr, uid, [], context=context + ) + if not fusion_server_ids: + raise exceptions.MissingError( + _(u"No Py3o server configuration found") + ) + fusion_server_id = fusion_server_ids[0] + + fusion_server = fusion_server_obj.browse( + cr, uid, fusion_server_id, context=context + ) + in_stream.seek(0) + files = { + 'tmpl_file': in_stream, + } + fields = { + "targetformat": filetype.fusion_ext, + "datadict": json.dumps(res), + "image_mapping": "{}", + } + r = requests.post(fusion_server.url, data=fields, files=files) + if r.status_code != 200: + # server says we have an issue... let's tell that to enduser + raise exceptions.Warning( + _('Fusion server error'), + r.text, + ) -# py3o.template operates on filenames so create temporary files. + # Here is a little joke about Odoo + # we do nice chunked reading from the network... + chunk_size = 1024 with NamedTemporaryFile( - suffix='.odt', - prefix='py3o-template-') as in_temp, NamedTemporaryFile( - suffix='.odt', - prefix='py3o-report-') as out_temp: - - in_temp.write(tmpl_data) - in_temp.flush() - - template = Template(in_temp.name, out_temp.name) - template.render(parser_instance.localcontext) - - out_temp.seek(0) - - # TODO: use py3o.formats to know native formats instead - # of hardcoding this value - # TODO: why use the human readable form when you're a machine? - # this is non-sense AND dangerous... please use technical name - if filetype.human_ext != 'odt': - # Now we ask fusion server to convert our template - fusion_server_obj = pool['py3o.server'] - fusion_server_id = fusion_server_obj.search( - cr, uid, [], context=context - )[0] - fusion_server = fusion_server_obj.browse( - cr, uid, fusion_server_id, context=context - ) - files = { - 'tmpl_file': out_temp, - } - fields = { - "targetformat": filetype.fusion_ext, - "datadict": "{}", - "image_mapping": "{}", - "skipfusion": True, - } - # Here is a little joke about Odoo - # we do nice chunked reading from the network... - r = requests.post(fusion_server.url, data=fields, files=files) - if r.status_code == 400: - # server says we have an issue... let's to that - raise ValidationError( - r.json(), - ) - - else: - chunk_size = 1024 - with NamedTemporaryFile( - suffix=filetype.human_ext, - prefix='py3o-template-' - ) as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) - fd.seek(0) - # ... but odoo wants the whole data in memory anyways :) - return fd.read(), filetype.human_ext - - return out_temp.read(), 'odt' + suffix=filetype.human_ext, + prefix='py3o-template-' + ) as fd: + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + # ... but odoo wants the whole data in memory anyways :) + return fd.read(), filetype.human_ext def create(self, cr, uid, ids, data, context=None): """ Override this function to handle our py3o report From 27155d26e8bb2b55f21d269e9b615482dc2921a3 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Mon, 9 Nov 2015 15:25:29 +0100 Subject: [PATCH 61/78] TAG_2.0b2 --HG-- branch : odoo8 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index b2e40c2e..905d6ef2 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -30,7 +30,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '2.0b1', + 'version': '2.0b2', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', From da9566cf0c21b19ca66790cc0acf5bd616f69d3f Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Mon, 9 Nov 2015 15:25:35 +0100 Subject: [PATCH 62/78] Added tag TAG_2.0b2 for changeset 2e68df0df26d --HG-- branch : odoo8 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 1269f5e7..c278154f 100644 --- a/.hgtags +++ b/.hgtags @@ -9,3 +9,4 @@ d6fa2a1477bc1f7a3590eb425ab7f907779cb732 TAG_1.2.4 ce6b34e125174856e86c108399dfbb0eb84a7418 TAG_1.3 a9d3f37477695c6255e7f603fa47defcfbd3a2af TAG_1.3.1 801e4bf837a28a824637570ec19bd6bc148c6837 TAG_2.0b1 +2e68df0df26d1dbcb28b30f8b626d8b237650751 TAG_2.0b2 From aacb84e23d1bd45e4d5ddff64e4b7e71981c5f3c Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 1 Dec 2015 15:34:02 +0100 Subject: [PATCH 63/78] i18n --HG-- branch : odoo8 --- i18n/fr.po | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 i18n/fr.po diff --git a/i18n/fr.po b/i18n/fr.po new file mode 100644 index 00000000..39653c67 --- /dev/null +++ b/i18n/fr.po @@ -0,0 +1,163 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * report_py3o +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-11-16 11:15+0000\n" +"PO-Revision-Date: 2015-11-27 14:56+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"Language: fr\n" +"X-Generator: Poedit 1.8.6\n" + +#. module: report_py3o +#: code:addons/report_py3o/py3o_parser.py:169 +#, python-format +msgid "Configuration Error" +msgstr "Erreur de configuration " + +#. module: report_py3o +#: field:py3o.fusion.filetype,create_uid:0 field:py3o.server,create_uid:0 +#: field:py3o.template,create_uid:0 +msgid "Created by" +msgstr "Créé par " + +#. module: report_py3o +#: field:py3o.fusion.filetype,create_date:0 field:py3o.server,create_date:0 +#: field:py3o.template,create_date:0 +msgid "Created on" +msgstr "Créé le " + +#. module: report_py3o +#: field:ir.actions.report.xml,py3o_template_fallback:0 +msgid "Fallback" +msgstr "Procédure de recours" + +#. module: report_py3o +#: field:py3o.fusion.filetype,fusion_ext:0 +msgid "Fusion Extension" +msgstr "Fusion Extension" + +#. module: report_py3o +#: code:addons/report_py3o/py3o_parser.py:190 +#, python-format +msgid "Fusion Server Says Error" +msgstr "Serveur Fusion affiche Erreur" + +#. module: report_py3o +#: field:py3o.fusion.filetype,human_ext:0 +msgid "Human readble extension" +msgstr "Extension facilement lisible" + +#. module: report_py3o +#: field:py3o.fusion.filetype,id:0 field:py3o.server,id:0 +#: field:py3o.template,id:0 +msgid "ID" +msgstr "ID" + +#. module: report_py3o +#: help:ir.actions.report.xml,py3o_template_fallback:0 +msgid "If the user does not provide a template this will be used it should be a relative path to root of YOUR module" +msgstr "If the user does not provide a template this will be used it should be a relative path to root of YOUR module" + +#. module: report_py3o +#: field:py3o.fusion.filetype,write_uid:0 field:py3o.server,write_uid:0 +#: field:py3o.template,write_uid:0 +msgid "Last Updated by" +msgstr "Dernière mise à jour par " + +#. module: report_py3o +#: field:py3o.fusion.filetype,write_date:0 field:py3o.server,write_date:0 +#: field:py3o.template,write_date:0 +msgid "Last Updated on" +msgstr "Dernière mise à jour le " + +#. module: report_py3o +#: view:ir.actions.report.xml:report_py3o.py3o_report_view +#: field:py3o.template,py3o_template_data:0 +msgid "LibreOffice template" +msgstr "LibreOffice template" + +#. module: report_py3o +#: field:ir.actions.report.xml,module:0 +msgid "Module" +msgstr "Module" + +#. module: report_py3o +#: field:py3o.template,name:0 +msgid "Name" +msgstr "Nom" + +#. module: report_py3o +#: code:addons/report_py3o/py3o_parser.py:170 +#, python-format +msgid "No Py3o server configuration found" +msgstr "Pas de configuration trouvée du serveur Py3o" + +#. module: report_py3o +#: field:ir.actions.report.xml,py3o_fusion_filetype:0 +msgid "Output Format" +msgstr "Format de sortie" + +#. module: report_py3o +#: model:ir.ui.menu,name:report_py3o.py3o_config_menu +msgid "Py3o" +msgstr "Py3o" + +#. module: report_py3o +#: model:ir.ui.menu,name:report_py3o.py3o_server_configuration_menu +#: view:py3o.server:report_py3o.py3o_server_configuration_form_view +#: view:py3o.server:report_py3o.py3o_server_configuration_tree_view +msgid "Py3o Server Configuration" +msgstr "Configuration du serveur Py3o" + +#. module: report_py3o +#: model:ir.ui.menu,name:report_py3o.py3o_template_configuration_menu +msgid "Py3o Templates" +msgstr "Py3o Templates" + +#. module: report_py3o +#: model:ir.actions.act_window,name:report_py3o.py3o_template_configuration_action +#: view:py3o.template:report_py3o.py3o_template_configuration_form_view +#: view:py3o.template:report_py3o.py3o_template_configuration_tree_view +msgid "Py3o Templates Configuration" +msgstr "Py3o Templates Configuration" + +#. module: report_py3o +#: code:addons/report_py3o/py3o_parser.py:130 +#, python-format +msgid "Report definition %s not found" +msgstr "Report definition %s not found" + +#. module: report_py3o +#: field:ir.actions.report.xml,py3o_template_id:0 +msgid "Template" +msgstr "Template" + +#. module: report_py3o +#: code:addons/report_py3o/py3o_parser.py:105 +#, python-format +msgid "Template Not Found" +msgstr "Template non trouvé" + +#. module: report_py3o +#: help:ir.actions.report.xml,module:0 +msgid "The implementer module that provides this report" +msgstr "The implementer module that provides this report" + +#. module: report_py3o +#: field:py3o.server,url:0 +msgid "URL" +msgstr "URL" + +#. module: report_py3o +#: model:ir.actions.act_window,name:report_py3o.py3o_server_configuration_action +msgid "py3o.server.configuration.action" +msgstr "py3o.server.configuration.action" From 2feb6accf3654c4b246725a806f3f2c4ea32428c Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 1 Dec 2015 15:35:09 +0100 Subject: [PATCH 64/78] 2.0 --HG-- branch : odoo8 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 905d6ef2..6b479c51 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -30,7 +30,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '2.0b2', + 'version': '2.0', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', From 7c6388566d28a710d7a9b1f6151fc978915eb820 Mon Sep 17 00:00:00 2001 From: Anael Lorimier Date: Tue, 1 Dec 2015 15:35:21 +0100 Subject: [PATCH 65/78] Added tag TAG_8.0.2.0 for changeset 77b8df614816 --HG-- branch : odoo8 --- .hgtags | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgtags b/.hgtags index c278154f..7520c187 100644 --- a/.hgtags +++ b/.hgtags @@ -10,3 +10,5 @@ ce6b34e125174856e86c108399dfbb0eb84a7418 TAG_1.3 a9d3f37477695c6255e7f603fa47defcfbd3a2af TAG_1.3.1 801e4bf837a28a824637570ec19bd6bc148c6837 TAG_2.0b1 2e68df0df26d1dbcb28b30f8b626d8b237650751 TAG_2.0b2 +0118ec4a766ed2a279ac2d6caaf71e0c3db0023b TAG_8.0.2.0 +77b8df6148164972274ab8246a56e053357d61ca TAG_8.0.2.0 From 4f2776c2d324bb6b61ac2c19d042ea05894dee22 Mon Sep 17 00:00:00 2001 From: Szeka Wong Date: Tue, 9 Feb 2016 10:16:57 +0100 Subject: [PATCH 66/78] 8.0.2.1 Fixed bug -> removed raise exception when no xml id found. --HG-- branch : odoo8 --- __openerp__.py | 2 +- py3o_parser.py | 11 ++++------- py3o_report_modif.py | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/__openerp__.py b/__openerp__.py index 6b479c51..328da8e6 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -30,7 +30,7 @@ templates. The py3o.template package is required; install it with: pip install py3o.template ''', - 'version': '2.0', + 'version': '8.0.2.1', 'category': 'Reporting', 'author': 'XCG Consulting', 'website': 'http://odoo.consulting/', diff --git a/py3o_parser.py b/py3o_parser.py index 793bfcb3..2a345889 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -124,14 +124,11 @@ class Py3oParser(report_sxw): ) xml_id = None - if not model_data_ids: - raise exceptions.MissingError( - _(u"Report %s not found" % report_xml) + if model_data_ids: + model_data = pool['ir.model.data'].browse( + cr, uid, model_data_ids[0], context=context ) - model_data = pool['ir.model.data'].browse( - cr, uid, model_data_ids[0], context=context - ) - xml_id = '%s.%s' % (model_data.module, model_data.name) + xml_id = '%s.%s' % (model_data.module, model_data.name) parser_instance = self.parser(cr, uid, self.name2, context=context) parser_instance.set_context( diff --git a/py3o_report_modif.py b/py3o_report_modif.py index 5c474835..0e496efb 100644 --- a/py3o_report_modif.py +++ b/py3o_report_modif.py @@ -51,6 +51,7 @@ class py3o_report(report_sxw): report_xml_ids = report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], # Ignore "report." context=context) + if not report_xml_ids: return super(py3o_report, self).create(cr, uid, ids, data, context=context) From 1d332217671f470c05168f588a52ec8dc33fdc45 Mon Sep 17 00:00:00 2001 From: Szeka Wong Date: Tue, 9 Feb 2016 10:17:28 +0100 Subject: [PATCH 67/78] =?UTF-8?q?=C3=89tiquette=20TAG=5F8.0.2.1=20ajout?= =?UTF-8?q?=C3=A9e=20=C3=A0=20la=20r=C3=A9vision=2065b3c62a20f1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- branch : odoo8 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 7520c187..41e72145 100644 --- a/.hgtags +++ b/.hgtags @@ -12,3 +12,4 @@ a9d3f37477695c6255e7f603fa47defcfbd3a2af TAG_1.3.1 2e68df0df26d1dbcb28b30f8b626d8b237650751 TAG_2.0b2 0118ec4a766ed2a279ac2d6caaf71e0c3db0023b TAG_8.0.2.0 77b8df6148164972274ab8246a56e053357d61ca TAG_8.0.2.0 +65b3c62a20f1f7f06c36783bc3fa2cc52dd8a0b3 TAG_8.0.2.1 From 49defabe881a511ca3932cb7fe602ee6f1bba922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Wed, 9 Mar 2016 12:17:53 +0100 Subject: [PATCH 68/78] Restore direct rendering for native ODT output formats --HG-- branch : odoo8 --- models/py3o_template.py | 13 ++++++ py3o_parser.py | 90 ++++++++++++++++++++++------------------- views/py3o_template.xml | 2 + 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/models/py3o_template.py b/models/py3o_template.py index c5392922..44f6ddcf 100644 --- a/models/py3o_template.py +++ b/models/py3o_template.py @@ -8,7 +8,20 @@ class py3o_template(osv.Model): 'name': fields.char( u"Name", ), + 'py3o_template_data': fields.binary( u"LibreOffice template", ), + + 'filetype': fields.selection( + [ + ('odt', u"ODF Text Document"), + ('ods', u"ODF Spreadsheet"), + ], + u"LibreOffice Template File Type", + ), + } + + _defaults = { + 'filetype': 'odt' } diff --git a/py3o_parser.py b/py3o_parser.py index 2a345889..67f5b17b 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -154,50 +154,58 @@ class Py3oParser(report_sxw): datadict = parser_instance.localcontext - res = data_struct.render(datadict) + parsed_datadict = data_struct.render(datadict) - fusion_server_obj = pool.get('py3o.server') - fusion_server_ids = fusion_server_obj.search( - cr, uid, [], context=context - ) - if not fusion_server_ids: - raise exceptions.MissingError( - _(u"No Py3o server configuration found") - ) - fusion_server_id = fusion_server_ids[0] + if filetype.fusion_ext == report_xml.py3o_template_id.filetype: + # No format conversion is needed, render the template directly + template.render(parsed_datadict) + res = out_stream.getvalue() - fusion_server = fusion_server_obj.browse( - cr, uid, fusion_server_id, context=context - ) - in_stream.seek(0) - files = { - 'tmpl_file': in_stream, - } - fields = { - "targetformat": filetype.fusion_ext, - "datadict": json.dumps(res), - "image_mapping": "{}", - } - r = requests.post(fusion_server.url, data=fields, files=files) - if r.status_code != 200: - # server says we have an issue... let's tell that to enduser - raise exceptions.Warning( - _('Fusion server error'), - r.text, + else: # Call py3o.server to render the template in the desired format + fusion_server_obj = pool.get('py3o.server') + fusion_server_ids = fusion_server_obj.search( + cr, uid, [], context=context ) - - # Here is a little joke about Odoo - # we do nice chunked reading from the network... - chunk_size = 1024 - with NamedTemporaryFile( - suffix=filetype.human_ext, - prefix='py3o-template-' - ) as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) - fd.seek(0) - # ... but odoo wants the whole data in memory anyways :) - return fd.read(), filetype.human_ext + if not fusion_server_ids: + raise exceptions.MissingError( + _(u"No Py3o server configuration found") + ) + fusion_server_id = fusion_server_ids[0] + + fusion_server = fusion_server_obj.browse( + cr, uid, fusion_server_id, context=context + ) + in_stream.seek(0) + files = { + 'tmpl_file': in_stream, + } + fields = { + "targetformat": filetype.fusion_ext, + "datadict": json.dumps(parsed_datadict), + "image_mapping": "{}", + } + r = requests.post(fusion_server.url, data=fields, files=files) + if r.status_code != 200: + # server says we have an issue... let's tell that to enduser + raise exceptions.Warning( + _('Fusion server error'), + r.text, + ) + + # Here is a little joke about Odoo + # we do nice chunked reading from the network... + chunk_size = 1024 + with NamedTemporaryFile( + suffix=filetype.human_ext, + prefix='py3o-template-' + ) as fd: + for chunk in r.iter_content(chunk_size): + fd.write(chunk) + fd.seek(0) + # ... but odoo wants the whole data in memory anyways :) + res = fd.read() + + return res, filetype.human_ext def create(self, cr, uid, ids, data, context=None): """ Override this function to handle our py3o report diff --git a/views/py3o_template.xml b/views/py3o_template.xml index 62625b52..6bb910a2 100644 --- a/views/py3o_template.xml +++ b/views/py3o_template.xml @@ -9,6 +9,7 @@ + @@ -22,6 +23,7 @@ + From ab49206f7283b7c80dcadac0a7ecdefc8ea13841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Wed, 9 Mar 2016 12:18:31 +0100 Subject: [PATCH 69/78] Add search view for py3o_template --HG-- branch : odoo8 --- views/py3o_template.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/views/py3o_template.xml b/views/py3o_template.xml index 6bb910a2..adc3a953 100644 --- a/views/py3o_template.xml +++ b/views/py3o_template.xml @@ -1,6 +1,17 @@ + + py3o.template.configuration.search.view + py3o.template + + + + + + + + py3o.template.configuration.form.view py3o.template From 1826aa2c4581123a6bee79bdd443a74f1f2c17e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Wed, 9 Mar 2016 17:50:37 +0100 Subject: [PATCH 70/78] Only use direct rendering as a fallback if no py3o server is defined --HG-- branch : odoo8 --- models/py3o_template.py | 1 + py3o_parser.py | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/models/py3o_template.py b/models/py3o_template.py index 44f6ddcf..29b49dfd 100644 --- a/models/py3o_template.py +++ b/models/py3o_template.py @@ -19,6 +19,7 @@ class py3o_template(osv.Model): ('ods', u"ODF Spreadsheet"), ], u"LibreOffice Template File Type", + required=True, ), } diff --git a/py3o_parser.py b/py3o_parser.py index 67f5b17b..3c21cc2f 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -156,20 +156,21 @@ class Py3oParser(report_sxw): parsed_datadict = data_struct.render(datadict) - if filetype.fusion_ext == report_xml.py3o_template_id.filetype: - # No format conversion is needed, render the template directly - template.render(parsed_datadict) - res = out_stream.getvalue() - - else: # Call py3o.server to render the template in the desired format - fusion_server_obj = pool.get('py3o.server') - fusion_server_ids = fusion_server_obj.search( - cr, uid, [], context=context - ) - if not fusion_server_ids: + fusion_server_obj = pool.get('py3o.server') + fusion_server_ids = fusion_server_obj.search( + cr, uid, [], context=context, limit=1 + ) + if not fusion_server_ids: + if filetype.fusion_ext == report_xml.py3o_template_id.filetype: + # No format conversion is needed, render the template directly + template.render(parsed_datadict) + res = out_stream.getvalue() + else: raise exceptions.MissingError( _(u"No Py3o server configuration found") ) + + else: # Call py3o.server to render the template in the desired format fusion_server_id = fusion_server_ids[0] fusion_server = fusion_server_obj.browse( From 7e9a76558cffd608a30f71893ff769c58d77d02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Wed, 9 Mar 2016 17:53:01 +0100 Subject: [PATCH 71/78] Can set Py3o servers as inactive --HG-- branch : odoo8 --- models/py3o_server.py | 7 +++++++ py3o_parser.py | 2 +- views/py3o_server.xml | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/models/py3o_server.py b/models/py3o_server.py index 957e7b81..d815a845 100644 --- a/models/py3o_server.py +++ b/models/py3o_server.py @@ -9,4 +9,11 @@ class py3o_server(osv.Model): u"URL", size=256, ), + 'is_active': fields.boolean( + u"Active", + ) + } + + _defaults = { + 'is_active': True, } diff --git a/py3o_parser.py b/py3o_parser.py index 3c21cc2f..b380ff7a 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -158,7 +158,7 @@ class Py3oParser(report_sxw): fusion_server_obj = pool.get('py3o.server') fusion_server_ids = fusion_server_obj.search( - cr, uid, [], context=context, limit=1 + cr, uid, [('is_active', '=', True)], context=context, limit=1 ) if not fusion_server_ids: if filetype.fusion_ext == report_xml.py3o_template_id.filetype: diff --git a/views/py3o_server.xml b/views/py3o_server.xml index ba3456a9..45fa384b 100644 --- a/views/py3o_server.xml +++ b/views/py3o_server.xml @@ -9,6 +9,7 @@ + @@ -21,6 +22,7 @@ + From 3f04c13fc1d0a145e9704e8f953d686f6ba3ca6b Mon Sep 17 00:00:00 2001 From: "stephane.bidoul@acsone.eu" Date: Mon, 14 Mar 2016 19:52:49 +0100 Subject: [PATCH 72/78] Fix raise error --HG-- branch : odoo8 --- py3o_parser.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/py3o_parser.py b/py3o_parser.py index b380ff7a..d7467f95 100644 --- a/py3o_parser.py +++ b/py3o_parser.py @@ -11,7 +11,6 @@ from openerp import _ from openerp import exceptions from openerp.report.report_sxw import report_sxw, rml_parse from openerp import registry -from openerp.exceptions import ValidationError from py3o.template.helpers import Py3oConvertor from py3o.template import Template @@ -189,8 +188,7 @@ class Py3oParser(report_sxw): if r.status_code != 200: # server says we have an issue... let's tell that to enduser raise exceptions.Warning( - _('Fusion server error'), - r.text, + _('Fusion server error %s') % r.text, ) # Here is a little joke about Odoo From 50cd4c6d3bea8efeca1349a9a6f62713f5e7b5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Fri, 8 Apr 2016 12:05:21 +0200 Subject: [PATCH 73/78] Fix py3o_template_fallback help string --HG-- branch : odoo8 --- models/ir_report.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/models/ir_report.py b/models/ir_report.py index b8d85eb1..85733e4f 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -31,9 +31,10 @@ class report_xml(osv.Model): 'py3o_template_fallback': fields.char( u"Fallback", size=128, - help=(u"If the user does not provide a template this will be used " - u"it should be a relattive path to root of YOUR module", - ), + help=( + u"If the user does not provide a template this will be used " + u"it should be a relative path to root of YOUR module", + ) ), 'report_type': fields.selection( [ From c766924e84b4a5a9f826c033c2e4813c710fe231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Gavrel?= Date: Fri, 8 Apr 2016 12:10:10 +0200 Subject: [PATCH 74/78] Fix py3o_template_fallback help string --HG-- branch : odoo8 --- models/ir_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/ir_report.py b/models/ir_report.py index 85733e4f..106bd332 100644 --- a/models/ir_report.py +++ b/models/ir_report.py @@ -33,7 +33,7 @@ class report_xml(osv.Model): size=128, help=( u"If the user does not provide a template this will be used " - u"it should be a relative path to root of YOUR module", + u"it should be a relative path to root of YOUR module" ) ), 'report_type': fields.selection( From d60fb75424ee85449a6cf704bfefc47f13a9e56e Mon Sep 17 00:00:00 2001 From: Szeka Wong Date: Wed, 14 Sep 2016 18:33:16 +0200 Subject: [PATCH 75/78] Add oe_json_serializer in external_dependencies. Fix get_user_variables call. --HG-- branch : odoo8 --- __openerp__.py | 2 +- py3o_report_modif.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__openerp__.py b/__openerp__.py index 328da8e6..5c8ac75a 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -39,7 +39,7 @@ The py3o.template package is required; install it with: 'report' ], 'external_dependencies': { - 'python': ['py3o.template'] + 'python': ['py3o.template', 'oe_json_serializer'] }, 'data': [ 'security/ir.model.access.csv', diff --git a/py3o_report_modif.py b/py3o_report_modif.py index 0e496efb..84028446 100644 --- a/py3o_report_modif.py +++ b/py3o_report_modif.py @@ -83,7 +83,7 @@ class py3o_report(report_sxw): #TODO: Find a way to avoid calling Template t = Template(in_temp.name, out_temp.name) # Remove 'py3o.' - user_variable = [x[5:] for x in t.get_user_variable()] + user_variable = [x[5:] for x in t.get_user_variables()] print user_variable values = self.get_values(cr, uid, ids, data, context) From 5089921bd275d92757367fe7e1b1480f8930ab9a Mon Sep 17 00:00:00 2001 From: Szeka Wong Date: Fri, 16 Sep 2016 15:14:56 +0200 Subject: [PATCH 76/78] Replace get_user_variables (=deprecated) with get_all_user_python_expression. Add call on template render function. --HG-- branch : odoo8 --- py3o_report_modif.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py3o_report_modif.py b/py3o_report_modif.py index 84028446..8683ea25 100644 --- a/py3o_report_modif.py +++ b/py3o_report_modif.py @@ -83,10 +83,11 @@ class py3o_report(report_sxw): #TODO: Find a way to avoid calling Template t = Template(in_temp.name, out_temp.name) # Remove 'py3o.' - user_variable = [x[5:] for x in t.get_user_variables()] + user_variable = [x[5:] for x in t.get_all_user_python_expression()] print user_variable values = self.get_values(cr, uid, ids, data, context) + t.render(values) print values #WARNING: We rely on the fact that there is a for loop on the report From 3a73f24c15cafdec89060401e30eb18f0f783685 Mon Sep 17 00:00:00 2001 From: Brendan Masson Date: Mon, 19 Sep 2016 10:47:09 +0200 Subject: [PATCH 77/78] Remove dependency to oe_json_serializer due to packaging issues --HG-- branch : odoo8 --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 5c8ac75a..328da8e6 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -39,7 +39,7 @@ The py3o.template package is required; install it with: 'report' ], 'external_dependencies': { - 'python': ['py3o.template', 'oe_json_serializer'] + 'python': ['py3o.template'] }, 'data': [ 'security/ir.model.access.csv', From c1479c64d25efe4d2907a6c45b8f91a3a7393079 Mon Sep 17 00:00:00 2001 From: Laurent Mignon Date: Mon, 3 Oct 2016 17:50:09 +0200 Subject: [PATCH 78/78] Move to report_py3o after import from HG --- LICENSE => report_py3o/LICENSE | 0 NEWS => report_py3o/NEWS | 0 README.md => report_py3o/README.md | 0 __init__.py => report_py3o/__init__.py | 0 __openerp__.py => report_py3o/__openerp__.py | 0 {data => report_py3o/data}/py3o.fusion.filetype.csv | 0 {i18n => report_py3o/i18n}/fr.po | 0 {models => report_py3o/models}/__init__.py | 0 {models => report_py3o/models}/ir_report.py | 0 {models => report_py3o/models}/py3o_fusion_filetype.py | 0 {models => report_py3o/models}/py3o_server.py | 0 {models => report_py3o/models}/py3o_template.py | 0 py3o_parser.py => report_py3o/py3o_parser.py | 0 py3o_report_modif.py => report_py3o/py3o_report_modif.py | 0 {security => report_py3o/security}/ir.model.access.csv | 0 {views => report_py3o/views}/ir_report.xml | 0 {views => report_py3o/views}/menu.xml | 0 {views => report_py3o/views}/py3o_server.xml | 0 {views => report_py3o/views}/py3o_template.xml | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename LICENSE => report_py3o/LICENSE (100%) rename NEWS => report_py3o/NEWS (100%) rename README.md => report_py3o/README.md (100%) rename __init__.py => report_py3o/__init__.py (100%) rename __openerp__.py => report_py3o/__openerp__.py (100%) rename {data => report_py3o/data}/py3o.fusion.filetype.csv (100%) rename {i18n => report_py3o/i18n}/fr.po (100%) rename {models => report_py3o/models}/__init__.py (100%) rename {models => report_py3o/models}/ir_report.py (100%) rename {models => report_py3o/models}/py3o_fusion_filetype.py (100%) rename {models => report_py3o/models}/py3o_server.py (100%) rename {models => report_py3o/models}/py3o_template.py (100%) rename py3o_parser.py => report_py3o/py3o_parser.py (100%) rename py3o_report_modif.py => report_py3o/py3o_report_modif.py (100%) rename {security => report_py3o/security}/ir.model.access.csv (100%) rename {views => report_py3o/views}/ir_report.xml (100%) rename {views => report_py3o/views}/menu.xml (100%) rename {views => report_py3o/views}/py3o_server.xml (100%) rename {views => report_py3o/views}/py3o_template.xml (100%) diff --git a/LICENSE b/report_py3o/LICENSE similarity index 100% rename from LICENSE rename to report_py3o/LICENSE diff --git a/NEWS b/report_py3o/NEWS similarity index 100% rename from NEWS rename to report_py3o/NEWS diff --git a/README.md b/report_py3o/README.md similarity index 100% rename from README.md rename to report_py3o/README.md diff --git a/__init__.py b/report_py3o/__init__.py similarity index 100% rename from __init__.py rename to report_py3o/__init__.py diff --git a/__openerp__.py b/report_py3o/__openerp__.py similarity index 100% rename from __openerp__.py rename to report_py3o/__openerp__.py diff --git a/data/py3o.fusion.filetype.csv b/report_py3o/data/py3o.fusion.filetype.csv similarity index 100% rename from data/py3o.fusion.filetype.csv rename to report_py3o/data/py3o.fusion.filetype.csv diff --git a/i18n/fr.po b/report_py3o/i18n/fr.po similarity index 100% rename from i18n/fr.po rename to report_py3o/i18n/fr.po diff --git a/models/__init__.py b/report_py3o/models/__init__.py similarity index 100% rename from models/__init__.py rename to report_py3o/models/__init__.py diff --git a/models/ir_report.py b/report_py3o/models/ir_report.py similarity index 100% rename from models/ir_report.py rename to report_py3o/models/ir_report.py diff --git a/models/py3o_fusion_filetype.py b/report_py3o/models/py3o_fusion_filetype.py similarity index 100% rename from models/py3o_fusion_filetype.py rename to report_py3o/models/py3o_fusion_filetype.py diff --git a/models/py3o_server.py b/report_py3o/models/py3o_server.py similarity index 100% rename from models/py3o_server.py rename to report_py3o/models/py3o_server.py diff --git a/models/py3o_template.py b/report_py3o/models/py3o_template.py similarity index 100% rename from models/py3o_template.py rename to report_py3o/models/py3o_template.py diff --git a/py3o_parser.py b/report_py3o/py3o_parser.py similarity index 100% rename from py3o_parser.py rename to report_py3o/py3o_parser.py diff --git a/py3o_report_modif.py b/report_py3o/py3o_report_modif.py similarity index 100% rename from py3o_report_modif.py rename to report_py3o/py3o_report_modif.py diff --git a/security/ir.model.access.csv b/report_py3o/security/ir.model.access.csv similarity index 100% rename from security/ir.model.access.csv rename to report_py3o/security/ir.model.access.csv diff --git a/views/ir_report.xml b/report_py3o/views/ir_report.xml similarity index 100% rename from views/ir_report.xml rename to report_py3o/views/ir_report.xml diff --git a/views/menu.xml b/report_py3o/views/menu.xml similarity index 100% rename from views/menu.xml rename to report_py3o/views/menu.xml diff --git a/views/py3o_server.xml b/report_py3o/views/py3o_server.xml similarity index 100% rename from views/py3o_server.xml rename to report_py3o/views/py3o_server.xml diff --git a/views/py3o_template.xml b/report_py3o/views/py3o_template.xml similarity index 100% rename from views/py3o_template.xml rename to report_py3o/views/py3o_template.xml