mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Add sub-events and relative date settings (#503)
* Data model * little crud * SubEventItemForm etc * Drop SubEventItem.active, quota editor * Fix failing tests * First frontend stuff * Addons form stuff * Quota calculation * net price display on EventIndex * Add tests, solve some bugs * Correct quota selection in more places, consolidate pricing logic * Fix failing quota tests * Fix TypeError * Add tests for checkout * Fixed a bug in QuotaForm * Prevent immutable cart if a quota was removed from an item * Add tests for pricing * Handle waiting list * Filter in check-in list * Fixed import lost in rebase * Fix waiting list widget * Voucher management * Voucher redemption * Fix broken tests * Add subevents to OrderChangeManager * Create a subevent during event creation * Fix bulk voucher creation * Introduce subevent.active * Copy from for subevents * Show active in list * ICal download for subevents * Check start and end of presale * Failing tests / show cart logic * Test * Rebase migrations * REST API integration of sub-events * Integrate quota calculation into the traditional quota form * Make subevent argument to add_position optional * Log-display foo * pretixdroid and subevents * Filter by subevent * Add more tests * Some mor tests * Rebase fixes * More tests * Relative dates * Restrict selection in relative datetime widgets * Filter subevent list * Re-label has_subevents * Rebase fixes, subevents in calendar view * Performance and caching issues * Refactor calendar templates * Permission tests * Calendar fixes and month selection * subevent selection * Rename subevents to dates * Add tests for calendar views
This commit is contained in:
@@ -11,7 +11,9 @@ from pretix.base.models import (
|
||||
CartPosition, Event, Item, ItemCategory, ItemVariation, Organizer,
|
||||
Question, QuestionAnswer, Quota, Voucher,
|
||||
)
|
||||
from pretix.base.models.items import ItemAddOn
|
||||
from pretix.base.models.items import (
|
||||
ItemAddOn, SubEventItem, SubEventItemVariation,
|
||||
)
|
||||
from pretix.base.services.cart import CartError, CartManager
|
||||
|
||||
|
||||
@@ -88,6 +90,195 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
|
||||
def test_subevent_missing(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_voucher_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
v = Voucher.objects.create(item=self.ticket, event=self.event, subevent=se)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
'subevent': se.pk
|
||||
}, follow=True)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
self.assertEqual(objs[0].subevent, se)
|
||||
|
||||
def test_voucher_any_subevent(self):
|
||||
v = Voucher.objects.create(item=self.ticket, event=self.event)
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
print(self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
'subevent': se.pk
|
||||
}, follow=True).rendered_content)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
self.assertEqual(objs[0].subevent, se)
|
||||
|
||||
def test_voucher_wrong_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
v = Voucher.objects.create(item=self.ticket, event=self.event, subevent=se2)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
'subevent': se.pk
|
||||
}, follow=True)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_inactive_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=False)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_subevent_sale_over(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True,
|
||||
presale_end=now() - timedelta(days=1))
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_subevent_sale_not_yet(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True,
|
||||
presale_start=now() + timedelta(days=1))
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_simple_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
self.assertEqual(objs[0].subevent, se)
|
||||
|
||||
def test_subevent_sold_out(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se1.quotas.create(name="foo", size=0, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se1.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_other_subevent_sold_out(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se1.quotas.create(name="foo", size=0, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
q = se2.quotas.create(name="foo", size=100, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se2.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
|
||||
def test_subevent_no_quota(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se1.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se2.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 0)
|
||||
|
||||
def test_subevent_price(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
SubEventItem.objects.create(subevent=se, item=self.ticket, price=42)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 42)
|
||||
self.assertEqual(objs[0].subevent, se)
|
||||
|
||||
def test_free_price(self):
|
||||
self.ticket.free_price = True
|
||||
self.ticket.save()
|
||||
@@ -198,6 +389,24 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertEqual(objs[0].variation, self.shirt_red)
|
||||
self.assertEqual(objs[0].price, 16)
|
||||
|
||||
def test_subevent_variation_price(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.variations.add(self.shirt_red)
|
||||
SubEventItemVariation.objects.create(subevent=se, variation=self.shirt_red, price=42)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
|
||||
'subevent': se.pk
|
||||
}, follow=False)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.shirt)
|
||||
self.assertEqual(objs[0].variation, self.shirt_red)
|
||||
self.assertEqual(objs[0].price, 42)
|
||||
self.assertEqual(objs[0].subevent, se)
|
||||
|
||||
def test_count(self):
|
||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '2'
|
||||
@@ -438,6 +647,30 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
|
||||
def test_subevent_quota_partly(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.size = 1
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
q2 = self.event.quotas.create(name='Foo', size=15)
|
||||
q2.items.add(self.ticket)
|
||||
|
||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '2',
|
||||
'subevent': se.pk
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
|
||||
def test_renew_in_time(self):
|
||||
cp = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
@@ -496,6 +729,48 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||
self.assertFalse(CartPosition.objects.filter(id=cp1.id).exists())
|
||||
|
||||
def test_subevent_renew_expired_successfully(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.save()
|
||||
self.quota_shirts.subevent = se
|
||||
self.quota_shirts.save()
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
|
||||
'subevent': se.pk,
|
||||
}, follow=True)
|
||||
obj = CartPosition.objects.get(id=cp1.id)
|
||||
self.assertEqual(obj.item, self.ticket)
|
||||
self.assertIsNone(obj.variation)
|
||||
self.assertEqual(obj.price, 23)
|
||||
self.assertEqual(obj.subevent, se)
|
||||
self.assertGreater(obj.expires, now())
|
||||
|
||||
def test_subevent_renew_expired_failed(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.subevent = se
|
||||
self.quota_tickets.size = 0
|
||||
self.quota_tickets.save()
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'subevent': se.pk,
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
|
||||
self.assertFalse(CartPosition.objects.filter(id=cp1.id).exists())
|
||||
|
||||
def test_remove_simple(self):
|
||||
cp = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
@@ -1048,6 +1323,50 @@ class CartAddonTest(CartTestMixin, TestCase):
|
||||
cp2 = cp1.addons.first()
|
||||
assert cp2.item == self.workshop1
|
||||
|
||||
def test_cart_subevent_set_simple_addon(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.workshopquota.subevent = se
|
||||
self.workshopquota.save()
|
||||
cp1 = CartPosition.objects.create(
|
||||
expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
|
||||
event=self.event, cart_id=self.session_key, subevent=se
|
||||
)
|
||||
|
||||
self.cm.set_addons([
|
||||
{
|
||||
'addon_to': cp1.pk,
|
||||
'item': self.workshop1.pk,
|
||||
'variation': None
|
||||
}
|
||||
])
|
||||
self.cm.commit()
|
||||
cp2 = cp1.addons.first()
|
||||
assert cp2.item == self.workshop1
|
||||
assert cp2.subevent == se
|
||||
|
||||
def test_cart_subevent_set_addon_for_wrong_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.workshopquota.subevent = se2
|
||||
self.workshopquota.save()
|
||||
cp1 = CartPosition.objects.create(
|
||||
expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
|
||||
event=self.event, cart_id=self.session_key, subevent=se
|
||||
)
|
||||
|
||||
with self.assertRaises(CartError):
|
||||
self.cm.set_addons([
|
||||
{
|
||||
'addon_to': cp1.pk,
|
||||
'item': self.workshop1.pk,
|
||||
'variation': None
|
||||
}
|
||||
])
|
||||
|
||||
def test_wrong_category(self):
|
||||
cp1 = CartPosition.objects.create(
|
||||
expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
|
||||
|
||||
@@ -13,7 +13,7 @@ from pretix.base.models import (
|
||||
CartPosition, Event, Item, ItemCategory, Order, OrderPosition, Organizer,
|
||||
Question, Quota, Voucher,
|
||||
)
|
||||
from pretix.base.models.items import ItemAddOn, ItemVariation
|
||||
from pretix.base.models.items import ItemAddOn, ItemVariation, SubEventItem
|
||||
|
||||
|
||||
class CheckoutTestCase(TestCase):
|
||||
@@ -300,6 +300,26 @@ class CheckoutTestCase(TestCase):
|
||||
session[key] = value
|
||||
session.save()
|
||||
|
||||
def test_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists())
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.first().subevent, se)
|
||||
|
||||
def test_free_price(self):
|
||||
self.ticket.free_price = True
|
||||
self.ticket.save()
|
||||
@@ -331,6 +351,29 @@ class CheckoutTestCase(TestCase):
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
|
||||
def test_subevent_confirm_expired_available(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now())
|
||||
self.quota_tickets.size = 0
|
||||
self.quota_tickets.subevent = se2
|
||||
self.quota_tickets.save()
|
||||
q2 = se.quotas.create(event=self.event, size=1, name='Bar')
|
||||
q2.items.add(self.ticket)
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists())
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
|
||||
def test_confirm_expired_available(self):
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
@@ -345,6 +388,25 @@ class CheckoutTestCase(TestCase):
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
|
||||
def test_subevent_confirm_price_changed(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24)
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select(".alert-danger")), 1)
|
||||
cr1 = CartPosition.objects.get(id=cr1.id)
|
||||
self.assertEqual(cr1.price, 24)
|
||||
|
||||
def test_confirm_price_changed(self):
|
||||
self.ticket.default_price = 24
|
||||
self.ticket.save()
|
||||
@@ -663,6 +725,35 @@ class CheckoutTestCase(TestCase):
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
|
||||
def test_subevent_confirm_expired_partial(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now())
|
||||
self.quota_tickets.size = 10
|
||||
self.quota_tickets.subevent = se2
|
||||
self.quota_tickets.save()
|
||||
q2 = se.quotas.create(event=self.event, size=1, name='Bar')
|
||||
q2.items.add(self.ticket)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se2
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select(".alert-danger")), 1)
|
||||
self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key).count(), 2)
|
||||
|
||||
def test_confirm_expired_partial(self):
|
||||
self.quota_tickets.size = 1
|
||||
self.quota_tickets.save()
|
||||
@@ -862,3 +953,83 @@ class CheckoutTestCase(TestCase):
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug))
|
||||
self.assertRedirects(response, '/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
|
||||
def test_set_addons_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
self.workshopquota.size = 1
|
||||
self.workshopquota.subevent = se
|
||||
self.workshopquota.save()
|
||||
SubEventItem.objects.create(subevent=se, item=self.workshop1, price=42)
|
||||
|
||||
ItemAddOn.objects.create(base_item=self.ticket, addon_category=self.workshopcat, min_count=1)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
assert 'Workshop 1 (+ EUR 42.00)' in response.rendered_content
|
||||
|
||||
def test_set_addons_subevent_net_prices(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
self.workshopquota.size = 1
|
||||
self.workshopquota.subevent = se
|
||||
self.workshopquota.save()
|
||||
self.workshop1.tax_rate = 19
|
||||
self.workshop1.save()
|
||||
self.workshop2.tax_rate = 19
|
||||
self.workshop2.save()
|
||||
SubEventItem.objects.create(subevent=se, item=self.workshop1, price=42)
|
||||
|
||||
ItemAddOn.objects.create(base_item=self.ticket, addon_category=self.workshopcat, min_count=1)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10), subevent=se
|
||||
)
|
||||
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
assert 'Workshop 1 (+ EUR 35.29 plus 19.00% taxes)' in response.rendered_content
|
||||
assert 'A (+ EUR 10.08 plus 19.00% taxes)' in response.rendered_content
|
||||
|
||||
def test_confirm_subevent_presale_not_yet(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_start=now() + datetime.timedelta(days=1))
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'presale period for one of the events in your cart has not yet started.' in response.rendered_content
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
def test_confirm_subevent_presale_over(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() - datetime.timedelta(days=1))
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'presale period for one of the events in your cart has ended.' in response.rendered_content
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
@@ -14,6 +14,7 @@ from pretix.base.models import (
|
||||
Event, Item, ItemCategory, ItemVariation, Order, Organizer, Quota, Team,
|
||||
User, WaitingListEntry,
|
||||
)
|
||||
from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
||||
|
||||
|
||||
class EventTestMixin:
|
||||
@@ -130,6 +131,94 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
|
||||
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||
self.assertNotIn("Early-bird", resp.rendered_content)
|
||||
|
||||
def test_subevents_inactive_unknown(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=False)
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
|
||||
assert resp.status_code == 404
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk + 1000))
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_subevent_list(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self.event.subevents.create(name='Foo SE1', date_from=now() + datetime.timedelta(days=1), active=True)
|
||||
self.event.subevents.create(name='Foo SE2', date_from=now() + datetime.timedelta(days=1), active=False)
|
||||
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||
self.assertIn("Foo SE1", resp.rendered_content)
|
||||
self.assertNotIn("Foo SE2", resp.rendered_content)
|
||||
|
||||
def test_subevent_calendar(self):
|
||||
self.event.settings.event_list_type = 'calendar'
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo SE1', date_from=now() + datetime.timedelta(days=64), active=True)
|
||||
self.event.subevents.create(name='Foo SE2', date_from=now() + datetime.timedelta(days=32), active=True)
|
||||
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||
self.assertIn("Foo SE2", resp.rendered_content)
|
||||
self.assertNotIn("Foo SE1", resp.rendered_content)
|
||||
resp = self.client.get('/%s/%s/?year=%d&month=%d' % (self.orga.slug, self.event.slug, se1.date_from.year,
|
||||
se1.date_from.month))
|
||||
self.assertIn("Foo SE1", resp.rendered_content)
|
||||
self.assertNotIn("Foo SE2", resp.rendered_content)
|
||||
|
||||
def test_subevents(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0)
|
||||
q.items.add(item)
|
||||
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
|
||||
self.assertIn("Early-bird", resp.rendered_content)
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
|
||||
self.assertNotIn("Early-bird", resp.rendered_content)
|
||||
|
||||
def test_subevent_prices(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=15)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
q.items.add(item)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
|
||||
q.items.add(item)
|
||||
SubEventItem.objects.create(subevent=se1, item=item, price=12)
|
||||
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
|
||||
self.assertIn("12.00", resp.rendered_content)
|
||||
self.assertNotIn("15.00", resp.rendered_content)
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
|
||||
self.assertIn("15.00", resp.rendered_content)
|
||||
self.assertNotIn("12.00", resp.rendered_content)
|
||||
|
||||
def test_subevent_net_prices(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self.event.settings.display_net_prices = True
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=15,
|
||||
tax_rate=19)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
q.items.add(item)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
|
||||
q.items.add(item)
|
||||
SubEventItem.objects.create(subevent=se1, item=item, price=12)
|
||||
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
|
||||
self.assertIn("10.08", resp.rendered_content)
|
||||
self.assertNotIn("12.00", resp.rendered_content)
|
||||
self.assertNotIn("15.00", resp.rendered_content)
|
||||
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
|
||||
self.assertIn("12.61", resp.rendered_content)
|
||||
self.assertNotIn("12.00", resp.rendered_content)
|
||||
self.assertNotIn("15.00", resp.rendered_content)
|
||||
|
||||
def test_no_variations_in_quota(self):
|
||||
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2)
|
||||
@@ -357,6 +446,99 @@ class VoucherRedeemItemDisplayTest(EventTestMixin, SoupTest):
|
||||
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, 'ABC'), follow=True)
|
||||
assert "alert-danger" in html.rendered_content
|
||||
|
||||
def test_subevent_net_prices(self):
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self.item.tax_rate = 19
|
||||
self.item.save()
|
||||
se1 = self.event.subevents.create(name='SE1', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
|
||||
var1 = ItemVariation.objects.create(item=self.item, value='Red', position=1)
|
||||
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
|
||||
q.variations.add(var1)
|
||||
q.variations.add(var2)
|
||||
SubEventItemVariation.objects.create(subevent=se1, variation=var1, price=10)
|
||||
|
||||
self.v.value = Decimal("2.00")
|
||||
self.v.price_mode = 'subtract'
|
||||
self.v.save()
|
||||
html = self.client.get('/%s/%s/redeem?voucher=%s&subevent=%s' % (
|
||||
self.orga.slug, self.event.slug, self.v.code, se1.pk
|
||||
))
|
||||
assert "SE1" in html.rendered_content
|
||||
assert "Early-bird" in html.rendered_content
|
||||
assert "8.40" in html.rendered_content
|
||||
assert "6.72" in html.rendered_content
|
||||
|
||||
def test_subevent_prices(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='SE1', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
|
||||
var1 = ItemVariation.objects.create(item=self.item, value='Red', position=1)
|
||||
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
|
||||
q.variations.add(var1)
|
||||
q.variations.add(var2)
|
||||
SubEventItemVariation.objects.create(subevent=se1, variation=var1, price=10)
|
||||
|
||||
self.v.value = Decimal("2.00")
|
||||
self.v.price_mode = 'subtract'
|
||||
self.v.save()
|
||||
html = self.client.get('/%s/%s/redeem?voucher=%s&subevent=%s' % (
|
||||
self.orga.slug, self.event.slug, self.v.code, se1.pk
|
||||
))
|
||||
assert "SE1" in html.rendered_content
|
||||
assert "Early-bird" in html.rendered_content
|
||||
assert "10.00" in html.rendered_content
|
||||
assert "8.00" in html.rendered_content
|
||||
assert "variation_%d_%d" % (self.item.pk, var1.pk) in html.rendered_content
|
||||
assert "variation_%d_%d" % (self.item.pk, var2.pk) in html.rendered_content
|
||||
|
||||
def test_voucher_ignore_other_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='SE1', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='SE2', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
|
||||
var1 = ItemVariation.objects.create(item=self.item, value='Red', position=1)
|
||||
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
|
||||
q.variations.add(var1)
|
||||
q.variations.add(var2)
|
||||
|
||||
self.v.subevent = se1
|
||||
self.v.save()
|
||||
html = self.client.get('/%s/%s/redeem?voucher=%s&subevent=%s' % (
|
||||
self.orga.slug, self.event.slug, self.v.code, se2.pk
|
||||
))
|
||||
assert "SE1" in html.rendered_content
|
||||
|
||||
def test_voucher_quota(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='SE1', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='SE2', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=0, subevent=se1)
|
||||
q2 = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
|
||||
|
||||
var1 = ItemVariation.objects.create(item=self.item, value='Red', position=1)
|
||||
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
|
||||
q.variations.add(var1)
|
||||
q2.variations.add(var1)
|
||||
q.variations.add(var2)
|
||||
q2.variations.add(var1)
|
||||
|
||||
self.v.save()
|
||||
html = self.client.get('/%s/%s/redeem?voucher=%s&subevent=%s' % (
|
||||
self.orga.slug, self.event.slug, self.v.code, se1.pk
|
||||
))
|
||||
assert "SE1" in html.rendered_content
|
||||
assert "variation_%d_%d" % (self.item.pk, var1.pk) not in html.rendered_content
|
||||
assert "variation_%d_%d" % (self.item.pk, var2.pk) not in html.rendered_content
|
||||
|
||||
|
||||
class WaitingListTest(EventTestMixin, SoupTest):
|
||||
def setUp(self):
|
||||
@@ -376,7 +558,7 @@ class WaitingListTest(EventTestMixin, SoupTest):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotIn('waitinglist', response.rendered_content)
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist?item=%d' % (self.orga.slug, self.event.slug, self.item.pk + 1)
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk + 1)
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
@@ -389,12 +571,12 @@ class WaitingListTest(EventTestMixin, SoupTest):
|
||||
|
||||
def test_submit_form(self):
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist?item=%d' % (self.orga.slug, self.event.slug, self.item.pk)
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk)
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('waiting list', response.rendered_content)
|
||||
response = self.client.post(
|
||||
'/%s/%s/waitinglist?item=%d' % (self.orga.slug, self.event.slug, self.item.pk), {
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk), {
|
||||
'email': 'foo@bar.com'
|
||||
}
|
||||
)
|
||||
@@ -406,17 +588,77 @@ class WaitingListTest(EventTestMixin, SoupTest):
|
||||
assert wle.voucher is None
|
||||
assert wle.locale == 'en'
|
||||
|
||||
def test_invalid_item(self):
|
||||
def test_subevent_valid(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name="Foobar", date_from=now(), active=True)
|
||||
self.q.subevent = se1
|
||||
self.q.save()
|
||||
q2 = self.event.quotas.create(name="Foobar", size=100, subevent=se2)
|
||||
q2.items.add(self.item)
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist?item=%d' % (self.orga.slug, self.event.slug, self.item.pk + 1)
|
||||
'/%s/%s/waitinglist/?item=%d&subevent=%d' % (self.orga.slug, self.event.slug, self.item.pk, se1.pk)
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('waiting list', response.rendered_content)
|
||||
response = self.client.post(
|
||||
'/%s/%s/waitinglist/?item=%d&subevent=%d' % (self.orga.slug, self.event.slug, self.item.pk, se1.pk), {
|
||||
'email': 'foo@bar.com'
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
wle = WaitingListEntry.objects.get(email='foo@bar.com')
|
||||
assert wle.event == self.event
|
||||
assert wle.item == self.item
|
||||
assert wle.subevent == se1
|
||||
|
||||
def test_invalid_item(self):
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk + 1)
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_invalid_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now(), active=False)
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk)
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d&subevent=%d' % (self.orga.slug, self.event.slug, self.item.pk, se1.pk + 100)
|
||||
)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d&subevent=%d' % (self.orga.slug, self.event.slug, self.item.pk, se1.pk)
|
||||
)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_available(self):
|
||||
self.q.size = 1
|
||||
self.q.save()
|
||||
response = self.client.post(
|
||||
'/%s/%s/waitinglist?item=%d' % (self.orga.slug, self.event.slug, self.item.pk), {
|
||||
'/%s/%s/waitinglist/?item=%d' % (self.orga.slug, self.event.slug, self.item.pk), {
|
||||
'email': 'foo@bar.com'
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertFalse(WaitingListEntry.objects.filter(email='foo@bar.com').exists())
|
||||
|
||||
def test_subevent_available(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name="Foobar", date_from=now(), active=True)
|
||||
self.q.size = 1
|
||||
self.q.subevent = se1
|
||||
self.q.save()
|
||||
q2 = self.event.quotas.create(name="Foobar", size=0, subevent=se2)
|
||||
q2.items.add(self.item)
|
||||
response = self.client.post(
|
||||
'/%s/%s/waitinglist/?item=%d&subevent=%d' % (self.orga.slug, self.event.slug, self.item.pk, se1.pk), {
|
||||
'email': 'foo@bar.com'
|
||||
}
|
||||
)
|
||||
@@ -575,14 +817,14 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
self.event.save()
|
||||
|
||||
def test_response_type(self):
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug))
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug))
|
||||
self.assertEqual(ical['Content-Type'], 'text/calendar')
|
||||
self.assertEqual(ical['Content-Disposition'], 'attachment; filename="{}-{}.ics"'.format(
|
||||
self.assertEqual(ical['Content-Disposition'], 'attachment; filename="{}-{}-0.ics"'.format(
|
||||
self.orga.slug, self.event.slug
|
||||
))
|
||||
|
||||
def test_header_footer(self):
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertTrue(ical.startswith('BEGIN:VCALENDAR'), 'missing VCALENDAR header')
|
||||
self.assertTrue(ical.strip().endswith('END:VCALENDAR'), 'missing VCALENDAR footer')
|
||||
self.assertIn('BEGIN:VEVENT', ical, 'missing VEVENT header')
|
||||
@@ -591,7 +833,7 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
def test_timezone_header_footer(self):
|
||||
self.event.settings.timezone = 'Asia/Tokyo'
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertTrue(ical.startswith('BEGIN:VCALENDAR'), 'missing VCALENDAR header')
|
||||
self.assertTrue(ical.strip().endswith('END:VCALENDAR'), 'missing VCALENDAR footer')
|
||||
self.assertIn('BEGIN:VEVENT', ical, 'missing VEVENT header')
|
||||
@@ -600,20 +842,20 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
self.assertIn('END:VTIMEZONE', ical, 'missing VTIMEZONE footer')
|
||||
|
||||
def test_metadata(self):
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertIn('VERSION:2.0', ical, 'incorrect version tag - 2.0')
|
||||
self.assertIn('-//pretix//%s//' % settings.PRETIX_INSTANCE_NAME, ical, 'incorrect PRODID')
|
||||
|
||||
def test_event_info(self):
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertIn('SUMMARY:%s' % self.event.name, ical, 'incorrect correct summary')
|
||||
self.assertIn('LOCATION:DUMMY ARENA', ical, 'incorrect location')
|
||||
self.assertIn('ORGANIZER:%s' % self.event.organizer.name, ical, 'incorrect organizer')
|
||||
self.assertTrue(re.search(r'DTSTAMP:\d{8}T\d{6}Z', ical), 'incorrect timestamp')
|
||||
self.assertTrue(re.search(r'UID:\w*-\w*-\d{20}', ical), 'missing UID key')
|
||||
self.assertTrue(re.search(r'UID:\w*-\w*-0-\d{20}', ical), 'missing UID key')
|
||||
|
||||
def test_utc_timezone(self):
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
# according to icalendar spec, timezone must NOT be shown if it is UTC
|
||||
self.assertIn('DTSTART:%s' % self.event.date_from.strftime('%Y%m%dT%H%M%SZ'), ical, 'incorrect start time')
|
||||
self.assertIn('DTEND:%s' % self.event.date_to.strftime('%Y%m%dT%H%M%SZ'), ical, 'incorrect end time')
|
||||
@@ -621,7 +863,7 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
def test_include_timezone(self):
|
||||
self.event.settings.timezone = 'Asia/Tokyo'
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
# according to icalendar spec, timezone must be shown if it is not UTC
|
||||
fmt = '%Y%m%dT%H%M%S'
|
||||
self.assertIn('DTSTART;TZID=%s:%s' %
|
||||
@@ -637,7 +879,7 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
def test_no_time(self):
|
||||
self.event.settings.show_times = False
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertIn('DTSTART;VALUE=DATE:%s' % self.event.date_from.strftime('%Y%m%d'), ical, 'incorrect start date')
|
||||
self.assertIn('DTEND;VALUE=DATE:%s' % self.event.date_to.strftime('%Y%m%d'), ical, 'incorrect end date')
|
||||
|
||||
@@ -645,7 +887,7 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
self.event.settings.timezone = 'Asia/Tokyo'
|
||||
self.event.settings.show_date_to = False
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
fmt = '%Y%m%dT%H%M%S'
|
||||
self.assertIn('DTSTART;TZID=%s:%s' %
|
||||
(self.event.settings.timezone,
|
||||
@@ -657,7 +899,7 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
self.event.settings.show_date_to = False
|
||||
self.event.settings.show_times = False
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertIn('DTSTART;VALUE=DATE:%s' % self.event.date_from.strftime('%Y%m%d'), ical, 'incorrect start date')
|
||||
self.assertNotIn('DTEND', ical, 'unexpected end time attribute')
|
||||
|
||||
@@ -667,10 +909,35 @@ class EventIcalDownloadTest(EventTestMixin, SoupTest):
|
||||
self.event.settings.timezone = 'Asia/Tokyo'
|
||||
self.event.settings.show_times = False
|
||||
self.event.save()
|
||||
ical = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
ical = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug)).content.decode()
|
||||
self.assertIn('DTSTART;VALUE=DATE:20131227', ical, 'incorrect start date')
|
||||
self.assertIn('DTEND;VALUE=DATE:20131229', ical, 'incorrect end date')
|
||||
|
||||
def test_subevent_required(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
resp = self.client.get('/%s/%s/ical/' % (self.orga.slug, self.event.slug))
|
||||
assert resp.status_code == 404
|
||||
resp = self.client.get('/%s/%s/ical/100/' % (self.orga.slug, self.event.slug))
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(
|
||||
name='My fancy subevent',
|
||||
location='Heeeeeere',
|
||||
date_from=datetime.datetime(2014, 12, 26, 21, 57, 58, tzinfo=datetime.timezone.utc),
|
||||
date_to=datetime.datetime(2014, 12, 28, 21, 57, 58, tzinfo=datetime.timezone.utc),
|
||||
active=True
|
||||
)
|
||||
self.event.settings.show_times = False
|
||||
ical = self.client.get('/%s/%s/ical/%d/' % (self.orga.slug, self.event.slug, se1.pk)).content.decode()
|
||||
self.assertIn('DTSTART;VALUE=DATE:20141226', ical, 'incorrect start date')
|
||||
self.assertIn('DTEND;VALUE=DATE:20141228', ical, 'incorrect end date')
|
||||
self.assertIn('SUMMARY:%s' % se1.name, ical, 'incorrect correct summary')
|
||||
self.assertIn('LOCATION:Heeeeeere', ical, 'incorrect location')
|
||||
|
||||
|
||||
class EventSlugBlacklistValidatorTest(EventTestMixin, SoupTest):
|
||||
def test_slug_validation(self):
|
||||
|
||||
@@ -9,6 +9,7 @@ from pretix.base.models import (
|
||||
Event, Item, ItemCategory, ItemVariation, Order, OrderPosition, Organizer,
|
||||
Question, Quota,
|
||||
)
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
|
||||
|
||||
@@ -350,6 +351,21 @@ class OrdersTest(TestCase):
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
|
||||
self.event.date_from = now() + datetime.timedelta(days=3)
|
||||
self.event.save()
|
||||
self.event.settings.set('ticket_download_date', RelativeDateWrapper(RelativeDate(
|
||||
base_date_name='date_from', days_before=2, time=None
|
||||
)))
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret, self.ticket_pos.pk),
|
||||
follow=True
|
||||
)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
|
||||
del self.event.settings['ticket_download_date']
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
from pytz import UTC
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
|
||||
@@ -95,3 +96,26 @@ def test_different_organizer_not_shown(env, client):
|
||||
)
|
||||
r = client.get('/mrmcd/')
|
||||
assert '32C3' not in r.rendered_content
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_calendar(env, client):
|
||||
env[0].settings.event_list_type = 'calendar'
|
||||
e = Event.objects.create(
|
||||
organizer=env[0], name='MRMCD2017', slug='2017',
|
||||
date_from=datetime(now().year + 1, 9, 1, tzinfo=UTC),
|
||||
live=True
|
||||
)
|
||||
r = client.get('/mrmcd/')
|
||||
assert 'MRMCD2017' not in r.rendered_content
|
||||
e.is_public = True
|
||||
e.save()
|
||||
r = client.get('/mrmcd/')
|
||||
assert 'MRMCD2017' in r.rendered_content
|
||||
assert 'September %d' % (now().year + 1) in r.rendered_content
|
||||
r = client.get('/mrmcd/events/2017/10/')
|
||||
assert 'MRMCD2017' not in r.rendered_content
|
||||
assert 'October 2017' in r.rendered_content
|
||||
r = client.get('/mrmcd/events/?month=10&year=2017')
|
||||
assert 'MRMCD2017' not in r.rendered_content
|
||||
assert 'October 2017' in r.rendered_content
|
||||
|
||||
Reference in New Issue
Block a user