Projet

Général

Profil

0002-managers-display-filters-on-check-page-53238.patch

Lauréline Guérin, 18 mai 2021 10:06

Télécharger (9,78 ko)

Voir les différences:

Subject: [PATCH 2/2] managers: display filters on check page (#53238)

 chrono/manager/forms.py                       | 35 +++++++++
 chrono/manager/static/css/style.scss          |  5 ++
 .../templates/chrono/manager_event_check.html | 11 +++
 chrono/manager/views.py                       | 21 +++--
 tests/manager/test_event.py                   | 77 ++++++++++++++++++-
 5 files changed, 140 insertions(+), 9 deletions(-)
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
-