diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 03cf209c8..ca22fd08a 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -124,6 +124,9 @@ class QuotaForm(I18nModelForm): class ItemCreateForm(I18nModelForm): + NONE = 'none' + EXISTING = 'existing' + NEW = 'new' has_variations = forms.BooleanField(label=_('The product should exist in multiple variations'), help_text=_('Select this option e.g. for t-shirts that come in multiple sizes. ' 'You can select the variations in the next step.'), @@ -132,6 +135,7 @@ class ItemCreateForm(I18nModelForm): def __init__(self, *args, **kwargs): self.event = kwargs['event'] super().__init__(*args, **kwargs) + self.fields['category'].queryset = self.instance.event.categories.all() self.fields['copy_from'] = forms.ModelChoiceField( label=_("Copy product information"), @@ -141,6 +145,40 @@ class ItemCreateForm(I18nModelForm): required=False ) + self.fields['quota_option'] = forms.ChoiceField( + label=_("Quota options"), + widget=forms.RadioSelect, + choices=( + (self.NONE, _("Do not add to a quota now")), + (self.EXISTING, _("Add product to an existing quota")), + (self.NEW, _("Create a new quota for this product")) + ), + initial=self.NONE, + required=False + ) + + self.fields['quota_add_existing'] = forms.ModelChoiceField( + label=_("Add to existing quota"), + widget=forms.Select(), + queryset=self.instance.event.quotas.all(), + required=False + ) + + self.fields['quota_add_new_name'] = forms.CharField( + label=_("Name"), + max_length=200, + widget=forms.TextInput(attrs={'placeholder': _("New quota name")}), + required=False + ) + + self.fields['quota_add_new_size'] = forms.IntegerField( + min_value=0, + label=_("Size"), + widget=forms.TextInput(attrs={'placeholder': _("New quota size")}), + help_text=_("Leave empty for an unlimited number of tickets."), + required=False + ) + def save(self, *args, **kwargs): if self.cleaned_data.get('copy_from'): self.instance.description = self.cleaned_data['copy_from'].description @@ -156,6 +194,18 @@ class ItemCreateForm(I18nModelForm): instance = super().save(*args, **kwargs) + if self.cleaned_data.get('quota_option') == self.EXISTING and self.cleaned_data.get('quota_add_existing') is not None: + quota = self.cleaned_data.get('quota_add_existing') + quota.items.add(self.instance) + elif self.cleaned_data.get('quota_option') == self.NEW: + quota_name = self.cleaned_data.get('quota_add_new_name') + quota_size = self.cleaned_data.get('quota_add_new_size') + + quota = Quota.objects.create( + event=self.event, name=quota_name, size=quota_size + ) + quota.items.add(self.instance) + if self.cleaned_data.get('has_variations'): if self.cleaned_data.get('copy_from') and self.cleaned_data.get('copy_from').has_variations: for variation in self.cleaned_data['copy_from'].variations.all(): @@ -172,6 +222,22 @@ class ItemCreateForm(I18nModelForm): return instance + def clean(self): + cleaned_data = super().clean() + + if cleaned_data.get('quota_option') == self.NEW: + if not self.cleaned_data.get('quota_add_new_name'): + raise forms.ValidationError( + {'quota_add_new_name': [_("Quota name is required.")]} + ) + elif cleaned_data.get('quota_option') == self.EXISTING: + if not self.cleaned_data.get('quota_add_existing'): + raise forms.ValidationError( + {'quota_add_existing': [_("Please select a quota.")]} + ) + + return cleaned_data + class Meta: model = Item localized_fields = '__all__' diff --git a/src/pretix/control/templates/pretixcontrol/item/create.html b/src/pretix/control/templates/pretixcontrol/item/create.html index 5ec7fd4d6..ef7ae1ba2 100644 --- a/src/pretix/control/templates/pretixcontrol/item/create.html +++ b/src/pretix/control/templates/pretixcontrol/item/create.html @@ -2,6 +2,9 @@ {% load i18n %} {% load bootstrap3 %} {% block inside %} +{% load static %} + +
{% csrf_token %}
@@ -12,6 +15,17 @@ {% bootstrap_field form.category layout="horizontal" %} {% bootstrap_field form.admission layout="horizontal" %}
+
+ {% trans "Quota settings" %} + {% bootstrap_field form.quota_option layout="horizontal" %} +
+ {% bootstrap_field form.quota_add_existing layout="horizontal" %} +
+
+ {% bootstrap_field form.quota_add_new_name layout="horizontal" %} + {% bootstrap_field form.quota_add_new_size layout="horizontal" %} +
+
{% trans "Price settings" %} {% bootstrap_field form.default_price layout="horizontal" %} diff --git a/src/pretix/static/pretixcontrol/js/ui/hidequota.js b/src/pretix/static/pretixcontrol/js/ui/hidequota.js new file mode 100644 index 000000000..389819b77 --- /dev/null +++ b/src/pretix/static/pretixcontrol/js/ui/hidequota.js @@ -0,0 +1,30 @@ +$(document).ready(function() { + hideDeselected(); +}); + +function hideDeselected() { + var v = $("input[name='quota_option']:checked").val(); + + if (v === "existing") { + hideAll(); + $("#existing-quota-group").children().slideDown(); + } else if (v === "new") { + hideAll(); + $("#new-quota-group").children().slideDown(); + } else { + hideAll(); + } +}; + +function hideAll() { + $("#new-quota-group").children().slideUp(); + $("#existing-quota-group").children().slideUp(); +}; + +$(function () { + $("input[name='quota_option']").on('change', + function() { + hideDeselected(); + } + ); +}); diff --git a/src/tests/control/test_items.py b/src/tests/control/test_items.py index 29a365e90..920d3db39 100644 --- a/src/tests/control/test_items.py +++ b/src/tests/control/test_items.py @@ -445,3 +445,36 @@ class ItemsTest(ItemFormTest): assert i_new.allow_cancel == i_old.allow_cancel assert set(i_new.questions.all()) == set(i_old.questions.all()) assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()]) + + def test_add_to_existing_quota(self): + q = Quota.objects.create(event=self.event1, name="New Test Quota", size=50) + + doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) + form_data = extract_form_fields(doc.select('.container-fluid form')[0]) + form_data['name_0'] = 'Existing' + form_data['default_price'] = '2.00' + form_data['quota_option'] = 'existing' + form_data['quota_add_existing'] = str(q.pk) + doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) + + i = Item.objects.get(name__icontains='Existing') + + assert doc.select(".alert-success") + assert q.items.filter(pk=i.pk).exists() + + def test_add_to_new_quota(self): + doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) + form_data = extract_form_fields(doc.select('.container-fluid form')[0]) + form_data['name_0'] = 'New Item' + form_data['default_price'] = '2.00' + form_data['quota_option'] = 'new' + form_data['quota_add_new_name'] = 'New Quota' + form_data['quota_add_new_size'] = '200' + doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) + + assert doc.select(".alert-success") + assert Quota.objects.filter(name__icontains='New Quota').exists() + assert Item.objects.filter(name__icontains='New Item').exists() + i = Item.objects.get(name__icontains='New Item') + q = Quota.objects.get(name__icontains='New Quota') + assert q.items.filter(pk=i.pk).exists()