Automated emails: Extend filter by check-in state (#3489)

Co-authored-by: Richard Schreiber <schreiber@rami.io>
Co-authored-by: Raphael Michel <michel@rami.io>
This commit is contained in:
Phin Wolkwitz
2023-08-23 16:19:27 +02:00
committed by GitHub
parent c2b25bad06
commit 4baf317934
9 changed files with 220 additions and 14 deletions

View File

@@ -34,7 +34,7 @@ class RuleSerializer(I18nAwareModelSerializer):
class Meta:
model = Rule
fields = ['id', 'subject', 'template', 'all_products', 'limit_products', 'restrict_to_status',
'send_date', 'send_offset_days', 'send_offset_time', 'date_is_absolute',
'checked_in_status', 'send_date', 'send_offset_days', 'send_offset_time', 'date_is_absolute',
'offset_to_event_end', 'offset_is_after', 'send_to', 'enabled']
read_only_fields = ['id']
@@ -88,6 +88,10 @@ class RuleSerializer(I18nAwareModelSerializer):
]:
raise ValidationError(f'status {s} not allowed: restrict_to_status may only include valid states')
if full_data.get('checked_in_status') == "":
# even though "blank" is not allowed on this field, "" gets accepted without this check
raise ValidationError('empty string not allowed: use null to disable check-in based filtering')
return full_data
def save(self, **kwargs):

View File

@@ -312,7 +312,7 @@ class RuleForm(FormPlaceholderMixin, I18nModelForm):
fields = ['subject', 'template', 'attach_ical',
'send_date', 'send_offset_days', 'send_offset_time',
'all_products', 'limit_products', 'restrict_to_status',
'send_to', 'enabled']
'checked_in_status', 'send_to', 'enabled']
field_classes = {
'subevent': SafeModelMultipleChoiceField,
@@ -337,6 +337,7 @@ class RuleForm(FormPlaceholderMixin, I18nModelForm):
'data-inverse-dependency': '#id_all_products'},
),
'send_to': forms.RadioSelect,
'checked_in_status': forms.RadioSelect,
}
def __init__(self, *args, **kwargs):

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.19 on 2023-08-09 11:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sendmail', '0004_rule_restrict_to_status'),
]
operations = [
migrations.AddField(
model_name='rule',
name='checked_in_status',
field=models.CharField(max_length=10, null=True),
),
]

View File

@@ -34,7 +34,8 @@ from i18nfield.fields import I18nCharField, I18nTextField
from pretix.base.email import get_email_context
from pretix.base.i18n import language
from pretix.base.models import (
Event, InvoiceAddress, Item, Order, OrderPosition, SubEvent, fields,
Checkin, Event, InvoiceAddress, Item, Order, OrderPosition, SubEvent,
fields,
)
from pretix.base.models.base import LoggingMixin
from pretix.base.services.mail import SendMailException
@@ -112,19 +113,30 @@ class ScheduledMail(models.Model):
e = self.event
orders = e.orders.all()
limit_products = self.rule.limit_products.values_list('pk', flat=True) if not self.rule.all_products else None
filter_orders_by_op = False
op_qs = OrderPosition.objects.filter(
order__event=self.event,
canceled=False,
)
if self.subevent:
orders = orders.filter(
Exists(OrderPosition.objects.filter(order=OuterRef('pk'), subevent=self.subevent))
)
filter_orders_by_op = True
op_qs = op_qs.filter(subevent=self.subevent)
elif e.has_subevents:
return # This rule should not even exist
if not self.rule.all_products:
orders = orders.filter(
Exists(OrderPosition.objects.filter(order=OuterRef('pk'), item_id__in=limit_products))
)
filter_orders_by_op = True
limit_products = self.rule.limit_products.values_list('pk', flat=True)
op_qs = op_qs.filter(item_id__in=limit_products)
if self.rule.checked_in_status == "no_checkin":
filter_orders_by_op = True
op_qs = op_qs.filter(~Exists(Checkin.objects.filter(position_id=OuterRef('pk'))))
elif self.rule.checked_in_status == "checked_in":
filter_orders_by_op = True
op_qs = op_qs.filter(Exists(Checkin.objects.filter(position_id=OuterRef('pk'))))
status_q = Q(status__in=self.rule.restrict_to_status)
if 'n__pending_approval' in self.rule.restrict_to_status:
@@ -142,6 +154,8 @@ class ScheduledMail(models.Model):
pk__gt=self.last_successful_order_id
)
if filter_orders_by_op:
orders = orders.filter(pk__in=op_qs.values_list('order_id', flat=True))
orders = orders.filter(
status_q,
).order_by('pk').select_related('invoice_address').prefetch_related('positions')
@@ -205,6 +219,12 @@ class Rule(models.Model, LoggingMixin):
(BOTH, _('Both (all order contact addresses and all attendee email addresses)'))
]
CHECK_IN_STATUS_CHOICES = [
(None, _("Everyone")),
("checked_in", _("Anyone who is or was checked in")),
("no_checkin", _("Anyone who never checked in before"))
]
id = models.BigAutoField(primary_key=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='sendmail_rules')
@@ -219,6 +239,15 @@ class Rule(models.Model, LoggingMixin):
default=['p', 'n__valid_if_pending'],
)
checked_in_status = models.CharField(
verbose_name=_("Restrict to check-in status"),
default=None,
choices=CHECK_IN_STATUS_CHOICES,
max_length=10,
null=True,
blank=True,
)
attach_ical = models.BooleanField(
default=False,
verbose_name=_("Attach calendar files"),

View File

@@ -28,6 +28,8 @@
<legend>{% trans "Recipients" %}</legend>
{% bootstrap_field form.send_to layout='control' %}
{% bootstrap_field form.restrict_to_status layout='control' %}
{% bootstrap_field form.checked_in_status layout='control' %}
<hr>
{% bootstrap_field form.all_products layout='control' %}
{% bootstrap_field form.limit_products layout='horizontal' %}
</fieldset>

View File

@@ -42,6 +42,8 @@
<legend>{% trans "Recipients" %}</legend>
{% bootstrap_field form.send_to layout='control' %}
{% bootstrap_field form.restrict_to_status layout='control' %}
{% bootstrap_field form.checked_in_status layout='control' %}
<hr>
{% bootstrap_field form.all_products layout='control' %}
{% bootstrap_field form.limit_products layout='horizontal' %}
</fieldset>