api: add 'max_places' argument to API (#89848)
gitea/chrono/pipeline/head This commit looks good Details

This commit is contained in:
Yann Weber 2024-04-22 10:49:11 +02:00
parent 88d8feacd8
commit ece23b6d89
4 changed files with 86 additions and 12 deletions

View File

@ -467,6 +467,7 @@ class DateRangeSerializer(DateRangeMixin, serializers.Serializer):
class DatetimesSerializer(DateRangeSerializer):
min_places = serializers.IntegerField(min_value=1, default=1)
max_places = serializers.IntegerField(min_value=0, default=0)
user_external_id = serializers.CharField(required=False, max_length=250, allow_blank=True)
exclude_user_external_id = serializers.CharField(required=False, max_length=250, allow_blank=True)
events = serializers.CharField(required=False, max_length=32, allow_blank=True)

View File

@ -149,6 +149,7 @@ def get_event_places(event):
def is_event_disabled(
event,
min_places=1,
max_places=0,
disable_booked=True,
bookable_events=None,
bypass_delays=False,
@ -170,7 +171,9 @@ def is_event_disabled(
):
# event is out of minimal delay and we don't want to bypass delays
return True
if event.remaining_places < min_places and event.remaining_waiting_list_places < min_places:
if 0 < max_places <= event.remaining_places:
return True
elif event.remaining_places < min_places and event.remaining_waiting_list_places < min_places:
if enable_full_when_booked and getattr(event, 'user_places_count', 0) > 0:
return False
return True
@ -210,6 +213,7 @@ def get_event_detail(
booking=None,
agenda=None,
min_places=1,
max_places=0,
booked_user_external_id=None,
bookable_events=None,
multiple_agendas=False,
@ -264,6 +268,7 @@ def get_event_detail(
'disabled': is_event_disabled(
event,
min_places=min_places,
max_places=max_places,
disable_booked=disable_booked,
bookable_events=bookable_events,
bypass_delays=bypass_delays,
@ -363,6 +368,7 @@ def get_events_meta_detail(
events,
agenda=None,
min_places=1,
max_places=0,
bookable_events=None,
multiple_agendas=False,
bypass_delays=False,
@ -373,7 +379,11 @@ def get_events_meta_detail(
for event in events:
bookable_datetimes_number_total += 1
if not is_event_disabled(
event, min_places=min_places, bookable_events=bookable_events, bypass_delays=bypass_delays
event,
min_places=min_places,
max_places=max_places,
bookable_events=bookable_events,
bypass_delays=bypass_delays,
):
bookable_datetimes_number_available += 1
if not first_bookable_slot:
@ -382,6 +392,7 @@ def get_events_meta_detail(
event,
agenda=agenda,
min_places=min_places,
max_places=max_places,
bookable_events=bookable_events,
multiple_agendas=multiple_agendas,
bypass_delays=bypass_delays,
@ -680,7 +691,8 @@ class Datetimes(APIView):
for e in entries
if not is_event_disabled(
e,
payload['min_places'],
min_places=payload['min_places'],
max_places=payload['max_places'],
disable_booked=disable_booked,
bookable_events=bookable_events,
bypass_delays=payload.get('bypass_delays'),
@ -694,6 +706,7 @@ class Datetimes(APIView):
x,
agenda=agenda,
min_places=payload['min_places'],
max_places=payload['max_places'],
booked_user_external_id=payload.get('user_external_id'),
bookable_events=bookable_events_raw,
disable_booked=disable_booked,
@ -706,6 +719,7 @@ class Datetimes(APIView):
entries,
agenda=agenda,
min_places=payload['min_places'],
max_places=payload['max_places'],
bookable_events=bookable_events_raw,
),
}
@ -803,6 +817,7 @@ class MultipleAgendasDatetimes(APIView):
request,
x,
min_places=payload['min_places'],
max_places=payload['max_places'],
booked_user_external_id=payload.get('user_external_id'),
multiple_agendas=True,
disable_booked=disable_booked,
@ -813,7 +828,11 @@ class MultipleAgendasDatetimes(APIView):
for x in entries
],
'meta': get_events_meta_detail(
request, entries, min_places=payload['min_places'], multiple_agendas=True
request,
entries,
min_places=payload['min_places'],
max_places=payload['max_places'],
multiple_agendas=True,
),
}
return Response(response)

View File

@ -198,7 +198,7 @@ def test_datetime_api_backoffice_url(app, admin_user):
assert event.label in app.get(url).text
def test_datetimes_api_min_places(app):
def test_datetimes_api_min_max_places(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(start_datetime=now() + datetime.timedelta(days=7), places=5, agenda=agenda)
@ -212,12 +212,30 @@ def test_datetimes_api_min_places(app):
resp = app.get('/api/agenda/%s/datetimes/?min_places=5' % agenda.slug)
assert resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?max_places=4' % agenda.slug)
assert resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?max_places=5' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?max_places=10&min_places=2' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?min_places=' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?max_places=' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?max_places=&min_places=' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?min_places=wrong' % agenda.slug, status=400)
assert resp.json['err'] == 1
resp = app.get('/api/agenda/%s/datetimes/?max_places=wrong' % agenda.slug, status=400)
assert resp.json['err'] == 1
def test_datetimes_api_(app):
events_type = EventsType.objects.create(
@ -634,6 +652,15 @@ def test_datetimes_api_meta(app, freezer):
'first_bookable_slot': resp.json['data'][1],
}
resp = app.get(api_url + '?max_places=15')
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 1,
'first_bookable_slot': resp.json['data'][0],
}
simulate_booking(events[0], 10)
resp = app.get(api_url)
assert len(resp.json['data']) == 3
@ -1161,30 +1188,43 @@ def test_past_datetimes_places(app, user):
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
def test_past_datetimes_min_places(app, user):
def test_past_datetimes_min_max_places(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=1,
places=10,
agenda=agenda,
)
Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=1,
places=10,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'min_places': 2})
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'min_places': 20})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'min_places': 2})
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'min_places': 20})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False # always available if past
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'max_places': 5})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'max_places': 5})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'

View File

@ -104,13 +104,27 @@ def test_datetimes_multiple_agendas(app):
assert 'booked_for_external_user' not in resp.json['data'][2]
assert resp.json['data'][2]['disabled'] is True
# check min_places
# check min_places & max_places
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['disabled'] is True
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'max_places': 3})
assert resp.json['data'][1]['disabled'] is True
assert resp.json['data'][2]['disabled'] is True
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'max_places': 4})
assert resp.json['data'][1]['disabled'] is True
assert resp.json['data'][2]['disabled'] is False
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'max_places': 10})
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['disabled'] is False
# check meta
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
resp = app.get(
'/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4, 'max_places': 10}
)
assert resp.json['meta']['bookable_datetimes_number_total'] == 5
assert resp.json['meta']['bookable_datetimes_number_available'] == 4
assert resp.json['meta']['first_bookable_slot'] == resp.json['data'][0]