api: set request_uuid and previous_state on bookings (#83098)
gitea/chrono/pipeline/head This commit looks good Details

This commit is contained in:
Lauréline Guérin 2023-11-03 15:45:31 +01:00
parent 63a575f303
commit 3dac9ed0fb
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 66 additions and 5 deletions

View File

@ -459,7 +459,16 @@ def get_minutes_from_request(request):
return serializer.validated_data.get('minutes')
def make_booking(event, payload, extra_data, primary_booking=None, in_waiting_list=False, color=None):
def make_booking(
event,
payload,
extra_data,
primary_booking=None,
in_waiting_list=False,
color=None,
request_uuid=None,
previous_state=None,
):
out_of_min_delay = False
if event.agenda.min_booking_datetime and event.start_datetime < event.agenda.min_booking_datetime:
out_of_min_delay = True
@ -486,6 +495,8 @@ def make_booking(event, payload, extra_data, primary_booking=None, in_waiting_li
end_time=payload.get('end_time'),
extra_data=extra_data,
color=color,
request_uuid=request_uuid,
previous_state=previous_state,
)
@ -1873,6 +1884,7 @@ class EventsFillslots(APIView):
return self.fillslots(request)
def fillslots(self, request):
request_uuid = uuid.uuid4() if self.multiple_agendas else None
start_datetime, end_datetime = get_start_and_end_datetime_from_request(request)
serializer = self.serializer_class(
@ -1926,6 +1938,7 @@ class EventsFillslots(APIView):
booking__user_external_id=user_external_id,
booking__cancellation_datetime__isnull=False,
)
events_cancelled_to_delete_ids = events_cancelled_to_delete.values_list('pk', flat=True)
# book only events without active booking for the user
events = events.exclude(
@ -1949,7 +1962,18 @@ class EventsFillslots(APIView):
waiting_list_event_ids = [event.pk for event in events if event.in_waiting_list]
extra_data = get_extra_data(request, payload)
bookings = [make_booking(event, payload, extra_data) for event in events]
bookings = [
make_booking(
event,
payload,
extra_data,
request_uuid=request_uuid if self.multiple_agendas else None,
previous_state=None
if not self.multiple_agendas
else ('cancelled' if event.pk in events_cancelled_to_delete_ids else 'unbooked'),
)
for event in events
]
bookings_to_cancel_out_of_min_delay = Booking.objects.filter(
user_external_id=user_external_id,
@ -1969,6 +1993,8 @@ class EventsFillslots(APIView):
Booking.objects.filter(primary_booking__in=bookings_to_cancel_out_of_min_delay).update(
cancellation_datetime=cancellation_datetime,
out_of_min_delay=True,
request_uuid=request_uuid,
previous_state='booked' if self.multiple_agendas else None,
)
cancelled_events = [
get_short_event_detail(
@ -1982,7 +2008,10 @@ class EventsFillslots(APIView):
cancellation_datetime=cancellation_datetime, out_of_min_delay=True
)
Booking.objects.filter(primary_booking__in=bookings_to_cancel).update(
cancellation_datetime=cancellation_datetime, out_of_min_delay=False
cancellation_datetime=cancellation_datetime,
out_of_min_delay=False,
request_uuid=request_uuid,
previous_state='booked' if self.multiple_agendas else None,
)
cancelled_events += [
get_short_event_detail(
@ -1993,7 +2022,10 @@ class EventsFillslots(APIView):
for x in bookings_to_cancel
]
cancelled_count += bookings_to_cancel.update(
cancellation_datetime=cancellation_datetime, out_of_min_delay=False
cancellation_datetime=cancellation_datetime,
out_of_min_delay=False,
request_uuid=request_uuid,
previous_state='booked' if self.multiple_agendas else None,
)
# and delete outdated cancelled bookings
Booking.objects.filter(
@ -2029,6 +2061,10 @@ class EventsFillslots(APIView):
}
if not self.multiple_agendas:
response['bookings_ics_url'] += '&agenda=%s' % self.agenda.slug
if request_uuid:
response['revert_url'] = request.build_absolute_uri(
reverse('api-agendas-events-fillslots-revert', args=[request_uuid])
)
return Response(response)
def get_events(self, request, payload, start_datetime, end_datetime):

View File

@ -52,6 +52,7 @@ def test_api_events_fillslots(app, user):
resp.json['bookings_ics_url']
== 'http://testserver/api/bookings/ics/?user_external_id=user_id&agenda=foo-bar'
)
assert 'revert_url' not in resp.json
events = Event.objects.all()
assert events.filter(booked_places=1).count() == 2

View File

@ -164,7 +164,7 @@ def test_api_events_fillslots_multiple_agendas(app, user):
params = {'user_external_id': 'user_id', 'check_overlaps': True, 'slots': event_slugs}
with CaptureQueriesContext(connection) as ctx:
resp = app.post_json('/api/agendas/events/fillslots/?agendas=%s' % agenda_slugs, params=params)
assert len(ctx.captured_queries) == 17
assert len(ctx.captured_queries) == 18
assert resp.json['booking_count'] == 2
assert len(resp.json['booked_events']) == 2
assert resp.json['booked_events'][0]['id'] == 'first-agenda@event'
@ -180,6 +180,14 @@ def test_api_events_fillslots_multiple_agendas(app, user):
assert first_event.booking_set.filter(cancellation_datetime__isnull=True).count() == 1
assert second_event.booking_set.filter(cancellation_datetime__isnull=True).count() == 1
assert resp.json['bookings_ics_url'] == 'http://testserver/api/bookings/ics/?user_external_id=user_id'
request_uuid = first_event.booking_set.get().request_uuid
assert request_uuid is not None
assert second_event.booking_set.get().request_uuid == request_uuid
assert first_event.booking_set.get().previous_state == 'unbooked'
assert second_event.booking_set.get().previous_state == 'unbooked'
assert (
resp.json['revert_url'] == 'http://testserver/api/agendas/events/fillslots/%s/revert/' % request_uuid
)
# booking modification
params = {'user_external_id': 'user_id', 'slots': 'first-agenda@event'}
@ -189,6 +197,12 @@ def test_api_events_fillslots_multiple_agendas(app, user):
assert resp.json['cancelled_booking_count'] == 1
assert first_event.booking_set.filter(cancellation_datetime__isnull=True).count() == 1
assert second_event.booking_set.filter(cancellation_datetime__isnull=True).count() == 0
request_uuid = second_event.booking_set.get().request_uuid
assert request_uuid is not None
assert second_event.booking_set.get().previous_state == 'booked'
assert (
resp.json['revert_url'] == 'http://testserver/api/agendas/events/fillslots/%s/revert/' % request_uuid
)
params = {'user_external_id': 'user_id_2', 'slots': event_slugs}
resp = app.post_json('/api/agendas/events/fillslots/?agendas=%s' % agenda_slugs, params=params)
@ -332,6 +346,16 @@ def test_api_events_fillslots_multiple_agendas_with_cancelled(app, user):
)
assert Booking.objects.filter(user_external_id='user_id').count() == 3
assert Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True).count() == 3
new_booking_1 = Booking.objects.get(event__agenda=agenda_1, event=event_1, user_external_id='user_id')
request_uuid = new_booking_1.request_uuid
assert request_uuid is not None
booking_3 = Booking.objects.get(event__agenda=agenda_2, event=event_3, user_external_id='user_id')
assert booking_3.request_uuid == request_uuid
assert new_booking_1.previous_state == 'cancelled'
assert booking_3.previous_state == 'unbooked'
assert (
resp.json['revert_url'] == 'http://testserver/api/agendas/events/fillslots/%s/revert/' % request_uuid
)
assert Booking.objects.filter(pk=booking_1.pk).exists() is False # cancelled booking deleted
booking_2.refresh_from_db()