diff --git a/addons/digest/models/digest.py b/addons/digest/models/digest.py index bfd55135e85..33d8c6c2dcc 100644 --- a/addons/digest/models/digest.py +++ b/addons/digest/models/digest.py @@ -144,7 +144,8 @@ class Digest(models.Model): 'tips': self._compute_tips(user.company_id, user, tips_count=tips_count, consumed=consum_tips), 'preferences': self._compute_preferences(user.company_id, user), }, - post_process=True + post_process=True, + options={'preserve_comments': True} )[self.id] full_mail = self.env['mail.render.mixin']._render_encapsulate( 'digest.digest_mail_layout', diff --git a/addons/mail/models/mail_render_mixin.py b/addons/mail/models/mail_render_mixin.py index 27eec614618..b24c9d3d357 100644 --- a/addons/mail/models/mail_render_mixin.py +++ b/addons/mail/models/mail_render_mixin.py @@ -276,8 +276,12 @@ class MailRenderMixin(models.AbstractModel): for record in self.env[model].browse(res_ids): variables['object'] = record try: - render_result = self.env['ir.qweb']._render(html.fragment_fromstring( - template_src, create_parent='div'), variables, raise_on_code=is_restricted) + render_result = self.env['ir.qweb']._render( + html.fragment_fromstring(template_src, create_parent='div'), + variables, + raise_on_code=is_restricted, + **(options or {}) + ) # remove the rendered tag
that was added in order to wrap potentially multiples nodes into one. render_result = render_result[5:-6] except QWebCodeFound: @@ -329,7 +333,7 @@ class MailRenderMixin(models.AbstractModel): for record in self.env[model].browse(res_ids): variables['object'] = record try: - render_result = view._render(variables, engine='ir.qweb', minimal_qcontext=True) + render_result = view._render(variables, engine='ir.qweb', minimal_qcontext=True, options=options) except Exception as e: _logger.info("Failed to render template : %s (%d)", template_src, view.id, exc_info=True) raise UserError(_("Failed to render template : %(xml_id)s (%(view_id)d)", diff --git a/addons/mail/tests/test_mail_composer.py b/addons/mail/tests/test_mail_composer.py index 8dd6c5614f1..f99e83cfe1b 100644 --- a/addons/mail/tests/test_mail_composer.py +++ b/addons/mail/tests/test_mail_composer.py @@ -47,14 +47,9 @@ class TestMailComposer(MailCommon): values = mail_compose_message.get_mail_values(self.partner_employee.ids) - self.assertIn("""
-

Hello sir!

-

Here! - A link for you! - Make good use of it.

-
""", + self.assertIn(self.body_html, values[self.partner_employee.id]['body_html'], - 'We must remove comments') + 'We must preserve (mso) comments in email html') @users('employee') def test_mail_mass_mode_compose_with_mso(self): @@ -74,11 +69,6 @@ class TestMailComposer(MailCommon): values = composer.get_mail_values(self.partner_employee.ids) - self.assertIn("""
-

Hello sir!

-

Here! - A link for you! - Make good use of it.

-
""", + self.assertIn(self.body_html, values[self.partner_employee.id]['body_html'], - 'We must remove comments') + 'We must preserve (mso) comments in email html') diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 5ef54670f28..a91b0c4bd4c 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -598,7 +598,8 @@ class MailComposer(models.TransientModel): res_ids = [res_ids] subjects = self._render_field('subject', res_ids, options={"render_safe": True}) - bodies = self._render_field('body', res_ids, post_process=True) + # We want to preserve comments in emails so as to keep mso conditionals + bodies = self._render_field('body', res_ids, post_process=True, options={'preserve_comments': self.composition_mode == 'mass_mail'}) emails_from = self._render_field('email_from', res_ids) replies_to = self._render_field('reply_to', res_ids) default_recipients = {} diff --git a/addons/web_editor/models/ir_ui_view.py b/addons/web_editor/models/ir_ui_view.py index 52bab6a98dd..ee7d3457751 100644 --- a/addons/web_editor/models/ir_ui_view.py +++ b/addons/web_editor/models/ir_ui_view.py @@ -18,7 +18,7 @@ EDITING_ATTRIBUTES = ['data-oe-model', 'data-oe-id', 'data-oe-field', 'data-oe-x class IrUiView(models.Model): _inherit = 'ir.ui.view' - def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False): + def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False, options=None): if values and values.get('editable'): try: self.check_access_rights('write') @@ -26,7 +26,7 @@ class IrUiView(models.Model): except AccessError: values['editable'] = False - return super(IrUiView, self)._render(values=values, engine=engine, minimal_qcontext=minimal_qcontext) + return super(IrUiView, self)._render(values=values, engine=engine, minimal_qcontext=minimal_qcontext, options=options) #------------------------------------------------------ # Save from html diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index 58aed3a3c4e..169c202314e 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -1974,13 +1974,13 @@ actual arch. def _render_template(self, template, values=None, engine='ir.qweb'): return self.browse(self.get_view_id(template))._render(values, engine) - def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False): + def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False, options=None): assert isinstance(self.id, int) qcontext = dict() if minimal_qcontext else self._prepare_qcontext() qcontext.update(values or {}) - return self.env[engine]._render(self.id, qcontext) + return self.env[engine]._render(self.id, qcontext, **(options or {})) @api.model def _prepare_qcontext(self): diff --git a/odoo/addons/base/models/qweb.py b/odoo/addons/base/models/qweb.py index cd10dbfb026..313352ac6a6 100644 --- a/odoo/addons/base/models/qweb.py +++ b/odoo/addons/base/models/qweb.py @@ -951,7 +951,10 @@ class QWeb(object): body = [] if el.getchildren(): for item in el: - if not isinstance(item, etree._Comment): + if isinstance(item, etree._Comment): + if options.get('preserve_comments'): + self._appendText("" % item.text, options) + else: body.extend(self._compile_node(item, options, indent)) # comments can also contains tail text if item.tail is not None: