mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
Determine not only availability, but number of remaining tickets
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{% load i18n %}
|
||||
{% if avail == 30 %}
|
||||
{% if avail == 0 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box gone">
|
||||
<strong>{% trans "SOLD OUT" %}</strong>
|
||||
</div>
|
||||
{% elif avail < 30 %}
|
||||
{% elif avail < 100 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box unavailable">
|
||||
<strong>{% trans "Unavailable" %}</strong><br />
|
||||
<small>
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if var.cached_availability == 0 %}
|
||||
{% if var.cached_availability.0 == 100 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box available">
|
||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0">
|
||||
</div>
|
||||
{% else %}
|
||||
{% include "pretixpresale/event/fragment_availability.html" with avail=var.cached_availability %}
|
||||
{% include "pretixpresale/event/fragment_availability.html" with avail=var.cached_availability.0 %}
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
@@ -51,12 +51,12 @@
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if item.cached_availability == 0 %}
|
||||
{% if item.cached_availability.0 == 100 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box available">
|
||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0">
|
||||
</div>
|
||||
{% else %}
|
||||
{% include "pretixpresale/event/fragment_availability.html" with avail=item.cached_availability %}
|
||||
{% include "pretixpresale/event/fragment_availability.html" with avail=item.cached_availability.0 %}
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user