[MIG] report_py3o, report_py3o_fusion_server: Migration to 12.0

This commit is contained in:
Laurent Mignon (ACSONE)
2018-11-26 17:58:30 +01:00
committed by Elmeri Niemelä
parent 80d8afb408
commit e65b6db22f
82 changed files with 231 additions and 243 deletions

View File

@@ -1,4 +1,3 @@
from . import ir_actions_report_xml
from . import py3o_template
from . import report
from . import ir_actions_report
from . import py3o_report

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2013 XCG Consulting (http://odoo.consulting)
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
import time
@@ -15,13 +15,13 @@ except ImportError:
logger.debug('Cannot import py3o.formats')
class IrActionsReportXml(models.Model):
""" Inherit from ir.actions.report.xml to allow customizing the template
class IrActionsReport(models.Model):
""" Inherit from ir.actions.report 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'
_inherit = 'ir.actions.report'
@api.multi
@api.constrains("py3o_filetype", "report_type")
@@ -43,6 +43,9 @@ class IrActionsReportXml(models.Model):
selections.append((name, description))
return selections
report_type = fields.Selection(
selection_add=[("py3o", "py3o")]
)
py3o_filetype = fields.Selection(
selection="_get_py3o_filetypes",
string="Output Format")
@@ -78,12 +81,21 @@ class IrActionsReportXml(models.Model):
def render_report(self, res_ids, name, data):
action_py3o_report = self.get_from_report_name(name, "py3o")
if action_py3o_report:
return self.env['py3o.report'].create({
'ir_actions_report_xml_id': action_py3o_report.id
}).create_report(res_ids, data)
return super(IrActionsReportXml, self).render_report(
return action_py3o_report._render_py3o(res_ids, data)
return super(IrActionsReport, self).render_report(
res_ids, name, data)
@api.multi
def _render_py3o(self, res_ids, data):
self.ensure_one()
if self.report_type != "py3o":
raise RuntimeError(
"py3o rendition is only available on py3o report.\n"
"(current: '{}', expected 'py3o'".format(self.report_type))
return self.env['py3o.report'].create({
'ir_actions_report_id': self.id
}).create_report(res_ids, data)
@api.multi
def gen_report_download_filename(self, res_ids, data):
"""Override this function to change the name of the downloaded report
@@ -95,3 +107,34 @@ class IrActionsReportXml(models.Model):
return safe_eval(report.print_report_name,
{'object': obj, 'time': time})
return "%s.%s" % (self.name, self.py3o_filetype)
@api.model
def _get_report_from_name(self, report_name):
"""Get the first record of ir.actions.report having the
``report_name`` as value for the field report_name.
"""
res = super(IrActionsReport, self)._get_report_from_name(report_name)
if res:
return res
# maybe a py3o report
context = self.env['res.users'].context_get()
return self.with_context(context).search(
[('report_type', '=', 'py3o'),
('report_name', '=', report_name)], limit=1)
@api.multi
def _get_attachments(self, res_ids):
""" Return the report already generated for the given res_ids
"""
self.ensure_one()
save_in_attachment = {}
if res_ids:
# Dispatch the records by ones having an attachment
Model = self.env[self.model]
record_ids = Model.browse(res_ids)
if self.attachment:
for record_id in record_ids:
attachment_id = self.retrieve_attachment(record_id)
if attachment_id:
save_in_attachment[record_id.id] = attachment_id
return save_in_attachment

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright 2013 XCG Consulting (http://odoo.consulting)
# Copyright 2016 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import base64
from base64 import b64decode
from cStringIO import StringIO
from io import BytesIO
import logging
import os
import cgi
@@ -16,8 +15,6 @@ import sys
import tempfile
from zipfile import ZipFile, ZIP_DEFLATED
from odoo.exceptions import AccessError
from odoo.report.report_sxw import rml_parse
from odoo import api, fields, models, tools, _
logger = logging.getLogger(__name__)
@@ -71,7 +68,7 @@ def format_multiline_value(value):
@py3o_report_extender()
def defautl_extend(report_xml, localcontext):
def default_extend(report_xml, localcontext):
# add the base64decode function to be able do decode binary fields into
# the template
localcontext['b64decode'] = b64decode
@@ -82,11 +79,10 @@ def defautl_extend(report_xml, localcontext):
class Py3oReport(models.TransientModel):
_name = "py3o.report"
_inherit = 'report'
_description = "Report Py30"
ir_actions_report_xml_id = fields.Many2one(
comodel_name="ir.actions.report.xml",
ir_actions_report_id = fields.Many2one(
comodel_name="ir.actions.report",
required=True
)
@@ -134,7 +130,7 @@ class Py3oReport(models.TransientModel):
"""
if not tmpl_name:
return None
report_xml = self.ir_actions_report_xml_id
report_xml = self.ir_actions_report_id
flbk_filename = None
if report_xml.module:
# if the default is defined
@@ -145,7 +141,7 @@ class Py3oReport(models.TransientModel):
elif self._is_valid_template_path(tmpl_name):
flbk_filename = os.path.realpath(tmpl_name)
if self._is_valid_template_filename(flbk_filename):
with open(flbk_filename, 'r') as tmpl:
with open(flbk_filename, 'rb') as tmpl:
return tmpl.read()
return None
@@ -156,7 +152,7 @@ class Py3oReport(models.TransientModel):
:return:
"""
self.ensure_one()
report_xml = self.ir_actions_report_xml_id
report_xml = self.ir_actions_report_id
return self._get_template_from_path(report_xml.py3o_template_fallback)
@api.multi
@@ -174,7 +170,7 @@ class Py3oReport(models.TransientModel):
odoo.exceptions.DeferredException
"""
self.ensure_one()
report_xml = self.ir_actions_report_xml_id
report_xml = self.ir_actions_report_id
if report_xml.py3o_template_id.py3o_template_data:
# if a user gave a report template
tmpl_data = b64decode(
@@ -187,7 +183,7 @@ class Py3oReport(models.TransientModel):
if tmpl_data is None:
# if for any reason the template is not found
raise TemplateNotFound(
_(u'No template found. Aborting.'),
_('No template found. Aborting.'),
sys.exc_info(),
)
@@ -197,47 +193,35 @@ class Py3oReport(models.TransientModel):
def _extend_parser_context(self, context_instance, report_xml):
# add default extenders
for fct in _extender_functions.get(None, []):
fct(report_xml, context_instance.localcontext)
fct(report_xml, context_instance)
# add extenders for registered on the template
xml_id = report_xml.get_external_id().get(report_xml.id)
if xml_id in _extender_functions:
for fct in _extender_functions[xml_id]:
fct(report_xml, context_instance.localcontext)
fct(report_xml, context_instance)
@api.multi
def _get_parser_context(self, model_instance, data):
report_xml = self.ir_actions_report_xml_id
context_instance = rml_parse(self.env.cr, self.env.uid,
report_xml.name,
context=self.env.context)
context_instance.set_context(model_instance, data, model_instance.ids,
report_xml.report_type)
self._extend_parser_context(context_instance, report_xml)
return context_instance.localcontext
@api.model
def _postprocess_report(self, report_path, res_id, save_in_attachment):
if save_in_attachment.get(res_id):
with open(report_path, 'rb') as pdfreport:
attachment = {
'name': save_in_attachment.get(res_id),
'datas': base64.encodestring(pdfreport.read()),
'datas_fname': save_in_attachment.get(res_id),
'res_model': save_in_attachment.get('model'),
'res_id': res_id,
}
try:
self.env['ir.attachment'].create(attachment)
except AccessError:
logger.info("Cannot save PDF report %r as attachment",
attachment['name'])
else:
logger.info(
'The PDF document %s is now saved in the database',
attachment['name'])
report_xml = self.ir_actions_report_id
context = report_xml._get_rendering_context(model_instance.ids, data)
context['objects'] = model_instance
self._extend_parser_context(context, report_xml)
return context
@api.multi
def _create_single_report(self, model_instance, data, save_in_attachment):
def _postprocess_report(self, model_instance, result_path):
if len(model_instance) == 1 and self.ir_actions_report_id.attachment:
with open(result_path, 'rb') as f:
# we do all the generation process using files to avoid memory
# consumption...
# ... but odoo wants the whole data in memory anyways :)
buffer = BytesIO(f.read())
self.ir_actions_report_id.postprocess_pdf_report(
model_instance, buffer)
return result_path
@api.multi
def _create_single_report(self, model_instance, data):
""" This function to generate our py3o report
"""
self.ensure_one()
@@ -245,8 +229,8 @@ class Py3oReport(models.TransientModel):
suffix='.ods', 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:
in_stream = BytesIO(tmpl_data)
with closing(os.fdopen(result_fd, 'wb+')) as out_stream:
template = Template(in_stream, out_stream, escape_false=True)
localcontext = self._get_parser_context(model_instance, data)
template.render(localcontext)
@@ -260,16 +244,12 @@ class Py3oReport(models.TransientModel):
result_path, model_instance, data
)
if len(model_instance) == 1:
self._postprocess_report(
result_path, model_instance.id, save_in_attachment)
return result_path
return self._postprocess_report(model_instance, result_path)
@api.multi
def _convert_single_report(self, result_path, model_instance, data):
"""Run a command to convert to our target format"""
filetype = self.ir_actions_report_xml_id.py3o_filetype
filetype = self.ir_actions_report_id.py3o_filetype
if not Formats().get_format(filetype).native:
command = self._convert_single_report_cmd(
result_path, model_instance, data,
@@ -297,30 +277,30 @@ class Py3oReport(models.TransientModel):
),
'--headless',
'--convert-to',
self.ir_actions_report_xml_id.py3o_filetype,
self.ir_actions_report_id.py3o_filetype,
result_path,
]
@api.multi
def _get_or_create_single_report(self, model_instance, data,
save_in_attachment):
existing_reports_attachment):
self.ensure_one()
if save_in_attachment and save_in_attachment[
'loaded_documents'].get(model_instance.id):
d = save_in_attachment[
'loaded_documents'].get(model_instance.id)
attachment = existing_reports_attachment.get(
model_instance.id)
if attachment and self.ir_actions_report_id.attachment_use:
content = base64.decodestring(attachment.datas)
report_file = tempfile.mktemp(
"." + self.ir_actions_report_xml_id.py3o_filetype)
"." + self.ir_actions_report_id.py3o_filetype)
with open(report_file, "wb") as f:
f.write(d)
f.write(content)
return report_file
return self._create_single_report(
model_instance, data, save_in_attachment)
model_instance, data)
@api.multi
def _zip_results(self, reports_path):
self.ensure_one()
zfname_prefix = self.ir_actions_report_xml_id.name
zfname_prefix = self.ir_actions_report_id.name
result_path = tempfile.mktemp(suffix="zip", prefix='py3o-zip-result')
with ZipFile(result_path, 'w', ZIP_DEFLATED) as zf:
cpt = 0
@@ -335,7 +315,7 @@ class Py3oReport(models.TransientModel):
@api.multi
def _merge_results(self, reports_path):
self.ensure_one()
filetype = self.ir_actions_report_xml_id.py3o_filetype
filetype = self.ir_actions_report_id.py3o_filetype
if not reports_path:
return False, False
if len(reports_path) == 1:
@@ -359,22 +339,22 @@ class Py3oReport(models.TransientModel):
def create_report(self, res_ids, data):
""" Override this function to handle our py3o report
"""
model_instances = self.env[self.ir_actions_report_xml_id.model].browse(
model_instances = self.env[self.ir_actions_report_id.model].browse(
res_ids)
save_in_attachment = self._check_attachment_use(
res_ids, self.ir_actions_report_xml_id) or {}
reports_path = []
if (
len(res_ids) > 1 and
self.ir_actions_report_xml_id.py3o_multi_in_one):
self.ir_actions_report_id.py3o_multi_in_one):
reports_path.append(
self._create_single_report(
model_instances, data, save_in_attachment))
model_instances, data))
else:
existing_reports_attachment = \
self.ir_actions_report_id._get_attachments(res_ids)
for model_instance in model_instances:
reports_path.append(
self._get_or_create_single_report(
model_instance, data, save_in_attachment))
model_instance, data, existing_reports_attachment))
result_path, filetype = self._merge_results(reports_path)
reports_path.append(result_path)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2013 XCG Consulting (http://odoo.consulting)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
@@ -6,6 +5,7 @@ from odoo import fields, models
class Py3oTemplate(models.Model):
_name = 'py3o.template'
_description = 'Py3o template'
name = fields.Char(required=True)
py3o_template_data = fields.Binary("LibreOffice Template")

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Akretion (http://www.akretion.com/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
class Report(models.Model):
_inherit = 'report'
@api.model
def _get_report_from_name(self, report_name):
"""Get the first record of ir.actions.report.xml having the
``report_name`` as value for the field report_name.
"""
res = super(Report, self)._get_report_from_name(report_name)
if res:
return res
# maybe a py3o report
report_obj = self.env['ir.actions.report.xml']
context = self.env['res.users'].context_get()
return report_obj.with_context(context).search(
[('report_type', '=', 'py3o'),
('report_name', '=', report_name)], limit=1)