api: revert endpoint (#83098)

This commit is contained in:
Lauréline Guérin 2023-11-03 14:47:56 +01:00
parent 678ac6c1de
commit 63a575f303
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 382 additions and 0 deletions

View File

@ -38,6 +38,11 @@ urlpatterns = [
views.agendas_events_fillslots,
name='api-agendas-events-fillslots',
),
path(
'agendas/events/fillslots/<uuid:request_uuid>/revert/',
views.agendas_events_fillslots_revert,
name='api-agendas-events-fillslots-revert',
),
path(
'agendas/events/check-status/',
views.agendas_events_check_status,

View File

@ -2131,6 +2131,74 @@ class MultipleAgendasEventsFillslots(EventsFillslots):
agendas_events_fillslots = MultipleAgendasEventsFillslots.as_view()
class MultipleAgendasEventsFillslotsRevert(APIView):
permission_classes = (permissions.IsAuthenticated,)
def post(self, request, request_uuid):
bookings = Booking.objects.filter(request_uuid=request_uuid)
bookings_to_cancel = []
bookings_to_book = []
bookings_to_delete = []
for booking in bookings:
if booking.previous_state == 'unbooked':
bookings_to_delete.append(booking)
if booking.previous_state == 'booked':
bookings_to_book.append(booking)
if booking.previous_state == 'cancelled':
bookings_to_cancel.append(booking)
events = Event.objects.filter(
pk__in=[b.event_id for b in bookings_to_cancel + bookings_to_book + bookings_to_delete]
).prefetch_related('agenda')
events_by_id = {x.id: x for x in events}
with transaction.atomic():
cancellation_datetime = now()
cancelled_events = [
get_short_event_detail(
request,
events_by_id[x.event_id],
multiple_agendas=True,
)
for x in bookings_to_cancel
]
cancelled_count = Booking.objects.filter(pk__in=[b.pk for b in bookings_to_cancel]).update(
cancellation_datetime=cancellation_datetime
)
booked_events = [
get_short_event_detail(
request,
events_by_id[x.event_id],
multiple_agendas=True,
)
for x in bookings_to_book
]
booked_count = Booking.objects.filter(pk__in=[b.pk for b in bookings_to_book]).update(
cancellation_datetime=None
)
deleted_events = [
get_short_event_detail(
request,
events_by_id[x.event_id],
multiple_agendas=True,
)
for x in bookings_to_delete
]
deleted_count = Booking.objects.filter(pk__in=[b.pk for b in bookings_to_delete]).delete()[0]
response = {
'err': 0,
'cancelled_booking_count': cancelled_count,
'cancelled_events': cancelled_events,
'booked_booking_count': booked_count,
'booked_events': booked_events,
'deleted_booking_count': deleted_count,
'deleted_events': deleted_events,
}
return Response(response)
agendas_events_fillslots_revert = MultipleAgendasEventsFillslotsRevert.as_view()
class MultipleAgendasEvents(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = serializers.SlotsSerializer

View File

@ -1,4 +1,5 @@
import datetime
import uuid
import pytest
from django.db import connection
@ -829,3 +830,311 @@ def test_api_events_fillslots_multiple_agendas_partial_bookings(app, user):
resp.json['errors']['non_field_errors'][0]
== 'must include start_time and end_time for partial bookings agenda'
)
@pytest.mark.freeze_time('2021-02-23 14:00')
def test_api_events_fillslots_multiple_agendas_revert(app, user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(
label='Event',
start_datetime=now() + datetime.timedelta(days=5),
duration=120,
places=1,
agenda=agenda,
)
app.authorization = ('Basic', ('john.doe', 'password'))
request_uuid = uuid.uuid4()
# no corresponding booking
revert_url = '/api/agendas/events/fillslots/%s/revert/' % request_uuid
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 0,
'booked_events': [],
}
booking1 = Booking.objects.create(event=event, request_uuid=uuid.uuid4())
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2 = Booking.objects.create(event=event, request_uuid=request_uuid)
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
# booking was previously cancelled
booking = Booking.objects.create(event=event, request_uuid=request_uuid, previous_state='cancelled')
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 1,
'cancelled_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
booking.refresh_from_db()
assert booking.cancellation_datetime is not None
# again, but with a cancelled booking
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 1,
'cancelled_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
booking.refresh_from_db()
assert booking.cancellation_datetime is not None
# booking was previously not cancelled
booking.previous_state = 'booked'
booking.save()
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 1,
'booked_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
booking.refresh_from_db()
assert booking.cancellation_datetime is None
# again, but with a not cancelled booking
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 0,
'deleted_events': [],
'booked_booking_count': 1,
'booked_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
booking.refresh_from_db()
assert booking.cancellation_datetime is None
# booking was previously unbooked
booking.previous_state = 'unbooked'
booking.save()
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 1,
'deleted_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
assert Booking.objects.filter(pk=booking.pk).exists() is False
# again, but with a cancelled booking
booking = Booking.objects.create(
event=event, request_uuid=request_uuid, previous_state='unbooked', cancellation_datetime=now()
)
resp = app.post(revert_url)
assert resp.json == {
'err': 0,
'cancelled_booking_count': 0,
'cancelled_events': [],
'deleted_booking_count': 1,
'deleted_events': [
{
'agenda_label': 'Foo bar',
'check_locked': False,
'checked': False,
'date': '2021-02-28',
'datetime': '2021-02-28 15:00:00',
'description': None,
'duration': 120,
'end_datetime': '2021-02-28 17:00:00',
'id': 'foo-bar@event',
'invoiced': False,
'label': 'Event',
'pricing': None,
'slug': 'event',
'text': 'Event',
'url': None,
}
],
'booked_booking_count': 0,
'booked_events': [],
}
booking1.refresh_from_db()
assert booking1.cancellation_datetime is None
booking2.refresh_from_db()
assert booking2.cancellation_datetime is None
assert Booking.objects.filter(pk=booking.pk).exists() is False
# check num queries
Booking.objects.create(
event=event, request_uuid=request_uuid, previous_state='cancelled', cancellation_datetime=now()
)
event = Event.objects.create(
label='Event',
start_datetime=now() + datetime.timedelta(days=5),
duration=120,
places=1,
agenda=agenda,
)
Booking.objects.create(
event=event, request_uuid=request_uuid, previous_state='booked', cancellation_datetime=now()
)
event = Event.objects.create(
label='Event',
start_datetime=now() + datetime.timedelta(days=5),
duration=120,
places=1,
agenda=agenda,
)
Booking.objects.create(
event=event, request_uuid=request_uuid, previous_state='unbooked', cancellation_datetime=now()
)
with CaptureQueriesContext(connection) as ctx:
resp = app.post(revert_url)
assert len(ctx.captured_queries) == 13