diff --git a/src/tixlbase/models.py b/src/tixlbase/models.py
index 195237a3a9..f5a698158d 100644
--- a/src/tixlbase/models.py
+++ b/src/tixlbase/models.py
@@ -538,9 +538,10 @@ class ItemVariation(models.Model):
)
active = models.BooleanField(
default=True,
+ verbose_name=_("Active"),
)
default_price = models.DecimalField(
decimal_places=2, max_digits=7,
null=True, blank=True,
- verbose_name=_("Default price")
+ verbose_name=_("Default price"),
)
diff --git a/src/tixlcontrol/static/tixlcontrol/less/forms.less b/src/tixlcontrol/static/tixlcontrol/less/forms.less
new file mode 100644
index 0000000000..46581d7a3f
--- /dev/null
+++ b/src/tixlcontrol/static/tixlcontrol/less/forms.less
@@ -0,0 +1,16 @@
+td > .form-group {
+ margin-bottom: 0;
+}
+td > .errorlist {
+ color: #a94442;
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+}
+td > .form-group > .checkbox {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.has-success .form-control {
+ border-color: #cccccc;
+}
diff --git a/src/tixlcontrol/static/tixlcontrol/less/main.less b/src/tixlcontrol/static/tixlcontrol/less/main.less
index d056d1fe2f..001ae5cfce 100644
--- a/src/tixlcontrol/static/tixlcontrol/less/main.less
+++ b/src/tixlcontrol/static/tixlcontrol/less/main.less
@@ -1,3 +1,4 @@
@import "../../../../tixlbase/static/bootstrap/less/bootstrap.less";
@import "../../../../tixlbase/static/fontawesome/less/font-awesome.less";
@fa-font-path: "../../fontawesome/fonts";
+@import "forms.less";
diff --git a/src/tixlcontrol/templates/tixlcontrol/item/base.html b/src/tixlcontrol/templates/tixlcontrol/item/base.html
index e618edf25f..6f388a8906 100644
--- a/src/tixlcontrol/templates/tixlcontrol/item/base.html
+++ b/src/tixlcontrol/templates/tixlcontrol/item/base.html
@@ -5,6 +5,7 @@
{% trans "Modify item:" %} {{ item.name }}
{% block inside %}
{% endblock %}
diff --git a/src/tixlcontrol/templates/tixlcontrol/item/variations_1d.html b/src/tixlcontrol/templates/tixlcontrol/item/variations_1d.html
new file mode 100644
index 0000000000..a8321e696a
--- /dev/null
+++ b/src/tixlcontrol/templates/tixlcontrol/item/variations_1d.html
@@ -0,0 +1,36 @@
+{% extends "tixlcontrol/item/base.html" %}
+{% load i18n %}
+{% load bootstrap3 %}
+{% block inside %}
+ {% trans "Variations" %}
+
+
+{% endblock %}
diff --git a/src/tixlcontrol/urls.py b/src/tixlcontrol/urls.py
index 7f68a9e76d..c3b048447f 100644
--- a/src/tixlcontrol/urls.py
+++ b/src/tixlcontrol/urls.py
@@ -21,6 +21,7 @@ urlpatterns += patterns(
url(r'^settings$', event.EventUpdate.as_view(), name='event.settings'),
url(r'^items$', item.ItemList.as_view(), name='event.items'),
url(r'^items/(?P- \d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'),
+ url(r'^items/(?P
- \d+)/variations$', item.ItemVariations.as_view(), name='event.item.variations'),
url(r'^categories$', item.CategoryList.as_view(), name='event.items.categories'),
url(r'^properties$', item.PropertyList.as_view(), name='event.items.properties'),
)
diff --git a/src/tixlcontrol/views/item.py b/src/tixlcontrol/views/item.py
index 248a3f853e..2ef14bc9af 100644
--- a/src/tixlcontrol/views/item.py
+++ b/src/tixlcontrol/views/item.py
@@ -1,9 +1,11 @@
from django.views.generic import ListView
from django.views.generic.edit import UpdateView
+from django.views.generic.base import TemplateView
+from django.views.generic.detail import SingleObjectMixin
from django.core.urlresolvers import resolve, reverse
from django import forms
-from tixlbase.models import Item, ItemCategory, Property
+from tixlbase.models import Item, ItemCategory, Property, ItemVariation
from tixlcontrol.permissions import EventPermissionRequiredMixin
@@ -81,3 +83,97 @@ class ItemUpdateGeneral(EventPermissionRequiredMixin, UpdateView):
'event': self.request.event.slug,
'item': self.get_object().pk,
}) + '?success=true'
+
+
+class ItemVariationForm(forms.ModelForm):
+
+ class Meta:
+ model = ItemVariation
+ localized_fields = '__all__'
+ fields = [
+ 'active',
+ 'default_price',
+ ]
+
+
+class ItemVariations(TemplateView, SingleObjectMixin):
+
+ model = Item
+ context_object_name = 'item'
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.item = None
+
+ def get_forms(self):
+ """
+ Returns one form per possible item variation. The forms are returned
+ twice: The first entry in the returned tuple contains a 1-, 2- or
+ 3-dimensional list, depending on the number of properties associated
+ with this item (this is being used for form display), the second
+ contains all forms in one single list (this is used for processing).
+ """
+ forms = []
+ forms_flat = []
+ variations = self.object.get_all_variations()
+ data = self.request.POST if self.request.method == 'POST' else None
+ if self.dimension == 1:
+ for var in variations:
+ val = [i[1] for i in sorted([it for it in var.items() if it[0] != 'variation'])]
+ if 'variation' in var:
+ form = ItemVariationForm(
+ data,
+ instance=var['variation'],
+ prefix=",".join([str(i) for i in val])
+ )
+ else:
+ form = ItemVariationForm(
+ data,
+ instance=ItemVariation(item=self.object),
+ prefix=",".join([str(i) for i in val])
+ )
+ form.values = val
+ forms.append(form)
+ forms_flat = forms
+ return forms, forms_flat
+
+ def main(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ self.properties = self.object.properties.all()
+ self.dimension = self.properties.count()
+ self.forms, self.forms_flat = self.get_forms()
+
+ def get(self, request, *args, **kwargs):
+ self.main(request, *args, **kwargs)
+ context = self.get_context_data(object=self.object)
+ return self.render_to_response(context)
+
+ def post(self, request, *args, **kwargs):
+ self.main(request, *args, **kwargs)
+ context = self.get_context_data(object=self.object)
+ for form in self.forms_flat:
+ if form.is_valid():
+ if form.instance.pk is None:
+ form.save()
+ form.instance.values.add(*form.values)
+ else:
+ form.save()
+ return self.render_to_response(context)
+
+ def get_object(self, queryset=None):
+ if not self.item:
+ url = resolve(self.request.path_info)
+ self.item = self.request.event.items.get(
+ id=url.kwargs['item']
+ )
+ return self.item
+
+ def get_template_names(self):
+ if self.dimension == 1:
+ return ['tixlcontrol/item/variations_1d.html']
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['forms'] = self.forms
+ context['properties'] = self.properties
+ return context