Add upper limit on positions in an order (#3806)

* Add upper limit on positions in an order

* Fix form validation
This commit is contained in:
Raphael Michel
2024-01-19 18:14:45 +01:00
committed by GitHub
parent 1f465ddddb
commit 4fb49820af
10 changed files with 97 additions and 3 deletions

View File

@@ -41,6 +41,7 @@ from typing import List, Optional
from celery.exceptions import MaxRetriesExceededError
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import DatabaseError, transaction
from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Value
@@ -378,8 +379,9 @@ class CartManager:
cartsize += sum([op.count for op in self._operations if isinstance(op, self.AddOperation) and not op.addon_to])
cartsize -= len([1 for op in self._operations if isinstance(op, self.RemoveOperation) if
not op.position.addon_to_id])
if cartsize > int(self.event.settings.max_items_per_order):
raise CartError(error_messages['max_items'] % self.event.settings.max_items_per_order)
limit = min(int(self.event.settings.max_items_per_order), settings.PRETIX_MAX_ORDER_SIZE)
if cartsize > limit:
raise CartError(error_messages['max_items'] % limit)
def _check_item_constraints(self, op, current_ops=[]):
if isinstance(op, (self.AddOperation, self.ExtendOperation)):

View File

@@ -23,6 +23,7 @@ import csv
import io
from decimal import Decimal
from django.conf import settings as django_settings
from django.core.exceptions import ValidationError
from django.db import transaction
from django.utils.timezone import now
@@ -124,6 +125,11 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
)
data.append(values)
if settings['orders'] == 'one' and len(data) > django_settings.PRETIX_MAX_ORDER_SIZE:
raise DataImportError(
_('Orders cannot have more than %(max)s positions.') % {'max': django_settings.PRETIX_MAX_ORDER_SIZE}
)
# Prepare model objects. Yes, this might consume lots of RAM, but allows us to make the actual SQL transaction
# shorter. We'll see what works better in reality…
lock_seats = []

View File

@@ -1512,6 +1512,7 @@ class OrderChangeManager:
"You need to select at least %(min)s items of the product %(product)s.",
"min"
),
'max_order_size': gettext_lazy('Orders cannot have more than %(max)s positions.'),
}
ItemOperation = namedtuple('ItemOperation', ('position', 'item', 'variation'))
SubeventOperation = namedtuple('SubeventOperation', ('position', 'subevent'))
@@ -2599,6 +2600,14 @@ class OrderChangeManager:
self.order.total = total + payment_fee
self.order.save()
def _check_order_size(self):
if (len(self.order.positions.all()) + len([op for op in self._operations if isinstance(op, self.AddOperation)])) > settings.PRETIX_MAX_ORDER_SIZE:
raise OrderError(
self.error_messages['max_order_size'] % {
'max': settings.PRETIX_MAX_ORDER_SIZE,
}
)
def _payment_fee_diff(self):
total = self.order.total + self._totaldiff
if self.open_payment:
@@ -2739,6 +2748,7 @@ class OrderChangeManager:
# finally, incorporate difference in payment fees
self._payment_fee_diff()
self._check_order_size()
with transaction.atomic():
locked_instance = Order.objects.select_for_update(of=OF_SELF).get(pk=self.order.pk)