Projet

Général

Profil

0006-manager-display-date-time-period-in-calendar-views-7.patch

Valentin Deniaud, 25 octobre 2022 10:53

Télécharger (10 ko)

Voir les différences:

Subject: [PATCH 6/7] manager: display date time period in calendar views
 (#70185)

 chrono/agendas/models.py   | 14 ++++----
 chrono/manager/views.py    |  7 ++--
 tests/manager/test_all.py  | 58 +++++++++++++++++++++++++++++++
 tests/test_agendas.py      |  2 +-
 tests/test_time_periods.py | 71 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 143 insertions(+), 9 deletions(-)
chrono/agendas/models.py
794 794
            end_datetime__gt=min_start,
795 795
        )
796 796

  
797
    def prefetch_desks_and_exceptions(self, with_sources=False, min_date=None):
797
    def prefetch_desks_and_exceptions(self, min_date, max_date=None, with_sources=False):
798 798
        if self.kind == 'meetings':
799 799
            desks = self.desk_set.all()
800 800
        elif self.kind == 'virtual':
......
806 806
        else:
807 807
            raise ValueError('does not work with kind %r' % self.kind)
808 808

  
809
        if min_date:
810
            past_date_time_periods = TimePeriod.objects.filter(desk=OuterRef('pk'), date__lt=min_date)
811
            desks = desks.annotate(has_past_date_time_periods=Exists(past_date_time_periods))
809
        past_date_time_periods = TimePeriod.objects.filter(desk=OuterRef('pk'), date__lt=min_date)
810
        desks = desks.annotate(has_past_date_time_periods=Exists(past_date_time_periods))
812 811

  
813
            time_period_queryset = TimePeriod.objects.filter(Q(date__isnull=True) | Q(date__gte=min_date))
812
        time_period_queryset = TimePeriod.objects.filter(Q(date__isnull=True) | Q(date__gte=min_date))
813
        if max_date:
814
            time_period_queryset = time_period_queryset.filter(Q(date__isnull=True) | Q(date__lte=max_date))
814 815

  
815 816
        self.prefetched_desks = desks.prefetch_related(
816 817
            'unavailability_calendars', Prefetch('timeperiod_set', queryset=time_period_queryset)
......
2274 2275
    def get_opening_hours(self, date):
2275 2276
        openslots = IntervalSet()
2276 2277
        weekday_index = get_weekday_index(date)
2278
        real_date = date.date() if isinstance(date, datetime.datetime) else date
2277 2279
        for timeperiod in self.timeperiod_set.all():
2278 2280
            if timeperiod.weekday_indexes and weekday_index not in timeperiod.weekday_indexes:
2279 2281
                continue
2280 2282
            # timeperiod_set.all() are prefetched, do not filter in queryset
2281
            if timeperiod.weekday != date.weekday():
2283
            if timeperiod.date != real_date and timeperiod.weekday != date.weekday():
2282 2284
                continue
2283 2285
            start_datetime = make_aware(datetime.datetime.combine(date, timeperiod.start_time))
2284 2286
            end_datetime = make_aware(datetime.datetime.combine(date, timeperiod.end_time))
chrono/manager/views.py
1182 1182
        if self.agenda.kind == 'events':
1183 1183
            queryset = self.agenda.event_set.filter(recurrence_days__isnull=True)
1184 1184
        else:
1185
            self.agenda.prefetch_desks_and_exceptions()
1185
            self.agenda.prefetch_desks_and_exceptions(
1186
                min_date=self.date, max_date=self.get_next_month(self.date.date())
1187
            )
1186 1188
            if self.agenda.kind == 'meetings':
1187 1189
                queryset = self.agenda.event_set.select_related('meeting_type').prefetch_related(
1188 1190
                    'booking_set'
......
1247 1249
        timeperiods = [
1248 1250
            t
1249 1251
            for t in timeperiods
1250
            if t.weekday == self.date.weekday()
1252
            if t.date == self.date.date()
1253
            or t.weekday == self.date.weekday()
1251 1254
            and (not t.weekday_indexes or get_weekday_index(self.date) in t.weekday_indexes)
1252 1255
        ]
1253 1256

  
tests/manager/test_all.py
3041 3041
    assert resp.text.count('height:400.0%') == 1
3042 3042
    assert resp.text.count('height:700.0%') == 1
3043 3043
    assert resp.text.count('height:300.0%') == 1
3044

  
3045

  
3046
@freezegun.freeze_time('2022-11-15 14:00')
3047
def test_agenda_day_and_month_views_date_time_period(app, admin_user):
3048
    agenda = Agenda.objects.create(label='New Example', kind='meetings')
3049
    desk = Desk.objects.create(agenda=agenda, label='New Desk')
3050
    MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
3051
    today = datetime.date.today()
3052
    TimePeriod.objects.create(
3053
        desk=desk,
3054
        date=today,
3055
        start_time=datetime.time(10, 0),
3056
        end_time=datetime.time(14, 0),
3057
    )
3058
    login(app)
3059

  
3060
    # check day view
3061
    resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
3062
    assert resp.text.count('<tr') == 5  # 10->14
3063
    assert 'style="height: 400%; top: 0%;"' in resp.text
3064

  
3065
    resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day + 7))
