api: allow changing multiple event bookings (#55368)
This commit is contained in:
parent
21fa37d374
commit
92d209ed11
|
@ -1646,6 +1646,8 @@ class EventsFillslots(APIView):
|
|||
|
||||
def post(self, request, agenda_identifier):
|
||||
agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
|
||||
start_datetime, end_datetime = get_start_and_end_datetime_from_request(request)
|
||||
|
||||
serializer = self.serializer_class(data=request.data, partial=True)
|
||||
if not serializer.is_valid():
|
||||
raise APIError(
|
||||
|
@ -1655,10 +1657,20 @@ class EventsFillslots(APIView):
|
|||
http_status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
payload = serializer.validated_data
|
||||
user_external_id = payload['user_external_id']
|
||||
|
||||
events = get_events_from_slots(payload['slots'], request, agenda, payload)
|
||||
events = Event.annotate_queryset(events)
|
||||
|
||||
already_booked_events = agenda.event_set.filter(booking__user_external_id=user_external_id)
|
||||
if start_datetime:
|
||||
already_booked_events = already_booked_events.filter(start_datetime__gte=start_datetime)
|
||||
if end_datetime:
|
||||
already_booked_events = already_booked_events.filter(start_datetime__lt=end_datetime)
|
||||
|
||||
events_to_unbook = list(already_booked_events.exclude(pk__in=events).values_list('pk', flat=True))
|
||||
events = events.exclude(booking__user_external_id=user_external_id)
|
||||
|
||||
full_events = [str(event) for event in events.filter(full=True)]
|
||||
if full_events:
|
||||
raise APIError(
|
||||
|
@ -1676,9 +1688,15 @@ class EventsFillslots(APIView):
|
|||
extra_data = {k: v for k, v in request.data.items() if k not in payload}
|
||||
bookings = [make_booking(event, payload, extra_data) for event in events]
|
||||
|
||||
events_to_update = Event.annotate_queryset(
|
||||
agenda.event_set.filter(pk__in=events_to_unbook + [event.pk for event in events])
|
||||
)
|
||||
with transaction.atomic():
|
||||
deleted_count = Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_to_unbook
|
||||
).delete()[0]
|
||||
Booking.objects.bulk_create(bookings)
|
||||
events.update(
|
||||
events_to_update.update(
|
||||
full=Q(booked_places_count__gte=F('places'), waiting_list_places=0)
|
||||
| Q(waiting_list_places__gt=0, waiting_list_count__gte=F('waiting_list_places')),
|
||||
almost_full=Q(booked_places_count__gte=0.9 * F('places')),
|
||||
|
@ -1688,6 +1706,7 @@ class EventsFillslots(APIView):
|
|||
'err': 0,
|
||||
'booking_count': len(bookings),
|
||||
'waiting_list_events': [get_event_detail(request, x, agenda=agenda) for x in waiting_list_events],
|
||||
'cancelled_booking_count': deleted_count,
|
||||
}
|
||||
return Response(response)
|
||||
|
||||
|
|
|
@ -2239,6 +2239,9 @@ def test_api_events_fillslots(app, user):
|
|||
second_event = Event.objects.create(
|
||||
label='Event 2', start_datetime=now() + datetime.timedelta(days=2), places=2, agenda=agenda
|
||||
)
|
||||
third_event = Event.objects.create(
|
||||
label='Event 3', start_datetime=now() + datetime.timedelta(days=3), places=2, agenda=agenda
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
|
||||
|
@ -2250,10 +2253,12 @@ def test_api_events_fillslots(app, user):
|
|||
events = Event.annotate_queryset(Event.objects.all())
|
||||
assert events.filter(booked_places_count=1).count() == 2
|
||||
|
||||
params['user_external_id'] = 'user_id_2'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 2
|
||||
assert len(resp.json['waiting_list_events']) == 0
|
||||
|
||||
params['user_external_id'] = 'user_id_3'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'some events are full: Event 2'
|
||||
|
@ -2264,6 +2269,37 @@ def test_api_events_fillslots(app, user):
|
|||
assert resp.json['waiting_list_events'][0]['slug'] == event.slug
|
||||
assert Booking.objects.filter(in_waiting_list=True, event=event).count() == 1
|
||||
|
||||
# change bookings
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event-2,event-3'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 1
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
|
||||
user_bookings = Booking.objects.filter(user_external_id='user_id')
|
||||
assert {b.event.slug for b in user_bookings} == {'event-2', 'event-3'}
|
||||
assert event.booking_set.count() == 2
|
||||
assert second_event.booking_set.count() == 2
|
||||
assert third_event.booking_set.count() == 1
|
||||
|
||||
# increase waiting_list_places to make "Event" bookable again
|
||||
event.waiting_list_places = 2
|
||||
event.save()
|
||||
|
||||
# specify time range so that "Event 3" is not cancelled
|
||||
params['slots'] = 'event,event-2'
|
||||
resp = app.post_json(fillslots_url + '?date_start=2021-09-06&date_end=2021-09-09', params=params)
|
||||
assert resp.json['booking_count'] == 1
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
|
||||
user_bookings = Booking.objects.filter(user_external_id='user_id')
|
||||
assert {b.event.slug for b in user_bookings} == {'event', 'event-2', 'event-3'}
|
||||
assert event.booking_set.count() == 3
|
||||
assert second_event.booking_set.count() == 2
|
||||
assert third_event.booking_set.count() == 1
|
||||
|
||||
# new event booking went in waiting list despite free slots on main list
|
||||
assert Booking.objects.filter(in_waiting_list=True, event=event).count() == 2
|
||||
|
||||
resp = app.post('/api/agenda/foobar/events/fillslots/', status=404)
|
||||
resp = app.post('/api/agenda/0/events/fillslots/', status=404)
|
||||
|
||||
|
|
Loading…
Reference in New Issue