api: cancel booking in events fillslots - instead of delete (#61066)
This commit is contained in:
parent
f65717725b
commit
b61a867667
|
@ -1788,7 +1788,7 @@ class EventsFillslots(APIView):
|
|||
if end_datetime:
|
||||
already_booked_events = already_booked_events.filter(start_datetime__lt=end_datetime)
|
||||
agendas_by_ids = self.get_agendas_by_ids()
|
||||
events_to_unbook_ids = []
|
||||
events_to_unbook = []
|
||||
events_in_request_ids = [e.pk for e in events]
|
||||
for event in already_booked_events:
|
||||
if event.pk in events_in_request_ids:
|
||||
|
@ -1802,9 +1802,19 @@ class EventsFillslots(APIView):
|
|||
continue
|
||||
if agenda.max_booking_datetime and event.start_datetime > agenda.max_booking_datetime:
|
||||
continue
|
||||
events_to_unbook_ids.append(event.pk)
|
||||
events_to_unbook.append(event)
|
||||
|
||||
events = events.exclude(booking__user_external_id=user_external_id)
|
||||
# outdated bookings to remove (cancelled bookings to replace by an active booking)
|
||||
events_cancelled_to_delete = events.filter(
|
||||
booking__user_external_id=user_external_id,
|
||||
booking__cancellation_datetime__isnull=False,
|
||||
)
|
||||
# book only events without active booking for the user
|
||||
events = events.exclude(
|
||||
pk__in=Booking.objects.filter(
|
||||
event__in=events, user_external_id=user_external_id, cancellation_datetime__isnull=True
|
||||
).values('event')
|
||||
)
|
||||
|
||||
full_events = [str(event) for event in events.filter(full=True)]
|
||||
if full_events:
|
||||
|
@ -1823,10 +1833,22 @@ 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]
|
||||
|
||||
bookings_to_cancel = Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_to_unbook, cancellation_datetime__isnull=True
|
||||
)
|
||||
|
||||
with transaction.atomic():
|
||||
deleted_count = Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_to_unbook_ids
|
||||
).delete()[0]
|
||||
# cancel existing bookings
|
||||
cancellation_datetime = now()
|
||||
Booking.objects.filter(primary_booking__in=bookings_to_cancel).update(
|
||||
cancellation_datetime=cancellation_datetime
|
||||
)
|
||||
cancelled_count = bookings_to_cancel.update(cancellation_datetime=cancellation_datetime)
|
||||
# and delete outdated cancelled bookings
|
||||
Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_cancelled_to_delete
|
||||
).delete()
|
||||
# create missing bookings
|
||||
Booking.objects.bulk_create(bookings)
|
||||
|
||||
response = {
|
||||
|
@ -1839,7 +1861,7 @@ class EventsFillslots(APIView):
|
|||
get_event_detail(request, x, multiple_agendas=self.multiple_agendas)
|
||||
for x in waiting_list_events
|
||||
],
|
||||
'cancelled_booking_count': deleted_count,
|
||||
'cancelled_booking_count': cancelled_count,
|
||||
}
|
||||
return Response(response)
|
||||
|
||||
|
@ -1847,7 +1869,9 @@ class EventsFillslots(APIView):
|
|||
return get_events_from_slots(payload['slots'], request, self.agenda, payload)
|
||||
|
||||
def get_already_booked_events(self, user_external_id):
|
||||
return self.agenda.event_set.filter(booking__user_external_id=user_external_id)
|
||||
return self.agenda.event_set.filter(
|
||||
booking__user_external_id=user_external_id, booking__cancellation_datetime__isnull=True
|
||||
)
|
||||
|
||||
def get_agendas_by_ids(self):
|
||||
return {self.agenda.pk: self.agenda}
|
||||
|
|
|
@ -3460,9 +3460,9 @@ def test_api_events_fillslots(app, user):
|
|||
assert resp.json['booking_count'] == 1
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
|
||||
user_bookings = Booking.objects.filter(user_external_id='user_id')
|
||||
user_bookings = Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True)
|
||||
assert {b.event.slug for b in user_bookings} == {'event-2', 'event-3'}
|
||||
assert event.booking_set.count() == 2
|
||||
assert event.booking_set.filter(cancellation_datetime__isnull=True).count() == 2
|
||||
assert second_event.booking_set.count() == 2
|
||||
assert third_event.booking_set.count() == 1
|
||||
|
||||
|
@ -3489,12 +3489,81 @@ def test_api_events_fillslots(app, user):
|
|||
params['slots'] = ''
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['cancelled_booking_count'] == 3
|
||||
assert Booking.objects.filter(user_external_id='user_id').count() == 0
|
||||
assert Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True).count() == 0
|
||||
|
||||
resp = app.post('/api/agenda/foobar/events/fillslots/', status=404)
|
||||
resp = app.post('/api/agenda/0/events/fillslots/', status=404)
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_with_cancelled(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event_1 = Event.objects.create(
|
||||
label='Event 1',
|
||||
start_datetime=now() + datetime.timedelta(days=1),
|
||||
places=2,
|
||||
agenda=agenda,
|
||||
)
|
||||
event_2 = Event.objects.create(
|
||||
label='Event 2',
|
||||
start_datetime=now() + datetime.timedelta(days=2),
|
||||
places=2,
|
||||
agenda=agenda,
|
||||
)
|
||||
Event.objects.create(
|
||||
label='Event 3',
|
||||
start_datetime=now() + datetime.timedelta(days=3),
|
||||
places=2,
|
||||
agenda=agenda,
|
||||
)
|
||||
|
||||
# create cancelled booking for the user
|
||||
booking_1 = Booking.objects.create(event=event_1, user_external_id='user_id')
|
||||
booking_1.cancel()
|
||||
assert booking_1.cancellation_datetime is not None
|
||||
# and non cancelled booking for the user
|
||||
booking_2 = Booking.objects.create(event=event_2, user_external_id='user_id')
|
||||
assert booking_2.cancellation_datetime is None
|
||||
# secondary booking for this one
|
||||
booking_2_secondary = Booking.objects.create(event=event_2, primary_booking=booking_2)
|
||||
# and bookings for another user
|
||||
Booking.objects.create(event=event_1, user_external_id='user_id_foobar')
|
||||
other_booking = Booking.objects.create(event=event_2, user_external_id='user_id_foobar')
|
||||
other_booking.cancel()
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
|
||||
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event-1,event-2,event-3'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 2
|
||||
assert len(resp.json['booked_events']) == 2
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert resp.json['booked_events'][0]['id'] == 'event-1'
|
||||
assert resp.json['booked_events'][1]['id'] == 'event-3'
|
||||
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
|
||||
|
||||
assert Booking.objects.filter(pk=booking_1.pk).exists() is False # cancelled booking deleted
|
||||
booking_2.refresh_from_db()
|
||||
booking_2_secondary.refresh_from_db()
|
||||
assert booking_2.cancellation_datetime is None
|
||||
assert booking_2_secondary.cancellation_datetime is None
|
||||
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event-3'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 2
|
||||
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() == 1
|
||||
|
||||
assert Booking.objects.filter(pk=booking_1.pk).exists() is False # cancelled booking deleted
|
||||
booking_2.refresh_from_db()
|
||||
booking_2_secondary.refresh_from_db()
|
||||
assert booking_2.cancellation_datetime is not None
|
||||
assert booking_2_secondary.cancellation_datetime is not None
|
||||
|
||||
|
||||
def test_api_events_fillslots_check_delays(app, user):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
||||
|
|
Loading…
Reference in New Issue