diff options
| author | laa <laa@odoo.com> | 2019-09-11 15:04:40 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2019-11-07 16:19:37 +0000 |
| commit | 72aa04984463db0b15770cbf26fd15dd9c2ccaee (patch) | |
| tree | 1cbd3b140dd9338a4a2f3e460cb552dd148487d8 /addons | |
| parent | dc70fb35a104e260b40425fce23cba84b9770994 (diff) | |
[IMP] mail, mass_mailing: add dynamic placeholder mixin and use it in mailing and templates
PURPOSE
Upgrade the "mass_mailing" and "mass_mailing_sms" modules with a dynamic
placeholder generator as it already exists in "mail module" as depicted in
https://www.screencast.com/t/cnFA0gIY.
SPECIFICATIONS
As duplicated code already exists for that and that a third version of this
code has to be added, instead create a mixin for this dynamic placeholder
generator to avoid code duplication.
Thereby
* a mail.render mixin for the dynamic placeholder generator must be
created in mail;
* dynamic placeholder generator code present in mail.template.py must be
moved to that mixin and replaced by a simple inherit;
* use the mixin in
* mail templates: mail.template.py (mail module);
* mass mailings: mailing.py (mass_mailing module);
* sms templates: sms.template (mass_mailing_sms module);
In a near future, some code will be added in this mixin, notably the template
rendering that could be moved outside of mail.template core model and moved
in that rendering mixin.
LINKS
Task ID 2070612
PR #36722
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/mail/models/__init__.py | 1 | ||||
| -rw-r--r-- | addons/mail/models/mail_render_mixin.py | 68 | ||||
| -rw-r--r-- | addons/mail/models/mail_template.py | 51 | ||||
| -rw-r--r-- | addons/mass_mailing/models/mailing.py | 4 | ||||
| -rw-r--r-- | addons/mass_mailing/views/mailing_mailing_views.xml | 13 | ||||
| -rw-r--r-- | addons/sms/models/sms_template.py | 56 |
6 files changed, 86 insertions, 107 deletions
diff --git a/addons/mail/models/__init__.py b/addons/mail/models/__init__.py index 9b82416fed2..e123a3920be 100644 --- a/addons/mail/models/__init__.py +++ b/addons/mail/models/__init__.py @@ -6,6 +6,7 @@ from . import mail_tracking_value from . import mail_alias from . import mail_followers from . import mail_notification +from . import mail_render_mixin from . import mail_message from . import mail_activity from . import mail_mail diff --git a/addons/mail/models/mail_render_mixin.py b/addons/mail/models/mail_render_mixin.py new file mode 100644 index 00000000000..c2fafe1d56e --- /dev/null +++ b/addons/mail/models/mail_render_mixin.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + +class MailRenderMixin(models.AbstractModel): + + _name = 'mail.render.mixin' + _description = 'Mail Render Mixin' + + model_object_field = fields.Many2one( + 'ir.model.fields', string="Field", store=False, + help="Select target field from the related document model.\n" + "If it is a relationship field you will be able to select " + "a target field at the destination of the relationship.") + sub_object = fields.Many2one( + 'ir.model', 'Sub-model', readonly=True, store=False, + help="When a relationship field is selected as first field, " + "this field shows the document model the relationship goes to.") + sub_model_object_field = fields.Many2one( + 'ir.model.fields', 'Sub-field', store=False, + help="When a relationship field is selected as first field, " + "this field lets you select the target field within the " + "destination document model (sub-model).") + null_value = fields.Char('Default Value', store=False, help="Optional value to use if the target field is empty") + copyvalue = fields.Char( + 'Placeholder Expression',store=False, + help="Final placeholder expression, to be copy-pasted in the desired template field.") + + @api.onchange('model_object_field', 'sub_model_object_field', 'null_value') + def _onchange_dynamic_placeholder(self): + """ Generate the dynamic placeholder """ + if self.model_object_field: + if self.model_object_field.ttype in ['many2one', 'one2many', 'many2many']: + model = self.env['ir.model']._get(self.model_object_field.relation) + if model: + self.sub_object = model.id + sub_field_name = self.sub_model_object_field.name + self.copyvalue = self._build_expression(self.model_object_field.name, + sub_field_name, self.null_value or False) + else: + self.sub_object = False + self.sub_model_object_field = False + self.copyvalue = self._build_expression(self.model_object_field.name, False, self.null_value or False) + else: + self.sub_object = False + self.copyvalue = False + self.sub_model_object_field = False + self.null_value = False + + @api.model + def _build_expression(self, field_name, sub_field_name, null_value): + """Returns a placeholder expression for use in a template field, + based on the values provided in the placeholder assistant. + + :param field_name: main field name + :param sub_field_name: sub field name (M2O) + :param null_value: default value if the target value is empty + :return: final placeholder expression """ + expression = '' + if field_name: + expression = "${object." + field_name + if sub_field_name: + expression += "." + sub_field_name + if null_value: + expression += " or '''%s'''" % null_value + expression += "}" + return expression diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 8a7eaff79ce..2a0261623a2 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -80,6 +80,7 @@ except ImportError: class MailTemplate(models.Model): "Templates for sending email" _name = "mail.template" + _inherit = ['mail.render.mixin'] _description = 'Email Templates' _order = 'name' @@ -134,20 +135,6 @@ class MailTemplate(models.Model): "emails created from this template") auto_delete = fields.Boolean('Auto Delete', default=True, help="Permanently delete this email after sending it, to save space") - # Fake fields used to implement the placeholder assistant - model_object_field = fields.Many2one('ir.model.fields', string="Field", - help="Select target field from the related document model.\n" - "If it is a relationship field you will be able to select " - "a target field at the destination of the relationship.") - sub_object = fields.Many2one('ir.model', 'Sub-model', readonly=True, - help="When a relationship field is selected as first field, " - "this field shows the document model the relationship goes to.") - sub_model_object_field = fields.Many2one('ir.model.fields', 'Sub-field', - help="When a relationship field is selected as first field, " - "this field lets you select the target field within the " - "destination document model (sub-model).") - null_value = fields.Char('Default Value', help="Optional value to use if the target field is empty") - copyvalue = fields.Char('Placeholder Expression', help="Final placeholder expression, to be copy-pasted in the desired template field.") scheduled_date = fields.Char('Scheduled Date', help="If set, the queue manager will send the email after the date. If not set, the email will be send as soon as possible. Jinja2 placeholders may be used.") @api.onchange('model_id') @@ -158,42 +145,6 @@ class MailTemplate(models.Model): else: self.model = False - def build_expression(self, field_name, sub_field_name, null_value): - """Returns a placeholder expression for use in a template field, - based on the values provided in the placeholder assistant. - - :param field_name: main field name - :param sub_field_name: sub field name (M2O) - :param null_value: default value if the target value is empty - :return: final placeholder expression """ - expression = '' - if field_name: - expression = "${object." + field_name - if sub_field_name: - expression += "." + sub_field_name - if null_value: - expression += " or '''%s'''" % null_value - expression += "}" - return expression - - @api.onchange('model_object_field', 'sub_model_object_field', 'null_value') - def onchange_sub_model_object_value_field(self): - if self.model_object_field: - if self.model_object_field.ttype in ['many2one', 'one2many', 'many2many']: - model = self.env['ir.model']._get(self.model_object_field.relation) - if model: - self.sub_object = model.id - self.copyvalue = self.build_expression(self.model_object_field.name, self.sub_model_object_field and self.sub_model_object_field.name or False, self.null_value or False) - else: - self.sub_object = False - self.sub_model_object_field = False - self.copyvalue = self.build_expression(self.model_object_field.name, False, self.null_value or False) - else: - self.sub_object = False - self.copyvalue = False - self.sub_model_object_field = False - self.null_value = False - def unlink(self): self.unlink_action() return super(MailTemplate, self).unlink() diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 019763ac20e..cd098b3a347 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -40,7 +40,7 @@ class MassMailing(models.Model): A mass mailing is an occurence of sending emails. """ _name = 'mailing.mailing' _description = 'Mass Mailing' - _inherit = [ 'mail.thread', 'mail.activity.mixin'] + _inherit = [ 'mail.thread', 'mail.activity.mixin', 'mail.render.mixin'] # number of periods for tracking mail_mail statistics _period_number = 6 _order = 'sent_date DESC' @@ -128,7 +128,7 @@ class MassMailing(models.Model): replied_ratio = fields.Integer(compute="_compute_statistics", string='Replied Ratio') bounced_ratio = fields.Integer(compute="_compute_statistics", string='Bounced Ratio') next_departure = fields.Datetime(compute="_compute_next_departure", string='Scheduled date') - + def _compute_total(self): for mass_mailing in self: mass_mailing.total = len(mass_mailing.sudo()._get_recipients()) diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index 7d26cce71be..ad6895ad170 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -177,6 +177,19 @@ 'inline-field': 'body_html' }" attrs="{'readonly': [('state', 'in', ('sending', 'done'))]}"/> </page> + <page string="Dynamic Placeholder Generator" groups="base.group_no_one"> + <group> + <field name="model_object_field" attrs="{'invisible': True}"/> + <field name="model_object_field" + domain="[('model_id','=',mailing_model_real),('ttype','!=','one2many'),('ttype','!=','many2many')]"/> + <field name="sub_object" readonly="1"/> + <field name="sub_model_object_field" + domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]" + attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"/> + <field name="null_value"/> + <field name="copyvalue"/> + </group> + </page> <page string="Settings"> <group> <group> diff --git a/addons/sms/models/sms_template.py b/addons/sms/models/sms_template.py index cf2120c8a5e..f106c21139f 100644 --- a/addons/sms/models/sms_template.py +++ b/addons/sms/models/sms_template.py @@ -7,6 +7,7 @@ from odoo import api, fields, models, _ class SMSTemplate(models.Model): "Templates for sending SMS" _name = "sms.template" + _inherit = ['mail.render.mixin'] _description = 'SMS Templates' @api.model @@ -30,61 +31,6 @@ class SMSTemplate(models.Model): 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 " "of the related document model") - # Fake fields used to implement the placeholder assistant - model_object_field = fields.Many2one('ir.model.fields', string="Field", store=False, - help="Select target field from the related document model.\n" - "If it is a relationship field you will be able to select " - "a target field at the destination of the relationship.") - sub_object = fields.Many2one('ir.model', 'Sub-model', readonly=True, store=False, - help="When a relationship field is selected as first field, " - "this field shows the document model the relationship goes to.") - sub_model_object_field = fields.Many2one('ir.model.fields', 'Sub-field', store=False, - help="When a relationship field is selected as first field, " - "this field lets you select the target field within the " - "destination document model (sub-model).") - null_value = fields.Char('Default Value', store=False, help="Optional value to use if the target field is empty") - copyvalue = fields.Char('Placeholder Expression', store=False, - help="Final placeholder expression, to be copy-pasted in the desired template field.") - - @api.onchange('model_object_field', 'sub_model_object_field', 'null_value') - def _onchange_dynamic_placeholder(self): - """ Generate the dynamic placeholder """ - if self.model_object_field: - if self.model_object_field.ttype in ['many2one', 'one2many', 'many2many']: - model = self.env['ir.model']._get(self.model_object_field.relation) - if model: - self.sub_object = model.id - sub_field_name = self.sub_model_object_field.name - self.copyvalue = self._build_expression(self.model_object_field.name, - sub_field_name, self.null_value or False) - else: - self.sub_object = False - self.sub_model_object_field = False - self.copyvalue = self._build_expression(self.model_object_field.name, False, self.null_value or False) - else: - self.sub_object = False - self.copyvalue = False - self.sub_model_object_field = False - self.null_value = False - - @api.model - def _build_expression(self, field_name, sub_field_name, null_value): - """Returns a placeholder expression for use in a template field, - based on the values provided in the placeholder assistant. - - :param field_name: main field name - :param sub_field_name: sub field name (M2O) - :param null_value: default value if the target value is empty - :return: final placeholder expression """ - expression = '' - if field_name: - expression = "${object." + field_name - if sub_field_name: - expression += "." + sub_field_name - if null_value: - expression += " or '''%s'''" % null_value - expression += "}" - return expression @api.returns('self', lambda value: value.id) def copy(self, default=None): |
