forked from CGM_Public/pretix_original
Very basic quota control
This commit is contained in:
25
src/tixlbase/migrations/0018_auto_20141025_0908.py
Normal file
25
src/tixlbase/migrations/0018_auto_20141025_0908.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tixlbase', '0017_auto_20141017_2148'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='quota',
|
||||||
|
name='event',
|
||||||
|
field=models.ForeignKey(to='tixlbase.Event', default=1, verbose_name='Event', related_name='quotas'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='cartposition',
|
||||||
|
name='datetime',
|
||||||
|
field=models.DateTimeField(verbose_name='Date'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -750,6 +750,12 @@ class Quota(models.Model):
|
|||||||
implementation specific and are considered private. It is planned that they
|
implementation specific and are considered private. It is planned that they
|
||||||
are being used as a fallback solution if redis is not available.
|
are being used as a fallback solution if redis is not available.
|
||||||
"""
|
"""
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="quotas",
|
||||||
|
verbose_name=_("Event"),
|
||||||
|
)
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=200,
|
max_length=200,
|
||||||
verbose_name=_("Name")
|
verbose_name=_("Name")
|
||||||
@@ -780,6 +786,9 @@ class Quota(models.Model):
|
|||||||
verbose_name = _("Quota")
|
verbose_name = _("Quota")
|
||||||
verbose_name_plural = _("Quotas")
|
verbose_name_plural = _("Quotas")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Order(models.Model):
|
class Order(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<li {% if "event.items.categories" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.categories' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Categories" %}</a></li>
|
<li {% if "event.items.categories" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.categories' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Categories" %}</a></li>
|
||||||
<li {% if "event.items.properties" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.properties' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Properties" %}</a></li>
|
<li {% if "event.items.properties" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.properties' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Properties" %}</a></li>
|
||||||
<li {% if "event.items.questions" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.questions' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Questions" %}</a></li>
|
<li {% if "event.items.questions" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.questions' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Questions" %}</a></li>
|
||||||
|
<li {% if "event.items.quotas" in url_name %}class="active"{% endif %}><a href="{% url 'control:event.items.quotas' organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Quotas" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% block inside %}
|
{% block inside %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
{% trans "Confirm" %}
|
{% trans "Confirm" %}
|
||||||
</button>
|
</button>
|
||||||
<a href="{% url "control:event.items.properties" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default">
|
<a href="{% url "control:event.items.questions" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default">
|
||||||
{% trans "Cancel" %}
|
{% trans "Cancel" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
27
src/tixlcontrol/templates/tixlcontrol/items/quota.html
Normal file
27
src/tixlcontrol/templates/tixlcontrol/items/quota.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% block title %}{% trans "Quota" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Quota" %}</h1>
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% if "success" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "Your changes have been saved." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans "General information" %}</legend>
|
||||||
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.size layout="horizontal" %}
|
||||||
|
</fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{% trans "Save" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% block title %}{% trans "Delete quota" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Delete quota" %}</h1>
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>{% blocktrans %}Are you sure you want to delete the quota <strong>{{ quota }}</strong>?{% endblocktrans %}</p>
|
||||||
|
{% if dependent|length > 0 %}
|
||||||
|
<p>{% blocktrans %}The following items might be no longer available for sale:{% endblocktrans %}</p>
|
||||||
|
{% for item in dependent %}
|
||||||
|
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{% trans "Confirm" %}
|
||||||
|
</button>
|
||||||
|
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default">
|
||||||
|
{% trans "Cancel" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
44
src/tixlcontrol/templates/tixlcontrol/items/quotas.html
Normal file
44
src/tixlcontrol/templates/tixlcontrol/items/quotas.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Quotas" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Quotas" %}</h1>
|
||||||
|
{% if "updated" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "Your changes have been saved." %}
|
||||||
|
</div>
|
||||||
|
{% elif "created" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "A new quota has been created." %}
|
||||||
|
</div>
|
||||||
|
{% elif "deleted" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "The quota has been deleted." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<p>
|
||||||
|
<a href="{% url "control:event.items.quotas.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new quota" %}</a>
|
||||||
|
</p>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Quota name" %}</th>
|
||||||
|
<th>{% trans "Items" %}</th>
|
||||||
|
<th>{% trans "Total capacity" %}</th>
|
||||||
|
<th>{% trans "Capacity left" %}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for q in quotas %}
|
||||||
|
<tr>
|
||||||
|
<td><strong><a href="{% url "control:event.items.quotas.edit" organizer=request.event.organizer.slug event=request.event.slug quota=q.pk %}">{{ q.name }}</a></strong></td>
|
||||||
|
<td></td>
|
||||||
|
<td>{{ q.size }}</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="text-right"><a href="{% url "control:event.items.quotas.delete" organizer=request.event.organizer.slug event=request.event.slug quota=q.pk %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
@@ -38,6 +38,11 @@ urlpatterns += patterns(
|
|||||||
url(r'^properties/(?P<property>\d+)/$', item.PropertyUpdate.as_view(), name='event.items.properties.edit'),
|
url(r'^properties/(?P<property>\d+)/$', item.PropertyUpdate.as_view(), name='event.items.properties.edit'),
|
||||||
url(r'^properties/(?P<property>\d+)/delete$', item.PropertyDelete.as_view(), name='event.items.properties.delete'),
|
url(r'^properties/(?P<property>\d+)/delete$', item.PropertyDelete.as_view(), name='event.items.properties.delete'),
|
||||||
url(r'^properties/add$', item.PropertyCreate.as_view(), name='event.items.properties.add'),
|
url(r'^properties/add$', item.PropertyCreate.as_view(), name='event.items.properties.add'),
|
||||||
|
url(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'),
|
||||||
|
url(r'^quotas/(?P<quota>\d+)/$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'),
|
||||||
|
url(r'^quotas/(?P<quota>\d+)/delete$', item.QuotaDelete.as_view(),
|
||||||
|
name='event.items.quotas.delete'),
|
||||||
|
url(r'^quotas/add$', item.QuotaCreate.as_view(), name='event.items.quotas.add'),
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ from django import forms
|
|||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.forms.models import inlineformset_factory
|
from django.forms.models import inlineformset_factory
|
||||||
|
|
||||||
from tixlbase.models import Item, ItemCategory, Property, ItemVariation, PropertyValue, Question
|
from tixlbase.models import (
|
||||||
|
Item, ItemCategory, Property, ItemVariation, PropertyValue, Question, Quota
|
||||||
|
)
|
||||||
from tixlcontrol.permissions import EventPermissionRequiredMixin, event_permission_required
|
from tixlcontrol.permissions import EventPermissionRequiredMixin, event_permission_required
|
||||||
from tixlcontrol.views.forms import TolerantFormsetModelForm
|
from tixlcontrol.views.forms import TolerantFormsetModelForm
|
||||||
from tixlcontrol.signals import restriction_formset
|
from tixlcontrol.signals import restriction_formset
|
||||||
@@ -406,6 +408,97 @@ class QuestionCreate(EventPermissionRequiredMixin, CreateView):
|
|||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaList(ListView):
|
||||||
|
model = Quota
|
||||||
|
context_object_name = 'quotas'
|
||||||
|
template_name = 'tixlcontrol/items/quotas.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Quota.objects.filter(
|
||||||
|
event=self.request.event
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Quota
|
||||||
|
localized_fields = '__all__'
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'size',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaCreate(EventPermissionRequiredMixin, CreateView):
|
||||||
|
model = Quota
|
||||||
|
form_class = QuotaForm
|
||||||
|
template_name = 'tixlcontrol/items/quota.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'quota'
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('control:event.items.quotas', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
}) + '?created=true'
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.event = self.request.event
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||||
|
model = Quota
|
||||||
|
form_class = QuotaForm
|
||||||
|
template_name = 'tixlcontrol/items/quota.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'quota'
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
url = resolve(self.request.path_info)
|
||||||
|
return self.request.event.quotas.get(
|
||||||
|
id=url.kwargs['quota']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('control:event.items.quotas', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
}) + '?updated=true'
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaDelete(EventPermissionRequiredMixin, DeleteView):
|
||||||
|
model = Quota
|
||||||
|
template_name = 'tixlcontrol/items/quota_delete.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'quota'
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
url = resolve(self.request.path_info)
|
||||||
|
return self.request.event.quotas.get(
|
||||||
|
id=url.kwargs['quota']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
context = super().get_context_data(*args, **kwargs)
|
||||||
|
context['dependent'] = list(self.get_object().items.all())
|
||||||
|
return context
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
self.object.items.update(category=None)
|
||||||
|
success_url = self.get_success_url()
|
||||||
|
self.object.delete()
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('control:event.items.quotas', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
}) + '?deleted=true'
|
||||||
|
|
||||||
|
|
||||||
class ItemDetailMixin(SingleObjectMixin):
|
class ItemDetailMixin(SingleObjectMixin):
|
||||||
model = Item
|
model = Item
|
||||||
context_object_name = 'item'
|
context_object_name = 'item'
|
||||||
|
|||||||
Reference in New Issue
Block a user