Projet

Général

Profil

0004-api-account-for-time-period-weekday-indexes-45159.patch

Valentin Deniaud, 10 mars 2022 16:02

Télécharger (9,23 ko)

Voir les différences:

Subject: [PATCH 4/5] api: account for time period weekday indexes (#45159)

 chrono/agendas/models.py             | 25 ++++++----
 tests/api/test_fillslot.py           | 44 ++++++++++++++++++
 tests/api/test_meetings_datetimes.py | 68 ++++++++++++++++++++++++++++
 3 files changed, 129 insertions(+), 8 deletions(-)
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
-