0006-manager-display-date-time-period-in-calendar-views-7.patch
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 |
- |