mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +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:
@@ -45,3 +45,11 @@ def token_client(client, team):
|
||||
t = team.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
return client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def subevent(event):
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
return event.subevents.create(name="Foobar",
|
||||
date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
|
||||
|
||||
@@ -12,6 +12,7 @@ TEST_EVENT_RES = {
|
||||
"presale_end": None,
|
||||
"location": None,
|
||||
"slug": "dummy",
|
||||
"has_subevents": False,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -192,12 +192,13 @@ TEST_QUOTA_RES = {
|
||||
"name": "Budget Quota",
|
||||
"size": 200,
|
||||
"items": [],
|
||||
"variations": []
|
||||
"variations": [],
|
||||
"subevent": None
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_quota_list(token_client, organizer, event, quota, item):
|
||||
def test_quota_list(token_client, organizer, event, quota, item, subevent):
|
||||
res = dict(TEST_QUOTA_RES)
|
||||
res["id"] = quota.pk
|
||||
res["items"] = [item.pk]
|
||||
@@ -206,6 +207,16 @@ def test_quota_list(token_client, organizer, event, quota, item):
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
quota.subevent = subevent
|
||||
quota.save()
|
||||
res["subevent"] = subevent.pk
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, subevent.pk + 1))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_quota_detail(token_client, organizer, event, quota, item):
|
||||
|
||||
@@ -57,7 +57,8 @@ TEST_ORDERPOSITION_RES = {
|
||||
"addon_to": None,
|
||||
"checkins": [],
|
||||
"downloads": [],
|
||||
"answers": []
|
||||
"answers": [],
|
||||
"subevent": None
|
||||
}
|
||||
TEST_ORDER_RES = {
|
||||
"code": "FOO",
|
||||
@@ -142,7 +143,7 @@ def test_order_detail(token_client, organizer, event, order, item):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_orderposition_list(token_client, organizer, event, order, item):
|
||||
def test_orderposition_list(token_client, organizer, event, order, item, subevent):
|
||||
var = item.variations.create(value="Children")
|
||||
res = dict(TEST_ORDERPOSITION_RES)
|
||||
op = order.positions.first()
|
||||
@@ -206,12 +207,24 @@ def test_orderposition_list(token_client, organizer, event, order, item):
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
order.positions.first().checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=UTC))
|
||||
op.checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=UTC))
|
||||
res['checkins'] = [{'datetime': '2017-12-26T10:00:00Z'}]
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
op.subevent = subevent
|
||||
op.save()
|
||||
res['subevent'] = subevent.pk
|
||||
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
|
||||
subevent.pk + 1))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_orderposition_detail(token_client, organizer, event, order, item):
|
||||
|
||||
42
src/tests/api/test_subevents.py
Normal file
42
src/tests/api/test_subevents.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import pytest
|
||||
|
||||
TEST_SUBEVENT_RES = {
|
||||
'active': False,
|
||||
'presale_start': None,
|
||||
'date_to': None,
|
||||
'date_admission': None,
|
||||
'name': {'en': 'Foobar'},
|
||||
'date_from': '2017-12-27T10:00:00Z',
|
||||
'presale_end': None,
|
||||
'id': 1,
|
||||
'variation_price_overrides': [],
|
||||
'location': None,
|
||||
'item_price_overrides': []
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_subevent_list(token_client, organizer, event, subevent):
|
||||
res = dict(TEST_SUBEVENT_RES)
|
||||
res["id"] = subevent.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
print(dict(resp.data['results'][0]))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/subevents/?active=false'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/subevents/?active=true'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_subevent_detail(token_client, organizer, event, subevent):
|
||||
res = dict(TEST_SUBEVENT_RES)
|
||||
res["id"] = subevent.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug,
|
||||
subevent.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res == resp.data
|
||||
@@ -35,12 +35,13 @@ TEST_VOUCHER_RES = {
|
||||
'variation': None,
|
||||
'quota': None,
|
||||
'tag': 'Foo',
|
||||
'comment': ''
|
||||
'comment': '',
|
||||
'subevent': None
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_list(token_client, organizer, event, voucher, item, quota):
|
||||
def test_voucher_list(token_client, organizer, event, voucher, item, quota, subevent):
|
||||
res = dict(TEST_VOUCHER_RES)
|
||||
res['item'] = item.pk
|
||||
res['id'] = voucher.pk
|
||||
@@ -187,6 +188,18 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota):
|
||||
)
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
voucher.subevent = subevent
|
||||
voucher.save()
|
||||
res['subevent'] = subevent.pk
|
||||
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug,
|
||||
subevent.pk + 1))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_detail(token_client, organizer, event, voucher, item):
|
||||
|
||||
@@ -28,12 +28,13 @@ TEST_WLE_RES = {
|
||||
"voucher": None,
|
||||
"item": 2,
|
||||
"variation": None,
|
||||
"locale": "en"
|
||||
"locale": "en",
|
||||
"subevent": None,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_wle_list(token_client, organizer, event, wle, item):
|
||||
def test_wle_list(token_client, organizer, event, wle, item, subevent):
|
||||
var = item.variations.create(value="Children")
|
||||
res = dict(TEST_WLE_RES)
|
||||
wle.variation = var
|
||||
@@ -91,6 +92,18 @@ def test_wle_list(token_client, organizer, event, wle, item):
|
||||
'/api/v1/organizers/{}/events/{}/waitinglistentries/?has_voucher=true'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
wle.subevent = subevent
|
||||
wle.save()
|
||||
res['subevent'] = subevent.pk
|
||||
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug,
|
||||
subevent.pk + 1))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_wle_detail(token_client, organizer, event, wle, item):
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import datetime
|
||||
import sys
|
||||
from datetime import timedelta
|
||||
from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.storage import default_storage
|
||||
@@ -15,6 +16,9 @@ from pretix.base.models import (
|
||||
CachedFile, CartPosition, Event, Item, ItemCategory, ItemVariation, Order,
|
||||
OrderPosition, Organizer, Question, Quota, User, Voucher, WaitingListEntry,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services.orders import (
|
||||
OrderError, cancel_order, mark_order_paid, perform_order,
|
||||
)
|
||||
@@ -378,6 +382,64 @@ class QuotaTestCase(BaseQuotaTestCase):
|
||||
with self.assertNumQueries(1):
|
||||
self.assertEqual(self.var1.check_quotas(_cache=cache, count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
|
||||
|
||||
def test_subevent_isolation(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
|
||||
se2 = self.event.subevents.create(date_from=now(), name="SE 2")
|
||||
q1 = self.event.quotas.create(name="Q1", subevent=se1, size=50)
|
||||
q2 = self.event.quotas.create(name="Q2", subevent=se2, size=50)
|
||||
q1.items.add(self.item1)
|
||||
q2.items.add(self.item1)
|
||||
|
||||
# Create orders
|
||||
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
|
||||
expires=now() + timedelta(days=3),
|
||||
total=6)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se2, price=2)
|
||||
order = Order.objects.create(event=self.event, status=Order.STATUS_PENDING,
|
||||
expires=now() + timedelta(days=3),
|
||||
total=8)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, subevent=se2, price=2)
|
||||
|
||||
Voucher.objects.create(item=self.item1, event=self.event, valid_until=now() + timedelta(days=5),
|
||||
block_quota=True, max_usages=6, subevent=se1)
|
||||
Voucher.objects.create(item=self.item1, event=self.event, valid_until=now() + timedelta(days=5),
|
||||
block_quota=True, max_usages=4, subevent=se2)
|
||||
|
||||
for i in range(8):
|
||||
CartPosition.objects.create(event=self.event, item=self.item1, price=2, subevent=se1,
|
||||
expires=now() + timedelta(days=3))
|
||||
|
||||
for i in range(5):
|
||||
CartPosition.objects.create(event=self.event, item=self.item1, price=2, subevent=se2,
|
||||
expires=now() + timedelta(days=3))
|
||||
|
||||
for i in range(16):
|
||||
WaitingListEntry.objects.create(
|
||||
event=self.event, item=self.item1, email='foo@bar.com', subevent=se1
|
||||
)
|
||||
|
||||
for i in range(13):
|
||||
WaitingListEntry.objects.create(
|
||||
event=self.event, item=self.item1, email='foo@bar.com', subevent=se2
|
||||
)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
self.item1.check_quotas()
|
||||
|
||||
self.assertEqual(self.item1.check_quotas(subevent=se1), (Quota.AVAILABILITY_OK, 50 - 5 - 6 - 8 - 16))
|
||||
self.assertEqual(self.item1.check_quotas(subevent=se2), (Quota.AVAILABILITY_OK, 50 - 2 - 4 - 5 - 13))
|
||||
self.assertEqual(q1.availability(), (Quota.AVAILABILITY_OK, 50 - 5 - 6 - 8 - 16))
|
||||
self.assertEqual(q2.availability(), (Quota.AVAILABILITY_OK, 50 - 2 - 4 - 5 - 13))
|
||||
self.event.has_subevents = False
|
||||
self.event.save()
|
||||
|
||||
|
||||
class WaitingListTestCase(BaseQuotaTestCase):
|
||||
|
||||
@@ -496,27 +558,27 @@ class VoucherTestCase(BaseQuotaTestCase):
|
||||
|
||||
def test_calculate_price_none(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='none', value=Decimal('10.00'))
|
||||
v.calculate_price(Decimal('23.42')) == Decimal('23.42')
|
||||
assert v.calculate_price(Decimal('23.42')) == Decimal('23.42')
|
||||
|
||||
def test_calculate_price_set_empty(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='set')
|
||||
v.calculate_price(Decimal('23.42')) == Decimal('23.42')
|
||||
assert v.calculate_price(Decimal('23.42')) == Decimal('23.42')
|
||||
|
||||
def test_calculate_price_set(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('10.00'))
|
||||
v.calculate_price(Decimal('23.42')) == Decimal('10.00')
|
||||
assert v.calculate_price(Decimal('23.42')) == Decimal('10.00')
|
||||
|
||||
def test_calculate_price_set_zero(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('0.00'))
|
||||
v.calculate_price(Decimal('23.42')) == Decimal('0.00')
|
||||
assert v.calculate_price(Decimal('23.42')) == Decimal('0.00')
|
||||
|
||||
def test_calculate_price_subtract(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='subtract', value=Decimal('10.00'))
|
||||
v.calculate_price(Decimal('23.42')) == Decimal('13.42')
|
||||
assert v.calculate_price(Decimal('23.42')) == Decimal('13.42')
|
||||
|
||||
def test_calculate_price_percent(self):
|
||||
v = Voucher.objects.create(event=self.event, price_mode='percent', value=Decimal('23.00'))
|
||||
v.calculate_price(Decimal('100.00')) == Decimal('77.00')
|
||||
assert v.calculate_price(Decimal('100.00')) == Decimal('77.00')
|
||||
|
||||
|
||||
class OrderTestCase(BaseQuotaTestCase):
|
||||
@@ -529,10 +591,10 @@ class OrderTestCase(BaseQuotaTestCase):
|
||||
expires=now() + timedelta(days=5), total=46
|
||||
)
|
||||
self.quota.items.add(self.item1)
|
||||
OrderPosition.objects.create(order=self.order, item=self.item1,
|
||||
variation=None, price=23)
|
||||
OrderPosition.objects.create(order=self.order, item=self.item1,
|
||||
variation=None, price=23)
|
||||
self.op1 = OrderPosition.objects.create(order=self.order, item=self.item1,
|
||||
variation=None, price=23)
|
||||
self.op2 = OrderPosition.objects.create(order=self.order, item=self.item1,
|
||||
variation=None, price=23)
|
||||
|
||||
def test_paid_in_time(self):
|
||||
self.quota.size = 0
|
||||
@@ -560,6 +622,29 @@ class OrderTestCase(BaseQuotaTestCase):
|
||||
self.order = Order.objects.get(id=self.order.id)
|
||||
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
|
||||
|
||||
def test_paid_expired_after_last_date_subevent_relative(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
|
||||
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.op2.subevent = se2
|
||||
self.op2.save()
|
||||
self.event.settings.set('payment_term_last', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
|
||||
self.order.status = Order.STATUS_EXPIRED
|
||||
self.order.expires = now() - timedelta(days=2)
|
||||
self.order.save()
|
||||
with self.assertRaises(Quota.QuotaExceededException):
|
||||
mark_order_paid(self.order)
|
||||
self.order = Order.objects.get(id=self.order.id)
|
||||
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
|
||||
self.event.has_subevents = False
|
||||
self.event.save()
|
||||
|
||||
def test_paid_expired_late_not_allowed(self):
|
||||
self.event.settings.payment_term_accept_late = False
|
||||
self.order.status = Order.STATUS_EXPIRED
|
||||
@@ -615,6 +700,86 @@ class OrderTestCase(BaseQuotaTestCase):
|
||||
self.event.settings.set('last_order_modification_date', now() - timedelta(days=1))
|
||||
assert not self.order.can_modify_answers
|
||||
|
||||
def test_can_modify_answers_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
|
||||
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
|
||||
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.op2.subevent = se2
|
||||
self.op2.save()
|
||||
self.event.settings.set('last_order_modification_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert self.order.can_modify_answers
|
||||
self.op2.subevent = se3
|
||||
self.op2.save()
|
||||
assert not self.order.can_modify_answers
|
||||
self.event.has_subevents = False
|
||||
self.event.save()
|
||||
|
||||
def test_payment_term_last_relative(self):
|
||||
self.event.settings.set('payment_term_last', date(2017, 5, 3))
|
||||
assert self.order.payment_term_last == datetime.datetime(2017, 5, 3, 23, 59, 59, tzinfo=pytz.UTC)
|
||||
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=pytz.UTC)
|
||||
self.event.save()
|
||||
self.event.settings.set('payment_term_last', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert self.order.payment_term_last == datetime.datetime(2017, 5, 1, 23, 59, 59, tzinfo=pytz.UTC)
|
||||
|
||||
def test_payment_term_last_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
|
||||
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
|
||||
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.op2.subevent = se2
|
||||
self.op2.save()
|
||||
self.event.settings.set('payment_term_last', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert self.order.payment_term_last > now()
|
||||
self.op2.subevent = se3
|
||||
self.op2.save()
|
||||
assert self.order.payment_term_last < now()
|
||||
self.event.has_subevents = False
|
||||
self.event.save()
|
||||
|
||||
def test_ticket_download_date_relative(self):
|
||||
self.event.settings.set('ticket_download_date', datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC))
|
||||
assert self.order.ticket_download_date == datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC)
|
||||
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=pytz.UTC)
|
||||
self.event.save()
|
||||
self.event.settings.set('ticket_download_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert self.order.ticket_download_date == datetime.datetime(2017, 5, 1, 12, 0, 0, tzinfo=pytz.UTC)
|
||||
|
||||
def test_ticket_download_date_subevent(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
|
||||
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
|
||||
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.op2.subevent = se2
|
||||
self.op2.save()
|
||||
self.event.settings.set('ticket_download_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert self.order.ticket_download_date > now()
|
||||
self.op2.subevent = se3
|
||||
self.op2.save()
|
||||
assert self.order.ticket_download_date < now()
|
||||
self.event.has_subevents = False
|
||||
self.event.save()
|
||||
|
||||
def test_can_cancel_order(self):
|
||||
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
|
||||
admission=True, allow_cancel=True)
|
||||
@@ -771,6 +936,41 @@ class EventTest(TestCase):
|
||||
self.assertIn('slug', str(context.exception))
|
||||
|
||||
|
||||
class SubEventTest(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
cls.event = Event.objects.create(
|
||||
organizer=cls.organizer, name='Dummy', slug='dummy',
|
||||
date_from=now(), date_to=now() - timedelta(hours=1),
|
||||
has_subevents=True
|
||||
)
|
||||
cls.se = SubEvent.objects.create(
|
||||
name='Testsub', date_from=now(), event=cls.event
|
||||
)
|
||||
|
||||
def test_override_prices(self):
|
||||
i = Item.objects.create(
|
||||
event=self.event, name="Ticket", default_price=23,
|
||||
active=True, available_until=now() + timedelta(days=1),
|
||||
)
|
||||
SubEventItem.objects.create(item=i, subevent=self.se, price=Decimal('30.00'))
|
||||
assert self.se.item_price_overrides == {
|
||||
i.pk: Decimal('30.00')
|
||||
}
|
||||
|
||||
def test_override_var_prices(self):
|
||||
i = Item.objects.create(
|
||||
event=self.event, name="Ticket", default_price=23,
|
||||
active=True, available_until=now() + timedelta(days=1),
|
||||
)
|
||||
v = i.variations.create(value='Type 1')
|
||||
SubEventItemVariation.objects.create(variation=v, subevent=self.se, price=Decimal('30.00'))
|
||||
assert self.se.var_price_overrides == {
|
||||
v.pk: Decimal('30.00')
|
||||
}
|
||||
|
||||
|
||||
class CachedFileTestCase(TestCase):
|
||||
def test_file_handling(self):
|
||||
cf = CachedFile()
|
||||
|
||||
@@ -7,8 +7,12 @@ from django.test import TestCase
|
||||
from django.utils.timezone import make_aware, now
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import Event, Item, Order, OrderPosition, Organizer
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Item, Order, OrderPosition, Organizer,
|
||||
)
|
||||
from pretix.base.models.items import SubEventItem
|
||||
from pretix.base.payment import FreeOrderProvider
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, _create_order, expire_orders,
|
||||
)
|
||||
@@ -71,6 +75,52 @@ def test_expiry_last(event):
|
||||
assert (order.expires - today).days == 5
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expiry_last_relative(event):
|
||||
today = now()
|
||||
event.settings.set('payment_term_days', 5)
|
||||
event.settings.set('payment_term_weekdays', False)
|
||||
event.date_from = now() + timedelta(days=5)
|
||||
event.save()
|
||||
event.settings.set('payment_term_last', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
order = _create_order(event, email='dummy@example.org', positions=[],
|
||||
now_dt=today, payment_provider=FreeOrderProvider(event),
|
||||
locale='de')
|
||||
assert (order.expires - today).days == 3
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expiry_last_relative_subevents(event):
|
||||
today = now()
|
||||
event.settings.set('payment_term_days', 100)
|
||||
event.settings.set('payment_term_weekdays', False)
|
||||
event.date_from = now() + timedelta(days=5)
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
|
||||
se1 = event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
|
||||
se2 = event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
|
||||
|
||||
cp1 = CartPosition.objects.create(
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), subevent=se1, event=event, cart_id="123"
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), subevent=se2, event=event, cart_id="123"
|
||||
)
|
||||
|
||||
event.settings.set('payment_term_last', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
order = _create_order(event, email='dummy@example.org', positions=[cp1, cp2],
|
||||
now_dt=today, payment_provider=FreeOrderProvider(event),
|
||||
locale='de')
|
||||
assert (order.expires - today).days == 6
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expiry_dst(event):
|
||||
event.settings.set('timezone', 'Europe/Berlin')
|
||||
@@ -153,6 +203,63 @@ class OrderChangeManagerTests(TestCase):
|
||||
price=Decimal("23.00"), attendee_name="Dieter", positionid=2
|
||||
)
|
||||
self.ocm = OrderChangeManager(self.order, None)
|
||||
self.quota = self.event.quotas.create(name='Test', size=None)
|
||||
self.quota.items.add(self.ticket)
|
||||
self.quota.items.add(self.ticket2)
|
||||
self.quota.items.add(self.shirt)
|
||||
|
||||
def test_change_subevent_quota_required(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event.subevents.create(name="Bar", date_from=now())
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.quota.subevent = se1
|
||||
self.quota.save()
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.change_subevent(self.op1, se2)
|
||||
|
||||
def test_change_subevent_success(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event.subevents.create(name="Bar", date_from=now())
|
||||
SubEventItem.objects.create(subevent=se2, item=self.ticket, price=12)
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.quota.subevent = se2
|
||||
self.quota.save()
|
||||
|
||||
self.ocm.change_subevent(self.op1, se2)
|
||||
self.ocm.commit()
|
||||
self.op1.refresh_from_db()
|
||||
self.order.refresh_from_db()
|
||||
assert self.op1.subevent == se2
|
||||
assert self.op1.price == 12
|
||||
assert self.order.total == self.op1.price + self.op2.price
|
||||
|
||||
def test_change_subevent_sold_out(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event.subevents.create(name="Bar", date_from=now())
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.quota.subevent = se2
|
||||
self.quota.size = 0
|
||||
self.quota.save()
|
||||
|
||||
self.ocm.change_subevent(self.op1, se2)
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.commit()
|
||||
self.op1.refresh_from_db()
|
||||
assert self.op1.subevent == se1
|
||||
|
||||
def test_change_item_quota_required(self):
|
||||
self.quota.delete()
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.change_item(self.op1, self.shirt, None)
|
||||
|
||||
def test_change_item_success(self):
|
||||
self.ocm.change_item(self.op1, self.shirt, None)
|
||||
@@ -325,6 +432,11 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert self.order.total == 46
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
|
||||
def test_add_item_quota_required(self):
|
||||
self.quota.delete()
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.add_position(self.shirt, None, None, None)
|
||||
|
||||
def test_add_item_success(self):
|
||||
self.ocm.add_position(self.shirt, None, None, None)
|
||||
self.ocm.commit()
|
||||
@@ -375,3 +487,26 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True)
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.add_position(self.shirt, None, Decimal('13.00'), None)
|
||||
|
||||
def test_add_item_subevent_required(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.add_position(self.ticket, None, None, None)
|
||||
|
||||
def test_add_item_subevent_price(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
SubEventItem.objects.create(subevent=se1, item=self.ticket, price=12)
|
||||
self.quota.subevent = se1
|
||||
self.quota.save()
|
||||
|
||||
self.ocm.add_position(self.ticket, None, None, subevent=se1)
|
||||
self.ocm.commit()
|
||||
self.order.refresh_from_db()
|
||||
assert self.order.positions.count() == 3
|
||||
nop = self.order.positions.last()
|
||||
assert nop.item == self.ticket
|
||||
assert nop.price == Decimal('12.00')
|
||||
assert nop.subevent == se1
|
||||
|
||||
@@ -6,7 +6,10 @@ import pytz
|
||||
from django.utils.timezone import now
|
||||
from tests.testdummy.payment import DummyPaymentProvider
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Item, Order, OrderPosition, Organizer,
|
||||
)
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -70,6 +73,23 @@ def test_availability_date_not_available(event):
|
||||
assert not result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_availability_date_relative(event):
|
||||
event.settings.set('timezone', 'US/Pacific')
|
||||
tz = pytz.timezone('US/Pacific')
|
||||
event.date_from = tz.localize(datetime.datetime(2016, 12, 3, 12, 0, 0))
|
||||
event.save()
|
||||
prov = DummyPaymentProvider(event)
|
||||
prov.settings.set('_availability_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=2, time=None, base_date_name='date_from')
|
||||
))
|
||||
|
||||
utc = pytz.timezone('UTC')
|
||||
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 11, 30, 23, 0, 0)).astimezone(utc))
|
||||
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 1, 23, 59, 0)).astimezone(utc))
|
||||
assert not prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 2, 0, 0, 1)).astimezone(utc))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_availability_date_timezones(event):
|
||||
event.settings.set('timezone', 'US/Pacific')
|
||||
@@ -81,3 +101,71 @@ def test_availability_date_timezones(event):
|
||||
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 11, 30, 23, 0, 0)).astimezone(utc))
|
||||
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 1, 23, 59, 0)).astimezone(utc))
|
||||
assert not prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 2, 0, 0, 1)).astimezone(utc))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_availability_date_cart_relative_subevents(event):
|
||||
event.date_from = now() + datetime.timedelta(days=5)
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
|
||||
se1 = event.subevents.create(name="SE1", date_from=now() + datetime.timedelta(days=10))
|
||||
se2 = event.subevents.create(name="SE2", date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
CartPosition.objects.create(
|
||||
item=ticket, price=23, expires=now() + datetime.timedelta(days=1), subevent=se1, event=event, cart_id="123"
|
||||
)
|
||||
CartPosition.objects.create(
|
||||
item=ticket, price=23, expires=now() + datetime.timedelta(days=1), subevent=se2, event=event, cart_id="123"
|
||||
)
|
||||
|
||||
prov = DummyPaymentProvider(event)
|
||||
prov.settings.set('_availability_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=3, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert prov._is_still_available(cart_id="123")
|
||||
|
||||
prov.settings.set('_availability_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=4, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert not prov._is_still_available(cart_id="123")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_availability_date_order_relative_subevents(event):
|
||||
event.date_from = now() + datetime.timedelta(days=5)
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
|
||||
se1 = event.subevents.create(name="SE1", date_from=now() + datetime.timedelta(days=10))
|
||||
se2 = event.subevents.create(name="SE2", date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
order = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + datetime.timedelta(days=10),
|
||||
total=Decimal('46.00'), payment_provider='dummtest'
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=order, item=ticket, variation=None, subevent=se1,
|
||||
price=Decimal("23.00"), attendee_name="Peter", positionid=1
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=order, item=ticket, variation=None, subevent=se2,
|
||||
price=Decimal("23.00"), attendee_name="Dieter", positionid=2
|
||||
)
|
||||
|
||||
prov = DummyPaymentProvider(event)
|
||||
prov.settings.set('_availability_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=3, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert prov._is_still_available(order=order)
|
||||
|
||||
prov.settings.set('_availability_date', RelativeDateWrapper(
|
||||
RelativeDate(days_before=4, time=None, base_date_name='date_from')
|
||||
))
|
||||
assert not prov._is_still_available(order=order)
|
||||
|
||||
195
src/tests/base/test_pricing.py
Normal file
195
src/tests/base/test_pricing.py
Normal file
@@ -0,0 +1,195 @@
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
||||
from pretix.base.services.pricing import get_price
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event():
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now()
|
||||
)
|
||||
return event
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def item(event):
|
||||
return event.items.create(name='Ticket', default_price=Decimal('23.00'))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def variation(item):
|
||||
return item.variations.create(value='Premium', default_price=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def voucher(event):
|
||||
return event.vouchers.create()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def subevent(event):
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
return event.subevents.create(name='Foobar', date_from=now())
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_base_item_default(item):
|
||||
assert get_price(item) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_base_item_subevent_no_entry(item, subevent):
|
||||
assert get_price(item, subevent=subevent) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_base_item_subevent_no_override(item, subevent):
|
||||
SubEventItem.objects.create(item=item, subevent=subevent, price=None)
|
||||
assert get_price(item, subevent=subevent) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_base_item_subevent_override(item, subevent):
|
||||
SubEventItem.objects.create(item=item, subevent=subevent, price=Decimal('24.00'))
|
||||
assert get_price(item, subevent=subevent) == Decimal('24.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_default_item_price(item, variation):
|
||||
assert get_price(item, variation=variation) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_specific_price(item, variation):
|
||||
variation.default_price = Decimal('24.00')
|
||||
assert get_price(item, variation=variation) == Decimal('24.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_default_subevent_and_default_price(item, subevent, variation):
|
||||
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=None)
|
||||
assert get_price(item, variation=variation, subevent=subevent) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_subevent_and_default_price(item, subevent, variation):
|
||||
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=Decimal('24.00'))
|
||||
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_no_subevent_and_specific_price(item, subevent, variation):
|
||||
variation.default_price = Decimal('24.00')
|
||||
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_default_subevent_and_specific_price(item, subevent, variation):
|
||||
variation.default_price = Decimal('24.00')
|
||||
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=None)
|
||||
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variation_with_subevent_and_specific_price(item, subevent, variation):
|
||||
variation.default_price = Decimal('24.00')
|
||||
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=Decimal('26.00'))
|
||||
assert get_price(item, variation=variation, subevent=subevent) == Decimal('26.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_no_override(item, subevent, voucher):
|
||||
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_set_price(item, subevent, voucher):
|
||||
voucher.price_mode = 'set'
|
||||
voucher.value = Decimal('12.00')
|
||||
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('12.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_subtract(item, subevent, voucher):
|
||||
voucher.price_mode = 'subtract'
|
||||
voucher.value = Decimal('12.00')
|
||||
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('11.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_voucher_percent(item, subevent, voucher):
|
||||
voucher.price_mode = 'percent'
|
||||
voucher.value = Decimal('10.00')
|
||||
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('20.70')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_ignored_if_disabled(item):
|
||||
assert get_price(item, custom_price=Decimal('42.00')) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_ignored_if_lower(item):
|
||||
item.free_price = True
|
||||
assert get_price(item, custom_price=Decimal('12.00')) == Decimal('23.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_ignored_if_lower_than_voucher(item, voucher):
|
||||
voucher.price_mode = 'set'
|
||||
voucher.value = Decimal('50.00')
|
||||
assert get_price(item, voucher=voucher, custom_price=Decimal('40.00')) == Decimal('50.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_ignored_if_lower_than_subevent(item, subevent):
|
||||
item.free_price = True
|
||||
SubEventItem.objects.create(item=item, subevent=subevent, price=Decimal('50.00'))
|
||||
assert get_price(item, subevent=subevent, custom_price=Decimal('40.00')) == Decimal('50.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_ignored_if_lower_than_variation(item, variation):
|
||||
variation.default_price = Decimal('50.00')
|
||||
item.free_price = True
|
||||
assert get_price(item, variation=variation, custom_price=Decimal('40.00')) == Decimal('50.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_accepted(item):
|
||||
item.free_price = True
|
||||
assert get_price(item, custom_price=Decimal('42.00')) == Decimal('42.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_string(item):
|
||||
item.free_price = True
|
||||
assert get_price(item, custom_price='42,00') == Decimal('42.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_float(item):
|
||||
item.free_price = True
|
||||
assert get_price(item, custom_price=42.00) == Decimal('42.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_limit(item):
|
||||
item.free_price = True
|
||||
with pytest.raises(ValueError):
|
||||
get_price(item, custom_price=Decimal('200000000'))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_free_price_net(item):
|
||||
item.free_price = True
|
||||
item.tax_rate = 19
|
||||
assert get_price(item, custom_price=Decimal('100.00'), custom_price_is_net=True) == Decimal('119.00')
|
||||
82
src/tests/base/test_reldate.py
Normal file
82
src/tests/base/test_reldate.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from datetime import datetime, time
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
|
||||
TOKYO = pytz.timezone('Asia/Tokyo')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event():
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=datetime(2017, 12, 27, 5, 0, 0, tzinfo=TOKYO),
|
||||
presale_start=datetime(2017, 12, 1, 5, 0, 0, tzinfo=TOKYO),
|
||||
plugins='pretix.plugins.banktransfer'
|
||||
|
||||
)
|
||||
event.settings.timezone = "Asia/Tokyo"
|
||||
return event
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_absolute_date(event):
|
||||
d = datetime(2017, 12, 25, 5, 0, 0, tzinfo=TOKYO)
|
||||
rdw = RelativeDateWrapper(d)
|
||||
assert rdw.datetime(event) == d
|
||||
assert rdw.to_string() == d.isoformat()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relative_date_without_time(event):
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from'))
|
||||
assert rdw.datetime(event).astimezone(TOKYO) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO)
|
||||
assert rdw.to_string() == 'RELDATE/1/-/date_from/'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relative_date_other_base_point(event):
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start'))
|
||||
assert rdw.datetime(event) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO)
|
||||
assert rdw.to_string() == 'RELDATE/1/-/presale_start/'
|
||||
|
||||
# presale_end is unset, defaults to date_from
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end'))
|
||||
assert rdw.datetime(event) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO)
|
||||
assert rdw.to_string() == 'RELDATE/1/-/presale_end/'
|
||||
|
||||
# subevent base
|
||||
se = event.subevents.create(name="SE1", date_from=datetime(2017, 11, 27, 5, 0, 0, tzinfo=TOKYO))
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from'))
|
||||
assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO)
|
||||
|
||||
# presale_start is unset on subevent, default to event
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start'))
|
||||
assert rdw.datetime(se) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO)
|
||||
|
||||
# presale_end is unset on all, default to date_from of subevent
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end'))
|
||||
assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relative_date_with_time(event):
|
||||
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=time(8, 5, 13), base_date_name='date_from'))
|
||||
assert rdw.to_string() == 'RELDATE/1/08:05:13/date_from/'
|
||||
assert rdw.datetime(event) == datetime(2017, 12, 26, 8, 5, 13, tzinfo=TOKYO)
|
||||
|
||||
|
||||
def test_unserialize():
|
||||
d = datetime(2017, 12, 25, 10, 0, 0, tzinfo=TOKYO)
|
||||
rdw = RelativeDateWrapper.from_string(d.isoformat())
|
||||
assert rdw.data == d
|
||||
|
||||
rdw = RelativeDateWrapper.from_string('RELDATE/1/-/date_from/')
|
||||
assert rdw.data == RelativeDate(days_before=1, time=None, base_date_name='date_from')
|
||||
|
||||
rdw = RelativeDateWrapper.from_string('RELDATE/1/18:05:13/date_from/')
|
||||
assert rdw.data == RelativeDate(days_before=1, time=time(18, 5, 13), base_date_name='date_from')
|
||||
@@ -2,11 +2,15 @@ import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import pytz
|
||||
from django.utils.timezone import now
|
||||
from i18nfield.strings import LazyI18nString
|
||||
from pytz import timezone
|
||||
from tests.base import SoupTest, extract_form_fields
|
||||
|
||||
from pretix.base.models import Event, Organizer, Team, User
|
||||
from pretix.base.models import (
|
||||
Event, Order, OrderPosition, Organizer, Team, User,
|
||||
)
|
||||
from pretix.base.models.items import SubEventItem
|
||||
from pretix.testutils.mock import mocker_context
|
||||
|
||||
|
||||
@@ -164,7 +168,10 @@ class EventsTest(SoupTest):
|
||||
'payment_banktransfer__fee_abs': '12.23',
|
||||
'payment_banktransfer_bank_details_0': 'Test',
|
||||
'settings-payment_term_days': '2',
|
||||
'settings-payment_term_last': (self.event1.presale_end - datetime.timedelta(1)).strftime('%Y-%m-%d'),
|
||||
'settings-payment_term_last_0': 'absolute',
|
||||
'settings-payment_term_last_1': (self.event1.presale_end - datetime.timedelta(1)).strftime('%Y-%m-%d'),
|
||||
'settings-payment_term_last_2': '0',
|
||||
'settings-payment_term_last_3': 'date_from',
|
||||
'settings-tax_rate_default': '19.00',
|
||||
})
|
||||
assert doc.select('.alert-danger')
|
||||
@@ -327,6 +334,41 @@ class EventsTest(SoupTest):
|
||||
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
|
||||
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
|
||||
|
||||
def test_create_event_with_subevents_success(self):
|
||||
doc = self.get_doc('/control/events/add')
|
||||
tabletext = doc.select("form")[0].text
|
||||
self.assertIn("CCC", tabletext)
|
||||
self.assertNotIn("MRM", tabletext)
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'foundation',
|
||||
'foundation-organizer': self.orga1.pk,
|
||||
'foundation-locales': ('en', 'de'),
|
||||
'foundation-has_subevents': 'on',
|
||||
})
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'basics',
|
||||
'basics-name_0': '33C3',
|
||||
'basics-name_1': '33C3',
|
||||
'basics-slug': '33c3',
|
||||
'basics-date_from': '2016-12-27 10:00:00',
|
||||
'basics-date_to': '2016-12-30 19:00:00',
|
||||
'basics-location_0': 'Hamburg',
|
||||
'basics-location_1': 'Hamburg',
|
||||
'basics-currency': 'EUR',
|
||||
'basics-locale': 'en',
|
||||
'basics-timezone': 'Europe/Berlin',
|
||||
'basics-presale_start': '2016-11-01 10:00:00',
|
||||
'basics-presale_end': '2016-11-30 18:00:00',
|
||||
})
|
||||
self.post_doc('/control/events/add', {
|
||||
'event_wizard-current_step': 'copy',
|
||||
'copy-copy_from_event': ''
|
||||
})
|
||||
ev = Event.objects.get(slug='33c3')
|
||||
assert ev.has_subevents
|
||||
assert ev.subevents.count() == 1
|
||||
|
||||
def test_create_event_only_date_from(self):
|
||||
# date_to, presale_start & presale_end are optional fields
|
||||
self.post_doc('/control/events/add', {
|
||||
@@ -431,3 +473,132 @@ class EventsTest(SoupTest):
|
||||
'basics-presale_end': '2016-11-30 18:00:00',
|
||||
})
|
||||
assert doc.select(".alert-danger")
|
||||
|
||||
|
||||
class SubEventsTest(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.event1 = Event.objects.create(
|
||||
organizer=self.orga1, name='30C3', slug='30c3',
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
plugins='pretix.plugins.banktransfer,tests.testdummy',
|
||||
has_subevents=True
|
||||
)
|
||||
|
||||
t = Team.objects.create(organizer=self.orga1, can_create_events=True, can_change_event_settings=True,
|
||||
can_change_items=True)
|
||||
t.members.add(self.user)
|
||||
t.limit_events.add(self.event1)
|
||||
self.ticket = self.event1.items.create(name='Early-bird ticket',
|
||||
category=None, default_price=23,
|
||||
admission=True)
|
||||
|
||||
self.client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
self.subevent1 = self.event1.subevents.create(name='SE1', date_from=now())
|
||||
|
||||
def test_list(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/')
|
||||
tabletext = doc.select("#page-wrapper .table")[0].text
|
||||
self.assertIn("SE1", tabletext)
|
||||
|
||||
def test_create(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/add')
|
||||
assert doc.select("input[name=quotas-TOTAL_FORMS]")
|
||||
doc = self.post_doc('/control/event/ccc/30c3/subevents/add', {
|
||||
'name_0': 'SE2',
|
||||
'active': 'on',
|
||||
'date_from': '2017-07-01 10:00:00',
|
||||
'date_to': '2017-07-01 12:00:00',
|
||||
'location_0': 'Hamburg',
|
||||
'presale_start': '2017-06-20 10:00:00',
|
||||
'quotas-TOTAL_FORMS': '1',
|
||||
'quotas-INITIAL_FORMS': '0',
|
||||
'quotas-MIN_NUM_FORMS': '0',
|
||||
'quotas-MAX_NUM_FORMS': '1000',
|
||||
'quotas-0-name': 'Q1',
|
||||
'quotas-0-size': '50',
|
||||
'quotas-0-itemvars': str(self.ticket.pk),
|
||||
'item-%d-price' % self.ticket.pk: '12'
|
||||
})
|
||||
assert doc.select(".alert-success")
|
||||
se = self.event1.subevents.first()
|
||||
assert str(se.name) == "SE2"
|
||||
assert se.active
|
||||
assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00"
|
||||
assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00"
|
||||
assert str(se.location) == "Hamburg"
|
||||
assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00"
|
||||
assert not se.presale_end
|
||||
assert se.quotas.count() == 1
|
||||
q = se.quotas.last()
|
||||
assert q.name == "Q1"
|
||||
assert q.size == 50
|
||||
assert list(q.items.all()) == [self.ticket]
|
||||
sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
|
||||
assert sei.price == 12
|
||||
|
||||
def test_modify(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk)
|
||||
assert doc.select("input[name=quotas-TOTAL_FORMS]")
|
||||
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk, {
|
||||
'name_0': 'SE2',
|
||||
'active': 'on',
|
||||
'date_from': '2017-07-01 10:00:00',
|
||||
'date_to': '2017-07-01 12:00:00',
|
||||
'location_0': 'Hamburg',
|
||||
'presale_start': '2017-06-20 10:00:00',
|
||||
'quotas-TOTAL_FORMS': '1',
|
||||
'quotas-INITIAL_FORMS': '0',
|
||||
'quotas-MIN_NUM_FORMS': '0',
|
||||
'quotas-MAX_NUM_FORMS': '1000',
|
||||
'quotas-0-name': 'Q1',
|
||||
'quotas-0-size': '50',
|
||||
'quotas-0-itemvars': str(self.ticket.pk),
|
||||
'item-%d-price' % self.ticket.pk: '12'
|
||||
})
|
||||
assert doc.select(".alert-success")
|
||||
self.subevent1.refresh_from_db()
|
||||
se = self.subevent1
|
||||
assert str(se.name) == "SE2"
|
||||
assert se.active
|
||||
assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00"
|
||||
assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00"
|
||||
assert str(se.location) == "Hamburg"
|
||||
assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00"
|
||||
assert not se.presale_end
|
||||
assert se.quotas.count() == 1
|
||||
q = se.quotas.last()
|
||||
assert q.name == "Q1"
|
||||
assert q.size == 50
|
||||
assert list(q.items.all()) == [self.ticket]
|
||||
sei = SubEventItem.objects.get(subevent=se, item=self.ticket)
|
||||
assert sei.price == 12
|
||||
|
||||
def test_delete(self):
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk)
|
||||
assert doc.select("button")
|
||||
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, {})
|
||||
assert doc.select(".alert-success")
|
||||
assert not SubEventItem.objects.filter(pk=self.subevent1.pk).exists()
|
||||
|
||||
def test_delete_with_orders(self):
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=self.event1, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + datetime.timedelta(days=10),
|
||||
total=14, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
OrderPosition.objects.create(
|
||||
order=o,
|
||||
item=self.ticket,
|
||||
subevent=self.subevent1,
|
||||
price=Decimal("14"),
|
||||
)
|
||||
doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, follow=True)
|
||||
assert doc.select(".alert-danger")
|
||||
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, {}, follow=True)
|
||||
assert doc.select(".alert-danger")
|
||||
assert self.event1.subevents.filter(pk=self.subevent1.pk).exists()
|
||||
|
||||
@@ -231,7 +231,7 @@ class QuotaTest(ItemFormTest):
|
||||
ItemVariation.objects.create(item=item2, value="Silver")
|
||||
ItemVariation.objects.create(item=item2, value="Gold")
|
||||
doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
doc.select('[name=item_%s]' % item1.id)[0]['checked'] = 'checked'
|
||||
[i for i in doc.select('[name=itemvars]') if i.get('value') == str(item1.id)][0]['checked'] = 'checked'
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['size'] = '350'
|
||||
doc = self.post_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
|
||||
@@ -242,6 +242,19 @@ class QuotaTest(ItemFormTest):
|
||||
assert Quota.objects.get(id=c.id).size == 350
|
||||
assert item1 in Quota.objects.get(id=c.id).items.all()
|
||||
|
||||
def test_update_subevent(self):
|
||||
self.event1.has_subevents = True
|
||||
self.event1.save()
|
||||
se1 = self.event1.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event1.subevents.create(name="Bar", date_from=now())
|
||||
c = Quota.objects.create(event=self.event1, name="Full house", size=500, subevent=se1)
|
||||
doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['subevent'] = se2.pk
|
||||
self.post_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id),
|
||||
form_data)
|
||||
assert Quota.objects.get(id=c.id).subevent == se2
|
||||
|
||||
def test_delete(self):
|
||||
c = Quota.objects.create(event=self.event1, name="Full house", size=500)
|
||||
doc = self.get_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
|
||||
@@ -476,6 +476,9 @@ class OrderChangeTests(SoupTest):
|
||||
order=self.order, item=self.ticket, variation=None,
|
||||
price=Decimal("23.00"), attendee_name="Dieter"
|
||||
)
|
||||
self.quota = self.event.quotas.create(name="All", size=100)
|
||||
self.quota.items.add(self.ticket)
|
||||
self.quota.items.add(self.shirt)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
t = Team.objects.create(organizer=o, can_view_orders=True, can_change_orders=True)
|
||||
t.members.add(user)
|
||||
@@ -499,6 +502,38 @@ class OrderChangeTests(SoupTest):
|
||||
assert self.op1.tax_rate == self.shirt.tax_rate
|
||||
assert self.order.total == self.op1.price + self.op2.price
|
||||
|
||||
def test_change_subevent_success(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = self.event.subevents.create(name='Bar', date_from=now())
|
||||
self.op1.subevent = se1
|
||||
self.op1.save()
|
||||
self.op2.subevent = se1
|
||||
self.op2.save()
|
||||
self.quota.subevent = se1
|
||||
self.quota.save()
|
||||
q2 = self.event.quotas.create(name='Q2', size=100, subevent=se2)
|
||||
q2.items.add(self.ticket)
|
||||
q2.items.add(self.shirt)
|
||||
self.client.post('/control/event/{}/{}/orders/{}/change'.format(
|
||||
self.event.organizer.slug, self.event.slug, self.order.code
|
||||
), {
|
||||
'op-{}-operation'.format(self.op1.pk): 'subevent',
|
||||
'op-{}-subevent'.format(self.op1.pk): str(se2.pk),
|
||||
'op-{}-itemvar'.format(self.op1.pk): str(self.ticket.pk),
|
||||
'op-{}-operation'.format(self.op2.pk): '',
|
||||
'op-{}-itemvar'.format(self.op2.pk): str(self.ticket.pk),
|
||||
'op-{}-subevent'.format(self.op2.pk): str(se1.pk),
|
||||
'add-itemvar'.format(self.op2.pk): str(self.ticket.pk),
|
||||
'add-subevent'.format(self.op2.pk): str(se1.pk),
|
||||
})
|
||||
self.op1.refresh_from_db()
|
||||
self.op2.refresh_from_db()
|
||||
self.order.refresh_from_db()
|
||||
assert self.op1.subevent == se2
|
||||
assert self.op2.subevent == se1
|
||||
|
||||
def test_change_price_success(self):
|
||||
self.client.post('/control/event/{}/{}/orders/{}/change'.format(
|
||||
self.event.organizer.slug, self.event.slug, self.order.code
|
||||
|
||||
@@ -64,6 +64,10 @@ event_urls = [
|
||||
"vouchers/add",
|
||||
"vouchers/bulk_add",
|
||||
"vouchers/rng",
|
||||
"subevents/",
|
||||
"subevents/add",
|
||||
"subevents/2/delete",
|
||||
"subevents/2/",
|
||||
"quotas/",
|
||||
"quotas/2/delete",
|
||||
"quotas/2/change",
|
||||
@@ -182,6 +186,10 @@ event_permission_urls = [
|
||||
("can_change_items", "quotas/2/change", 404),
|
||||
("can_change_items", "quotas/2/delete", 404),
|
||||
("can_change_items", "quotas/add", 200),
|
||||
("can_change_event_settings", "subevents/", 200),
|
||||
("can_change_event_settings", "subevents/2/", 404),
|
||||
("can_change_event_settings", "subevents/2/delete", 404),
|
||||
("can_change_event_settings", "subevents/add", 200),
|
||||
("can_view_orders", "orders/overview/", 200),
|
||||
("can_view_orders", "orders/export/", 200),
|
||||
("can_view_orders", "orders/", 200),
|
||||
|
||||
@@ -425,3 +425,53 @@ class VoucherFormTest(SoupTest):
|
||||
doc = self.post_doc('/control/event/%s/%s/vouchers/%s/delete' % (self.orga.slug, self.event.slug, v.pk),
|
||||
{}, follow=True)
|
||||
assert doc.select(".alert-danger")
|
||||
|
||||
def test_subevent_optional(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self._create_voucher({
|
||||
'itemvar': '%d' % self.ticket.pk,
|
||||
})
|
||||
|
||||
def test_subevent_required_for_blocking(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self._create_voucher({
|
||||
'itemvar': '%d' % self.ticket.pk,
|
||||
'block_quota': 'on'
|
||||
}, expected_failure=True)
|
||||
|
||||
def test_subevent_blocking_quota_free(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event.subevents.create(name="Bar", date_from=now())
|
||||
|
||||
self.quota_tickets.subevent = se1
|
||||
self.quota_tickets.save()
|
||||
q2 = Quota.objects.create(event=self.event, name='Tickets', size=0, subevent=se2)
|
||||
q2.items.add(self.ticket)
|
||||
|
||||
self._create_voucher({
|
||||
'itemvar': '%d' % self.ticket.pk,
|
||||
'block_quota': 'on',
|
||||
'subevent': se1.pk
|
||||
})
|
||||
|
||||
def test_subevent_blocking_quota_full(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se1 = self.event.subevents.create(name="Foo", date_from=now())
|
||||
se2 = self.event.subevents.create(name="Bar", date_from=now())
|
||||
|
||||
self.quota_tickets.subevent = se1
|
||||
self.quota_tickets.size = 0
|
||||
self.quota_tickets.save()
|
||||
q2 = Quota.objects.create(event=self.event, name='Tickets', size=5, subevent=se2)
|
||||
q2.items.add(self.ticket)
|
||||
|
||||
self._create_voucher({
|
||||
'itemvar': '%d' % self.ticket.pk,
|
||||
'block_quota': 'on',
|
||||
'subevent': se1.pk
|
||||
}, expected_failure=True)
|
||||
|
||||
0
src/tests/plugins/pretixdroid/__init__.py
Normal file
0
src/tests/plugins/pretixdroid/__init__.py
Normal file
@@ -20,7 +20,7 @@ def env():
|
||||
)
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
|
||||
t = Team.objects.create(organizer=o, can_change_event_settings=True, can_change_items=True)
|
||||
t = Team.objects.create(organizer=o, can_change_event_settings=True, can_change_orders=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
@@ -47,14 +47,15 @@ def env():
|
||||
@pytest.mark.django_db
|
||||
def test_flush_key(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
client.get('/control/event/%s/%s/pretixdroid/' % (env[0].organizer.slug, env[0].slug))
|
||||
env[0].settings.flush()
|
||||
env[0].settings.get('pretixdroid_key') == 'abcdefg'
|
||||
assert env[0].settings.get('pretixdroid_key') == 'abcdefg'
|
||||
|
||||
client.get('/control/event/%s/%s/pretixdroid/?flush_key=1' % (env[0].organizer.slug, env[0].slug))
|
||||
env[0].settings.flush()
|
||||
env[0].settings.get('pretixdroid_key') != 'abcdefg'
|
||||
assert env[0].settings.get('pretixdroid_key') != 'abcdefg'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
172
src/tests/plugins/pretixdroid/test_subevents.py
Normal file
172
src/tests/plugins/pretixdroid/test_subevents.py
Normal file
@@ -0,0 +1,172 @@
|
||||
import json
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import (
|
||||
Checkin, Event, Item, ItemVariation, Order, OrderPosition, Organizer, Team,
|
||||
User,
|
||||
)
|
||||
from pretix.plugins.pretixdroid.views import API_VERSION
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def 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,pretix.plugins.pretixdroid',
|
||||
has_subevents=True
|
||||
)
|
||||
se1 = event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = event.subevents.create(name='Bar', date_from=now())
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
|
||||
t = Team.objects.create(organizer=o, can_change_event_settings=True, can_change_orders=True)
|
||||
t.members.add(user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
shirt = Item.objects.create(event=event, name='T-Shirt', default_price=12)
|
||||
shirt_red = ItemVariation.objects.create(item=shirt, default_price=14, value="Red")
|
||||
ItemVariation.objects.create(item=shirt, value="Blue")
|
||||
ticket = Item.objects.create(event=event, name='Ticket', default_price=23)
|
||||
o1 = Order.objects.create(
|
||||
code='FOO', event=event, status=Order.STATUS_PAID,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=0, payment_provider='banktransfer'
|
||||
)
|
||||
op1 = OrderPosition.objects.create(
|
||||
order=o1, item=shirt, variation=shirt_red,
|
||||
price=12, attendee_name=None, secret='1234', subevent=se1
|
||||
)
|
||||
op2 = OrderPosition.objects.create(
|
||||
order=o1, item=ticket,
|
||||
price=23, attendee_name="Peter", secret='5678910', subevent=se2
|
||||
)
|
||||
return event, user, o1, op1, op2, se1, se2
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_config(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
r = client.get('/control/event/%s/%s/pretixdroid/' % (env[0].organizer.slug, env[0].slug))
|
||||
print(r.content)
|
||||
assert 'qrcodeCanvas' not in r.rendered_content
|
||||
|
||||
r = client.get('/control/event/%s/%s/pretixdroid/?subevent=%d' % (env[0].organizer.slug, env[0].slug, env[5].pk))
|
||||
assert 'qrcodeCanvas' in r.rendered_content
|
||||
assert '/%d/' % env[5].pk in r.rendered_content
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_custom_datetime(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
dt = now() - timedelta(days=1)
|
||||
dt = dt.replace(microsecond=0)
|
||||
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'
|
||||
), data={'secret': '1234', 'datetime': dt.isoformat()})
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert jdata['version'] == API_VERSION
|
||||
assert jdata['status'] == 'ok'
|
||||
assert Checkin.objects.last().datetime == dt
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_wrong_subevent(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
|
||||
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'
|
||||
), data={'secret': '5678910'})
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert jdata['status'] == 'error'
|
||||
assert jdata['reason'] == 'unknown_ticket'
|
||||
|
||||
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[6].pk, 'abcdefg'
|
||||
), data={'secret': '5678910'})
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert jdata['status'] == 'ok'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_unknown_subevent(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
resp = client.post('/pretixdroid/api/%s/%s/%d/redeem/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[6].pk + 1000, 'abcdefg'
|
||||
), data={'secret': '5678910'})
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_no_subevent(client, env):
|
||||
resp = client.post('/pretixdroid/api/%s/%s/redeem/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, 'abcdefg'
|
||||
), data={'secret': '5678910'})
|
||||
assert resp.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
resp = client.get('/pretixdroid/api/%s/%s/%d/search/?key=%s&query=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg', '567891'))
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert len(jdata['results']) == 0
|
||||
resp = client.get('/pretixdroid/api/%s/%s/%d/search/?key=%s&query=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[6].pk, 'abcdefg', '567891'))
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert len(jdata['results']) == 1
|
||||
assert jdata['results'][0]['secret'] == '5678910'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_download_all_data(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
resp = client.get('/pretixdroid/api/%s/%s/%d/download/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'))
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert len(jdata['results']) == 1
|
||||
assert jdata['results'][0]['secret'] == '1234'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_status(client, env):
|
||||
env[0].settings.set('pretixdroid_key', 'abcdefg')
|
||||
Checkin.objects.create(position=env[3])
|
||||
resp = client.get('/pretixdroid/api/%s/%s/%d/status/?key=%s' % (
|
||||
env[0].organizer.slug, env[0].slug, env[5].pk, 'abcdefg'))
|
||||
jdata = json.loads(resp.content.decode("utf-8"))
|
||||
assert jdata['checkins'] == 1
|
||||
assert jdata['total'] == 1
|
||||
assert jdata['items'] == [
|
||||
{'name': 'T-Shirt',
|
||||
'id': env[3].item.pk,
|
||||
'checkins': 1,
|
||||
'admission': False,
|
||||
'total': 1,
|
||||
'variations': [
|
||||
{'name': 'Red',
|
||||
'id': env[3].variation.pk,
|
||||
'checkins': 1,
|
||||
'total': 1
|
||||
},
|
||||
{'name': 'Blue',
|
||||
'id': env[3].item.variations.get(value='Blue').pk,
|
||||
'checkins': 0,
|
||||
'total': 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{'name': 'Ticket',
|
||||
'id': env[4].item.pk,
|
||||
'checkins': 0,
|
||||
'admission': False,
|
||||
'total': 0,
|
||||
'variations': []
|
||||
}
|
||||
]
|
||||
@@ -174,3 +174,42 @@ def test_sendmail_multi_locales(logged_in_client, sendmail_url, event, item):
|
||||
assert response.status_code == 200
|
||||
assert 'Benutzer' in response.rendered_content
|
||||
assert 'Test nachricht' in response.rendered_content
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_sendmail_subevents(logged_in_client, sendmail_url, event, order):
|
||||
event.has_subevents = True
|
||||
event.save()
|
||||
se1 = event.subevents.create(name='Subevent FOO', date_from=now())
|
||||
se2 = event.subevents.create(name='Bar', date_from=now())
|
||||
op = order.positions.last()
|
||||
op.subevent = se1
|
||||
op.save()
|
||||
|
||||
djmail.outbox = []
|
||||
response = logged_in_client.post(sendmail_url,
|
||||
{'sendto': 'n',
|
||||
'subject_0': 'Test subject',
|
||||
'message_0': 'This is a test file for sending mails.',
|
||||
'subevent': se1.pk
|
||||
},
|
||||
follow=True)
|
||||
assert response.status_code == 200
|
||||
assert 'alert-success' in response.rendered_content
|
||||
assert len(djmail.outbox) == 1
|
||||
|
||||
djmail.outbox = []
|
||||
response = logged_in_client.post(sendmail_url,
|
||||
{'sendto': 'n',
|
||||
'subject_0': 'Test subject',
|
||||
'message_0': 'This is a test file for sending mails.',
|
||||
'subevent': se2.pk
|
||||
},
|
||||
follow=True)
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
url = sendmail_url + 'history/'
|
||||
response = logged_in_client.get(url)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert 'Subevent FOO' in response.rendered_content
|
||||
|
||||
@@ -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