Check-in: New flags for check-in lists (#3577)

This commit is contained in:
Raphael Michel
2023-10-23 15:52:06 +02:00
committed by GitHub
parent da9aa3e133
commit a0831890ad
14 changed files with 82 additions and 13 deletions

View File

@@ -38,7 +38,7 @@ class CheckinListSerializer(I18nAwareModelSerializer):
model = CheckinList
fields = ('id', 'name', 'all_products', 'limit_products', 'subevent', 'checkin_count', 'position_count',
'include_pending', 'auto_checkin_sales_channels', 'allow_multiple_entries', 'allow_entry_after_exit',
'rules', 'exit_all_at', 'addon_match')
'rules', 'exit_all_at', 'addon_match', 'ignore_in_statistics', 'consider_tickets_used')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View File

@@ -0,0 +1,22 @@
# Generated by Django 4.2.4 on 2023-09-06 11:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("pretixbase", "0246_bigint"),
]
operations = [
migrations.AddField(
model_name="checkinlist",
name="consider_tickets_used",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="checkinlist",
name="ignore_in_statistics",
field=models.BooleanField(default=False),
),
]

View File

@@ -62,6 +62,16 @@ class CheckinList(LoggedModel):
'and valid for check-in regardless of which date they are purchased for. '
'You can limit their validity through the advanced check-in rules, '
'though.'))
ignore_in_statistics = models.BooleanField(
verbose_name=pgettext_lazy('checkin', 'Ignore check-ins on this list in statistics'),
default=False
)
consider_tickets_used = models.BooleanField(
verbose_name=pgettext_lazy('checkin', 'Tickets with a check-in on this list should be considered "used"'),
help_text=_('This is relevant in various situations, e.g. for deciding if a ticket can still be canceled by '
'the customer.'),
default=True
)
include_pending = models.BooleanField(verbose_name=pgettext_lazy('checkin', 'Include pending orders'),
default=False,
help_text=_('With this option, people will be able to check in even if the '

View File

@@ -633,7 +633,7 @@ class Order(LockModel, LoggedModel):
positions = list(
self.positions.all().annotate(
has_variations=Exists(ItemVariation.objects.filter(item_id=OuterRef('item_id'))),
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk')))
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True))
).select_related('item').prefetch_related('issued_gift_cards')
)
if self.event.settings.change_allow_user_if_checked_in:
@@ -665,7 +665,7 @@ class Order(LockModel, LoggedModel):
return False
positions = list(
self.positions.all().annotate(
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk')))
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True))
).select_related('item').prefetch_related('issued_gift_cards')
)
cancelable = all([op.item.allow_cancel and not op.has_checkin and not op.blocked for op in positions])
@@ -820,7 +820,7 @@ class Order(LockModel, LoggedModel):
positions = list(
self.positions.all().annotate(
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk')))
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True))
).select_related('item').prefetch_related('item__questions')
)
if not self.event.settings.allow_modifications_after_checkin:

View File

@@ -1996,7 +1996,7 @@ class OrderChangeManager:
for a in current_addons[cp][k][:current_num - input_num]:
if a.canceled:
continue
if a.checkins.exists():
if a.checkins.filter(list__consider_tickets_used=True).exists():
raise OrderError(
error_messages['addon_already_checked_in'] % {
'addon': str(a.item.name),

View File

@@ -2072,7 +2072,8 @@ class VoucherFilterForm(FilterForm):
qs = qs.filter(Q(valid_until__isnull=False) & Q(valid_until__lt=now())).filter(redeemed=0)
elif s == 'c':
checkins = Checkin.objects.filter(
position__voucher=OuterRef('pk')
position__voucher=OuterRef('pk'),
list__consider_tickets_used=True,
)
qs = qs.annotate(has_checkin=Exists(checkins)).filter(
redeemed__gt=0, has_checkin=True

View File

@@ -390,7 +390,7 @@
{% elif c.auto_checked_in %}
<span class="fa fa-fw fa-magic text-success" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% else %}
<span class="fa fa-fw fa-check text-success" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
<span class="fa fa-fw fa-check {% if c.list.consider_tickets_used %}text-success{% else %}text-muted{% endif %}" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% endif %}
{% endfor %}
{% endif %}

View File

@@ -133,10 +133,10 @@ class ScheduledMail(models.Model):
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'))))
op_qs = op_qs.filter(~Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True)))
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'))))
op_qs = op_qs.filter(Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True)))
status_q = Q(status__in=self.rule.restrict_to_status)
if 'n__pending_approval' in self.rule.restrict_to_status:

View File

@@ -67,6 +67,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
any_checkins=Exists(
Checkin.objects.filter(
Q(position_id=OuterRef('pk')) | Q(position__addon_to_id=OuterRef('pk')),
list__consider_tickets_used=True,
)
),
matching_checkins=Exists(

View File

@@ -373,7 +373,8 @@ class OrderSendView(BaseSenderView):
any_checkins=Exists(
Checkin.all.filter(
Q(position_id=OuterRef('pk')) | Q(position__addon_to_id=OuterRef('pk')),
successful=True
successful=True,
list__consider_tickets_used=True,
)
)
)

View File

@@ -246,7 +246,10 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin,
qs = qs.annotate(
checkin_count=Subquery(
Checkin.objects.filter(
successful=True, type=Checkin.TYPE_ENTRY, position_id=OuterRef('pk')
successful=True,
type=Checkin.TYPE_ENTRY,
position_id=OuterRef('pk'),
list__consider_tickets_used=True,
).order_by().values('position').annotate(c=Count('*')).values('c')
)
)
@@ -358,7 +361,10 @@ class OrderPositionDetails(EventViewMixin, OrderPositionDetailMixin, CartMixin,
qs = qs.annotate(
checkin_count=Subquery(
Checkin.objects.filter(
successful=True, type=Checkin.TYPE_ENTRY, position_id=OuterRef('pk')
successful=True,
type=Checkin.TYPE_ENTRY,
position_id=OuterRef('pk'),
list__consider_tickets_used=True,
).order_by().values('position').annotate(c=Count('*')).values('c')
)
)