mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
Added the option of unlimited quotas
This commit is contained in:
19
src/pretix/base/migrations/0002_auto_20151021_1412.py
Normal file
19
src/pretix/base/migrations/0002_auto_20151021_1412.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pretixbase', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='quota',
|
||||||
|
name='size',
|
||||||
|
field=models.PositiveIntegerField(help_text='Leave empty for an unlimited number of tickets.', verbose_name='Total capacity', blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from itertools import product
|
from itertools import product
|
||||||
|
import sys
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q, Case, Count, Sum, When
|
from django.db.models import Q, Case, Count, Sum, When
|
||||||
@@ -315,7 +316,8 @@ class Item(Versionable):
|
|||||||
if self.properties.count() > 0: # NOQA
|
if self.properties.count() > 0: # NOQA
|
||||||
raise ValueError('Do not call this directly on items which have properties '
|
raise ValueError('Do not call this directly on items which have properties '
|
||||||
'but call this on their ItemVariation objects')
|
'but call this on their ItemVariation objects')
|
||||||
return min([q.availability() for q in self.quotas.all()])
|
return min([q.availability() for q in self.quotas.all()],
|
||||||
|
key=lambda s: (s[0], s[1] if s[1] is not None else sys.maxsize))
|
||||||
|
|
||||||
def check_restrictions(self):
|
def check_restrictions(self):
|
||||||
"""
|
"""
|
||||||
@@ -513,7 +515,8 @@ class ItemVariation(Versionable):
|
|||||||
|
|
||||||
:returns: any of the return codes of :py:meth:`Quota.availability()`.
|
:returns: any of the return codes of :py:meth:`Quota.availability()`.
|
||||||
"""
|
"""
|
||||||
return min([q.availability() for q in self.quotas.all()])
|
return min([q.availability() for q in self.quotas.all()],
|
||||||
|
key=lambda s: (s[0], s[1] if s[1] is not None else sys.maxsize))
|
||||||
|
|
||||||
def to_variation_dict(self):
|
def to_variation_dict(self):
|
||||||
"""
|
"""
|
||||||
@@ -769,7 +772,9 @@ class Quota(Versionable):
|
|||||||
verbose_name=_("Name")
|
verbose_name=_("Name")
|
||||||
)
|
)
|
||||||
size = models.PositiveIntegerField(
|
size = models.PositiveIntegerField(
|
||||||
verbose_name=_("Total capacity")
|
verbose_name=_("Total capacity"),
|
||||||
|
null=True, blank=True,
|
||||||
|
help_text=_("Leave empty for an unlimited number of tickets.")
|
||||||
)
|
)
|
||||||
items = VersionedManyToManyField(
|
items = VersionedManyToManyField(
|
||||||
Item,
|
Item,
|
||||||
@@ -810,6 +815,9 @@ class Quota(Versionable):
|
|||||||
and the second is the number of available tickets.
|
and the second is the number of available tickets.
|
||||||
"""
|
"""
|
||||||
size_left = self.size
|
size_left = self.size
|
||||||
|
if size_left is None:
|
||||||
|
return Quota.AVAILABILITY_OK, None
|
||||||
|
|
||||||
# TODO: Test for interference with old versions of Item-Quota-relations, etc.
|
# TODO: Test for interference with old versions of Item-Quota-relations, etc.
|
||||||
# TODO: Prevent corner-cases like people having ordered an item before it got
|
# TODO: Prevent corner-cases like people having ordered an item before it got
|
||||||
# its first variationsadde
|
# its first variationsadde
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ class Order(Versionable):
|
|||||||
else:
|
else:
|
||||||
# Use cached version
|
# Use cached version
|
||||||
quota = quota_cache[quota.identity]
|
quota = quota_cache[quota.identity]
|
||||||
|
if quota.cached_availability is not None:
|
||||||
quota.cached_availability -= 1
|
quota.cached_availability -= 1
|
||||||
if quota.cached_availability < 0:
|
if quota.cached_availability < 0:
|
||||||
# This quota is sold out/currently unavailable, so do not sell this at all
|
# This quota is sold out/currently unavailable, so do not sell this at all
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def _add_items(event, items, session, expiry):
|
|||||||
quota_ok = i[2]
|
quota_ok = i[2]
|
||||||
for quota in quotas:
|
for quota in quotas:
|
||||||
avail = quota.availability()
|
avail = quota.availability()
|
||||||
if avail[1] < i[2]:
|
if avail[1] is not None and avail[1] < i[2]:
|
||||||
# This quota is not available or less than i[2] items are left, so we have to
|
# This quota is not available or less than i[2] items are left, so we have to
|
||||||
# reduce the number of bought items
|
# reduce the number of bought items
|
||||||
if avail[0] != Quota.AVAILABILITY_OK:
|
if avail[0] != Quota.AVAILABILITY_OK:
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
{% if availability.0 == 10 %}
|
{% if availability.0 == 10 %}
|
||||||
<span class="label label-warning">{% trans "Sold out (pending orders)" %}</span>
|
<span class="label label-warning">{% trans "Sold out (pending orders)" %}</span>
|
||||||
{% elif availability.0 == 100 %}
|
{% elif availability.0 == 100 %}
|
||||||
|
{% if availability.1 != None %}
|
||||||
<span class="label label-success">{% blocktrans trimmed with num=availability.1 %}
|
<span class="label label-success">{% blocktrans trimmed with num=availability.1 %}
|
||||||
{{ num }} available{% endblocktrans %}</span>
|
{{ num }} available{% endblocktrans %}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="label label-success">{% trans "Unlimited" %}</span>
|
||||||
|
{% endif %}
|
||||||
{% elif availability.0 == 20 %}
|
{% elif availability.0 == 20 %}
|
||||||
<span class="label label-warning">{% trans "Sold out (or reserved)" %}</span>
|
<span class="label label-warning">{% trans "Sold out (or reserved)" %}</span>
|
||||||
{% elif availability.0 == 0 %}
|
{% elif availability.0 == 0 %}
|
||||||
|
|||||||
@@ -303,6 +303,19 @@ class QuotaTestCase(BaseQuotaTestCase):
|
|||||||
quota2.save()
|
quota2.save()
|
||||||
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
|
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0))
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
class OrderTestCase(BaseQuotaTestCase):
|
class OrderTestCase(BaseQuotaTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user