Add unlimited_items_per_order-flag to Sales Channels (#1508)

* Add unlimited_items_per_order-flag to Sales Channels

* Test for unlimited_items_per_order Sales Channels-flag

* Fix test
This commit is contained in:
Martin Gross
2019-11-28 16:31:38 +01:00
committed by Raphael Michel
parent fd7ad3cb16
commit 0474651070
4 changed files with 50 additions and 9 deletions

View File

@@ -53,6 +53,14 @@ class SalesChannel:
""" """
return True return True
@property
def unlimited_items_per_order(self) -> bool:
"""
If this property is ``True``, purchases made using this sales channel are not limited to the maximum amount of
items defined in the event settings.
"""
return False
def get_all_sales_channels(): def get_all_sales_channels():
global _ALL_CHANNELS global _ALL_CHANNELS

View File

@@ -12,6 +12,7 @@ from django.utils.timezone import make_aware, now
from django.utils.translation import pgettext_lazy, ugettext as _ from django.utils.translation import pgettext_lazy, ugettext as _
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from pretix.base.channels import get_all_sales_channels
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
CartPosition, Event, InvoiceAddress, Item, ItemBundle, ItemVariation, Seat, CartPosition, Event, InvoiceAddress, Item, ItemBundle, ItemVariation, Seat,
@@ -218,13 +219,14 @@ class CartManager:
}) })
def _check_max_cart_size(self): def _check_max_cart_size(self):
cartsize = self.positions.filter(addon_to__isnull=True).count() if not get_all_sales_channels()[self._sales_channel].unlimited_items_per_order:
cartsize += sum([op.count for op in self._operations if isinstance(op, self.AddOperation) and not op.addon_to]) cartsize = self.positions.filter(addon_to__isnull=True).count()
cartsize -= len([1 for op in self._operations if isinstance(op, self.RemoveOperation) if cartsize += sum([op.count for op in self._operations if isinstance(op, self.AddOperation) and not op.addon_to])
not op.position.addon_to_id]) cartsize -= len([1 for op in self._operations if isinstance(op, self.RemoveOperation) if
if cartsize > int(self.event.settings.max_items_per_order): not op.position.addon_to_id])
# TODO: i18n plurals if cartsize > int(self.event.settings.max_items_per_order):
raise CartError(_(error_messages['max_items']) % (self.event.settings.max_items_per_order,)) # TODO: i18n plurals
raise CartError(_(error_messages['max_items']) % (self.event.settings.max_items_per_order,))
def _check_item_constraints(self, op): def _check_item_constraints(self, op):
if isinstance(op, self.AddOperation) or isinstance(op, self.ExtendOperation): if isinstance(op, self.AddOperation) or isinstance(op, self.ExtendOperation):

View File

@@ -17,6 +17,7 @@ from django.views import View
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView from django.views.generic import TemplateView
from pretix.base.channels import get_all_sales_channels
from pretix.base.models import ItemVariation, Quota, SeatCategoryMapping from pretix.base.models import ItemVariation, Quota, SeatCategoryMapping
from pretix.base.models.event import SubEvent from pretix.base.models.event import SubEvent
from pretix.base.models.items import ItemBundle from pretix.base.models.items import ItemBundle
@@ -119,7 +120,10 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
item.available_variations = [v for v in item.available_variations item.available_variations = [v for v in item.available_variations
if v.pk == voucher.variation_id] if v.pk == voucher.variation_id]
max_per_order = item.max_per_order or int(event.settings.max_items_per_order) if get_all_sales_channels()[channel].unlimited_items_per_order:
max_per_order = sys.maxsize
else:
max_per_order = item.max_per_order or int(event.settings.max_items_per_order)
if item.hidden_if_available: if item.hidden_if_available:
q = item.hidden_if_available.availability(_cache=quota_cache) q = item.hidden_if_available.availability(_cache=quota_cache)

View File

@@ -4,6 +4,7 @@ from datetime import timedelta
from decimal import Decimal from decimal import Decimal
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from django.dispatch import receiver
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import now from django.utils.timezone import now
from django_countries.fields import Country from django_countries.fields import Country
@@ -21,6 +22,7 @@ from pretix.base.models.items import (
from pretix.base.services.cart import ( from pretix.base.services.cart import (
CartError, CartManager, error_messages, update_tax_rates, CartError, CartManager, error_messages, update_tax_rates,
) )
from pretix.base.signals import register_sales_channels
from pretix.testutils.scope import classscope from pretix.testutils.scope import classscope
from pretix.testutils.sessions import get_cart_session_key from pretix.testutils.sessions import get_cart_session_key
@@ -29,7 +31,15 @@ class FoobarSalesChannel(SalesChannel):
identifier = "bar" identifier = "bar"
verbose_name = "Foobar" verbose_name = "Foobar"
icon = "home" icon = "home"
testmode_supported = True testmode_supported = False
unlimited_items_per_order = True
@receiver(register_sales_channels, dispatch_uid="test_cart_register_sales_channels")
def base_sales_channels(sender, **kwargs):
return (
FoobarSalesChannel(),
)
class CartTestMixin: class CartTestMixin:
@@ -816,6 +826,23 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled(): with scopes_disabled():
self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key, event=self.event).count(), 1) self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key, event=self.event).count(), 1)
def test_max_items_unlimited_sales_channel(self):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10)
)
self.event.settings.max_items_per_order = 5
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'item_%d' % self.ticket.id: '5',
}, follow=True, PRETIX_SALES_CHANNEL=FoobarSalesChannel)
self.assertRedirects(response, '/%s/%s/?require_cookie=true' % (self.orga.slug, self.event.slug),
target_status_code=200)
doc = BeautifulSoup(response.rendered_content, "lxml")
self.assertNotIn('more than', doc.select('.alert-danger')[0].text)
with scopes_disabled():
self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key, event=self.event).count(), 1)
def test_max_per_item_failed(self): def test_max_per_item_failed(self):
self.ticket.max_per_order = 2 self.ticket.max_per_order = 2
self.ticket.save() self.ticket.save()