From 25896130b14aac7cd4ae375107d151b64503550a Mon Sep 17 00:00:00 2001 From: Gilles Meyomesse Date: Thu, 29 Nov 2018 17:03:05 +0100 Subject: [PATCH] [12.0][MIG] improvement py3o_report_extender --- report_py3o/models/_py3o_parser_context.py | 96 ++++++++++++++++++++++ report_py3o/models/py3o_report.py | 30 +++---- report_py3o/tests/test_report_py3o.py | 3 +- 3 files changed, 108 insertions(+), 21 deletions(-) create mode 100644 report_py3o/models/_py3o_parser_context.py diff --git a/report_py3o/models/_py3o_parser_context.py b/report_py3o/models/_py3o_parser_context.py new file mode 100644 index 00000000..d42949cd --- /dev/null +++ b/report_py3o/models/_py3o_parser_context.py @@ -0,0 +1,96 @@ +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import html +import time +import logging + +from base64 import b64decode +from odoo.tools import misc, mail + +logger = logging.getLogger(__name__) + +try: + from genshi.core import Markup +except ImportError: + logger.debug('Cannot import py3o.template') + + +def format_multiline_value(value): + if value: + return Markup(html.escape(value).replace('\n', ''). + replace('\t', '')) + return "" + + +def display_address(address_record, without_company=False): + return address_record.display_address(without_company=without_company) + + +class Py3oParserContext(object): + def __init__(self, env): + self._env = env + + self.localcontext = { + # Odoo default format methods + 'o_format_lang': self._format_lang, + # prefixes with o_ to avoid nameclash with default method provided + # by py3o.template + 'o_format_date': self._format_date, + # give access to the time lib + 'time': time, + # keeps methods from report_sxw to ease migration + 'display_address': display_address, + 'formatLang': self._old_format_lang, + 'format_multiline_value': format_multiline_value, + 'html_sanitize': mail.html2plaintext, + 'b64decode': b64decode, + } + + def _format_lang(self, _env, value, digits=None, grouping=True, + monetary=False, dp=False, currency_obj=False, + no_break_space=True): + formatted_value = misc.formatLang( + _env, value, digits=digits, grouping=grouping, + monetary=monetary, dp=dp, currency_obj=currency_obj) + if currency_obj and currency_obj.symbol and no_break_space: + parts = [] + if currency_obj.position == 'after': + parts = formatted_value.rsplit(" ", 1) + elif currency_obj and currency_obj.position == 'before': + parts = formatted_value.split(" ", 1) + if parts: + formatted_value = "\N{NO-BREAK SPACE}".join(parts) + return formatted_value + + def _format_date(self, value, lang_code=False, date_format=False): + return misc.format_date( + self._env, value, lang_code=lang_code, date_format=date_format) + + def _old_format_lang(self, value, digits=None, date=False, date_time=False, + grouping=True, monetary=False, dp=False, + currency_obj=False): + """ + :param value: The value to format + :param digits: Number of digits to display by default + :param date: True if value must be formatted as a date (default False) + :param date_time: True if value must be formatted as a datetime + (default False) + :param grouping: If value is float and grouping is True, the value will + be formatted with the appropriate separators between + figures according to the current lang specifications + :param monetary: If value is float and monetary is True and grouping is + True the value will be formatted according to the + monetary format defined for the current lang + :param dp: Decimal precision + :param currency_obj: If provided the currency symbol will be added to + value at position defined by the currency object + :return: The formatted value + """ + if not date and not date_time: + return self._format_lang( + self._env, value, digits=digits, grouping=grouping, + monetary=monetary, dp=dp, currency_obj=currency_obj, + no_break_space=True) + + return self._format_date(self._env, value) diff --git a/report_py3o/models/py3o_report.py b/report_py3o/models/py3o_report.py index 29b947f5..c1eda37f 100644 --- a/report_py3o/models/py3o_report.py +++ b/report_py3o/models/py3o_report.py @@ -6,7 +6,6 @@ from base64 import b64decode from io import BytesIO import logging import os -import cgi from contextlib import closing import subprocess @@ -16,13 +15,13 @@ import tempfile from zipfile import ZipFile, ZIP_DEFLATED from odoo import api, fields, models, tools, _ +from ._py3o_parser_context import Py3oParserContext logger = logging.getLogger(__name__) try: from py3o.template import Template from py3o import formats - from genshi.core import Markup except ImportError: logger.debug('Cannot import py3o.template') try: @@ -60,21 +59,9 @@ def py3o_report_extender(report_xml_id=None): return fct1 -def format_multiline_value(value): - if value: - return Markup(cgi.escape(value).replace('\n', ''). - replace('\t', '')) - return "" - - @py3o_report_extender() -def default_extend(report_xml, localcontext): - # add the base64decode function to be able do decode binary fields into - # the template - localcontext['b64decode'] = b64decode - localcontext['report_xml'] = report_xml - localcontext['format_multiline_value'] = format_multiline_value - localcontext['html_sanitize'] = tools.html2plaintext +def default_extend(report_xml, context): + context['report_xml'] = report_xml class Py3oReport(models.TransientModel): @@ -190,20 +177,23 @@ class Py3oReport(models.TransientModel): return tmpl_data @api.multi - def _extend_parser_context(self, context_instance, report_xml): + def _extend_parser_context(self, context, report_xml): # add default extenders for fct in _extender_functions.get(None, []): - fct(report_xml, context_instance) + fct(report_xml, context) # 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) + fct(report_xml, context) @api.multi def _get_parser_context(self, model_instance, data): report_xml = self.ir_actions_report_id - context = report_xml._get_rendering_context(model_instance.ids, data) + context = Py3oParserContext(self.env).localcontext + context.update( + report_xml._get_rendering_context(model_instance.ids, data) + ) context['objects'] = model_instance self._extend_parser_context(context, report_xml) return context diff --git a/report_py3o/tests/test_report_py3o.py b/report_py3o/tests/test_report_py3o.py index c29c0e98..f89a9951 100644 --- a/report_py3o/tests/test_report_py3o.py +++ b/report_py3o/tests/test_report_py3o.py @@ -15,7 +15,8 @@ from odoo.tests.common import TransactionCase from odoo.exceptions import ValidationError from odoo.addons.base.tests.test_mimetypes import PNG -from ..models.py3o_report import TemplateNotFound, format_multiline_value +from ..models.py3o_report import TemplateNotFound +from ..models._py3o_parser_context import format_multiline_value from base64 import b64encode import logging