Allow to adjust the order of products (closes #60)

This commit is contained in:
Raphael Michel
2015-06-03 00:48:35 +02:00
parent f68132f006
commit 3114e2d959
6 changed files with 105 additions and 9 deletions

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.core.validators
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0002_auto_20150524_1148'),
]
operations = [
migrations.AlterModelOptions(
name='item',
options={'verbose_name_plural': 'Products', 'ordering': ('category__position', 'category', 'position'), 'verbose_name': 'Product'},
),
migrations.AddField(
model_name='item',
name='position',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='organizer',
name='slug',
field=models.SlugField(help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')], verbose_name='Slug'),
),
]

View File

@@ -860,10 +860,14 @@ class Item(Versionable):
),
default=False
)
position = models.IntegerField(
default=0
)
class Meta:
verbose_name = _("Product")
verbose_name_plural = _("Products")
ordering = ("category__position", "category", "position")
def __str__(self):
return str(self.name)

View File

@@ -3,6 +3,13 @@
{% block title %}{% trans "Products" %}{% endblock %}
{% block inside %}
<h1>{% trans "Products" %}</h1>
<p>
{% blocktrans trimmed %}
Below, you find a list of all available products. You can click on a product name to inspect and change
product details. You can also use the buttons on the right to change the order of products within a
give category.
{% endblocktrans %}
</p>
<p>
<a href="{% url "control:event.items.add" organizer=request.event.organizer.slug event=request.event.slug %}"
class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create new product" %}</a>
@@ -12,16 +19,24 @@
<tr>
<th>{% trans "Product name" %}</th>
<th>{% trans "Category" %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for i in items %}
<tr>
<td><strong><a href="
{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}">{{ i.name }}</a></strong></td>
<td>{% if i.category %}{{ i.category.name }}{% endif %}</td>
</tr>
{% endfor %}
{% regroup items by category as cat_list %}
{% for c in cat_list %}
{% for i in c.list %}
<tr>
<td><strong><a href="
{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}">{{ i.name }}</a></strong></td>
<td>{% if i.category %}{{ i.category.name }}{% endif %}</td>
<td>
<a href="{% url "control:event.items.up" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}" class="btn btn-default btn-sm {% if forloop.counter0 == 0 %}disabled{% endif %}"><i class="fa fa-arrow-up"></i></a>
<a href="{% url "control:event.items.down" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}" class="btn btn-default btn-sm {% if forloop.revcounter0 == 0 %}disabled{% endif %}"><i class="fa fa-arrow-down"></i></a>
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
{% include "pretixcontrol/pagination.html" %}

View File

@@ -27,6 +27,8 @@ urlpatterns = [
name='event.item.variations'),
url(r'^items/(?P<item>[0-9a-f-]+)/restrictions$', item.ItemRestrictions.as_view(),
name='event.item.restrictions'),
url(r'^items/(?P<item>[0-9a-f-]+)/up$', item.item_move_up, name='event.items.up'),
url(r'^items/(?P<item>[0-9a-f-]+)/down$', item.item_move_down, name='event.items.down'),
url(r'^categories/$', item.CategoryList.as_view(), name='event.items.categories'),
url(r'^categories/(?P<category>[0-9a-f-]+)/delete$', item.CategoryDelete.as_view(),
name='event.items.categories.delete'),

View File

@@ -27,7 +27,9 @@ from . import UpdateView, CreateView
class ItemList(ListView):
model = Item
context_object_name = 'items'
paginate_by = 30
# paginate_by = 30
# Pagination is disabled as it is very unlikely to be necessary
# here and could cause problems with the "reorder-within-category" feature
template_name = 'pretixcontrol/items/index.html'
def get_queryset(self):
@@ -36,6 +38,49 @@ class ItemList(ListView):
).prefetch_related("category")
def item_move(request, item, up=True):
"""
This is a helper function to avoid duplicating code in item_move_up and
item_move_down. It takes an item and a direction and then tries to bring
all items for this category in a new order.
"""
try:
item = request.event.items.current.get(
identity=item
)
except Item.DoesNotExist:
raise Http404(_("The requested product does not exist."))
items = list(request.event.items.current.filter(category=item.category).order_by("position"))
index = items.index(item)
if index != 0 and up:
items[index - 1], items[index] = items[index], items[index - 1]
elif index != len(items) - 1 and not up:
items[index + 1], items[index] = items[index], items[index + 1]
for i, item in enumerate(items):
if item.position != i:
item.position = i
item.save() # TODO: Clone or document sloppiness?
messages.success(request, _('The order of items as been updated.'))
@event_permission_required("can_change_items")
def item_move_up(request, organizer, event, item):
item_move(request, item, up=True)
return redirect('control:event.items',
organizer=request.event.organizer.slug,
event=request.event.slug)
@event_permission_required("can_change_items")
def item_move_down(request, organizer, event, item):
item_move(request, item, up=False)
return redirect('control:event.items',
organizer=request.event.organizer.slug,
event=request.event.slug)
class CategoryForm(VersionedModelForm):
class Meta:
@@ -159,6 +204,7 @@ def category_move(request, category, up=True):
if cat.position != i:
cat.position = i
cat.save() # TODO: Clone or document sloppiness?
messages.success(request, _('The order of categories as been updated.'))
@event_permission_required("can_change_items")

View File

@@ -35,7 +35,7 @@ class EventIndex(EventViewMixin, CartDisplayMixin, TemplateView):
'quotas', 'variations__quotas', 'quotas__event' # for .availability()
).annotate(quotac=Count('quotas')).filter(
quotac__gt=0
).order_by('category__position', 'category_id', 'name')
).order_by('category__position', 'category_id', 'position', 'name')
for item in items:
item.available_variations = sorted(item.get_all_available_variations(),