manager: display date time period in calendar views (#70185)
This commit is contained in:
parent
e716f57c36
commit
bb148dc008
|
@ -795,7 +795,7 @@ class Agenda(models.Model):
|
|||
end_datetime__gt=min_start,
|
||||
)
|
||||
|
||||
def prefetch_desks_and_exceptions(self, with_sources=False, min_date=None):
|
||||
def prefetch_desks_and_exceptions(self, min_date, max_date=None, with_sources=False):
|
||||
if self.kind == 'meetings':
|
||||
desks = self.desk_set.all()
|
||||
elif self.kind == 'virtual':
|
||||
|
@ -807,11 +807,12 @@ class Agenda(models.Model):
|
|||
else:
|
||||
raise ValueError('does not work with kind %r' % self.kind)
|
||||
|
||||
if min_date:
|
||||
past_date_time_periods = TimePeriod.objects.filter(desk=OuterRef('pk'), date__lt=min_date)
|
||||
desks = desks.annotate(has_past_date_time_periods=Exists(past_date_time_periods))
|
||||
|
||||
time_period_queryset = TimePeriod.objects.filter(Q(date__isnull=True) | Q(date__gte=min_date))
|
||||
if max_date:
|
||||
time_period_queryset = time_period_queryset.filter(Q(date__isnull=True) | Q(date__lte=max_date))
|
||||
|
||||
self.prefetched_desks = desks.prefetch_related(
|
||||
'unavailability_calendars', Prefetch('timeperiod_set', queryset=time_period_queryset)
|
||||
|
@ -2276,11 +2277,12 @@ class Desk(models.Model):
|
|||
def get_opening_hours(self, date):
|
||||
openslots = IntervalSet()
|
||||
weekday_index = get_weekday_index(date)
|
||||
real_date = date.date() if isinstance(date, datetime.datetime) else date
|
||||
for timeperiod in self.timeperiod_set.all():
|
||||
if timeperiod.weekday_indexes and weekday_index not in timeperiod.weekday_indexes:
|
||||
continue
|
||||
# timeperiod_set.all() are prefetched, do not filter in queryset
|
||||
if timeperiod.weekday != date.weekday():
|
||||
if timeperiod.date != real_date and timeperiod.weekday != date.weekday():
|
||||
continue
|
||||
start_datetime = make_aware(datetime.datetime.combine(date, timeperiod.start_time))
|
||||
end_datetime = make_aware(datetime.datetime.combine(date, timeperiod.end_time))
|
||||
|
|
|
@ -1264,7 +1264,7 @@ class AgendaDateView(DateMixin, ViewableAgendaMixin):
|
|||
if self.agenda.kind == 'events':
|
||||
queryset = self.agenda.event_set.filter(recurrence_days__isnull=True)
|
||||
else:
|
||||
self.agenda.prefetch_desks_and_exceptions()
|
||||
self.agenda.prefetch_desks_and_exceptions(min_date=self.date, max_date=self.get_max_date())
|
||||
if self.agenda.kind == 'meetings':
|
||||
queryset = self.agenda.event_set.select_related('meeting_type').prefetch_related(
|
||||
'booking_set'
|
||||
|
@ -1324,12 +1324,16 @@ class AgendaDayView(AgendaDateView, DayArchiveView):
|
|||
},
|
||||
)
|
||||
|
||||
def get_max_date(self):
|
||||
return self.date.date() + datetime.timedelta(days=1)
|
||||
|
||||
def get_timetable_infos(self):
|
||||
timeperiods = itertools.chain(*(d.timeperiod_set.all() for d in self.agenda.prefetched_desks))
|
||||
timeperiods = [
|
||||
t
|
||||
for t in timeperiods
|
||||
if t.weekday == self.date.weekday()
|
||||
if t.date == self.date.date()
|
||||
or t.weekday == self.date.weekday()
|
||||
and (not t.weekday_indexes or get_weekday_index(self.date) in t.weekday_indexes)
|
||||
]
|
||||
|
||||
|
@ -1457,9 +1461,11 @@ class AgendaWeekMonthMixin:
|
|||
if timeperiods:
|
||||
min_timeperiod = min(x.start_time for x in timeperiods)
|
||||
max_timeperiod = max(x.end_time for x in timeperiods)
|
||||
hide_sunday_timeperiod = not any([e.weekday == 6 for e in timeperiods])
|
||||
hide_sunday_timeperiod = not any(
|
||||
[e.weekday == 6 or (e.date and e.date.weekday() == 6) for e in timeperiods]
|
||||
)
|
||||
hide_weekend_timeperiod = hide_sunday_timeperiod and not any(
|
||||
[e.weekday == 5 for e in timeperiods]
|
||||
[e.weekday == 5 or (e.date and e.date.weekday() == 5) for e in timeperiods]
|
||||
)
|
||||
active_events = [
|
||||
x for x in self.object_list if any([y.cancellation_datetime is None for y in x.booking_set.all()])
|
||||
|
@ -1633,6 +1639,9 @@ class AgendaWeekView(AgendaWeekMonthMixin, AgendaDateView, WeekArchiveView):
|
|||
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w")
|
||||
return date.day
|
||||
|
||||
def get_max_date(self):
|
||||
return self.get_next_week(self.date.date())
|
||||
|
||||
|
||||
agenda_weekly_view = AgendaWeekView.as_view()
|
||||
|
||||
|
@ -1665,6 +1674,9 @@ class AgendaMonthView(AgendaWeekMonthMixin, AgendaDateView, MonthArchiveView):
|
|||
def get_day(self):
|
||||
return '1'
|
||||
|
||||
def get_max_date(self):
|
||||
return self.get_next_month(self.date.date())
|
||||
|
||||
|
||||
agenda_monthly_view = AgendaMonthView.as_view()
|
||||
|
||||
|
|
|
@ -3716,3 +3716,152 @@ def test_agenda_day_and_month_views_weekday_indexes(app, admin_user):
|
|||
assert resp.text.count('height:400.0%') == 1
|
||||
assert resp.text.count('height:700.0%') == 1
|
||||
assert resp.text.count('height:300.0%') == 1
|
||||
|
||||
|
||||
@freezegun.freeze_time('2022-11-15 14:00')
|
||||
def test_agenda_calendar_views_date_time_period(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
||||
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
||||
today = datetime.date.today()
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today,
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
login(app)
|
||||
|
||||
# check day view
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
||||
assert resp.text.count('<tr') == 5 # 10->14
|
||||
assert 'style="height: 400%; top: 0%;"' in resp.text
|
||||
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day + 7))
|
||||
assert 'No opening hours this day.' in resp.text
|
||||
|
||||
# check week view
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert resp.text.count('height:400.0%') == 1
|
||||
|
||||
# check month view
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert resp.text.count('height:400.0%') == 1
|
||||
|
||||
# check month boundaries
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=1),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=30),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert resp.text.count('height:400.0%') == 3
|
||||
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=31, month=10),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=1, month=12),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert resp.text.count('height:400.0%') == 3
|
||||
|
||||
# check week boundaries
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=14),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=20),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert resp.text.count('height:400.0%') == 3
|
||||
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=13),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=today.replace(day=21),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(14, 0),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert resp.text.count('height:400.0%') == 3
|
||||
|
||||
|
||||
@freezegun.freeze_time('2022-11-15 14:00')
|
||||
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
||||
def test_agenda_date_time_period_hide_weekend(app, admin_user, kind):
|
||||
today = datetime.date.today() # Tuesday
|
||||
if kind == 'meetings':
|
||||
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
else:
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
||||
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, date=today, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
|
||||
login(app)
|
||||
# check month view
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
|
||||
# check week view
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, date=today.replace(day=19), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
) # Saturday
|
||||
|
||||
# check month view
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
# check week view
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, date=today.replace(day=20), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
) # Sunday
|
||||
|
||||
# check month view
|
||||
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
# check week view
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.isocalendar().week))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
|
|
@ -276,7 +276,7 @@ def test_agenda_is_available_for_simple_management(settings, with_prefetch):
|
|||
def check_is_available(result, use_prefetch=True):
|
||||
agenda = Agenda.objects.get()
|
||||
if with_prefetch and use_prefetch:
|
||||
agenda.prefetch_desks_and_exceptions(with_sources=True)
|
||||
agenda.prefetch_desks_and_exceptions(with_sources=True, min_date=now())
|
||||
assert agenda.is_available_for_simple_management() == result
|
||||
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
|
|
|
@ -299,6 +299,77 @@ def test_desk_opening_hours_weekday_indexes():
|
|||
assert len(hours) == 0
|
||||
|
||||
|
||||
def test_desk_opening_hours_date_time_period():
|
||||
def set_prefetched_exceptions(desk):
|
||||
desk.prefetched_exceptions = TimePeriodException.objects.filter(
|
||||
Q(desk=desk) | Q(unavailability_calendar__desks=desk)
|
||||
)
|
||||
|
||||
agenda = Agenda.objects.create(label='Foo bar', slug='bar')
|
||||
desk = Desk.objects.create(label='Desk 1', agenda=agenda)
|
||||
|
||||
# morning
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=datetime.date(2022, 10, 24),
|
||||
start_time=datetime.time(9, 0),
|
||||
end_time=datetime.time(12, 0),
|
||||
)
|
||||
set_prefetched_exceptions(desk)
|
||||
hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
|
||||
assert len(hours) == 1
|
||||
assert hours[0].begin.time() == datetime.time(9, 0)
|
||||
assert hours[0].end.time() == datetime.time(12, 0)
|
||||
|
||||
# and afternoon
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
date=datetime.date(2022, 10, 24),
|
||||
start_time=datetime.time(14, 0),
|
||||
end_time=datetime.time(17, 0),
|
||||
)
|
||||
set_prefetched_exceptions(desk)
|
||||
previous_hours = hours
|
||||
hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
|
||||
assert len(hours) == 2
|
||||
assert hours[0] == previous_hours[0]
|
||||
|
||||
assert hours[1].begin.time() == datetime.time(14, 0)
|
||||
assert hours[1].end.time() == datetime.time(17, 0)
|
||||
|
||||
# mix with repeating period
|
||||
TimePeriod.objects.create(
|
||||
desk=desk,
|
||||
weekday=0,
|
||||
start_time=datetime.time(19, 0),
|
||||
end_time=datetime.time(20, 0),
|
||||
)
|
||||
previous_hours = hours
|
||||
hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
|
||||
assert len(hours) == 3
|
||||
assert hours[:2] == previous_hours[:2]
|
||||
|
||||
assert hours[2].begin.time() == datetime.time(19, 0)
|
||||
assert hours[2].end.time() == datetime.time(20, 0)
|
||||
|
||||
# full day exception
|
||||
TimePeriodException.objects.create(
|
||||
desk=desk,
|
||||
start_datetime=make_aware(datetime.datetime(2022, 10, 24)),
|
||||
end_datetime=make_aware(datetime.datetime(2022, 10, 25)),
|
||||
)
|
||||
|
||||
set_prefetched_exceptions(desk)
|
||||
hours = desk.get_opening_hours(datetime.date(2022, 10, 24))
|
||||
assert len(hours) == 0
|
||||
|
||||
# next week
|
||||
hours = desk.get_opening_hours(datetime.date(2022, 10, 31))
|
||||
assert len(hours) == 1
|
||||
assert hours[0].begin.time() == datetime.time(19, 0)
|
||||
assert hours[0].end.time() == datetime.time(20, 0)
|
||||
|
||||
|
||||
def test_timeperiod_midnight_overlap_time_slots():
|
||||
# https://dev.entrouvert.org/issues/29142
|
||||
agenda = Agenda(label='Foo bar', slug='bar')
|
||||
|
|
Loading…
Reference in New Issue