[REF] mail: improve propagation and setup of render context when posting messages
PURPOSE Purpose of this commit is to cleanup flow of values going through message_post and its sub methods until email generation for notifications. SPECIFICATIONS Ensure some values are given directly when creating message linked to post methods to avoid browsing message when value is not known. Notably make signature propagation (add_sign) more explicit in message_post and its sub methods (notify, log, ...). Prepare future language related improvements by allowing to force company and lang values for rendering context. Also add ``is_html_empty`` tool method to use it in notification templates. It will be used notably to check for empty html blocks, e.g. user signature. Rename some internal variables to better understand their purpose. Finally update some outdated and/or badly indented docstrings. Task-2726501 (Mail: Propagate message values in post methods) Part-of: odoo/odoo#82167
This commit is contained in:
@@ -7,6 +7,7 @@ import logging
|
|||||||
|
|
||||||
from odoo import _, api, fields, models, tools, Command
|
from odoo import _, api, fields, models, tools, Command
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
from odoo.tools import is_html_empty
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -301,10 +302,20 @@ class MailTemplate(models.Model):
|
|||||||
model = model.with_context(lang=lang)
|
model = model.with_context(lang=lang)
|
||||||
|
|
||||||
template_ctx = {
|
template_ctx = {
|
||||||
|
# message
|
||||||
'message': self.env['mail.message'].sudo().new(dict(body=values['body_html'], record_name=record.display_name)),
|
'message': self.env['mail.message'].sudo().new(dict(body=values['body_html'], record_name=record.display_name)),
|
||||||
|
'subtype': self.env['mail.message.subtype'].sudo(),
|
||||||
|
# record
|
||||||
'model_description': model.display_name,
|
'model_description': model.display_name,
|
||||||
'company': 'company_id' in record and record['company_id'] or self.env.company,
|
|
||||||
'record': record,
|
'record': record,
|
||||||
|
'record_name': False,
|
||||||
|
# user / environment
|
||||||
|
'company': 'company_id' in record and record['company_id'] or self.env.company,
|
||||||
|
'email_add_signature': False,
|
||||||
|
'signature': '',
|
||||||
|
'website_url': '',
|
||||||
|
# tools
|
||||||
|
'is_html_empty': is_html_empty,
|
||||||
}
|
}
|
||||||
body = template._render(template_ctx, engine='ir.qweb', minimal_qcontext=True)
|
body = template._render(template_ctx, engine='ir.qweb', minimal_qcontext=True)
|
||||||
values['body_html'] = self.env['mail.render.mixin']._replace_local_links(body)
|
values['body_html'] = self.env['mail.render.mixin']._replace_local_links(body)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from xmlrpc import client as xmlrpclib
|
|||||||
from odoo import _, api, exceptions, fields, models, tools, registry, SUPERUSER_ID, Command
|
from odoo import _, api, exceptions, fields, models, tools, registry, SUPERUSER_ID, Command
|
||||||
from odoo.exceptions import MissingError
|
from odoo.exceptions import MissingError
|
||||||
from odoo.osv import expression
|
from odoo.osv import expression
|
||||||
|
from odoo.tools import is_html_empty
|
||||||
from odoo.tools.misc import clean_context, split_every
|
from odoo.tools.misc import clean_context, split_every
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
@@ -1644,12 +1644,22 @@ class MailThread(models.AbstractModel):
|
|||||||
|
|
||||||
def _message_post_process_attachments(self, attachments, attachment_ids, message_values):
|
def _message_post_process_attachments(self, attachments, attachment_ids, message_values):
|
||||||
""" Preprocess attachments for mail_thread.message_post() or mail_mail.create().
|
""" Preprocess attachments for mail_thread.message_post() or mail_mail.create().
|
||||||
|
Purpose is to
|
||||||
|
|
||||||
:param list attachments: list of attachment tuples in the form ``(name,content)``, #todo xdo update that
|
* transfer attachments given by ``attachment_ids`` from the composer to
|
||||||
where content is NOT base64 encoded
|
the record (if any);
|
||||||
:param list attachment_ids: a list of attachment ids, not in tomany command form
|
* limit attachments manipulation when being a shared user;
|
||||||
:param dict message_data: model: the model of the attachments parent record,
|
* create attachments from ``attachments``. If those are linked to the
|
||||||
res_id: the id of the attachments parent record
|
content (body) through CIDs body is updated accordingly;
|
||||||
|
|
||||||
|
:param list(tuple(str,str), tuple(str,str, dict)) attachments : list of attachment
|
||||||
|
tuples in the form ``(name,content)`` or ``(name,content, info)`` where content
|
||||||
|
is NOT base64 encoded;
|
||||||
|
:param list attachment_ids: list of existing attachments to link to this message;
|
||||||
|
:param message_values: dictionary of values that will be used to create the
|
||||||
|
message. It is used to find back record- or content- context;
|
||||||
|
|
||||||
|
:return dict: new values for message: 'attachment_ids' and optionally 'body'
|
||||||
"""
|
"""
|
||||||
return_values = {}
|
return_values = {}
|
||||||
body = message_values.get('body')
|
body = message_values.get('body')
|
||||||
@@ -1703,7 +1713,7 @@ class MailThread(models.AbstractModel):
|
|||||||
content = content.as_bytes()
|
content = content.as_bytes()
|
||||||
elif content is None:
|
elif content is None:
|
||||||
continue
|
continue
|
||||||
attachement_values= {
|
attachement_values = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'datas': base64.b64encode(content),
|
'datas': base64.b64encode(content),
|
||||||
'type': 'binary',
|
'type': 'binary',
|
||||||
@@ -1753,29 +1763,37 @@ class MailThread(models.AbstractModel):
|
|||||||
email_from=None, author_id=None, parent_id=False,
|
email_from=None, author_id=None, parent_id=False,
|
||||||
subtype_xmlid=None, subtype_id=False, partner_ids=None,
|
subtype_xmlid=None, subtype_id=False, partner_ids=None,
|
||||||
attachments=None, attachment_ids=None,
|
attachments=None, attachment_ids=None,
|
||||||
add_sign=True, record_name=False,
|
|
||||||
**kwargs):
|
**kwargs):
|
||||||
""" Post a new message in an existing thread, returning the new
|
""" Post a new message in an existing thread, returning the new mail.message.
|
||||||
mail.message ID.
|
|
||||||
:param str body: body of the message, usually raw HTML that will
|
:param str body: body of the message, usually raw HTML that will
|
||||||
be sanitized
|
be sanitized
|
||||||
:param str subject: subject of the message
|
:param str subject: subject of the message
|
||||||
:param str message_type: see mail_message.message_type field. Can be anything but
|
:param str message_type: see mail_message.message_type field. Can be anything but
|
||||||
user_notification, reserved for message_notify
|
user_notification, reserved for message_notify
|
||||||
:param int parent_id: handle thread formation
|
:param str email_from: from address of the author. See ``_message_compute_author``
|
||||||
:param int subtype_id: subtype_id of the message, used mainly use for
|
that uses it to make email_from / author_id coherent;
|
||||||
followers notification mechanism;
|
:param int author_id: optional ID of partner record being the author. See
|
||||||
:param list(int) partner_ids: partner_ids to notify in addition to partners
|
``_message_compute_author`` that uses it to make email_from / author_id coherent;
|
||||||
computed based on subtype / followers matching;
|
:param int parent_id: handle thread formation
|
||||||
:param list(tuple(str,str), tuple(str,str, dict) or int) attachments : list of attachment tuples in the form
|
:param int subtype_id: subtype_id of the message, used mainly for followers
|
||||||
``(name,content)`` or ``(name,content, info)``, where content is NOT base64 encoded
|
notification mechanism;
|
||||||
:param list id attachment_ids: list of existing attachement to link to this message
|
:param list(int) partner_ids: partner_ids to notify in addition to partners
|
||||||
-Should only be setted by chatter
|
computed based on subtype / followers matching;
|
||||||
-Attachement object attached to mail.compose.message(0) will be attached
|
:param list(tuple(str,str), tuple(str,str, dict)) attachments : list of attachment
|
||||||
to the related document.
|
tuples in the form ``(name,content)`` or ``(name,content, info)`` where content
|
||||||
Extra keyword arguments will be used as default column values for the
|
is NOT base64 encoded;
|
||||||
new mail.message record.
|
:param list attachment_ids: list of existing attachments to link to this message
|
||||||
:return int: ID of newly created mail.message
|
-Should only be set by chatter
|
||||||
|
-Attachment object attached to mail.compose.message(0) will be attached
|
||||||
|
to the related document.
|
||||||
|
|
||||||
|
Extra keyword arguments will be used either
|
||||||
|
* as default column values for the new mail.message record if they match
|
||||||
|
mail.message fields;
|
||||||
|
* propagated to notification methods;
|
||||||
|
|
||||||
|
:return record: newly create mail.message
|
||||||
"""
|
"""
|
||||||
self.ensure_one() # should always be posted on a record, use message_notify if no record
|
self.ensure_one() # should always be posted on a record, use message_notify if no record
|
||||||
# split message additional values from notify additional values
|
# split message additional values from notify additional values
|
||||||
@@ -1795,12 +1813,11 @@ class MailThread(models.AbstractModel):
|
|||||||
if any(not isinstance(pc_id, int) for pc_id in partner_ids):
|
if any(not isinstance(pc_id, int) for pc_id in partner_ids):
|
||||||
raise ValueError(_('message_post partner_ids and must be integer list, not commands.'))
|
raise ValueError(_('message_post partner_ids and must be integer list, not commands.'))
|
||||||
|
|
||||||
self = self._fallback_lang() # add lang to context imediatly since it will be usefull in various flows latter.
|
self = self._fallback_lang() # add lang to context immediately since it will be useful in various flows latter.
|
||||||
|
|
||||||
# Explicit access rights check, because display_name is computed as sudo.
|
# Explicit access rights check, because display_name is computed as sudo.
|
||||||
self.check_access_rights('read')
|
self.check_access_rights('read')
|
||||||
self.check_access_rule('read')
|
self.check_access_rule('read')
|
||||||
record_name = record_name or self.display_name
|
|
||||||
|
|
||||||
# Find the message's author
|
# Find the message's author
|
||||||
if self.env.user._is_public() and 'guest' in self.env.context:
|
if self.env.user._is_public() and 'guest' in self.env.context:
|
||||||
@@ -1821,38 +1838,43 @@ class MailThread(models.AbstractModel):
|
|||||||
|
|
||||||
parent_id = self._message_compute_parent_id(parent_id)
|
parent_id = self._message_compute_parent_id(parent_id)
|
||||||
|
|
||||||
values = dict(msg_kwargs)
|
msg_values = dict(msg_kwargs)
|
||||||
values.update({
|
if 'add_sign' not in msg_values:
|
||||||
|
msg_values['add_sign'] = True
|
||||||
|
if not msg_values.get('record_name'):
|
||||||
|
msg_values['record_name'] = self.display_name
|
||||||
|
msg_values.update({
|
||||||
'author_id': author_id,
|
'author_id': author_id,
|
||||||
'author_guest_id': author_guest_id,
|
'author_guest_id': author_guest_id,
|
||||||
'email_from': email_from,
|
'email_from': email_from,
|
||||||
'model': self._name,
|
'model': self._name,
|
||||||
'res_id': self.id,
|
'res_id': self.id,
|
||||||
|
# content
|
||||||
'body': body,
|
'body': body,
|
||||||
'subject': subject or False,
|
'subject': subject or False,
|
||||||
'message_type': message_type,
|
'message_type': message_type,
|
||||||
'parent_id': parent_id,
|
'parent_id': parent_id,
|
||||||
'subtype_id': subtype_id,
|
'subtype_id': subtype_id,
|
||||||
|
# recipients
|
||||||
'partner_ids': partner_ids,
|
'partner_ids': partner_ids,
|
||||||
'add_sign': add_sign,
|
|
||||||
'record_name': record_name,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
attachments = attachments or []
|
attachments = attachments or []
|
||||||
attachment_ids = attachment_ids or []
|
attachment_ids = attachment_ids or []
|
||||||
attachement_values = self._message_post_process_attachments(attachments, attachment_ids, values)
|
attachement_values = self._message_post_process_attachments(attachments, attachment_ids, msg_values)
|
||||||
values.update(attachement_values) # attachement_ids, [body]
|
msg_values.update(attachement_values) # attachement_ids, [body]
|
||||||
|
|
||||||
new_message = self._message_create(values)
|
new_message = self._message_create(msg_values)
|
||||||
|
|
||||||
# Set main attachment field if necessary
|
# Set main attachment field if necessary
|
||||||
self._message_set_main_attachment_id(values['attachment_ids'])
|
self._message_set_main_attachment_id(msg_values['attachment_ids'])
|
||||||
|
|
||||||
if values['author_id'] and values['message_type'] != 'notification' and not self._context.get('mail_create_nosubscribe'):
|
if msg_values['author_id'] and msg_values['message_type'] != 'notification' and not self._context.get('mail_create_nosubscribe'):
|
||||||
if self.env['res.partner'].browse(values['author_id']).active: # we dont want to add odoobot/inactive as a follower
|
if self.env['res.partner'].browse(msg_values['author_id']).active: # we dont want to add odoobot/inactive as a follower
|
||||||
self._message_subscribe(partner_ids=[values['author_id']])
|
self._message_subscribe(partner_ids=[msg_values['author_id']])
|
||||||
|
|
||||||
self._message_post_after_hook(new_message, values)
|
self._message_post_after_hook(new_message, msg_values)
|
||||||
self._notify_thread(new_message, values, **notif_kwargs)
|
self._notify_thread(new_message, msg_values, **notif_kwargs)
|
||||||
return new_message
|
return new_message
|
||||||
|
|
||||||
def _message_set_main_attachment_id(self, attachment_ids): # todo move this out of mail.thread
|
def _message_set_main_attachment_id(self, attachment_ids): # todo move this out of mail.thread
|
||||||
@@ -1957,7 +1979,7 @@ class MailThread(models.AbstractModel):
|
|||||||
res_id = False
|
res_id = False
|
||||||
|
|
||||||
MailThread = self.env['mail.thread']
|
MailThread = self.env['mail.thread']
|
||||||
values = {
|
msg_values = {
|
||||||
'parent_id': parent_id,
|
'parent_id': parent_id,
|
||||||
'model': self._name if self else model,
|
'model': self._name if self else model,
|
||||||
'res_id': self.id if self else res_id,
|
'res_id': self.id if self else res_id,
|
||||||
@@ -1973,9 +1995,12 @@ class MailThread(models.AbstractModel):
|
|||||||
'reply_to': MailThread._notify_get_reply_to(default=email_from)[False],
|
'reply_to': MailThread._notify_get_reply_to(default=email_from)[False],
|
||||||
'message_id': tools.generate_tracking_message_id('message-notify'),
|
'message_id': tools.generate_tracking_message_id('message-notify'),
|
||||||
}
|
}
|
||||||
values.update(msg_kwargs)
|
msg_values.update(msg_kwargs)
|
||||||
new_message = MailThread._message_create(values)
|
if 'add_sign' not in msg_values:
|
||||||
MailThread._notify_thread(new_message, values, **notif_kwargs)
|
msg_values['add_sign'] = True
|
||||||
|
|
||||||
|
new_message = MailThread._message_create(msg_values)
|
||||||
|
MailThread._notify_thread(new_message, msg_values, **notif_kwargs)
|
||||||
return new_message
|
return new_message
|
||||||
|
|
||||||
def _message_log_with_view(self, views_or_xmlid, **kwargs):
|
def _message_log_with_view(self, views_or_xmlid, **kwargs):
|
||||||
@@ -1992,7 +2017,7 @@ class MailThread(models.AbstractModel):
|
|||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
author_id, email_from = self._message_compute_author(author_id, email_from, raise_exception=False)
|
author_id, email_from = self._message_compute_author(author_id, email_from, raise_exception=False)
|
||||||
|
|
||||||
message_values = {
|
msg_values = {
|
||||||
'subject': subject,
|
'subject': subject,
|
||||||
'body': body,
|
'body': body,
|
||||||
'author_id': author_id,
|
'author_id': author_id,
|
||||||
@@ -2005,9 +2030,10 @@ class MailThread(models.AbstractModel):
|
|||||||
'record_name': False,
|
'record_name': False,
|
||||||
'reply_to': self.env['mail.thread']._notify_get_reply_to(default=email_from)[False],
|
'reply_to': self.env['mail.thread']._notify_get_reply_to(default=email_from)[False],
|
||||||
'message_id': tools.generate_tracking_message_id('message-notify'), # why? this is all but a notify
|
'message_id': tools.generate_tracking_message_id('message-notify'), # why? this is all but a notify
|
||||||
|
'add_sign': False, # False as no notification -> no need to compute signature
|
||||||
}
|
}
|
||||||
message_values.update(kwargs)
|
msg_values.update(kwargs)
|
||||||
return self.sudo()._message_create(message_values)
|
return self.sudo()._message_create(msg_values)
|
||||||
|
|
||||||
def _message_log_batch(self, bodies, author_id=None, email_from=None, subject=False, message_type='notification'):
|
def _message_log_batch(self, bodies, author_id=None, email_from=None, subject=False, message_type='notification'):
|
||||||
""" Shortcut allowing to post notes on a batch of documents. It achieve the
|
""" Shortcut allowing to post notes on a batch of documents. It achieve the
|
||||||
@@ -2028,6 +2054,7 @@ class MailThread(models.AbstractModel):
|
|||||||
'record_name': False,
|
'record_name': False,
|
||||||
'reply_to': self.env['mail.thread']._notify_get_reply_to(default=email_from)[False],
|
'reply_to': self.env['mail.thread']._notify_get_reply_to(default=email_from)[False],
|
||||||
'message_id': tools.generate_tracking_message_id('message-notify'), # why? this is all but a notify
|
'message_id': tools.generate_tracking_message_id('message-notify'), # why? this is all but a notify
|
||||||
|
'add_sign': False,
|
||||||
}
|
}
|
||||||
values_list = [dict(base_message_values,
|
values_list = [dict(base_message_values,
|
||||||
res_id=record.id,
|
res_id=record.id,
|
||||||
@@ -2121,6 +2148,9 @@ class MailThread(models.AbstractModel):
|
|||||||
|
|
||||||
:return: recipients data (see ``MailThread._notify_get_recipients()``)
|
:return: recipients data (see ``MailThread._notify_get_recipients()``)
|
||||||
"""
|
"""
|
||||||
|
# add lang to context immediately since it will be useful in various rendering later
|
||||||
|
self = self._fallback_lang()
|
||||||
|
|
||||||
msg_vals = msg_vals if msg_vals else {}
|
msg_vals = msg_vals if msg_vals else {}
|
||||||
recipients_data = self._notify_get_recipients(message, msg_vals)
|
recipients_data = self._notify_get_recipients(message, msg_vals)
|
||||||
if not recipients_data:
|
if not recipients_data:
|
||||||
@@ -2170,8 +2200,8 @@ class MailThread(models.AbstractModel):
|
|||||||
self.env['bus.bus'].sudo()._sendmany(bus_notifications)
|
self.env['bus.bus'].sudo()._sendmany(bus_notifications)
|
||||||
|
|
||||||
def _notify_thread_by_email(self, message, recipients_data, msg_vals=False,
|
def _notify_thread_by_email(self, message, recipients_data, msg_vals=False,
|
||||||
mail_auto_delete=True, # mail.mail
|
mail_auto_delete=True, # mail.mail
|
||||||
model_description=False, # rendering
|
model_description=False, force_email_company=False, force_email_lang=False, # rendering
|
||||||
check_existing=False, force_send=True, send_after_commit=True, # email send
|
check_existing=False, force_send=True, send_after_commit=True, # email send
|
||||||
**kwargs):
|
**kwargs):
|
||||||
""" Method to send email linked to notified messages.
|
""" Method to send email linked to notified messages.
|
||||||
@@ -2196,10 +2226,11 @@ class MailThread(models.AbstractModel):
|
|||||||
|
|
||||||
:param model_description: model description used in email notification process
|
:param model_description: model description used in email notification process
|
||||||
(computed if not given);
|
(computed if not given);
|
||||||
|
:param force_email_company: see ``_notify_by_email_prepare_rendering_context``;
|
||||||
|
:param force_email_lang: see ``_notify_by_email_prepare_rendering_context``;
|
||||||
|
|
||||||
:param check_existing: check for existing notifications to update based on
|
:param check_existing: check for existing notifications to update based on
|
||||||
mailed recipient, otherwise create new notifications;
|
mailed recipient, otherwise create new notifications;
|
||||||
|
|
||||||
:param force_send: send emails directly instead of using queue;
|
:param force_send: send emails directly instead of using queue;
|
||||||
:param send_after_commit: if force_send, tells whether to send emails after
|
:param send_after_commit: if force_send, tells whether to send emails after
|
||||||
the transaction has been committed using a post-commit hook;
|
the transaction has been committed using a post-commit hook;
|
||||||
@@ -2209,14 +2240,18 @@ class MailThread(models.AbstractModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
model = msg_vals.get('model') if msg_vals else message.model
|
model = msg_vals.get('model') if msg_vals else message.model
|
||||||
model_name = model_description or (self._fallback_lang().env['ir.model']._get(model).display_name if model else False) # one query for display name
|
model_name = model_description or (self.env['ir.model']._get(model).display_name if model else False) # one query for display name
|
||||||
recipients_groups_data = self._notify_get_recipients_classify(partners_data, model_name, msg_vals=msg_vals)
|
recipients_groups_data = self._notify_get_recipients_classify(partners_data, model_name, msg_vals=msg_vals)
|
||||||
|
|
||||||
if not recipients_groups_data:
|
if not recipients_groups_data:
|
||||||
return True
|
return True
|
||||||
force_send = self.env.context.get('mail_notify_force_send', force_send)
|
force_send = self.env.context.get('mail_notify_force_send', force_send)
|
||||||
|
|
||||||
template_values = self._notify_by_email_prepare_rendering_context(message, msg_vals, model_description=model_description) # 10 queries
|
template_values = self._notify_by_email_prepare_rendering_context(
|
||||||
|
message, msg_vals=msg_vals, model_description=model_description,
|
||||||
|
force_email_company=force_email_company,
|
||||||
|
force_email_lang=force_email_lang,
|
||||||
|
) # 10 queries
|
||||||
|
|
||||||
email_layout_xmlid = msg_vals.get('email_layout_xmlid') if msg_vals else message.email_layout_xmlid
|
email_layout_xmlid = msg_vals.get('email_layout_xmlid') if msg_vals else message.email_layout_xmlid
|
||||||
template_xmlid = email_layout_xmlid if email_layout_xmlid else 'mail.message_notification_email'
|
template_xmlid = email_layout_xmlid if email_layout_xmlid else 'mail.message_notification_email'
|
||||||
@@ -2316,7 +2351,8 @@ class MailThread(models.AbstractModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _notify_by_email_prepare_rendering_context(self, message, msg_vals, model_description=False):
|
def _notify_by_email_prepare_rendering_context(self, message, msg_vals=False, model_description=False,
|
||||||
|
force_email_company=False, force_email_lang=False):
|
||||||
""" Prepare rendering context for notification email.
|
""" Prepare rendering context for notification email.
|
||||||
|
|
||||||
Signature: if asked a default signature is computed based on author. Either
|
Signature: if asked a default signature is computed based on author. Either
|
||||||
@@ -2324,75 +2360,101 @@ class MailThread(models.AbstractModel):
|
|||||||
user and we compute a default one based on the author's name.
|
user and we compute a default one based on the author's name.
|
||||||
|
|
||||||
Company: either there is one defined on the record (company_id field set
|
Company: either there is one defined on the record (company_id field set
|
||||||
with a value), either we use env.company.
|
with a value), either we use env.company. A new parameter allows to force
|
||||||
|
its value.
|
||||||
|
|
||||||
Lang: when calling this method, ``_fallback_lang`` should already been
|
Lang: when calling this method, ``_fallback_lang`` should already been
|
||||||
called, or a lang set in context with another way. A wild guess is done
|
called, or a lang set in context with another way. A wild guess is done
|
||||||
based on templates to try to retrieve the recipient's language when a flow
|
based on templates to try to retrieve the recipient's language when a flow
|
||||||
like "send by email" is performed. Lang is used to try to have the
|
like "send by email" is performed. Lang is used to try to have the
|
||||||
notification layout in the same language as the email content.
|
notification layout in the same language as the email content. A new
|
||||||
|
parameter allows to force its value.
|
||||||
|
|
||||||
|
:param msg_vals: dictionary of values used to create the message. If given it
|
||||||
|
may be used to access values related to ``message`` without accessing it
|
||||||
|
directly. It lessens query count in some optimized use cases by avoiding
|
||||||
|
access message content in db;
|
||||||
:param model_description: model description used in email notification process
|
:param model_description: model description used in email notification process
|
||||||
(computed if not given);
|
(computed if not given);
|
||||||
|
:param force_email_company: res.company record used when rendering notification
|
||||||
|
layout. Otherwise computed based on current record;
|
||||||
|
:param force_email_lang: lang used when rendering content, used notably to
|
||||||
|
compute model name;
|
||||||
"""
|
"""
|
||||||
|
if msg_vals is False:
|
||||||
|
msg_vals = {}
|
||||||
|
|
||||||
|
# compute send user and its related signature; try to use self.env.user instead of browsing
|
||||||
|
# user_ids if he is the author will give a sudo user, improving access performances and cache usage.
|
||||||
signature = ''
|
signature = ''
|
||||||
user = self.env.user
|
add_sign = msg_vals.get('add_sign') if 'add_sign' in msg_vals else message.add_sign
|
||||||
author = message.env['res.partner'].browse(msg_vals.get('author_id')) if msg_vals else message.author_id
|
if add_sign:
|
||||||
model = msg_vals.get('model') if msg_vals else message.model
|
author = message.env['res.partner'].browse(msg_vals.get('author_id')) if 'author_id' in msg_vals else message.author_id
|
||||||
add_sign = msg_vals.get('add_sign') if msg_vals else message.add_sign
|
author_user = self.env.user if self.env.user.partner_id == author else author.user_ids[0] if author and author.user_ids else False
|
||||||
subtype_id = msg_vals.get('subtype_id') if msg_vals else message.subtype_id.id
|
if author_user:
|
||||||
message_id = message.id
|
signature = author_user.signature
|
||||||
record_name = msg_vals.get('record_name') if msg_vals else message.record_name
|
else:
|
||||||
author_user = user if user.partner_id == author else author.user_ids[0] if author and author.user_ids else False
|
|
||||||
# trying to use user (self.env.user) instead of browing user_ids if he is the author will give a sudo user,
|
|
||||||
# improving access performances and cache usage.
|
|
||||||
if author_user:
|
|
||||||
user = author_user
|
|
||||||
if add_sign:
|
|
||||||
signature = user.signature
|
|
||||||
else:
|
|
||||||
if add_sign:
|
|
||||||
signature = "<p>-- <br/>%s</p>" % author.name
|
signature = "<p>-- <br/>%s</p>" % author.name
|
||||||
|
|
||||||
company = self.company_id.sudo() if self and 'company_id' in self and self.company_id else self.env.company
|
if force_email_company:
|
||||||
|
company = force_email_company
|
||||||
|
else:
|
||||||
|
company = self.company_id.sudo() if self and 'company_id' in self and self.company_id else self.env.company
|
||||||
if company.website:
|
if company.website:
|
||||||
website_url = 'http://%s' % company.website if not company.website.lower().startswith(('http:', 'https:')) else company.website
|
website_url = 'http://%s' % company.website if not company.website.lower().startswith(('http:', 'https:')) else company.website
|
||||||
else:
|
else:
|
||||||
website_url = False
|
website_url = False
|
||||||
|
|
||||||
# TDE FIXME: this whole brol should be cleaned !
|
# compute lang in which content was rendered or typed
|
||||||
lang = self.env.context.get('lang')
|
lang = False
|
||||||
if {'default_template_id', 'default_model', 'default_res_id'} <= self.env.context.keys():
|
if force_email_lang:
|
||||||
|
lang = force_email_lang
|
||||||
|
elif {'default_template_id', 'default_model', 'default_res_id'} <= self.env.context.keys():
|
||||||
|
# TDE FIXME: this whole brol should be cleaned !
|
||||||
template = self.env['mail.template'].browse(self.env.context['default_template_id'])
|
template = self.env['mail.template'].browse(self.env.context['default_template_id'])
|
||||||
if template and template.lang:
|
if template and template.lang:
|
||||||
lang = template._render_lang([self.env.context['default_res_id']])[self.env.context['default_res_id']]
|
lang = template._render_lang([self.env.context['default_res_id']])[self.env.context['default_res_id']]
|
||||||
|
if not lang:
|
||||||
|
lang = self.env.context.get('lang')
|
||||||
|
|
||||||
if not model_description and model:
|
# record, model
|
||||||
model_description = self.env['ir.model'].with_context(lang=lang)._get(model).display_name
|
if not model_description:
|
||||||
|
model = msg_vals.get('model') if 'model' in msg_vals else message.model
|
||||||
|
if model:
|
||||||
|
model_description = self.env['ir.model'].with_context(lang=lang)._get(model).display_name
|
||||||
|
record_name = msg_vals.get('record_name') if 'record_name' in msg_vals else message.record_name
|
||||||
|
|
||||||
|
# tracking
|
||||||
tracking = []
|
tracking = []
|
||||||
if msg_vals.get('tracking_value_ids', True) if msg_vals else bool(self): # could be tracking
|
if msg_vals.get('tracking_value_ids', True) if msg_vals else bool(self): # could be tracking
|
||||||
for tracking_value in self.env['mail.tracking.value'].sudo().search([('mail_message_id', '=', message.id)]):
|
for tracking_value in self.env['mail.tracking.value'].sudo().search([('mail_message_id', '=', message.id)]):
|
||||||
groups = tracking_value.field_groups
|
groups = tracking_value.field_groups
|
||||||
if not groups or self.env.is_superuser() or self.user_has_groups(groups):
|
if not groups or self.env.is_superuser() or self.user_has_groups(groups):
|
||||||
tracking.append((tracking_value.field_desc,
|
tracking.append((tracking_value.field_desc,
|
||||||
tracking_value.get_old_display_value()[0],
|
tracking_value.get_old_display_value()[0],
|
||||||
tracking_value.get_new_display_value()[0]))
|
tracking_value.get_new_display_value()[0]))
|
||||||
|
|
||||||
|
subtype_id = msg_vals.get('subtype_id') if msg_vals and 'subtype_id' in msg_vals else message.subtype_id.id
|
||||||
is_discussion = subtype_id == self.env['ir.model.data']._xmlid_to_res_id('mail.mt_comment')
|
is_discussion = subtype_id == self.env['ir.model.data']._xmlid_to_res_id('mail.mt_comment')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
# message
|
||||||
|
'is_discussion': is_discussion,
|
||||||
'message': message,
|
'message': message,
|
||||||
'signature': signature,
|
'subtype': message.subtype_id,
|
||||||
'website_url': website_url,
|
'tracking_values': tracking,
|
||||||
'company': company,
|
# record
|
||||||
'model_description': model_description,
|
'model_description': model_description,
|
||||||
'record': self,
|
'record': self,
|
||||||
'record_name': record_name,
|
'record_name': record_name,
|
||||||
'tracking_values': tracking,
|
# user / environment
|
||||||
'is_discussion': is_discussion,
|
'add_sign': add_sign,
|
||||||
'subtype': message.subtype_id,
|
'company': company,
|
||||||
'lang': lang,
|
'lang': lang,
|
||||||
|
'signature': signature,
|
||||||
|
'website_url': website_url,
|
||||||
|
# tools
|
||||||
|
'is_html_empty': is_html_empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _notify_by_email_get_base_mail_values(self, message, additional_values=None):
|
def _notify_by_email_get_base_mail_values(self, message, additional_values=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user