forked from CGM_Public/pretix_original
* add checkin status page add dashboard widget add checkin page under orders * modify checkin logic added new fields in checkin page added filter items * add tests for checkins & minor improvement * support addin_product & noadm setting logic * remove name ordering check test case
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% load urlreplace %}
|
||||
{% block title %}{% trans "Check-ins" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Check-ins" %}</h1>
|
||||
<p>
|
||||
<form class="form-inline helper-display-inline" action="" method="get">
|
||||
<select name="status" class="form-control">
|
||||
<option value="">{% trans "All status" %}</option>
|
||||
<option value="1" {% if request.GET.status == "1" %}selected="selected"{% endif %}>{% trans "Checked in" %}</option>
|
||||
<option value="0" {% if request.GET.status == "0" %}selected="selected"{% endif %}>{% trans "Not checked in" %}</option>
|
||||
</select>
|
||||
<select name="item" class="form-control">
|
||||
<option value="">{% trans "All products" %}</option>
|
||||
{% for item in items %}
|
||||
<option value="{{ item.id }}"
|
||||
{% if request.GET.item|add:0 == item.id %}selected="selected"{% endif %}>
|
||||
{{ item.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="text" name="user" class="form-control" placeholder="{% trans "Search user" %}" value="{{ request.GET.user }}">
|
||||
<button class="btn btn-primary" type="submit">{% trans "Filter" %}</button>
|
||||
</form>
|
||||
</p>
|
||||
{% if entries|length == 0 %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
No check-in record was found.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Order code" %} <a href="?{% url_replace request 'ordering' '-code'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'code'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
<th>{% trans "Item" %} <a href="?{% url_replace request 'ordering' '-item'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'item'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
<th>{% trans "Email" %} <a href="?{% url_replace request 'ordering' '-email'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'email'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
<th>{% trans "Name" %} <a href="?{% url_replace request 'ordering' '-name'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'name'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
<th>{% trans "Status" %} <a href="?{% url_replace request 'ordering' '-status'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'status'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
<th>{% trans "Timestamp" %} <a href="?{% url_replace request 'ordering' '-timestamp'%}"><i class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'timestamp'%}"><i class="fa fa-caret-up"></i></a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for e in entries %}
|
||||
{% with e.checkins.first as checkin %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong><a href="{% url "control:event.order" event=request.event.slug organizer=request.event.organizer.slug code=e.order.code %}"
|
||||
>{{ e.order.code }}</a></strong>
|
||||
</td>
|
||||
<td>{{ e.item.name }}</td>
|
||||
<td>{{ e.order.email }}</td>
|
||||
<td>
|
||||
{% if e.addon_to %}
|
||||
{{ e.addon_to.attendee_name }}
|
||||
{% elif e.attendee_name %}
|
||||
{{ e.attendee_name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if not checkin %}
|
||||
<span class="label label-danger">{% trans "Not checked in" %}</span>
|
||||
{% else %}
|
||||
<span class="label label-success">{% trans "Checked in" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if checkin %}
|
||||
{{ checkin.datetime|date:"SHORT_DATETIME_FORMAT" }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -90,6 +90,12 @@
|
||||
{% trans "Waiting list" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'control:event.orders.checkins' organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
{% if url_name == "event.orders.checkins" %}class="active"{% endif %}>
|
||||
{% trans "Check-ins" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from pretix.control.views import (
|
||||
auth, dashboards, event, global_settings, item, main, orders, organizer,
|
||||
user, vouchers, waitinglist,
|
||||
auth, checkin, dashboards, event, global_settings, item, main, orders,
|
||||
organizer, user, vouchers, waitinglist,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
@@ -138,5 +138,6 @@ urlpatterns = [
|
||||
url(r'^orders/$', orders.OrderList.as_view(), name='event.orders'),
|
||||
url(r'^waitinglist/$', waitinglist.WaitingListView.as_view(), name='event.orders.waitinglist'),
|
||||
url(r'^waitinglist/auto_assign$', waitinglist.AutoAssign.as_view(), name='event.orders.waitinglist.auto'),
|
||||
url(r'^checkins/$', checkin.CheckInView.as_view(), name='event.orders.checkins'),
|
||||
])),
|
||||
]
|
||||
|
||||
79
src/pretix/control/views/checkin.py
Normal file
79
src/pretix/control/views/checkin.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from django.db.models import Prefetch, Q
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.views.generic import ListView
|
||||
|
||||
from pretix.base.models import Checkin, Item, OrderPosition
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
|
||||
|
||||
class CheckInView(EventPermissionRequiredMixin, ListView):
|
||||
model = Checkin
|
||||
context_object_name = 'entries'
|
||||
paginate_by = 30
|
||||
template_name = 'pretixcontrol/checkin/index.html'
|
||||
permission = 'can_view_orders'
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
qs = OrderPosition.objects.filter(order__event=self.request.event, order__status='p')
|
||||
|
||||
# if this setting is False, we check only items for admission
|
||||
if not self.request.event.settings.ticket_download_nonadm:
|
||||
qs = qs.filter(item__admission=True)
|
||||
|
||||
if self.request.GET.get("status", "") != "":
|
||||
p = self.request.GET.get("status", "")
|
||||
if p == '1':
|
||||
# records with check-in record
|
||||
qs = qs.filter(checkins__isnull=False)
|
||||
elif p == '0':
|
||||
qs = qs.filter(checkins__isnull=True)
|
||||
|
||||
if self.request.GET.get("user", "") != "":
|
||||
u = self.request.GET.get("user", "")
|
||||
qs = qs.filter(
|
||||
Q(order__email__icontains=u) | Q(attendee_name__icontains=u) | Q(attendee_email__icontains=u)
|
||||
)
|
||||
|
||||
if self.request.GET.get("item", "") != "":
|
||||
u = self.request.GET.get("item", "")
|
||||
qs = qs.filter(item_id__in=(u,))
|
||||
|
||||
qs = qs.prefetch_related(
|
||||
Prefetch('checkins', queryset=Checkin.objects.filter(position__order__event=self.request.event))
|
||||
).select_related('order', 'item', 'addon_to')
|
||||
|
||||
if self.request.GET.get("ordering", "") != "":
|
||||
p = self.request.GET.get("ordering", "")
|
||||
keys_allowed = self.get_ordering_keys_mappings()
|
||||
if p in keys_allowed:
|
||||
mapped_field = keys_allowed[p]
|
||||
if type(mapped_field) is tuple:
|
||||
qs = qs.annotate(**mapped_field[1]).order_by(mapped_field[0])
|
||||
else:
|
||||
qs = qs.order_by(mapped_field)
|
||||
|
||||
return qs.distinct()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['items'] = Item.objects.filter(event=self.request.event)
|
||||
ctx['filtered'] = ("status" in self.request.GET or "user" in self.request.GET or "item" in self.request.GET)
|
||||
return ctx
|
||||
|
||||
@staticmethod
|
||||
def get_ordering_keys_mappings():
|
||||
return {
|
||||
'code': 'order__code',
|
||||
'-code': '-order__code',
|
||||
'email': 'order__email',
|
||||
'-email': '-order__email',
|
||||
'status': 'checkins__id',
|
||||
'-status': '-checkins__id',
|
||||
'timestamp': 'checkins__datetime',
|
||||
'-timestamp': '-checkins__datetime',
|
||||
'item': 'item__name',
|
||||
'-item': '-item__name',
|
||||
'name': ('display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
|
||||
'-name': ('-display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
|
||||
}
|
||||
@@ -168,6 +168,27 @@ def shop_state_widget(sender, **kwargs):
|
||||
}]
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def checkin_widget(sender, **kwargs):
|
||||
size_qs = OrderPosition.objects.filter(order__event=sender, order__status='p')
|
||||
checked_qs = OrderPosition.objects.filter(order__event=sender, order__status='p', checkins__isnull=False)
|
||||
|
||||
# if this setting is False, we check only items for admission
|
||||
if not sender.settings.ticket_download_nonadm:
|
||||
size_qs = size_qs.filter(item__admission=True)
|
||||
checked_qs = checked_qs.filter(item__admission=True)
|
||||
|
||||
return [{
|
||||
'content': NUM_WIDGET.format(num='{}/{}'.format(checked_qs.count(), size_qs.count()), text=_('Checked in')),
|
||||
'display_size': 'small',
|
||||
'priority': 50,
|
||||
'url': reverse('control:event.orders.checkins', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
})
|
||||
}]
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def welcome_wizard_widget(sender, **kwargs):
|
||||
template = get_template('pretixcontrol/event/dashboard_widget_welcome.html')
|
||||
|
||||
375
src/tests/control/test_checkins.py
Normal file
375
src/tests/control/test_checkins.py
Normal file
@@ -0,0 +1,375 @@
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import (
|
||||
Checkin, Event, Item, ItemAddOn, ItemCategory, Order, OrderPosition,
|
||||
Organizer, Team, User,
|
||||
)
|
||||
from pretix.control.views.dashboards import checkin_widget
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashboard_env():
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,tests.testdummy'
|
||||
)
|
||||
event.settings.set('ticketoutput_testdummy__enabled', True)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True)
|
||||
item_mascot = Item.objects.create(event=event, name="Mascot", default_price=10, admission=False)
|
||||
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
event.settings.set('attendee_names_asked', True)
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
|
||||
order_paid = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=33, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=order_paid,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="Peter"
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=order_paid,
|
||||
item=item_mascot,
|
||||
variation=None,
|
||||
price=Decimal("10")
|
||||
)
|
||||
|
||||
return event, user, o, order_paid, item_ticket, item_mascot
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard(dashboard_env):
|
||||
c = checkin_widget(dashboard_env[0])
|
||||
assert '0/2' in c[0]['content']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard_pending_not_count(dashboard_env):
|
||||
c = checkin_widget(dashboard_env[0])
|
||||
order_pending = Order.objects.create(
|
||||
code='FOO', event=dashboard_env[0], email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=order_pending,
|
||||
item=dashboard_env[4],
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="NotPaid"
|
||||
)
|
||||
assert '0/2' in c[0]['content']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard_with_checkin(dashboard_env):
|
||||
op = OrderPosition.objects.get(
|
||||
order=dashboard_env[3],
|
||||
item=dashboard_env[4]
|
||||
)
|
||||
Checkin.objects.create(position=op)
|
||||
c = checkin_widget(dashboard_env[0])
|
||||
assert '1/2' in c[0]['content']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard_exclude_non_admission_item(dashboard_env):
|
||||
dashboard_env[0].settings.ticket_download_nonadm = False
|
||||
dashboard_env[0].save()
|
||||
c = checkin_widget(dashboard_env[0])
|
||||
assert '0/1' in c[0]['content']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard_exclude_non_admission_item_with_checkin(dashboard_env):
|
||||
dashboard_env[0].settings.ticket_download_nonadm = False
|
||||
dashboard_env[0].save()
|
||||
op = OrderPosition.objects.get(
|
||||
order=dashboard_env[3],
|
||||
item=dashboard_env[4]
|
||||
)
|
||||
Checkin.objects.create(position=op)
|
||||
c = checkin_widget(dashboard_env[0])
|
||||
assert '1/1' in c[0]['content']
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def checkin_list_env():
|
||||
# permission
|
||||
orga = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
team = Team.objects.create(organizer=orga, can_view_orders=True, can_change_orders=True)
|
||||
team.members.add(user)
|
||||
|
||||
# event
|
||||
event = Event.objects.create(
|
||||
organizer=orga, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,tests.testdummy'
|
||||
)
|
||||
event.settings.set('ticketoutput_testdummy__enabled', True)
|
||||
event.settings.set('attendee_names_asked', True)
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
team.limit_events.add(event)
|
||||
|
||||
# item
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True)
|
||||
item_mascot = Item.objects.create(event=event, name="Mascot", default_price=10, admission=False)
|
||||
|
||||
# order
|
||||
order_pending = Order.objects.create(
|
||||
code='PENDING', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
order_a1 = Order.objects.create(
|
||||
code='A1', event=event, email='a1dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=33, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
order_a2 = Order.objects.create(
|
||||
code='A2', event=event, email='a2dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
order_a3 = Order.objects.create(
|
||||
code='A3', event=event, email='a3dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
|
||||
# order position
|
||||
op_pending_ticket = OrderPosition.objects.create(
|
||||
order=order_pending,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="Pending"
|
||||
)
|
||||
op_a1_ticket = OrderPosition.objects.create(
|
||||
order=order_a1,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="A1"
|
||||
)
|
||||
op_a1_mascot = OrderPosition.objects.create(
|
||||
order=order_a1,
|
||||
item=item_mascot,
|
||||
variation=None,
|
||||
price=Decimal("10")
|
||||
)
|
||||
op_a2_ticket = OrderPosition.objects.create(
|
||||
order=order_a2,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="A2"
|
||||
)
|
||||
op_a3_ticket = OrderPosition.objects.create(
|
||||
order=order_a3,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="a4", # a3 attendee is a4
|
||||
attendee_email="a3company@dummy.test"
|
||||
)
|
||||
|
||||
# checkin
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1))
|
||||
Checkin.objects.create(position=op_a3_ticket)
|
||||
|
||||
return event, user, orga, [item_ticket, item_mascot], [order_pending, order_a1, order_a2, order_a3], \
|
||||
[op_pending_ticket, op_a1_ticket, op_a1_mascot, op_a2_ticket, op_a3_ticket]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("order_key, expected", [
|
||||
('', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('-code', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
|
||||
('code', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('-email', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
|
||||
('email', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
# ('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
|
||||
# ('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
|
||||
# ('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
|
||||
# ('timestamp', ['A1Mascot', 'A2Ticket', 'A3Ticket', 'A1Ticket']),
|
||||
# ('-name', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
|
||||
# ('name', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']), # mascot doesn't include attendee name
|
||||
('-item', ['A1Ticket', 'A2Ticket', 'A3Ticket', 'A1Mascot']),
|
||||
('item', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']),
|
||||
])
|
||||
def test_checkins_list_ordering(client, checkin_list_env, order_key, expected):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/checkins/?ordering=' + order_key)
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) for q in qs]
|
||||
assert item_keys == expected
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("query, expected", [
|
||||
('status=&item=&user=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('status=1&item=&user=', ['A1Ticket', 'A3Ticket']),
|
||||
('status=0&item=&user=', ['A1Mascot', 'A2Ticket']),
|
||||
('status=&item=&user=a3dummy', ['A3Ticket']), # match order email
|
||||
('status=&item=&user=a3dummy', ['A3Ticket']), # match order email,
|
||||
('status=&item=&user=a4', ['A3Ticket']), # match attendee name
|
||||
('status=&item=&user=a3company', ['A3Ticket']), # match attendee email
|
||||
('status=1&item=&user=a3company', ['A3Ticket']),
|
||||
])
|
||||
def test_checkins_list_filter(client, checkin_list_env, query, expected):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/checkins/?' + query)
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) for q in qs]
|
||||
print([str(item.name) + '-' + str(item.id) for item in Item.objects.all()])
|
||||
assert item_keys == expected
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_checkins_item_filter(client, checkin_list_env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
for item in checkin_list_env[3]:
|
||||
response = client.get('/control/event/dummy/dummy/checkins/?item=' + str(item.id))
|
||||
assert all(i.item.id == item.id for i in response.context['entries'])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("query, expected", [
|
||||
('status=&item=&user=&ordering=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('status=1&item=&user=&ordering=timestamp', ['A3Ticket', 'A1Ticket']),
|
||||
# ('status=0&item=&user=&ordering=-name', ['A2Ticket', 'A1Mascot']),
|
||||
# ('status=&item=Ticket&user=&ordering=checkins__datetime', ['A2Ticket', 'A3Ticket', 'A1Ticket']),
|
||||
])
|
||||
def test_checkins_list_mixed(client, checkin_list_env, query, expected):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/checkins/?' + query)
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) for q in qs]
|
||||
assert item_keys == expected
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def checkin_list_with_addon_env():
|
||||
# permission
|
||||
orga = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
team = Team.objects.create(organizer=orga, can_view_orders=True, can_change_orders=True)
|
||||
team.members.add(user)
|
||||
|
||||
# event
|
||||
event = Event.objects.create(
|
||||
organizer=orga, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer,tests.testdummy'
|
||||
)
|
||||
event.settings.set('ticketoutput_testdummy__enabled', True)
|
||||
event.settings.set('attendee_names_asked', True)
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
team.limit_events.add(event)
|
||||
|
||||
# item
|
||||
cat_adm = ItemCategory.objects.create(event=event, name="Admission")
|
||||
cat_workshop = ItemCategory.objects.create(event=event, name="Admission", is_addon=True)
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True, category=cat_adm)
|
||||
item_workshop = Item.objects.create(event=event, name="Workshop", default_price=10, admission=False,
|
||||
category=cat_workshop)
|
||||
ItemAddOn.objects.create(base_item=item_ticket, addon_category=cat_workshop, min_count=0, max_count=2)
|
||||
|
||||
# order
|
||||
order_pending = Order.objects.create(
|
||||
code='PENDING', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
order_a1 = Order.objects.create(
|
||||
code='A1', event=event, email='a1dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=33, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
order_a2 = Order.objects.create(
|
||||
code='A2', event=event, email='a2dummy@dummy.test',
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
|
||||
# order position
|
||||
op_pending_ticket = OrderPosition.objects.create(
|
||||
order=order_pending,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="Pending"
|
||||
)
|
||||
op_a1_ticket = OrderPosition.objects.create(
|
||||
order=order_a1,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="A1"
|
||||
)
|
||||
op_a1_workshop = OrderPosition.objects.create(
|
||||
order=order_a1,
|
||||
item=item_workshop,
|
||||
variation=None,
|
||||
price=Decimal("10"),
|
||||
addon_to=op_a1_ticket
|
||||
)
|
||||
op_a2_ticket = OrderPosition.objects.create(
|
||||
order=order_a2,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name="A2"
|
||||
)
|
||||
|
||||
# checkin
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1))
|
||||
|
||||
return event, user, orga, [item_ticket, item_workshop], [order_pending, order_a1, order_a2], \
|
||||
[op_pending_ticket, op_a1_ticket, op_a1_workshop, op_a2_ticket]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_checkins_attendee_name_from_addon_available(client, checkin_list_with_addon_env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/checkins/')
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) +
|
||||
(str(q.addon_to.attendee_name) if q.addon_to is not None else str(q.attendee_name)) for q in qs]
|
||||
assert item_keys == ['A1TicketA1', 'A1WorkshopA1', 'A2TicketA2'] # A1Workshop<name> comes from addon_to position
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_checkins_with_noadm_option(client, checkin_list_with_addon_env):
|
||||
checkin_list_with_addon_env[0].settings.ticket_download_nonadm = False
|
||||
checkin_list_with_addon_env[0].save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/checkins/')
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) +
|
||||
(str(q.addon_to.attendee_name) if q.addon_to is not None else str(q.attendee_name)) for q in qs]
|
||||
assert item_keys == ['A1TicketA1', 'A2TicketA2']
|
||||
@@ -201,6 +201,7 @@ event_permission_urls = [
|
||||
("can_change_vouchers", "vouchers/1234/delete", 404),
|
||||
("can_view_orders", "waitinglist/", 200),
|
||||
("can_change_orders", "waitinglist/auto_assign", 405),
|
||||
("can_view_orders", "checkins/", 200),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user