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. -->