Verified Commit f699ff92 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Add email for event's organising party at registration cancellation.

parent 7bfde2f1
......@@ -53,7 +53,7 @@ class EventAdmin(DoNextModelAdmin):
inlines = (RegistrationInformationFieldInline,)
fields = ('title', 'description', 'start', 'end', 'organiser', 'category',
'registration_start', 'registration_end', 'cancel_deadline',
'location', 'map_location', 'price', 'fine',
'send_cancel_email', 'location', 'map_location', 'price', 'fine',
'max_participants', 'no_registration_message', 'published')
list_display = ('overview_link', 'event_date', 'registration_date',
'num_participants', 'organiser', 'category', 'published',
......
......@@ -18,7 +18,7 @@ def notify_first_waiting(request, event):
.order_by('date')[event.max_participants])
first_waiting_member = first_waiting.member
text_template = get_template('events/email.txt')
text_template = get_template('events/member_email.txt')
with translation.override(first_waiting_member.language):
subject = _("[THALIA] Notification about your "
......@@ -36,3 +36,22 @@ def notify_first_waiting(request, event):
text_message,
to=[first_waiting_member.user.email]
).send()
def notify_organiser(event, registration):
if event.organiser is None or event.organiser.contact_mailinglist is None:
return
text_template = get_template('events/organiser_email.txt')
subject = 'Registration for {} cancelled by member'.format(
event.title)
text_message = text_template.render({
'event': event,
'registration': registration
})
EmailMessage(
subject,
text_message,
to=[event.organiser.contact_mailinglist.name + "@thalia.nu"]
).send()
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-22 14:54+0200\n"
"PO-Revision-Date: 2017-09-22 14:54+0200\n"
"POT-Creation-Date: 2017-09-23 13:33+0200\n"
"PO-Revision-Date: 2017-09-23 13:35+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n"
"Language: nl\n"
......@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.3\n"
"X-Generator: Poedit 2.0.4\n"
#: admin.py:86
msgid "Event Date"
......@@ -122,7 +122,7 @@ msgstr "Geen aanmelding vereist"
msgid "title"
msgstr "titel"
#: models.py:36 models.py:384
#: models.py:36 models.py:398
msgid "description"
msgstr "beschrijving"
......@@ -162,16 +162,28 @@ msgstr "einde aanmelden"
msgid "cancel deadline"
msgstr "afmelddeadline"
#: models.py:82 templates/events/admin/details.html:76
#: models.py:81
msgid "send cancellation notifications"
msgstr "verstuur afmeldnotificaties"
#: models.py:83
msgid ""
"Send an email to the organising party when a member cancels their "
"registration after the deadline."
msgstr ""
"Verzend een e-mail naar de organiserende partij wanneer een lid zich na de "
"afmelddeadline afmeld voor een evenement."
#: models.py:89 templates/events/admin/details.html:76
#: templates/events/event.html:38
msgid "location"
msgstr "locatie"
#: models.py:87
#: models.py:94
msgid "location for minimap"
msgstr "locatie voor minimap"
#: models.py:89
#: models.py:96
msgid ""
"Location of Huygens: Heyendaalseweg 135, Nijmegen. Location of Mercator 1: "
"Toernooiveld 212, Nijmegen. Not shown as text!!"
......@@ -179,138 +191,142 @@ msgstr ""
"Locatie van ’t Huygens: Heyendaalseweg 135, Nijmegen. Locatie van Mercator "
"1: Toernooiveld 212, Nijmegen. Dit veld wordt niet getoond als tekst!!"
#: models.py:95 templates/events/admin/details.html:78
#: models.py:102 templates/events/admin/details.html:78
#: templates/events/event.html:43
msgid "price"
msgstr "prijs"
#: models.py:103
#: models.py:110
msgid "fine"
msgstr "boete"
#: models.py:109
#: models.py:116
msgid "Fine if participant does not show up (at least €5)."
msgstr "Boete als deelnemer niet komt opdagen (minimaal €5)."
#: models.py:114
#: models.py:121
msgid "maximum number of participants"
msgstr "maximum aantal deelnemers"
#: models.py:121
#: models.py:128
msgid "message when there is no registration"
msgstr "bericht dat getoond wordt wanneer aanmelden niet nodig is"
#: models.py:125
#: models.py:132
msgid "Default:"
msgstr "Standaard:"
#: models.py:129
#: models.py:136
msgid "published"
msgstr "gepubliceerd"
#: models.py:185
#: models.py:192
msgid "Can't have an event travel back in time"
msgstr "Een evenement kan niet terugreizen in de tijd"
#: models.py:189
#: models.py:196
msgid "The fine for this event is too low (must be at least €5)."
msgstr "De boete voor dit evenement is te laag (minimaal €5)."
#: models.py:196
#: models.py:203
msgid "Doesn't make sense to have this if you require registrations."
msgstr "Het is niet logisch om dit te hebben als je aanmelden vereist."
#: models.py:201
#: models.py:208
msgid "If registration is required, you need a start of registration"
msgstr ""
"Als aanmelden vereist is, dan heb je een starttijd voor de aanmeldperiode "
"nodig"
#: models.py:206
#: models.py:213
msgid "If registration is required, you need an end of registration"
msgstr ""
"Als aanmelden vereist is, dan heb je een eindtijd voor de aanmeldperiode "
"nodig"
#: models.py:211
#: models.py:218
msgid "If registration is required, you need a deadline for the cancellation"
msgstr ""
"Als aanmelden vereist is, dan heb je een eindtijd voor de aanmeldperiode "
"nodig"
#: models.py:216
#: models.py:223
msgid "The cancel deadline should be before the start of the event."
msgstr "De afmelddeadline moet voor de start van het evenement liggen."
#: models.py:220
#: models.py:227
msgid "Registration start should be before registration end"
msgstr "De starttijd voor de aanmeldperiode moet voor de eindtijd liggen"
#: models.py:251
#: models.py:236
msgid "This organiser does not have a contact mailinglist."
msgstr "De organisator heeft geen contact mailinglijst."
#: models.py:265
msgid "No payment"
msgstr "Niet betaald"
#: models.py:252
#: models.py:266
msgid "Paid with cash"
msgstr "Contact betaald"
#: models.py:253
#: models.py:267
msgid "Paid with card"
msgstr "Pin betaald"
#: models.py:266 templates/events/admin/registrations_table.html:6
#: models.py:280 templates/events/admin/registrations_table.html:6
msgid "name"
msgstr "naam"
#: models.py:268
#: models.py:282
msgid "Use this for non-members"
msgstr "Gebruikt dit voor niet-leden"
#: models.py:273
#: models.py:287
msgid "registration date"
msgstr "aanmelddatum"
#: models.py:275
#: models.py:289
msgid "cancellation date"
msgstr "afmelddatum"
#: models.py:280 templates/events/admin/registrations_table.html:11
#: models.py:294 templates/events/admin/registrations_table.html:11
msgid "present"
msgstr "aanwezig"
#: models.py:287
#: models.py:301
msgid "payment"
msgstr "betaling"
#: models.py:340 models.py:341
#: models.py:354 models.py:355
msgid "Either specify a member or a name"
msgstr "Geef een lid of een naam op"
#: models.py:364
#: models.py:378
msgid "Checkbox"
msgstr "Checkbox"
#: models.py:365
#: models.py:379
msgid "Text"
msgstr "Text"
#: models.py:366
#: models.py:380
msgid "Integer"
msgstr "Integer"
#: models.py:371
#: models.py:385
msgid "field type"
msgstr "veldtype"
#: models.py:378
#: models.py:392
msgid "field name"
msgstr "veldnaam"
#: models.py:390
#: models.py:404
msgid "required"
msgstr "verplicht"
#: models.py:442
#: models.py:456
msgid "last changed"
msgstr "laatst aangepast"
......@@ -328,7 +344,7 @@ msgstr "Je bent al aangemeld."
msgid "You may not register."
msgstr "Je mag je niet aanmelden."
#: services.py:117 services.py:131 services.py:182
#: services.py:121 services.py:135 services.py:186
msgid "You are not registered for this event."
msgstr "Je bent niet aangemeld voor dit evenement."
......@@ -486,39 +502,6 @@ msgstr "Aangemeld voor dit evenement"
msgid "Not registered for this event"
msgstr "Niet aangemeld voor dit evenement"
#: templates/events/email.txt:1
#, python-format
msgid ""
"Hi %(name)s,\n"
"\n"
"You registered for the event '%(event_title)s' on %(registration_date)s and "
"unfortunately you were placed on the waiting list.\n"
"However someone just unregistered and we would like to let you know that "
"you'll be able to attend now!\n"
"\n"
"You can find more information about the event on the website: %(baseurl)s"
"%(event_url)s\n"
"\n"
"We're assuming that you'll be there, but you're still able to unregister "
"until %(cancel_deadline)s.\n"
"\n"
"Best regards,\n"
"Study Association Thalia"
msgstr ""
"Beste %(name)s,\n"
"\n"
"Je hebt je op %(registration_date)s aangemeld voor het evenement "
"'%(event_title)s’. Toen kwam je op de wachtlijst terecht, maar inmiddels is "
"er plaats!\n"
"\n"
"Je kunt het evenement terugvinden op de website: %(baseurl)s%(event_url)s\n"
"\n"
"We gaan ervan uit dat je erbij bent, maar tot %(cancel_deadline)s kan je je "
"nog afmelden.\n"
"\n"
"Met vriendelijke groet,\n"
"Studievereniging Thalia"
#: templates/events/event.html:4 templates/events/event.html:5
#: templates/events/index.html:5 templates/events/index.html:6
#: templates/events/index.html:18 templates/events/registration.html:4
......@@ -645,6 +628,39 @@ msgstr "toon verjaardagen"
msgid "list"
msgstr "lijst"
#: templates/events/member_email.txt:1
#, python-format
msgid ""
"Hi %(name)s,\n"
"\n"
"You registered for the event '%(event_title)s' on %(registration_date)s and "
"unfortunately you were placed on the waiting list.\n"
"However someone just unregistered and we would like to let you know that "
"you'll be able to attend now!\n"
"\n"
"You can find more information about the event on the website: %(baseurl)s"
"%(event_url)s\n"
"\n"
"We're assuming that you'll be there, but you're still able to unregister "
"until %(cancel_deadline)s.\n"
"\n"
"Best regards,\n"
"Study Association Thalia"
msgstr ""
"Beste %(name)s,\n"
"\n"
"Je hebt je op %(registration_date)s aangemeld voor het evenement "
"'%(event_title)s’. Toen kwam je op de wachtlijst terecht, maar inmiddels is "
"er plaats!\n"
"\n"
"Je kunt het evenement terugvinden op de website: %(baseurl)s%(event_url)s\n"
"\n"
"We gaan ervan uit dat je erbij bent, maar tot %(cancel_deadline)s kan je je "
"nog afmelden.\n"
"\n"
"Met vriendelijke groet,\n"
"Studievereniging Thalia"
#: templates/events/registration.html:4 templates/events/registration.html:5
msgid "Registration"
msgstr "Aanmelding"
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.5 on 2017-09-27 17:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('events', '0018_2_registration_payment'),
]
operations = [
migrations.AddField(
model_name='event',
name='send_cancel_email',
field=models.BooleanField(default=False, help_text='Send an email to the organising party when a member cancels their registration after the deadline.', verbose_name='send cancellation notifications'),
),
migrations.AlterField(
model_name='event',
name='send_cancel_email',
field=models.BooleanField(default=True,
help_text='Send an email to the organising party when a member cancels their registration after the deadline.',
verbose_name='send cancellation notifications'),
),
]
......@@ -77,6 +77,13 @@ class Event(models.Model, metaclass=ModelTranslateMeta):
blank=True
)
send_cancel_email = models.BooleanField(
_('send cancellation notifications'),
default=True,
help_text=_("Send an email to the organising party when a member "
"cancels their registration after the deadline."),
)
location = MultilingualField(
models.CharField,
_("location"),
......@@ -222,6 +229,13 @@ class Event(models.Model, metaclass=ModelTranslateMeta):
errors.update({
'registration_start': message,
'registration_end': message})
if (self.organiser is not None and
self.send_cancel_email and
self.organiser.contact_mailinglist is None):
errors.update(
{'send_cancel_email': _("This organiser does not "
"have a contact mailinglist.")})
if errors:
raise ValidationError(errors)
......
......@@ -107,6 +107,10 @@ def cancel_registration(request, user, event):
if registration.queue_position == 0:
emails.notify_first_waiting(request, event)
if (event.send_cancel_email and
event.after_cancel_deadline):
emails.notify_organiser(event, registration)
# Note that this doesn"t remove the values for the
# information fields that the user entered upon registering.
# But this is regarded as a feature, not a bug. Especially
......
{% load baseurl %}Hi,
A member that was registered for the event '{{ event.title }}' that you're organising has cancelled their registration after the deadline.
Name: {{ registration.member.display_name }}
Registration date: {{ registration.date|date:"SHORT_DATETIME_FORMAT" }}
......@@ -6,20 +6,31 @@ from django.utils import timezone
from activemembers.models import Committee
from events.models import Event, Registration
from mailinglists.models import MailingList
from members.models import Member
class EventTest(TestCase):
"""Tests events"""
fixtures = ['members.json', 'committees.json']
fixtures = ['members.json']
@classmethod
def setUpTestData(cls):
cls.mailinglist = MailingList.objects.create(
name="testmail"
)
cls.committee = Committee.objects.create(
name_nl="commissie",
name_en="committee",
contact_mailinglist=cls.mailinglist
)
cls.event = Event.objects.create(
title_nl='testevene',
title_en='testevent',
organiser=Committee.objects.get(pk=1),
organiser=cls.committee,
description_en='desc',
description_nl='besch',
start=(timezone.now() + datetime.timedelta(hours=1)),
......@@ -32,6 +43,8 @@ class EventTest(TestCase):
cls.member = Member.objects.all()[0]
def setUp(self):
self.mailinglist.refresh_from_db()
self.committee.refresh_from_db()
self.event.refresh_from_db()
self.member.refresh_from_db()
......@@ -185,6 +198,14 @@ class EventTest(TestCase):
self.event.cancel_deadline = None
self.assertFalse(self.event.registration_allowed)
def test_missing_orgination_mailinglist(self):
self.event.clean()
self.event.organiser.contact_mailinglist = None
with self.assertRaises(ValidationError):
self.event.clean()
def test_cancellation_allowed(self):
# Open
self.event.registration_start = (timezone.now() -
......
import datetime
from django.contrib.auth.models import Permission
from django.core import mail
from django.test import Client, TestCase
from django.utils import timezone
......@@ -10,6 +11,7 @@ from events.models import (Event, Registration,
BooleanRegistrationInformation,
IntegerRegistrationInformation,
TextRegistrationInformation)
from mailinglists.models import MailingList
from members.models import Member
......@@ -132,9 +134,17 @@ class RegistrationTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.mailinglist = MailingList.objects.create(
name="testmail"
)
cls.committee = Committee.objects.create(
name_nl="commissie",
name_en="committee",
contact_mailinglist=cls.mailinglist
)
cls.event = Event.objects.create(
pk=1,
organiser=Committee.objects.get(pk=1),
organiser=cls.committee,
title_nl='testevene',
title_en='testevent',
description_en='desc',
......@@ -432,3 +442,21 @@ class RegistrationTest(TestCase):
self.assertEqual(field1.get_value_for(registration), False)
self.assertEqual(field2.get_value_for(registration), 1337)
self.assertEqual(field3.get_value_for(registration), 'no text')
def test_registration_cancel_after_deadline_notification(self):
self.event.registration_start = (timezone.now() -
datetime.timedelta(hours=2))
self.event.registration_end = (timezone.now() -
datetime.timedelta(hours=1))
self.event.cancel_deadline = (timezone.now() -
datetime.timedelta(hours=1))
self.event.send_cancel_email = True
self.event.save()
Registration.objects.create(event=self.event, member=self.member)
response = self.client.post('/events/1/registration/cancel/',
follow=True)
self.assertEqual(response.status_code, 200)
self.assertEqual(self.event.participants.count(), 0)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.event.organiser.
contact_mailinglist.name + "@thalia.nu"])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment