# -*- coding: utf-8 -*- ############################################################################## # # Author: Yannick Vaucher # Copyright 2013 Camptocamp SA # # 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 . # ############################################################################## import time import base64 from PyPDF2 import PdfFileReader, PdfFileWriter from StringIO import StringIO from openerp.netsvc import ExportService from openerp.report import report_sxw from openerp import pooler _POLLING_DELAY = 0.25 def assemble_pdf(pdf_list): """ Assemble a list of pdf """ # Even though we are using PyPDF2 we can't use PdfFileMerger # as this issue still exists in mostly used wktohtml reports version # http://code.google.com/p/wkhtmltopdf/issues/detail?id=635 # merger = PdfFileMerger() # merger.append(fileobj=StringIO(invoice_pdf)) # merger.append(fileobj=StringIO(bvr_pdf)) # with tempfile.TemporaryFile() as merged_pdf: # merger.write(merged_pdf) # return merged_pdf.read(), 'pdf' output = PdfFileWriter() for pdf in pdf_list: reader = PdfFileReader(StringIO(pdf)) for page in range(reader.getNumPages()): output.addPage(reader.getPage(page)) s = StringIO() output.write(s) return s.getvalue() class PDFReportAssembler(report_sxw.report_sxw): """ PDFReportAssembler allows to put 2 pdf reports in one single pdf""" def _generate_all_pdf(self, cr, uid, ids, data, report_ids, context=None): """ Return a list of pdf encoded in base64 """ pool = pooler.get_pool(cr.dbname) report_obj = pool.get('ir.actions.report.xml') spool = ExportService._services['report'] pdf_reports = [] report_list = report_obj.browse(cr, uid, report_ids, context=context) for report in report_list: report_key = spool.exp_report(cr.dbname, uid, report.report_name, ids, datas=data, context=context) while 1: res = spool.exp_report_get(cr.dbname, uid, report_key) if res.get('state'): break time.sleep(_POLLING_DELAY) pdf = base64.b64decode(res.get('result')) pdf_reports.append(pdf) return pdf_reports def _get_report_ids(self, cr, uid, ids, context=None): """ Hook to define the list of report to print """ return [] def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None): """Call both report to assemble both pdf""" report_ids = self._get_report_ids(cr, uid, ids, context=context) pdf_reports = self._generate_all_pdf( cr, uid, ids, data, report_ids, context=context) pdf_assemblage = assemble_pdf(pdf_reports) return pdf_assemblage, 'pdf' def create(self, cr, uid, ids, data, context=None): """We override the create function in order to handle generator Code taken from report openoffice. Thanks guys :) """ pool = pooler.get_pool(cr.dbname) ir_obj = pool.get('ir.actions.report.xml') report_xml_ids = ir_obj.search( cr, uid, [('report_name', '=', self.name[7:])], context=context) if report_xml_ids: report_xml = ir_obj.browse(cr, uid, report_xml_ids[0], context=context) report_xml.report_rml = None report_xml.report_rml_content = None report_xml.report_sxw_content_data = None report_xml.report_sxw_content = None report_xml.report_sxw = None else: return super(PDFReportAssembler, self).create( cr, uid, ids, data, context) if report_xml.report_type != 'assemblage': return super(PDFReportAssembler, self).create( cr, uid, ids, data, context) result = self.create_source_pdf( cr, uid, ids, data, report_xml, context) if not result: return (False, False) return result