mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
1624 lines
78 KiB
Python
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)
|