api: add date time period support in datetimes and fillslot (#70185)
This commit is contained in:
parent
bb148dc008
commit
f8e1888144
|
@ -542,43 +542,55 @@ class Agenda(models.Model):
|
||||||
self.reminder_settings.duplicate(agenda_target=new_agenda)
|
self.reminder_settings.duplicate(agenda_target=new_agenda)
|
||||||
return new_agenda
|
return new_agenda
|
||||||
|
|
||||||
def get_effective_time_periods(self):
|
def get_effective_time_periods(self, min_datetime=None, max_datetime=None):
|
||||||
"""Regroup timeperiods by desks.
|
"""Regroup timeperiods by desks.
|
||||||
|
|
||||||
List all timeperiods, timeperiods having the same begin_time and
|
List all timeperiods, timeperiods having the same begin_time and
|
||||||
end_time are regrouped in a SharedTimePeriod object, which has a
|
end_time are regrouped in a SharedTimePeriod object, which has a
|
||||||
list of desks instead of only one desk.
|
list of desks instead of only one desk.
|
||||||
"""
|
"""
|
||||||
|
min_date = min_datetime.date() if min_datetime else None
|
||||||
|
max_date = max_datetime.date() if max_datetime else None
|
||||||
if self.kind == 'virtual':
|
if self.kind == 'virtual':
|
||||||
return self.get_effective_time_periods_virtual()
|
return self.get_effective_time_periods_virtual(min_date, max_date)
|
||||||
elif self.kind == 'meetings':
|
elif self.kind == 'meetings':
|
||||||
return self.get_effective_time_periods_meetings()
|
return self.get_effective_time_periods_meetings(min_date, max_date)
|
||||||
else:
|
else:
|
||||||
raise ValueError('does not work with kind %r' % self.kind)
|
raise ValueError('does not work with kind %r' % self.kind)
|
||||||
|
|
||||||
def get_effective_time_periods_meetings(self):
|
def get_effective_time_periods_meetings(self, min_date, max_date):
|
||||||
"""List timeperiod instances for all desks of the agenda, convert them
|
"""List timeperiod instances for all desks of the agenda, convert them
|
||||||
into an Interval of WeekTime which can be compared and regrouped using
|
into an Interval of WeekTime which can be compared and regrouped using
|
||||||
itertools.groupby.
|
itertools.groupby.
|
||||||
"""
|
"""
|
||||||
|
time_periods = TimePeriod.objects.filter(desk__agenda=self)
|
||||||
|
if min_date:
|
||||||
|
time_periods.filter(Q(date__isnull=True) | Q(date__gte=min_date))
|
||||||
|
if max_date:
|
||||||
|
time_periods.filter(Q(date__isnull=True) | Q(date__lte=max_date))
|
||||||
|
|
||||||
yield from (
|
yield from (
|
||||||
SharedTimePeriod.from_weektime_interval(
|
SharedTimePeriod.from_weektime_interval(
|
||||||
weektime_interval,
|
weektime_interval,
|
||||||
desks=[time_period.desk for time_period in time_periods],
|
desks=[time_period.desk for time_period in time_periods],
|
||||||
)
|
)
|
||||||
for weektime_interval, time_periods in itertools.groupby(
|
for weektime_interval, time_periods in itertools.groupby(
|
||||||
TimePeriod.objects.filter(desk__agenda=self)
|
time_periods.prefetch_related('desk').order_by('weekday', 'start_time', 'end_time'),
|
||||||
.prefetch_related('desk')
|
|
||||||
.order_by('weekday', 'start_time', 'end_time'),
|
|
||||||
key=TimePeriod.as_weektime_interval,
|
key=TimePeriod.as_weektime_interval,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_effective_time_periods_virtual(self):
|
def get_effective_time_periods_virtual(self, min_date, max_date):
|
||||||
"""List timeperiod instances for all desks of all real agendas of this
|
"""List timeperiod instances for all desks of all real agendas of this
|
||||||
virtual agenda, convert them into an Interval of WeekTime which can be
|
virtual agenda, convert them into an Interval of WeekTime which can be
|
||||||
compared and regrouped using itertools.groupby.
|
compared and regrouped using itertools.groupby.
|
||||||
"""
|
"""
|
||||||
|
time_periods = TimePeriod.objects.filter(desk__agenda__virtual_agendas=self)
|
||||||
|
if min_date:
|
||||||
|
time_periods.filter(Q(date__isnull=True) | Q(date__gte=min_date))
|
||||||
|
if max_date:
|
||||||
|
time_periods.filter(Q(date__isnull=True) | Q(date__lte=max_date))
|
||||||
|
|
||||||
closed_hours_by_days = IntervalSet.from_ordered(
|
closed_hours_by_days = IntervalSet.from_ordered(
|
||||||
[
|
[
|
||||||
time_period.as_weektime_interval()
|
time_period.as_weektime_interval()
|
||||||
|
@ -586,9 +598,7 @@ class Agenda(models.Model):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
for time_period_interval, time_periods in itertools.groupby(
|
for time_period_interval, time_periods in itertools.groupby(
|
||||||
TimePeriod.objects.filter(desk__agenda__virtual_agendas=self)
|
time_periods.order_by('weekday', 'start_time', 'end_time').prefetch_related('desk'),
|
||||||
.order_by('weekday', 'start_time', 'end_time')
|
|
||||||
.prefetch_related('desk'),
|
|
||||||
key=lambda tp: tp.as_weektime_interval(),
|
key=lambda tp: tp.as_weektime_interval(),
|
||||||
):
|
):
|
||||||
time_periods = list(time_periods)
|
time_periods = list(time_periods)
|
||||||
|
@ -1091,14 +1101,17 @@ WEEKDAYS_LIST = sorted(WEEKDAYS.items(), key=lambda x: x[0])
|
||||||
class WeekTime(collections.namedtuple('WeekTime', ['weekday', 'time'])):
|
class WeekTime(collections.namedtuple('WeekTime', ['weekday', 'time'])):
|
||||||
"""Representation of a time point in a weekday, ex.: Monday at 5 o'clock."""
|
"""Representation of a time point in a weekday, ex.: Monday at 5 o'clock."""
|
||||||
|
|
||||||
def __new__(cls, weekday, weekday_indexes, time):
|
def __new__(cls, weekday, weekday_indexes, date, time):
|
||||||
|
if date:
|
||||||
|
weekday = date.weekday()
|
||||||
self = super().__new__(cls, weekday, time)
|
self = super().__new__(cls, weekday, time)
|
||||||
self.weekday_indexes = weekday_indexes
|
self.weekday_indexes = weekday_indexes
|
||||||
|
self.date = date
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s / %s' % (
|
return '%s / %s' % (
|
||||||
force_str(WEEKDAYS[self.weekday]),
|
self.date or force_str(WEEKDAYS[self.weekday]),
|
||||||
date_format(self.time, 'TIME_FORMAT'),
|
date_format(self.time, 'TIME_FORMAT'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1139,12 +1152,15 @@ class TimePeriod(models.Model):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
label = force_str(WEEKDAYS[self.weekday])
|
if self.date:
|
||||||
if self.weekday_indexes:
|
label = date_format(self.date, 'l d F Y')
|
||||||
label = _('%(weekday)s (%(ordinals)s of the month)') % {
|
else:
|
||||||
'weekday': label,
|
label = force_str(WEEKDAYS[self.weekday])
|
||||||
'ordinals': ', '.join(ordinal(i) for i in self.weekday_indexes),
|
if self.weekday_indexes:
|
||||||
}
|
label = _('%(weekday)s (%(ordinals)s of the month)') % {
|
||||||
|
'weekday': label,
|
||||||
|
'ordinals': ', '.join(ordinal(i) for i in self.weekday_indexes),
|
||||||
|
}
|
||||||
|
|
||||||
label = '%s / %s → %s' % (
|
label = '%s / %s → %s' % (
|
||||||
label,
|
label,
|
||||||
|
@ -1191,8 +1207,8 @@ class TimePeriod(models.Model):
|
||||||
|
|
||||||
def as_weektime_interval(self):
|
def as_weektime_interval(self):
|
||||||
return Interval(
|
return Interval(
|
||||||
WeekTime(self.weekday, self.weekday_indexes, self.start_time),
|
WeekTime(self.weekday, self.weekday_indexes, self.date, self.start_time),
|
||||||
WeekTime(self.weekday, self.weekday_indexes, self.end_time),
|
WeekTime(self.weekday, self.weekday_indexes, self.date, self.end_time),
|
||||||
)
|
)
|
||||||
|
|
||||||
def as_shared_timeperiods(self):
|
def as_shared_timeperiods(self):
|
||||||
|
@ -1201,6 +1217,7 @@ class TimePeriod(models.Model):
|
||||||
weekday_indexes=self.weekday_indexes,
|
weekday_indexes=self.weekday_indexes,
|
||||||
start_time=self.start_time,
|
start_time=self.start_time,
|
||||||
end_time=self.end_time,
|
end_time=self.end_time,
|
||||||
|
date=self.date,
|
||||||
desks=[self.desk],
|
desks=[self.desk],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1226,13 +1243,14 @@ class SharedTimePeriod:
|
||||||
of get_all_slots() for details).
|
of get_all_slots() for details).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['weekday', 'weekday_indexes', 'start_time', 'end_time', 'desks']
|
__slots__ = ['weekday', 'weekday_indexes', 'start_time', 'end_time', 'date', 'desks']
|
||||||
|
|
||||||
def __init__(self, weekday, weekday_indexes, start_time, end_time, desks):
|
def __init__(self, weekday, weekday_indexes, start_time, end_time, date, desks):
|
||||||
self.weekday = weekday
|
self.weekday = weekday
|
||||||
self.weekday_indexes = weekday_indexes
|
self.weekday_indexes = weekday_indexes
|
||||||
self.start_time = start_time
|
self.start_time = start_time
|
||||||
self.end_time = end_time
|
self.end_time = end_time
|
||||||
|
self.date = date
|
||||||
self.desks = set(desks)
|
self.desks = set(desks)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -1243,17 +1261,19 @@ class SharedTimePeriod:
|
||||||
)
|
)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.weekday, self.start_time, self.end_time) == (
|
return (self.weekday, self.start_time, self.end_time, self.date) == (
|
||||||
other.weekday,
|
other.weekday,
|
||||||
other.start_time,
|
other.start_time,
|
||||||
other.end_time,
|
other.end_time,
|
||||||
|
other.date,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return (self.weekday, self.start_time, self.end_time) < (
|
return (self.weekday, self.start_time, self.end_time, self.date) < (
|
||||||
other.weekday,
|
other.weekday,
|
||||||
other.start_time,
|
other.start_time,
|
||||||
other.end_time,
|
other.end_time,
|
||||||
|
other.date,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_time_slots(self, min_datetime, max_datetime, meeting_duration, base_duration):
|
def get_time_slots(self, min_datetime, max_datetime, meeting_duration, base_duration):
|
||||||
|
@ -1278,10 +1298,17 @@ class SharedTimePeriod:
|
||||||
Generated start_datetime MUST be in the local timezone, and the local
|
Generated start_datetime MUST be in the local timezone, and the local
|
||||||
timezone must not change, as the API needs it to generate stable ids.
|
timezone must not change, as the API needs it to generate stable ids.
|
||||||
"""
|
"""
|
||||||
|
if self.date and not (min_datetime.date() <= self.date <= max_datetime.date()):
|
||||||
|
return
|
||||||
|
|
||||||
meeting_duration = datetime.timedelta(minutes=meeting_duration)
|
meeting_duration = datetime.timedelta(minutes=meeting_duration)
|
||||||
duration = datetime.timedelta(minutes=base_duration)
|
duration = datetime.timedelta(minutes=base_duration)
|
||||||
|
|
||||||
real_min_datetime = min_datetime + datetime.timedelta(days=self.weekday - min_datetime.weekday())
|
real_min_datetime = (
|
||||||
|
min_datetime + datetime.timedelta(days=self.weekday - min_datetime.weekday())
|
||||||
|
if not self.date
|
||||||
|
else min_datetime
|
||||||
|
)
|
||||||
if real_min_datetime < min_datetime:
|
if real_min_datetime < min_datetime:
|
||||||
real_min_datetime += datetime.timedelta(days=7)
|
real_min_datetime += datetime.timedelta(days=7)
|
||||||
|
|
||||||
|
@ -1293,6 +1320,10 @@ class SharedTimePeriod:
|
||||||
event_datetime = make_aware(make_naive(real_min_datetime)).replace(
|
event_datetime = make_aware(make_naive(real_min_datetime)).replace(
|
||||||
hour=self.start_time.hour, minute=self.start_time.minute, second=0, microsecond=0
|
hour=self.start_time.hour, minute=self.start_time.minute, second=0, microsecond=0
|
||||||
)
|
)
|
||||||
|
if self.date:
|
||||||
|
event_datetime = event_datetime.replace(
|
||||||
|
day=self.date.day, month=self.date.month, year=self.date.year
|
||||||
|
)
|
||||||
# don't start before min_datetime
|
# don't start before min_datetime
|
||||||
event_datetime = max(event_datetime, min_datetime)
|
event_datetime = max(event_datetime, min_datetime)
|
||||||
|
|
||||||
|
@ -1305,6 +1336,10 @@ class SharedTimePeriod:
|
||||||
or event_datetime.date() != next_time.date()
|
or event_datetime.date() != next_time.date()
|
||||||
or (self.weekday_indexes and get_weekday_index(event_datetime) not in self.weekday_indexes)
|
or (self.weekday_indexes and get_weekday_index(event_datetime) not in self.weekday_indexes)
|
||||||
):
|
):
|
||||||
|
# if time slot is not repeating, end now
|
||||||
|
if self.date:
|
||||||
|
break
|
||||||
|
|
||||||
# switch to naive time for day/week changes
|
# switch to naive time for day/week changes
|
||||||
event_datetime = make_naive(event_datetime)
|
event_datetime = make_naive(event_datetime)
|
||||||
# back to morning
|
# back to morning
|
||||||
|
@ -1335,6 +1370,7 @@ class SharedTimePeriod:
|
||||||
weekday_indexes=begin.weekday_indexes or end.weekday_indexes,
|
weekday_indexes=begin.weekday_indexes or end.weekday_indexes,
|
||||||
start_time=begin.time,
|
start_time=begin.time,
|
||||||
end_time=end.time,
|
end_time=end.time,
|
||||||
|
date=begin.date or end.date,
|
||||||
desks=desks,
|
desks=desks,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ def get_all_slots(
|
||||||
)
|
)
|
||||||
|
|
||||||
unique_booked = {}
|
unique_booked = {}
|
||||||
for time_period in base_agenda.get_effective_time_periods():
|
for time_period in base_agenda.get_effective_time_periods(base_min_datetime, base_max_datetime):
|
||||||
duration = (
|
duration = (
|
||||||
datetime.datetime.combine(base_date, time_period.end_time)
|
datetime.datetime.combine(base_date, time_period.end_time)
|
||||||
- datetime.datetime.combine(base_date, time_period.start_time)
|
- datetime.datetime.combine(base_date, time_period.start_time)
|
||||||
|
|
|
@ -2426,3 +2426,91 @@ def test_datetimes_api_meetings_virtual_agenda_weekday_indexes(app):
|
||||||
'2022-03-07 11:30:00',
|
'2022-03-07 11:30:00',
|
||||||
'2022-03-14 11:30:00',
|
'2022-03-14 11:30:00',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.freeze_time('2022-10-24 10:00')
|
||||||
|
def test_datetimes_api_meetings_agenda_date_time_period(app):
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=8
|
||||||
|
)
|
||||||
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
||||||
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
||||||
|
|
||||||
|
TimePeriod.objects.create(
|
||||||
|
date=datetime.date(2022, 10, 24),
|
||||||
|
start_time=datetime.time(12, 0),
|
||||||
|
end_time=datetime.time(14, 0),
|
||||||
|
desk=desk,
|
||||||
|
)
|
||||||
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
||||||
|
|
||||||
|
resp = app.get(api_url)
|
||||||
|
assert [x['datetime'] for x in resp.json['data']] == [
|
||||||
|
'2022-10-24 12:00:00',
|
||||||
|
'2022-10-24 12:30:00',
|
||||||
|
'2022-10-24 13:00:00',
|
||||||
|
'2022-10-24 13:30:00',
|
||||||
|
]
|
||||||
|
|
||||||
|
resp = app.get(api_url, params={'date_start': '2022-10-25'})
|
||||||
|
assert resp.json['data'] == []
|
||||||
|
|
||||||
|
# mix with repeating period
|
||||||
|
TimePeriod.objects.create(
|
||||||
|
weekday=0,
|
||||||
|
start_time=datetime.time(13, 0),
|
||||||
|
end_time=datetime.time(15, 0),
|
||||||
|
desk=desk,
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = app.get(api_url)
|
||||||
|
assert [x['datetime'] for x in resp.json['data']] == [
|
||||||
|
'2022-10-24 12:00:00',
|
||||||
|
'2022-10-24 12:30:00',
|
||||||
|
'2022-10-24 13:00:00',
|
||||||
|
'2022-10-24 13:30:00',
|
||||||
|
'2022-10-24 14:00:00',
|
||||||
|
'2022-10-24 14:30:00',
|
||||||
|
'2022-10-31 13:00:00',
|
||||||
|
'2022-10-31 13:30:00',
|
||||||
|
'2022-10-31 14:00:00',
|
||||||
|
'2022-10-31 14:30:00',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.freeze_time('2022-10-24 10:00')
|
||||||
|
def test_datetimes_api_meetings_virtual_agenda_date_time_period(app):
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=8
|
||||||
|
)
|
||||||
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
||||||
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
||||||
|
virtual_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='virtual')
|
||||||
|
virtual_agenda.real_agendas.add(agenda)
|
||||||
|
|
||||||
|
TimePeriod.objects.create(
|
||||||
|
date=datetime.date(2022, 10, 24),
|
||||||
|
start_time=datetime.time(12, 0),
|
||||||
|
end_time=datetime.time(14, 0),
|
||||||
|
desk=desk,
|
||||||
|
)
|
||||||
|
|
||||||
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
||||||
|
resp = app.get(api_url)
|
||||||
|
assert [x['datetime'] for x in resp.json['data']] == [
|
||||||
|
'2022-10-24 12:00:00',
|
||||||
|
'2022-10-24 12:30:00',
|
||||||
|
'2022-10-24 13:00:00',
|
||||||
|
'2022-10-24 13:30:00',
|
||||||
|
]
|
||||||
|
|
||||||
|
# add exclusion period on virtual agenda
|
||||||
|
TimePeriod.objects.create(
|
||||||
|
weekday=0, start_time=datetime.time(12, 00), end_time=datetime.time(13, 00), agenda=virtual_agenda
|
||||||
|
)
|
||||||
|
resp = app.get(api_url)
|
||||||
|
resp = app.get(api_url)
|
||||||
|
assert [x['datetime'] for x in resp.json['data']] == [
|
||||||
|
'2022-10-24 13:00:00',
|
||||||
|
'2022-10-24 13:30:00',
|
||||||
|
]
|
||||||
|
|
|
@ -995,6 +995,42 @@ def test_booking_api_with_data(app, user):
|
||||||
assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
|
assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.freeze_time('2022-10-24 10:00')
|
||||||
|
def test_booking_api_meeting_date_time_period(app, user):
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=8
|
||||||
|
)
|
||||||
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
||||||
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
||||||
|
|
||||||
|
TimePeriod.objects.create(
|
||||||
|
date=datetime.date(2022, 10, 24),
|
||||||
|
start_time=datetime.time(12, 0),
|
||||||
|
end_time=datetime.time(14, 0),
|
||||||
|
desk=desk,
|
||||||
|
)
|
||||||
|
datetimes_resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug))
|
||||||
|
slot = datetimes_resp.json['data'][0]['id']
|
||||||
|
assert slot == 'plop:2022-10-24-1200'
|
||||||
|
|
||||||
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||||
|
|
||||||
|
# single booking
|
||||||
|
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, slot))
|
||||||
|
assert Booking.objects.count() == 1
|
||||||
|
assert resp.json['duration'] == 30
|
||||||
|
|
||||||
|
# multiple slots
|
||||||
|
slots = [datetimes_resp.json['data'][1]['id'], datetimes_resp.json['data'][2]['id']]
|
||||||
|
assert slots == ['plop:2022-10-24-1230', 'plop:2022-10-24-1300']
|
||||||
|
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug, params={'slots': slots})
|
||||||
|
assert Booking.objects.count() == 3
|
||||||
|
|
||||||
|
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, slot))
|
||||||
|
assert resp.json['err'] == 1
|
||||||
|
assert resp.json['err_desc'] == 'no more desk available'
|
||||||
|
|
||||||
|
|
||||||
def test_booking_api_available(app, user):
|
def test_booking_api_available(app, user):
|
||||||
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
||||||
for i in range(0, 10):
|
for i in range(0, 10):
|
||||||
|
|
|
@ -491,3 +491,28 @@ def test_time_period_check_constraint():
|
||||||
start_time=datetime.time(hour=1, minute=0),
|
start_time=datetime.time(hour=1, minute=0),
|
||||||
end_time=datetime.time(hour=2, minute=0),
|
end_time=datetime.time(hour=2, minute=0),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_timeperiod_date_time_slots():
|
||||||
|
agenda = Agenda(label='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,
|
||||||
|
date=datetime.date(2022, 10, 24),
|
||||||
|
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(2022, 10, 1)),
|
||||||
|
max_datetime=make_aware(datetime.datetime(2022, 11, 1)),
|
||||||
|
meeting_duration=meeting_type.duration,
|
||||||
|
base_duration=agenda.get_base_meeting_duration(),
|
||||||
|
)
|
||||||
|
assert [x.timetuple()[:5] for x in sorted(events)] == [
|
||||||
|
(2022, 10, 24, 9, 0),
|
||||||
|
(2022, 10, 24, 10, 0),
|
||||||
|
(2022, 10, 24, 11, 0),
|
||||||
|
]
|
||||||
|
|
Loading…
Reference in New Issue