api: bypass_delays parameter for event fillslot endpoints (#57961)
This commit is contained in:
parent
b07288d1be
commit
268a0db229
|
@ -1451,19 +1451,25 @@ class Event(models.Model):
|
|||
self.checked = True
|
||||
self.save(update_fields=['checked'])
|
||||
|
||||
def in_bookable_period(self):
|
||||
def in_bookable_period(self, bypass_delays=False):
|
||||
if self.publication_datetime and now() < self.publication_datetime:
|
||||
return False
|
||||
if self.agenda.maximal_booking_delay and self.start_datetime > self.agenda.max_booking_datetime:
|
||||
if (
|
||||
not bypass_delays
|
||||
and self.agenda.maximal_booking_delay
|
||||
and self.start_datetime > self.agenda.max_booking_datetime
|
||||
):
|
||||
return False
|
||||
if self.recurrence_days is not None:
|
||||
# bookable recurrences probably exist
|
||||
return True
|
||||
if self.agenda.minimal_booking_delay and self.start_datetime < self.agenda.min_booking_datetime:
|
||||
if (
|
||||
not bypass_delays
|
||||
and self.agenda.minimal_booking_delay
|
||||
and self.start_datetime < self.agenda.min_booking_datetime
|
||||
):
|
||||
return False
|
||||
if self.start_datetime < now():
|
||||
# past the event date, we may want in the future to allow for some
|
||||
# extra late booking but it's forbidden for now.
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class SlotSerializer(serializers.Serializer):
|
|||
user_phone_number = serializers.CharField(max_length=16, allow_blank=True)
|
||||
exclude_user = serializers.BooleanField(default=False)
|
||||
events = serializers.CharField(max_length=16, allow_blank=True)
|
||||
bypass_delays = serializers.BooleanField(default=False)
|
||||
form_url = serializers.CharField(max_length=250, allow_blank=True)
|
||||
backoffice_url = serializers.URLField(allow_blank=True)
|
||||
cancel_callback_url = serializers.URLField(allow_blank=True)
|
||||
|
@ -57,7 +58,7 @@ class EventsSlotsSerializer(SlotSerializer):
|
|||
|
||||
def validate(self, attrs):
|
||||
super().validate(attrs)
|
||||
if not 'slots' in attrs:
|
||||
if 'slots' not in attrs:
|
||||
raise serializers.ValidationError({'slots': _('This field is required.')})
|
||||
if not attrs.get('user_external_id'):
|
||||
raise serializers.ValidationError({'user_external_id': _('This field is required.')})
|
||||
|
|
|
@ -598,6 +598,7 @@ def get_events_from_slots(slots, request, agenda, payload):
|
|||
book_events = payload.get('events') or request.query_params.get('events') or 'future'
|
||||
book_past = book_events in ['all', 'past']
|
||||
book_future = book_events in ['all', 'future']
|
||||
bypass_delays = payload.get('bypass_delays')
|
||||
|
||||
# convert event recurrence identifiers to real event slugs
|
||||
for i, slot in enumerate(slots.copy()):
|
||||
|
@ -613,7 +614,7 @@ def get_events_from_slots(slots, request, agenda, payload):
|
|||
|
||||
for event in events:
|
||||
if event.start_datetime >= now():
|
||||
if not book_future or not event.in_bookable_period():
|
||||
if not book_future or not event.in_bookable_period(bypass_delays=bypass_delays):
|
||||
raise APIError(_('event %s is not bookable') % event.slug, err_class='event not bookable')
|
||||
else:
|
||||
if not book_past:
|
||||
|
|
|
@ -168,6 +168,43 @@ def test_booking_api(app, some_data, user):
|
|||
resp = app.post('/api/agenda/0/fillslot/%s/' % event.id, status=404)
|
||||
|
||||
|
||||
def test_booking_api_check_delays(app, user):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
||||
)
|
||||
event = Event.objects.create(
|
||||
slug='event-slug',
|
||||
start_datetime=localtime() + datetime.timedelta(days=5),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test minimal_booking_delay
|
||||
agenda.minimal_booking_delay = 6
|
||||
agenda.save()
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'bypass_delays': True})
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test maximal_booking_delay
|
||||
agenda.minimal_booking_delay = 0
|
||||
agenda.maximal_booking_delay = 3
|
||||
agenda.save()
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'bypass_delays': True})
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-02-23')
|
||||
def test_booking_api_exclude_slots(app, user):
|
||||
agenda = Agenda.objects.create(
|
||||
|
@ -2398,6 +2435,48 @@ def test_api_events_fillslots(app, user):
|
|||
resp = app.post('/api/agenda/0/events/fillslots/', status=404)
|
||||
|
||||
|
||||
def test_api_events_fillslots_check_delays(app, user):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
||||
)
|
||||
Event.objects.create(
|
||||
slug='event-slug',
|
||||
start_datetime=localtime() + datetime.timedelta(days=5),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
|
||||
resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test minimal_booking_delay
|
||||
agenda.minimal_booking_delay = 6
|
||||
agenda.save()
|
||||
resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug', 'bypass_delays': True}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test maximal_booking_delay
|
||||
agenda.minimal_booking_delay = 0
|
||||
agenda.maximal_booking_delay = 3
|
||||
agenda.save()
|
||||
resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug', 'bypass_delays': True}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_past_event(app, user):
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
|
@ -2512,6 +2591,58 @@ def test_api_events_fillslots_multiple_agendas(app, user):
|
|||
)
|
||||
|
||||
|
||||
def test_api_events_fillslots_multiple_agendas_check_delays(app, user):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
||||
)
|
||||
Event.objects.create(
|
||||
slug='event-slug',
|
||||
start_datetime=localtime() + datetime.timedelta(days=5),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post(
|
||||
'/api/agendas/events/fillslots/?agendas=foo-bar',
|
||||
params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test minimal_booking_delay
|
||||
agenda.minimal_booking_delay = 6
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
'/api/agendas/events/fillslots/?agendas=foo-bar',
|
||||
params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
'/api/agendas/events/fillslots/?agendas=foo-bar',
|
||||
params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug', 'bypass_delays': True},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
# test maximal_booking_delay
|
||||
agenda.minimal_booking_delay = 0
|
||||
agenda.maximal_booking_delay = 3
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
'/api/agendas/events/fillslots/?agendas=foo-bar',
|
||||
params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event not bookable'
|
||||
agenda.save()
|
||||
resp = app.post(
|
||||
'/api/agendas/events/fillslots/?agendas=foo-bar',
|
||||
params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug', 'bypass_delays': True},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
def test_url_translation(app, some_data, user):
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
agenda_id = Agenda.objects.filter(label='Foo bar')[0].id
|
||||
|
|
Loading…
Reference in New Issue