From 2d7090df285b0ea1d7842e9e5b48b7e3d3af872f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Aug 2017 22:53:56 +0200 Subject: [PATCH] Add attachments to email issue6675 review40581002 --- __init__.py | 1 + doc/index.rst | 1 + notification.py | 66 +++++++++++++++++++++++++++++- tests/test_notification_email.py | 69 ++++++++++++++++++++++++++++++++ view/email_form.xml | 1 + 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index baf6727044..72a499c7ac 100644 --- a/__init__.py +++ b/__init__.py @@ -8,6 +8,7 @@ from . import ir def register(): Pool.register( notification.Email, + notification.EmailAttachment, notification.Log, ir.Trigger, module='notification_email', type_='model') diff --git a/doc/index.rst b/doc/index.rst index e6d213ee20..c79ba5d0c2 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -3,3 +3,4 @@ Notification Email Module The notification email module allows to define email templates which will be sent to a list of recipients when a trigger is fired on a record event. +Extra reports from the same record can be attached to the email. diff --git a/notification.py b/notification.py index 2caef0d579..29646520ff 100644 --- a/notification.py +++ b/notification.py @@ -1,6 +1,7 @@ # 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 email.header import Header +from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formataddr, getaddresses @@ -17,7 +18,7 @@ from trytond.pyson import Eval from trytond.sendmail import sendmail_transactional, SMTPDataManager from trytond.transaction import Transaction -__all__ = ['Email', 'Log'] +__all__ = ['Email', 'EmailAttachment', 'Log'] def _formataddr(name, email): @@ -85,6 +86,14 @@ class Email(ModelSQL, ModelView): 'ir.action.report', "Content", required=True, domain=[('template_extension', 'in', ['plain', 'html', 'xhtml'])], help="The report used as email template.") + attachments = fields.Many2Many( + 'notification.email.attachment', 'notification', 'report', + "Attachments", + domain=[ + ('model', '=', Eval('model')), + ], + depends=['model'], + help="The reports used as attachments.") triggers = fields.One2Many( 'ir.trigger', 'notification_email', "Triggers", @@ -170,8 +179,21 @@ class Email(ModelSQL, ModelView): return {self._get_language(value)} def get_email(self, record, from_, to, cc, bcc, languages): - msg, title = _get_email_template( + pool = Pool() + Attachment = pool.get('notification.email.attachment') + + content, title = _get_email_template( self.content.report_name, record, languages) + + 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)) + else: + msg = content + msg['From'] = from_ msg['To'] = ', '.join(to) msg['Cc'] = ', '.join(cc) @@ -238,6 +260,46 @@ class Email(ModelSQL, ModelView): Log.create(logs) +class EmailAttachment(ModelSQL): + "Email Notification Attachment" + __name__ = 'notification.email.attachment' + + notification = fields.Many2One( + 'notification.email', "Notification", + required=True, select=True) + report = fields.Many2One( + 'ir.action.report', "Report", required=True, + domain=[ + ('model', '=', Eval('model')), + ], + depends=['model']) + + model = fields.Function(fields.Char("Model"), 'get_model') + + def get_model(self, name): + return self.notification.model + + @classmethod + def get_mime(cls, report, record, language): + pool = Pool() + Report = pool.get(report.report_name, type='report') + with Transaction().set_context(language=language): + ext, content, _, title = Report.execute( + [record.id], { + 'action_id': report.id, + }) + name = '%s.%s' % (title, ext) + msg = MIMEApplication(content) + if not isinstance(name, str): + name = name.encode('utf-8') + if not isinstance(language, str): + language = language.encode('utf-8') + msg.add_header( + 'Content-Disposition', 'attachment', + filename=('utf-8', language, name)) + return msg + + class Log(ModelSQL, ModelView): "Notitification Log" __name__ = 'notification.log' diff --git a/tests/test_notification_email.py b/tests/test_notification_email.py index f4242d0102..02c53d92e1 100644 --- a/tests/test_notification_email.py +++ b/tests/test_notification_email.py @@ -105,6 +105,75 @@ class NotificationEmailTestCase(ModuleTestCase): self.assertEqual(log.recipients_secondary, '') self.assertEqual(log.recipients_hidden, '') + @with_transaction() + def test_notification_email_attachment(self): + "Test email notificiation with attachment" + pool = Pool() + Model = pool.get('ir.model') + ModelField = pool.get('ir.model.field') + Action = pool.get('ir.action') + Report = pool.get('ir.action.report') + User = pool.get('res.user') + NotificationEmail = pool.get('notification.email') + + model, = Model.search([ + ('model', '=', User.__name__), + ]) + action_model, = Model.search([ + ('model', '=', 'notification.email'), + ]) + + action = Action(name="Notification Email", type='ir.action.report') + action.save() + report = Report() + report.report_name = 'notification_notification.test.report' + report.action = action + report.template_extension = 'plain' + report.report_content = b'Hello ${records[0].name}' + report.model = model.model + report.save() + + attachment = Report() + attachment.name = "Attachment" + attachment.report_name = 'notification_notification.test.report' + attachment.template_extension = 'plain' + attachment.report_content = b'attachment for ${records[0].name}' + attachment.model = model.model + attachment.save() + + user = User(Transaction().user) + user.email = 'user@example.com' + user.save() + + notification_email = NotificationEmail() + notification_email.recipients, = ModelField.search([ + ('model.model', '=', model.model), + ('name', '=', 'create_uid'), + ]) + notification_email.content = report + notification_email.attachments = [attachment] + notification_email.save() + + user, = User.create([{'name': "Michael Scott", 'login': "msc"}]) + + msg = notification_email.get_email( + user, FROM, ['Administrator '], [], [], ['en']) + + self.assertEqual(msg['From'], FROM) + self.assertEqual(msg['Subject'], 'Notification Email') + self.assertEqual(msg['To'], 'Administrator ') + self.assertEqual(msg.get_content_type(), 'multipart/mixed') + self.assertEqual( + msg.get_payload(0).get_content_type(), 'multipart/alternative') + + attachment = msg.get_payload(1) + self.assertEqual( + attachment.get_payload(None, True), + 'attachment for Michael Scott') + self.assertEqual( + attachment.get_content_type(), 'application/octet-stream') + self.assertEqual(attachment.get_filename(), "Attachment.plain") + def suite(): suite = test_suite() diff --git a/view/email_form.xml b/view/email_form.xml index cfa63a162c..f0c214f952 100644 --- a/view/email_form.xml +++ b/view/email_form.xml @@ -12,5 +12,6 @@ this repository contains the full copyright notices and license terms. -->