forked from CGM_Public/pretix_original
Waiting list: group product choices by category (#6006)
* Group waiting list product choices by category Use optgroups to group products by category in the waiting list selection dropdown. Products are normally separated in the UI by category grouping, but this context is lost in the waiting list form. When multiple products share the same name, this can make it difficult for customers to distinguish between them. * Add tests for waiting list initial selection with optgroups Verify that the initial product selection (via `?item=` and `?var=` query parameters) works correctly when choices are grouped by category into `<optgroup>`s. Covers both plain items and items with variations.
This commit is contained in:
@@ -66,22 +66,27 @@ class WaitingView(EventViewMixin, FormView):
|
||||
if customer else None
|
||||
),
|
||||
)
|
||||
choices = []
|
||||
groups = {}
|
||||
for i in items:
|
||||
if not i.allow_waitinglist:
|
||||
continue
|
||||
|
||||
category_name = str(i.category.name) if i.category else ''
|
||||
group = groups.setdefault(category_name, [])
|
||||
|
||||
if i.has_variations:
|
||||
for v in i.available_variations:
|
||||
if v.cached_availability[0] == Quota.AVAILABILITY_OK:
|
||||
continue
|
||||
choices.append((f'{i.pk}-{v.pk}', f'{i.name} – {v.value}'))
|
||||
group.append((f'{i.pk}-{v.pk}', f'{i.name} – {v.value}'))
|
||||
|
||||
else:
|
||||
if i.cached_availability[0] == Quota.AVAILABILITY_OK:
|
||||
continue
|
||||
choices.append((f'{i.pk}', f'{i.name}'))
|
||||
return choices
|
||||
group.append((f'{i.pk}', f'{i.name}'))
|
||||
|
||||
# Remove categories where all items were available (no waiting list choices)
|
||||
return [(cat, choices) for cat, choices in groups.items() if choices]
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
|
||||
@@ -1162,6 +1162,65 @@ class WaitingListTest(EventTestMixin, SoupTest):
|
||||
assert wle.voucher is None
|
||||
assert wle.locale == 'en'
|
||||
|
||||
def test_initial_selection(self):
|
||||
with scopes_disabled():
|
||||
cat = ItemCategory.objects.create(event=self.event, name='Tickets')
|
||||
self.item.category = cat
|
||||
self.item.save()
|
||||
|
||||
item2 = Item.objects.create(
|
||||
event=self.event, name='VIP ticket',
|
||||
default_price=Decimal('25.00'),
|
||||
active=True, category=cat,
|
||||
)
|
||||
self.q.items.add(item2)
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d' % (
|
||||
self.orga.slug, self.event.slug, item2.pk
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
doc = BeautifulSoup(response.render().content, "lxml")
|
||||
|
||||
select = doc.find('select', {'name': 'itemvar'})
|
||||
optgroup = select.find('optgroup')
|
||||
self.assertIsNotNone(optgroup, 'Choices should be grouped by category')
|
||||
self.assertEqual(optgroup['label'], 'Tickets')
|
||||
|
||||
selected = select.find_all('option', selected=True)
|
||||
self.assertEqual(len(selected), 1, 'Exactly one option should be pre-selected')
|
||||
self.assertEqual(selected[0]['value'], str(item2.pk))
|
||||
|
||||
def test_initial_selection_with_variation(self):
|
||||
with scopes_disabled():
|
||||
cat = ItemCategory.objects.create(event=self.event, name='Tickets')
|
||||
self.item.category = cat
|
||||
self.item.has_variations = True
|
||||
self.item.save()
|
||||
|
||||
var1 = ItemVariation.objects.create(item=self.item, value='Standard')
|
||||
var2 = ItemVariation.objects.create(item=self.item, value='Premium')
|
||||
self.q.variations.add(var1, var2)
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/waitinglist/?item=%d&var=%d' % (
|
||||
self.orga.slug, self.event.slug,
|
||||
self.item.pk, var2.pk,
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
doc = BeautifulSoup(response.render().content, "lxml")
|
||||
|
||||
select = doc.find('select', {'name': 'itemvar'})
|
||||
optgroup = select.find('optgroup')
|
||||
self.assertIsNotNone(optgroup, 'Choices should be grouped by category')
|
||||
self.assertEqual(optgroup['label'], 'Tickets')
|
||||
|
||||
selected = select.find_all('option', selected=True)
|
||||
self.assertEqual(len(selected), 1, 'Exactly one option should be pre-selected')
|
||||
self.assertEqual(selected[0]['value'], '%d-%d' % (self.item.pk, var2.pk))
|
||||
|
||||
def test_subevent_valid(self):
|
||||
with scopes_disabled():
|
||||
self.event.has_subevents = True
|
||||
|
||||
Reference in New Issue
Block a user