diff --git a/src/pretix/locale/de_Informal/LC_MESSAGES/django.po b/src/pretix/locale/de_Informal/LC_MESSAGES/django.po
index 595707394..c28e158bb 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 859603d03..4b8c4dafc 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 000000000..61d7fc480
--- /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 e7b9d7be1..a6138e96d 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 81241b562..22d707c3e 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 e9266f301..ae58d2be9 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 ac8065db0..6cd296edf 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