diff --git a/CHANGELOG b/CHANGELOG
index 9738c31895..1db436a09e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/exceptions.py b/exceptions.py
new file mode 100644
index 0000000000..4296c57e58
--- /dev/null
+++ b/exceptions.py
@@ -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
diff --git a/message.xml b/message.xml
new file mode 100644
index 0000000000..ffa300a047
--- /dev/null
+++ b/message.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Invalid e-mail subject in notification "%(notification)s" with exception "%(exception)s".
+
+
+
diff --git a/notification.py b/notification.py
index 58958ec645..617aeb78c9 100644
--- a/notification.py
+++ b/notification.py
@@ -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"
diff --git a/setup.py b/setup.py
index 711e36e468..0f0c699b95 100755
--- a/setup.py
+++ b/setup.py
@@ -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))
diff --git a/tests/test_notification_email.py b/tests/test_notification_email.py
index 903ea2fef7..9c116ab2ff 100644
--- a/tests/test_notification_email.py
+++ b/tests/test_notification_email.py
@@ -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 '], [], [], [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 '], [], [], [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()
diff --git a/tryton.cfg b/tryton.cfg
index 86c41f3fd8..3852fde0f0 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -11,3 +11,4 @@ extras_depend:
xml:
notification.xml
ir.xml
+ message.xml
diff --git a/view/email_form.xml b/view/email_form.xml
index 565c122fee..4790df4380 100644
--- a/view/email_form.xml
+++ b/view/email_form.xml
@@ -6,6 +6,8 @@ this repository contains the full copyright notices and license terms. -->
+
+