Add optional subject to notifications

issue9321
review290011002
This commit is contained in:
Sergi Almacellas Abellana
2020-07-04 20:07:54 +02:00
parent 50078c76a3
commit fbde26b3c1
8 changed files with 120 additions and 2 deletions
+2
View File
@@ -1,3 +1,5 @@
* Add optional subject to notifications
Version 5.6.0 - 2020-05-04
* Bug fixes (see mercurial logs for details)
* Add commission agent as a recipient
+8
View File
@@ -0,0 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model.exceptions import ValidationError
class TemplateError(ValidationError):
pass
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data grouped="1">
<record model="ir.message" id="msg_notification_invalid_subject">
<field name="text">Invalid e-mail subject in notification "%(notification)s" with exception "%(exception)s".</field>
</record>
</data>
</tryton>
+34 -1
View File
@@ -8,13 +8,17 @@ from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
from email.utils import formataddr, getaddresses
from genshi.template import TextTemplate
from trytond.config import config
from trytond.i18n import gettext
from trytond.model import ModelView, ModelSQL, fields
from trytond.pool import Pool
from trytond.pyson import Eval
from trytond.report import get_email
from trytond.sendmail import sendmail_transactional, SMTPDataManager
from trytond.transaction import Transaction
from .exceptions import TemplateError
_EMAIL_MODELS = [
'res.user',
@@ -37,6 +41,11 @@ class Email(ModelSQL, ModelView):
from_ = fields.Char(
"From",
help="Leave empty for the value defined in the configuration file.")
subject = fields.Char(
"Subject", translate=True,
help="The Genshi syntax can be used "
"with 'record' in the evaluation context.\n"
"If empty the report name will be used.")
recipients = fields.Many2One(
'ir.model.field', "Recipients",
domain=[
@@ -240,11 +249,17 @@ class Email(ModelSQL, ModelView):
# TODO order languages to get default as last one for title
content, title = get_email(self.content, record, languages)
language = list(languages)[-1]
if self.subject:
with Transaction().set_context(language=language.code):
notification = self.__class__(self.id)
title = (TextTemplate(notification.subject)
.generate(record=record)
.render())
if self.attachments:
msg = MIMEMultipart('mixed')
msg.attach(content)
language = list(languages)[-1]
for report in self.attachments:
msg.attach(Attachment.get_mime(report, record, language.code))
else:
@@ -329,6 +344,24 @@ class Email(ModelSQL, ModelView):
if logs:
Log.create(logs)
@classmethod
def validate(cls, notifications):
super().validate(notifications)
for notification in notifications:
notification.check_subject()
def check_subject(self):
if not self.subject:
return
try:
TextTemplate(self.subject)
except Exception as exception:
raise TemplateError(
gettext('notification_email.'
'msg_notification_invalid_subject',
notification=self.rec_name,
exception=exception)) from exception
class EmailAttachment(ModelSQL):
"Email Notification Attachment"
+1 -1
View File
@@ -51,7 +51,7 @@ for build in ['CI_BUILD_NUMBER', 'CI_JOB_NUMBER', 'CI_JOB_ID']:
if local_version:
version += '+' + '.'.join(local_version)
requires = []
requires = ['Genshi']
for dep in info.get('depends', []):
if not re.match(r'(ir|res)(\W|$)', dep):
requires.append(get_require_version('trytond_%s' % dep))
+62
View File
@@ -168,6 +168,68 @@ class NotificationEmailTestCase(ModuleTestCase):
attachment.get_content_type(), 'text/plain')
self.assertEqual(attachment.get_filename(), "Attachment.txt")
@with_transaction()
def test_notification_email_subject(self):
"Test email notificiation with subject"
pool = Pool()
Model = pool.get('ir.model')
User = pool.get('res.user')
NotificationEmail = pool.get('notification.email')
Language = pool.get('ir.lang')
self._setup_notification()
model, = Model.search([
('model', '=', User.__name__),
])
en, = Language.search([('code', '=', 'en')])
notification_email, = NotificationEmail.search([])
notification_email.subject = 'Notification for ${record.name}'
notification_email.save()
user, = User.create([{'name': "Michael Scott", 'login': "msc"}])
msg = notification_email.get_email(
user, FROM, ['Administrator <user@example.com>'], [], [], [en])
self.assertEqual(msg['Subject'], 'Notification for Michael Scott')
@with_transaction()
def test_notification_email_translated_subject(self):
"Test email notificiation with translated subject"
pool = Pool()
Model = pool.get('ir.model')
User = pool.get('res.user')
NotificationEmail = pool.get('notification.email')
Language = pool.get('ir.lang')
self._setup_notification()
model, = Model.search([
('model', '=', User.__name__),
])
es, = Language.search([('code', '=', 'es')])
Language.load_translations([es])
notification_email, = NotificationEmail.search([])
notification_email.subject = 'Notification for ${record.name}'
notification_email.save()
with Transaction().set_context(lang='es'):
notification_email, = NotificationEmail.search([])
notification_email.subject = 'Notificación para ${record.name}'
notification_email.save()
user, = User.create([{
'name': "Michael Scott",
'login': "msc",
'language': es.id,
}])
msg = notification_email.get_email(
user, FROM, ['Administrator <user@example.com>'], [], [], [es])
self.assertEqual(msg['Subject'], 'Notificación para Michael Scott')
@unittest.skipIf(
(3, 5, 0) <= sys.version_info < (3, 5, 2), "python bug #25195")
@with_transaction()
+1
View File
@@ -11,3 +11,4 @@ extras_depend:
xml:
notification.xml
ir.xml
message.xml
+2
View File
@@ -6,6 +6,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="from_"/>
<label name="content"/>
<field name="content"/>
<label name="subject"/>
<field name="subject" colspan="3"/>
<label name="recipients"/>
<field name="recipients"/>
<label name="fallback_recipients"/>