feat(members/waitinglist): notify responsibles in case of rejections

MK/finance_workflow
Christian Merten 8 months ago
parent 5d728f1eee
commit 0535cce70f
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -22,6 +22,24 @@ bestätige falls möglich. Zu der Registrierung kommst du hier:
Viele Grüße Viele Grüße
Dein KOMPASS""") Dein KOMPASS""")
GROUP_INVITATION_LEFT_WAITINGLIST = get_text('group_invitation_left_waitinglist',
default="""Hallo {name},
der*die kürzlich zu einer Schnupperstunde für die Gruppe {group} eingeladene Wartende {waiter}
hat die Warteliste verlassen.
Viele Grüße
Dein KOMPASS""")
GROUP_INVITATION_REJECTED = get_text('group_invitation_rejected',
default="""Hallo {name},
{waiter} hat die Einladung zu einer Schnupperstunde bei der Gruppe {group} abgelehnt, ist
aber weiterhin auf der Warteliste.
Viele Grüße
Dein KOMPASS""")
GROUP_TIME_AVAILABLE_TEXT = get_text('group_time_available', GROUP_TIME_AVAILABLE_TEXT = get_text('group_time_available',
default="""Die Gruppenstunde findet jeden {weekday} von {start_time} bis {end_time} Uhr statt.""") default="""Die Gruppenstunde findet jeden {weekday} von {start_time} bis {end_time} Uhr statt.""")

@ -712,7 +712,12 @@ class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin):
def invite_view(self, request, object_id): def invite_view(self, request, object_id):
if type(object_id) == str: if type(object_id) == str:
waiter = MemberWaitingList.objects.get(pk=object_id) try:
waiter = MemberWaitingList.objects.get(pk=object_id)
except MemberWaitingList.DoesNotExist:
messages.error(request,
_("A waiter with this ID does not exist."))
return HttpResponseRedirect(reverse('admin:members_memberwaitinglist_changelist'))
queryset = [waiter] queryset = [waiter]
id_list = [waiter.pk] id_list = [waiter.pk]
else: else:
@ -756,7 +761,8 @@ class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin):
_("An error occurred while trying to invite said members. Please try again.")) _("An error occurred while trying to invite said members. Please try again."))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
for w in queryset: for w in queryset:
w.invite_to_group(group, text_template=text_template) w.invite_to_group(group, text_template=text_template,
creator=request.user.member if hasattr(request.user, 'member') else None)
messages.success(request, messages.success(request,
_("Successfully invited %(name)s to %(group)s.") % {'name': w.name, 'group': w.invited_for_group.name}) _("Successfully invited %(name)s to %(group)s.") % {'name': w.name, 'group': w.invited_for_group.name})

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-08 16:16+0100\n" "POT-Creation-Date: 2025-04-06 14:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -226,6 +226,10 @@ msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen"
msgid "Offer waiter a place in a group." msgid "Offer waiter a place in a group."
msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten."
#: members/admin.py
msgid "A waiter with this ID does not exist."
msgstr "Es existiert keine wartende Person mit dieser ID."
#: members/admin.py #: members/admin.py
msgid "" msgid ""
"An error occurred while trying to invite said members. Please try again." "An error occurred while trying to invite said members. Please try again."
@ -763,6 +767,10 @@ msgstr "Einladungsdatum"
msgid "Invitation rejected" msgid "Invitation rejected"
msgstr "Einladung abgelehnt" msgstr "Einladung abgelehnt"
#: members/models.py
msgid "Created by"
msgstr "Erstellt von"
#: members/models.py #: members/models.py
msgid "Invitation to group" msgid "Invitation to group"
msgstr "Gruppeneinladung" msgstr "Gruppeneinladung"
@ -787,6 +795,16 @@ msgstr "Ausstehend"
msgid "Status" msgid "Status"
msgstr "Status" msgstr "Status"
#: members/models.py
#, python-format
msgid "%(waiter)s left the waiting list"
msgstr "%(waiter)s hat die Warteliste verlassen"
#: members/models.py
#, python-format
msgid "Group invitation rejected by %(waiter)s"
msgstr "Einladung zur Schnupperstunde von %(waiter)s abgelehnt"
#: members/models.py #: members/models.py
msgid "Do you want to tell us something else?" msgid "Do you want to tell us something else?"
msgstr "Möchtest du uns noch etwas mitteilen?" msgstr "Möchtest du uns noch etwas mitteilen?"

