Projet

Général

Profil

0002-api-fillslot-past-events-48397.patch

Lauréline Guérin, 04 juin 2021 10:51

Télécharger (13,4 ko)

Voir les différences:

Subject: [PATCH 2/2] api: fillslot & past events (#48397)

 chrono/api/views.py        |  55 +++++-----
 tests/api/test_fillslot.py | 200 +++++++++++++++++++++++++++++++++++++
 2 files changed, 232 insertions(+), 23 deletions(-)
chrono/api/views.py
951 951
    user_email = serializers.CharField(max_length=250, allow_blank=True)
952 952
    user_phone_number = serializers.CharField(max_length=16, allow_blank=True)
953 953
    exclude_user = serializers.BooleanField(default=False)
954
    events = serializers.CharField(max_length=16, allow_blank=True)
954 955
    form_url = serializers.CharField(max_length=250, allow_blank=True)
955 956
    backoffice_url = serializers.URLField(allow_blank=True)
956 957
    cancel_callback_url = serializers.URLField(allow_blank=True)
......
1086 1087
        color = None
1087 1088
        user_external_id = payload.get('user_external_id') or None
1088 1089
        exclude_user = payload.get('exclude_user')
1090
        book_events = payload.get('events') or 'future'
1091
        book_past = book_events in ['all', 'past']
1092
        book_future = book_events in ['all', 'future']
1089 1093

  
1090 1094
        if agenda.accept_meetings():
1091 1095
            # slots are actually timeslot ids (meeting_type:start_datetime), not events ids.
......
1241 1245
                events = agenda.event_set.filter(slug__in=slots).order_by('start_datetime')
1242 1246

  
1243 1247
            for event in events:
1244
                if not event.in_bookable_period():
1245
                    raise APIError(_('event not bookable'), err_class='event not bookable')
1248
                if event.start_datetime >= now():
1249
                    if not book_future or not event.in_bookable_period():
1250
                        raise APIError(_('event not bookable'), err_class='event not bookable')
1251
                else:
1252
                    if not book_past:
1253
                        raise APIError(_('event not bookable'), err_class='event not bookable')
1246 1254
                if event.cancelled:
1247 1255
                    raise APIError(_('event is cancelled'), err_class='event is cancelled')
1248 1256
                if exclude_user and user_external_id:
......
1261 1269
        # search free places. Switch to waiting list if necessary.
1262 1270
        in_waiting_list = False
1263 1271
        for event in events:
1264
            if payload.get('force_waiting_list') and not event.waiting_list_places:
1265
                raise APIError(
1266
                    _('no waiting list'),
1267
                    err_class='no waiting list',
1268
                )
1272
            if event.start_datetime > now():
1273
                if payload.get('force_waiting_list') and not event.waiting_list_places:
1274
                    raise APIError(
1275
                        _('no waiting list'),
1276
                        err_class='no waiting list',
1277
                    )
1269 1278

  
1270
            if event.waiting_list_places:
1271
                if (
1272
                    payload.get('force_waiting_list')
1273
                    or (event.booked_places + places_count) > event.places
1274
                    or event.waiting_list
1275
                ):
1276
                    # if this is full or there are people waiting, put new bookings
1277
                    # in the waiting list.
1278
                    in_waiting_list = True
1279
                    if (event.waiting_list + places_count) > event.waiting_list_places:
1279
                if event.waiting_list_places:
1280
                    if (
1281
                        payload.get('force_waiting_list')
1282
                        or (event.booked_places + places_count) > event.places
1283
                        or event.waiting_list
1284
                    ):
1285
                        # if this is full or there are people waiting, put new bookings
1286
                        # in the waiting list.
1287
                        in_waiting_list = True
1288
                        if (event.waiting_list + places_count) > event.waiting_list_places:
1289
                            raise APIError(
1290
                                _('sold out'),
1291
                                err_class='sold out',
1292
                            )
1293
                else:
1294
                    if (event.booked_places + places_count) > event.places:
1280 1295
                        raise APIError(
1281 1296
                            _('sold out'),
1282 1297
                            err_class='sold out',
1283 1298
                        )
1284
            else:
1285
                if (event.booked_places + places_count) > event.places:
1286
                    raise APIError(
1287
                        _('sold out'),
1288
                        err_class='sold out',
1289
                    )
1290 1299

  
1291 1300
        with transaction.atomic():
1292 1301
            if to_cancel_booking:
tests/api/test_fillslot.py
1890 1890
    ics = app.get(resp.json['api']['ics_url']).text
1891 1891
    assert 'DTSTART:20170519T231200Z' in ics
1892 1892
    assert 'DTEND:20170520T004200Z' in ics
1893

  
1894

  
1895
def test_fillslot_past_event(app, user):
1896
    app.authorization = ('Basic', ('john.doe', 'password'))
1897
    agenda = Agenda.objects.create(
1898
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
1899
    )
1900
    event1 = Event.objects.create(
1901
        label='Today before now',
1902
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
1903
        places=5,
1904
        agenda=agenda,
1905
    )
1906
    event2 = Event.objects.create(
1907
        label='Today after now',
1908
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
1909
        places=5,
1910
        agenda=agenda,
1911
    )
1912

  
1913
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event1.slug))
1914
    assert resp.json['err'] == 1
