api: exclude slots already booked by user in fillslot (#51432)
This commit is contained in:
parent
6d83b95b1e
commit
5b7c92ea5d
|
@ -856,6 +856,7 @@ class SlotSerializer(serializers.Serializer):
|
|||
user_display_label = serializers.CharField(max_length=250, allow_blank=True)
|
||||
user_email = serializers.CharField(max_length=250, allow_blank=True)
|
||||
user_phone_number = serializers.CharField(max_length=16, allow_blank=True)
|
||||
exclude_user = 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)
|
||||
|
@ -978,6 +979,8 @@ class Fillslots(APIView):
|
|||
|
||||
available_desk = None
|
||||
color = None
|
||||
user_external_id = payload.get('user_external_id') or None
|
||||
exclude_user = payload.get('exclude_user')
|
||||
|
||||
if agenda.accept_meetings():
|
||||
# slots are actually timeslot ids (meeting_type:start_datetime), not events ids.
|
||||
|
@ -1024,7 +1027,12 @@ class Fillslots(APIView):
|
|||
http_status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
all_slots = sorted(
|
||||
get_all_slots(agenda, meeting_type, resources=resources),
|
||||
get_all_slots(
|
||||
agenda,
|
||||
meeting_type,
|
||||
resources=resources,
|
||||
excluded_user_external_id=user_external_id if exclude_user else None,
|
||||
),
|
||||
key=lambda slot: slot.start_datetime,
|
||||
)
|
||||
|
||||
|
@ -1117,7 +1125,7 @@ class Fillslots(APIView):
|
|||
else:
|
||||
# convert event recurrence identifiers to real event slugs
|
||||
for i, slot in enumerate(slots.copy()):
|
||||
if not ':' in slot:
|
||||
if ':' not in slot:
|
||||
continue
|
||||
event = get_event_recurrence(agenda, slot)
|
||||
slots[i] = event.slug
|
||||
|
@ -1132,6 +1140,11 @@ class Fillslots(APIView):
|
|||
raise APIError(_('event not bookable'), err_class='event not bookable')
|
||||
if event.cancelled:
|
||||
raise APIError(_('event is cancelled'), err_class='event is cancelled')
|
||||
if exclude_user and user_external_id:
|
||||
if event.booking_set.filter(user_external_id=user_external_id).exists():
|
||||
raise APIError(
|
||||
_('event is already booked by user'), err_class='event is already booked by user'
|
||||
)
|
||||
|
||||
if not events.count():
|
||||
raise APIError(
|
||||
|
|
|
@ -1173,6 +1173,103 @@ def test_booking_api(app, some_data, user):
|
|||
resp = app.post('/api/agenda/0/fillslot/%s/' % event.id, status=404)
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-02-23')
|
||||
def test_booking_api_exclude_slots(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().replace(hour=10, minute=0),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
Booking.objects.create(event=event, user_external_id='42')
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'user_external_id': '42'}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug),
|
||||
params={'user_external_id': '42', 'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event is already booked by user'
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'exclude_user': True})
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
event.delete()
|
||||
|
||||
# recurrent event
|
||||
event = Event.objects.create(
|
||||
slug='recurrent',
|
||||
start_datetime=localtime().replace(hour=12, minute=0),
|
||||
repeat='weekly',
|
||||
places=2,
|
||||
agenda=agenda,
|
||||
)
|
||||
first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
|
||||
Booking.objects.create(event=first_recurrence, user_external_id='42')
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'user_external_id': '42'}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug),
|
||||
params={'user_external_id': '42', 'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'event is already booked by user'
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'exclude_user': True})
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-02-25')
|
||||
def test_booking_api_meetings_agenda_exclude_slots(app, user):
|
||||
tomorrow = now() + datetime.timedelta(days=1)
|
||||
agenda = Agenda.objects.create(
|
||||
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=10
|
||||
)
|
||||
desk = Desk.objects.create(agenda=agenda, slug='desk')
|
||||
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo-bar')
|
||||
TimePeriod.objects.create(
|
||||
weekday=tomorrow.date().weekday(),
|
||||
start_time=datetime.time(9, 0),
|
||||
end_time=datetime.time(17, 00),
|
||||
desk=desk,
|
||||
)
|
||||
desk.duplicate()
|
||||
desk.duplicate()
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
meeting_type=meeting_type,
|
||||
places=1,
|
||||
start_datetime=localtime(tomorrow).replace(hour=9, minute=0),
|
||||
desk=desk,
|
||||
)
|
||||
Booking.objects.create(event=event, user_external_id='42')
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (agenda.slug, meeting_type.slug),
|
||||
params={'user_external_id': '42'},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (agenda.slug, meeting_type.slug),
|
||||
params={'user_external_id': '42', 'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'no more desk available'
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (agenda.slug, meeting_type.slug),
|
||||
params={'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
def test_booking_ics(app, some_data, meetings_agenda, user):
|
||||
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
|
||||
event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
|
||||
|
@ -5055,6 +5152,67 @@ def test_virtual_agendas_meetings_booking(app, mock_now, user):
|
|||
assert resp_booking.json['err_desc'] == 'no more desk available'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-02-25')
|
||||
def test_virtual_agendas_meetings_booking_exclude_slots(app, user):
|
||||
tomorrow = now() + datetime.timedelta(days=1)
|
||||
agenda = Agenda.objects.create(
|
||||
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=10
|
||||
)
|
||||
desk = Desk.objects.create(agenda=agenda, slug='desk')
|
||||
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo-bar')
|
||||
TimePeriod.objects.create(
|
||||
weekday=tomorrow.date().weekday(),
|
||||
start_time=datetime.time(9, 0),
|
||||
end_time=datetime.time(17, 00),
|
||||
desk=desk,
|
||||
)
|
||||
agenda2 = agenda.duplicate()
|
||||
agenda3 = agenda.duplicate()
|
||||
virt_agenda = Agenda.objects.create(
|
||||
label='Virtual Agenda', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=10
|
||||
)
|
||||
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=agenda)
|
||||
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=agenda2)
|
||||
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=agenda3)
|
||||
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
meeting_type=meeting_type,
|
||||
places=1,
|
||||
start_datetime=localtime(tomorrow).replace(hour=9, minute=0),
|
||||
desk=desk,
|
||||
)
|
||||
Booking.objects.create(event=event, user_external_id='42')
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (virt_agenda.slug, meeting_type.slug),
|
||||
params={'user_external_id': '42'},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (virt_agenda.slug, meeting_type.slug),
|
||||
params={'user_external_id': '42', 'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'no more desk available'
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (virt_agenda.slug, meeting_type.slug),
|
||||
params={'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
virt_agenda.minimal_booking_delay = None
|
||||
virt_agenda.maximal_booking_delay = None
|
||||
virt_agenda.save()
|
||||
resp = app.post(
|
||||
'/api/agenda/%s/fillslot/%s:2021-02-26-0900/' % (virt_agenda.slug, meeting_type.slug),
|
||||
params={'user_external_id': '42', 'exclude_user': True},
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'no more desk available'
|
||||
|
||||
|
||||
def test_virtual_agendas_meetings_booking_default_policy(app, mock_now, user):
|
||||
foo_agenda = Agenda.objects.create(
|
||||
label='Foo Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=5
|
||||
|
|
Loading…
Reference in New Issue