Projet

Général

Profil

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

Lauréline Guérin, 22 avril 2021 11:40

Télécharger (9,55 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                       | 19 +++--
 tests/manager/test_event.py                   | 77 ++++++++++++++++++-
 5 files changed, 140 insertions(+), 7 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
......
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
-