forked from CGM_Public/pretix_original
Allow users to see the number of checkins (#2561)
Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
@@ -1195,7 +1195,20 @@ DEFAULTS = {
|
|||||||
help_text=_("If you ask for a phone number, explain why you do so and what you will use the phone number for.")
|
help_text=_("If you ask for a phone number, explain why you do so and what you will use the phone number for.")
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
'show_checkin_number_user': {
|
||||||
|
'default': 'False',
|
||||||
|
'type': bool,
|
||||||
|
'serializer_class': serializers.BooleanField,
|
||||||
|
'form_class': forms.BooleanField,
|
||||||
|
'form_kwargs': dict(
|
||||||
|
label=_("Show number of check-ins to customer"),
|
||||||
|
help_text=_('With this option enabled, your customers will be able how many times they entered '
|
||||||
|
'the event. This is usually not necessary, but might be useful in combination with tickets '
|
||||||
|
'that are usable a specific number of times, so customers can see how many times they have '
|
||||||
|
'already been used. Exits or failed scans will not be counted, and the user will not see '
|
||||||
|
'the different check-in lists.'),
|
||||||
|
)
|
||||||
|
},
|
||||||
'ticket_download': {
|
'ticket_download': {
|
||||||
'default': 'False',
|
'default': 'False',
|
||||||
'type': bool,
|
'type': bool,
|
||||||
|
|||||||
@@ -523,6 +523,7 @@ class EventSettingsForm(SettingsForm):
|
|||||||
'last_order_modification_date',
|
'last_order_modification_date',
|
||||||
'allow_modifications_after_checkin',
|
'allow_modifications_after_checkin',
|
||||||
'checkout_show_copy_answers_button',
|
'checkout_show_copy_answers_button',
|
||||||
|
'show_checkin_number_user',
|
||||||
'primary_color',
|
'primary_color',
|
||||||
'theme_color_success',
|
'theme_color_success',
|
||||||
'theme_color_danger',
|
'theme_color_danger',
|
||||||
|
|||||||
@@ -221,6 +221,7 @@
|
|||||||
{% bootstrap_field sform.show_items_outside_presale_period layout="control" %}
|
{% bootstrap_field sform.show_items_outside_presale_period layout="control" %}
|
||||||
{% bootstrap_field sform.last_order_modification_date layout="control" %}
|
{% bootstrap_field sform.last_order_modification_date layout="control" %}
|
||||||
{% bootstrap_field sform.allow_modifications_after_checkin layout="control" %}
|
{% bootstrap_field sform.allow_modifications_after_checkin layout="control" %}
|
||||||
|
{% bootstrap_field sform.show_checkin_number_user layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Display" %}</legend>
|
<legend>{% trans "Display" %}</legend>
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
</p>
|
</p>
|
||||||
{% if line.seat or line.voucher or line.subevent or line.used_membership%}
|
{% if line.seat or line.voucher or line.subevent or line.used_membership%}
|
||||||
<dl class="dl-inline">
|
<dl class="dl-inline">
|
||||||
|
{% elif event.settings.show_checkin_number_user and line.checkin_count %}
|
||||||
|
<dl class="dl-inline">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if line.seat %}
|
{% if line.seat %}
|
||||||
<div class="cart-icon-details">
|
<div class="cart-icon-details">
|
||||||
@@ -94,8 +96,25 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if event.settings.show_checkin_number_user and line.checkin_count %}
|
||||||
|
<div class="cart-icon-details">
|
||||||
|
<dt class="sr-only">{% trans "Usage:" context "ticket_checkins" %}</dt>
|
||||||
|
<dd class="text-success">
|
||||||
|
<span class="fa fa-check-circle fa-fw text-success" aria-hidden="true"></span>
|
||||||
|
<strong>
|
||||||
|
{% blocktrans trimmed count count=line.checkin_count %}
|
||||||
|
This ticket has been used once.
|
||||||
|
{% plural %}
|
||||||
|
This ticket has been used {{ count }} times.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</strong>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if line.seat or line.voucher or line.subevent or line.used_membership%}
|
{% if line.seat or line.voucher or line.subevent or line.used_membership%}
|
||||||
</dl>
|
</dl>
|
||||||
|
{% elif event.settings.show_checkin_number_user and line.checkin_count %}
|
||||||
|
</dl>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if line.issued_gift_cards.exists %}
|
{% if line.issued_gift_cards.exists %}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ from django.contrib import messages
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Exists, OuterRef, Q, Sum
|
from django.db.models import Count, Exists, OuterRef, Q, Subquery, Sum
|
||||||
from django.http import (
|
from django.http import (
|
||||||
FileResponse, Http404, HttpResponseRedirect, JsonResponse,
|
FileResponse, Http404, HttpResponseRedirect, JsonResponse,
|
||||||
)
|
)
|
||||||
@@ -60,7 +60,8 @@ from django.views.decorators.clickjacking import xframe_options_exempt
|
|||||||
from django.views.generic import TemplateView, View
|
from django.views.generic import TemplateView, View
|
||||||
|
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CachedTicket, GiftCard, Invoice, Order, OrderPosition, Quota, TaxRule,
|
CachedTicket, Checkin, GiftCard, Invoice, Order, OrderPosition, Quota,
|
||||||
|
TaxRule,
|
||||||
)
|
)
|
||||||
from pretix.base.models.orders import (
|
from pretix.base.models.orders import (
|
||||||
CachedCombinedTicket, InvoiceAddress, OrderFee, OrderPayment, OrderRefund,
|
CachedCombinedTicket, InvoiceAddress, OrderFee, OrderPayment, OrderRefund,
|
||||||
@@ -124,12 +125,13 @@ class OrderDetailMixin(NoSearchIndexViewMixin):
|
|||||||
class OrderPositionDetailMixin(NoSearchIndexViewMixin):
|
class OrderPositionDetailMixin(NoSearchIndexViewMixin):
|
||||||
@cached_property
|
@cached_property
|
||||||
def position(self):
|
def position(self):
|
||||||
p = OrderPosition.objects.filter(
|
qs = OrderPosition.objects.filter(
|
||||||
order__event=self.request.event,
|
order__event=self.request.event,
|
||||||
addon_to__isnull=True,
|
addon_to__isnull=True,
|
||||||
order__code=self.kwargs['order'],
|
order__code=self.kwargs['order'],
|
||||||
positionid=self.kwargs['position']
|
positionid=self.kwargs['position']
|
||||||
).select_related('order', 'order__event').first()
|
).select_related('order', 'order__event')
|
||||||
|
p = qs.first()
|
||||||
if p:
|
if p:
|
||||||
if p.web_secret.lower() == self.kwargs['secret'].lower():
|
if p.web_secret.lower() == self.kwargs['secret'].lower():
|
||||||
return p
|
return p
|
||||||
@@ -229,9 +231,21 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin,
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
qs = self.order.positions.prefetch_related('issued_gift_cards').select_related('tax_rule')
|
||||||
|
if self.request.event.settings.show_checkin_number_user:
|
||||||
|
qs = qs.annotate(
|
||||||
|
checkin_count=Subquery(
|
||||||
|
Checkin.objects.filter(
|
||||||
|
successful=True, type=Checkin.TYPE_ENTRY, position_id=OuterRef('pk')
|
||||||
|
).order_by().values('position').annotate(c=Count('*')).values('c')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
ctx['cart'] = self.get_cart(
|
ctx['cart'] = self.get_cart(
|
||||||
answers=True, downloads=ctx['can_download'],
|
answers=True,
|
||||||
queryset=self.order.positions.prefetch_related('issued_gift_cards').select_related('tax_rule'),
|
downloads=ctx['can_download'],
|
||||||
|
queryset=qs,
|
||||||
order=self.order
|
order=self.order
|
||||||
)
|
)
|
||||||
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p.generate_ticket]
|
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p.generate_ticket]
|
||||||
@@ -328,14 +342,23 @@ class OrderPositionDetails(EventViewMixin, OrderPositionDetailMixin, CartMixin,
|
|||||||
return buttons
|
return buttons
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
qs = self.order.positions.select_related('tax_rule').filter(
|
||||||
|
Q(pk=self.position.pk) | Q(addon_to__id=self.position.pk)
|
||||||
|
)
|
||||||
|
if self.request.event.settings.show_checkin_number_user:
|
||||||
|
qs = qs.annotate(
|
||||||
|
checkin_count=Subquery(
|
||||||
|
Checkin.objects.filter(
|
||||||
|
successful=True, type=Checkin.TYPE_ENTRY, position_id=OuterRef('pk')
|
||||||
|
).order_by().values('position').annotate(c=Count('*')).values('c')
|
||||||
|
)
|
||||||
|
)
|
||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
ctx['can_download_multi'] = False
|
ctx['can_download_multi'] = False
|
||||||
ctx['position'] = self.position
|
ctx['position'] = self.position
|
||||||
ctx['cart'] = self.get_cart(
|
ctx['cart'] = self.get_cart(
|
||||||
answers=True, downloads=ctx['can_download'],
|
answers=True, downloads=ctx['can_download'],
|
||||||
queryset=self.order.positions.select_related('tax_rule').filter(
|
queryset=qs,
|
||||||
Q(pk=self.position.pk) | Q(addon_to__id=self.position.pk)
|
|
||||||
),
|
|
||||||
order=self.order
|
order=self.order
|
||||||
)
|
)
|
||||||
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p.generate_ticket]
|
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p.generate_ticket]
|
||||||
|
|||||||
Reference in New Issue
Block a user