lingo: send emails when notifying new invoices (#13122)

This commit is contained in:
Serghei Mihai 2018-03-07 19:20:31 +01:00
parent 834e1e8612
commit 7d58ccfd3c
7 changed files with 118 additions and 10 deletions

View File

@ -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
@ -229,13 +232,20 @@ class Regie(models.Model):
items_page_url = ''
# notification should be created
if pay_limit_date > now:
# if no notification exists, send the email
if not Notification.objects.find(user, invoice_id):
self.notify_remote_invoice_by_email(user, invoice)
notification = Notification.notify(user, _('Invoice %s to pay') % invoice['label'], id=invoice_id,
url=items_page_url, end_timestamp=invoice['pay_limit_date'])
if pay_limit_date <= now + remind_delta or not notification.acked:
url=items_page_url, end_timestamp=pay_limit_date)
if pay_limit_date <= now + remind_delta or notification.acked:
# if no remind notification exists, send the email
if not Notification.objects.find(user, reminder_id):
self.notify_remote_invoice_by_email(user, invoice)
# create remind notification
Notification.notify(user, _('Reminder: invoice %s to pay') % invoice['label'],
id=reminder_id, url=items_page_url,
end_timestamp=invoice['pay_limit_date'])
self.notify_remote_invoice_by_email(user, invoice)
else:
Notification.forget(user, invoice_id)
Notification.forget(user, reminder_id)
@ -251,6 +261,27 @@ class Regie(models.Model):
if Decimal(invoice['total_amount']) >= self.payment_min_amount:
self.notify_invoice(user, invoice)
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)

View File

@ -0,0 +1,20 @@
{% load i18n %}
<html>
<body style="max-width: 60em">
<p>{% 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 %}</p>
{% if item.online_payment %}
<p>{% blocktrans %}You can <a href="{{ payment_url }}">view and pay it online</a>.{% endblocktrans %}</p>
{% else %}
<p>{% blocktrans %}You can view it by going on your <a href="{{ portal_url }}">{{ site_title }}</a>.{% endblocktrans %}</p>
{% if item.no_online_payment_reason == 'autobilling' %}
<p>{% 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 %}
</p>
{% endif %}
{% endif %}
</body>
</html>

View File

@ -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 %}

View File

@ -0,0 +1,4 @@
{% load i18n %}
{% blocktrans with invoice_id=item.id %}
New invoice nr. {{ invoice_id }} is available
{% endblocktrans %}

View File

@ -288,6 +288,9 @@ COMBO_MAP_ATTRIBUTION = 'Map data &copy; <a href="https://openstreetmap.org">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

View File

@ -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'

View File

@ -280,14 +280,14 @@ def test_notify_remote_items(mock_get, app, user, user2, regie):
creation_date = (invoice_now - timedelta(days=1)).strftime(datetime_format)
pay_limit_date = (invoice_now + timedelta(days=5)).strftime(datetime_format)
FAKE_PENDING_INVOICES = {
"data" : {"admin": {"invoices": [{'id': '01', 'label': '010101', 'total_amount': '10',
'created': creation_date, 'pay_limit_date': pay_limit_date},
{'id': '011', 'label': '0101011', 'total_amount': '1.5',
'created': creation_date, 'pay_limit_date': pay_limit_date}]},
'admin2': {'invoices': [{'id': '02', 'label': '020202', 'total_amount': '2.0',
'created': creation_date, 'pay_limit_date': pay_limit_date}]},
'foo': {'invoices': [{'id': 'O3', 'label': '030303', 'total_amount': '42',
'created': creation_date, 'pay_limit_date': pay_limit_date}]}
"data" : {"admin": {"invoices": [{'id': '01', 'label': '010101', 'total_amount': '10', 'amount': '10',
'created': creation_date, 'pay_limit_date': pay_limit_date, 'has_pdf': False},
{'id': '011', 'label': '0101011', 'total_amount': '1.5', 'amount': '1.5',
'created': creation_date, 'pay_limit_date': pay_limit_date, 'has_pdf': False}]},
'admin2': {'invoices': [{'id': '02', 'label': '020202', 'total_amount': '2.0', 'amount': '2.0',
'created': creation_date, 'pay_limit_date': pay_limit_date, 'has_pdf': False}]},
'foo': {'invoices': [{'id': 'O3', 'label': '030303', 'total_amount': '42', 'amount': '42',
'created': creation_date, 'pay_limit_date': pay_limit_date, 'has_pdf': False}]}
}
}
mock_response = mock.Mock(status_code=200, content=json.dumps(FAKE_PENDING_INVOICES))
@ -298,6 +298,7 @@ def test_notify_remote_items(mock_get, app, user, user2, regie):
regie.webservice_url = 'http://example.org/regie' # is_remote
regie.save()
regie.notify_new_remote_invoices()
assert Notification.objects.filter(external_id__startswith='invoice-%s' % regie.slug).count() == 2
for notif in Notification.objects.all():
print notif, notif.external_id