diff --git a/src/pretixbase/models.py b/src/pretixbase/models.py index baf93a4b0e..d0bb354058 100644 --- a/src/pretixbase/models.py +++ b/src/pretixbase/models.py @@ -781,7 +781,7 @@ class Item(Versionable): if self.properties.count() > 0: raise ValueError('Do not call this directly on items which have properties ' 'but call this on their ItemVariation objects') - return max([q.availability() for q in self.quotas.all()]) + return min([q.availability() for q in self.quotas.all()]) class ItemVariation(Versionable): @@ -840,7 +840,7 @@ class ItemVariation(Versionable): This method is used to determine whether this Item is currently available for sale. It may return any of the return codes of Quota.availability() """ - return max([q.availability() for q in self.quotas.all()]) + return min([q.availability() for q in self.quotas.all()]) class VariationsField(VersionedManyToManyField): @@ -929,7 +929,7 @@ class Quota(Versionable): anything with quotas. This might confuse you otherwise. http://docs.pretix.eu/en/latest/development/concepts.html#restriction-by-number - The AVAILABILITY_* constants represent varios states of an quota allowing + The AVAILABILITY_* constants represent various states of an quota allowing its items/variations being for sale. AVAILABILITY_OK @@ -949,10 +949,10 @@ class Quota(Versionable): This item is completely sold out. """ - AVAILABILITY_GONE = 30 - AVAILABILITY_ORDERED = 20 - AVAILABILITY_RESERVED = 10 - AVAILABILITY_OK = 0 + AVAILABILITY_GONE = 0 + AVAILABILITY_ORDERED = 10 + AVAILABILITY_RESERVED = 20 + AVAILABILITY_OK = 100 event = VersionedForeignKey( Event, @@ -1000,9 +1000,9 @@ class Quota(Versionable): def availability(self): """ This method is used to determine whether Items or ItemVariations belonging - to this quota should currently be available for sale. It returns one of the - Quota.AVAILABILITY_ constants. 0 is returned if the item is available, a - positive number depending on the reason, if not. + to this quota should currently be available for sale. It returns a tuple where + the first entry is one of the Quota.AVAILABILITY_ constants and the second + is the number of available tickets. """ # TODO: These lookups are highly inefficient. However, we'll wait with optimizing # until Django 1.8 is released, as the following feature might make it a @@ -1024,7 +1024,7 @@ class Quota(Versionable): & quotalookup ).count() if paid_orders >= self.size: - return Quota.AVAILABILITY_GONE + return (Quota.AVAILABILITY_GONE, 0) pending_valid_orders = OrderPosition.objects.filter( Q(order__status=Order.STATUS_PENDING) @@ -1032,16 +1032,16 @@ class Quota(Versionable): & quotalookup ).count() if (paid_orders + pending_valid_orders) >= self.size: - return Quota.AVAILABILITY_ORDERED + return (Quota.AVAILABILITY_ORDERED, 0) valid_cart_positions = CartPosition.objects.filter( Q(expires__gte=now()) & quotalookup ).count() if (paid_orders + pending_valid_orders + valid_cart_positions) >= self.size: - return Quota.AVAILABILITY_RESERVED + return (Quota.AVAILABILITY_RESERVED, 0) - return Quota.AVAILABILITY_OK + return (Quota.AVAILABILITY_OK, self.size - paid_orders - pending_valid_orders - valid_cart_positions) class Order(Versionable): diff --git a/src/pretixbase/tests/test_models.py b/src/pretixbase/tests/test_models.py index c8e67f146b..68becc1b00 100644 --- a/src/pretixbase/tests/test_models.py +++ b/src/pretixbase/tests/test_models.py @@ -202,7 +202,7 @@ class QuotaTestCase(TestCase): def test_available(self): self.quota.items.add(self.item1) - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_OK, 2)) self.quota.items.add(self.item2) self.quota.variations.add(self.var1) try: @@ -210,7 +210,7 @@ class QuotaTestCase(TestCase): self.assertTrue(False) except: pass - self.assertEqual(self.var1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.var1.availability(), (Quota.AVAILABILITY_OK, 2)) def test_sold_out(self): self.quota.items.add(self.item1) @@ -219,19 +219,19 @@ class QuotaTestCase(TestCase): 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.availability(), Quota.AVAILABILITY_GONE) + self.assertEqual(self.item1.availability(), (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.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.var1.availability(), (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.availability(), Quota.AVAILABILITY_GONE) + self.assertEqual(self.var1.availability(), (Quota.AVAILABILITY_GONE, 0)) def test_ordered(self): self.quota.items.add(self.item1) @@ -239,17 +239,17 @@ class QuotaTestCase(TestCase): expires=now() + timedelta(days=3), total=4) OrderPosition.objects.create(order=order, item=self.item1, price=2) - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (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.availability(), Quota.AVAILABILITY_ORDERED) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_ORDERED, 0)) order.expires = now() - timedelta(days=3) order.save() - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_OK, 1)) def test_reserved(self): self.quota.items.add(self.item1) @@ -259,32 +259,36 @@ class QuotaTestCase(TestCase): expires=now() + timedelta(days=3), total=4) OrderPosition.objects.create(order=order, item=self.item1, price=2) - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (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.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (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.availability(), Quota.AVAILABILITY_RESERVED) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_RESERVED, 0)) cp.expires = now() - timedelta(days=3) cp.save() - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (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.availability(), Quota.AVAILABILITY_RESERVED) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_RESERVED, 0)) def test_multiple(self): self.quota.items.add(self.item1) - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_OK) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_OK, 2)) - quota2 = Quota.objects.create(event=self.event, name="Test 2", size=0) + quota2 = Quota.objects.create(event=self.event, name="Test 2", size=1) quota2.items.add(self.item1) - self.assertEqual(self.item1.availability(), Quota.AVAILABILITY_GONE) + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_OK, 1)) + + quota2.size = 0 + quota2.save() + self.assertEqual(self.item1.availability(), (Quota.AVAILABILITY_GONE, 0)) diff --git a/src/pretixpresale/templates/pretixpresale/event/fragment_availability.html b/src/pretixpresale/templates/pretixpresale/event/fragment_availability.html index bf8792446b..411ad9a622 100644 --- a/src/pretixpresale/templates/pretixpresale/event/fragment_availability.html +++ b/src/pretixpresale/templates/pretixpresale/event/fragment_availability.html @@ -1,9 +1,9 @@ {% load i18n %} -{% if avail == 30 %} +{% if avail == 0 %}