From 5b7dac99412398fc1622464d3ea22d51e6e85fa8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 3 Mar 2020 13:43:00 +0100
Subject: [PATCH] api: add a param in_waiting_list to fillslot (#40022)

---
 chrono/api/views.py |  8 ++++--
 tests/test_api.py   | 64 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/chrono/api/views.py b/chrono/api/views.py
index 6a664c1..9157b59 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -387,6 +387,7 @@ class SlotSerializer(serializers.Serializer):
     backoffice_url = serializers.URLField(allow_blank=True)
     count = serializers.IntegerField(min_value=1)
     cancel_booking_id = serializers.CharField(max_length=250, allow_blank=True, allow_null=True)
+    in_waiting_list = serializers.BooleanField(default=False)
 
 
 class StringOrListField(serializers.ListField):
@@ -605,13 +606,16 @@ class Fillslots(APIView):
         # search free places. Switch to waiting list if necessary.
         in_waiting_list = False
         for event in events:
+            if payload.get('in_waiting_list') and not event.waiting_list_places:
+                return Response({'err': 1, 'err_class': 'no waiting list', 'err_desc': _('no waiting list')})
+
             if event.waiting_list_places:
-                if (event.booked_places + places_count) > event.places or event.waiting_list:
+                if payload.get('in_waiting_list') or (event.booked_places + places_count) > event.places or event.waiting_list:
                     # if this is full or there are people waiting, put new bookings
                     # in the waiting list.
                     in_waiting_list = True
                     if (event.waiting_list + places_count) > event.waiting_list_places:
-                        return Response({'err': 1, 'err_class': 'sold out', 'err_desc': _('sold out'),})
+                        return Response({'err': 1, 'err_class': 'sold out', 'err_desc': _('sold out')})
             else:
                 if (event.booked_places + places_count) > event.places:
                     return Response({'err': 1, 'err_class': 'sold out', 'err_desc': _('sold out')})
diff --git a/tests/test_api.py b/tests/test_api.py
index 4555ed7..629598e 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -965,6 +965,70 @@ def test_booking_api_available(app, some_data, meetings_agenda, user):
     assert 'places' not in resp.json
 
 
+def test_booking_api_force_waiting_list(app, some_data, user):
+    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
+    event = Event.objects.filter(agenda=agenda)[0]
+
+    app.authorization = ('Basic', ('john.doe', 'password'))
+
+    # no waiting list
+    assert event.waiting_list_places == 0
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'in_waiting_list': True})
+    assert resp.json['err'] == 1
+    assert resp.json['reason'] == 'no waiting list'  # legacy
+    assert resp.json['err_class'] == 'no waiting list'
+    assert resp.json['err_desc'] == 'no waiting list'
+
+    event.waiting_list_places = 2
+    event.save()
+    # add a booking
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
+    assert resp.json['err'] == 0
+    assert resp.json['places']['total'] == 10
+    assert resp.json['places']['available'] == 9
+    assert resp.json['places']['reserved'] == 1
+    assert resp.json['places']['waiting_list_total'] == 2
+    assert resp.json['places']['waiting_list_available'] == 2
+    assert resp.json['places']['waiting_list_reserved'] == 0
+
+    # add another booking
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'in_waiting_list': False})
+    assert resp.json['err'] == 0
+    assert resp.json['places']['total'] == 10
+    assert resp.json['places']['available'] == 8
+    assert resp.json['places']['reserved'] == 2
+    assert resp.json['places']['waiting_list_total'] == 2
+    assert resp.json['places']['waiting_list_available'] == 2
+    assert resp.json['places']['waiting_list_reserved'] == 0
+
+    # add a booking, but in waiting list
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'in_waiting_list': True})
+    assert resp.json['err'] == 0
+    assert resp.json['places']['total'] == 10
+    assert resp.json['places']['available'] == 8
+    assert resp.json['places']['reserved'] == 2
+    assert resp.json['places']['waiting_list_total'] == 2
+    assert resp.json['places']['waiting_list_available'] == 1
+    assert resp.json['places']['waiting_list_reserved'] == 1
+
+    # add a booking => booked in waiting list
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
+    assert resp.json['err'] == 0
+    assert resp.json['places']['total'] == 10
+    assert resp.json['places']['available'] == 8
+    assert resp.json['places']['reserved'] == 2
+    assert resp.json['places']['waiting_list_total'] == 2
+    assert resp.json['places']['waiting_list_available'] == 0
+    assert resp.json['places']['waiting_list_reserved'] == 2
+
+    # waiting list is full
+    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'in_waiting_list': True})
+    assert resp.json['err'] == 1
+    assert resp.json['reason'] == 'sold out'  # legacy
+    assert resp.json['err_class'] == 'sold out'
+    assert resp.json['err_desc'] == 'sold out'
+
+
 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]
-- 
2.20.1

