api: allow changing recurrence bookings (#54746)
This commit is contained in:
parent
92d209ed11
commit
96b10d052b
|
@ -1571,6 +1571,7 @@ class RecurringFillslots(APIView):
|
|||
http_status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
payload = serializer.validated_data
|
||||
user_external_id = payload['user_external_id']
|
||||
|
||||
open_event_slugs = set(agenda.get_open_recurring_events().values_list('slug', flat=True))
|
||||
slots = collections.defaultdict(list)
|
||||
|
@ -1600,15 +1601,18 @@ class RecurringFillslots(APIView):
|
|||
|
||||
events_to_book = Event.objects.filter(event_filter)
|
||||
events_to_book = events_to_book.filter(start_datetime__gte=start_datetime, cancelled=False)
|
||||
if end_datetime:
|
||||
events_to_book = events_to_book.filter(start_datetime__lte=end_datetime)
|
||||
|
||||
events_to_unbook = list(
|
||||
agenda.event_set.filter(booking__user_external_id=user_external_id, primary_event__isnull=False)
|
||||
.exclude(pk__in=events_to_book)
|
||||
.values_list('pk', flat=True)
|
||||
)
|
||||
events_to_book = events_to_book.exclude(booking__user_external_id=user_external_id)
|
||||
|
||||
full_events = list(events_to_book.filter(full=True))
|
||||
events_to_book = events_to_book.filter(full=False)
|
||||
if end_datetime:
|
||||
events_to_book = events_to_book.filter(start_datetime__lte=end_datetime)
|
||||
if not events_to_book.exists():
|
||||
if full_events:
|
||||
raise APIError(_('all events are all full'), err_class='all events are all full')
|
||||
raise APIError(_('no event recurrences to book'), err_class='no event recurrences to book')
|
||||
|
||||
events_to_book = Event.annotate_queryset(events_to_book)
|
||||
events_to_book = events_to_book.annotate(
|
||||
|
@ -1621,9 +1625,15 @@ class RecurringFillslots(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_to_book]
|
||||
|
||||
events_to_update = Event.annotate_queryset(
|
||||
agenda.event_set.filter(pk__in=events_to_unbook + [event.pk for event in events_to_book])
|
||||
)
|
||||
with transaction.atomic():
|
||||
deleted_count = Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_to_unbook
|
||||
).delete()[0]
|
||||
Booking.objects.bulk_create(bookings)
|
||||
events_to_book.update(
|
||||
events_to_update.update(
|
||||
full=Q(booked_places_count__gte=F('places'), waiting_list_places=0)
|
||||
| Q(waiting_list_places__gt=0, waiting_list_count__gte=F('waiting_list_places')),
|
||||
almost_full=Q(booked_places_count__gte=0.9 * F('places')),
|
||||
|
@ -1632,6 +1642,7 @@ class RecurringFillslots(APIView):
|
|||
response = {
|
||||
'err': 0,
|
||||
'booking_count': len(bookings),
|
||||
'cancelled_booking_count': deleted_count,
|
||||
'full_events': [get_event_detail(request, x, agenda=agenda) for x in full_events],
|
||||
}
|
||||
return Response(response)
|
||||
|
|
|
@ -2168,21 +2168,22 @@ def test_recurring_events_api_fillslots(app, user, freezer):
|
|||
assert resp.json['booking_count'] == 155
|
||||
assert len(resp.json['full_events']) == 1
|
||||
assert resp.json['full_events'][0]['slug'] == event.slug
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
|
||||
# events are full
|
||||
params['user_external_id'] = 'user_id_4'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'all events are all full'
|
||||
assert resp.json['booking_count'] == 0
|
||||
|
||||
# no event in range
|
||||
resp = app.post_json(fillslots_url + '?date_start=2020-10-06&date_end=2020-11-06', params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
|
||||
params['slots'] = 'event:1'
|
||||
resp = app.post_json(fillslots_url + '?date_start=2021-10-06&date_end=2021-11-06', params=params)
|
||||
assert resp.json['booking_count'] == 4
|
||||
assert Booking.objects.filter(user_external_id='user_id_4').count() == 4
|
||||
|
||||
resp = app.post_json(fillslots_url + '?date_start=2020-10-06&date_end=2020-11-06', params=params)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'no event recurrences to book'
|
||||
|
||||
del params['user_external_id']
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
|
@ -2226,6 +2227,80 @@ def test_recurring_events_api_fillslots_waiting_list(app, user, freezer):
|
|||
assert events.filter(waiting_list_count=2).count() == 5
|
||||
|
||||
|
||||
def test_recurring_events_api_fillslots_change_bookings(app, user, freezer):
|
||||
freezer.move_to('2021-09-06 12:00')
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event = Event.objects.create(
|
||||
label='Event',
|
||||
start_datetime=now(),
|
||||
recurrence_days=[0, 1, 3, 4], # Monday, Tuesday, Thursday, Friday
|
||||
places=1,
|
||||
waiting_list_places=1,
|
||||
agenda=agenda,
|
||||
recurrence_end_date=now() + datetime.timedelta(days=364),
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agenda/%s/recurring-events/fillslots/' % agenda.slug
|
||||
params = {'user_external_id': 'user_id'}
|
||||
# Book Monday and Thursday
|
||||
params['slots'] = 'event:0,event:3'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 104
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert Booking.objects.count() == 104
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 52
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=5).count() == 52
|
||||
|
||||
# Change booking to Monday and Tuesday
|
||||
params['slots'] = 'event:0,event:1'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 52
|
||||
assert resp.json['cancelled_booking_count'] == 52
|
||||
assert Booking.objects.count() == 104
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 52
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=3).count() == 52
|
||||
|
||||
# Booking again does nothing
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert Booking.objects.count() == 104
|
||||
|
||||
params = {'user_external_id': 'user_id_2'}
|
||||
params['slots'] = 'event:0,event:3'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 104
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert Booking.objects.count() == 208
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 104
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=5).count() == 52
|
||||
events = Event.annotate_queryset(Event.objects.filter(primary_event__isnull=False))
|
||||
assert events.filter(booked_places_count=1).count() == 156
|
||||
assert events.filter(waiting_list_count=1).count() == 52
|
||||
|
||||
params['slots'] = 'event:1,event:4'
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 104
|
||||
assert resp.json['cancelled_booking_count'] == 104
|
||||
assert Booking.objects.count() == 208
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=3).count() == 104
|
||||
assert Booking.objects.filter(event__start_datetime__week_day=6).count() == 52
|
||||
events = Event.annotate_queryset(Event.objects.filter(primary_event__isnull=False))
|
||||
assert events.filter(booked_places_count=1).count() == 156
|
||||
assert events.filter(waiting_list_count=1).count() == 52
|
||||
|
||||
# only recurring events are impacted
|
||||
normal_event = Event.objects.create(
|
||||
start_datetime=now() + datetime.timedelta(days=1), places=2, agenda=agenda
|
||||
)
|
||||
Booking.objects.create(event=normal_event, user_external_id='user_id')
|
||||
resp = app.post_json(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event:0'})
|
||||
assert resp.json['cancelled_booking_count'] == 52
|
||||
assert Booking.objects.filter(user_external_id='user_id', event=normal_event).count() == 1
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
|
|
Loading…
Reference in New Issue