0004-api-account-for-time-period-weekday-indexes-45159.patch
chrono/agendas/models.py | ||
---|---|---|
51 | 51 |
from django.utils.translation import ungettext |
52 | 52 | |
53 | 53 |
from chrono.interval import Interval, IntervalSet |
54 |
from chrono.utils.date import get_weekday_index |
|
54 | 55 |
from chrono.utils.publik_urls import translate_from_publik_url |
55 | 56 |
from chrono.utils.requests_wrapper import requests as requests_wrapper |
56 | 57 | |
... | ... | |
1148 | 1149 |
WEEKDAYS_LIST = sorted(WEEKDAYS.items(), key=lambda x: x[0]) |
1149 | 1150 | |
1150 | 1151 | |
1151 |
class WeekTime(collections.namedtuple('WeekTime', ['weekday', 'time'])): |
|
1152 |
class WeekTime(collections.namedtuple('WeekTime', ['weekday', 'weekday_indexes', 'time'])):
|
|
1152 | 1153 |
"""Representation of a time point in a weekday, ex.: Monday at 5 o'clock.""" |
1153 | 1154 | |
1154 | 1155 |
def __repr__(self): |
... | ... | |
1236 | 1237 | |
1237 | 1238 |
def as_weektime_interval(self): |
1238 | 1239 |
return Interval( |
1239 |
WeekTime(self.weekday, self.start_time), |
|
1240 |
WeekTime(self.weekday, self.end_time), |
|
1240 |
WeekTime(self.weekday, self.weekday_indexes, self.start_time),
|
|
1241 |
WeekTime(self.weekday, self.weekday_indexes, self.end_time),
|
|
1241 | 1242 |
) |
1242 | 1243 | |
1243 | 1244 |
def as_shared_timeperiods(self): |
1244 | 1245 |
return SharedTimePeriod( |
1245 | 1246 |
weekday=self.weekday, |
1247 |
weekday_indexes=self.weekday_indexes, |
|
1246 | 1248 |
start_time=self.start_time, |
1247 | 1249 |
end_time=self.end_time, |
1248 | 1250 |
desks=[self.desk], |
... | ... | |
1270 | 1272 |
of get_all_slots() for details). |
1271 | 1273 |
""" |
1272 | 1274 | |
1273 |
__slots__ = ['weekday', 'start_time', 'end_time', 'desks'] |
|
1275 |
__slots__ = ['weekday', 'weekday_indexes', 'start_time', 'end_time', 'desks']
|
|
1274 | 1276 | |
1275 |
def __init__(self, weekday, start_time, end_time, desks): |
|
1277 |
def __init__(self, weekday, weekday_indexes, start_time, end_time, desks):
|
|
1276 | 1278 |
self.weekday = weekday |
1279 |
self.weekday_indexes = weekday_indexes |
|
1277 | 1280 |
self.start_time = start_time |
1278 | 1281 |
self.end_time = end_time |
1279 | 1282 |
self.desks = set(desks) |
... | ... | |
1343 | 1346 |
while event_datetime < max_datetime: |
1344 | 1347 |
end_time = event_datetime + meeting_duration |
1345 | 1348 |
next_time = event_datetime + duration |
1346 |
if end_time.time() > self.end_time or event_datetime.date() != next_time.date(): |
|
1349 |
if ( |
|
1350 |
end_time.time() > self.end_time |
|
1351 |
or event_datetime.date() != next_time.date() |
|
1352 |
or (self.weekday_indexes and get_weekday_index(event_datetime) not in self.weekday_indexes) |
|
1353 |
): |
|
1347 | 1354 |
# switch to naive time for day/week changes |
1348 | 1355 |
event_datetime = make_naive(event_datetime) |
1349 | 1356 |
# back to morning |
... | ... | |
1352 | 1359 |
) |
1353 | 1360 |
# but next week |
1354 | 1361 |
event_datetime += datetime.timedelta(days=7) |
1362 | ||
1355 | 1363 |
# and re-align to timezone afterwards |
1356 | 1364 |
event_datetime = make_aware(event_datetime) |
1357 |
next_time = event_datetime + duration
|
|
1365 |
continue
|
|
1358 | 1366 | |
1359 | 1367 |
# don't end after max_datetime |
1360 | 1368 |
if event_datetime > max_datetime: |
... | ... | |
1366 | 1374 |
@classmethod |
1367 | 1375 |
def from_weektime_interval(cls, weektime_interval, desks=()): |
1368 | 1376 |
begin, end = weektime_interval |
1369 |
assert begin.weekday == end.weekday |
|
1377 |
assert begin.weekday == end.weekday and begin.weekday_indexes == end.weekday_indexes
|
|
1370 | 1378 |
return cls( |
1371 | 1379 |
weekday=begin.weekday, |
1380 |
weekday_indexes=begin.weekday_indexes, |
|
1372 | 1381 |
start_time=begin.time, |
1373 | 1382 |
end_time=end.time, |
1374 | 1383 |
desks=desks, |
tests/api/test_fillslot.py | ||
---|---|---|
889 | 889 |
assert resp.json['data'][event_index]['disabled'] |
890 | 890 | |
891 | 891 | |
892 |
@pytest.mark.freeze_time('2022-01-20 14:00') # Thursday |
|
893 |
def test_booking_api_meeting_weekday_indexes(app, user): |
|
894 |
agenda = Agenda.objects.create( |
|
895 |
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=60 |
|
896 |
) |
|
897 |
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30) |
|
898 |
desk = Desk.objects.create(agenda=agenda, label='desk') |
|
899 | ||
900 |
time_period = TimePeriod.objects.create( |
|
901 |
weekday=3, # Thursday |
|
902 |
weekday_indexes=[1, 3], |
|
903 |
start_time=datetime.time(11, 0), |
|
904 |
end_time=datetime.time(12, 0), |
|
905 |
desk=desk, |
|
906 |
) |
|
907 |
datetimes_resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)) |
|
908 |
slot = datetimes_resp.json['data'][0]['id'] |
|
909 |
assert slot == 'plop:2022-02-03-1100' |
|
910 | ||
911 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
912 | ||
913 |
# single booking |
|
914 |
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, slot)) |
|
915 |
assert Booking.objects.count() == 1 |
|
916 |
assert resp.json['duration'] == 30 |
|
917 | ||
918 |
# multiple slots |
|
919 |
slots = [datetimes_resp.json['data'][1]['id'], datetimes_resp.json['data'][2]['id']] |
|
920 |
assert slots == ['plop:2022-02-03-1130', 'plop:2022-02-17-1100'] |
|
921 |
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug, params={'slots': slots}) |
|
922 |
assert Booking.objects.count() == 3 |
|
923 | ||
924 |
# try to book slot on a skipped week |
|
925 |
slot = datetimes_resp.json['data'][3]['id'] |
|
926 |
time_period.weekday_indexes = [1] |
|
927 |
time_period.save() |
|
928 |
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)) |
|
929 |
assert slot not in {slot['id'] for slot in resp.json['data']} |
|
930 | ||
931 |
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, slot)) |
|
932 |
assert resp.json['err'] == 1 |
|
933 |
assert resp.json['err_desc'] == 'no more desk available' |
|
934 | ||
935 | ||
892 | 936 |
def test_booking_api_with_data(app, user): |
893 | 937 |
agenda = Agenda.objects.create(label='Foo bar', kind='events') |
894 | 938 |
event = Event.objects.create( |
tests/api/test_meetings_datetimes.py | ||
---|---|---|
2300 | 2300 |
assert ( |
2301 | 2301 |
False |
2302 | 2302 |
), 'slot should not appear due to maximal_booking_delay of the real agenda (and no maximal_booking_delay) is defined on the real agenda' |
2303 | ||
2304 | ||
2305 |
@pytest.mark.freeze_time('2022-01-20 14:00') # Thursday |
|
2306 |
def test_datetimes_api_meetings_agenda_weekday_indexes(app): |
|
2307 |
agenda = Agenda.objects.create( |
|
2308 |
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=60 |
|
2309 |
) |
|
2310 |
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30) |
|
2311 |
desk = Desk.objects.create(agenda=agenda, label='desk') |
|
2312 | ||
2313 |
time_period = TimePeriod.objects.create( |
|
2314 |
weekday=3, # Thursday |
|
2315 |
start_time=datetime.time(11, 0), |
|
2316 |
end_time=datetime.time(12, 0), |
|
2317 |
desk=desk, |
|
2318 |
) |
|
2319 |
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug) |
|
2320 | ||
2321 |
resp = app.get(api_url) |
|
2322 |
assert len(resp.json['data']) == 16 |
|
2323 |
assert [x['datetime'] for x in resp.json['data']][:6] == [ |
|
2324 |
'2022-01-27 11:00:00', |
|
2325 |
'2022-01-27 11:30:00', |
|
2326 |
'2022-02-03 11:00:00', |
|
2327 |
'2022-02-03 11:30:00', |
|
2328 |
'2022-02-10 11:00:00', |
|
2329 |
'2022-02-10 11:30:00', |
|
2330 |
] |
|
2331 |
every_weeks_resp = resp |
|
2332 | ||
2333 |
time_period.weekday_indexes = [1] |
|
2334 |
time_period.save() |
|
2335 |
resp = app.get(api_url) |
|
2336 |
assert len(resp.json['data']) == 4 |
|
2337 |
assert [x['datetime'] for x in resp.json['data']] == [ |
|
2338 |
'2022-02-03 11:00:00', |
|
2339 |
'2022-02-03 11:30:00', |
|
2340 |
'2022-03-03 11:00:00', |
|
2341 |
'2022-03-03 11:30:00', |
|
2342 |
] |
|
2343 | ||
2344 |
time_period.weekday_indexes = [1, 3] |
|
2345 |
time_period.save() |
|
2346 |
resp = app.get(api_url) |
|
2347 |
assert len(resp.json['data']) == 8 |
|
2348 |
assert [x['datetime'] for x in resp.json['data']] == [ |
|
2349 |
'2022-02-03 11:00:00', |
|
2350 |
'2022-02-03 11:30:00', |
|
2351 |
'2022-02-17 11:00:00', |
|
2352 |
'2022-02-17 11:30:00', |
|
2353 |
'2022-03-03 11:00:00', |
|
2354 |
'2022-03-03 11:30:00', |
|
2355 |
'2022-03-17 11:00:00', |
|
2356 |
'2022-03-17 11:30:00', |
|
2357 |
] |
|
2358 | ||
2359 |
time_period.weekday_indexes = [1, 2, 3, 4, 5] |
|
2360 |
time_period.save() |
|
2361 |
resp = app.get(api_url) |
|
2362 |
assert resp.json == every_weeks_resp.json |
|
2363 | ||
2364 |
# there are five Mondays this month |
|
2365 |
time_period.weekday = 0 |
|
2366 |
time_period.weekday_indexes = [5] |
|
2367 |
time_period.save() |
|
2368 |
resp = app.get(api_url) |
|
2369 |
assert len(resp.json['data']) == 2 |
|
2370 |
assert [x['datetime'] for x in resp.json['data']] == ['2022-01-31 11:00:00', '2022-01-31 11:30:00'] |
|
2303 |
- |