diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po
index 5957073947..c28e158bba 100644
--- a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po
+++ b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po
@@ -22739,7 +22739,7 @@ msgstr "Neue Regel erstellen"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html:24
msgid "Email subject"
-msgstr "E-Mail wurde verschickt"
+msgstr "E-Mail-Betreff"
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html:26
msgid "Scheduled time"
diff --git a/src/pretix/plugins/sendmail/models.py b/src/pretix/plugins/sendmail/models.py
index 859603d03f..4b8c4dafc2 100644
--- a/src/pretix/plugins/sendmail/models.py
+++ b/src/pretix/plugins/sendmail/models.py
@@ -45,10 +45,10 @@ class ScheduledMail(models.Model):
STATE_MISSED = 'missed'
STATE_CHOICES = [
- (STATE_SCHEDULED, STATE_SCHEDULED),
- (STATE_FAILED, STATE_FAILED),
- (STATE_COMPLETED, STATE_COMPLETED),
- (STATE_MISSED, STATE_MISSED),
+ (STATE_SCHEDULED, _('scheduled')),
+ (STATE_FAILED, _('failed')),
+ (STATE_COMPLETED, _('completed')),
+ (STATE_MISSED, _('missed')),
]
id = models.BigAutoField(primary_key=True)
@@ -71,6 +71,9 @@ class ScheduledMail(models.Model):
super().save(**kwargs)
def recompute(self):
+ if self.state in (self.STATE_COMPLETED, self.STATE_MISSED):
+ return
+
if self.rule.date_is_absolute:
self.computed_datetime = self.rule.send_date
else:
diff --git a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_inspect.html b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_inspect.html
new file mode 100644
index 0000000000..61d7fc4804
--- /dev/null
+++ b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_inspect.html
@@ -0,0 +1,62 @@
+{% extends "pretixcontrol/event/base.html" %}
+{% load i18n %}
+{% load static %}
+{% block title %}{% trans "Inspect Email Rule" %}{% endblock %}
+{% block content %}
+
{% trans "Inspect Email Rule" %}
+
+ {% blocktrans trimmed %}
+ This page shows when your rule is planned to be sent.
+ {% endblocktrans %}
+
+
+ {% trans "Email subject" %}
+ {{ rule.subject }}
+ {% trans "Recipient" %}
+ {{ rule.get_send_to_display }}
+ {% trans "Scheduled time" %}
+ {{ rule.human_readable_time }}
+
+
+
+
+
+
+ {% trans "Scheduled time" %}
+ {% if request.event.has_subevents %}
+ {% trans "Date" context "subevent" %}
+ {% endif %}
+ {% trans "Status" %}
+ {% trans "Last schedule computation" %}
+
+
+
+
+ {% for sm in scheduled_mails %}
+
+
+ {{ sm.computed_datetime|date:"SHORT_DATETIME_FORMAT" }}
+
+ {% if request.event.has_subevents %}
+
+
+ {{ sm.subevent.name }}
+
+ {{ sm.get_date_range_display }}
+
+ {% endif %}
+
+
+ {{ sm.get_state_display }}
+
+
+
+ {{ sm.last_computed|date:"SHORT_DATETIME_FORMAT" }}
+
+
+ {% endfor %}
+
+
+
+ {% include "pretixcontrol/pagination.html" %}
+{% endblock %}
diff --git a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html
index e7b9d7be10..a6138e96d8 100644
--- a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html
+++ b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html
@@ -74,6 +74,7 @@
{{ r.sent_mails }} / {{ r.total_mails }}
+
@@ -95,4 +96,4 @@
{% endif %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html
index 81241b5629..22d707c3ed 100644
--- a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html
+++ b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html
@@ -10,8 +10,21 @@
{% csrf_token %}
{% bootstrap_form_errors form %}
- {% bootstrap_field form.enabled layout='control' %}
+ {% if rule.total_mails == rule.sent_mails %}
+
+ {% if event.has_subevents %}
+ {% trans "This email has already been sent for all existing dates. Changing it will have no effect unless you create additional dates in this event series." %}
+ {% else %}
+ {% trans "This email has already been sent. Changing it will have no effect." %}
+ {% endif %}
+
+ {% elif rule.total_mails > 0 and event.has_subevents %}
+
+ {% trans "This email has already been sent for some of the dates in your series. Changing it will only have an effect on dates for which the email has not yet been sent." %}
+
+ {% endif %}
+ {% bootstrap_field form.enabled layout='control' %}
{% trans "Content" %}
{% bootstrap_field form.subject layout='control' %}
@@ -63,4 +76,4 @@
{% endblock %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/src/pretix/plugins/sendmail/urls.py b/src/pretix/plugins/sendmail/urls.py
index e9266f301c..ae58d2be95 100644
--- a/src/pretix/plugins/sendmail/urls.py
+++ b/src/pretix/plugins/sendmail/urls.py
@@ -46,6 +46,9 @@ urlpatterns = [
name='history'),
re_path(r'^control/event/(?P[^/]+)/(?P[^/]+)/sendmail/rules/create', views.CreateRule.as_view(),
name='rule.create'),
+ re_path(r'^control/event/(?P[^/]+)/(?P[^/]+)/sendmail/rules/(?P[^/]+)/schedule',
+ views.ScheduleView.as_view(),
+ name='rule.schedule'),
re_path(r'^control/event/(?P[^/]+)/(?P[^/]+)/sendmail/rules/(?P[^/]+)/delete',
views.DeleteRule.as_view(),
name='rule.delete'),
diff --git a/src/pretix/plugins/sendmail/views.py b/src/pretix/plugins/sendmail/views.py
index ac8065db02..6cd296edf1 100644
--- a/src/pretix/plugins/sendmail/views.py
+++ b/src/pretix/plugins/sendmail/views.py
@@ -43,6 +43,7 @@ from django.db.models import Count, Exists, Max, Min, OuterRef, Q
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
+from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django.views.generic import DeleteView, FormView, ListView
@@ -385,7 +386,14 @@ class UpdateRule(EventPermissionRequiredMixin, UpdateView):
permission = 'can_change_event_settings'
def get_object(self, queryset=None) -> Rule:
- return get_object_or_404(Rule, event=self.request.event, id=self.kwargs['rule'])
+ return get_object_or_404(
+ Rule.objects.annotate(
+ total_mails=Count('scheduledmail'),
+ sent_mails=Count('scheduledmail', filter=Q(scheduledmail__state=ScheduledMail.STATE_COMPLETED)),
+ ),
+ event=self.request.event,
+ id=self.kwargs['rule']
+ )
def get_success_url(self):
return reverse('plugins:sendmail:rule.update', kwargs={
@@ -485,3 +493,23 @@ class DeleteRule(EventPermissionRequiredMixin, DeleteView):
self.object.delete()
messages.success(self.request, _('The selected rule has been deleted.'))
return HttpResponseRedirect(success_url)
+
+
+class ScheduleView(EventPermissionRequiredMixin, PaginationMixin, ListView):
+ template_name = 'pretixplugins/sendmail/rule_inspect.html'
+ model = ScheduledMail
+ context_object_name = 'scheduled_mails'
+
+ @cached_property
+ def rule(self):
+ return get_object_or_404(Rule, event=self.request.event, id=self.kwargs['rule'])
+
+ def get_queryset(self):
+ return self.rule.scheduledmail_set.select_related('subevent').order_by(
+ '-computed_datetime'
+ )
+
+ def get_context_data(self, **kwargs):
+ ctx = super().get_context_data(**kwargs)
+ ctx['rule'] = self.rule
+ return ctx