diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-03-06 13:17:20 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-03-24 10:24:42 +0000 |
| commit | 2835e0ba38f67f76b7f43948290050dcc68cd9db (patch) | |
| tree | 369ae761539aca4cef909656cfd6e63b6d56af0c | |
| parent | 822f468059c9702b0898016e7bfbaf036a2c4036 (diff) | |
[MOV] mail, sms: move language computation in render mixin directly
PURPOSE
Merge rendering tools used in mail and sms templates as well as partially
in mailings and move them directly in mail.render.mixin.
SPECIFICATIONS
Move tools related to language computation from mail.template model to the
mail.render.mixin. It allows to update both
* mail.template: simply update calls accordingly;
* sms.template: remove code doing what is now available through mail.render
.mixin inherit;
Lang field is moved to mail.render.mixin as it is used notably for the language
computation. It therefore adds the field on mailing.mailing model although
not used currently.
LINKS
Task ID 1963529
Community PR odoo/odoo#32397
| -rw-r--r-- | addons/mail/models/mail_render_mixin.py | 78 | ||||
| -rw-r--r-- | addons/mail/models/mail_template.py | 82 | ||||
| -rw-r--r-- | addons/sms/models/mail_thread.py | 3 | ||||
| -rw-r--r-- | addons/sms/models/sms_template.py | 43 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_composer.py | 4 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_template_preview.py | 7 | ||||
| -rw-r--r-- | addons/test_mail_full/tests/test_sms_template.py | 17 |
7 files changed, 94 insertions, 140 deletions
diff --git a/addons/mail/models/mail_render_mixin.py b/addons/mail/models/mail_render_mixin.py index cbb70d3aacf..5804481f15c 100644 --- a/addons/mail/models/mail_render_mixin.py +++ b/addons/mail/models/mail_render_mixin.py @@ -80,6 +80,13 @@ class MailRenderMixin(models.AbstractModel): _name = 'mail.render.mixin' _description = 'Mail Render Mixin' + # language for rendering + lang = fields.Char( + 'Language', placeholder="${object.partner_id.lang}", + help="Optional translation language (ISO code) to select when sending out an email. " + "If not set, the english version will be used. This should usually be a placeholder expression " + "that provides the appropriate language, e.g. ${object.partner_id.lang}.") + # expression builder model_object_field = fields.Many2one( 'ir.model.fields', string="Field", store=False, help="Select target field from the related document model.\n" @@ -250,3 +257,74 @@ class MailRenderMixin(models.AbstractModel): rendered = self._render_template_postprocess(rendered) return rendered + + def _render_lang(self, res_ids): + """ Given some record ids, return the lang for each record based on + lang field of template or through specific context-based key. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + + :return dict: {res_id: lang code (i.e. en_US)} + """ + self.ensure_one() + if not isinstance(res_ids, (list, tuple)): + raise ValueError(_('Template rendering for language should be called with a list of IDs.')) + + if self.env.context.get('template_preview_lang'): + return dict((res_id, self.env.context['template_preview_lang']) for res_id in res_ids) + else: + rendered_langs = self._render_template(self.lang, self.model, res_ids) + return dict((res_id, lang) + for res_id, lang in rendered_langs.items()) + + def _classify_per_lang(self, res_ids): + """ Given some record ids, return for computed each lang a contextualized + template and its subset of res_ids. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + + :return dict: {lang: (template with lang=lang_code if specific lang computed + or template, res_ids targeted by that language} + """ + self.ensure_one() + + lang_to_res_ids = {} + for res_id, lang in self._render_lang(res_ids).items(): + lang_to_res_ids.setdefault(lang, []).append(res_id) + + return dict( + (lang, (self.with_context(lang=lang) if lang else self, lang_res_ids)) + for lang, lang_res_ids in lang_to_res_ids.items() + ) + + def _render_field(self, field, res_ids, compute_lang=False, set_lang=False, post_process=False): + """ Given some record ids, render a given field of template rendered on + all records. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + :param compute_lang: compute rendering language based on template.lang + :param set_lang: force language + :param post_process: perform rendered str / html post processing (see + ``_render_template_postprocess``) + + :return dict: {res_id: string of rendered template based on record} + """ + self.ensure_one() + if compute_lang: + templates_res_ids = self._classify_per_lang(res_ids) + elif set_lang: + templates_res_ids = {set_lang: (self.with_context(lang=set_lang), res_ids)} + else: + templates_res_ids = {self._context.get('lang'): (self, res_ids)} + + return dict( + (res_id, rendered) + for lang, (template, tpl_res_ids) in templates_res_ids.items() + for res_id, rendered in template._render_template( + template[field], template.model, tpl_res_ids, + post_process=post_process + ).items() + ) diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 72183aabf01..3fbe4b03e68 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -29,13 +29,6 @@ class MailTemplate(models.Model): name = fields.Char('Name') model_id = fields.Many2one('ir.model', 'Applies to', help="The type of document this template can be used with") model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True) - lang = fields.Char('Language', - help="Optional translation language (ISO code) to select when sending out an email. " - "If not set, the english version will be used. " - "This should usually be a placeholder expression " - "that provides the appropriate language, e.g. " - "${object.partner_id.lang}.", - placeholder="${object.partner_id.lang}") subject = fields.Char('Subject', translate=True, help="Subject (placeholders may be used here)") email_from = fields.Char('From', help="Sender address (placeholders may be used here). If not set, the default " @@ -111,81 +104,6 @@ class MailTemplate(models.Model): return True # ------------------------------------------------------------ - # RENDERING - # ------------------------------------------------------------ - - def _render_lang(self, res_ids): - """ Given some record ids, return the lang for each record based on - lang field of template or through specific context-based key. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - - :return dict: {res_id: lang code (i.e. en_US)} - """ - self.ensure_one() - if not isinstance(res_ids, (list, tuple)): - raise ValueError(_('Template rendering for language should be called with a list of IDs.')) - - if self.env.context.get('template_preview_lang'): - return dict((res_id, self.env.context['template_preview_lang']) for res_id in res_ids) - else: - rendered_langs = self._render_template(self.lang, self.model, res_ids) - return dict((res_id, lang) - for res_id, lang in rendered_langs.items()) - - def _classify_per_lang(self, res_ids): - """ Given some record ids, return for computed each lang a contextualized - template and its subset of res_ids. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - - :return dict: {lang: (template with lang=lang_code if specific lang computed - or template, res_ids targeted by that language} - """ - self.ensure_one() - - lang_to_res_ids = {} - for res_id, lang in self._render_lang(res_ids).items(): - lang_to_res_ids.setdefault(lang, []).append(res_id) - - return dict( - (lang, (self.with_context(lang=lang) if lang else self, lang_res_ids)) - for lang, lang_res_ids in lang_to_res_ids.items() - ) - - def _render_field(self, field, res_ids, compute_lang=False, set_lang=False, post_process=False): - """ Given some record ids, render a given field of template rendered on - all records. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - :param compute_lang: compute rendering language based on template.lang - :param set_lang: force language - :param post_process: perform rendered str / html post processing (see - ``_render_template_postprocess``) - - :return dict: {res_id: string of rendered template based on record} - """ - self.ensure_one() - if compute_lang: - templates_res_ids = self._classify_per_lang(res_ids) - elif set_lang: - templates_res_ids = {set_lang: (self.with_context(lang=set_lang), res_ids)} - else: - templates_res_ids = {self._context.get('lang'): (self, res_ids)} - - return dict( - (res_id, rendered) - for lang, (template, tpl_res_ids) in templates_res_ids.items() - for res_id, rendered in template._render_template( - template[field], template.model, tpl_res_ids, - post_process=post_process - ).items() - ) - - # ------------------------------------------------------------ # MESSAGE/EMAIL VALUES GENERATION # ------------------------------------------------------------ diff --git a/addons/sms/models/mail_thread.py b/addons/sms/models/mail_thread.py index 86713fddc24..820c5230cfe 100644 --- a/addons/sms/models/mail_thread.py +++ b/addons/sms/models/mail_thread.py @@ -180,8 +180,7 @@ class MailThread(models.AbstractModel): if not template and template_xmlid: template = self.env.ref(template_xmlid, raise_if_not_found=False) if template: - template_w_lang = template._get_context_lang_per_id(self.ids)[self.id] - body = template._render_template(template_w_lang.body, self._name, self.ids)[self.id] + body = template._render_field('body', self.ids, compute_lang=True)[self.id] else: body = self.env['sms.template']._render_template(template_fallback, self._name, self.ids)[self.id] return self._message_sms(body, partner_ids=partner_ids, **kwargs) diff --git a/addons/sms/models/sms_template.py b/addons/sms/models/sms_template.py index a2b2300051b..fb5b8877e87 100644 --- a/addons/sms/models/sms_template.py +++ b/addons/sms/models/sms_template.py @@ -24,9 +24,6 @@ class SMSTemplate(models.Model): help="The type of document this template can be used with", ondelete='cascade') model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True) body = fields.Char('Body', translate=True, required=True) - lang = fields.Char('Language', help="Use this field to either force a specific language (ISO code) or dynamically " - "detect the language of your recipient by a placeholder expression " - "(e.g. ${object.partner_id.lang})") # Use to create contextual action (same as for email template) sidebar_action_id = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False, help="Sidebar action to make this template available on records " @@ -67,43 +64,3 @@ class SMSTemplate(models.Model): if template.sidebar_action_id: template.sidebar_action_id.unlink() return True - - # ------------------------------------------------------------ - # RENDERING - # ------------------------------------------------------------ - - def _get_context_lang_per_id(self, res_ids): - self.ensure_one() - if res_ids is None: - return {None: self} - - if self.env.context.get('template_preview_lang'): - lang = self.env.context.get('template_preview_lang') - results = dict((res_id, self.with_context(lang=lang)) for res_id in res_ids) - else: - rendered_langs = self._render_template(self.lang, self.model, res_ids) - results = dict( - (res_id, self.with_context(lang=lang) if lang else self) - for res_id, lang in rendered_langs.items()) - - return results - - def _get_ids_per_lang(self, res_ids): - self.ensure_one() - - rids_to_tpl = self._get_context_lang_per_id(res_ids) - tpl_to_rids = {} - for res_id, template in rids_to_tpl.items(): - tpl_to_rids.setdefault(template._context.get('lang', self.env.user.lang), []).append(res_id) - - return tpl_to_rids - - def _get_translated_bodies(self, res_ids): - """ return sms translated bodies into a dict {'res_id':'body'} """ - self.ensure_one() - lang_to_rids = self._get_ids_per_lang(res_ids) - all_bodies = {} - for lang, rids in lang_to_rids.items(): - template = self.with_context(lang=lang) - all_bodies.update(template._render_template(template.body, self.model, rids)) - return all_bodies diff --git a/addons/sms/wizard/sms_composer.py b/addons/sms/wizard/sms_composer.py index 60c915d8172..7d5cbc9bfd2 100644 --- a/addons/sms/wizard/sms_composer.py +++ b/addons/sms/wizard/sms_composer.py @@ -168,7 +168,7 @@ class SendSMS(models.TransientModel): @api.onchange('composition_mode', 'res_model', 'res_id', 'template_id') def _onchange_template_id(self): if self.template_id and self.composition_mode == 'comment' and self.res_id: - self.body = self.template_id._get_translated_bodies([self.res_id])[self.res_id] + self.body = self.template_id._render_field('body', [self.res_id], compute_lang=True)[self.res_id] elif self.template_id: self.body = self.template_id.body @@ -279,7 +279,7 @@ class SendSMS(models.TransientModel): def _prepare_body_values(self, records): if self.template_id and self.body == self.template_id.body: - all_bodies = self.template_id._get_translated_bodies(records.ids) + all_bodies = self.template_id._render_field('body', records.ids, compute_lang=True) else: all_bodies = self.env['mail.render.mixin']._render_template(self.body, records._name, records.ids) return all_bodies diff --git a/addons/sms/wizard/sms_template_preview.py b/addons/sms/wizard/sms_template_preview.py index 9d00185ee2e..837c0b821b8 100644 --- a/addons/sms/wizard/sms_template_preview.py +++ b/addons/sms/wizard/sms_template_preview.py @@ -45,6 +45,7 @@ class SMSTemplatePreview(models.TransientModel): @api.depends('lang', 'resource_ref') def _compute_sms_template_fields(self): for wizard in self: - # Update body depending of the resource_ref - sms_template = wizard.sms_template_id.with_context(lang=wizard.lang) - wizard.body = sms_template._render_template(sms_template.body, sms_template.model, wizard.resource_ref.id) if wizard.resource_ref else sms_template.body + if wizard.sms_template_id and wizard.resource_ref: + wizard.body = wizard.sms_template_id._render_field('body', [wizard.resource_ref.id], set_lang=wizard.lang)[wizard.resource_ref.id] + else: + wizard.body = wizard.sms_template_id.body diff --git a/addons/test_mail_full/tests/test_sms_template.py b/addons/test_mail_full/tests/test_sms_template.py index a39edf8545f..d688b30d0f7 100644 --- a/addons/test_mail_full/tests/test_sms_template.py +++ b/addons/test_mail_full/tests/test_sms_template.py @@ -50,18 +50,20 @@ class TestSmsTemplate(test_mail_full_common.TestSMSCommon, test_mail_full_common self.assertEqual(self.sms_template.body, self.body_en) self.assertEqual(self.sms_template.with_context(lang='fr_FR').body, self.body_fr) - rid_to_tpl = self.sms_template._get_context_lang_per_id((self.test_record | test_record_2).ids) - self.assertEqual(set(rid_to_tpl.keys()), set((self.test_record | test_record_2).ids)) - for rid, tpl in rid_to_tpl.items(): + rid_to_lang = self.sms_template._render_lang((self.test_record | test_record_2).ids) + self.assertEqual(set(rid_to_lang.keys()), set((self.test_record | test_record_2).ids)) + for rid, lang in rid_to_lang.items(): + # TDE FIXME: False or en_US ? if rid == self.test_record.id: - self.assertEqual(tpl._context.get('lang'), 'en_US') + self.assertEqual(lang, 'en_US') elif rid == test_record_2.id: - self.assertEqual(tpl._context.get('lang'), 'fr_FR') + self.assertEqual(lang, 'fr_FR') else: self.assertTrue(False) - lang_to_rids = self.sms_template._get_ids_per_lang((self.test_record | test_record_2).ids) - for lang, rids in lang_to_rids.items(): + tpl_to_rids = self.sms_template._classify_per_lang((self.test_record | test_record_2).ids) + for lang, (tpl, rids) in tpl_to_rids.items(): + # TDE FIXME: False or en_US ? if lang == 'en_US': self.assertEqual(rids, self.test_record.ids) elif lang == 'fr_FR': @@ -87,4 +89,3 @@ class TestSmsTemplate(test_mail_full_common.TestSMSCommon, test_mail_full_common self.sms_template.unlink() self.assertEqual(ActWindow.search_count([('id', '=', action_id)]), 0) - |
