pricing: criterias can be ordered (#64746)

This commit is contained in:
Lauréline Guérin 2022-05-03 15:10:43 +02:00
parent 1b82b01fea
commit 687fe2e9c3
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
6 changed files with 148 additions and 3 deletions

View File

@ -522,3 +522,21 @@ table.timesheet {
.page_break {
height: 20px;
}
ul.objects-list.sortable {
li {
position: relative;
span.handle {
cursor: move;
display: inline-block;
padding: 0.5ex;
text-align: center;
width: 2em;
height: 100%;
box-sizing: border-box;
}
& > a {
display: inline-block;
}
}
}

View File

@ -48,4 +48,23 @@ $(function() {
total_form.val(form_num + 1);
})
}
$('ul.sortable').sortable({
handle: '.handle',
items: 'li.sortable-item',
update : function(event, ui) {
var new_order = '';
$(this).find('li.sortable-item').each(function(i, x) {
var item_id = $(x).data('item-id');
if (new_order) {
new_order += ',';
}
new_order += item_id;
});
$.ajax({
url: $(this).data('order-url'),
data: {'new-order': new_order}
});
}
});
});

View File

@ -18,6 +18,13 @@
<div class="pk-information">
<p>{% trans "Define here pricing criterias used in events agendas." %}</p>
</div>
{% if object_list %}
<p class="hint">
{% blocktrans %}
Use drag and drop with the ⣿ handles to reorder criterias inside a category.
{% endblocktrans %}
</p>
{% endif %}
{% for object in object_list %}
<div class="section criteria-category">
<h3>
@ -28,9 +35,10 @@
</span>
</h3>
<div>
<ul class="objects-list single-links">
<ul class="objects-list single-links sortable" data-order-url="{% url 'chrono-manager-pricing-criteria-order' object.pk %}">
{% for criteria in object.criterias.all %}
<li>
<li class="sortable-item" data-item-id="{{ criteria.pk }}">
<span class="handle"></span>
<a rel="popup" href="{% url 'chrono-manager-pricing-criteria-edit' object.pk criteria.pk %}">{{ criteria }}</a>
<a class="delete" rel="popup" href="{% url 'chrono-manager-pricing-criteria-delete' object.pk criteria.pk %}">{% trans "delete"%}</a>
</li>

View File

@ -40,6 +40,11 @@ urlpatterns = [
views.criteria_category_export,
name='chrono-manager-pricing-criteria-category-export',
),
url(
r'^criteria/category/(?P<pk>\d+)/order/$',
views.criteria_order,
name='chrono-manager-pricing-criteria-order',
),
url(
r'^criteria/category/(?P<category_pk>\d+)/add/$',
views.criteria_add,

View File

@ -18,7 +18,7 @@ import datetime
import json
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseBadRequest
from django.urls import reverse
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView
@ -114,6 +114,35 @@ class CriteriaCategoryExport(DetailView):
criteria_category_export = CriteriaCategoryExport.as_view()
class CriteriaOrder(DetailView):
model = CriteriaCategory
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
if 'new-order' not in request.GET:
return HttpResponseBadRequest('missing new-order parameter')
category = self.get_object()
try:
new_order = [int(x) for x in request.GET['new-order'].split(',')]
except ValueError:
return HttpResponseBadRequest('incorrect new-order parameter')
criterias = category.criterias.all()
if set(new_order) != {x.pk for x in criterias} or len(new_order) != len(criterias):
return HttpResponseBadRequest('incorrect new-order parameter')
criterias_by_id = {c.pk: c for c in criterias}
for i, c_id in enumerate(new_order):
criterias_by_id[c_id].order = i + 1
criterias_by_id[c_id].save()
return HttpResponse(status=204)
criteria_order = CriteriaOrder.as_view()
class CriteriaAddView(CreateView):
template_name = 'chrono/pricing/manager_criteria_form.html'
model = Criteria

View File

@ -194,6 +194,72 @@ def test_delete_criteria_as_manager(app, manager_user):
app.get('/manage/pricing/criteria/category/%s/%s/delete/' % (category.pk, criteria.pk), status=403)
def test_reorder_criterias(app, admin_user):
category = CriteriaCategory.objects.create(label='QF')
criteria1 = Criteria.objects.create(label='QF 1', category=category)
criteria2 = Criteria.objects.create(label='QF 2', category=category)
criteria3 = Criteria.objects.create(label='QF 3', category=category)
criteria4 = Criteria.objects.create(label='QF 4', category=category)
assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
criteria1.pk,
criteria2.pk,
criteria3.pk,
criteria4.pk,
]
assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
app = login(app)
# missing get params
app.get('/manage/pricing/criteria/category/%s/order/' % (category.pk), status=400)
# bad new-order param
bad_params = [
# missing criteria3 in order
','.join(str(x) for x in [criteria1.pk, criteria2.pk, criteria4.pk]),
# criteria1 mentionned twice
','.join(str(x) for x in [criteria1.pk, criteria2.pk, criteria3.pk, criteria4.pk, criteria1.pk]),
# not an id
'foo,1,2,3,4',
' 1 ,2,3,4',
]
for bad_param in bad_params:
app.get(
'/manage/pricing/criteria/category/%s/order/' % (category.pk),
params={'new-order': bad_param},
status=400,
)
# not changed
assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
criteria1.pk,
criteria2.pk,
criteria3.pk,
criteria4.pk,
]
assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
# change order
app.get(
'/manage/pricing/criteria/category/%s/order/' % (category.pk),
params={
'new-order': ','.join(str(x) for x in [criteria3.pk, criteria1.pk, criteria4.pk, criteria2.pk])
},
)
assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
criteria3.pk,
criteria1.pk,
criteria4.pk,
criteria2.pk,
]
assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
def test_reorder_criterias_as_manager(app, manager_user):
category = CriteriaCategory.objects.create(label='QF')
app = login(app, username='manager', password='manager')
app.get('/manage/pricing/criteria/category/%s/order/' % (category.pk), status=403)
@pytest.mark.freeze_time('2021-07-08')
def test_import_criteria_category(app, admin_user):
category = CriteriaCategory.objects.create(label='Foo bar')