3066
    assert 'No opening hours this day.' in resp.text
3067

  
3068
    # check month view
3069
    resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
3070
    assert resp.text.count('height:400.0%') == 1
3071

  
3072
    # check boundaries
3073
    TimePeriod.objects.create(
3074
        desk=desk,
3075
        date=today.replace(day=1),
3076
        start_time=datetime.time(10, 0),
3077
        end_time=datetime.time(14, 0),
3078
    )
3079
    TimePeriod.objects.create(
3080
        desk=desk,
3081
        date=today.replace(day=30),
3082
        start_time=datetime.time(10, 0),
3083
        end_time=datetime.time(14, 0),
3084
    )
3085
    resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
3086
    assert resp.text.count('height:400.0%') == 3
3087

  
3088
    TimePeriod.objects.create(
3089
        desk=desk,
3090
        date=today.replace(day=31, month=10),
3091
        start_time=datetime.time(10, 0),
3092
        end_time=datetime.time(14, 0),
3093
    )
3094
    TimePeriod.objects.create(
3095
        desk=desk,
3096
        date=today.replace(day=1, month=12),
3097
        start_time=datetime.time(10, 0),
3098
        end_time=datetime.time(14, 0),
3099
    )
3100
    resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
3101
    assert resp.text.count('height:400.0%') == 3
tests/test_agendas.py
276 276
    def check_is_available(result, use_prefetch=True):
277 277
        agenda = Agenda.objects.get()
278 278
        if with_prefetch and use_prefetch:
279
            agenda.prefetch_desks_and_exceptions(with_sources=True)
279
            agenda.prefetch_desks_and_exceptions(with_sources=True, min_date=now())
280 280
        assert agenda.is_available_for_simple_management() == result
281 281

  
282 282
    agenda = Agenda.objects.create(label='Agenda', kind='meetings')
tests/test_time_periods.py
299 299
    assert len(hours) == 0
300 300

  
301 301

  
302
def test_desk_opening_hours_date_time_period():
303
    def set_prefetched_exceptions(desk):
304
        desk.prefetched_exceptions = TimePeriodException.objects.filter(
305
            Q(desk=desk) | Q(unavailability_calendar__desks=desk)
306
        )
307

  
308
    agenda = Agenda.objects.create(label='Foo bar', slug='bar')
309
    desk = Desk.objects.create(label='Desk 1', agenda=agenda)
310

  
311
    # morning
312
    TimePeriod.objects.create(
313
        desk=desk,
314
        date=datetime.date(2022, 10, 24),
315
        start_time=datetime.time(9, 0),
316
        end_time=datetime.time(12, 0),
317
    )
318
    set_prefetched_exceptions(desk)
319
    hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
320
    assert len(hours) == 1
321
    assert hours[0].begin.time() == datetime.time(9, 0)
322
    assert hours[0].end.time() == datetime.time(12, 0)
323

  
324
    # and afternoon
325
    TimePeriod.objects.create(
326
        desk=desk,
327
        date=datetime.date(2022, 10, 24),
328
        start_time=datetime.time(14, 0),
329
        end_time=datetime.time(17, 0),
330
    )
331
    set_prefetched_exceptions(desk)
332
    previous_hours = hours
333
    hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
334
    assert len(hours) == 2
335
    assert hours[0] == previous_hours[0]
336

  
337
    assert hours[1].begin.time() == datetime.time(14, 0)
338
    assert hours[1].end.time() == datetime.time(17, 0)
339

  
340
    # mix with repeating period
341
    TimePeriod.objects.create(
342
        desk=desk,
343
        weekday=0,
344
        start_time=datetime.time(19, 0),
345
        end_time=datetime.time(20, 0),
346
    )
347
    previous_hours = hours
348
    hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
349
    assert len(hours) == 3
350
    assert hours[:2] == previous_hours[:2]
351

  
352
    assert hours[2].begin.time() == datetime.time(19, 0)
353
    assert hours[2].end.time() == datetime.time(20, 0)
354

  
355
    # full day exception
356
    TimePeriodException.objects.create(
357
        desk=desk,
358
        start_datetime=make_aware(datetime.datetime(2022, 10, 24)),
359
        end_datetime=make_aware(datetime.datetime(2022, 10, 25)),
360
    )
361

  
362
    set_prefetched_exceptions(desk)
363
    hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
364
    assert len(hours) == 0
365

  
366
    # next week
367
    hours = desk.get_opening_hours(datetime.date(2022, 10, 31))
368
    assert len(hours) == 1
369
    assert hours[0].begin.time() == datetime.time(19, 0)
370
    assert hours[0].end.time() == datetime.time(20, 0)
371

  
372

  
302 373
def test_timeperiod_midnight_overlap_time_slots():
303 374
    # https://dev.entrouvert.org/issues/29142
304 375
    agenda = Agenda(label='Foo bar', slug='bar')
305
-