manager: test booking reminders sending (#61234)
This commit is contained in:
parent
52a45656a1
commit
aaf66f3930
|
@ -32,20 +32,11 @@ def send_reminder(booking, msg_type):
|
|||
except (VariableDoesNotExist, TemplateSyntaxError):
|
||||
pass
|
||||
|
||||
if msg_type == 'email':
|
||||
emails = set(booking.extra_emails)
|
||||
if booking.user_email:
|
||||
emails.add(booking.user_email)
|
||||
|
||||
for email in emails:
|
||||
if msg_type == 'email' and booking.emails:
|
||||
for email in booking.emails:
|
||||
send_email_reminder(email, booking, kind, ctx)
|
||||
elif msg_type == 'sms':
|
||||
phone_numbers = set(booking.extra_phone_numbers)
|
||||
if booking.user_phone_number:
|
||||
phone_numbers.add(booking.user_phone_number)
|
||||
|
||||
if phone_numbers:
|
||||
send_sms_reminder(list(phone_numbers), booking, kind, ctx)
|
||||
elif msg_type == 'sms' and booking.phone_numbers:
|
||||
send_sms_reminder(booking.phone_numbers, booking, kind, ctx)
|
||||
|
||||
|
||||
def send_email_reminder(email, booking, kind, ctx):
|
||||
|
|
|
@ -1933,6 +1933,20 @@ class Booking(models.Model):
|
|||
def user_name(self):
|
||||
return ('%s %s' % (self.user_first_name, self.user_last_name)).strip()
|
||||
|
||||
@cached_property
|
||||
def emails(self):
|
||||
emails = set(self.extra_emails)
|
||||
if self.user_email:
|
||||
emails.add(self.user_email)
|
||||
return list(emails)
|
||||
|
||||
@cached_property
|
||||
def phone_numbers(self):
|
||||
phone_numbers = set(self.extra_phone_numbers)
|
||||
if self.user_phone_number:
|
||||
phone_numbers.add(self.user_phone_number)
|
||||
return list(phone_numbers)
|
||||
|
||||
def cancel(self, trigger_callback=False):
|
||||
timestamp = now()
|
||||
with transaction.atomic():
|
||||
|
|
|
@ -30,6 +30,7 @@ from django.core.exceptions import FieldDoesNotExist
|
|||
from django.db import transaction
|
||||
from django.forms import ValidationError
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.six import StringIO
|
||||
from django.utils.timezone import localtime, make_aware, now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -1213,6 +1214,55 @@ class AgendaReminderForm(forms.ModelForm):
|
|||
del self.fields['sms_extra_info']
|
||||
|
||||
|
||||
class BookingChoiceField(forms.ModelChoiceField):
|
||||
def label_from_instance(self, obj):
|
||||
name = obj.user_name or obj.label or _('Anonymous')
|
||||
date = date_format(localtime(obj.creation_datetime), 'SHORT_DATETIME_FORMAT')
|
||||
emails = ', '.join(sorted(obj.emails)) or _('no email')
|
||||
phone_numbers = ', '.join(sorted(obj.phone_numbers)) or _('no phone number')
|
||||
|
||||
if settings.SMS_URL:
|
||||
return '%s, %s, %s (%s)' % (name, emails, phone_numbers, date)
|
||||
else:
|
||||
return '%s, %s (%s)' % (name, emails, date)
|
||||
|
||||
|
||||
class AgendaReminderTestForm(forms.Form):
|
||||
booking = BookingChoiceField(
|
||||
label=_('Booking'),
|
||||
queryset=Booking.objects.none(),
|
||||
help_text=_('Only the last ten bookings are displayed.'),
|
||||
)
|
||||
msg_type = forms.MultipleChoiceField(
|
||||
label=_('Send via'),
|
||||
choices=(('email', _('Email')), ('sms', _('SMS'))),
|
||||
widget=forms.CheckboxSelectMultiple(),
|
||||
)
|
||||
email = forms.EmailField(
|
||||
label=_('Email'),
|
||||
help_text=_('This will override email specified on booking creation, if any.'),
|
||||
required=False,
|
||||
)
|
||||
phone_number = forms.CharField(
|
||||
label=_('Phone number'),
|
||||
max_length=16,
|
||||
help_text=_('This will override phone number specified on booking creation, if any.'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
agenda = kwargs.pop('agenda')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['booking'].queryset = Booking.objects.filter(
|
||||
pk__in=Booking.objects.filter(event__agenda=agenda).order_by('-creation_datetime')[:10]
|
||||
).order_by('-creation_datetime')
|
||||
|
||||
if not settings.SMS_URL:
|
||||
self.fields['msg_type'].initial = ['email']
|
||||
self.fields['msg_type'].widget = forms.MultipleHiddenInput()
|
||||
del self.fields['phone_number']
|
||||
|
||||
|
||||
class AgendasExportForm(forms.Form):
|
||||
agendas = forms.BooleanField(label=_('Agendas'), required=False, initial=True)
|
||||
unavailability_calendars = forms.BooleanField(
|
||||
|
|
|
@ -57,6 +57,11 @@
|
|||
<a rel="popup" data-selector="#message-preview" href="{% url 'chrono-manager-agenda-reminder-preview' pk=object.id type='sms' %}">{% trans "Preview SMS" %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% if agenda.reminder_settings.days_before_email or agenda.reminder_settings.days_before_sms %}
|
||||
<p>
|
||||
<a rel="popup" href="{% url 'chrono-manager-agenda-reminder-test' pk=object.pk %}">{% trans "Test reminder sending" %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "chrono/manager_agenda_view.html" %}
|
||||
{% load i18n gadjo %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-agenda-settings' agenda.pk %}">{% trans 'Settings' %}</a>
|
||||
<a href="{% url 'chrono-manager-agenda-edit' agenda.pk %}">{{ title }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Test reminder sending" %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form|with_template }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Send" %}</button>
|
||||
<a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=agenda.id %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -186,6 +186,11 @@ urlpatterns = [
|
|||
views.agenda_reminder_settings,
|
||||
name='chrono-manager-agenda-reminder-settings',
|
||||
),
|
||||
url(
|
||||
r'^agendas/(?P<pk>\d+)/reminder/test/$',
|
||||
views.agenda_reminder_test,
|
||||
name='chrono-manager-agenda-reminder-test',
|
||||
),
|
||||
url(
|
||||
r'^agendas/(?P<pk>\d+)/reminder/preview/(?P<type>(email|sms))/$',
|
||||
views.agenda_reminder_preview,
|
||||
|
|
|
@ -58,6 +58,7 @@ from django.views.generic import (
|
|||
from django.views.generic.dates import MonthMixin, YearMixin
|
||||
from weasyprint import HTML
|
||||
|
||||
from chrono.agendas.management.commands.utils import send_reminder
|
||||
from chrono.agendas.models import (
|
||||
AbsenceReason,
|
||||
AbsenceReasonGroup,
|
||||
|
@ -93,6 +94,7 @@ from .forms import (
|
|||
AgendaEditForm,
|
||||
AgendaNotificationsForm,
|
||||
AgendaReminderForm,
|
||||
AgendaReminderTestForm,
|
||||
AgendaResourceForm,
|
||||
AgendaRolesForm,
|
||||
AgendasExportForm,
|
||||
|
@ -1916,6 +1918,34 @@ class AgendaReminderSettingsView(AgendaEditView):
|
|||
agenda_reminder_settings = AgendaReminderSettingsView.as_view()
|
||||
|
||||
|
||||
class AgendaReminderTestView(ManagedAgendaMixin, FormView):
|
||||
template_name = 'chrono/manager_send_reminder_form.html'
|
||||
form_class = AgendaReminderTestForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(FormView, self).get_form_kwargs()
|
||||
kwargs['agenda'] = self.agenda
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
booking = form.cleaned_data['booking']
|
||||
|
||||
if form.cleaned_data.get('phone_number'):
|
||||
booking.user_phone_number = form.cleaned_data['phone_number']
|
||||
booking.extra_phone_numbers.clear()
|
||||
|
||||
if form.cleaned_data.get('email'):
|
||||
booking.user_email = form.cleaned_data['email']
|
||||
booking.extra_emails.clear()
|
||||
|
||||
for msg_type in form.cleaned_data['msg_type']:
|
||||
send_reminder(booking, msg_type)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
agenda_reminder_test = AgendaReminderTestView.as_view()
|
||||
|
||||
|
||||
class AgendaReminderPreviewView(ManagedAgendaMixin, TemplateView):
|
||||
template_name = 'chrono/manager_agenda_reminder_preview.html'
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import datetime
|
||||
import json
|
||||
from unittest import mock
|
||||
|
||||
import freezegun
|
||||
|
@ -2631,6 +2632,105 @@ def test_manager_reminders_preview(app, admin_user):
|
|||
assert '{{ booking.extra_data.xxx }}' in resp.text
|
||||
|
||||
|
||||
def test_manager_reminders_test_sending(app, admin_user, freezer, mailoutbox, settings):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
AgendaReminderSettings.objects.create(
|
||||
agenda=agenda,
|
||||
days_before_email=1,
|
||||
email_extra_info='Take your {{ booking.extra_data.document_type }}.',
|
||||
days_before_sms=1,
|
||||
sms_extra_info='Take {{ booking.extra_data.document_type }}.',
|
||||
)
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
||||
resp = resp.click('Test reminder sending')
|
||||
|
||||
assert 'phone_number' not in resp.form.fields
|
||||
assert resp.form['msg_type'].attrs['type'] == 'hidden'
|
||||
assert resp.form['booking'].options == [('', True, '---------')]
|
||||
|
||||
# add bookings
|
||||
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
|
||||
freezer.move_to('2020-01-01 14:00')
|
||||
Booking.objects.create(user_first_name='oldest', user_email='t@test.org', event=event)
|
||||
freezer.move_to('2020-01-02 14:00')
|
||||
for _ in range(10):
|
||||
Booking.objects.create(
|
||||
event=event,
|
||||
user_first_name='Jon',
|
||||
user_last_name='Doe',
|
||||
user_email='t@test.org',
|
||||
user_phone_number='+336123456780',
|
||||
)
|
||||
freezer.move_to('2020-01-03 14:00')
|
||||
last_booking = Booking.objects.create(
|
||||
event=event,
|
||||
user_first_name='Jane',
|
||||
user_last_name='Doe',
|
||||
user_email='t@test.org',
|
||||
extra_emails=['u@test.org'],
|
||||
user_phone_number='+33122334455',
|
||||
extra_phone_numbers=['+33122334456'],
|
||||
extra_data={'document_type': 'receipt'},
|
||||
)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/reminder/test/' % agenda.id)
|
||||
assert [x[2] for x in resp.form['booking'].options[:2]] == [
|
||||
'---------',
|
||||
'Jane Doe, t@test.org, u@test.org (01/03/2020 3 p.m.)',
|
||||
]
|
||||
assert [x[2] for x in resp.form['booking'].options[2:]] == ['Jon Doe, t@test.org (01/02/2020 3 p.m.)'] * 9
|
||||
|
||||
resp.form['booking'] = last_booking.pk
|
||||
resp = resp.form.submit().follow()
|
||||
|
||||
assert len(mailoutbox) == 2
|
||||
assert {x.to[0] for x in mailoutbox} == {'t@test.org', 'u@test.org'}
|
||||
assert all('Take your receipt' in mail.body for mail in mailoutbox)
|
||||
mailoutbox.clear()
|
||||
|
||||
settings.SMS_URL = 'https://passerelle.test.org/sms/send/'
|
||||
settings.SMS_SENDER = 'EO'
|
||||
|
||||
resp = app.get('/manage/agendas/%s/reminder/test/' % agenda.id)
|
||||
assert [x[2] for x in resp.form['booking'].options[:2]] == [
|
||||
'---------',
|
||||
'Jane Doe, t@test.org, u@test.org, +33122334455, +33122334456 (01/03/2020 3 p.m.)',
|
||||
]
|
||||
assert [x[2] for x in resp.form['booking'].options[2:]] == [
|
||||
'Jon Doe, t@test.org, +336123456780 (01/02/2020 3 p.m.)'
|
||||
] * 9
|
||||
|
||||
resp.form['booking'] = last_booking.pk
|
||||
resp.form['msg_type'] = ['email', 'sms']
|
||||
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
||||
mock_send.return_value = mock.Mock(status_code=200)
|
||||
resp = resp.form.submit().follow()
|
||||
|
||||
body = json.loads(mock_send.call_args[0][0].body.decode())
|
||||
assert 'Take receipt' in body['message']
|
||||
assert set(body['to']) == {'+33122334455', '+33122334456'}
|
||||
|
||||
assert len(mailoutbox) == 2
|
||||
mailoutbox.clear()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/reminder/test/' % agenda.id)
|
||||
resp.form['booking'] = last_booking.pk
|
||||
resp.form['msg_type'] = ['sms', 'email']
|
||||
resp.form['email'] = 'v@test.org'
|
||||
resp.form['phone_number'] = '+33333333333'
|
||||
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
||||
mock_send.return_value = mock.Mock(status_code=200)
|
||||
resp = resp.form.submit().follow()
|
||||
|
||||
body = json.loads(mock_send.call_args[0][0].body.decode())
|
||||
assert body['to'] == ['+33333333333']
|
||||
assert len(mailoutbox) == 1
|
||||
assert mailoutbox[0].to == ['v@test.org']
|
||||
|
||||
|
||||
def test_manager_agenda_roles(app, admin_user, manager_user):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
|
|
Loading…
Reference in New Issue