mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
* Data model and migration * Some backwards compatibility * CRUD for checkin lists * Show and perform checkins * Correct numbers in table and dashboard widget * event creation and cloning * Allow to link specific exports and pass options per query * Play with the CSV export * PDF export * Collapse exports by default * Improve PDF exporter * Addon stuff * Subevent stuff, pretixdroid tests * pretixdroid tests * Add CRUD API * Test compatibility * Fix test * DB-independent sorting behavior * Add CRUD and coyp tests * Re-enable pretixdroid plugin * pretixdroid config * Tests & fixes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
@@ -10,6 +10,8 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.control.views.dashboards import checkin_widget
|
||||
|
||||
from ..base import SoupTest, extract_form_fields
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashboard_env():
|
||||
@@ -27,6 +29,8 @@ def dashboard_env():
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
cl = event.checkin_lists.create(name="Default", all_products=True)
|
||||
|
||||
event.settings.set('attendee_names_asked', True)
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
|
||||
@@ -50,7 +54,7 @@ def dashboard_env():
|
||||
price=Decimal("10")
|
||||
)
|
||||
|
||||
return event, user, o, order_paid, item_ticket, item_mascot
|
||||
return event, user, o, order_paid, item_ticket, item_mascot, cl
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -84,32 +88,11 @@ def test_dashboard_with_checkin(dashboard_env):
|
||||
order=dashboard_env[3],
|
||||
item=dashboard_env[4]
|
||||
)
|
||||
Checkin.objects.create(position=op)
|
||||
Checkin.objects.create(position=op, list=dashboard_env[6])
|
||||
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
|
||||
@@ -128,9 +111,11 @@ def checkin_list_env():
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
team.limit_events.add(event)
|
||||
|
||||
cl = event.checkin_lists.create(name="Default", all_products=True)
|
||||
|
||||
# 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)
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True, position=0)
|
||||
item_mascot = Item.objects.create(event=event, name="Mascot", default_price=10, admission=False, position=1)
|
||||
|
||||
# order
|
||||
order_pending = Order.objects.create(
|
||||
@@ -196,32 +181,32 @@ def checkin_list_env():
|
||||
)
|
||||
|
||||
# checkin
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1))
|
||||
Checkin.objects.create(position=op_a3_ticket)
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1), list=cl)
|
||||
Checkin.objects.create(position=op_a3_ticket, list=cl)
|
||||
|
||||
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]
|
||||
[op_pending_ticket, op_a1_ticket, op_a1_mascot, op_a2_ticket, op_a3_ticket], cl
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("order_key, expected", [
|
||||
('', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('-code', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
|
||||
('code', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('code', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']),
|
||||
('-email', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
|
||||
('email', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
|
||||
('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
|
||||
('email', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']),
|
||||
('-status', ['A3Ticket', 'A1Ticket', 'A2Ticket', 'A1Mascot']),
|
||||
('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
|
||||
('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
|
||||
('-timestamp', ['A1Ticket', 'A3Ticket', 'A2Ticket', 'A1Mascot']), # 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', ['A3Ticket', 'A2Ticket', 'A1Ticket', '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)
|
||||
response = client.get('/control/event/dummy/dummy/checkinlists/{}/?ordering='.format(checkin_list_env[6].pk) + order_key)
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) for q in qs]
|
||||
assert item_keys == expected
|
||||
@@ -240,7 +225,7 @@ def test_checkins_list_ordering(client, checkin_list_env, order_key, expected):
|
||||
])
|
||||
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)
|
||||
response = client.get('/control/event/dummy/dummy/checkinlists/{}/?'.format(checkin_list_env[6].pk) + 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()])
|
||||
@@ -251,7 +236,7 @@ def test_checkins_list_filter(client, checkin_list_env, query, expected):
|
||||
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))
|
||||
response = client.get('/control/event/dummy/dummy/checkinlists/{}/?item={}'.format(checkin_list_env[6].pk, item.pk))
|
||||
assert all(i.item.id == item.id for i in response.context['entries'])
|
||||
|
||||
|
||||
@@ -263,7 +248,7 @@ def test_checkins_item_filter(client, checkin_list_env):
|
||||
])
|
||||
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)
|
||||
response = client.get('/control/event/dummy/dummy/checkinlists/{}/?{}'.format(checkin_list_env[6].pk, query))
|
||||
qs = response.context['entries']
|
||||
item_keys = [q.order.code + str(q.item.name) for q in qs]
|
||||
assert item_keys == expected
|
||||
@@ -273,7 +258,7 @@ def test_checkins_list_mixed(client, checkin_list_env, query, expected):
|
||||
def test_manual_checkins(client, checkin_list_env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
assert not checkin_list_env[5][3].checkins.exists()
|
||||
client.post('/control/event/dummy/dummy/checkins/', {
|
||||
client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), {
|
||||
'checkin': [checkin_list_env[5][3].pk]
|
||||
})
|
||||
assert checkin_list_env[5][3].checkins.exists()
|
||||
@@ -299,6 +284,7 @@ def checkin_list_with_addon_env():
|
||||
event.settings.set('attendee_names_asked', True)
|
||||
event.settings.set('locales', ['en', 'de'])
|
||||
team.limit_events.add(event)
|
||||
cl = event.checkin_lists.create(name="Default", all_products=True)
|
||||
|
||||
# item
|
||||
cat_adm = ItemCategory.objects.create(event=event, name="Admission")
|
||||
@@ -359,29 +345,69 @@ def checkin_list_with_addon_env():
|
||||
)
|
||||
|
||||
# checkin
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1))
|
||||
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1), list=cl)
|
||||
|
||||
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]
|
||||
[op_pending_ticket, op_a1_ticket, op_a1_workshop, op_a2_ticket], cl
|
||||
|
||||
|
||||
@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/')
|
||||
response = client.get('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_with_addon_env[6].pk))
|
||||
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']
|
||||
class CheckinListFormTest(SoupTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc')
|
||||
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm')
|
||||
self.event1 = Event.objects.create(
|
||||
organizer=self.orga1, name='30C3', slug='30c3',
|
||||
date_from=datetime(2013, 12, 26, tzinfo=timezone.utc),
|
||||
)
|
||||
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_view_orders=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
self.item_ticket = Item.objects.create(event=self.event1, name="Ticket", default_price=23, admission=True)
|
||||
|
||||
def test_create(self):
|
||||
doc = self.get_doc('/control/event/%s/%s/checkinlists/add' % (self.orga1.slug, self.event1.slug))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['name'] = 'All'
|
||||
form_data['all_products'] = 'on'
|
||||
doc = self.post_doc('/control/event/%s/%s/checkinlists/add' % (self.orga1.slug, self.event1.slug), form_data)
|
||||
assert doc.select(".alert-success")
|
||||
self.assertIn("All", doc.select("#page-wrapper table")[0].text)
|
||||
assert self.event1.checkin_lists.get(
|
||||
name='All', all_products=True
|
||||
)
|
||||
|
||||
def test_update(self):
|
||||
cl = self.event1.checkin_lists.create(name='All', all_products=True)
|
||||
doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/change' % (self.orga1.slug, self.event1.slug, cl.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['all_products'] = ''
|
||||
form_data['limit_products'] = str(self.item_ticket.pk)
|
||||
doc = self.post_doc('/control/event/%s/%s/checkinlists/%s/change' % (self.orga1.slug, self.event1.slug, cl.id),
|
||||
form_data)
|
||||
assert doc.select(".alert-success")
|
||||
cl.refresh_from_db()
|
||||
assert not cl.all_products
|
||||
assert list(cl.limit_products.all()) == [self.item_ticket]
|
||||
|
||||
def test_delete(self):
|
||||
cl = self.event1.checkin_lists.create(name='All', all_products=True)
|
||||
doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
doc = self.post_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id),
|
||||
form_data)
|
||||
assert doc.select(".alert-success")
|
||||
self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text)
|
||||
assert not self.event1.checkin_lists.exists()
|
||||
|
||||
@@ -613,6 +613,12 @@ class SubEventsTest(SoupTest):
|
||||
'location_0': 'Hamburg',
|
||||
'presale_start_0': '2017-06-20',
|
||||
'presale_start_1': '10:00:00',
|
||||
'checkinlist_set-TOTAL_FORMS': '1',
|
||||
'checkinlist_set-INITIAL_FORMS': '0',
|
||||
'checkinlist_set-MIN_NUM_FORMS': '0',
|
||||
'checkinlist_set-MAX_NUM_FORMS': '1000',
|
||||
'checkinlist_set-0-name': 'Default',
|
||||
'checkinlist_set-0-all_products': 'on',
|
||||
'quotas-TOTAL_FORMS': '1',
|
||||
'quotas-INITIAL_FORMS': '0',
|
||||
'quotas-MIN_NUM_FORMS': '0',
|
||||
@@ -638,6 +644,7 @@ class SubEventsTest(SoupTest):
|
||||
assert list(q.items.all()) == [self.ticket]
|
||||
sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
|
||||
assert sei.price == 12
|
||||
assert se.checkinlist_set.count() == 1
|
||||
|
||||
def test_modify(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk)
|
||||
@@ -659,8 +666,15 @@ class SubEventsTest(SoupTest):
|
||||
'quotas-0-name': 'Q1',
|
||||
'quotas-0-size': '50',
|
||||
'quotas-0-itemvars': str(self.ticket.pk),
|
||||
'checkinlist_set-TOTAL_FORMS': '1',
|
||||
'checkinlist_set-INITIAL_FORMS': '0',
|
||||
'checkinlist_set-MIN_NUM_FORMS': '0',
|
||||
'checkinlist_set-MAX_NUM_FORMS': '1000',
|
||||
'checkinlist_set-0-name': 'Default',
|
||||
'checkinlist_set-0-all_products': 'on',
|
||||
'item-%d-price' % self.ticket.pk: '12'
|
||||
})
|
||||
print(doc)
|
||||
assert doc.select(".alert-success")
|
||||
self.subevent1.refresh_from_db()
|
||||
se = self.subevent1
|
||||
@@ -678,6 +692,7 @@ class SubEventsTest(SoupTest):
|
||||
assert list(q.items.all()) == [self.ticket]
|
||||
sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
|
||||
assert sei.price == 12
|
||||
assert se.checkinlist_set.count() == 1
|
||||
|
||||
def test_delete(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk)
|
||||
|
||||
@@ -89,6 +89,10 @@ event_urls = [
|
||||
"orders/ABC/checkvatid",
|
||||
"orders/ABC/",
|
||||
"orders/",
|
||||
"checkinlists/",
|
||||
"checkinlists/1/",
|
||||
"checkinlists/1/change",
|
||||
"checkinlists/1/delete",
|
||||
"waitinglist/",
|
||||
"waitinglist/auto_assign",
|
||||
"invoice/1",
|
||||
@@ -225,7 +229,11 @@ 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),
|
||||
("can_view_orders", "checkinlists/", 200),
|
||||
("can_view_orders", "checkinlists/1/", 404),
|
||||
("can_change_event_settings", "checkinlists/add", 200),
|
||||
("can_change_event_settings", "checkinlists/1/change", 404),
|
||||
("can_change_event_settings", "checkinlists/1/delete", 404),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user