1915
    assert resp.json['err_desc'] == 'event not bookable'
1916

  
1917
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event1.slug), params={'events': 'future'})
1918
    assert resp.json['err'] == 1
1919
    assert resp.json['err_desc'] == 'event not bookable'
1920

  
1921
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event1.slug), params={'events': 'past'})
1922
    assert resp.json['err'] == 0
1923

  
1924
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event1.slug), params={'events': 'all'})
1925
    assert resp.json['err'] == 0
1926

  
1927
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event2.slug))
1928
    assert resp.json['err'] == 0
1929

  
1930
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event2.slug), params={'events': 'future'})
1931
    assert resp.json['err'] == 0
1932

  
1933
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event2.slug), params={'events': 'past'})
1934
    assert resp.json['err'] == 1
1935
    assert resp.json['err_desc'] == 'event not bookable'
1936

  
1937
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event2.slug), params={'events': 'all'})
1938
    assert resp.json['err'] == 0
1939

  
1940
    # check canceled
1941
    event1.cancel()
1942
    event2.cancel()
1943
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event1.slug), params={'events': 'all'})
1944
    assert resp.json['err'] == 1
1945
    assert resp.json['err_desc'] == 'event is cancelled'
1946
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event2.slug), params={'events': 'all'})
1947
    assert resp.json['err'] == 1
1948
    assert resp.json['err_desc'] == 'event is cancelled'
1949

  
1950

  
1951
def test_fillslot_past_event_places(app, user):
1952
    app.authorization = ('Basic', ('john.doe', 'password'))
1953
    agenda = Agenda.objects.create(
1954
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
1955
    )
1956
    event = Event.objects.create(
1957
        label='Today before now',
1958
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
1959
        places=1,
1960
        agenda=agenda,
1961
    )
1962
    Booking.objects.create(event=event)
1963

  
1964
    # always bookable if past
1965
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'events': 'past'})
1966
    assert resp.json['err'] == 0
1967

  
1968
    event.waiting_list_places = 1
1969
    event.save()
1970
    Booking.objects.create(event=event, in_waiting_list=True)
1971
    # always bookable if past
1972
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'events': 'past'})
1973
    assert resp.json['err'] == 0
1974

  
1975

  
1976
def test_fillslot_past_events_min_places(app, user):
1977
    app.authorization = ('Basic', ('john.doe', 'password'))
1978
    agenda = Agenda.objects.create(
1979
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
1980
    )
1981
    event = Event.objects.create(
1982
        label='Today before now',
1983
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
1984
        places=1,
1985
        agenda=agenda,
1986
    )
1987

  
1988
    # always bookable if past
1989
    resp = app.post(
1990
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'events': 'past', 'count': 2}
1991
    )
1992
    assert resp.json['err'] == 0
