From 55f6d0e47d1addd6e58c6537d447081ba237d5e3 Mon Sep 17 00:00:00 2001 From: Emmanuel Cazenave Date: Tue, 25 Feb 2020 10:30:47 +0100 Subject: [PATCH] virtual agendas: use real agendas booking delays (#40121) If booking delays are defined on the virtual agenda, they will take precedence. --- chrono/api/views.py | 40 ++++++++++++++++++++++++++------- tests/test_api.py | 55 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/chrono/api/views.py b/chrono/api/views.py index 3867429d..3c43df38 100644 --- a/chrono/api/views.py +++ b/chrono/api/views.py @@ -49,13 +49,24 @@ def get_exceptions_by_desk(agenda): return exceptions_by_desk -def get_all_slots(agenda, meeting_type): +def get_min_datetime(agenda): + if agenda.minimal_booking_delay is None: + return None min_datetime = now() + datetime.timedelta(days=agenda.minimal_booking_delay) - max_datetime = now() + datetime.timedelta(days=agenda.maximal_booking_delay) - min_datetime = min_datetime.replace(hour=0, minute=0, second=0, microsecond=0) - max_datetime = max_datetime.replace(hour=0, minute=0, second=0, microsecond=0) - max_datetime = max_datetime + datetime.timedelta(days=1) + return min_datetime.replace(hour=0, minute=0, second=0, microsecond=0) + +def get_max_datetime(agenda): + if agenda.maximal_booking_delay is None: + return None + max_datetime = now() + datetime.timedelta(days=agenda.maximal_booking_delay) + max_datetime = max_datetime.replace(hour=0, minute=0, second=0, microsecond=0) + return max_datetime + datetime.timedelta(days=1) + + +def get_all_slots(agenda, meeting_type): + min_datetime = get_min_datetime(agenda) + max_datetime = get_max_datetime(agenda) time_period_filters = { 'min_datetime': min_datetime, 'max_datetime': max_datetime, @@ -71,6 +82,12 @@ def get_all_slots(agenda, meeting_type): open_slots[agenda] = defaultdict(lambda: Intervals()) for agenda in agendas: + used_time_period_filters = time_period_filters.copy() + if used_time_period_filters['min_datetime'] is None: + used_time_period_filters['min_datetime'] = get_min_datetime(agenda) + if used_time_period_filters['max_datetime'] is None: + used_time_period_filters['max_datetime'] = get_max_datetime(agenda) + for time_period in TimePeriod.objects.filter(desk__agenda=agenda): duration = ( datetime.datetime.combine(base_date, time_period.end_time) @@ -79,7 +96,7 @@ def get_all_slots(agenda, meeting_type): if duration < meeting_type.duration: # skip time period that can't even hold a single meeting continue - for slot in time_period.get_time_slots(**time_period_filters): + for slot in time_period.get_time_slots(**used_time_period_filters): slot.full = False open_slots[agenda][time_period.desk_id].add(slot.start_datetime, slot.end_datetime, slot) @@ -93,11 +110,18 @@ def get_all_slots(agenda, meeting_type): open_slots[agenda][desk].remove_overlap(localtime(begin), localtime(end)) for agenda in agendas: + used_min_datetime = min_datetime + if used_min_datetime is None: + used_min_datetime = get_min_datetime(agenda) + used_max_datetime = max_datetime + if used_max_datetime is None: + used_max_datetime = get_max_datetime(agenda) + for event in ( agenda.event_set.filter( agenda=agenda, - start_datetime__gte=min_datetime, - start_datetime__lte=max_datetime + datetime.timedelta(meeting_type.duration), + start_datetime__gte=used_min_datetime, + start_datetime__lte=used_max_datetime + datetime.timedelta(meeting_type.duration), ) .select_related('meeting_type') .exclude(booking__cancellation_datetime__isnull=False) diff --git a/tests/test_api.py b/tests/test_api.py index 2386e0a1..b81cc073 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2465,8 +2465,8 @@ def test_virtual_agenda_detail(app, virtual_meetings_agenda): 'text': 'Virtual Agenda', 'id': 'virtual-agenda', 'slug': 'virtual-agenda', - 'minimal_booking_delay': 1, - 'maximal_booking_delay': 56, + 'minimal_booking_delay': None, + 'maximal_booking_delay': None, 'kind': 'virtual', 'api': { 'meetings_url': 'http://testserver/api/agenda/%s/meetings/' % virtual_meetings_agenda.slug, @@ -2625,6 +2625,57 @@ def test_virtual_agendas_meetings_datetimes_api(app, virtual_meetings_agenda): assert len(resp.json['data']) == 3 +def test_virtual_agendas_meetings_datetimes_delays_api(app, mock_now): + foo_agenda = Agenda.objects.create(label='Foo Meeting', kind='meetings', maximal_booking_delay=7) + MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30) + foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1') + TimePeriod.objects.create( + weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk_1, + ) + TimePeriod.objects.create( + weekday=1, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk_1, + ) + + bar_agenda = Agenda.objects.create(label='Bar Meeting', kind='meetings', maximal_booking_delay=7) + MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30) + bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1') + TimePeriod.objects.create( + weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_1, + ) + TimePeriod.objects.create( + weekday=3, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_1, + ) + + virt_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual') + + VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda) + VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda) + virt_meeting_type = virt_agenda.iter_meetingtypes()[0] + api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, virt_meeting_type.slug) + resp = app.get(api_url) + # 8 slots for m each agenda + assert len(resp.json['data']) == 16 + + # restrict foo's minimal_booking_delay : only bar's slots are left + foo_agenda.minimal_booking_delay = 6 + foo_agenda.save() + resp = app.get(api_url) + assert len(resp.json['data']) == 8 + + # restrict bar's maximal_booking_delay : only half of bar's slots are left + bar_agenda.maximal_booking_delay = 4 + bar_agenda.save() + resp = app.get(api_url) + assert len(resp.json['data']) == 4 + + # put back very slots from foo + foo_agenda.minimal_booking_delay = 1 + foo_agenda.maximal_booking_delay = 7 + foo_agenda.save() + resp = app.get(api_url) + assert len(resp.json['data']) == 12 + + def test_virtual_agendas_meetings_exception(app, user, virtual_meetings_agenda): app.authorization = ('Basic', ('john.doe', 'password')) real_agenda = virtual_meetings_agenda.real_agendas.first()