From 1933eb6a9f6c8cd859fa1af6809a9c15fc8810cd Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Wed, 7 Mar 2018 19:20:31 +0100 Subject: [PATCH] lingo: send emails when notifying new invoices (#13122) --- combo/apps/lingo/models.py | 26 ++++++++++++++ .../invoice_email_notification_body.html | 20 +++++++++++ .../combo/invoice_email_notification_body.txt | 13 +++++++ .../invoice_email_notification_subject.txt | 4 +++ combo/settings.py | 3 ++ tests/test_lingo_remote_regie.py | 36 +++++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.html create mode 100644 combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.txt create mode 100644 combo/apps/lingo/templates/lingo/combo/invoice_email_notification_subject.txt diff --git a/combo/apps/lingo/models.py b/combo/apps/lingo/models.py index bbd26083..9b53de7b 100644 --- a/combo/apps/lingo/models.py +++ b/combo/apps/lingo/models.py @@ -33,10 +33,13 @@ from django.db import models from django.forms import models as model_forms, Select from django.utils.translation import ugettext_lazy as _ from django.utils import timezone, dateparse +from django.core.mail import EmailMultiAlternatives +from django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.utils.http import urlencode from django.contrib.auth.models import User +from django.template.loader import render_to_string from combo.data.fields import RichTextField from combo.data.models import CellBase @@ -247,6 +250,8 @@ class Regie(models.Model): else: message = _('Reminder: invoice %s to pay') % invoice['label'] notification_id = notification_reminder_id + if not Notification.objects.find(user, notification_id).exists(): + self.notify_remote_invoice_by_email(user, invoice) Notification.notify(user, summary=message, id=notification_id, @@ -271,6 +276,27 @@ class Regie(models.Model): .exclude(external_id__in=notification_ids) \ .forget() + def notify_remote_invoice_by_email(self, user, invoice): + + subject_template = 'lingo/combo/invoice_email_notification_subject.txt' + text_body_template = 'lingo/combo/invoice_email_notification_body.txt' + html_body_template = 'lingo/combo/invoice_email_notification_body.html' + + remote_item = build_remote_item(invoice, self) + payment_url = reverse('view-item', kwargs={'regie_id': self.id, + 'item_crypto_id': remote_item.crypto_id}) + ctx = {'item': remote_item} + ctx.update({'payment_url': urlparse.urljoin(settings.SITE_BASE_URL, payment_url)}) + subject = render_to_string([subject_template], ctx).strip() + text_body = render_to_string([text_body_template], ctx) + html_body = render_to_string([html_body_template], ctx) + message = EmailMultiAlternatives(subject, text_body, to=[user.email]) + message.attach_alternative(html_body, 'text/html') + if invoice['has_pdf']: + invoice_pdf = self.get_invoice_pdf(user, invoice['id']) + message.attach('%s.pdf' % invoice['id'], invoice_pdf.content, 'application/pdf') + message.send() + class BasketItem(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True) diff --git a/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.html b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.html new file mode 100644 index 00000000..16bb059c --- /dev/null +++ b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.html @@ -0,0 +1,20 @@ +{% load i18n %} + + + +

{% blocktrans with id=item.id creation_date=item.creation_date|date:"DATE_FORMAT" amount=item.amount %} + We inform you that your invoice nr. {{ id }} issued on {{ creation_date }} of amount of {{ amount }}€ is available on {{ site_title }}. + {% endblocktrans %}

+ {% if item.online_payment %} +

{% blocktrans %}You can view and pay it online.{% endblocktrans %}

+ {% else %} +

{% blocktrans %}You can view it by going on your {{ site_title }}.{% endblocktrans %}

+ {% if item.no_online_payment_reason == 'autobilling' %} +

{% blocktrans with debit_date=item.payment_limit_date|date:"DATE_FORMAT" %} + The amount of this invoice will be debited from your account at {{ debit_date }}. + {% endblocktrans %} +

+ {% endif %} + {% endif %} + + diff --git a/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.txt b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.txt new file mode 100644 index 00000000..7b562fb7 --- /dev/null +++ b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_body.txt @@ -0,0 +1,13 @@ +{% load i18n %} +{% blocktrans with id=item.id creation_date=item.creation_date|date:"DATE_FORMAT" amount=item.amount %} +We inform you that your invoice nr. {{ id }} issued on {{ creation_date }} of amount +of {{ amount }}€ is available on {{ site_title }}.{% endblocktrans %} + +{% if item.online_payment %}{% blocktrans %}You can view and pay it online on {{ payment_url }}.{% endblocktrans %} +{% else %}{% blocktrans %}You can view it by going on {{ portal_url }}.{% endblocktrans %} + +{% if item.no_online_payment_reason == 'autobilling' %} +{% blocktrans with debit_date=item.payment_limit_date|date:"DATE_FORMAT" %}The amount of this invoice will be debited from your account at {{ debit_date }}.{% endblocktrans %} +{% endif %} +{% endif %} + diff --git a/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_subject.txt b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_subject.txt new file mode 100644 index 00000000..83c802e7 --- /dev/null +++ b/combo/apps/lingo/templates/lingo/combo/invoice_email_notification_subject.txt @@ -0,0 +1,4 @@ +{% load i18n %} +{% blocktrans with invoice_id=item.id %} +New invoice nr. {{ invoice_id }} is available +{% endblocktrans %} diff --git a/combo/settings.py b/combo/settings.py index 4460d016..a7b47380 100644 --- a/combo/settings.py +++ b/combo/settings.py @@ -288,6 +288,9 @@ COMBO_MAP_ATTRIBUTION = 'Map data © Ope # default delta, in days, for invoice remind notifications LINGO_NEW_INVOICES_REMIND_DELTA = 7 +# default site +SITE_BASE_URL = 'http://localhost' + # timeout used in python-requests call, in seconds # we use 28s by default: timeout just before web server, which is usually 30s REQUESTS_TIMEOUT = 28 diff --git a/tests/test_lingo_remote_regie.py b/tests/test_lingo_remote_regie.py index 09a59676..30a7bbfa 100644 --- a/tests/test_lingo_remote_regie.py +++ b/tests/test_lingo_remote_regie.py @@ -9,6 +9,8 @@ from django.test.client import RequestFactory from django.core.urlresolvers import reverse from django.conf import settings from django.core.management import call_command +from django.utils.timezone import timedelta, now +from django.contrib.auth.models import User from combo.utils import check_query, aes_hex_encrypt from combo.data.models import Page @@ -36,6 +38,16 @@ INVOICES = [ }, ] +@pytest.fixture +def admin(): + try: + admin = User.objects.get(username='foo') + except User.DoesNotExist: + admin = User.objects.create_user('foo', email=None, password='bar') + admin.email = 'foo@example.net' + admin.save() + return admin + @pytest.fixture def remote_regie(): try: @@ -336,3 +348,27 @@ def test_remote_item_payment_failure(mock_post, mock_get, mock_pay_invoice, app, assert Transaction.objects.all()[0].to_be_paid_remote_items is None call_command('update_transactions') + +@mock.patch('combo.apps.lingo.models.requests.get') +def test_send_new_remote_invoices_by_email(mock_get, admin, app, remote_regie, mailoutbox): + datetime_format = '%Y-%m-%dT%H:%M:%S' + invoice_now = now() + creation_date = (invoice_now - timedelta(days=1)).strftime(datetime_format) + pay_limit_date = (invoice_now + timedelta(days=30)).strftime(datetime_format) + FAKE_PENDING_INVOICES = { + 'data' : {'foo': {'invoices': [{'id': '01', 'label': '010101', 'paid': False, + 'amount': '37.26', 'total_amount': '37.26', 'online_payment': True, + 'has_pdf': True, 'created': creation_date, + 'pay_limit_date': pay_limit_date}]}, + } + } + mock_response = mock.Mock(status_code=200, content=json.dumps(FAKE_PENDING_INVOICES)) + mock_response.json.return_value = FAKE_PENDING_INVOICES + mock_get.return_value = mock_response + remote_regie.notify_new_remote_invoices() + assert len(mailoutbox) == 1 + assert mailoutbox[0].recipients() == ['foo@example.net'] + assert mailoutbox[0].from_email == settings.DEFAULT_FROM_EMAIL + assert mailoutbox[0].subject == 'New invoice nr. 01 is available' + assert mailoutbox[0].attachments[0][0] == '01.pdf' + assert mailoutbox[0].attachments[0][2] == 'application/pdf'