Files
pretix_original/src/tests/presale/test_event.py

1624 lines
78 KiB
Python

#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
#
# This file contains Apache-licensed contributions copyrighted by: Christopher Dambamuromo, Joepriesto, Sohalt, Tobias
# Kunze, Vishal Sodani, jasonwaiting@live.hk
#
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import datetime
import re
from decimal import Decimal
from json import loads
from zoneinfo import ZoneInfo
from bs4 import BeautifulSoup
from django.conf import settings
from django.core import mail
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils.timezone import now
from django_scopes import scopes_disabled
from tests.base import SoupTest
from tests.testdummy.signals import FoobarSalesChannel
from pretix.base.models import (
Event, Item, ItemCategory, ItemVariation, Order, Organizer, Quota, Team,
User, WaitingListEntry,
)
from pretix.base.models.items import SubEventItem, SubEventItemVariation
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
class EventTestMixin:
@scopes_disabled()
def setUp(self):
super().setUp()
self.orga = Organizer.objects.create(name='CCC', slug='ccc')
self.event = Event.objects.create(
organizer=self.orga, name='30C3', slug='30c3',
date_from=datetime.datetime(now().year + 1, 12, 26, 14, 0, tzinfo=datetime.timezone.utc),
live=True,
)
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
t = Team.objects.create(organizer=self.orga, can_change_event_settings=True)
t.members.add(self.user)
t.limit_events.add(self.event)
class EventMiddlewareTest(EventTestMixin, SoupTest):
def test_event_header(self):
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn(str(self.event.name), doc.find("h1").text)
def test_not_found(self):
resp = self.client.get('/%s/%s/' % ('foo', 'bar'))
self.assertEqual(resp.status_code, 404)
def test_not_live(self):
self.event.live = False
self.event.save()
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertEqual(resp.status_code, 403)
def test_not_live_logged_in(self):
self.event.live = False
self.event.save()
self.client.login(email='dummy@dummy.dummy', password='dummy')
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertEqual(resp.status_code, 200)
def test_not_found_event(self):
resp = self.client.get('/%s/%s/ical' % ('foo', 'bar'))
self.assertEqual(resp.status_code, 404)
def test_mandatory_field(self):
self.event.date_to = self.event.date_from + datetime.timedelta(days=2)
self.event.save()
resp = self.client.get('/%s/%s/ical' % (self.orga.slug, self.event.slug))
self.assertEqual(resp.status_code, 200)
class ItemDisplayTest(EventTestMixin, SoupTest):
def test_link_rewrite(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
description="http://example.org [Sample](http://example.net)")
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn('href="http://example.org', html)
self.assertNotIn('href="http://example.net', html)
self.assertIn('href="/redirect/?url=http%3A//example.org%3A', html)
self.assertIn('href="/redirect/?url=http%3A//example.net%3A', html)
def test_not_active(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=False)
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
self.assertNotIn("btn-add-to-cart", html)
def test_filter_by_url(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True)
q.items.add(item)
doc = self.get_doc('/%s/%s/?item=%d' % (self.orga.slug, self.event.slug, item.pk))
self.assertIn("Early-bird", doc.select("section .product-row")[0].text)
doc = self.get_doc('/%s/%s/?item=%d' % (self.orga.slug, self.event.slug, item.pk + 1))
assert not doc.select("section .product-row")
def test_without_category(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True)
q.items.add(item)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section .product-row")[0].text)
self.assertEqual(len(doc.select("#btn-add-to-cart")), 1)
def test_sales_channel(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
all_sales_channels=False)
item.limit_sales_channels.add(self.orga.sales_channels.get(identifier="bar"))
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
html = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug),
PRETIX_SALES_CHANNEL=FoobarSalesChannel.identifier
).rendered_content
self.assertIn("Early-bird", html)
def test_timely_available(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
available_until=now() + datetime.timedelta(days=2),
available_from=now() - datetime.timedelta(days=2))
q.items.add(item)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("body")[0].text)
def test_no_longer_available(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
available_until=now() - datetime.timedelta(days=2))
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
def test_not_yet_available(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
available_from=now() + datetime.timedelta(days=2))
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
def test_hidden_without_voucher(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
hide_without_voucher=True)
q.items.add(item)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
def test_hidden_without_membership(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
mt = self.orga.membership_types.create(name="foo")
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
require_membership=True, require_membership_hidden=True)
item.require_membership_types.add(mt)
q.items.add(item)
customer = self.orga.customers.create(email='john@example.org', is_verified=True, is_active=True)
customer.set_password('foo')
customer.save()
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
r = self.client.post('/%s/account/login' % self.orga.slug, {
'email': 'john@example.org',
'password': 'foo',
})
assert r.status_code == 302
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
with scopes_disabled():
m = customer.memberships.create(
membership_type=mt,
date_start=self.event.date_from - datetime.timedelta(days=5),
date_end=self.event.date_from + datetime.timedelta(days=5),
)
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertIn("Early-bird", html)
m.canceled = True
m.save()
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
m.canceled = False
m.testmode = True
m.save()
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
m.testmode = False
m.date_end = m.date_start
m.save()
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertNotIn("Early-bird", html)
def test_simple_with_category(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
q.items.add(item)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Entry tickets", doc.select("section:nth-of-type(1) h3")[0].text)
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
def test_simple_without_quota(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
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()
with scopes_disabled():
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_activeness(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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_list_ordering(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
self.event.subevents.create(name='Epic SE', date_from=now() + datetime.timedelta(days=1), active=True)
self.event.subevents.create(name='Cool SE', date_from=now() + datetime.timedelta(days=2), active=True)
self.event.settings.frontpage_subevent_ordering = 'date_ascending'
content = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertLess(content.index('Epic SE'), content.index('Cool SE'))
self.event.settings.frontpage_subevent_ordering = 'date_descending'
content = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertLess(content.index('Cool SE'), content.index('Epic SE'))
self.event.settings.frontpage_subevent_ordering = 'name_ascending'
content = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
self.assertLess(content.index('Cool SE'), content.index('Epic SE'))
def test_subevent_calendar(self):
self.event.settings.event_list_type = 'calendar'
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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/?date=%d-%02d' % (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_subevent_week_calendar(self):
self.event.settings.event_list_type = 'week'
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se1 = self.event.subevents.create(name='Foo SE1', date_from=now() + datetime.timedelta(days=24),
active=True)
self.event.subevents.create(name='Foo SE2', date_from=now() + datetime.timedelta(days=12),
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/?date=%d-W%d' % (self.orga.slug, self.event.slug, se1.date_from.isocalendar()[0], se1.date_from.isocalendar()[1]))
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()
with scopes_disabled():
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_disabled(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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, disabled=True)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
self.assertNotIn("Early-bird", resp.rendered_content)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
self.assertIn("Early-bird", resp.rendered_content)
def test_subevent_availability(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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, available_until=now() - datetime.timedelta(hours=1))
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
self.assertNotIn("Early-bird", resp.rendered_content)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
self.assertIn("Early-bird", resp.rendered_content)
def test_subevent_prices(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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
with scopes_disabled():
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
tr = self.event.tax_rules.get_or_create(rate=Decimal('19.00'))[0]
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=15,
tax_rule=tr)
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))
doc = BeautifulSoup(resp.rendered_content, "lxml")
self.assertIn("€10.08", doc.text)
self.assertNotIn("€12.00", doc.text)
self.assertNotIn("€15.00", doc.text)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
doc = BeautifulSoup(resp.rendered_content, "lxml")
self.assertIn("€12.61", doc.text)
self.assertNotIn("€12.00", doc.text)
self.assertNotIn("€15.00", doc.text)
def test_variations_subevent_disabled(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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)
v = ItemVariation.objects.create(item=item, value='Blue')
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
q.items.add(item)
q.variations.add(v)
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
q.items.add(item)
q.variations.add(v)
SubEventItemVariation.objects.create(subevent=se1, variation=v, disabled=True)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
self.assertNotIn("Early-bird", resp.rendered_content)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
self.assertIn("Early-bird", resp.rendered_content)
def test_variations_subevent_availability(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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)
v = ItemVariation.objects.create(item=item, value='Blue')
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
q.items.add(item)
q.variations.add(v)
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
q.items.add(item)
q.variations.add(v)
SubEventItemVariation.objects.create(subevent=se1, variation=v, available_from=now() + datetime.timedelta(hours=1))
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk))
self.assertNotIn("Early-bird", resp.rendered_content)
resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se2.pk))
self.assertIn("Early-bird", resp.rendered_content)
def test_no_variations_in_quota(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
ItemVariation.objects.create(item=item, value='Blue')
q.items.add(item)
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", resp.rendered_content)
def test_one_variation_in_quota(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
ItemVariation.objects.create(item=item, value='Blue')
q.items.add(item)
q.variations.add(var1)
self._assert_variation_found()
def test_one_variation_in_unlimited_quota(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
ItemVariation.objects.create(item=item, value='Blue')
q.items.add(item)
q.variations.add(var1)
self._assert_variation_found()
def test_variation_available_from(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red', available_from=now() - datetime.timedelta(days=1))
var2 = ItemVariation.objects.create(item=item, value='Blue', available_from=now() + datetime.timedelta(days=1))
q.items.add(item)
q.variations.add(var1)
q.variations.add(var2)
self._assert_variation_found()
def test_variation_available_until(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red', available_until=now() + datetime.timedelta(days=1))
var2 = ItemVariation.objects.create(item=item, value='Blue', available_until=now() - datetime.timedelta(days=1))
q.items.add(item)
q.variations.add(var1)
q.variations.add(var2)
self._assert_variation_found()
def test_variation_hide_without_voucher(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
var2 = ItemVariation.objects.create(item=item, value='Blue', hide_without_voucher=True)
q.items.add(item)
q.variations.add(var1)
q.variations.add(var2)
self._assert_variation_found()
def test_variation_sales_channel(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
var2 = ItemVariation.objects.create(item=item, value='Blue', all_sales_channels=False)
var2.limit_sales_channels.add(self.orga.sales_channels.get(identifier='bar'))
q.items.add(item)
q.variations.add(var1)
q.variations.add(var2)
self._assert_variation_found()
def _assert_variation_found(self):
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("Red", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("Black", doc.select("section:nth-of-type(1)")[0].text)
def test_variation_prices_in_quota(self):
with scopes_disabled():
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=12)
var1 = ItemVariation.objects.create(item=item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=item, value='Black', position=2)
q.variations.add(var1)
q.variations.add(var2)
q.items.add(item)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("Red", doc.select("section:nth-of-type(1) .variation")[0].text)
self.assertIn("14.00", doc.select("section:nth-of-type(1) .variation")[0].text)
self.assertIn("Black", doc.select("section:nth-of-type(1) .variation")[1].text)
self.assertIn("12.00", doc.select("section:nth-of-type(1) .variation")[1].text)
def test_require_bundling(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12)
q.items.add(item)
q2 = Quota.objects.create(event=self.event, name='Quota', size=2)
item2 = Item.objects.create(event=self.event, name='Dinner', default_price=12, require_bundling=True)
q2.items.add(item2)
item.bundles.create(bundled_item=item2, designated_price=2, count=1)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertEqual(1, len(doc.select(".availability-box")))
def test_hide_sold_out(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=0)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12)
q.items.add(item)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
self.event.settings.hide_sold_out = True
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", doc.select("body")[0].text)
self.assertNotIn("SOLD OUT", doc.select("body")[0].text)
def test_hidden_if_available(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Early-bird', size=10)
q2 = Quota.objects.create(event=self.event, name='Late-bird', size=10)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12)
item2 = Item.objects.create(event=self.event, name='Late-bird ticket', default_price=12,
hidden_if_available=q)
q.items.add(item)
q2.items.add(item2)
self.event.settings.hide_sold_out = True
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("Late-bird", doc.select("section:nth-of-type(1)")[0].text)
q.size = 0
q.save()
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
self.assertIn("Late-bird", doc.select("section:nth-of-type(1)")[0].text)
def test_hidden_if_item_available(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Early-bird', size=10)
q2 = Quota.objects.create(event=self.event, name='Late-bird', size=10)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12)
item2 = Item.objects.create(event=self.event, name='Late-bird ticket', default_price=12,
hidden_if_item_available=item)
q.items.add(item)
q2.items.add(item2)
self.event.settings.hide_sold_out = True
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("Late-bird", doc.select("section:nth-of-type(1)")[0].text)
q.size = 0
q.save()
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", doc.select("section:nth-of-type(1)")[0].text)
self.assertNotIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
self.assertIn("Late-bird", doc.select("section:nth-of-type(1)")[0].text)
def test_bundle_sold_out(self):
with scopes_disabled():
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12)
q.items.add(item)
q2 = Quota.objects.create(event=self.event, name='Quota', size=0)
item2 = Item.objects.create(event=self.event, name='Dinner', default_price=12, position=10)
q2.items.add(item2)
item.bundles.create(bundled_item=item2, designated_price=2, count=1)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("SOLD OUT", doc.select("section:nth-of-type(1)")[0].text)
def test_bundle_mixed_tax_rate(self):
with scopes_disabled():
tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12, tax_rule=tr19)
q.items.add(item)
q2 = Quota.objects.create(event=self.event, name='Quota', size=0)
item2 = Item.objects.create(event=self.event, name='Dinner', default_price=12, tax_rule=tr7, position=10)
q2.items.add(item2)
item.bundles.create(bundled_item=item2, designated_price=2, count=1)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("12.00", doc.select("section:nth-of-type(1) div.price")[0].text)
self.assertIn("incl. taxes", doc.select("section:nth-of-type(1) div.price")[0].text)
def test_bundle_mixed_tax_rate_show_net(self):
with scopes_disabled():
self.event.settings.display_net_prices = True
tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=12, tax_rule=tr19)
q.items.add(item)
q2 = Quota.objects.create(event=self.event, name='Quota', size=0)
item2 = Item.objects.create(event=self.event, name='Dinner', default_price=12, tax_rule=tr7, position=10)
q2.items.add(item2)
item.bundles.create(bundled_item=item2, designated_price=2, count=1)
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
self.assertIn("10.27", doc.select("section:nth-of-type(1) div.price")[0].text)
self.assertIn("plus taxes", doc.select("section:nth-of-type(1) div.price")[0].text)
class VoucherRedeemItemDisplayTest(EventTestMixin, SoupTest):
@scopes_disabled()
def setUp(self):
super().setUp()
self.q = Quota.objects.create(event=self.event, name='Quota', size=2)
self.v = self.event.vouchers.create(quota=self.q)
self.item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=Decimal('12.00'),
active=True)
self.q.items.add(self.item)
def test_not_active(self):
self.item.active = False
self.item.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" not in html.rendered_content
def test_not_in_quota(self):
with scopes_disabled():
q2 = Quota.objects.create(event=self.event, name='Quota', size=2)
self.v.quota = q2
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" not in html.rendered_content
def test_in_quota(self):
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
assert "12.00" in html.rendered_content
def test_specific_item(self):
self.v.item = self.item
self.v.quota = None
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
def test_hide_wo_voucher_quota(self):
self.item.hide_without_voucher = True
self.item.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
def test_hide_wo_voucher_quota_dont_show(self):
self.v.show_hidden_items = False
self.v.save()
self.item.hide_without_voucher = True
self.item.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" not in html.rendered_content
def test_hide_without_voucher_item(self):
self.item.hide_without_voucher = True
self.item.save()
self.v.item = self.item
self.v.quota = None
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
def test_variations_all(self):
with scopes_disabled():
var1 = ItemVariation.objects.create(item=self.item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
self.q.variations.add(var1)
self.q.variations.add(var2)
self.v.item = self.item
self.v.quota = None
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Red" in html.rendered_content
assert "Black" in html.rendered_content
def test_variations_specific(self):
with scopes_disabled():
var1 = ItemVariation.objects.create(item=self.item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
self.q.variations.add(var1)
self.q.variations.add(var2)
self.v.item = self.item
self.v.variation = var1
self.v.quota = None
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Red" in html.rendered_content
assert "Black" not in html.rendered_content
def test_sold_out(self):
self.q.size = 0
self.q.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "_voucher_item" not in html.rendered_content
def test_sold_out_blocking(self):
self.q.size = 0
self.q.save()
self.v.block_quota = True
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "_voucher_item" in html.rendered_content
def test_sold_out_ignore(self):
self.q.size = 0
self.q.save()
self.v.allow_ignore_quota = True
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "_voucher_item" in html.rendered_content
def test_variations_sold_out(self):
with scopes_disabled():
var1 = ItemVariation.objects.create(item=self.item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
self.q.variations.add(var1)
self.q.variations.add(var2)
self.q.size = 0
self.q.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "_voucher_item" not in html.rendered_content
def test_variations_sold_out_blocking(self):
with scopes_disabled():
var1 = ItemVariation.objects.create(item=self.item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
self.q.variations.add(var1)
self.q.variations.add(var2)
self.q.size = 0
self.q.save()
self.v.block_quota = True
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "_voucher_item" in html.rendered_content
def test_voucher_price(self):
self.v.value = Decimal("10.00")
self.v.price_mode = 'set'
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
assert "10.00" in html.rendered_content
def test_voucher_price_percentage(self):
self.v.value = Decimal("10.00")
self.v.price_mode = 'percent'
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
assert "10.80" in html.rendered_content
def test_voucher_price_variations(self):
with scopes_disabled():
var1 = ItemVariation.objects.create(item=self.item, value='Red', default_price=14, position=1)
var2 = ItemVariation.objects.create(item=self.item, value='Black', position=2)
self.q.variations.add(var1)
self.q.variations.add(var2)
self.v.value = Decimal("10.00")
self.v.price_mode = 'set'
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code))
assert "Early-bird" in html.rendered_content
assert "10.00" in html.rendered_content
assert re.search(r"<del>.*€14\.00.*</del>", html.rendered_content.replace("\n", ""))
def test_fail_redeemed(self):
self.v.redeemed = 1
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code), follow=True)
assert "alert-danger" in html.rendered_content
def test_fail_expired(self):
self.v.valid_until = now() - datetime.timedelta(days=1)
self.v.save()
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, self.v.code), follow=True)
assert "alert-danger" in html.rendered_content
def test_fail_unknown(self):
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_not_yet_started(self):
self.event.presale_start = now() + datetime.timedelta(days=1)
self.event.save()
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_over(self):
self.event.presale_end = now() - datetime.timedelta(days=1)
self.event.save()
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):
with scopes_disabled():
self.event.settings.display_net_prices = True
self.event.has_subevents = True
self.event.save()
self.item.tax_rule = self.event.tax_rules.get_or_create(rate=Decimal('19.00'))[0]
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.items.add(self.item)
q.variations.add(var1)
q.variations.add(var2)
SubEventItemVariation.objects.create(subevent=se1, variation=var1, price=10)
self.v.quota = q
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):
with scopes_disabled():
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.items.add(self.item)
q.variations.add(var1)
q.variations.add(var2)
SubEventItemVariation.objects.create(subevent=se1, variation=var1, price=10)
self.v.quota = q
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):
with scopes_disabled():
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.items.add(self.item)
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):
with scopes_disabled():
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 'name="variation_%d_%d' % (self.item.pk, var1.pk) not in html.rendered_content
assert 'name="variation_%d_%d' % (self.item.pk, var2.pk) not in html.rendered_content
class WaitingListTest(EventTestMixin, SoupTest):
@scopes_disabled()
def setUp(self):
super().setUp()
self.q = Quota.objects.create(event=self.event, name='Quota', size=0)
self.v = self.event.vouchers.create(quota=self.q)
self.item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=Decimal('12.00'),
active=True)
self.q.items.add(self.item)
self.event.settings.set('waiting_list_enabled', True)
def test_disabled(self):
self.event.settings.set('waiting_list_enabled', False)
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
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)
)
self.assertEqual(response.status_code, 302)
def test_auto_disable(self):
self.event.settings.set('waiting_list_enabled', True)
self.event.settings.waiting_list_auto_disable = RelativeDateWrapper(
RelativeDate(days=900, time=datetime.time(9, 0, 0), base_date_name='date_from', minutes=None, is_after=False)
)
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
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)
)
self.assertEqual(response.status_code, 302)
def test_display_link(self):
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('waitinglist', response.rendered_content)
def test_submit_form(self):
response = self.client.get(
'/%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), {
'email': 'foo@bar.com',
'itemvar': str(self.item.pk)
}
)
self.assertEqual(response.status_code, 302)
with scopes_disabled():
wle = WaitingListEntry.objects.get(email='foo@bar.com')
assert wle.event == self.event
assert wle.item == self.item
assert wle.variation is None
assert wle.voucher is None
assert wle.locale == 'en'
def test_subevent_valid(self):
with scopes_disabled():
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&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',
'itemvar': str(self.item.pk)
}
)
self.assertEqual(response.status_code, 302)
with scopes_disabled():
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.post(
'/%s/%s/waitinglist/' % (self.orga.slug, self.event.slug),
{
'email': 'foo@bar.com',
'itemvar': str(self.item.pk + 1),
}
)
self.assertEqual(response.status_code, 200)
def test_invalid_subevent(self):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
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), {
'email': 'foo@bar.com',
'itemvar': str(self.item.pk)
}
)
self.assertEqual(response.status_code, 200)
with scopes_disabled():
self.assertFalse(WaitingListEntry.objects.filter(email='foo@bar.com').exists())
def test_subevent_available(self):
with scopes_disabled():
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',
'itemvar': str(self.item.pk),
}
)
self.assertEqual(response.status_code, 200)
with scopes_disabled():
self.assertFalse(WaitingListEntry.objects.filter(email='foo@bar.com').exists())
def test_remove_valid(self):
with scopes_disabled():
v = self.event.vouchers.create(item=self.item, block_quota=True)
WaitingListEntry.objects.create(
event=self.event, item=self.item, email='bar@bar.com', voucher=v
)
response = self.client.get(
'/%s/%s/waitinglist/remove?voucher=%s' % (self.orga.slug, self.event.slug, v.code), {
}
)
self.assertEqual(response.status_code, 200)
response = self.client.post(
'/%s/%s/waitinglist/remove?voucher=%s' % (self.orga.slug, self.event.slug, v.code), {
}
)
self.assertEqual(response.status_code, 302)
v.refresh_from_db()
assert not v.is_active()
def test_remove_waiting_list_vouchers_only(self):
with scopes_disabled():
v = self.event.vouchers.create(item=self.item, block_quota=True)
response = self.client.get(
'/%s/%s/waitinglist/remove?voucher=%s' % (self.orga.slug, self.event.slug, v.code), {
}
)
self.assertEqual(response.status_code, 302)
response = self.client.post(
'/%s/%s/waitinglist/remove?voucher=%s' % (self.orga.slug, self.event.slug, v.code), {
}
)
self.assertEqual(response.status_code, 302)
v.refresh_from_db()
assert v.is_active()
class DeadlineTest(EventTestMixin, TestCase):
@scopes_disabled()
def setUp(self):
super().setUp()
q = Quota.objects.create(event=self.event, name='Quota', size=2)
self.item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True)
q.items.add(self.item)
def test_not_yet_started(self):
self.event.presale_start = now() + datetime.timedelta(days=1)
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('alert-info', response.rendered_content)
self.assertNotIn('btn-add-to-cart', response.rendered_content)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1',
},
follow=True
)
self.assertIn('alert-danger', response.rendered_content)
self.assertIn('not yet started', response.rendered_content)
def test_event_over(self):
self.event.date_to = now() - datetime.timedelta(days=1)
self.event.presale_end = None
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('alert-info', response.rendered_content)
self.assertNotIn('btn-add-to-cart', response.rendered_content)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1'
},
follow=True
)
self.assertIn('alert-danger', response.rendered_content)
self.assertIn('is over', response.rendered_content)
def test_over(self):
self.event.presale_end = now() - datetime.timedelta(days=1)
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('alert-info', response.rendered_content)
self.assertNotIn('btn-add-to-cart', response.rendered_content)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1'
},
follow=True
)
self.assertIn('alert-danger', response.rendered_content)
self.assertIn('is over', response.rendered_content)
def test_not_set(self):
self.event.presale_start = None
self.event.presale_end = None
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertNotIn('alert-info', response.rendered_content)
self.assertIn('btn-add-to-cart', response.rendered_content)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1'
}
)
self.assertNotEqual(response.status_code, 403)
def test_saleschannel_disabled(self):
self.event.presale_start = None
self.event.presale_end = None
self.event.all_sales_channels = False
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 404)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1'
}
)
self.assertEqual(response.status_code, 404)
def test_in_time(self):
self.event.presale_start = now() - datetime.timedelta(days=1)
self.event.presale_end = now() + datetime.timedelta(days=1)
self.event.save()
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertNotIn('alert-info', response.rendered_content)
self.assertIn('btn-add-to-cart', response.rendered_content)
response = self.client.post(
'/%s/%s/cart/add' % (self.orga.slug, self.event.slug),
{
'item_%d' % self.item.id: '1'
}
)
self.assertNotEqual(response.status_code, 403)
class TestResendLink(EventTestMixin, SoupTest):
def test_no_orders(self):
mail.outbox = []
url = '/{}/{}/resend/'.format(self.orga.slug, self.event.slug)
resp = self.client.post(url, data={'email': 'dummy@dummy.dummy'})
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 0)
def test_no_orders_from_user(self):
with scopes_disabled():
Order.objects.create(
code='DUMMY1', status=Order.STATUS_PENDING, event=self.event,
email='dummy@dummy.dummy', datetime=now(), expires=now(),
sales_channel=self.orga.sales_channels.get(identifier="web"),
total=0,
)
mail.outbox = []
url = '/{}/{}/resend/'.format(self.orga.slug, self.event.slug)
resp = self.client.post(url, data={'email': 'dummy@dummy.different'})
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 0)
def test_one_order(self):
with scopes_disabled():
Order.objects.create(
code='DUMMY1', status=Order.STATUS_PENDING, event=self.event,
email='dummy@dummy.dummy', datetime=now(), expires=now(),
sales_channel=self.orga.sales_channels.get(identifier="web"),
total=0,
)
mail.outbox = []
url = '/{}/{}/resend/'.format(self.orga.slug, self.event.slug)
resp = self.client.post(url, data={'email': 'dummy@dummy.dummy'})
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 1)
self.assertIn('DUMMY1', mail.outbox[0].body)
def test_multiple_orders(self):
with scopes_disabled():
Order.objects.create(
code='DUMMY1', status=Order.STATUS_PENDING, event=self.event,
email='dummy@dummy.dummy', datetime=now(), expires=now(),
sales_channel=self.orga.sales_channels.get(identifier="web"),
total=0,
)
Order.objects.create(
code='DUMMY2', status=Order.STATUS_PENDING, event=self.event,
email='dummy@dummy.dummy', datetime=now(), expires=now(),
sales_channel=self.orga.sales_channels.get(identifier="web"),
total=0,
)
mail.outbox = []
url = '/{}/{}/resend/'.format(self.orga.slug, self.event.slug)
resp = self.client.post(url, data={'email': 'dummy@dummy.dummy'})
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 1)
self.assertIn('DUMMY1', mail.outbox[0].body)
self.assertIn('DUMMY2', mail.outbox[0].body)
class EventIcalDownloadTest(EventTestMixin, SoupTest):
def setUp(self):
super().setUp()
self.event.settings.show_date_to = True
self.event.settings.show_times = True
self.event.location = 'DUMMY ARENA'
self.event.date_from = datetime.datetime(2013, 12, 26, 21, 57, 58, tzinfo=datetime.timezone.utc)
self.event.date_to = self.event.date_from + datetime.timedelta(days=2)
self.event.settings.timezone = 'UTC'
self.event.save()
def test_response_type(self):
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="{}-{}-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()
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')
self.assertIn('END:VEVENT', ical, 'missing VEVENT footer')
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()
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')
self.assertIn('END:VEVENT', ical, 'missing VEVENT footer')
self.assertIn('BEGIN:VTIMEZONE', ical, 'missing VTIMEZONE header')
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()
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()
self.assertIn('SUMMARY:%s' % self.event.name, ical, 'incorrect correct summary')
self.assertIn('LOCATION:DUMMY ARENA', ical, 'incorrect location')
self.assertTrue(re.search(r'DTSTAMP:\d{8}T\d{6}Z', ical), 'incorrect timestamp')
self.assertTrue(re.search(r'UID:pretix-\w*-\w*-0@', ical), 'missing UID key')
def test_utc_timezone(self):
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')
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()
# 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' %
(self.event.settings.timezone,
self.event.date_from.astimezone(ZoneInfo(self.event.settings.timezone)).strftime(fmt)),
ical, 'incorrect start time')
self.assertIn('DTEND;TZID=%s:%s' %
(self.event.settings.timezone,
self.event.date_to.astimezone(ZoneInfo(self.event.settings.timezone)).strftime(fmt)),
ical, 'incorrect end time')
self.assertIn('TZID:%s' % self.event.settings.timezone, ical, 'missing VCALENDAR')
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()
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 + datetime.timedelta(days=1)).strftime('%Y%m%d'), ical, 'incorrect end date')
def test_no_date_to(self):
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()
fmt = '%Y%m%dT%H%M%S'
self.assertIn('DTSTART;TZID=%s:%s' %
(self.event.settings.timezone,
self.event.date_from.astimezone(ZoneInfo(self.event.settings.timezone)).strftime(fmt)),
ical, 'incorrect start time')
self.assertIn('DTEND;TZID=%s:%s' %
(self.event.settings.timezone,
(self.event.date_from.astimezone(ZoneInfo(self.event.settings.timezone)) + datetime.timedelta(hours=1)).strftime(fmt)),
ical, 'incorrect end time')
def test_no_date_to_and_time(self):
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()
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_from + datetime.timedelta(days=1)).strftime('%Y%m%d'), ical, 'incorrect start date')
def test_local_date_diff_from_utc(self):
self.event.date_from = datetime.datetime(2013, 12, 26, 21, 57, 58, tzinfo=datetime.timezone.utc)
self.event.date_to = self.event.date_from + datetime.timedelta(days=2)
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()
self.assertIn('DTSTART;VALUE=DATE:20131227', ical, 'incorrect start date')
self.assertIn('DTEND;VALUE=DATE:20131230', 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()
with scopes_disabled():
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:20141229', ical, 'incorrect end date')
self.assertIn('SUMMARY:%s' % se1.name, ical, 'incorrect correct summary')
self.assertIn('LOCATION:Heeeeeere', ical, 'incorrect location')
class EventMicrodataTest(EventTestMixin, SoupTest):
def setUp(self):
super().setUp()
self.event.settings.show_date_to = True
self.event.settings.show_times = True
self.event.location = 'DUMMY ARENA'
self.event.date_from = datetime.datetime(2013, 12, 26, 21, 57, 58, tzinfo=datetime.timezone.utc)
self.event.date_to = self.event.date_from + datetime.timedelta(days=2)
self.event.settings.timezone = 'UTC'
self.event.save()
def _get_json(self):
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
microdata = loads(doc.find(type="application/ld+json").string)
return microdata
def test_name(self):
md = self._get_json()
self.assertEqual(self.event.name, md['name'], msg='Name not present')
def test_location(self):
md = self._get_json()
self.assertEqual(self.event.location, md['location']['address'], msg='Location not present')
def test_date_to(self):
md = self._get_json()
self.assertEqual(self.event.date_to.isoformat(), md['endDate'], msg='Date To not present')
self.event.settings.show_date_to = False
md = self._get_json()
self.assertNotIn(self.event.date_to.isoformat(), md,
msg='Date To present when show date to setting is false')
def test_no_times(self):
self.event.settings.show_times = False
md = self._get_json()
self.assertNotEqual(self.event.date_from.isoformat(), md['startDate'], msg='Date including time present')
self.assertEqual(self.event.date_from.date().isoformat(), md['startDate'], msg='Date not present at all')
def test_date_from(self):
md = self._get_json()
self.assertEqual(self.event.date_from.isoformat(), md['startDate'], msg='Date From not present')
class EventSlugBanlistValidatorTest(EventTestMixin, SoupTest):
@scopes_disabled()
def test_slug_validation(self):
event = Event(
organizer=self.orga,
name='download',
slug='download',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
live=True
)
with self.assertRaises(ValidationError):
if event.full_clean():
event.save()
self.assertEqual(Event.objects.filter(name='download').count(), 0)
class EventLocaleTest(EventTestMixin, SoupTest):
@scopes_disabled()
def setUp(self):
super().setUp()
self.event.settings.locales = ['de', 'en']
self.event.settings.locale = 'de'
self.event.settings.timezone = 'UTC'
def test_german_by_default(self):
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('26. Dezember', response.rendered_content)
self.assertIn('14:00', response.rendered_content)
def test_english_no_region_set(self):
self.client.get('/locale/set?locale=en')
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('Fri, Dec. 26th,', response.rendered_content)
self.assertIn('14:00', response.rendered_content)
def test_english_region_US(self):
self.event.settings.region = 'US'
self.client.get('/locale/set?locale=en')
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('Fri, Dec. 26th,', response.rendered_content)
self.assertIn('2 p.m.', response.rendered_content)
def test_german_region_US(self):
self.event.settings.region = 'US'
self.client.get('/locale/set?locale=de')
response = self.client.get(
'/%s/%s/' % (self.orga.slug, self.event.slug)
)
self.assertEqual(response.status_code, 200)
self.assertIn('Fr, 26. Dezember', response.rendered_content)
self.assertIn('14:00', response.rendered_content)