1993

  
1994

  
1995
def test_fillslot_past_events_exclude_slots(app, user):
1996
    app.authorization = ('Basic', ('john.doe', 'password'))
1997
    agenda = Agenda.objects.create(
1998
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
1999
    )
2000
    event = Event.objects.create(
2001
        label='Today before now',
2002
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
2003
        places=5,
2004
        agenda=agenda,
2005
    )
2006
    Booking.objects.create(event=event, user_external_id='42')
2007

  
2008
    resp = app.post(
2009
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug),
2010
        params={'events': 'past', 'user_external_id': '35', 'exclude_user': True},
2011
    )
2012
    assert resp.json['err'] == 0
2013
    resp = app.post(
2014
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug),
2015
        params={'events': 'past', 'user_external_id': '35', 'exclude_user': True},
2016
    )
2017
    assert resp.json['err'] == 1
2018
    assert resp.json['err_desc'] == 'event is already booked by user'
2019

  
2020

  
2021
def test_fillslot_past_events_recurring_event(app, user):
2022
    app.authorization = ('Basic', ('john.doe', 'password'))
2023
    agenda = Agenda.objects.create(
2024
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
2025
    )
2026
    event = Event.objects.create(
2027
        label='Recurring',
2028
        start_datetime=localtime(now() - datetime.timedelta(days=3 * 7)),
2029
        repeat='weekly',
2030
        places=5,
2031
        agenda=agenda,
2032
    )
2033

  
2034
    event_slug = '%s:%s' % (
2035
        event.slug,
2036
        (event.start_datetime - datetime.timedelta(days=7)).strftime('%Y-%m-%d-%H%M'),
2037
    )  # too soon
2038
    resp = app.post(
2039
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'all'}, status=400
2040
    )
2041
    assert resp.json['err'] == 1
2042
    assert resp.json['err_desc'] == 'invalid datetime for event %s' % event_slug
2043

  
2044
    event_slug = '%s:%s' % (
2045
        event.slug,
2046
        (event.start_datetime + datetime.timedelta(days=7)).strftime('%Y-%m-%d-%H%M'),
2047
    )
2048
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'past'})
2049
    assert resp.json['err'] == 0
2050
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'all'})
2051
    assert resp.json['err'] == 0
2052
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'future'})
2053
    assert resp.json['err'] == 1
2054
    assert resp.json['err_desc'] == 'event not bookable'
2055

  
2056
    event_slug = '%s:%s' % (
2057
        event.slug,
2058
        (event.start_datetime + datetime.timedelta(days=50 * 7)).strftime('%Y-%m-%d-%H%M'),
2059
    )  # too late
2060
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'all'})
2061
    assert resp.json['err'] == 1
2062
    assert resp.json['err_desc'] == 'event not bookable'
2063

  
2064
    event_slug = '%s:%s' % (
2065
        event.slug,
2066
        (event.start_datetime + datetime.timedelta(days=4 * 7)).strftime('%Y-%m-%d-%H%M'),
2067
    )
2068
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'past'})
2069
    assert resp.json['err'] == 1
2070
    assert resp.json['err_desc'] == 'event not bookable'
2071
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'all'})
2072
    assert resp.json['err'] == 0
2073
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event_slug), params={'events': 'future'})
2074
    assert resp.json['err'] == 0
2075

  
2076
    # check exclude_user_external_id
2077
    first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
2078
    Booking.objects.create(event=first_recurrence, user_external_id='42')
2079
    resp = app.post(
2080
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, first_recurrence.slug),
2081
        params={'events': 'past', 'user_external_id': '42', 'exclude_user': True},
2082
    )
2083
    assert resp.json['err'] == 1
2084
    assert resp.json['err_desc'] == 'event is already booked by user'
2085

  
2086
    # check canceled
2087
    first_recurrence.cancel()
2088
    resp = app.post(
2089
        '/api/agenda/%s/fillslot/%s/' % (agenda.slug, first_recurrence.slug), params={'events': 'past'}
2090
    )
2091
    assert resp.json['err'] == 1
2092
    assert resp.json['err_desc'] == 'event is cancelled'
1893
-