Projet

Général

Profil

0002-manager-unavailability-calendars-exceptions-in-timet.patch

Valentin Deniaud, 10 décembre 2020 15:37

Télécharger (10,1 ko)

Voir les différences:

Subject: [PATCH 2/2] manager: unavailability calendars exceptions in timetable
 views (#48306)

 chrono/agendas/models.py | 18 ++++++++++-----
 chrono/manager/views.py  | 33 ++++++++++++---------------
 tests/test_manager.py    | 48 +++++++++++++++++++++++++++++++---------
 3 files changed, 64 insertions(+), 35 deletions(-)
chrono/agendas/models.py
530 530
            return
531 531

  
532 532
    def prefetch_desks_and_exceptions(self):
533
        assert self.kind != 'events'
533
        if self.kind == 'meetings':
534
            desks = self.desk_set.all()
535
        elif self.kind == 'virtual':
536
            desks = (
537
                Desk.objects.filter(agenda__virtual_agendas=self)
538
                .select_related('agenda')
539
                .order_by('agenda', 'label')
540
            )
541
        else:
542
            raise TypeError('This method cannot be called on events agendas.')
534 543

  
535
        self.prefetched_desks = self.desk_set.all().prefetch_related(
536
            'timeperiod_set', 'unavailability_calendars',
537
        )
544
        self.prefetched_desks = desks.prefetch_related('timeperiod_set', 'unavailability_calendars')
538 545
        all_desks_exceptions = TimePeriodException.objects.filter(
539 546
            Q(desk__in=self.prefetched_desks) | Q(unavailability_calendar__desks__in=self.prefetched_desks)
540 547
        ).select_related('source')
......
1382 1389
        aware_date = make_aware(datetime.datetime(date.year, date.month, date.day))
1383 1390
        exceptions = IntervalSet()
1384 1391
        aware_next_date = aware_date + datetime.timedelta(days=1)
1385
        for exception in self.timeperiodexception_set.all():
1386
            # timeperiodexception_set.all() are prefetched, do not filter in queryset
1392
        for exception in self.prefetched_exceptions:
1387 1393
            if exception.end_datetime < aware_date:
1388 1394
                continue
1389 1395
            if exception.start_datetime > aware_next_date:
chrono/manager/views.py
877 877
    def get_queryset(self):
878 878
        if self.agenda.kind == 'events':
879 879
            queryset = self.agenda.event_set.all()
880
        elif self.agenda.kind == 'meetings':
881
            self.agenda.prefetched_desks = self.agenda.desk_set.all().prefetch_related(
882
                'timeperiod_set', 'timeperiodexception_set'
883
            )
884
            queryset = self.agenda.event_set.select_related('meeting_type').prefetch_related('booking_set')
885 880
        else:
886
            self.agenda.prefetched_desks = (
887
                Desk.objects.filter(agenda__virtual_agendas=self.agenda)
888
                .prefetch_related('timeperiod_set', 'timeperiodexception_set')
889
                .select_related('agenda')
890
                .order_by('agenda', 'label')
891
            )
892
            queryset = (
893
                Event.objects.filter(agenda__virtual_agendas=self.agenda)
894
                .select_related('meeting_type')
895
                .prefetch_related('booking_set')
896
            )
881
            self.agenda.prefetch_desks_and_exceptions()
882
            if self.agenda.kind == 'meetings':
883
                queryset = self.agenda.event_set.select_related('meeting_type').prefetch_related(
884
                    'booking_set'
885
                )
886
            else:
887
                queryset = (
888
                    Event.objects.filter(agenda__virtual_agendas=self.agenda)
889
                    .select_related('meeting_type')
890
                    .prefetch_related('booking_set')
891
                )
897 892
        return queryset
898 893

  
899 894

  
......
977 972

  
978 973
                    # and exceptions for this desk
979 974
                    info['exceptions'] = []
980
                    for exception in desk.timeperiodexception_set.all():
981
                        if exception.end_datetime < start_date:
975
                    for exception in desk.prefetched_exceptions:
976
                        if exception.end_datetime < current_date:
982 977
                            continue
983 978
                        if exception.start_datetime > max_date:
984 979
                            continue
......
1177 1172
                                'css_left': left,
1178 1173
                            }
1179 1174
                        )
1180
                    for exception in desk.timeperiodexception_set.all():
1175
                    for exception in desk.prefetched_exceptions:
1181 1176
                        if exception.end_datetime < current_date:
1182 1177
                            continue
1183 1178
                        if exception.start_datetime > max_date:
tests/test_manager.py
2984 2984
    resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200)
2985 2985

  
2986 2986
    # display exception
2987
    unavailability_calendar = UnavailabilityCalendar.objects.create(label='calendar')
