Add OrderPosition.ignore_from_quota_while_blocked (#3119)

This commit is contained in:
Raphael Michel
2023-02-22 12:44:51 +01:00
committed by GitHub
parent 175921fbaf
commit f08333814f
5 changed files with 53 additions and 8 deletions

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.17 on 2023-02-14 10:35
import django.core.serializers.json
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0232_exchangerate'),
]
operations = [
migrations.AddField(
model_name='orderposition',
name='ignore_from_quota_while_blocked',
field=models.BooleanField(default=False),
),
]

View File

@@ -2212,6 +2212,9 @@ class OrderPosition(AbstractPosition):
description by a plugin. If the position is not blocked, the value must be ``None``, not an empty
list.
:type blocked: list
:param ignore_from_quota_while_blocked: Ignore this order position from quota, as long as ``blocked`` is set. Only
to be used carefully by specific plugins.
:type ignore_from_quota_while_blocked: boolean
:param valid_from: The ticket will not be considered valid before this date. If the value is ``None``, no check on
ticket level is made.
:type valid_from: datetime
@@ -2257,6 +2260,7 @@ class OrderPosition(AbstractPosition):
canceled = models.BooleanField(default=False)
blocked = models.JSONField(null=True, blank=True)
ignore_from_quota_while_blocked = models.BooleanField(default=False)
valid_from = models.DateTimeField(
verbose_name=_("Valid from"),
null=True,

View File

@@ -1437,8 +1437,8 @@ class OrderChangeManager:
RegenerateSecretOperation = namedtuple('RegenerateSecretOperation', ('position',))
ChangeValidFromOperation = namedtuple('ChangeValidFromOperation', ('position', 'valid_from'))
ChangeValidUntilOperation = namedtuple('ChangeValidUntilOperation', ('position', 'valid_until'))
AddBlockOperation = namedtuple('AddBlockOperation', ('position', 'block_name'))
RemoveBlockOperation = namedtuple('RemoveBlockOperation', ('position', 'block_name'))
AddBlockOperation = namedtuple('AddBlockOperation', ('position', 'block_name', 'ignore_from_quota_while_blocked'))
RemoveBlockOperation = namedtuple('RemoveBlockOperation', ('position', 'block_name', 'ignore_from_quota_while_blocked'))
def __init__(self, order: Order, user=None, auth=None, notify=True, reissue_invoice=True):
self.order = order
@@ -1548,11 +1548,11 @@ class OrderChangeManager:
def change_valid_until(self, position: OrderPosition, new_value: datetime):
self._operations.append(self.ChangeValidUntilOperation(position, new_value))
def add_block(self, position: OrderPosition, block_name: str):
self._operations.append(self.AddBlockOperation(position, block_name))
def add_block(self, position: OrderPosition, block_name: str, ignore_from_quota_while_blocked=None):
self._operations.append(self.AddBlockOperation(position, block_name, ignore_from_quota_while_blocked))
def remove_block(self, position: OrderPosition, block_name: str):
self._operations.append(self.RemoveBlockOperation(position, block_name))
def remove_block(self, position: OrderPosition, block_name: str, ignore_from_quota_while_blocked=None):
self._operations.append(self.RemoveBlockOperation(position, block_name, ignore_from_quota_while_blocked))
def change_price(self, position: OrderPosition, price: Decimal):
tax_rule = self._current_tax_rules().get(position.pk, position.tax_rule) or TaxRule.zero()
@@ -2258,7 +2258,9 @@ class OrderChangeManager:
op.position.blocked = op.position.blocked + [op.block_name]
else:
op.position.blocked = [op.block_name]
op.position.save(update_fields=['blocked'])
if op.ignore_from_quota_while_blocked is not None:
op.position.ignore_from_quota_while_blocked = op.ignore_from_quota_while_blocked
op.position.save(update_fields=['blocked', 'ignore_from_quota_while_blocked'])
if op.position.blocked:
op.position.blocked_secrets.update_or_create(
event=self.event,
@@ -2278,7 +2280,9 @@ class OrderChangeManager:
op.position.blocked = [b for b in op.position.blocked if b != op.block_name]
if not op.position.blocked:
op.position.blocked = None
op.position.save(update_fields=['blocked'])
if op.ignore_from_quota_while_blocked is not None:
op.position.ignore_from_quota_while_blocked = op.ignore_from_quota_while_blocked
op.position.save(update_fields=['blocked', 'ignore_from_quota_while_blocked'])
if not op.position.blocked:
try:
bs = op.position.blocked_secrets.get(secret=op.position.secret)

View File

@@ -295,6 +295,8 @@ class QuotaAvailability:
Q(item_id__in={i['item_id'] for i in q_items if i['quota_id'] in quota_ids})
) | Q(
variation_id__in={i['itemvariation_id'] for i in q_vars if i['quota_id'] in quota_ids})
).filter(
~Q(Q(ignore_from_quota_while_blocked=True) & Q(blocked__isnull=False))
).order_by()
if any(q.release_after_exit for q in quotas):
op_lookup = op_lookup.annotate(

View File

@@ -483,6 +483,22 @@ class QuotaTestCase(BaseQuotaTestCase):
with self.assertNumQueries(1):
self.assertEqual(self.var1.check_quotas(_cache=cache, count_waitinglist=False), (Quota.AVAILABILITY_OK, 1))
@classscope(attr='o')
def test_ignore_if_blocked(self):
q1 = self.event.quotas.create(name="Q1", size=50)
q1.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, price=2)
OrderPosition.objects.create(order=order, item=self.item1, price=2, blocked=["foo"])
OrderPosition.objects.create(order=order, item=self.item1, price=2, blocked=["foo"], ignore_from_quota_while_blocked=True)
OrderPosition.objects.create(order=order, item=self.item1, price=2, ignore_from_quota_while_blocked=True)
self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 47))
@classscope(attr='o')
def test_subevent_isolation(self):
self.event.has_subevents = True