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 |
... | ... | |
240 | 242 |
return self.instance |
241 | 243 | |
242 | 244 | |
245 |
class BookingCheckFilterSet(django_filters.FilterSet): |
|
246 |
class Meta: |
|
247 |
model = Booking |
|
248 |
fields = [] |
|
249 | ||
250 |
def __init__(self, *args, **kwargs): |
|
251 |
self.agenda = kwargs.pop('agenda') |
|
252 |
super().__init__(*args, **kwargs) |
|
253 | ||
254 |
# build filters from DB |
|
255 |
agenda_filters = self.agenda.get_booking_check_filters() |
|
256 |
filters = collections.defaultdict(set) |
|
257 |
for extra_data in self.queryset.filter(extra_data__has_any_keys=agenda_filters).values_list( |
|
258 |
'extra_data', flat=True |
|
259 |
): |
|
260 |
for k, v in extra_data.items(): |
|
261 |
if k in agenda_filters: |
|
262 |
filters[k].add(v) |
|
263 |
filters = sorted(filters.items()) |
|
264 |
filters = {k: sorted(list(v)) for k, v in filters} |
|
265 | ||
266 |
# add filters to filterset |
|
267 |
for key, values in filters.items(): |
|
268 |
self.filters[key] = django_filters.ChoiceFilter( |
|
269 |
label=_('Filter by %s') % key, |
|
270 |
field_name='extra_data__%s' % key, |
|
271 |
lookup_expr='iexact', |
|
272 |
choices=[(v, v) for v in values], |
|
273 |
empty_label=_('all'), |
|
274 |
widget=forms.RadioSelect, |
|
275 |
) |
|
276 | ||
277 | ||
243 | 278 |
class BookingAbsenceReasonForm(forms.Form): |
244 | 279 |
reason = forms.ChoiceField(required=False) |
245 | 280 |
chrono/manager/static/css/style.scss | ||
---|---|---|
408 | 408 |
} |
409 | 409 |
} |
410 | 410 | |
411 |
form.check-bookings-filters li { |
|
412 |
display: inline; |
|
413 |
margin-right: 10px; |
|
414 |
} |
|
415 | ||
411 | 416 |
// booking colors |
412 | 417 |
$booking-colors: ( |
413 | 418 |
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 |
{% if booked_without_status %} |
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 |
... | ... | |
90 | 91 |
AgendasImportForm, |
91 | 92 |
BookingAbsenceReasonForm, |
92 | 93 |
BookingCancelForm, |
94 |
BookingCheckFilterSet, |
|
93 | 95 |
DeskForm, |
94 | 96 |
EventCancelForm, |
95 | 97 |
EventForm, |
... | ... | |
1960 | 1962 | |
1961 | 1963 |
def get_context_data(self, **kwargs): |
1962 | 1964 |
context = super().get_context_data(**kwargs) |
1965 | ||
1963 | 1966 |
event = self.object |
1964 |
context['booked'] = event.booking_set.filter( |
|
1965 |
cancellation_datetime__isnull=True, in_waiting_list=False |
|
1966 |
).order_by('user_name') |
|
1967 |
booked_qs = event.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False) |
|
1968 |
filterset = BookingCheckFilterSet(self.request.GET, queryset=booked_qs, agenda=self.agenda) |
|
1969 |
context['filterset'] = filterset |
|
1970 | ||
1971 |
# build booking list |
|
1972 |
context['booked'] = filterset.qs.order_by('user_name') |
|
1967 | 1973 |
context['booked_without_status'] = any(e.user_was_present is None for e in context['booked']) |
1968 |
if context['booked_without_status']: |
|
1969 |
context['absence_form'] = BookingAbsenceReasonForm(agenda=self.agenda) |
|
1970 |
context['waiting'] = event.booking_set.filter( |
|
1971 |
cancellation_datetime__isnull=True, in_waiting_list=True |
|
1972 |
).order_by('user_name') |
|
1973 | 1974 |
for booking in context['booked']: |
1974 | 1975 |
booking.form = BookingAbsenceReasonForm( |
1975 | 1976 |
agenda=self.agenda, initial={'reason': booking.user_absence_reason} |
1976 | 1977 |
) |
1978 |
context['waiting'] = event.booking_set.filter( |
|
1979 |
cancellation_datetime__isnull=True, in_waiting_list=True |
|
1980 |
).order_by('user_name') |
|
1981 | ||
1977 | 1982 |
return context |
1978 | 1983 | |
1979 | 1984 |
tests/manager/test_event.py | ||
---|---|---|
1083 | 1083 |
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp |
1084 | 1084 |
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404) |
1085 | 1085 | |
1086 |
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it'os ok all the day
|
|
1086 |
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it's ok all the day |
|
1087 | 1087 |
event.save() |
1088 | 1088 |
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk)) |
1089 | 1089 |
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) in resp |
... | ... | |
1170 | 1170 |
event.cancellation_datetime = None |
1171 | 1171 | |
1172 | 1172 | |
1173 |
def test_event_check_filters(app, admin_user): |
|
1174 |
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar') |
|
1175 |
event = Event.objects.create( |
|
1176 |
label='xyz', |
|
1177 |
start_datetime=now() - datetime.timedelta(days=1), |
|
1178 |
places=10, |
|
1179 |
agenda=agenda, |
|
1180 |
) |
|
1181 |
Booking.objects.create(event=event, user_name='User none') |
|
1182 |
Booking.objects.create(event=event, user_name='User empty', extra_data={}) |
|
1183 |
Booking.objects.create(event=event, user_name='User foo-val1 bar-none', extra_data={'foo': 'val1'}) |
|
1184 |
Booking.objects.create( |
|
1185 |
event=event, user_name='User foo-val2 bar-val1', extra_data={'foo': 'val2', 'bar': 'val1'} |
|
1186 |
) |
|
1187 |
Booking.objects.create( |
|
1188 |
event=event, user_name='User foo-val1 bar-val2', extra_data={'foo': 'val1', 'bar': 'val2'} |
|
1189 |
) |
|
1190 |
Booking.objects.create(event=event, user_name='User foo-none bar-val2', extra_data={'bar': 'val2'}) |
|
1191 |
login(app) |
|
1192 | ||
1193 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1194 |
assert 'User none' in resp |
|
1195 |
assert 'User empty' in resp |
|
1196 |
assert 'User foo-val1' in resp |
|
1197 |
assert 'User foo-val2 bar-val1' in resp |
|
1198 |
assert 'User foo-val1 bar-val2' in resp |
|
1199 |
assert 'User foo-none bar-val2' in resp |
|
1200 | ||
1201 |
resp = app.get( |
|
1202 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'unknown': 'unknown'} |
|
1203 |
) |
|
1204 |
assert 'User none' in resp |
|
1205 |
assert 'User empty' in resp |
|
1206 |
assert 'User foo-val1 bar-none' in resp |
|
1207 |
assert 'User foo-val2 bar-val1' in resp |
|
1208 |
assert 'User foo-val1 bar-val2' in resp |
|
1209 |
assert 'User foo-none bar-val2' in resp |
|
1210 | ||
1211 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'unknown'}) |
|
1212 |
assert 'User none' in resp |
|
1213 |
assert 'User empty' in resp |
|
1214 |
assert 'User foo-val1 bar-none' in resp |
|
1215 |
assert 'User foo-val2 bar-val1' in resp |
|
1216 |
assert 'User foo-val1 bar-val2' in resp |
|
1217 |
assert 'User foo-none bar-val2' in resp |
|
1218 | ||
1219 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val1'}) |
|
1220 |
assert 'User none' not in resp |
|
1221 |
assert 'User empty' not in resp |
|
1222 |
assert 'User foo-val1 bar-none' in resp |
|
1223 |
assert 'User foo-val2 bar-val1' not in resp |
|
1224 |
assert 'User foo-val1 bar-val2' in resp |
|
1225 |
assert 'User foo-none bar-val2' not in resp |
|
1226 | ||
1227 |
resp = app.get( |
|
1228 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val1', 'bar': 'val2'} |
|
1229 |
) |
|
1230 |
assert 'User none' not in resp |
|
1231 |
assert 'User empty' not in resp |
|
1232 |
assert 'User foo-val1 bar-none' not in resp |
|
1233 |
assert 'User foo-val2 bar-val1' not in resp |
|
1234 |
assert 'User foo-val1 bar-val2' in resp |
|
1235 |
assert 'User foo-none bar-val2' not in resp |
|
1236 | ||
1237 |
resp = app.get( |
|
1238 |
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'foo': 'val2', 'bar': 'val2'} |
|
1239 |
) |
|
1240 |
assert 'User none' not in resp |
|
1241 |
assert 'User empty' not in resp |
|
1242 |
assert 'User foo-val1 bar-none' not in resp |
|
1243 |
assert 'User foo-val2 bar-val1' not in resp |
|
1244 |
assert 'User foo-val1 bar-val2' not in resp |
|
1245 |
assert 'User foo-none bar-val2' not in resp |
|
1246 | ||
1247 | ||
1173 | 1248 |
def test_event_check_booking(app, admin_user): |
1174 | 1249 |
group = AbsenceReasonGroup.objects.create(label='Foo bar') |
1175 | 1250 |
agenda = Agenda.objects.create(label='Events', kind='events') |
1176 |
- |