From 70cc466dd0f3b9770bf2aa2f460d5fb370dab454 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 3 Feb 2022 09:45:19 +0100
Subject: [PATCH 3/5] api: remove user bookings on subscription deletion
 (#61065)

---
 chrono/api/views.py            |  12 ++++
 tests/api/test_subscription.py | 103 ++++++++++++++++++++++++++++++++-
 2 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/chrono/api/views.py b/chrono/api/views.py
index 0946289..f8bbb17 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -2009,6 +2009,18 @@ class SubscriptionAPI(APIView):
         return self.get(request, *args, **kwargs)
 
     def delete(self, request, *args, **kwargs):
+        booking_qs = Booking.objects.filter(
+            # remove user bookings for this agenda
+            event__agenda=self.subscription.agenda,
+            user_external_id=self.subscription.user_external_id,
+            # in the period of the deleted subscription
+            event__start_datetime__gt=self.subscription.date_start,
+            event__start_datetime__lt=self.subscription.date_end + datetime.timedelta(days=1),
+        ).filter(
+            # but only in the future
+            event__start_datetime__gt=now(),
+        )
+        booking_qs.delete()
         self.subscription.delete()
         response = {'err': 0}
         return Response(response)
diff --git a/tests/api/test_subscription.py b/tests/api/test_subscription.py
index 528f6dc..888b82c 100644
--- a/tests/api/test_subscription.py
+++ b/tests/api/test_subscription.py
@@ -1,8 +1,9 @@
 import datetime
 
 import pytest
+from django.utils.timezone import make_aware, now
 
-from chrono.agendas.models import Agenda, Subscription
+from chrono.agendas.models import Agenda, Booking, Event, Subscription
 
 pytestmark = pytest.mark.django_db
 
@@ -397,6 +398,106 @@ def test_api_delete_subscription(app, user):
     assert Subscription.objects.filter(pk=subscription.pk).exists() is False
 
 
+@pytest.mark.parametrize(
+    'date_now, event_date, user_id, in_waiting_list, cancelled, deleted',
+    [
+        # event in the future, but no booking for the user
+        ('2021-09-09 09:59', (2021, 9, 10, 12, 0), 'yyy', False, False, False),
+        # event in the future
+        ('2021-09-09 09:59', (2021, 9, 10, 12, 0), 'xxx', False, False, True),
+        ('2021-09-09 09:59', (2021, 9, 10, 12, 0), 'xxx', True, False, True),
+        ('2021-09-09 09:59', (2021, 9, 10, 12, 0), 'xxx', False, True, True),
+        # event in the past
+        ('2021-09-10 10:00', (2021, 9, 10, 12, 0), 'xxx', False, False, False),
+        # event in the future, before the period
+        ('2021-08-01 10:00', (2021, 8, 14, 12, 0), 'xxx', False, False, False),
+        ('2021-08-01 10:00', (2021, 8, 31, 12, 0), 'xxx', False, False, False),
+        # event in the future, after the period
+        ('2021-08-01 10:00', (2021, 10, 1, 12, 0), 'xxx', False, False, False),
+        ('2021-08-01 10:00', (2021, 10, 16, 12, 0), 'xxx', False, False, False),
+    ],
+)
+def test_api_delete_subscription_and_bookings(
+    app, user, freezer, date_now, event_date, user_id, in_waiting_list, cancelled, deleted
+):
+    agenda = Agenda.objects.create(label='Foo bar', kind='events')
+    subscription = Subscription.objects.create(
+        agenda=agenda,
+        user_external_id='xxx',
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2021, month=9, day=30),
+    )
+    Subscription.objects.create(
+        agenda=agenda,
+        user_external_id='zzz',  # another user
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2021, month=9, day=30),
+    )
+
+    other_agenda = Agenda.objects.create(label='Foo bar', kind='events')
+    Subscription.objects.create(
+        agenda=other_agenda,
+        user_external_id='xxx',
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2021, month=10, day=1),
+    )
+
+    app.authorization = ('Basic', ('john.doe', 'password'))
+
+    freezer.move_to(date_now)
+    event = Event.objects.create(
+        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
+    )
+    booking = Booking.objects.create(
+        event=event,
+        user_external_id=user_id,
+        in_waiting_list=in_waiting_list,
+        cancellation_datetime=(now() if cancelled else None),
+    )
+    resp = app.delete('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk))
+    assert resp.json['err'] == 0
+    assert Subscription.objects.filter(pk=subscription.pk).exists() is False
+    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
+
+
+@pytest.mark.parametrize(
+    'event_date, deleted',
+    [
+        # just before first day
+        ((2021, 8, 31, 12, 00), False),
+        # first day
+        ((2021, 9, 1, 12, 00), True),
+        # last day
+        ((2021, 9, 30, 12, 00), True),
+        # just after last day
+        ((2021, 10, 1, 12, 00), False),
+    ],
+)
+def test_api_delete_subscription_and_bookings_on_limit(app, user, freezer, event_date, deleted):
+    agenda = Agenda.objects.create(label='Foo bar', kind='events')
+    subscription = Subscription.objects.create(
+        agenda=agenda,
+        user_external_id='xxx',
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2021, month=9, day=30),
+    )
+
+    app.authorization = ('Basic', ('john.doe', 'password'))
+
+    freezer.move_to('2021-08-01 10:00')
+    event = Event.objects.create(
+        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
+    )
+    booking = Booking.objects.create(
+        event=event,
+        user_external_id='xxx',
+    )
+    resp = app.delete('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk))
+    assert resp.json['err'] == 0
+    assert Subscription.objects.filter(pk=subscription.pk).exists() is False
+    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
+
+
 def test_api_patch_subscription(app, user):
     agenda = Agenda.objects.create(label='Foo bar', kind='events')
     subscription = Subscription.objects.create(
-- 
2.34.1

