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):