2988
    TimePeriodException.objects.create(
2989
        label='Calendar exception',
2990
        unavailability_calendar=unavailability_calendar,
2991
        start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 13, 0)),
2992
        end_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 15, 0)),
2993
    )
2994
    unavailability_calendar.desks.add(desk)
2987 2995
    TimePeriodException.objects.create(
2988 2996
        label='Exception for the afternoon',
2989 2997
        desk=desk,
2990
        start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 13, 0)),
2998
        start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 16, 0)),
2991 2999
        end_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 23, 0)),
2992 3000
    )
2993 3001
    with CaptureQueriesContext(connection) as ctx:
2994 3002
        resp = app.get(
2995 3003
            '/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
2996 3004
        )
2997
        assert len(ctx.captured_queries) == 14
3005
        assert len(ctx.captured_queries) == 15
2998 3006
    # day is displaying rows from 10am to 6pm,
2999 3007
    # opening hours, 10am to 1pm gives top: 300%
3000
    # rest of the day, 1pm to 6(+1)pm gives 600%
3008
    # calendar exception, 1pm to 3pm gives heigh: 200%
3001 3009
    assert resp.pyquery.find('.exception-hours')[0].attrib == {
3002 3010
        'class': 'exception-hours',
3003
        'style': 'height: 600%; top: 300%;',
3011
        'style': 'height: 200%; top: 300%;',
3004 3012
    }
3005
    assert resp.pyquery.find('.exception-hours span')[0].text == 'Exception for the afternoon'
3013
    assert resp.pyquery.find('.exception-hours span')[0].text == 'Calendar exception'
3014
    # rest of the day, opened from 3pm to 4pm, since we left off at 500% it gives top: 600%
3015
    # then exception from 4pm to 6pm included, gives height: 300%
3016
    assert resp.pyquery.find('.exception-hours')[1].attrib == {
3017
        'class': 'exception-hours',
3018
        'style': 'height: 300%; top: 600%;',
3019
    }
3020
    assert resp.pyquery.find('.exception-hours span')[1].text == 'Exception for the afternoon'
3006 3021

  
3007 3022

  
3008 3023
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
......
3295 3310
    assert 'No opening hours this month.' not in resp.text
3296 3311

  
3297 3312
    # display exception
3313
    unavailability_calendar = UnavailabilityCalendar.objects.create(label='calendar')
3314
    TimePeriodException.objects.create(
3315
        label='Calendar exception',
3316
        unavailability_calendar=unavailability_calendar,
3317
        start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
3318
        end_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)),
3319
    )
3320
    unavailability_calendar.desks.add(desk)
3298 3321
    TimePeriodException.objects.create(
3299 3322
        label='Exception for a December day',
3300 3323
        desk=desk,
3301
        start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
3324
        start_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)),
3302 3325
        end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
3303 3326
    )
3304 3327
    with CaptureQueriesContext(connection) as ctx:
3305 3328
        resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
3306
        assert len(ctx.captured_queries) == 9
3329
        assert len(ctx.captured_queries) == 10
3307 3330
    assert resp.pyquery.find('.exception-hours')[0].attrib == {
3308 3331
        'class': 'exception-hours',
3309
        'style': 'height:800.0%;top:0.0%;width:48.0%;left:50.0%;',
3332
        'style': 'height:400.0%;top:0.0%;width:48.0%;left:50.0%;',
3333
        'title': 'Calendar exception',
3334
    }
3335
    assert resp.pyquery.find('.exception-hours')[1].attrib == {
3336
        'class': 'exception-hours',
3337
        'style': 'height:400.0%;top:400.0%;width:48.0%;left:50.0%;',
3310 3338
        'title': 'Exception for a December day',
3311 3339
    }
3312 3340

  
......
3934 3962
        resp = app.get(
3935 3963
            '/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
3936 3964
        )
3937
        assert len(ctx.captured_queries) == 15
3965
        assert len(ctx.captured_queries) == 16
3938 3966
    # day is displaying rows from 10am to 6pm,
3939 3967
    # opening hours, 10am to 1pm gives top: 300%
3940 3968
    # rest of the day, 1pm to 6(+1)pm gives 600%
......
4032 4060
    )
4033 4061
    with CaptureQueriesContext(connection) as ctx:
4034 4062
        resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
4035
        assert len(ctx.captured_queries) == 10
4063
        assert len(ctx.captured_queries) == 11
4036 4064
    assert resp.pyquery.find('.exception-hours')[0].attrib == {
4037 4065
        'class': 'exception-hours',
4038 4066
        'style': 'height:800.0%;top:0.0%;width:48.0%;left:1.0%;',
4039
-