pricing: criterias can be ordered (#64746)
This commit is contained in:
parent
1b82b01fea
commit
687fe2e9c3
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue