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'))]}"/> + + + + + + + + + + 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):