api: cancel a booking when making a new one (#33489)

This commit is contained in:
Emmanuel Cazenave 2019-05-28 16:32:30 +02:00
parent aeea3b78d6
commit ab9ff7adf1
2 changed files with 111 additions and 16 deletions

View File

@ -18,6 +18,7 @@ from collections import defaultdict
import datetime
from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.dateparse import parse_date
@ -315,6 +316,7 @@ class SlotSerializer(serializers.Serializer):
user_display_label = serializers.CharField(max_length=250, allow_blank=True)
backoffice_url = serializers.URLField(allow_blank=True)
count = serializers.IntegerField(min_value=1)
cancel_booking_id = serializers.IntegerField()
class SlotsSerializer(SlotSerializer):
@ -381,6 +383,23 @@ class Fillslots(APIView):
'reason': 'count cannot be less than or equal to zero'
}, status=status.HTTP_400_BAD_REQUEST)
to_cancel_booking = None
if 'cancel_booking_id' in payload:
cancel_error = None
try:
to_cancel_booking = Booking.objects.get(pk=payload.get('cancel_booking_id'))
if to_cancel_booking.cancellation_datetime:
cancel_error = 'cancel booking: booking already cancelled'
else:
to_cancel_places_count = to_cancel_booking.secondary_booking_set.count() + 1
if places_count != to_cancel_places_count:
cancel_error = 'cancel booking: count is different'
except Booking.DoesNotExist:
cancel_error = 'cancel booking: booking does no exist'
if cancel_error:
return Response({'err': 1, 'reason': cancel_error})
extra_data = {}
for k, v in request.data.items():
if k not in serializer.validated_data:
@ -447,22 +466,27 @@ class Fillslots(APIView):
if (event.booked_places + places_count) > event.places:
return Response({'err': 1, 'reason': 'sold out'})
# now we have a list of events, book them.
primary_booking = None
for event in events:
for i in range(places_count):
new_booking = Booking(event_id=event.id,
in_waiting_list=in_waiting_list,
label=payload.get('label', ''),
user_name=payload.get('user_name', ''),
backoffice_url=payload.get('backoffice_url', ''),
user_display_label=payload.get('user_display_label', ''),
extra_data=extra_data)
if primary_booking is not None:
new_booking.primary_booking = primary_booking
new_booking.save()
if primary_booking is None:
primary_booking = new_booking
with transaction.atomic():
if to_cancel_booking:
cancelled_booking_id = to_cancel_booking.pk
to_cancel_booking.cancel()
# now we have a list of events, book them.
primary_booking = None
for event in events:
for i in range(places_count):
new_booking = Booking(event_id=event.id,
in_waiting_list=in_waiting_list,
label=payload.get('label', ''),
user_name=payload.get('user_name', ''),
backoffice_url=payload.get('backoffice_url', ''),
user_display_label=payload.get('user_display_label', ''),
extra_data=extra_data)
if primary_booking is not None:
new_booking.primary_booking = primary_booking
new_booking.save()
if primary_booking is None:
primary_booking = new_booking
response = {
'err': 0,
@ -486,6 +510,8 @@ class Fillslots(APIView):
response['desk'] = {
'label': available_desk.label,
'slug': available_desk.slug}
if to_cancel_booking:
response['cancelled_booking_id'] = cancelled_booking_id
return Response(response)

View File

@ -721,6 +721,75 @@ def test_booking_api_with_data(app, some_data, user):
assert Booking.objects.count() == 1
assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
def test_booking_api_with_cancel_booking(app, some_data, user):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
event_0, event_1, event_2, event_3 = Event.objects.filter(agenda_id=agenda_id)[0:4]
app.authorization = ('Basic', ('john.doe', 'password'))
app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id))
assert Booking.objects.count() == 1
first_booking = Booking.objects.first()
# Book a new event and cancel previous booking
resp = app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
params={'cancel_booking_id': first_booking.pk}
)
assert resp.json['err'] == 0
assert resp.json['cancelled_booking_id'] == first_booking.pk
assert Booking.objects.count() == 2
first_booking = Booking.objects.get(pk=first_booking.pk)
assert first_booking.cancellation_datetime
# Cancelling an already cancelled booking returns an error
resp = app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
params={'cancel_booking_id': first_booking.pk}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: booking already cancelled'
assert Booking.objects.count() == 2
# Cancelling a non existent booking returns an error
resp = app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
params={'cancel_booking_id': '-1'}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: booking does no exist'
assert Booking.objects.count() == 2
# Cancelling booking with different count than new booking
resp = app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_2.id),
params={'count': 2}
)
assert resp.json['err'] == 0
assert Booking.objects.count() == 4
booking_id = resp.json['booking_id']
resp = app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_3.id),
params={'cancel_booking_id': booking_id, 'count': 1}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: count is different'
assert Booking.objects.count() == 4
# cancel_booking_id must be an integer
app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id),
params={'cancel_booking_id': 'no an integer'},
status=400)
# cancel_booking_id can't be empty if specified
app.post_json(
'/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id),
params={'cancel_booking_id': ''},
status=400)
def test_booking_cancellation_api(app, some_data, user):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
event = Event.objects.filter(agenda_id=agenda_id)[0]