260 lines
9.9 KiB
Python
260 lines
9.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import datetime
|
|
|
|
import pytest
|
|
from django.db.models import Q
|
|
from django.test import override_settings
|
|
from django.utils.encoding import force_text
|
|
from django.utils.timezone import localtime, make_aware
|
|
|
|
from chrono.agendas.models import Agenda, Desk, MeetingType, TimePeriod, TimePeriodException
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
def test_timeperiod_time_slots():
|
|
agenda = Agenda(label=u'Foo bar', slug='bar')
|
|
agenda.save()
|
|
desk = Desk.objects.create(label='Desk 1', agenda=agenda)
|
|
meeting_type = MeetingType(duration=60, agenda=agenda)
|
|
meeting_type.save()
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 5, 9, 0)
|
|
assert events[1].timetuple()[:5] == (2016, 9, 5, 10, 0)
|
|
assert events[2].timetuple()[:5] == (2016, 9, 5, 11, 0)
|
|
assert events[3].timetuple()[:5] == (2016, 9, 12, 9, 0)
|
|
assert events[4].timetuple()[:5] == (2016, 9, 12, 10, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 26, 11, 0)
|
|
assert len(events) == 12
|
|
|
|
# another start before the timeperiod
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=1, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 6, 9, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 27, 11, 0)
|
|
assert len(events) == 12
|
|
|
|
# a start on the day of the timeperiod
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=3, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 1, 9, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 29, 11, 0)
|
|
assert len(events) == 15
|
|
|
|
# a start after the day of the timeperiod
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=4, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 2, 9, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 30, 11, 0)
|
|
assert len(events) == 15
|
|
|
|
# another start after the day of the timeperiod
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=5, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 3, 9, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 24, 11, 0)
|
|
assert len(events) == 12
|
|
|
|
# shorter duration -> double the events
|
|
meeting_type.duration = 30
|
|
meeting_type.save()
|
|
del agenda.__dict__['cached_meetingtypes']
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=5, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 3, 9, 0)
|
|
assert events[-1].timetuple()[:5] == (2016, 9, 24, 11, 30)
|
|
assert len(events) == 24
|
|
|
|
|
|
@override_settings(LANGUAGE_CODE='fr-fr')
|
|
def test_time_period_exception_as_string():
|
|
# single day
|
|
assert (
|
|
force_text(
|
|
TimePeriodException(
|
|
start_datetime=make_aware(datetime.datetime(2018, 1, 18)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 19)),
|
|
)
|
|
)
|
|
== u'18 jan. 2018'
|
|
)
|
|
|
|
# multiple full days
|
|
assert (
|
|
force_text(
|
|
TimePeriodException(
|
|
start_datetime=make_aware(datetime.datetime(2018, 1, 18)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 20)),
|
|
)
|
|
)
|
|
== u'18 jan. 2018 → 20 jan. 2018'
|
|
)
|
|
|
|
# a few hours in a day
|
|
assert (
|
|
force_text(
|
|
TimePeriodException(
|
|
start_datetime=make_aware(datetime.datetime(2018, 1, 18, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 18, 12, 0)),
|
|
)
|
|
)
|
|
== u'18 jan. 2018 10:00 → 12:00'
|
|
)
|
|
|
|
# multiple days and different times
|
|
assert (
|
|
force_text(
|
|
TimePeriodException(
|
|
start_datetime=make_aware(datetime.datetime(2018, 1, 18, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 20, 12, 0)),
|
|
)
|
|
)
|
|
== u'18 jan. 2018 10:00 → 20 jan. 2018 12:00'
|
|
)
|
|
|
|
|
|
def test_desk_opening_hours():
|
|
def set_prefetched_exceptions(desk):
|
|
desk.prefetched_exceptions = TimePeriodException.objects.filter(
|
|
Q(desk=desk) | Q(unavailability_calendar__desks=desk)
|
|
)
|
|
|
|
agenda = Agenda(label=u'Foo bar', slug='bar')
|
|
agenda.save()
|
|
desk = Desk.objects.create(label='Desk 1', agenda=agenda)
|
|
|
|
# nothing yet
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
assert len(hours) == 0
|
|
|
|
# morning
|
|
TimePeriod(desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save()
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
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(desk=desk, weekday=0, start_time=datetime.time(14, 0), end_time=datetime.time(17, 0)).save()
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
assert len(hours) == 2
|
|
assert hours[0].begin.time() == datetime.time(9, 0)
|
|
assert hours[0].end.time() == datetime.time(12, 0)
|
|
|
|
assert hours[1].begin.time() == datetime.time(14, 0)
|
|
assert hours[1].end.time() == datetime.time(17, 0)
|
|
|
|
# full day exception
|
|
exception = TimePeriodException(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2018, 1, 22)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 23)),
|
|
)
|
|
exception.save()
|
|
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
assert len(hours) == 0
|
|
|
|
# closed from 11am
|
|
exception.start_datetime = make_aware(datetime.datetime(2018, 1, 22, 11, 0))
|
|
exception.save()
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
assert len(hours) == 1
|
|
assert localtime(hours[0].begin).time() == datetime.time(9, 0)
|
|
assert localtime(hours[0].end).time() == datetime.time(11, 0)
|
|
|
|
# closed in the middle
|
|
exception.start_datetime = make_aware(datetime.datetime(2018, 1, 22, 10, 0))
|
|
exception.end_datetime = make_aware(datetime.datetime(2018, 1, 22, 11, 0))
|
|
exception.save()
|
|
set_prefetched_exceptions(desk)
|
|
hours = desk.get_opening_hours(datetime.date(2018, 1, 22))
|
|
assert len(hours) == 3
|
|
assert localtime(hours[0].begin).time() == datetime.time(9, 0)
|
|
assert localtime(hours[0].end).time() == datetime.time(10, 0)
|
|
|
|
assert localtime(hours[1].begin).time() == datetime.time(11, 0)
|
|
assert localtime(hours[1].end).time() == datetime.time(12, 0)
|
|
|
|
assert localtime(hours[2].begin).time() == datetime.time(14, 0)
|
|
assert localtime(hours[2].end).time() == datetime.time(17, 0)
|
|
|
|
|
|
def test_timeperiod_midnight_overlap_time_slots():
|
|
# https://dev.entrouvert.org/issues/29142
|
|
agenda = Agenda(label=u'Foo bar', slug='bar')
|
|
agenda.save()
|
|
desk = Desk.objects.create(label='Desk 1', agenda=agenda)
|
|
meeting_type = MeetingType(duration=120, agenda=agenda)
|
|
meeting_type.save()
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=0, start_time=datetime.time(21, 0), end_time=datetime.time(23, 0)
|
|
)
|
|
events = timeperiod.as_shared_timeperiods().get_time_slots(
|
|
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
|
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
|
meeting_duration=meeting_type.duration,
|
|
base_duration=agenda.get_base_meeting_duration(),
|
|
)
|
|
events = sorted(events)
|
|
assert events[0].timetuple()[:5] == (2016, 9, 5, 21, 0)
|
|
assert events[1].timetuple()[:5] == (2016, 9, 12, 21, 0)
|
|
assert events[2].timetuple()[:5] == (2016, 9, 19, 21, 0)
|
|
assert events[3].timetuple()[:5] == (2016, 9, 26, 21, 0)
|
|
assert len(events) == 4
|