def _create_single_report(self, model_instance, data, save_in_attachment): """ This function to generate our py3o report """ self.ensure_one() report_xml = self.ir_actions_report_xml_id filetype = report_xml.py3o_filetype result_fd, result_path = tempfile.mkstemp( suffix='.' + filetype, prefix='p3o.report.tmp.') tmpl_data = self.get_template(model_instance) in_stream = StringIO(tmpl_data) with closing(os.fdopen(result_fd, 'w+')) as out_stream: template = Template(in_stream, out_stream, escape_false=True) localcontext = self._get_parser_context(model_instance, data) is_native = Formats().get_format(filetype).native if report_xml.py3o_is_local_fusion: template.render(localcontext) out_stream.seek(0) tmpl_data = out_stream.read() datadict = {} else: expressions = template.get_all_user_python_expression() py_expression = template.convert_py3o_to_python_ast( expressions) convertor = Py3oConvertor() data_struct = convertor(py_expression) datadict = data_struct.render(localcontext) # if not is_native or not report_xml.py3o_is_local_fusion: # # Call py3o.server to render the template in the desired format # files = { # 'tmpl_file': tmpl_data, # } # fields = { # "targetformat": filetype, # "datadict": json.dumps(datadict), # "image_mapping": "{}", # "escape_false": "on", # } # if report_xml.py3o_is_local_fusion: # fields['skipfusion'] = '1' # r = requests.post( # report_xml.py3o_server_id.url, data=fields, files=files) # if r.status_code != 200: # # server says we have an issue... let's tell that to enduser # raise UserError( # _('Fusion server error %s') % r.text, # ) # chunk_size = 1024 # with open(result_path, 'w+') as fd: # for chunk in r.iter_content(chunk_size): # fd.write(chunk) if len(model_instance) == 1: self._postprocess_report( result_path, model_instance.id, save_in_attachment) return result_path
def _create_single_report(self, model_instance, data, save_in_attachment): """ This function to generate our py3o report """ self.ensure_one() report_xml = self.ir_actions_report_xml_id filetype = report_xml.py3o_filetype if not report_xml.py3o_server_id: return super(Py3oReport, self)._create_single_report( model_instance, data, save_in_attachment, ) elif report_xml.py3o_is_local_fusion: result_path = super( Py3oReport, self.with_context( report_py3o_skip_conversion=True, ))._create_single_report( model_instance, data, save_in_attachment, ) with closing(open(result_path, 'r')) as out_stream: tmpl_data = out_stream.read() datadict = {} else: result_fd, result_path = tempfile.mkstemp(suffix='.' + filetype, prefix='p3o.report.tmp.') tmpl_data = self.get_template(model_instance) in_stream = StringIO(tmpl_data) with closing(os.fdopen(result_fd, 'w+')) as out_stream: template = Template(in_stream, out_stream, escape_false=True) localcontext = self._get_parser_context(model_instance, data) expressions = template.get_all_user_python_expression() py_expression = template.convert_py3o_to_python_ast( expressions) convertor = Py3oConvertor() data_struct = convertor(py_expression) datadict = data_struct.render(localcontext) # Call py3o.server to render the template in the desired format files = { 'tmpl_file': tmpl_data, } fields = { "targetformat": filetype, "datadict": json.dumps(datadict), "image_mapping": "{}", "escape_false": "on", } if report_xml.py3o_is_local_fusion: fields['skipfusion'] = '1' url = report_xml.py3o_server_id.url logger.info('Connecting to %s to convert report %s to %s', url, report_xml.report_name, filetype) if filetype == 'pdf': options = report_xml.pdf_options_id or\ report_xml.py3o_server_id.pdf_options_id if options: pdf_options_dict = options.odoo2libreoffice_options() fields['pdf_options'] = json.dumps(pdf_options_dict) logger.debug('PDF Export options: %s', pdf_options_dict) start_chrono = datetime.now() r = requests.post(url, data=fields, files=files) if r.status_code != 200: # server says we have an issue... let's tell that to enduser logger.error('Py3o fusion server error: %s', r.text) raise UserError(_('Fusion server error %s') % r.text, ) chunk_size = 1024 with open(result_path, 'w+') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) end_chrono = datetime.now() convert_seconds = (end_chrono - start_chrono).total_seconds() logger.info('Report %s converted to %s in %s seconds', report_xml.report_name, filetype, convert_seconds) if len(model_instance) == 1: self._postprocess_report(result_path, model_instance.id, save_in_attachment) return result_path
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]: fct(pool, cr, uid, parser_instance.localcontext, context) 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 datadict = parser_instance.localcontext parsed_datadict = data_struct.render(datadict) fusion_server_obj = pool.get('py3o.server') fusion_server_ids = fusion_server_obj.search( cr, uid, [('is_active', '=', True)], 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: if USE_LOCAL_LIBREOFFICE: import sh import tempfile template.render(parsed_datadict) res = out_stream.getvalue() arq = tempfile.NamedTemporaryFile(delete=False) arq.seek(0) arq.write(res) arq.flush() res_arq_name = arq.name + '.' + filetype.fusion_ext sh.libreoffice('--headless', '--invisible', \ '--convert-to', filetype.fusion_ext, \ '--outdir', '/tmp', arq.name) res = file(res_arq_name, 'r').read() os.remove(res_arq_name) os.remove(arq.name) 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( 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 %s') % 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