From 88df78d4cf3803fcab39ca998079517fc1145ce7 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Thu, 8 Jan 2015 00:13:20 +0100 Subject: [PATCH] tixlcontrol: Quota UI --- src/tixlbase/forms.py | 2 +- src/tixlbase/models.py | 61 ++++++++++-- .../static/tixlcontrol/js/ui/main.js | 13 ++- .../static/tixlcontrol/less/forms.less | 11 +++ .../templates/tixlcontrol/item/base.html | 8 ++ .../tixlcontrol/item/restrictions.html | 2 +- .../templates/tixlcontrol/items/base.html | 2 +- .../templates/tixlcontrol/items/quota.html | 29 ++++++ .../templates/tixlcontrol/items/quotas.html | 12 ++- src/tixlcontrol/views/forms.py | 4 +- src/tixlcontrol/views/item.py | 98 +++++++++++++++++-- 11 files changed, 219 insertions(+), 23 deletions(-) diff --git a/src/tixlbase/forms.py b/src/tixlbase/forms.py index 3b661dc4e..aa3996e22 100644 --- a/src/tixlbase/forms.py +++ b/src/tixlbase/forms.py @@ -11,7 +11,7 @@ class VersionedBaseModelForm(BaseModelForm): if self.instance.pk is not None and isinstance(self.instance, Versionable): if self.has_changed(): self.instance = self.instance.clone() - super().save(commit) + return super().save(commit) class VersionedModelForm(six.with_metaclass(ModelFormMetaclass, VersionedBaseModelForm)): diff --git a/src/tixlbase/models.py b/src/tixlbase/models.py index 37c74278d..cd4621c7d 100644 --- a/src/tixlbase/models.py +++ b/src/tixlbase/models.py @@ -1,4 +1,6 @@ from itertools import product +import copy +import uuid from django.db import models from django.conf import settings @@ -6,11 +8,54 @@ from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, Permis from django.utils.translation import ugettext_lazy as _ from django.template.defaultfilters import date as _date from django.core.validators import RegexValidator -from versions.models import Versionable, VersionedForeignKey, VersionedManyToManyField +import six +from versions.models import Versionable as BaseVersionable +from versions.models import VersionedForeignKey, VersionedManyToManyField, get_utc_now from tixlbase.types import VariationDict +class Versionable(BaseVersionable): + + class Meta: + abstract = True + + def clone_shallow(self, forced_version_date=None): + """ + This behaves like clone(), but misses all the Many2Many-relation-handling. This is + a performance optimization for cases in which we have to handle the Many2Many relations + by handy anyways. + """ + if not self.pk: + raise ValueError('Instance must be saved before it can be cloned') + + if self.version_end_date: + raise ValueError('This is a historical item and can not be cloned.') + + if forced_version_date: + if not self.version_start_date <= forced_version_date <= get_utc_now(): + raise ValueError('The clone date must be between the version start date and now.') + else: + forced_version_date = get_utc_now() + + earlier_version = self + + later_version = copy.copy(earlier_version) + later_version.version_end_date = None + later_version.version_start_date = forced_version_date + + # set earlier_version's ID to a new UUID so the clone (later_version) can + # get the old one -- this allows 'head' to always have the original + # id allowing us to get at all historic foreign key relationships + earlier_version.id = six.u(str(uuid.uuid4())) + earlier_version.version_end_date = forced_version_date + earlier_version.save() + + later_version.save() + + return later_version + + class UserManager(BaseUserManager): """ This is the user manager for our custom user model. See the User @@ -614,18 +659,18 @@ class Item(Versionable): if use_cache and hasattr(self, '_get_all_variations_cache'): return self._get_all_variations_cache - all_variations = self.variations.current.all().prefetch_related("values") - all_properties = self.properties.current.all().prefetch_related("values") + all_variations = self.variations.all().prefetch_related("values") + all_properties = self.properties.all().prefetch_related("values") variations_cache = {} for var in all_variations: key = [] - for v in var.values.current.all(): + for v in var.values.all(): key.append((v.prop_id, v.identity)) key = tuple(sorted(key)) variations_cache[key] = var result = [] - for comb in product(*[prop.values.current.all() for prop in all_properties]): + for comb in product(*[prop.values.all() for prop in all_properties]): if len(comb) == 0: result.append(VariationDict()) continue @@ -772,8 +817,8 @@ class Quota(Versionable): and no more than 100 of them will be VIP tickets (but 450 normal and 50 VIP tickets will be fine). - As always, a quota can not only be tied to an item, but also to a specific - variation. We follow the general rule here: If there are no variations + As always, a quota can not only be tied to an item, but also to specific + variations. We follow the general rule here: If there are no variations speficied, the quota applies to all of them, and if there are variations specified, the quota applies to those. @@ -797,10 +842,12 @@ class Quota(Versionable): items = VersionedManyToManyField( Item, verbose_name=_("Item"), + related_name="quotas", blank=True ) variations = VariationsField( ItemVariation, + related_name="quotas", blank=True, verbose_name=_("Variations") ) diff --git a/src/tixlcontrol/static/tixlcontrol/js/ui/main.js b/src/tixlcontrol/static/tixlcontrol/js/ui/main.js index 924392903..fd00da129 100644 --- a/src/tixlcontrol/static/tixlcontrol/js/ui/main.js +++ b/src/tixlcontrol/static/tixlcontrol/js/ui/main.js @@ -5,14 +5,23 @@ $(function () { reorderMode: 'animate' }); $(document).on("click", ".variations .variations-select-all", function (e) { - $(this).parent().parent().find("input[type=checkbox]").prop("checked", true); + $(this).parent().parent().find("input[type=checkbox]").prop("checked", true).change(); e.stopPropagation(); return false; }); $(document).on("click", ".variations .variations-select-none", function (e) { - $(this).parent().parent().find("input[type=checkbox]").prop("checked", false); + $(this).parent().parent().find("input[type=checkbox]").prop("checked", false).change(); e.stopPropagation(); return false; }); + if ($(".items-on-quota").length) { + $(".items-on-quota .panel").each(function () { + var $panel = $(this); + $panel.toggleClass("panel-success", $panel.find("input:checked").length > 0); + $(this).find("input").change(function () { + $panel.toggleClass("panel-success", $panel.find("input:checked").length > 0); + }); + }); + } $('.collapse').collapse(); }); diff --git a/src/tixlcontrol/static/tixlcontrol/less/forms.less b/src/tixlcontrol/static/tixlcontrol/less/forms.less index 33ee8299d..8d854c7a2 100644 --- a/src/tixlcontrol/static/tixlcontrol/less/forms.less +++ b/src/tixlcontrol/static/tixlcontrol/less/forms.less @@ -47,6 +47,10 @@ td > .form-group > .checkbox { } } +.panel .form-group:last-child { + margin-bottom: 0; +} + .container ul.nav-pills { margin: 20px 0; } @@ -56,6 +60,13 @@ td > .form-group > .checkbox { margin: 0; } } + +.table-quotas td ul { + list-style: none; + margin-left: 0; + padding-left: 0; +} + @media (min-width: @screen-sm-min) { .variation-matrix > tbody > tr > td { line-height: 34px; diff --git a/src/tixlcontrol/templates/tixlcontrol/item/base.html b/src/tixlcontrol/templates/tixlcontrol/item/base.html index 7a7aa2c3d..8f9dc3058 100644 --- a/src/tixlcontrol/templates/tixlcontrol/item/base.html +++ b/src/tixlcontrol/templates/tixlcontrol/item/base.html @@ -8,6 +8,14 @@
  • {% trans "Variations" %}
  • {% trans "Restrictions" %}
  • + {% if item.identity and not item.quotas.exists %} +
    + {% blocktrans trimmed %} + Please note, that your item will not be available for sale until you added your item + to an existing or newly created quota. + {% endblocktrans %} +
    + {% endif %} {% block inside %} {% endblock %} {% endblock %} diff --git a/src/tixlcontrol/templates/tixlcontrol/item/restrictions.html b/src/tixlcontrol/templates/tixlcontrol/item/restrictions.html index e0c0dc6d7..4b82f1933 100644 --- a/src/tixlcontrol/templates/tixlcontrol/item/restrictions.html +++ b/src/tixlcontrol/templates/tixlcontrol/item/restrictions.html @@ -22,7 +22,7 @@

    - Test + {{ set.title }}

    diff --git a/src/tixlcontrol/templates/tixlcontrol/items/base.html b/src/tixlcontrol/templates/tixlcontrol/items/base.html index c636133df..a9b6c3c5c 100644 --- a/src/tixlcontrol/templates/tixlcontrol/items/base.html +++ b/src/tixlcontrol/templates/tixlcontrol/items/base.html @@ -4,10 +4,10 @@ {% block content %} {% block inside %} {% endblock %} diff --git a/src/tixlcontrol/templates/tixlcontrol/items/quota.html b/src/tixlcontrol/templates/tixlcontrol/items/quota.html index 9599952ea..a9d4efebf 100644 --- a/src/tixlcontrol/templates/tixlcontrol/items/quota.html +++ b/src/tixlcontrol/templates/tixlcontrol/items/quota.html @@ -15,6 +15,35 @@ {% trans "General information" %} {% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.size layout="horizontal" %} + {% trans "Items" %} +

    + {% blocktrans trimmed %} + Please select the items or item variations this quota should be applied to. If you apply two + quotas to the same items, it will only be available if both quotas have capacity + left. + {% endblocktrans %} +

    +
    + {% for item in items %} +
    + +
    +
    +
    + {% bootstrap_field item.field layout="horizontal" %} +
    +
    +
    +
    + {% endfor %} +