@ -0,0 +1,19 @@
# Generated by Django 4.2.20 on 2025-04-06 11:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('members', '0039_membertraining_certificate_attendance'),
]
operations = [
migrations.AddField(
model_name='invitationtogroup',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_group_invitations', to='members.member', verbose_name='Created by'),
),
]

@ -874,6 +874,11 @@ class InvitationToGroup(models.Model):
date = models.DateField(default=timezone.now, verbose_name=_('Invitation date')) date = models.DateField(default=timezone.now, verbose_name=_('Invitation date'))
rejected = models.BooleanField(verbose_name=_('Invitation rejected'), default=False) rejected = models.BooleanField(verbose_name=_('Invitation rejected'), default=False)
key = models.CharField(max_length=32, default=gen_key) key = models.CharField(max_length=32, default=gen_key)
created_by = models.ForeignKey(Member, verbose_name=_('Created by'),
blank=True,
null=True,
on_delete=models.SET_NULL,
related_name='created_group_invitations')
class Meta: class Meta:
verbose_name = _('Invitation to group') verbose_name = _('Invitation to group')
@ -891,6 +896,42 @@ class InvitationToGroup(models.Model):
return _('Undecided') return _('Undecided')
status.short_description = _('Status') status.short_description = _('Status')
def send_left_waitinglist_notification_to(self, recipient):
send_mail(_('%(waiter)s left the waiting list') % {'waiter': self.waiter},
settings.GROUP_INVITATION_LEFT_WAITINGLIST.format(name=recipient.prename,
waiter=self.waiter,
group=self.group),
settings.DEFAULT_SENDING_MAIL,
recipient.email)
def send_reject_notification_to(self, recipient):
send_mail(_('Group invitation rejected by %(waiter)s') % {'waiter': self.waiter},
settings.GROUP_INVITATION_REJECTED.format(name=recipient.prename,
waiter=self.waiter,
group=self.group),
settings.DEFAULT_SENDING_MAIL,
recipient.email)
def notify_left_waitinglist(self):
"""
Inform youth leaders of the group and the inviter that the waiter left the waitinglist,
prompted by this group invitation.
"""
if self.created_by:
self.send_left_waitinglist_notification_to(self.created_by)
for jl in self.group.leiters.all():
self.send_left_waitinglist_notification_to(jl)
def reject(self):
"""Reject this invitation. Informs the youth leaders of the group of the rejection."""
self.rejected = True
self.save()
# send notifications
if self.created_by:
self.send_reject_notification_to(self.created_by)
for jl in self.group.leiters.all():
self.send_reject_notification_to(jl)
class MemberWaitingList(Person): class MemberWaitingList(Person):
"""A participant on the waiting list""" """A participant on the waiting list"""
@ -1008,7 +1049,7 @@ class MemberWaitingList(Person):
except InvitationToGroup.DoesNotExist: except InvitationToGroup.DoesNotExist:
return False return False
def invite_to_group(self, group, text_template=None): def invite_to_group(self, group, text_template=None, creator=None):
""" """
Invite waiter to given group. Stores a new group invitation Invite waiter to given group. Stores a new group invitation
and sends a personalized e-mail based on the passed template. and sends a personalized e-mail based on the passed template.
@ -1017,7 +1058,7 @@ class MemberWaitingList(Person):
self.save() self.save()
if not text_template: if not text_template:
text_template = group.get_invitation_text_template() text_template = group.get_invitation_text_template()
invitation = InvitationToGroup(group=group, waiter=self) invitation = InvitationToGroup(group=group, waiter=self, created_by=creator)
invitation.save() invitation.save()
self.send_mail(_("Invitation to trial group meeting"), self.send_mail(_("Invitation to trial group meeting"),
text_template.format(name=self.prename, text_template.format(name=self.prename,

@ -470,10 +470,10 @@ def reject_invitation(request):
except InvitationToGroup.DoesNotExist: except InvitationToGroup.DoesNotExist:
return render_reject_invalid(request) return render_reject_invalid(request)
if 'reject_invitation' in request.POST: if 'reject_invitation' in request.POST:
invitation.rejected = True invitation.reject()
invitation.save()
return render_reject_success(request, invitation) return render_reject_success(request, invitation)
elif 'leave_waitinglist' in request.POST: elif 'leave_waitinglist' in request.POST:
invitation.notify_left_waitinglist()
invitation.waiter.unregister() invitation.waiter.unregister()
return render_reject_success(request, invitation, leave_waitinglist=True) return render_reject_success(request, invitation, leave_waitinglist=True)
return render_reject_invalid(request) return render_reject_invalid(request)

Loading…
Cancel
Save