Files
pretix_original/src/tests/base/test_models.py
2017-10-24 18:42:50 +02:00

1065 lines
48 KiB
Python

import datetime
import sys
from datetime import date, timedelta
from decimal import Decimal
import pytest
import pytz
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.files.storage import default_storage
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.utils.timezone import now
from pretix.base.models import (
CachedFile, CartPosition, Event, Item, ItemCategory, ItemVariation, Order,
OrderPosition, Organizer, Question, Quota, User, Voucher, WaitingListEntry,
)
from pretix.base.models.event import SubEvent
from pretix.base.models.items import SubEventItem, SubEventItemVariation
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
from pretix.base.services.orders import (
OrderError, cancel_order, mark_order_paid, perform_order,
)
class UserTestCase(TestCase):
def test_name(self):
u = User.objects.create_user('test@foo.bar', 'test')
u.fullname = "Christopher Nolan"
u.set_password("test")
u.save()
self.assertEqual(u.get_full_name(), 'Christopher Nolan')
self.assertEqual(u.get_short_name(), 'Christopher Nolan')
u.fullname = None
u.save()
self.assertEqual(u.get_full_name(), 'test@foo.bar')
self.assertEqual(u.get_short_name(), 'test@foo.bar')
class BaseQuotaTestCase(TestCase):
@classmethod
def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy')
cls.event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
date_from=now(),
)
def setUp(self):
self.quota = Quota.objects.create(name="Test", size=2, event=self.event)
self.item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True)
self.item2 = Item.objects.create(event=self.event, name="T-Shirt", default_price=23)
self.item3 = Item.objects.create(event=self.event, name="Goodie", default_price=23)
self.var1 = ItemVariation.objects.create(item=self.item2, value='S')
self.var2 = ItemVariation.objects.create(item=self.item2, value='M')
self.var3 = ItemVariation.objects.create(item=self.item3, value='Fancy')
class QuotaTestCase(BaseQuotaTestCase):
def test_available(self):
self.quota.items.add(self.item1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 2))
self.quota.items.add(self.item2)
self.quota.variations.add(self.var1)
try:
self.item2.check_quotas()
self.assertTrue(False)
except:
pass
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 2))
def test_sold_out(self):
self.quota.items.add(self.item1)
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
self.quota.items.add(self.item2)
self.quota.variations.add(self.var1)
self.quota.size = 3
self.quota.save()
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item2, variation=self.var1, price=2)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
def test_ordered(self):
self.quota.items.add(self.item1)
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
order = Order.objects.create(event=self.event, status=Order.STATUS_PENDING,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0))
order.expires = now() - timedelta(days=3)
order.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0))
order.status = Order.STATUS_EXPIRED
order.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
def test_ordered_multi_quota(self):
quota2 = Quota.objects.create(name="Test", size=2, event=self.event)
quota2.items.add(self.item2)
quota2.variations.add(self.var1)
self.quota.items.add(self.item2)
self.quota.variations.add(self.var1)
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item2, variation=self.var1, price=2)
self.assertEqual(quota2.availability(), (Quota.AVAILABILITY_OK, 1))
def test_reserved(self):
self.quota.items.add(self.item1)
self.quota.size = 3
self.quota.save()
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 2))
order = Order.objects.create(event=self.event, status=Order.STATUS_PENDING,
expires=now() + timedelta(days=3),
total=4)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
cp = CartPosition.objects.create(event=self.event, item=self.item1, price=2,
expires=now() + timedelta(days=3))
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
cp.expires = now() - timedelta(days=3)
cp.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.quota.items.add(self.item2)
self.quota.variations.add(self.var1)
cp = CartPosition.objects.create(event=self.event, item=self.item2, variation=self.var1,
price=2, expires=now() + timedelta(days=3))
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_multiple(self):
self.quota.items.add(self.item1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 2))
quota2 = Quota.objects.create(event=self.event, name="Test 2", size=1)
quota2.items.add(self.item1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
quota2.size = 0
quota2.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
def test_ignore_quotas(self):
self.quota.items.add(self.item1)
quota2 = Quota.objects.create(event=self.event, name="Test 2", size=0)
quota2.items.add(self.item1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
self.assertEqual(self.item1.check_quotas(ignored_quotas=[quota2]), (Quota.AVAILABILITY_OK, 2))
self.assertEqual(self.item1.check_quotas(ignored_quotas=[self.quota, quota2]),
(Quota.AVAILABILITY_OK, sys.maxsize))
def test_unlimited(self):
self.quota.items.add(self.item1)
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=2)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, price=2)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
self.quota.size = None
self.quota.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, None))
def test_voucher_product(self):
self.quota.items.add(self.item1)
self.quota.size = 1
self.quota.save()
v = Voucher.objects.create(item=self.item1, event=self.event)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertTrue(v.is_active())
v.block_quota = True
v.save()
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_voucher_variation(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
v = Voucher.objects.create(item=self.item2, variation=self.var1, event=self.event)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertTrue(v.is_active())
v.block_quota = True
v.save()
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_voucher_quota(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
v = Voucher.objects.create(quota=self.quota, event=self.event)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertTrue(v.is_active())
v.block_quota = True
v.save()
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_voucher_quota_multiuse(self):
self.quota.size = 5
self.quota.variations.add(self.var1)
self.quota.save()
Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, max_usages=5, redeemed=2)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 2))
Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, max_usages=2)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_voucher_multiuse_count_overredeemed(self):
if 'sqlite' not in settings.DATABASES['default']['ENGINE']:
pytest.xfail('This should raise a type error on most databases')
Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, max_usages=2, redeemed=4)
self.assertEqual(self.quota.count_blocking_vouchers(), 0)
def test_voucher_quota_multiuse_multiproduct(self):
q2 = Quota.objects.create(event=self.event, name="foo", size=10)
q2.items.add(self.item1)
self.quota.size = 5
self.quota.items.add(self.item1)
self.quota.items.add(self.item2)
self.quota.items.add(self.item3)
self.quota.variations.add(self.var1)
self.quota.variations.add(self.var2)
self.quota.variations.add(self.var3)
self.quota.save()
Voucher.objects.create(item=self.item1, event=self.event, block_quota=True, max_usages=5, redeemed=2)
Voucher.objects.create(item=self.item2, variation=self.var2, event=self.event, block_quota=True, max_usages=5,
redeemed=2)
Voucher.objects.create(item=self.item2, variation=self.var2, event=self.event, block_quota=True, max_usages=5,
redeemed=2)
self.assertEqual(self.quota.count_blocking_vouchers(), 9)
def test_voucher_quota_expiring_soon(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() + timedelta(days=5),
block_quota=True)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
def test_voucher_quota_expired(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() - timedelta(days=5),
block_quota=True)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertFalse(v.is_active())
def test_blocking_voucher_in_cart(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() + timedelta(days=5),
block_quota=True)
CartPosition.objects.create(event=self.event, item=self.item1, price=2,
expires=now() + timedelta(days=3), voucher=v)
self.assertTrue(v.is_in_cart())
self.assertEqual(self.quota.count_blocking_vouchers(), 1)
self.assertEqual(self.quota.count_in_cart(), 0)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
def test_blocking_voucher_in_cart_inifinitely_valid(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True)
CartPosition.objects.create(event=self.event, item=self.item1, price=2,
expires=now() + timedelta(days=3), voucher=v)
self.assertEqual(self.quota.count_blocking_vouchers(), 1)
self.assertEqual(self.quota.count_in_cart(), 0)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
def test_blocking_expired_voucher_in_cart(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() - timedelta(days=5),
block_quota=True)
CartPosition.objects.create(event=self.event, item=self.item1, price=2,
expires=now() + timedelta(days=3), voucher=v)
self.assertEqual(self.quota.count_blocking_vouchers(), 0)
self.assertEqual(self.quota.count_in_cart(), 1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
def test_nonblocking_voucher_in_cart(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event)
CartPosition.objects.create(event=self.event, item=self.item1, price=2,
expires=now() + timedelta(days=3), voucher=v)
self.assertEqual(self.quota.count_blocking_vouchers(), 0)
self.assertEqual(self.quota.count_in_cart(), 1)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
def test_waitinglist_item_active(self):
self.quota.items.add(self.item1)
self.quota.size = 1
self.quota.save()
WaitingListEntry.objects.create(
event=self.event, item=self.item1, email='foo@bar.com'
)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
self.assertEqual(self.item1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
def test_waitinglist_variation_active(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0))
self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
def test_waitinglist_variation_fulfilled(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
v = Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, redeemed=1)
WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com', voucher=v
)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
def test_waitinglist_variation_other(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var2, email='foo@bar.com'
)
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
def test_quota_cache(self):
self.quota.variations.add(self.var1)
self.quota.size = 1
self.quota.save()
WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
)
cache = {}
self.assertEqual(self.var1.check_quotas(_cache=cache), (Quota.AVAILABILITY_RESERVED, 0))
with self.assertNumQueries(1):
self.assertEqual(self.var1.check_quotas(_cache=cache), (Quota.AVAILABILITY_RESERVED, 0))
# Do not reuse cache for count_waitinglist=False
self.assertEqual(self.var1.check_quotas(_cache=cache, count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
with self.assertNumQueries(1):
self.assertEqual(self.var1.check_quotas(_cache=cache, count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
def test_subevent_isolation(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(date_from=now(), name="SE 1")
se2 = self.event.subevents.create(date_from=now(), name="SE 2")
q1 = self.event.quotas.create(name="Q1", subevent=se1, size=50)
q2 = self.event.quotas.create(name="Q2", subevent=se2, size=50)
q1.items.add(self.item1)
q2.items.add(self.item1)
# Create orders
order = Order.objects.create(event=self.event, status=Order.STATUS_PAID,
expires=now() + timedelta(days=3),
total=6)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se2, price=2)
order = Order.objects.create(event=self.event, status=Order.STATUS_PENDING,
expires=now() + timedelta(days=3),
total=8)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se1, price=2)
OrderPosition.objects.create(order=order, item=self.item1, subevent=se2, price=2)
Voucher.objects.create(item=self.item1, event=self.event, valid_until=now() + timedelta(days=5),
block_quota=True, max_usages=6, subevent=se1)
Voucher.objects.create(item=self.item1, event=self.event, valid_until=now() + timedelta(days=5),
block_quota=True, max_usages=4, subevent=se2)
for i in range(8):
CartPosition.objects.create(event=self.event, item=self.item1, price=2, subevent=se1,
expires=now() + timedelta(days=3))
for i in range(5):
CartPosition.objects.create(event=self.event, item=self.item1, price=2, subevent=se2,
expires=now() + timedelta(days=3))
for i in range(16):
WaitingListEntry.objects.create(
event=self.event, item=self.item1, email='foo@bar.com', subevent=se1
)
for i in range(13):
WaitingListEntry.objects.create(
event=self.event, item=self.item1, email='foo@bar.com', subevent=se2
)
with self.assertRaises(TypeError):
self.item1.check_quotas()
self.assertEqual(self.item1.check_quotas(subevent=se1), (Quota.AVAILABILITY_OK, 50 - 5 - 6 - 8 - 16))
self.assertEqual(self.item1.check_quotas(subevent=se2), (Quota.AVAILABILITY_OK, 50 - 2 - 4 - 5 - 13))
self.assertEqual(q1.availability(), (Quota.AVAILABILITY_OK, 50 - 5 - 6 - 8 - 16))
self.assertEqual(q2.availability(), (Quota.AVAILABILITY_OK, 50 - 2 - 4 - 5 - 13))
self.event.has_subevents = False
self.event.save()
class WaitingListTestCase(BaseQuotaTestCase):
def test_duplicate(self):
w1 = WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
)
w1.clean()
w2 = WaitingListEntry(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
)
with self.assertRaises(ValidationError):
w2.clean()
def test_duplicate_of_successful(self):
v = Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, redeemed=1)
w1 = WaitingListEntry.objects.create(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com',
voucher=v
)
w1.clean()
w2 = WaitingListEntry(
event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com'
)
w2.clean()
def test_missing_variation(self):
w2 = WaitingListEntry(
event=self.event, item=self.item2, email='foo@bar.com'
)
with self.assertRaises(ValidationError):
w2.clean()
class VoucherTestCase(BaseQuotaTestCase):
def test_voucher_reuse(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() + timedelta(days=5))
self.assertTrue(v.is_active())
self.assertFalse(v.is_in_cart())
self.assertFalse(v.is_ordered())
# use a voucher normally
cart = CartPosition.objects.create(event=self.event, item=self.item1, price=self.item1.default_price,
expires=now() + timedelta(days=3), voucher=v)
self.assertTrue(v.is_active())
self.assertTrue(v.is_in_cart())
self.assertFalse(v.is_ordered())
order = perform_order(event=self.event.id, payment_provider='free', positions=[cart.id])
v.refresh_from_db()
self.assertFalse(v.is_active())
self.assertFalse(v.is_in_cart())
self.assertTrue(v.is_ordered())
# assert that the voucher cannot be reused
cart = CartPosition.objects.create(event=self.event, item=self.item1, price=self.item1.default_price,
expires=now() + timedelta(days=3), voucher=v)
self.assertRaises(OrderError, perform_order, event=self.event.id, payment_provider='free', positions=[cart.id])
# assert that the voucher can be re-used after cancelling the successful order
cancel_order(order)
v.refresh_from_db()
self.assertTrue(v.is_active())
self.assertFalse(v.is_in_cart())
self.assertTrue(v.is_ordered())
cart = CartPosition.objects.create(event=self.event, item=self.item1, price=self.item1.default_price,
expires=now() + timedelta(days=3), voucher=v)
perform_order(event=self.event.id, payment_provider='free', positions=[cart.id])
def test_voucher_applicability_quota(self):
self.quota.items.add(self.item1)
v = Voucher.objects.create(quota=self.quota, event=self.event)
self.assertTrue(v.applies_to(self.item1))
self.assertFalse(v.applies_to(self.item2))
def test_voucher_applicability_item(self):
v = Voucher.objects.create(item=self.var1.item, event=self.event)
self.assertFalse(v.applies_to(self.item1))
self.assertTrue(v.applies_to(self.var1.item))
self.assertTrue(v.applies_to(self.var1.item, self.var1))
def test_voucher_applicability_variation(self):
v = Voucher.objects.create(item=self.var1.item, variation=self.var1, event=self.event)
self.assertFalse(v.applies_to(self.item1))
self.assertFalse(v.applies_to(self.var1.item))
self.assertTrue(v.applies_to(self.var1.item, self.var1))
self.assertFalse(v.applies_to(self.var1.item, self.var2))
def test_voucher_no_item_with_quota(self):
with self.assertRaises(ValidationError):
v = Voucher(quota=self.quota, item=self.item1, event=self.event)
v.clean()
def test_voucher_item_with_no_variation(self):
with self.assertRaises(ValidationError):
v = Voucher(item=self.item1, variation=self.var1, event=self.event)
v.clean()
def test_voucher_item_does_not_match_variation(self):
with self.assertRaises(ValidationError):
v = Voucher(item=self.item2, variation=self.var3, event=self.event)
v.clean()
def test_voucher_specify_variation_for_block_quota(self):
with self.assertRaises(ValidationError):
v = Voucher(item=self.item2, block_quota=True, event=self.event)
v.clean()
def test_voucher_no_item_but_variation(self):
with self.assertRaises(ValidationError):
v = Voucher(variation=self.var1, event=self.event)
v.clean()
def test_calculate_price_none(self):
v = Voucher.objects.create(event=self.event, price_mode='none', value=Decimal('10.00'))
assert v.calculate_price(Decimal('23.42')) == Decimal('23.42')
def test_calculate_price_set_empty(self):
v = Voucher.objects.create(event=self.event, price_mode='set')
assert v.calculate_price(Decimal('23.42')) == Decimal('23.42')
def test_calculate_price_set(self):
v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('10.00'))
assert v.calculate_price(Decimal('23.42')) == Decimal('10.00')
def test_calculate_price_set_zero(self):
v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('0.00'))
assert v.calculate_price(Decimal('23.42')) == Decimal('0.00')
def test_calculate_price_subtract(self):
v = Voucher.objects.create(event=self.event, price_mode='subtract', value=Decimal('10.00'))
assert v.calculate_price(Decimal('23.42')) == Decimal('13.42')
def test_calculate_price_percent(self):
v = Voucher.objects.create(event=self.event, price_mode='percent', value=Decimal('23.00'))
assert v.calculate_price(Decimal('100.00')) == Decimal('77.00')
class OrderTestCase(BaseQuotaTestCase):
def setUp(self):
super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.order = Order.objects.create(
status=Order.STATUS_PENDING, event=self.event,
datetime=now() - timedelta(days=5),
expires=now() + timedelta(days=5), total=46
)
self.quota.items.add(self.item1)
self.op1 = OrderPosition.objects.create(order=self.order, item=self.item1,
variation=None, price=23)
self.op2 = OrderPosition.objects.create(order=self.order, item=self.item1,
variation=None, price=23)
def test_paid_in_time(self):
self.quota.size = 0
self.quota.save()
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_paid_expired_available(self):
self.event.settings.payment_term_last = (now() + timedelta(days=2)).strftime('%Y-%m-%d')
self.order.status = Order.STATUS_EXPIRED
self.order.expires = now() - timedelta(days=2)
self.order.save()
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_paid_expired_after_last_date(self):
self.event.settings.payment_term_last = (now() - timedelta(days=2)).strftime('%Y-%m-%d')
self.order.status = Order.STATUS_EXPIRED
self.order.expires = now() - timedelta(days=2)
self.order.save()
with self.assertRaises(Quota.QuotaExceededException):
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
def test_paid_expired_after_last_date_subevent_relative(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
self.op1.subevent = se1
self.op1.save()
self.op2.subevent = se2
self.op2.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
self.order.status = Order.STATUS_EXPIRED
self.order.expires = now() - timedelta(days=2)
self.order.save()
with self.assertRaises(Quota.QuotaExceededException):
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
self.event.has_subevents = False
self.event.save()
def test_paid_expired_late_not_allowed(self):
self.event.settings.payment_term_accept_late = False
self.order.status = Order.STATUS_EXPIRED
self.order.expires = now() - timedelta(days=2)
self.order.save()
with self.assertRaises(Quota.QuotaExceededException):
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
def test_paid_expired_unavailable(self):
self.event.settings.payment_term_accept_late = True
self.order.expires = now() - timedelta(days=2)
self.order.status = Order.STATUS_EXPIRED
self.order.save()
self.quota.size = 0
self.quota.save()
with self.assertRaises(Quota.QuotaExceededException):
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertIn(self.order.status, (Order.STATUS_PENDING, Order.STATUS_EXPIRED))
def test_paid_after_deadline_but_not_expired(self):
self.event.settings.payment_term_accept_late = True
self.order.expires = now() - timedelta(days=2)
self.order.save()
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_paid_expired_unavailable_force(self):
self.event.settings.payment_term_accept_late = True
self.order.expires = now() - timedelta(days=2)
self.order.status = Order.STATUS_EXPIRED
self.order.save()
self.quota.size = 0
self.quota.save()
mark_order_paid(self.order, force=True)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_paid_expired_unavailable_waiting_list(self):
self.event.settings.payment_term_accept_late = True
self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com')
self.order.expires = now() - timedelta(days=2)
self.order.status = Order.STATUS_EXPIRED
self.order.save()
self.quota.size = 2
self.quota.save()
with self.assertRaises(Quota.QuotaExceededException):
mark_order_paid(self.order)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_EXPIRED)
def test_paid_expired_unavailable_waiting_list_ignore(self):
self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com')
self.order.expires = now() - timedelta(days=2)
self.order.status = Order.STATUS_EXPIRED
self.order.save()
self.quota.size = 2
self.quota.save()
mark_order_paid(self.order, count_waitinglist=False)
self.order = Order.objects.get(id=self.order.id)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_can_modify_answers(self):
self.event.settings.set('invoice_address_asked', False)
self.event.settings.set('attendee_names_asked', True)
assert self.order.can_modify_answers
self.event.settings.set('attendee_names_asked', False)
assert not self.order.can_modify_answers
self.event.settings.set('invoice_address_asked', True)
assert self.order.can_modify_answers
q = Question.objects.create(question='Foo', type=Question.TYPE_BOOLEAN, event=self.event)
self.item1.questions.add(q)
assert self.order.can_modify_answers
self.order.status = Order.STATUS_REFUNDED
assert not self.order.can_modify_answers
self.order.status = Order.STATUS_PAID
assert self.order.can_modify_answers
self.event.settings.set('last_order_modification_date', now() - timedelta(days=1))
assert not self.order.can_modify_answers
def test_can_modify_answers_subevent(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
self.op1.subevent = se1
self.op1.save()
self.op2.subevent = se2
self.op2.save()
self.event.settings.set('last_order_modification_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
assert self.order.can_modify_answers
self.op2.subevent = se3
self.op2.save()
assert not self.order.can_modify_answers
self.event.has_subevents = False
self.event.save()
def test_payment_term_last_relative(self):
self.event.settings.set('payment_term_last', date(2017, 5, 3))
assert self.order.payment_term_last == datetime.datetime(2017, 5, 3, 23, 59, 59, tzinfo=pytz.UTC)
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=pytz.UTC)
self.event.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
assert self.order.payment_term_last == datetime.datetime(2017, 5, 1, 23, 59, 59, tzinfo=pytz.UTC)
def test_payment_term_last_subevent(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
self.op1.subevent = se1
self.op1.save()
self.op2.subevent = se2
self.op2.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
assert self.order.payment_term_last > now()
self.op2.subevent = se3
self.op2.save()
assert self.order.payment_term_last < now()
self.event.has_subevents = False
self.event.save()
def test_ticket_download_date_relative(self):
self.event.settings.set('ticket_download_date', datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC))
assert self.order.ticket_download_date == datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC)
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=pytz.UTC)
self.event.save()
self.event.settings.set('ticket_download_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
assert self.order.ticket_download_date == datetime.datetime(2017, 5, 1, 12, 0, 0, tzinfo=pytz.UTC)
def test_ticket_download_date_subevent(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
se2 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=8))
se3 = self.event.subevents.create(name="SE2", date_from=now() + timedelta(days=1))
self.op1.subevent = se1
self.op1.save()
self.op2.subevent = se2
self.op2.save()
self.event.settings.set('ticket_download_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from')
))
assert self.order.ticket_download_date > now()
self.op2.subevent = se3
self.op2.save()
assert self.order.ticket_download_date < now()
self.event.has_subevents = False
self.event.save()
def test_can_cancel_order(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
assert self.order.can_user_cancel
def test_can_cancel_order_multiple(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel
def test_can_not_cancel_order(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
assert self.order.can_user_cancel is False
def test_can_not_cancel_order_multiple(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel is False
def test_can_not_cancel_order_multiple_mixed(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel is False
def test_no_duplicate_position_secret(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
p1 = OrderPosition.objects.create(order=self.order, item=item1, secret='ABC',
variation=None, price=23)
p2 = OrderPosition.objects.create(order=self.order, item=item1, secret='ABC',
variation=None, price=23)
assert p1.secret != p2.secret
assert self.order.can_user_cancel is False
class ItemCategoryTest(TestCase):
"""
This test case tests various methods around the category model.
"""
@classmethod
def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy')
cls.event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
date_from=now(),
)
def test_sorting(self):
c1 = ItemCategory.objects.create(event=self.event)
c2 = ItemCategory.objects.create(event=self.event)
assert c1 < c2
c1.position = 2
c2.position = 1
assert c2 < c1
assert not c1 < c2
assert c1 > c2
c1.position = 1
c2.position = 2
assert c1 < c2
assert c2 > c1
class ItemTest(TestCase):
"""
This test case tests various methods around the item model.
"""
@classmethod
def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy')
cls.event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
date_from=now(),
)
def test_is_available(self):
i = Item.objects.create(
event=self.event, name="Ticket", default_price=23,
active=True, available_until=now() + timedelta(days=1),
)
assert i.is_available()
i.available_from = now() - timedelta(days=1)
assert i.is_available()
i.available_from = now() + timedelta(days=1)
i.available_until = None
assert not i.is_available()
i.available_from = None
i.available_until = now() - timedelta(days=1)
assert not i.is_available()
i.available_from = None
i.available_until = None
assert i.is_available()
i.active = False
assert not i.is_available()
class EventTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
def test_event_end_before_start(self):
event = Event(
organizer=self.organizer, name='Dummy', slug='dummy',
date_from=now(), date_to=now() - timedelta(hours=1)
)
with self.assertRaises(ValidationError) as context:
event.clean()
self.assertIn('date_to', str(context.exception))
def test_presale_end_before_start(self):
event = Event(
organizer=self.organizer, name='Dummy', slug='dummy',
presale_start=now(), presale_end=now() - timedelta(hours=1)
)
with self.assertRaises(ValidationError) as context:
event.clean()
self.assertIn('presale_end', str(context.exception))
def test_slug_validation(self):
event = Event(
organizer=self.organizer, name='Download', slug='download',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc)
)
with self.assertRaises(ValidationError) as context:
event.full_clean()
self.assertIn('slug', str(context.exception))
def test_copy(self):
event1 = Event.objects.create(
organizer=self.organizer, name='Download', slug='ab1234',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
is_public=True,
)
tr7 = event1.tax_rules.create(rate=Decimal('7.00'))
c1 = event1.categories.create(name='Tickets')
c2 = event1.categories.create(name='Workshops')
i1 = event1.items.create(name='Foo', default_price=Decimal('13.00'), tax_rule=tr7,
category=c1)
v1 = i1.variations.create(value='Bar')
i1.addons.create(addon_category=c2)
q1 = event1.quotas.create(name='Quota 1', size=50)
q1.items.add(i1)
q1.variations.add(v1)
que1 = event1.questions.create(question="Age", type="N")
que1.items.add(i1)
event1.settings.foo_setting = 23
event1.settings.tax_rate_default = tr7
event2 = Event.objects.create(
organizer=self.organizer, name='Download', slug='ab1234',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc)
)
event2.copy_data_from(event1)
for a in (tr7, c1, c2, i1, q1, que1):
a.refresh_from_db()
assert a.event == event1
trnew = event2.tax_rules.first()
assert trnew.rate == tr7.rate
c1new = event2.categories.get(name='Tickets')
c2new = event2.categories.get(name='Workshops')
i1new = event2.items.first()
assert i1new.name == i1.name
assert i1new.category == c1new
assert i1new.tax_rule == trnew
assert i1new.variations.count() == 1
assert i1new.addons.get(addon_category=c2new)
q1new = event2.quotas.first()
assert q1new.size == q1.size
assert q1new.items.get(pk=i1new.pk)
que1new = event2.questions.first()
assert que1new.type == que1.type
assert que1new.items.get(pk=i1new.pk)
assert event2.settings.foo_setting == '23'
assert event2.settings.tax_rate_default == trnew
class SubEventTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
cls.event = Event.objects.create(
organizer=cls.organizer, name='Dummy', slug='dummy',
date_from=now(), date_to=now() - timedelta(hours=1),
has_subevents=True
)
cls.se = SubEvent.objects.create(
name='Testsub', date_from=now(), event=cls.event
)
def test_override_prices(self):
i = Item.objects.create(
event=self.event, name="Ticket", default_price=23,
active=True, available_until=now() + timedelta(days=1),
)
SubEventItem.objects.create(item=i, subevent=self.se, price=Decimal('30.00'))
assert self.se.item_price_overrides == {
i.pk: Decimal('30.00')
}
def test_override_var_prices(self):
i = Item.objects.create(
event=self.event, name="Ticket", default_price=23,
active=True, available_until=now() + timedelta(days=1),
)
v = i.variations.create(value='Type 1')
SubEventItemVariation.objects.create(variation=v, subevent=self.se, price=Decimal('30.00'))
assert self.se.var_price_overrides == {
v.pk: Decimal('30.00')
}
class CachedFileTestCase(TestCase):
def test_file_handling(self):
cf = CachedFile()
val = SimpleUploadedFile("testfile.txt", b"file_content")
cf.file.save("testfile.txt", val)
cf.type = "text/plain"
cf.filename = "testfile.txt"
cf.save()
assert default_storage.exists(cf.file.name)
with default_storage.open(cf.file.name, 'r') as f:
assert f.read().strip() == "file_content"
cf.delete()
assert not default_storage.exists(cf.file.name)