api: do not cancel out of delay bookings in events fillslots (#59821)
This commit is contained in:
parent
20f86b91f3
commit
5e4675f533
|
@ -1703,6 +1703,7 @@ class EventsFillslots(APIView):
|
|||
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
|
||||
payload = serializer.validated_data
|
||||
user_external_id = payload['user_external_id']
|
||||
bypass_delays = payload.get('bypass_delays')
|
||||
|
||||
events = self.get_events(request, payload)
|
||||
|
||||
|
@ -1712,8 +1713,23 @@ class EventsFillslots(APIView):
|
|||
already_booked_events = already_booked_events.filter(start_datetime__gte=start_datetime)
|
||||
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_in_request_ids = [e.pk for e in events]
|
||||
for event in already_booked_events:
|
||||
if event.pk in events_in_request_ids:
|
||||
continue
|
||||
agenda = agendas_by_ids[event.agenda_id]
|
||||
if (
|
||||
not bypass_delays
|
||||
and agenda.min_booking_datetime
|
||||
and event.start_datetime < agenda.min_booking_datetime
|
||||
):
|
||||
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 = list(already_booked_events.exclude(pk__in=events).values_list('pk', flat=True))
|
||||
events = events.exclude(booking__user_external_id=user_external_id)
|
||||
|
||||
full_events = [str(event) for event in events.filter(full=True)]
|
||||
|
@ -1735,7 +1751,7 @@ class EventsFillslots(APIView):
|
|||
|
||||
with transaction.atomic():
|
||||
deleted_count = Booking.objects.filter(
|
||||
user_external_id=user_external_id, event__in=events_to_unbook
|
||||
user_external_id=user_external_id, event__in=events_to_unbook_ids
|
||||
).delete()[0]
|
||||
Booking.objects.bulk_create(bookings)
|
||||
|
||||
|
@ -1753,6 +1769,9 @@ class EventsFillslots(APIView):
|
|||
def get_already_booked_events(self, user_external_id):
|
||||
return self.agenda.event_set.filter(booking__user_external_id=user_external_id)
|
||||
|
||||
def get_agendas_by_ids(self):
|
||||
return {self.agenda.pk: self.agenda}
|
||||
|
||||
|
||||
events_fillslots = EventsFillslots.as_view()
|
||||
|
||||
|
@ -1806,6 +1825,9 @@ class MultipleAgendasEventsFillslots(EventsFillslots):
|
|||
def get_already_booked_events(self, user_external_id):
|
||||
return Event.objects.filter(agenda__in=self.agendas, booking__user_external_id=user_external_id)
|
||||
|
||||
def get_agendas_by_ids(self):
|
||||
return {a.pk: a for a in self.agendas}
|
||||
|
||||
@property
|
||||
def serializer_extra_context(self):
|
||||
return {'allowed_agenda_slugs': self.agenda_slugs}
|
||||
|
|
|
@ -2773,6 +2773,115 @@ def test_api_events_fillslots_preserve_past_bookings(app, user, freezer):
|
|||
assert second_event.booking_set.count() == 0
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_preserve_out_of_delays_bookings(app, user, freezer):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=2, maximal_booking_delay=10
|
||||
)
|
||||
event = Event.objects.create(
|
||||
label='Event', start_datetime=now() + datetime.timedelta(days=5), places=2, agenda=agenda
|
||||
)
|
||||
second_event = Event.objects.create(
|
||||
label='Event 2', start_datetime=now() + datetime.timedelta(days=9), places=2, agenda=agenda
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event,event-2'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 2
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
|
||||
# book only second event while first event is out of delay
|
||||
freezer.move_to('2021-09-10')
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event-2'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
booking = event.booking_set.get()
|
||||
# except if we want to bypass delays
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event-2', 'bypass_delays': True}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
assert event.booking_set.count() == 0
|
||||
assert second_event.booking_set.count() == 1
|
||||
booking.save() # reset
|
||||
|
||||
# cancel all bookings in delays
|
||||
params = {'user_external_id': 'user_id', 'slots': ''}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 0
|
||||
# bypass delays
|
||||
params = {'user_external_id': 'user_id', 'slots': '', 'bypass_delays': True}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
assert event.booking_set.count() == 0
|
||||
assert second_event.booking_set.count() == 0
|
||||
booking.save() # reset
|
||||
|
||||
# book only second event while first event is out of delay with multiple agendas API
|
||||
params = {'user_external_id': 'user_id', 'slots': 'foo-bar@event-2'}
|
||||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=foo-bar', params=params)
|
||||
assert resp.json['booking_count'] == 1
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
# except if we want to bypass delays
|
||||
params = {'user_external_id': 'user_id', 'slots': 'foo-bar@event-2', 'bypass_delays': True}
|
||||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=foo-bar', params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
assert event.booking_set.count() == 0
|
||||
assert second_event.booking_set.count() == 1
|
||||
booking.save() # reset
|
||||
|
||||
# book only first event while second event is out of delay
|
||||
freezer.move_to('2021-09-04')
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
# bypass_delays has no effect on maximal_booking_delay
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event', 'bypass_delays': True}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
|
||||
# cancel all bookings in delays
|
||||
params = {'user_external_id': 'user_id', 'slots': ''}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 1
|
||||
assert event.booking_set.count() == 0
|
||||
assert second_event.booking_set.count() == 1
|
||||
|
||||
# book only first event while second event is out of delay with multiple agendas API
|
||||
params = {'user_external_id': 'user_id', 'slots': 'foo-bar@event'}
|
||||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=foo-bar', params=params)
|
||||
assert resp.json['booking_count'] == 1
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
# bypass_delays has no effect on maximal_booking_delay
|
||||
params = {'user_external_id': 'user_id', 'slots': 'foo-bar@event', 'bypass_delays': True}
|
||||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=foo-bar', params=params)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert event.booking_set.count() == 1
|
||||
assert second_event.booking_set.count() == 1
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_multiple_agendas(app, user):
|
||||
first_agenda = Agenda.objects.create(label='First agenda', kind='events')
|
||||
|
|
Loading…
Reference in New Issue