diff --git a/doc/user/events/widget.rst b/doc/user/events/widget.rst
index 8182db5fc..a9d84f514 100644
--- a/doc/user/events/widget.rst
+++ b/doc/user/events/widget.rst
@@ -135,6 +135,10 @@ Alternatively, you can select one or more categories to be shown::
+Or variation IDs::
+
+
+
Multi-event selection
---------------------
diff --git a/src/pretix/presale/views/widget.py b/src/pretix/presale/views/widget.py
index b2090c5e2..bf531749d 100644
--- a/src/pretix/presale/views/widget.py
+++ b/src/pretix/presale/views/widget.py
@@ -54,7 +54,7 @@ from lxml import html
from pretix.base.context import get_powered_by
from pretix.base.i18n import language
-from pretix.base.models import CartPosition, Event, Quota, SubEvent, Voucher
+from pretix.base.models import CartPosition, Event, Quota, SubEvent, Voucher, ItemVariation
from pretix.base.services.cart import error_messages
from pretix.base.settings import GlobalSettingsObject
from pretix.base.templatetags.rich_text import rich_text
@@ -222,9 +222,18 @@ class WidgetAPIProductList(EventListMixin, View):
def _get_items(self):
qs = self.request.event.items
if 'items' in self.request.GET:
- qs = qs.filter(pk__in=self.request.GET.get('items').split(","))
+ qs = qs.filter(pk__in=[pk for pk in self.request.GET.get('items').split(",") if pk.isdigit()])
if 'categories' in self.request.GET:
- qs = qs.filter(category__pk__in=self.request.GET.get('categories').split(","))
+ qs = qs.filter(category__pk__in=[pk for pk in self.request.GET.get('categories').split(",") if pk.isdigit()])
+ variation_filter = None
+ if 'variations' in self.request.GET:
+ variation_filter = [int(pk) for pk in self.request.GET.get('variations').split(",") if pk.isdigit()]
+ qs = qs.filter(
+ pk__in=ItemVariation.objects.filter(
+ item__event=self.request.event,
+ pk__in=variation_filter,
+ ).values_list('item_id', flat=True)
+ )
items, display_add_to_cart = get_grouped_items(
self.request.event,
@@ -295,7 +304,7 @@ class WidgetAPIProductList(EventListMixin, View):
var.cached_availability[0],
var.cached_availability[1] if item.do_show_quota_left else None
],
- } for var in item.available_variations
+ } for var in item.available_variations if (not variation_filter or var.id in variation_filter)
]
} for item in g
diff --git a/src/tests/presale/test_widget.py b/src/tests/presale/test_widget.py
index 6dc61af5b..03e331eff 100644
--- a/src/tests/presale/test_widget.py
+++ b/src/tests/presale/test_widget.py
@@ -290,6 +290,50 @@ class WidgetCartTest(CartTestMixin, TestCase):
data = json.loads(response.content.decode())
assert len(data['items_by_category']) == 0
+ def test_product_list_view_variation_filter(self):
+ response = self.client.get('/%s/%s/widget/product_list?variations=%s' % (self.orga.slug, self.event.slug,
+ self.shirt_red.pk))
+ assert response['Access-Control-Allow-Origin'] == '*'
+ data = json.loads(response.content.decode())
+ assert data['items_by_category'] == [
+ {
+ "items": [
+ {
+ "require_voucher": False,
+ "order_min": None,
+ "max_price": "14.00",
+ "price": None,
+ "picture": None,
+ "has_variations": 4,
+ "allow_waitinglist": True,
+ "description": None,
+ "min_price": "12.00",
+ "avail": None,
+ "variations": [
+ {
+ "value": "Red",
+ "id": self.shirt_red.pk,
+ 'original_price': None,
+ "price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "",
+ "rate": "19.00", "includes_mixed_tax_rate": False},
+ "description": None,
+ "avail": [100, None],
+ "order_max": 2
+ }
+ ],
+ "id": self.shirt.pk,
+ "free_price": False,
+ "original_price": None,
+ "name": "T-Shirt",
+ "order_max": None
+ }
+ ],
+ "description": None,
+ "id": self.category.pk,
+ "name": "Everything"
+ }
+ ]
+
def test_product_list_view_with_voucher(self):
with scopes_disabled():
self.event.vouchers.create(item=self.ticket, code="ABCDE")