0002-managers-display-filters-on-check-page-53238.patch
chrono/manager/forms.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
from __future__ import unicode_literals |
18 | 18 | |
19 |
import collections |
|
19 | 20 |
import csv |
20 | 21 |
import datetime |
21 | 22 | |
23 |
import django_filters |
|
22 | 24 |
from django import forms |
23 | 25 |
from django.conf import settings |
24 | 26 |
from django.contrib.auth.models import Group |
... | ... | |
225 | 227 |
return self.instance |
226 | 228 | |
227 | 229 | |
230 |
class BookingCheckFilterSet(django_filters.FilterSet): |
|
231 |
class Meta: |
|
232 |
model = Booking |
|
233 |
fields = [] |
|
234 | ||
235 |
def __init__(self, *args, **kwargs): |
|
236 |
self.agenda = kwargs.pop('agenda') |
|
237 |
super().__init__(*args, **kwargs) |
|
238 | ||
239 |
# build filters from DB |
|
240 |
agenda_filters = self.agenda.get_booking_check_filters() |
|
241 |
filters = collections.defaultdict(set) |
|
242 |
for extra_data in self.queryset.filter(extra_data__has_any_keys=agenda_filters).values_list( |
|
243 |
'extra_data', flat=True |
|
244 |
): |
|
245 |
for k, v in extra_data.items(): |
|
246 |
if k in agenda_filters: |
|
247 |
filters[k].add(v) |
|
248 |
filters = sorted(filters.items()) |
|
249 |
filters = {k: sorted(list(v)) for k, v in filters} |
|
250 | ||
251 |
# add filters to filterset |
|
252 |
for key, values in filters.items(): |
|
253 |
self.filters[key] = django_filters.ChoiceFilter( |
|
254 |
label=_('Filter by %s') % key, |
|
255 |
field_name='extra_data__%s' % key, |
|
256 |
lookup_expr='iexact', |
|
257 |
choices=[(v, v) for v in values], |
|
258 |
empty_label=_('all'), |
|
259 |
widget=forms.RadioSelect, |
|
260 |
) |
|
261 | ||
262 | ||
228 | 263 |
class BookingAbsenceReasonForm(forms.Form): |
229 | 264 |
reason = forms.ChoiceField(required=False) |
230 | 265 |
chrono/manager/static/css/style.scss | ||
---|---|---|
382 | 382 |
} |
383 | 383 |
} |
384 | 384 | |
385 |
form.check-bookings-filters li { |
|
386 |
display: inline; |
|
387 |
margin-right: 10px; |
|
388 |
} |
|
389 | ||
385 | 390 |
// booking colors |
386 | 391 |
$booking-colors: ( |
387 | 392 |
0: hsl(30, 100%, 46%), |
chrono/manager/templates/chrono/manager_event_check.html | ||
---|---|---|
14 | 14 |
{% blocktrans with places=object.places booked_places=booked|length %}Bookings ({{ booked_places }}/{{ places }}){% endblocktrans %} |
15 | 15 |
</h3> |
16 | 16 |
<div> |
17 |
<form class="check-bookings-filters"> |
|
18 |
{{ filterset.form.as_p }} |
|
19 |
<script> |
|
20 |
$(function() { |
|
21 |
$('form.check-bookings-filters input').on('change', |
|
22 |
function() { |
|
23 |
$(this).parents('form').submit(); |
|
24 |
}); |
|
25 |
}); |
|
26 |
</script> |
|
27 |
</form> |
|
17 | 28 |
<table class="main check-bookings"> |
18 | 29 |
<tbody> |
19 | 30 |
{% for booking in booked %} |
chrono/manager/views.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import collections |
|
17 | 18 |
import csv |
18 | 19 |
import datetime |
19 | 20 |
import itertools |
... | ... | |
89 | 90 |
AgendasImportForm, |
90 | 91 |
BookingAbsenceReasonForm, |
91 | 92 |
BookingCancelForm, |
93 |
BookingCheckFilterSet, |
|
92 | 94 |
DeskForm, |
93 | 95 |
EventCancelForm, |
94 | 96 |
EventForm, |
... | ... | |
1946 | 1948 | |
1947 | 1949 |
def get_context_data(self, **kwargs): |
1948 | 1950 |
context = super().get_context_data(**kwargs) |
1951 | ||
1949 | 1952 |
event = self.object |
1950 |
context['booked'] = event.booking_set.filter(
|
|
1951 |
cancellation_datetime__isnull=True, in_waiting_list=False
|
|
1952 |
).order_by('user_name')
|
|
1953 |
context['waiting'] = event.booking_set.filter( |
|
1954 |
cancellation_datetime__isnull=True, in_waiting_list=True
|
|
1955 |
).order_by('user_name')
|
|
1953 |
booked_qs = event.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False)
|
|
1954 |
filterset = BookingCheckFilterSet(self.request.GET, queryset=booked_qs, agenda=self.agenda)
|
|
1955 |
context['filterset'] = filterset
|
|
1956 | ||
1957 |
# build booking list
|
|
1958 |
context['booked'] = filterset.qs.order_by('user_name')
|
|
1956 | 1959 |
for booking in context['booked']: |
1957 | 1960 |
booking.form = BookingAbsenceReasonForm( |
1958 | 1961 |
agenda=self.agenda, initial={'reason': booking.user_absence_reason} |
1959 | 1962 |
) |
1963 |
context['waiting'] = event.booking_set.filter( |
|
1964 |
cancellation_datetime__isnull=True, in_waiting_list=True |
|
1965 |
).order_by('user_name') |
|
1966 | ||
1960 | 1967 |
return context |
1961 | 1968 | |
1962 | 1969 |
tests/manager/test_event.py | ||
---|---|---|
1077 | 1077 |
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp |
1078 | 1078 |
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404) |
1079 | 1079 | |
1080 |
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it'os ok all the day
|
|
1080 |
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it's ok all the day |
|
1081 | 1081 |
event.save() |
1082 | 1082 |
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk)) |
1083 | 1083 |
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) in resp |
... | ... | |
1164 | 1164 |
event.cancellation_datetime = None |
1165 | 1165 | |
1166 | 1166 | |
1167 |
def test_event_check_filters(app, admin_user): |
|
1168 |
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar') |
|
1169 |
event = Event.objects.create( |
|
1170 |
label='xyz', |
|
1171 |
start_datetime=now() - datetime.timedelta(days=1), |
|
1172 |
places=10, |
|
1173 |
agenda=agenda, |
|
1174 |
) |
|
1175 |
Booking.objects.create(event=event, user_name='User none') |
|
1176 |
Booking.objects.create(event=event, user_name='User empty', extra_data={}) |
|
1177 |
Booking.objects.create(event=event, user_name='User foo-val1 bar-none', extra_data={'foo': 'val1'}) |
|
1178 |
Booking.objects.create( |
|
1179 |
event=event, user_name='User foo-val2 bar-val1', extra_data={'foo': 'val2', 'bar': 'val1'} |
|
1180 |
) |
|
1181 |
Booking.objects.create( |
|
1182 |
event=event, user_name='User foo-val1 bar-val2', extra_data={'foo': 'val1', 'bar': 'val2'} |
|
1183 |
) |
|
1184 |
Booking.objects.create(event=event, user_name='User foo-none bar-val2', extra_data={'bar': 'val2'}) |
|
1185 |
login(app) |
|
1186 | ||
1187 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1188 |
assert 'User none' in resp |
|
1189 |
assert 'User empty' in resp |
|
1190 |
assert 'User foo-val1' in resp |
|
1191 |
assert 'User foo-val2 bar-val1' in resp |
|
1192 |
assert 'User foo-val1 bar-val2' in resp |
|
1193 |
assert 'User foo-none bar-val2' in resp |
|
1194 | ||
1195 |
resp = app.get( |
|
1196 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'unknown': 'unknown'} |
|
1197 |
) |
|
1198 |
assert 'User none' in resp |
|
1199 |
assert 'User empty' in resp |
|
1200 |
assert 'User foo-val1 bar-none' in resp |
|
1201 |
assert 'User foo-val2 bar-val1' in resp |
|
1202 |
assert 'User foo-val1 bar-val2' in resp |
|
1203 |
assert 'User foo-none bar-val2' in resp |
|
1204 | ||
1205 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'unknown'}) |
|
1206 |
assert 'User none' in resp |
|
1207 |
assert 'User empty' in resp |
|
1208 |
assert 'User foo-val1 bar-none' in resp |
|
1209 |
assert 'User foo-val2 bar-val1' in resp |
|
1210 |
assert 'User foo-val1 bar-val2' in resp |
|
1211 |
assert 'User foo-none bar-val2' in resp |
|
1212 | ||
1213 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val1'}) |
|
1214 |
assert 'User none' not in resp |
|
1215 |
assert 'User empty' not in resp |
|
1216 |
assert 'User foo-val1 bar-none' in resp |
|
1217 |
assert 'User foo-val2 bar-val1' not in resp |
|
1218 |
assert 'User foo-val1 bar-val2' in resp |
|
1219 |
assert 'User foo-none bar-val2' not in resp |
|
1220 | ||
1221 |
resp = app.get( |
|
1222 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val1', 'bar': 'val2'} |
|
1223 |
) |
|
1224 |
assert 'User none' not in resp |
|
1225 |
assert 'User empty' not in resp |
|
1226 |
assert 'User foo-val1 bar-none' not in resp |
|
1227 |
assert 'User foo-val2 bar-val1' not in resp |
|
1228 |
assert 'User foo-val1 bar-val2' in resp |
|
1229 |
assert 'User foo-none bar-val2' not in resp |
|
1230 | ||
1231 |
resp = app.get( |
|
1232 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val2', 'bar': 'val2'} |
|
1233 |
) |
|
1234 |
assert 'User none' not in resp |
|
1235 |
assert 'User empty' not in resp |
|
1236 |
assert 'User foo-val1 bar-none' not in resp |
|
1237 |
assert 'User foo-val2 bar-val1' not in resp |
|
1238 |
assert 'User foo-val1 bar-val2' not in resp |
|
1239 |
assert 'User foo-none bar-val2' not in resp |
|
1240 | ||
1241 | ||
1167 | 1242 |
def test_event_check_booking(app, admin_user): |
1168 | 1243 |
group = AbsenceReasonGroup.objects.create(label='Foo bar') |
1169 | 1244 |
agenda = Agenda.objects.create(label='Events', kind='events') |
1170 |
- |