[MERGE][IMP] mail, account, purchase, sale: improves activity notification
Ease the understanding of the notifications sent when users are assigned to an activity. Improves mail layout re-usability by replacing the 2 existing layouts: - message_notification_email --> mail_notification_layout: a little more generic (introduce a list of subtitles instead of a unique one) and defined as the default layout. Note the rework version done to support outlook client in odoo/odoo#92847 has been integrated - mail_notification_paynow --> mail_notification_responsible_signature_layout: inherited from mail_notification_layout with just the signature changed. Technical note: the customization of data sent to the email layout template (here subtitles) should be done by overriding mail_thread._notify_by_email_prepare_rendering_context on the model. But in this case, we send an activity (ex.: todo) for a model (ex.: crm.lead) which involves 2 models. Data from both models must be sent to the template layout. To solve this problem an optional parameters to mail_thread.message_notify has been added: subtitles. This allows the caller which knows about the 2 models to set the values for subtitles for the template. Task-2801600 closes odoo/odoo#88466 Related: odoo/enterprise#31281 Related: odoo/upgrade#3620 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -3063,7 +3063,7 @@ class AccountMove(models.Model):
|
||||
'res_model': 'account.invoice.send',
|
||||
'view_mode': 'form',
|
||||
'context': {
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_paynow',
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_layout_with_responsible_signature',
|
||||
'default_template_id': self.env.ref(self._get_mail_template()).id,
|
||||
'mark_invoice_as_sent': True,
|
||||
'active_model': 'account.move',
|
||||
@@ -3099,7 +3099,7 @@ class AccountMove(models.Model):
|
||||
default_template_id=template and template.id or False,
|
||||
default_composition_mode='comment',
|
||||
mark_invoice_as_sent=True,
|
||||
default_email_layout_xmlid="mail.mail_notification_paynow",
|
||||
default_email_layout_xmlid="mail.mail_notification_layout_with_responsible_signature",
|
||||
model_description=self.with_context(lang=lang).type_name,
|
||||
force_email=True,
|
||||
)
|
||||
@@ -3584,13 +3584,15 @@ class AccountMove(models.Model):
|
||||
message, msg_vals, model_description=model_description,
|
||||
force_email_company=force_email_company, force_email_lang=force_email_lang
|
||||
)
|
||||
subtitles = [render_context['record'].name]
|
||||
if self.invoice_date_due:
|
||||
render_context['subtitle'] = _('%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
subtitles.append(_('%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
amount=format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')),
|
||||
date=format_date(self.env, self.invoice_date_due, date_format='short', lang_code=render_context.get('lang'))
|
||||
)
|
||||
))
|
||||
else:
|
||||
render_context['subtitle'] = format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang'))
|
||||
subtitles.append(format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')))
|
||||
render_context['subtitles'] = subtitles
|
||||
return render_context
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -16,6 +16,7 @@ from odoo.exceptions import UserError, AccessError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools import date_utils, email_re, email_split, is_html_empty, groupby
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
from . import crm_stage
|
||||
|
||||
@@ -1792,6 +1793,17 @@ class Lead(models.Model):
|
||||
return self.env.ref('crm.mt_lead_lost')
|
||||
return super(Lead, self)._track_subtype(init_values)
|
||||
|
||||
def _notify_by_email_prepare_rendering_context(self, message, msg_vals=False, model_description=False,
|
||||
force_email_company=False, force_email_lang=False):
|
||||
render_context = super()._notify_by_email_prepare_rendering_context(
|
||||
message, msg_vals, model_description=model_description,
|
||||
force_email_company=force_email_company, force_email_lang=force_email_lang
|
||||
)
|
||||
if self.date_deadline:
|
||||
render_context['subtitles'].append(
|
||||
_('Deadline: %s', self.date_deadline.strftime(get_lang(self.env).date_format)))
|
||||
return render_context
|
||||
|
||||
def _notify_get_recipients_groups(self, msg_vals=None):
|
||||
""" Handle salesman recipients that can convert leads into opportunities
|
||||
and set opportunities as won / lost. """
|
||||
|
||||
@@ -3,15 +3,10 @@
|
||||
<data>
|
||||
<!-- Discuss utility templates for notifications -->
|
||||
<template id="message_user_assigned">
|
||||
<p style="margin: 0px;">
|
||||
<span>Dear <t t-esc="object.user_id.sudo().name"/>,</span><br />
|
||||
<span>Dear <t t-esc="object.user_id.sudo().name"/>,</span>
|
||||
<br/><br/>
|
||||
<span style="margin-top: 8px;">You have been assigned to the <t t-esc="model_description or 'document'"/> <t t-esc="object.display_name"/>.</span>
|
||||
</p>
|
||||
<p style="padding-top: 24px; padding-bottom: 16px;">
|
||||
<a t-att-href="access_link" t-att-data-oe-model="object._name" t-att-data-oe-id="object.id" style="background-color:#875A7B; padding: 10px; text-decoration: none; color: #fff; border-radius: 5px;">
|
||||
View <t t-esc="model_description or 'document'"/>
|
||||
</a>
|
||||
</p>
|
||||
<br/>
|
||||
</template>
|
||||
|
||||
<template id="message_activity_done">
|
||||
@@ -36,17 +31,18 @@
|
||||
|
||||
<template id="message_activity_assigned">
|
||||
<div style="margin: 0px; padding: 0px; font-size: 13px;">
|
||||
<span t-field="activity.create_uid.name"/> assigned you an activity <span t-field="activity.activity_type_id.name"/>
|
||||
<t t-if="activity.summary">(<span t-field="activity.summary"/>)</t>
|
||||
on <span t-field="activity.res_name"/>
|
||||
to close for <span t-field="activity.date_deadline"/>.<br />
|
||||
<p style="padding: 16px 0px 16px 0px;">
|
||||
<a t-att-href="access_link" t-att-data-oe-model="activity.res_model" t-att-data-oe-id="activity.res_id"
|
||||
style="background-color:#875A7B; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px;">
|
||||
View <t t-esc="model_description or 'document'"/>
|
||||
</a>
|
||||
Dear <span t-field="activity.user_id.name"/>,
|
||||
<br/><br/>
|
||||
<p>
|
||||
<span t-field="activity.create_uid.name"/> has just assigned you the following activity:
|
||||
<ul>
|
||||
<li>Document: "<t t-esc="activity.res_name"/>"
|
||||
<t t-if="model_description"> (<t t-esc="model_description"/>)</t>
|
||||
</li>
|
||||
<li t-if="activity.summary">Summary: <span t-field="activity.summary"/></li>
|
||||
<li>Deadline: <span t-field="activity.date_deadline"/></li>
|
||||
</ul>
|
||||
</p>
|
||||
<div t-if="activity.note" style="margin-top: 8px;" t-field="activity.note"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="message_notification_email">
|
||||
<template id="mail_notification_layout" name="Mail: mail notification layout template">
|
||||
<html t-att-lang="lang">
|
||||
<header>
|
||||
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
|
||||
</header>
|
||||
<body>
|
||||
<t t-set="subtype_internal" t-value="subtype.internal"/>
|
||||
<body style="font-family:Verdana, Arial,sans-serif; color: #454748;">
|
||||
<t t-set="subtype_internal" t-value="subtype and subtype.internal"/>
|
||||
<!-- HEADER -->
|
||||
<t t-call="mail.notification_preview"/>
|
||||
<div style="max-width: 900px; width: 100%;">
|
||||
<div t-if="has_button_access" itemscope="itemscope" itemtype="http://schema.org/EmailMessage">
|
||||
@@ -17,7 +18,7 @@
|
||||
<meta itemprop="name" t-att-content="button_access['title']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="has_button_access or len(actions) > 0 or not is_discussion"
|
||||
<div t-if="subtitles or has_button_access or len(actions) > 0 or not is_discussion"
|
||||
summary="o_mail_notification" style="padding: 0px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="width: 100%; margin-top: 5px;">
|
||||
<tbody>
|
||||
@@ -36,27 +37,31 @@
|
||||
<table cellspacing="0" cellpadding="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td t-if="has_button_access" style="border-radius: 3px; background: #875A7B; text-align: center; padding: 8px 12px;">
|
||||
<td t-if="has_button_access" style="border-radius: 3px; background: #875A7B; text-align: center; padding: 8px 12px 11px;">
|
||||
<a t-att-href="button_access['url']" style="font-size: 12px; color: #FFFFFF; text-decoration: none !important; font-weight: 400;">
|
||||
<t t-out="button_access['title']"/>
|
||||
</a>
|
||||
</td>
|
||||
<td t-if="has_button_access">&nbsp;&nbsp;</td>
|
||||
|
||||
<td t-if="subtitles" style="font-size: 12px;">
|
||||
<t t-foreach="subtitles" t-as="subtitle">
|
||||
<span t-attf-style="{{ 'font-weight:bold;' if subtitle_first else '' }}"
|
||||
t-out="subtitle"/>
|
||||
<br t-if="not subtitle_last"/>
|
||||
</t>
|
||||
</td>
|
||||
<td t-else=""><span style="font-weight:bold;" t-out="record_name"/><br/></td>
|
||||
<td>&nbsp;&nbsp;</td>
|
||||
|
||||
<td t-if="actions">
|
||||
<t t-foreach="actions" t-as="action">
|
||||
|
|
||||
<a t-att-href="action['url']" style="color: #875A7B; text-decoration:none !important;">
|
||||
<a t-att-href="action['url']" style="font-size: 12px; color: #875A7B; text-decoration:none !important;">
|
||||
<t t-out="action['title']"/>
|
||||
</a>
|
||||
</t>
|
||||
</td>
|
||||
<td t-if="actions">&nbsp;&nbsp;</td>
|
||||
|
||||
<td style="font-size: 12px;">
|
||||
<span style="font-weight:bold;" t-out="record_name"/><br/>
|
||||
<span t-if="not is_html_empty(subtitle)" t-out="subtitle"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -66,7 +71,7 @@
|
||||
<td valign="center">
|
||||
<hr width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0;margin: 10px 0px;"/>
|
||||
<p t-if="subtype_internal" style="background-color: #f2dede; padding: 5px; margin-bottom: 16px;">
|
||||
<p t-if="subtype_internal" style="background-color: #f2dede; padding: 5px; margin-bottom: 16px; font-size: 13px;">
|
||||
<strong>Internal communication</strong>: Replying will post an internal note. Followers won't receive any email notification.
|
||||
</p>
|
||||
</td>
|
||||
@@ -74,24 +79,30 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div t-out="message.body"/>
|
||||
<!-- CONTENT -->
|
||||
<div t-out="message.body" style="font-size: 13px;"/>
|
||||
<ul t-if="tracking_values">
|
||||
<t t-foreach="tracking_values" t-as="tracking">
|
||||
<li><t t-out="tracking[0]"/>: <t t-out="tracking[1]"/> → <t t-out="tracking[2]"/></li>
|
||||
</t>
|
||||
</ul>
|
||||
<div t-if="email_add_signature and not is_html_empty(signature)" t-out="signature" style="font-size: 13px;"/>
|
||||
<p style="color: #555555; margin-top:32px;">
|
||||
Sent
|
||||
<span t-if="company.name">
|
||||
by
|
||||
<a t-if="website_url" t-att-href="website_url" style="text-decoration:none; color: #875A7B;">
|
||||
<span t-out="company.name"/>
|
||||
</a>
|
||||
<span t-if="not website_url" t-out="company.name"/>
|
||||
</span>
|
||||
using
|
||||
<a target="_blank" href="https://www.odoo.com?utm_source=db&utm_medium=email" style="text-decoration:none; color: #875A7B;">Odoo</a>.
|
||||
<t class="o_signature">
|
||||
<div t-if="email_add_signature and not is_html_empty(signature)" t-out="signature" style="font-size: 13px;"/>
|
||||
</t>
|
||||
<!-- FOOTER -->
|
||||
<div style="margin-top:32px;">
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 4px 0px;"/>
|
||||
<b t-out="company.name" style="font-size:11px;"/><br/>
|
||||
<p style="color: #999999; margin-top:2px; font-size:11px;">
|
||||
<t t-out="company.phone"/>
|
||||
<t t-if="company.email and company.phone"> |</t>
|
||||
<a t-if="company.email" t-att-href="'mailto:%s' % company.email" style="text-decoration:none; color: #999999;" t-out="company.email"/>
|
||||
<t t-if="company.website and (company.phone or company.email)"> |</t>
|
||||
<a t-if="company.website" t-att-href="'%s' % company.website" style="text-decoration:none; color: #999999;" t-out="company.website"/>
|
||||
</p>
|
||||
</div>
|
||||
<p style="color: #555555; font-size:11px;">
|
||||
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&utm_medium=email" style="color: #875A7B;">Odoo</a>
|
||||
</p>
|
||||
</div>
|
||||
</body></html>
|
||||
@@ -168,112 +179,6 @@
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<!-- Used mainly in conjunction of portal models (SO, PO, Invoices) although not mandatory -->
|
||||
<template id="mail_notification_paynow" name="Mail: Pay Now mail notification template">
|
||||
<html t-att-lang="lang">
|
||||
<header>
|
||||
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
|
||||
</header>
|
||||
<body>
|
||||
<t t-set="subtype_internal" t-value="False"/>
|
||||
<t t-call="mail.notification_preview"/>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="background-color: #FFFFFF; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"><tr><td>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="max-width:900px; width:100%; background-color: #FFFFFF; color: #454748; border-collapse:separate;">
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="5" width="100%" style="background-color: #FFFFFF; padding: 0; border-collapse:separate;">
|
||||
<tr><td>
|
||||
<img t-att-src="'/logo.png?company=%s' % (company.id or 0)" height="48" style="padding: 0; margin: 0" t-att-alt="'%s' % company.name"/>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin:5px 0;"/>
|
||||
</td></tr>
|
||||
<tr><td valign="middle" style="white-space:nowrap;"><table cellspacing="0" cellpadding="0"><tr>
|
||||
<t t-if="has_button_access"><td>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
||||
<tr><td style="border-radius: 3px; background: #875A7B; text-align: center; padding: 8px 12px;">
|
||||
<a t-att-href="button_access['url']"
|
||||
style="border: 0; font-size: 12px; text-decoration: none !important; text-decoration: none; font-weight: 400; text-align: center; display: block;">
|
||||
<span style="white-space:nowrap; color:#FFFFFF;" t-out="button_access['title']"></span>
|
||||
</a>
|
||||
</td></tr>
|
||||
</table></td><td width="7"></td><!--only inner cellspacing-->
|
||||
</t>
|
||||
<t t-if="not has_button_access and is_html_empty(subtitle)">
|
||||
<td>
|
||||
<span style="font-size: 10px;">Your <t t-out="model_description or 'document'"/></span>
|
||||
<br />
|
||||
<span style="font-size: 20px; font-weight: bold;">
|
||||
<t t-out="message.record_name and message.record_name.replace('/','-') or ''"/>
|
||||
</span>
|
||||
</td><td width="7"></td>
|
||||
</t>
|
||||
<t t-if="actions">
|
||||
<td>
|
||||
<t t-foreach="actions" t-as="action">
|
||||
|
|
||||
<a t-att-href="action['url']" style="color: #875A7B; text-decoration:none !important; text-decoration: none;">
|
||||
<t t-out="action['title']"/>
|
||||
</a>
|
||||
</t>
|
||||
</td><td width="7"></td>
|
||||
</t>
|
||||
<t t-if="not is_html_empty(subtitle)">
|
||||
<td style="font-size: 12px;">
|
||||
<span style="font-weight:bold;" t-out="record.name"/><br/>
|
||||
<span t-out="subtitle"/>
|
||||
</td>
|
||||
</t>
|
||||
</tr></table></td></tr>
|
||||
<tr><td>
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 5px 0px;"/>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- CONTENT -->
|
||||
<tr>
|
||||
<td style="padding-left: 5px;">
|
||||
<t t-out="message.body"/>
|
||||
<t t-if="email_add_signature and 'user_id' in record and record.user_id and not record.env.user._is_superuser() and not is_html_empty(record.user_id.sudo().signature)">
|
||||
<div style="margin: 0px; padding: 0px; font-size:13px;">
|
||||
Best regards,
|
||||
</div>
|
||||
<div>&nbsp;</div>
|
||||
<div style="font-size: 13px;">
|
||||
<div t-out="record.user_id.sudo().signature"/>
|
||||
</div>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- FOOTER -->
|
||||
<tr>
|
||||
<td style="padding-left: 5px; font-size:11px;">
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 4px 0px;"/>
|
||||
<b t-out="company.name"/><br/>
|
||||
<div style="color: #999999; padding-top:2px">
|
||||
<t t-out="company.phone"/>
|
||||
<t t-if="company.email and company.phone"> |</t>
|
||||
<a t-if="company.email" t-att-href="'mailto:%s' % company.email" style="text-decoration:none; color: #999999;" t-out="company.email"/>
|
||||
<t t-if="company.website and (company.phone or company.email)"> |</t>
|
||||
<a t-if="company.website" t-att-href="'%s' % company.website" style="text-decoration:none; color: #999999;" t-out="company.website"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- POWERED BY -->
|
||||
<tr><td style="padding: 2px 0 0 5px; font-size:11px;">
|
||||
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&utm_medium=email" style="color: #875A7B;">Odoo</a>
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<template id="notification_preview">
|
||||
<div style="display: none; max-height: 0px; overflow: hidden;">
|
||||
<t t-if="tracking_values">
|
||||
@@ -286,5 +191,16 @@
|
||||
<t t-out="'͏ ​ ' * 140"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="mail_notification_layout_with_responsible_signature"
|
||||
name="Mail: mail notification layout with responsible signature (user_id of the record)"
|
||||
inherit_id="mail.mail_notification_layout" primary="True">
|
||||
<xpath expr="//t[hasclass('o_signature')]" position="replace">
|
||||
<t class="o_signature">
|
||||
<div t-if="email_add_signature and 'user_id' in record and record.user_id and not record.env.user._is_superuser() and not is_html_empty(record.user_id.sudo().signature)"
|
||||
t-out="record.user_id.sudo().signature" style="font-size: 13px;"/>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -9,7 +9,8 @@ from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import api, exceptions, fields, models, _, Command
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.misc import clean_context
|
||||
from odoo.tools import is_html_empty
|
||||
from odoo.tools.misc import clean_context, get_lang
|
||||
|
||||
|
||||
class MailActivity(models.Model):
|
||||
@@ -480,11 +481,11 @@ class MailActivity(models.Model):
|
||||
model_description = activity.env['ir.model']._get(activity.res_model).display_name
|
||||
body = activity.env['ir.qweb']._render(
|
||||
'mail.message_activity_assigned',
|
||||
dict(
|
||||
activity=activity,
|
||||
model_description=model_description,
|
||||
access_link=activity.env['mail.thread']._notify_get_action_link('view', model=activity.res_model, res_id=activity.res_id),
|
||||
),
|
||||
{
|
||||
'activity': activity,
|
||||
'model_description': model_description,
|
||||
'is_html_empty': is_html_empty,
|
||||
},
|
||||
minimal_qcontext=True
|
||||
)
|
||||
record = activity.env[activity.res_model].browse(activity.res_id)
|
||||
@@ -492,12 +493,14 @@ class MailActivity(models.Model):
|
||||
record.message_notify(
|
||||
partner_ids=activity.user_id.partner_id.ids,
|
||||
body=body,
|
||||
subject=_('%(activity_name)s: %(summary)s assigned to you',
|
||||
activity_name=activity.res_name,
|
||||
summary=activity.summary or activity.activity_type_id.name),
|
||||
record_name=activity.res_name,
|
||||
model_description=model_description,
|
||||
email_layout_xmlid='mail.mail_notification_light',
|
||||
email_layout_xmlid='mail.mail_notification_layout',
|
||||
subject=_('"%(activity_name)s: %(summary)s" assigned to you',
|
||||
activity_name=activity.res_name,
|
||||
summary=activity.summary or activity.activity_type_id.name),
|
||||
subtitles=[_('Activity: %s', activity.activity_type_id.name),
|
||||
_('Deadline: %s', activity.date_deadline.strftime(get_lang(activity.env).date_format))]
|
||||
)
|
||||
|
||||
def action_done(self):
|
||||
|
||||
@@ -319,7 +319,7 @@ class MailTemplate(models.Model):
|
||||
'model_description': model.display_name,
|
||||
'record': record,
|
||||
'record_name': False,
|
||||
'subtitle': False,
|
||||
'subtitles': False,
|
||||
# user / environment
|
||||
'company': 'company_id' in record and record['company_id'] or self.env.company,
|
||||
'email_add_signature': False,
|
||||
|
||||
@@ -2411,7 +2411,7 @@ class MailThread(models.AbstractModel):
|
||||
mail_auto_delete=True, # mail.mail
|
||||
model_description=False, force_email_company=False, force_email_lang=False, # rendering
|
||||
resend_existing=False, force_send=True, send_after_commit=True, # email send
|
||||
**kwargs):
|
||||
subtitles=None, **kwargs):
|
||||
""" Method to send email linked to notified messages.
|
||||
|
||||
:param message: ``mail.message`` record to notify;
|
||||
@@ -2442,6 +2442,7 @@ class MailThread(models.AbstractModel):
|
||||
:param force_send: send emails directly instead of using queue;
|
||||
:param send_after_commit: if force_send, tells whether to send emails after
|
||||
the transaction has been committed using a post-commit hook;
|
||||
:param subtitles: optional list that will be set as template value "subtitles"
|
||||
"""
|
||||
partners_data = [r for r in recipients_data if r['notif'] == 'email']
|
||||
if not partners_data:
|
||||
@@ -2460,9 +2461,11 @@ class MailThread(models.AbstractModel):
|
||||
force_email_company=force_email_company,
|
||||
force_email_lang=force_email_lang,
|
||||
) # 10 queries
|
||||
if subtitles:
|
||||
template_values['subtitles'] = subtitles
|
||||
|
||||
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.mail_notification_layout'
|
||||
base_mail_values = self._notify_by_email_get_base_mail_values(message, additional_values={'auto_delete': mail_auto_delete})
|
||||
|
||||
# Clean the context to get rid of residual default_* keys that could cause issues during
|
||||
@@ -2649,7 +2652,7 @@ class MailThread(models.AbstractModel):
|
||||
'model_description': model_description,
|
||||
'record': self,
|
||||
'record_name': record_name,
|
||||
'subtitle': False,
|
||||
'subtitles': [record_name],
|
||||
# user / environment
|
||||
'company': company,
|
||||
'email_add_signature': email_add_signature,
|
||||
@@ -3070,7 +3073,7 @@ class MailThread(models.AbstractModel):
|
||||
body=assignation_msg,
|
||||
partner_ids=partner_ids,
|
||||
record_name=record.display_name,
|
||||
email_layout_xmlid='mail.mail_notification_light',
|
||||
email_layout_xmlid='mail.mail_notification_layout',
|
||||
model_description=model_description,
|
||||
)
|
||||
|
||||
|
||||
@@ -100,15 +100,10 @@
|
||||
|
||||
<!-- You have been assigned email -->
|
||||
<template id="project_message_user_assigned">
|
||||
<p style="margin: 0px;">
|
||||
<span>Dear <t t-esc="assignee_name"/>,</span><br />
|
||||
<span>Dear <t t-esc="assignee_name"/>,</span>
|
||||
<br/><br/>
|
||||
<span style="margin-top: 8px;">You have been assigned to the <t t-esc="model_description or 'document'"/> <t t-esc="object.display_name"/>.</span>
|
||||
</p>
|
||||
<p style="padding-top: 24px; padding-bottom: 16px;">
|
||||
<a t-att-href="access_link" t-att-data-oe-model="object._name" t-att-data-oe-id="object.id" style="background-color:#875A7B; padding: 10px; text-decoration: none; color: #fff; border-radius: 5px;">
|
||||
View <t t-esc="model_description or 'document'"/>
|
||||
</a>
|
||||
</p>
|
||||
<br/>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -2045,8 +2045,6 @@ class Task(models.Model):
|
||||
|
||||
result = super(Task, tasks).write(vals)
|
||||
|
||||
self._task_message_auto_subscribe_notify({task: task.user_ids - old_user_ids[task] - self.env.user for task in self})
|
||||
|
||||
if 'user_ids' in vals:
|
||||
tasks._populate_missing_personal_stages()
|
||||
|
||||
@@ -2065,6 +2063,8 @@ class Task(models.Model):
|
||||
if task.display_project_id != task.project_id and not task.parent_id:
|
||||
# We must make the display_project_id follow the project_id if no parent_id set
|
||||
task.display_project_id = task.project_id
|
||||
|
||||
self._task_message_auto_subscribe_notify({task: task.user_ids - old_user_ids[task] - self.env.user for task in self})
|
||||
return result
|
||||
|
||||
def update_date_end(self, stage_id):
|
||||
@@ -2141,6 +2141,20 @@ class Task(models.Model):
|
||||
# Mail gateway
|
||||
# ---------------------------------------------------
|
||||
|
||||
def _notify_by_email_prepare_rendering_context(self, message, msg_vals=False, model_description=False,
|
||||
force_email_company=False, force_email_lang=False):
|
||||
render_context = super()._notify_by_email_prepare_rendering_context(
|
||||
message, msg_vals, model_description=model_description,
|
||||
force_email_company=force_email_company, force_email_lang=force_email_lang
|
||||
)
|
||||
if self.date_deadline:
|
||||
render_context['subtitles'].append(
|
||||
_('Deadline: %s', self.date_deadline.strftime(get_lang(self.env).date_format)))
|
||||
elif self.date_assign:
|
||||
render_context['subtitles'].append(
|
||||
_('Assigned On: %s', self.date_assign.strftime(get_lang(self.env).date_format)))
|
||||
return render_context
|
||||
|
||||
@api.model
|
||||
def _task_message_auto_subscribe_notify(self, users_per_task):
|
||||
# Utility method to send assignation notification upon writing/creation.
|
||||
@@ -2165,7 +2179,7 @@ class Task(models.Model):
|
||||
body=assignation_msg,
|
||||
partner_ids=user.partner_id.ids,
|
||||
record_name=task.display_name,
|
||||
email_layout_xmlid='mail.mail_notification_light',
|
||||
email_layout_xmlid='mail.mail_notification_layout',
|
||||
model_description=task_model_description,
|
||||
)
|
||||
|
||||
|
||||
@@ -366,15 +366,17 @@ class PurchaseOrder(models.Model):
|
||||
message, msg_vals, model_description=model_description,
|
||||
force_email_company=force_email_company, force_email_lang=force_email_lang
|
||||
)
|
||||
subtitles = [render_context['record'].name]
|
||||
# don't show price on RFQ mail
|
||||
if self.state not in ['draft', 'sent']:
|
||||
if self.date_order:
|
||||
render_context['subtitle'] = _('%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
amount=format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')),
|
||||
date=format_date(self.env, self.date_order, date_format='short', lang_code=render_context.get('lang'))
|
||||
)
|
||||
subtitles.append(_('%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
amount=format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')),
|
||||
date=format_date(self.env, self.date_order, date_format='short', lang_code=render_context.get('lang'))
|
||||
))
|
||||
else:
|
||||
render_context['subtitle'] = format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang'))
|
||||
subtitles.append(format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')))
|
||||
render_context['subtitles'] = subtitles
|
||||
return render_context
|
||||
|
||||
def _track_subtype(self, init_values):
|
||||
@@ -421,7 +423,7 @@ class PurchaseOrder(models.Model):
|
||||
'default_use_template': bool(template_id),
|
||||
'default_template_id': template_id,
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_layout_xmlid': "mail.mail_notification_paynow",
|
||||
'default_email_layout_xmlid': "mail.mail_notification_layout_with_responsible_signature",
|
||||
'force_email': True,
|
||||
'mark_rfq_as_sent': True,
|
||||
})
|
||||
@@ -745,7 +747,7 @@ class PurchaseOrder(models.Model):
|
||||
if send_single:
|
||||
return order._send_reminder_open_composer(template.id)
|
||||
else:
|
||||
order.with_context(is_reminder=True).message_post_with_template(template.id, email_layout_xmlid="mail.mail_notification_paynow", composition_mode='comment')
|
||||
order.with_context(is_reminder=True).message_post_with_template(template.id, email_layout_xmlid="mail.mail_notification_layout_with_responsible_signature", composition_mode='comment')
|
||||
|
||||
def send_reminder_preview(self):
|
||||
self.ensure_one()
|
||||
@@ -758,7 +760,7 @@ class PurchaseOrder(models.Model):
|
||||
self.id,
|
||||
force_send=True,
|
||||
raise_exception=False,
|
||||
email_layout_xmlid="mail.mail_notification_paynow",
|
||||
email_layout_xmlid="mail.mail_notification_layout_with_responsible_signature",
|
||||
email_values={'email_to': self.env.user.email, 'recipient_ids': []},
|
||||
)
|
||||
return {'toast_message': escape(_("A sample email has been sent to %s.", self.env.user.email))}
|
||||
@@ -778,7 +780,7 @@ class PurchaseOrder(models.Model):
|
||||
'default_use_template': bool(template_id),
|
||||
'default_template_id': template_id,
|
||||
'default_composition_mode': 'comment',
|
||||
'default_email_layout_xmlid': "mail.mail_notification_paynow",
|
||||
'default_email_layout_xmlid': "mail.mail_notification_layout_with_responsible_signature",
|
||||
'force_email': True,
|
||||
'mark_rfq_as_sent': True,
|
||||
})
|
||||
|
||||
@@ -132,7 +132,7 @@ class PaymentTransaction(models.Model):
|
||||
for invoice in invoice_to_send.with_user(SUPERUSER_ID):
|
||||
invoice.message_post_with_template(
|
||||
int(template_id),
|
||||
email_layout_xmlid='mail.mail_notification_paynow',
|
||||
email_layout_xmlid='mail.mail_notification_layout_with_responsible_signature',
|
||||
)
|
||||
|
||||
def _cron_send_invoice(self):
|
||||
|
||||
@@ -94,7 +94,7 @@ class ResCompany(models.Model):
|
||||
message_composer = self.env['mail.compose.message'].with_context(
|
||||
default_use_template=bool(template),
|
||||
mark_so_as_sent=True,
|
||||
default_email_layout_xmlid='mail.mail_notification_paynow',
|
||||
default_email_layout_xmlid='mail.mail_notification_layout_with_responsible_signature',
|
||||
proforma=self.env.context.get('proforma', False),
|
||||
force_email=True, mail_notify_author=True
|
||||
).create({
|
||||
|
||||
@@ -728,7 +728,7 @@ class SaleOrder(models.Model):
|
||||
'default_template_id': mail_template.id if mail_template else None,
|
||||
'default_composition_mode': 'comment',
|
||||
'mark_so_as_sent': True,
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_paynow',
|
||||
'default_email_layout_xmlid': "mail.mail_notification_layout_with_responsible_signature",
|
||||
'proforma': self.env.context.get('proforma', False),
|
||||
'force_email': True,
|
||||
'model_description': self.with_context(lang=lang).type_name,
|
||||
@@ -837,7 +837,7 @@ class SaleOrder(models.Model):
|
||||
self.with_context(force_send=True).message_post_with_template(
|
||||
mail_template.id,
|
||||
composition_mode='comment',
|
||||
email_layout_xmlid='mail.mail_notification_paynow',
|
||||
email_layout_xmlid='mail.mail_notification_layout_with_responsible_signature',
|
||||
)
|
||||
|
||||
def action_done(self):
|
||||
@@ -873,7 +873,7 @@ class SaleOrder(models.Model):
|
||||
'default_template_id': template_id,
|
||||
'default_order_id': self.id,
|
||||
'mark_so_as_canceled': True,
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_paynow',
|
||||
'default_email_layout_xmlid': "mail.mail_notification_layout_with_responsible_signature",
|
||||
'model_description': self.with_context(lang=lang).type_name,
|
||||
}
|
||||
return {
|
||||
@@ -1231,15 +1231,15 @@ class SaleOrder(models.Model):
|
||||
message, msg_vals, model_description=model_description,
|
||||
force_email_company=force_email_company, force_email_lang=force_email_lang
|
||||
)
|
||||
subtitles = [render_context['record'].name]
|
||||
if self.validity_date:
|
||||
render_context['subtitle'] = _(
|
||||
u'%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
amount=format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')),
|
||||
date=format_date(self.env, self.validity_date, date_format='short', lang_code=render_context.get('lang'))
|
||||
)
|
||||
subtitles.append(_(u'%(amount)s due\N{NO-BREAK SPACE}%(date)s',
|
||||
amount=format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')),
|
||||
date=format_date(self.env, self.validity_date, date_format='short', lang_code=render_context.get('lang'))
|
||||
))
|
||||
else:
|
||||
render_context['subtitle'] = format_amount(
|
||||
self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang'))
|
||||
subtitles.append(format_amount(self.env, self.amount_total, self.currency_id, lang_code=render_context.get('lang')))
|
||||
render_context['subtitles'] = subtitles
|
||||
return render_context
|
||||
|
||||
def _sms_get_number_fields(self):
|
||||
|
||||
@@ -176,7 +176,7 @@ class TestActivityFlow(TestActivityCommon):
|
||||
rec = self.test_record.with_user(self.user_employee)
|
||||
with self.assertSinglePostNotifications(
|
||||
[{'partner': self.partner_admin, 'type': 'email'}],
|
||||
message_info={'content': 'assigned you an activity', 'subtype': 'mail.mt_note', 'message_type': 'user_notification'}):
|
||||
message_info={'content': 'assigned you the following activity', 'subtype': 'mail.mt_note', 'message_type': 'user_notification'}):
|
||||
activity = rec.activity_schedule(
|
||||
'test_mail.mail_act_test_todo',
|
||||
user_id=self.user_admin.id)
|
||||
|
||||
@@ -86,9 +86,9 @@ class TestMailNotifyAPI(TestMessagePostCommon):
|
||||
test_message = self.env['mail.message'].browse(self.test_message.ids)
|
||||
|
||||
recipients_data = self._generate_notify_recipients(self.partner_1 + self.partner_2 + self.partner_employee)
|
||||
for email_xmlid in ['mail.message_notification_email',
|
||||
'mail.mail_notification_light',
|
||||
'mail.mail_notification_paynow']:
|
||||
for email_xmlid in ['mail.mail_notification_light',
|
||||
'mail.mail_notification_layout',
|
||||
'mail.mail_notification_layout_with_responsible_signature']:
|
||||
test_message.sudo().notification_ids.unlink() # otherwise partner/message constraint fails
|
||||
test_message.write({'email_layout_xmlid': email_xmlid})
|
||||
with self.mock_mail_gateway():
|
||||
@@ -118,14 +118,14 @@ class TestMailNotifyAPI(TestMessagePostCommon):
|
||||
|
||||
signature = self.env.user.signature
|
||||
|
||||
template = self.env.ref('mail.mail_notification_paynow', raise_if_not_found=True).sudo()
|
||||
template = self.env.ref('mail.mail_notification_layout_with_responsible_signature', raise_if_not_found=True).sudo()
|
||||
self.assertIn("record.user_id.sudo().signature", template.arch)
|
||||
|
||||
with self.mock_mail_gateway():
|
||||
test_track.message_post(
|
||||
body="Test body",
|
||||
email_add_signature=True,
|
||||
email_layout_xmlid="mail.mail_notification_paynow",
|
||||
email_layout_xmlid="mail.mail_notification_layout_with_responsible_signature",
|
||||
mail_auto_delete=False,
|
||||
partner_ids=[self.partner_1.id, self.partner_2.id],
|
||||
)
|
||||
@@ -137,7 +137,7 @@ class TestMailNotifyAPI(TestMessagePostCommon):
|
||||
test_track.message_post(
|
||||
body="Test body",
|
||||
email_add_signature=False,
|
||||
email_layout_xmlid="mail.mail_notification_paynow",
|
||||
email_layout_xmlid="mail.mail_notification_layout_with_responsible_signature",
|
||||
mail_auto_delete=False,
|
||||
partner_ids=[self.partner_1.id, self.partner_2.id],
|
||||
)
|
||||
|
||||
@@ -522,7 +522,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
|
||||
def test_message_assignation_email(self):
|
||||
self.user_test.write({'notification_type': 'email'})
|
||||
record = self.env['mail.test.track'].create({'name': 'Test'})
|
||||
with self.assertQueryCount(__system__=27, employee=28):
|
||||
with self.assertQueryCount(__system__=28, employee=29):
|
||||
record.write({
|
||||
'user_id': self.user_test.id,
|
||||
})
|
||||
@@ -850,7 +850,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
|
||||
})
|
||||
rec1 = rec.with_context(active_test=False) # to see inactive records
|
||||
self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id)
|
||||
with self.assertQueryCount(__system__=24, employee=25):
|
||||
with self.assertQueryCount(__system__=25, employee=26):
|
||||
rec.write({'user_id': self.user_portal.id})
|
||||
self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id)
|
||||
# write tracking message
|
||||
@@ -870,7 +870,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
|
||||
customer_id = self.customer.id
|
||||
user_id = self.user_portal.id
|
||||
|
||||
with self.assertQueryCount(__system__=56, employee=57): # tm 56/57
|
||||
with self.assertQueryCount(__system__=57, employee=58): # tm 57/58
|
||||
rec = self.env['mail.test.ticket'].create({
|
||||
'name': 'Test',
|
||||
'container_id': container_id,
|
||||
|
||||
@@ -345,7 +345,7 @@ class SaleOrder(models.Model):
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_composition_mode': 'mass_mail' if len(self.ids) > 1 else 'comment',
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_paynow',
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_layout_with_responsible_signature',
|
||||
'default_res_id': self.ids[0],
|
||||
'default_model': 'sale.order',
|
||||
'default_use_template': bool(template_id),
|
||||
|
||||
Reference in New Issue
Block a user