mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
Add support for reserved seating (#1228)
* Initial work on seating * Add seat guids * Add product_list_top * CartAdd: Ignore item when a seat is passed * Cart display * product_list_top → render_seating_plan * Render seating plan in voucher redemption * Fix failing tests * Add tests for extending cart positions with seats * Add subevent_forms to docs * Update schema, migrations * Dealing with expired orders * steps to order change * Change order positions * Allow to add seats * tests for ocm * Fix things after rebase * Seating plans API * Add more tests for cart behaviour * Widget support * Adjust widget tests * Re-enable CSP * Update schema * Api: position.seat * Add guid to word list * API: (sub)event.seating_plan * Vali fixes * Fix api * Fix reference in test * Fix test for real
This commit is contained in:
@@ -18,7 +18,7 @@ from pretix.base.i18n import language
|
||||
from pretix.base.models import (
|
||||
CachedFile, CartPosition, Checkin, CheckinList, Event, Item, ItemCategory,
|
||||
ItemVariation, Order, OrderFee, OrderPayment, OrderPosition, OrderRefund,
|
||||
Organizer, Question, Quota, User, Voucher, WaitingListEntry,
|
||||
Organizer, Question, Quota, SeatingPlan, User, Voucher, WaitingListEntry,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.items import (
|
||||
@@ -1971,6 +1971,157 @@ class CheckinListTestCase(TestCase):
|
||||
assert lists[3].percent == 25
|
||||
|
||||
|
||||
class SeatingTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
with scope(organizer=self.organizer):
|
||||
self.event = Event.objects.create(
|
||||
organizer=self.organizer, name='Dummy', slug='dummy',
|
||||
date_from=now(), date_to=now() - timedelta(hours=1),
|
||||
)
|
||||
self.ticket = self.event.items.create(name="Ticket", default_price=12)
|
||||
self.plan = SeatingPlan.objects.create(
|
||||
name="Plan", organizer=self.organizer, layout="{}"
|
||||
)
|
||||
self.event.seat_category_mappings.create(
|
||||
layout_category='Stalls', product=self.ticket
|
||||
)
|
||||
self.seat_a1 = self.event.seats.create(name="A1", product=self.ticket, blocked=False)
|
||||
self.seat_a2 = self.event.seats.create(name="A2", product=self.ticket, blocked=False)
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_free(self):
|
||||
assert set(self.event.free_seats) == {self.seat_a1, self.seat_a2}
|
||||
assert self.seat_a1.is_available()
|
||||
assert self.seat_a2.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_blocked(self):
|
||||
self.seat_a1.blocked = True
|
||||
self.seat_a1.save()
|
||||
assert set(self.event.free_seats) == {self.seat_a2}
|
||||
assert not self.seat_a1.is_available()
|
||||
assert self.seat_a2.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_order_pending(self):
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test', total=Decimal("30"),
|
||||
locale='en', status=Order.STATUS_PENDING, datetime=now(),
|
||||
expires=now() + timedelta(days=10),
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o, item=self.ticket, variation=None, price=Decimal("12"),
|
||||
seat=self.seat_a1
|
||||
)
|
||||
assert set(self.event.free_seats) == {self.seat_a2}
|
||||
assert not self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_order_paid(self):
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test', total=Decimal("30"),
|
||||
locale='en', status=Order.STATUS_PAID, datetime=now(),
|
||||
expires=now() + timedelta(days=10),
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o, item=self.ticket, variation=None, price=Decimal("12"),
|
||||
seat=self.seat_a1
|
||||
)
|
||||
assert set(self.event.free_seats) == {self.seat_a2}
|
||||
assert not self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_order_expired(self):
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test', total=Decimal("30"),
|
||||
locale='en', status=Order.STATUS_EXPIRED, datetime=now(),
|
||||
expires=now() + timedelta(days=10),
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o, item=self.ticket, variation=None, price=Decimal("12"),
|
||||
seat=self.seat_a1
|
||||
)
|
||||
assert set(self.event.free_seats) == {self.seat_a1, self.seat_a2}
|
||||
assert self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_cart_active(self):
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id='a', item=self.ticket, seat=self.seat_a1,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
assert set(self.event.free_seats) == {self.seat_a2}
|
||||
assert not self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_cart_expired(self):
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id='a', item=self.ticket, seat=self.seat_a1,
|
||||
price=23, expires=now() - timedelta(minutes=10)
|
||||
)
|
||||
assert set(self.event.free_seats) == {self.seat_a1, self.seat_a2}
|
||||
assert self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_subevent_order_pending(self):
|
||||
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
|
||||
self.seat_a1.subevent = se1
|
||||
self.seat_a1.save()
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test', total=Decimal("30"),
|
||||
locale='en', status=Order.STATUS_PAID, datetime=now(),
|
||||
expires=now() + timedelta(days=10),
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o, item=self.ticket, variation=None, price=Decimal("12"),
|
||||
seat=self.seat_a1, subevent=se1
|
||||
)
|
||||
assert set(se1.free_seats) == set()
|
||||
assert not self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_subevent_order_canceled(self):
|
||||
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
|
||||
self.seat_a1.subevent = se1
|
||||
self.seat_a1.save()
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test', total=Decimal("30"),
|
||||
locale='en', status=Order.STATUS_CANCELED, datetime=now(),
|
||||
expires=now() + timedelta(days=10),
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o, item=self.ticket, variation=None, price=Decimal("12"),
|
||||
seat=self.seat_a1, subevent=se1
|
||||
)
|
||||
assert set(se1.free_seats) == {self.seat_a1}
|
||||
assert self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_subevent_cart_active(self):
|
||||
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
|
||||
self.seat_a1.subevent = se1
|
||||
self.seat_a1.save()
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id='a', item=self.ticket, seat=self.seat_a1,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se1
|
||||
)
|
||||
assert set(se1.free_seats) == set()
|
||||
assert not self.seat_a1.is_available()
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_subevent_cart_expired(self):
|
||||
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
|
||||
self.seat_a1.subevent = se1
|
||||
self.seat_a1.save()
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id='a', item=self.ticket, seat=self.seat_a1,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se1
|
||||
)
|
||||
assert set(se1.free_seats) == {self.seat_a1}
|
||||
assert self.seat_a1.is_available()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("qtype,answer,expected", [
|
||||
(Question.TYPE_STRING, "a", "a"),
|
||||
|
||||
Reference in New Issue
Block a user