2545 lines
98 KiB
Python
2545 lines
98 KiB
Python
import datetime
|
|
|
|
import pytest
|
|
from django.db import connection
|
|
from django.test.utils import CaptureQueriesContext
|
|
from django.utils.timezone import localtime, make_aware, now
|
|
|
|
from chrono.agendas.models import (
|
|
Agenda,
|
|
Booking,
|
|
Desk,
|
|
Event,
|
|
MeetingType,
|
|
Resource,
|
|
TimePeriod,
|
|
TimePeriodException,
|
|
UnavailabilityCalendar,
|
|
VirtualMember,
|
|
)
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
def datetime_from_str(dt_str):
|
|
return datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
def test_datetimes_api_meetings_agenda(app, meetings_agenda):
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meeting_type.agenda.slug, meeting_type.slug)
|
|
|
|
resp = app.get('/api/agenda/%s/meetings/xxx/datetimes/' % meeting_type.agenda.slug, status=404)
|
|
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 144
|
|
assert resp.json == app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id).json
|
|
|
|
meetings_agenda.minimal_booking_delay = 7
|
|
meetings_agenda.maximal_booking_delay = 28
|
|
meetings_agenda.save()
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == 54
|
|
|
|
meetings_agenda.minimal_booking_delay = 1
|
|
meetings_agenda.maximal_booking_delay = 56
|
|
meetings_agenda.save()
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == 144
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event(
|
|
agenda=meetings_agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=Desk.objects.first(),
|
|
)
|
|
ev.save()
|
|
booking = Booking(event=ev)
|
|
booking.save()
|
|
|
|
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp2.json['data']) == 144
|
|
assert resp.json['data'][0] == resp2.json['data'][0]
|
|
assert resp.json['data'][1] == resp2.json['data'][1]
|
|
assert resp.json['data'][2] != resp2.json['data'][2]
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
assert resp2.json['data'][2]['disabled'] is True
|
|
assert resp.json['data'][3] == resp2.json['data'][3]
|
|
|
|
# test with a timeperiod overlapping current moment, it should get one
|
|
# datetime for the current timeperiod + two from the next week.
|
|
if localtime(now()).time().hour == 23:
|
|
# skip this part of the test as it would require support for events
|
|
# crossing midnight
|
|
return
|
|
default_desk, _ = Desk.objects.get_or_create(agenda=meetings_agenda, slug='desk-1')
|
|
TimePeriod.objects.filter(desk=default_desk).delete()
|
|
start_time = localtime(now()) - datetime.timedelta(minutes=10)
|
|
time_period = TimePeriod(
|
|
weekday=localtime(now()).weekday(),
|
|
start_time=start_time,
|
|
end_time=start_time + datetime.timedelta(hours=1),
|
|
desk=default_desk,
|
|
)
|
|
time_period.save()
|
|
meetings_agenda.minimal_booking_delay = 0
|
|
meetings_agenda.maximal_booking_delay = 10
|
|
meetings_agenda.save()
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == 3
|
|
|
|
|
|
@pytest.mark.freeze_time('2020-10-24') # tomorrow is time change
|
|
def test_datetimes_api_meetings_agenda_time_change(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=3
|
|
)
|
|
desk = Desk.objects.create(agenda=agenda, slug='desk')
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo', duration=60)
|
|
for weekday in [0, 5, 6]: # monday, saturday, sunday
|
|
TimePeriod.objects.create(
|
|
weekday=weekday,
|
|
start_time=datetime.time(9, 0),
|
|
end_time=datetime.time(10, 00),
|
|
desk=desk,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=weekday,
|
|
start_time=datetime.time(14, 0),
|
|
end_time=datetime.time(15, 00),
|
|
desk=desk,
|
|
)
|
|
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'] == [
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-24-0900/'},
|
|
'date': '2020-10-24',
|
|
'datetime': '2020-10-24 09:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-24-0900',
|
|
'text': 'Oct. 24, 2020, 9 a.m.',
|
|
},
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-24-1400/'},
|
|
'date': '2020-10-24',
|
|
'datetime': '2020-10-24 14:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-24-1400',
|
|
'text': 'Oct. 24, 2020, 2 p.m.',
|
|
},
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-25-0900/'},
|
|
'date': '2020-10-25',
|
|
'datetime': '2020-10-25 09:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-25-0900',
|
|
'text': 'Oct. 25, 2020, 9 a.m.',
|
|
},
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-25-1400/'},
|
|
'date': '2020-10-25',
|
|
'datetime': '2020-10-25 14:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-25-1400',
|
|
'text': 'Oct. 25, 2020, 2 p.m.',
|
|
},
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-26-0900/'},
|
|
'date': '2020-10-26',
|
|
'datetime': '2020-10-26 09:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-26-0900',
|
|
'text': 'Oct. 26, 2020, 9 a.m.',
|
|
},
|
|
{
|
|
'api': {'fillslot_url': 'http://testserver/api/agenda/agenda/fillslot/foo:2020-10-26-1400/'},
|
|
'date': '2020-10-26',
|
|
'datetime': '2020-10-26 14:00:00',
|
|
'disabled': False,
|
|
'id': 'foo:2020-10-26-1400',
|
|
'text': 'Oct. 26, 2020, 2 p.m.',
|
|
},
|
|
]
|
|
|
|
|
|
def test_datetimes_api_meetings_agenda_with_resources(app):
|
|
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
|
|
tomorrow_str = tomorrow.isoformat()
|
|
agenda = Agenda.objects.create(
|
|
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=10
|
|
)
|
|
other_agenda = Agenda.objects.create(label='Other', kind='meetings')
|
|
other_desk = Desk.objects.create(agenda=other_agenda, slug='desk-1')
|
|
other_meeting_type = MeetingType.objects.create(agenda=other_agenda, slug='foo-bar', duration=90)
|
|
resource1 = Resource.objects.create(label='Resource 1')
|
|
resource2 = Resource.objects.create(label='Resource 2')
|
|
resource3 = Resource.objects.create(label='Resource 3')
|
|
agenda.resources.add(resource1, resource2, resource3)
|
|
desk = Desk.objects.create(agenda=agenda, slug='desk-1')
|
|
desk2 = Desk.objects.create(agenda=agenda, slug='desk-2')
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo-bar')
|
|
TimePeriod.objects.create(
|
|
weekday=tomorrow.weekday(),
|
|
start_time=datetime.time(9, 0),
|
|
end_time=datetime.time(17, 00),
|
|
desk=desk,
|
|
)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == []
|
|
|
|
# all resources are free
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s,%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource1.slug,
|
|
resource2.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == []
|
|
for slot in resp.json['data']:
|
|
assert slot['api']['fillslot_url'].endswith('/?resources=%s,%s' % (resource1.slug, resource2.slug))
|
|
|
|
# resource 1 is not available from 10h to 11h30 in another agenda
|
|
dt = make_aware(datetime.datetime.combine(tomorrow, datetime.time(10, 0)))
|
|
event1 = Event.objects.create(
|
|
agenda=other_agenda,
|
|
meeting_type=other_meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=dt,
|
|
desk=other_desk,
|
|
)
|
|
event1.resources.add(resource1)
|
|
booking_r1 = Booking.objects.create(event=event1)
|
|
# resource 3 is not available from 9h to 10h in this agenda (but desk-1 is free)
|
|
dt = make_aware(datetime.datetime.combine(tomorrow, datetime.time(9, 0)))
|
|
event2 = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=dt,
|
|
desk=desk2,
|
|
)
|
|
event2.resources.add(resource3)
|
|
Booking.objects.create(event=event2)
|
|
dt = make_aware(datetime.datetime.combine(tomorrow, datetime.time(9, 30)))
|
|
event3 = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=dt,
|
|
desk=desk2,
|
|
)
|
|
event3.resources.add(resource3)
|
|
Booking.objects.create(event=event3)
|
|
|
|
# check for resource 1 and resource 2: not available from 10H to 11H30
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s,%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource1.slug,
|
|
resource2.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 10:00:00' % tomorrow_str,
|
|
'%s 10:30:00' % tomorrow_str,
|
|
'%s 11:00:00' % tomorrow_str,
|
|
]
|
|
|
|
# check for resource 2 only ? it's free
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource2.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == []
|
|
for slot in resp.json['data']:
|
|
assert slot['api']['fillslot_url'].endswith('/?resources=%s' % resource2.slug)
|
|
|
|
# check for resource 3: not available from 9H to 10H
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource3.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:00:00' % tomorrow_str,
|
|
'%s 09:30:00' % tomorrow_str,
|
|
]
|
|
|
|
# check for resource 1 and resource 3
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s,%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource1.slug,
|
|
resource3.slug,
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(api_url)
|
|
assert len(ctx.captured_queries) == 10
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:00:00' % tomorrow_str,
|
|
'%s 09:30:00' % tomorrow_str,
|
|
'%s 10:00:00' % tomorrow_str,
|
|
'%s 10:30:00' % tomorrow_str,
|
|
'%s 11:00:00' % tomorrow_str,
|
|
]
|
|
|
|
# no resources to book
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == []
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == []
|
|
|
|
# event 3 is booked without resource, only one desk
|
|
event3.desk = desk
|
|
event3.save()
|
|
event3.resources.clear()
|
|
desk2.delete()
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:30:00' % tomorrow_str
|
|
]
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource1.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:30:00' % tomorrow_str,
|
|
'%s 10:00:00' % tomorrow_str,
|
|
'%s 10:30:00' % tomorrow_str,
|
|
'%s 11:00:00' % tomorrow_str,
|
|
]
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource3.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:30:00' % tomorrow_str
|
|
]
|
|
|
|
# resource is unknown or not valid for this agenda
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=foobarbaz' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
)
|
|
resp = app.get(api_url, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'invalid slugs: foobarbaz' # legacy
|
|
assert resp.json['err_class'] == 'invalid slugs: foobarbaz'
|
|
assert resp.json['err_desc'] == 'invalid slugs: foobarbaz'
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s,foobarbaz' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource3.slug,
|
|
)
|
|
resp = app.get(api_url, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'invalid slugs: foobarbaz' # legacy
|
|
assert resp.json['err_class'] == 'invalid slugs: foobarbaz'
|
|
assert resp.json['err_desc'] == 'invalid slugs: foobarbaz'
|
|
agenda.resources.remove(resource3)
|
|
resp = app.get(api_url, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'invalid slugs: foobarbaz, resource-3' # legacy
|
|
assert resp.json['err_class'] == 'invalid slugs: foobarbaz, resource-3'
|
|
assert resp.json['err_desc'] == 'invalid slugs: foobarbaz, resource-3'
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource3.slug,
|
|
)
|
|
resp = app.get(api_url, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'invalid slugs: resource-3' # legacy
|
|
assert resp.json['err_class'] == 'invalid slugs: resource-3'
|
|
assert resp.json['err_desc'] == 'invalid slugs: resource-3'
|
|
|
|
# if booking is canceled the resource is free
|
|
booking_r1.cancel()
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/?resources=%s' % (
|
|
agenda.slug,
|
|
meeting_type.slug,
|
|
resource1.slug,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 32
|
|
assert [s['datetime'] for s in resp.json['data'] if s['disabled'] is True] == [
|
|
'%s 09:30:00' % tomorrow_str
|
|
]
|
|
|
|
|
|
def test_datetimes_api_meetings_agenda_short_time_periods(app, meetings_agenda, user):
|
|
meetings_agenda.minimal_booking_delay = 0
|
|
meetings_agenda.maximal_booking_delay = 10
|
|
meetings_agenda.save()
|
|
|
|
default_desk, _ = Desk.objects.get_or_create(agenda=meetings_agenda, slug='desk-1')
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
|
|
# test with short time periods
|
|
TimePeriod.objects.filter(desk=default_desk).delete()
|
|
test_1st_weekday = (localtime(now()).weekday() + 2) % 7
|
|
time_period = TimePeriod(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(10, 30),
|
|
desk=default_desk,
|
|
)
|
|
time_period.save()
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == 2
|
|
fillslot_url = resp.json['data'][0]['api']['fillslot_url']
|
|
two_slots = [resp.json['data'][0]['id'], resp.json['data'][1]['id']]
|
|
|
|
time_period.end_time = datetime.time(10, 15)
|
|
time_period.save()
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == 0
|
|
|
|
# check booking is not possible
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.post(fillslot_url)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'no more desk available' # legacy
|
|
assert resp.json['err_class'] == 'no more desk available'
|
|
assert resp.json['err_desc'] == 'no more desk available'
|
|
# booking the two slots fails too
|
|
fillslots_url = '/api/agenda/%s/fillslots/' % meeting_type.agenda.slug
|
|
resp = app.post(fillslots_url, params={'slots': two_slots})
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['reason'] == 'no more desk available' # legacy
|
|
assert resp.json['err_class'] == 'no more desk available'
|
|
assert resp.json['err_desc'] == 'no more desk available'
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-25')
|
|
def test_datetimes_api_meetings_agenda_exclude_slots(app):
|
|
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()
|
|
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')
|
|
event2 = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
start_datetime=localtime(tomorrow).replace(hour=10, minute=0),
|
|
desk=desk,
|
|
)
|
|
cancelled = Booking.objects.create(event=event2, user_external_id='35')
|
|
cancelled.cancel()
|
|
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug))
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '35'},
|
|
)
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '42'},
|
|
)
|
|
assert len(ctx.captured_queries) == 9
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'foo-bar:2021-02-26-0930'
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-25')
|
|
def test_datetimes_api_meetings_agenda_user_external_id(app):
|
|
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()
|
|
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')
|
|
event2 = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
start_datetime=localtime(tomorrow).replace(hour=10, minute=0),
|
|
desk=desk,
|
|
)
|
|
cancelled = Booking.objects.create(event=event2, user_external_id='35')
|
|
cancelled.cancel()
|
|
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug))
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '35'},
|
|
)
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'user_external_id': '42'},
|
|
)
|
|
assert len(ctx.captured_queries) == 9
|
|
assert resp.json['data'][0]['booked_for_external_user'] is True
|
|
|
|
# mix with exclude_user_external_id
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'user_external_id': '42', 'exclude_user_external_id': '35'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'user_external_id and exclude_user_external_id have different values'
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-03-15')
|
|
def test_datetimes_api_meetings_agenda_hide_disabled(app):
|
|
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', duration=60)
|
|
start_date = now() + datetime.timedelta(days=3)
|
|
TimePeriod.objects.create(
|
|
weekday=start_date.weekday(),
|
|
start_time=datetime.time(9, 0),
|
|
end_time=datetime.time(10, 00),
|
|
desk=desk,
|
|
)
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
start_datetime=localtime(start_date).replace(hour=9, minute=0),
|
|
desk=desk,
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug))
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-03-18-0900'
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug),
|
|
params={'hide_disabled': True},
|
|
)
|
|
assert resp.json['data'] == []
|
|
|
|
|
|
def test_booking_api_meeting_different_durations_book_short(app, meetings_agenda, user):
|
|
agenda_id = meetings_agenda.id
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
|
|
meeting_type_2 = MeetingType(agenda=meetings_agenda, label='Shorter', duration=15)
|
|
meeting_type_2.save()
|
|
|
|
# get long events
|
|
resp_long = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
|
|
# book a short event
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_2.id)
|
|
event_id = resp.json['data'][0]['id']
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
|
|
assert Booking.objects.count() == 1
|
|
|
|
# the longer event at the same time shouldn't be available anymore
|
|
resp_long2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert (
|
|
len(resp_long.json['data']) == len([x for x in resp_long2.json['data'] if not x.get('disabled')]) + 1
|
|
)
|
|
assert resp_long.json['data'][1:] == [x for x in resp_long2.json['data'] if not x.get('disabled')]
|
|
|
|
|
|
def test_booking_api_meeting_different_durations_book_long(app, meetings_agenda, user):
|
|
agenda_id = meetings_agenda.id
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
|
|
meeting_type_2 = MeetingType(agenda=meetings_agenda, label='Shorter', duration=15)
|
|
meeting_type_2.save()
|
|
|
|
# get short events
|
|
resp_short = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_2.id)
|
|
|
|
# book a long event
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
event_id = resp.json['data'][0]['id']
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
|
|
assert Booking.objects.count() == 1
|
|
|
|
# this should have removed two short events
|
|
resp_short2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_2.id)
|
|
assert (
|
|
len(resp_short.json['data'])
|
|
== len([x for x in resp_short2.json['data'] if not x.get('disabled')]) + 2
|
|
)
|
|
|
|
# book another long event
|
|
event_id = resp.json['data'][10]['id']
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
|
|
assert Booking.objects.count() == 2
|
|
|
|
resp_short2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_2.id)
|
|
assert (
|
|
len(resp_short.json['data'])
|
|
== len([x for x in resp_short2.json['data'] if not x.get('disabled')]) + 4
|
|
)
|
|
|
|
|
|
def test_agenda_meeting_next_day(app, meetings_agenda, mock_now, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
agenda = Agenda(label='Foo', kind='meetings')
|
|
agenda.minimal_booking_delay = 1
|
|
agenda.maximal_booking_delay = 15
|
|
agenda.save()
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Blah', duration=30)
|
|
datetime_url = '/api/agenda/meetings/%s/datetimes/' % meeting_type.id
|
|
desk = Desk.objects.create(label='foo', agenda=agenda)
|
|
for weekday in range(7):
|
|
TimePeriod.objects.create(
|
|
weekday=weekday, start_time=datetime.time(11, 0), end_time=datetime.time(12, 30), desk=desk
|
|
)
|
|
resp = app.get(datetime_url)
|
|
event_data = resp.json['data'][0]
|
|
# check all proposed dates are on the next day
|
|
tomorrow = mock_now + datetime.timedelta(days=1)
|
|
event_datetime = datetime.datetime.strptime(event_data['datetime'], '%Y-%m-%d %H:%M:%S').timetuple()
|
|
assert event_datetime[:3] == tomorrow.timetuple()[:3]
|
|
|
|
# check booking works
|
|
first_booking_url = resp.json['data'][0]['api']['fillslot_url']
|
|
assert app.post(first_booking_url).json['err'] == 0
|
|
assert app.post(first_booking_url).json['err'] == 1
|
|
|
|
last_booking_url = resp.json['data'][-1]['api']['fillslot_url']
|
|
assert app.post(last_booking_url).json['err'] == 0
|
|
assert app.post(last_booking_url).json['err'] == 1
|
|
|
|
# check full datetimes are marked as disabled
|
|
resp = app.get(datetime_url)
|
|
assert resp.json['data'][0]['disabled']
|
|
assert not resp.json['data'][1]['disabled']
|
|
assert resp.json['data'][-1]['disabled']
|
|
assert not resp.json['data'][-2]['disabled']
|
|
|
|
|
|
def test_agenda_meeting_api_exception(app, meetings_agenda, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
desk = meetings_agenda.desk_set.first()
|
|
# test exception at the lowest limit
|
|
excp1 = TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 4
|
|
|
|
# test exception at the highest limit
|
|
excp1.end_datetime = make_aware(datetime.datetime(2017, 5, 22, 11, 0))
|
|
excp1.save()
|
|
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 2
|
|
|
|
# add an exception with an end datetime less than excp1 end datetime
|
|
# and make sure that excp1 end datetime preveil
|
|
excp1.end_datetime = make_aware(datetime.datetime(2017, 5, 23, 11, 0))
|
|
excp1.save()
|
|
|
|
TimePeriodException.objects.create(
|
|
desk=excp1.desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 15, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 23, 9, 0)),
|
|
)
|
|
|
|
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 6
|
|
|
|
# cover completely to test limit condition in get_all_slots()
|
|
full_coverage = TimePeriodException.objects.create(
|
|
desk=excp1.desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 1, 1, 0, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 1, 0, 0)),
|
|
)
|
|
resp21 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp21.json['data']) == 0
|
|
full_coverage.delete()
|
|
|
|
# with a second desk
|
|
desk2 = Desk.objects.create(label='Desk 2', agenda=meetings_agenda)
|
|
time_period = desk.timeperiod_set.first()
|
|
TimePeriod.objects.create(
|
|
desk=desk2,
|
|
start_time=time_period.start_time,
|
|
end_time=time_period.end_time,
|
|
weekday=time_period.weekday,
|
|
)
|
|
resp3 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp3.json['data']) + 2 # +2 because excp1 changed
|
|
|
|
# try to booking just after an exception is set
|
|
TimePeriodException.objects.create(
|
|
desk=desk2,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 9, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
booking_url = resp3.json['data'][0]['api']['fillslot_url']
|
|
resp = app.post(booking_url)
|
|
assert resp.json['err'] == 1
|
|
|
|
|
|
def test_agenda_meeting_api_in_between_exceptions(app, meetings_agenda, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
desk = meetings_agenda.desk_set.first()
|
|
# test exception at the lowest limit
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 4
|
|
# exclude slots on 2017-05-30 and 2017-07-10
|
|
date_2017_05_30 = datetime.datetime(2017, 5, 30).date()
|
|
date_2017_07_10 = datetime.datetime(2017, 7, 10).date()
|
|
count_on_2017_05_30 = len(
|
|
[
|
|
datum
|
|
for datum in resp.json['data']
|
|
if datetime_from_str(datum['datetime']).date() == date_2017_05_30
|
|
]
|
|
)
|
|
count_on_2017_07_10 = len(
|
|
[
|
|
datum
|
|
for datum in resp.json['data']
|
|
if datetime_from_str(datum['datetime']).date() == date_2017_07_10
|
|
]
|
|
)
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 30, 8, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 30, 18, 0)),
|
|
)
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 7, 10, 8, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 7, 10, 18, 0)),
|
|
)
|
|
resp3 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp2.json['data']) == len(resp3.json['data']) + count_on_2017_05_30 + count_on_2017_07_10
|
|
assert (
|
|
len(
|
|
[
|
|
datum
|
|
for datum in resp3.json['data']
|
|
if datetime_from_str(datum['datetime']).date() == date_2017_05_30
|
|
]
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
len(
|
|
[
|
|
datum
|
|
for datum in resp3.json['data']
|
|
if datetime_from_str(datum['datetime']).date() == date_2017_07_10
|
|
]
|
|
)
|
|
== 0
|
|
)
|
|
# with a second desk with the same time periods
|
|
desk2 = Desk.objects.create(label='Desk 2', agenda=meetings_agenda)
|
|
for time_period in desk.timeperiod_set.all():
|
|
TimePeriod.objects.create(
|
|
desk=desk2,
|
|
start_time=time_period.start_time,
|
|
end_time=time_period.end_time,
|
|
weekday=time_period.weekday,
|
|
)
|
|
resp4 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
assert len(resp.json['data']) == len(resp4.json['data'])
|
|
|
|
|
|
def test_agenda_meeting_api_desk_info(app, meetings_agenda, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
desk = meetings_agenda.desk_set.get(slug='desk-1')
|
|
desk2 = Desk.objects.create(label='Desk 2', agenda=meetings_agenda)
|
|
for time_period in desk.timeperiod_set.all():
|
|
TimePeriod.objects.create(
|
|
desk=desk2,
|
|
start_time=time_period.start_time,
|
|
end_time=time_period.end_time,
|
|
weekday=time_period.weekday,
|
|
)
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
|
booking_url = resp.json['data'][0]['api']['fillslot_url']
|
|
booking_url2 = resp.json['data'][3]['api']['fillslot_url']
|
|
resp = app.post(booking_url)
|
|
assert resp.json['desk']['label'] == desk.label
|
|
assert resp.json['desk']['slug'] == desk.slug
|
|
# book the same slot and make sure desk 2 info are returned
|
|
resp = app.post(booking_url)
|
|
assert resp.json['desk']['label'] == desk2.label
|
|
assert resp.json['desk']['slug'] == desk2.slug
|
|
# booking slot 3 and make sure desk 1 info are returned
|
|
resp = app.post(booking_url2)
|
|
assert resp.json['desk']['label'] == desk.label
|
|
assert resp.json['desk']['slug'] == desk.slug
|
|
|
|
|
|
@pytest.mark.freeze_time('2017-05-20')
|
|
def test_agenda_meeting_gcd_durations(app, user):
|
|
meetings_agenda = Agenda.objects.create(
|
|
label='Foo bar Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=8
|
|
)
|
|
meeting_type_30 = MeetingType.objects.create(agenda=meetings_agenda, label='Blah', duration=30)
|
|
desk = Desk.objects.create(agenda=meetings_agenda, label='Desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(13, 0),
|
|
desk=desk,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(17, 0),
|
|
desk=desk,
|
|
)
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.pk)
|
|
assert len(resp.json['data']) == 20
|
|
|
|
meeting_type_20 = MeetingType.objects.create(agenda=meetings_agenda, label='Lorem', duration=20)
|
|
|
|
assert meetings_agenda.get_base_meeting_duration() == 10
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.id)
|
|
assert len(resp.json['data']) == 56
|
|
# 16:30 is time period end time (17:00) minus meeting type duration
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-23 16:30:00'
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_20.id)
|
|
assert len(resp.json['data']) == 58
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-23 16:40:00'
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.id)
|
|
event_id = resp.json['data'][0]['id']
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
app.post('/api/agenda/%s/fillslot/%s/' % (meetings_agenda.id, event_id))
|
|
assert Booking.objects.count() == 1
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_20.id)
|
|
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 55
|
|
event_id = [x for x in resp.json['data'] if not x.get('disabled')][0]['id']
|
|
resp = app.post('/api/agenda/%s/fillslot/%s/' % (meetings_agenda.id, event_id))
|
|
assert resp.json['datetime'] == '2017-05-22 10:30:00'
|
|
assert Booking.objects.count() == 2
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.id)
|
|
event_id = [x for x in resp.json['data'] if not x.get('disabled')][0]['id']
|
|
resp = app.post('/api/agenda/%s/fillslot/%s/' % (meetings_agenda.id, event_id))
|
|
assert resp.json['datetime'] == '2017-05-22 10:50:00'
|
|
assert Booking.objects.count() == 3
|
|
|
|
# create a gap
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.id)
|
|
event_id = [x for x in resp.json['data'] if not x.get('disabled')][1]['id']
|
|
resp = app.post('/api/agenda/%s/fillslot/%s/' % (meetings_agenda.id, event_id))
|
|
assert resp.json['datetime'] == '2017-05-22 11:30:00'
|
|
assert Booking.objects.count() == 4
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_20.id)
|
|
assert [x for x in resp.json['data'] if not x.get('disabled')][0]['datetime'].startswith(
|
|
'2017-05-22 12:00:00'
|
|
)
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_30.id)
|
|
assert [x for x in resp.json['data'] if not x.get('disabled')][0]['datetime'].startswith(
|
|
'2017-05-22 12:00:00'
|
|
)
|
|
|
|
|
|
@pytest.mark.freeze_time('2017-05-20')
|
|
def test_agenda_meeting_gcd_durations_and_exceptions(app, user):
|
|
meetings_agenda = Agenda.objects.create(
|
|
label='Foo bar Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=3
|
|
)
|
|
desk = Desk.objects.create(agenda=meetings_agenda, label='Desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(17, 0),
|
|
desk=desk,
|
|
)
|
|
meeting_type_20 = MeetingType.objects.create(agenda=meetings_agenda, label='Blah 20', duration=20)
|
|
meeting_type_40 = MeetingType.objects.create(agenda=meetings_agenda, label='Blah 40', duration=40)
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_20.id)
|
|
assert len(resp.json['data']) == 6
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_40.id)
|
|
assert len(resp.json['data']) == 5
|
|
|
|
# exception to just leave enough place for a single 20-minutes meeting.
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 20)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_20.id)
|
|
assert len(resp.json['data']) == 1
|
|
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type_40.id)
|
|
assert len(resp.json['data']) == 0
|
|
|
|
|
|
def test_agenda_meeting_deleted_meetingtype(app, meetings_agenda, user):
|
|
MeetingType.objects.all().delete()
|
|
meeting_type = MeetingType.objects.create(
|
|
agenda=meetings_agenda, label='Blah 20', duration=20, deleted=True
|
|
)
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (meetings_agenda.slug, meeting_type.slug), status=404
|
|
)
|
|
|
|
meeting_type.deleted = False
|
|
meeting_type.save()
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (meetings_agenda.slug, meeting_type.slug))
|
|
data = resp.json['data']
|
|
assert len(data) == 216
|
|
|
|
# try to book if disabled
|
|
meeting_type.deleted = True
|
|
meeting_type.save()
|
|
|
|
fillslot_url = data[0]['api']['fillslot_url']
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp_booking = app.post(fillslot_url, status=400)
|
|
assert 'invalid meeting type id' in resp_booking.json['err_desc']
|
|
|
|
|
|
def test_datetimes_api_meetings_agenda_start_hour_change(app, meetings_agenda):
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meeting_type.agenda.slug, meeting_type.slug)
|
|
|
|
resp = app.get(api_url)
|
|
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event(
|
|
agenda=meetings_agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=Desk.objects.first(),
|
|
)
|
|
ev.save()
|
|
booking = Booking(event=ev)
|
|
booking.save()
|
|
|
|
resp = app.get(api_url)
|
|
assert len([x for x in resp.json['data'] if x['disabled']]) == 1
|
|
|
|
desk = Desk.objects.get(label='Desk 1')
|
|
# shift opening times by 15 minutes
|
|
for timeperiod in desk.timeperiod_set.all():
|
|
timeperiod.start_time = timeperiod.start_time.replace(minute=15)
|
|
timeperiod.end_time = timeperiod.end_time.replace(minute=15)
|
|
timeperiod.save()
|
|
|
|
# two slots should now be marked as disabled as the previous booking spans
|
|
# them.
|
|
resp = app.get(api_url)
|
|
assert len([x for x in resp.json['data'] if x['disabled']]) == 2
|
|
|
|
|
|
def test_virtual_agendas_meetings_datetimes_api(app, virtual_meetings_agenda):
|
|
real_agenda = virtual_meetings_agenda.real_agendas.first()
|
|
meeting_type = real_agenda.meetingtype_set.first()
|
|
default_desk = real_agenda.desk_set.first()
|
|
# Unkown meeting
|
|
app.get('/api/agenda/%s/meetings/xxx/datetimes/' % virtual_meetings_agenda.slug, status=404)
|
|
|
|
virt_meeting_type = virtual_meetings_agenda.iter_meetingtypes()[0]
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_meetings_agenda.slug, virt_meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 144
|
|
|
|
# cover completely to test limit condition in get_all_slots()
|
|
full_coverage = TimePeriodException.objects.create(
|
|
desk=default_desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 1, 1, 0, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 1, 1, 0, 0)),
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 0
|
|
full_coverage.delete()
|
|
|
|
virtual_meetings_agenda.minimal_booking_delay = 7
|
|
virtual_meetings_agenda.maximal_booking_delay = 28
|
|
virtual_meetings_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 54
|
|
|
|
virtual_meetings_agenda.minimal_booking_delay = 1
|
|
virtual_meetings_agenda.maximal_booking_delay = 56
|
|
virtual_meetings_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 144
|
|
|
|
resp = app.get(api_url)
|
|
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event(
|
|
agenda=real_agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=default_desk,
|
|
)
|
|
ev.save()
|
|
booking = Booking(event=ev)
|
|
booking.save()
|
|
resp2 = app.get(api_url)
|
|
assert len(resp2.json['data']) == 144
|
|
assert resp.json['data'][0] == resp2.json['data'][0]
|
|
assert resp.json['data'][1] == resp2.json['data'][1]
|
|
assert resp.json['data'][2] != resp2.json['data'][2]
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
assert resp2.json['data'][2]['disabled'] is True
|
|
assert resp.json['data'][3] == resp2.json['data'][3]
|
|
|
|
# test with a timeperiod overlapping current moment, it should get one
|
|
# datetime for the current timeperiod + two from the next week.
|
|
if localtime(now()).time().hour == 23:
|
|
# skip this part of the test as it would require support for events
|
|
# crossing midnight
|
|
return
|
|
|
|
TimePeriod.objects.filter(desk=default_desk).delete()
|
|
start_time = localtime(now()) - datetime.timedelta(minutes=10)
|
|
time_period = TimePeriod(
|
|
weekday=localtime(now()).weekday(),
|
|
start_time=start_time,
|
|
end_time=start_time + datetime.timedelta(hours=1),
|
|
desk=default_desk,
|
|
)
|
|
time_period.save()
|
|
virtual_meetings_agenda.minimal_booking_delay = 0
|
|
virtual_meetings_agenda.maximal_booking_delay = 10
|
|
virtual_meetings_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 3
|
|
|
|
|
|
def test_virtual_agendas_meetings_datetimes_api_with_similar_desk(app):
|
|
agenda_foo = Agenda.objects.create(
|
|
label='Agenda Foo', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=4
|
|
)
|
|
MeetingType.objects.create(agenda=agenda_foo, label='Meeting Type', duration=30)
|
|
test_1st_weekday = (localtime(now()).weekday() + 1) % 7
|
|
test_2nd_weekday = (localtime(now()).weekday() + 2) % 7
|
|
test_3rd_weekday = (localtime(now()).weekday() + 3) % 7
|
|
|
|
desk_foo = Desk.objects.create(agenda=agenda_foo, label='Desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_foo,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=test_2nd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_foo,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=test_3rd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_foo,
|
|
)
|
|
|
|
agenda_bar = Agenda.objects.create(
|
|
label='Agenda Bar', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=4
|
|
)
|
|
meeting_type_bar = MeetingType.objects.create(agenda=agenda_bar, label='Meeting Type', duration=30)
|
|
desk_bar = Desk.objects.create(agenda=agenda_bar, label='Desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_bar,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=test_2nd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_bar,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=test_3rd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_bar,
|
|
)
|
|
|
|
virtual_agenda = Agenda.objects.create(
|
|
label='Agenda Virtual', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=4
|
|
)
|
|
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_foo)
|
|
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_bar)
|
|
|
|
# 4 slots each day * 3 days
|
|
foo_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda_foo.slug, meeting_type_bar.slug)
|
|
resp = app.get(foo_api_url)
|
|
assert len(resp.json['data']) == 12
|
|
# same thing bar agenda
|
|
bar_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda_foo.slug, meeting_type_bar.slug)
|
|
resp = app.get(bar_api_url)
|
|
assert len(resp.json['data']) == 12
|
|
# same thing on the virtual agenda
|
|
virtual_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type_bar.slug)
|
|
resp = app.get(virtual_api_url)
|
|
assert len(resp.json['data']) == 12
|
|
|
|
# exclude first day
|
|
start = (localtime(now()) + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
end = (localtime(now()) + datetime.timedelta(days=1)).replace(
|
|
hour=23, minute=59, second=59, microsecond=0
|
|
)
|
|
TimePeriodException.objects.create(start_datetime=start, end_datetime=end, desk=desk_foo)
|
|
TimePeriodException.objects.create(start_datetime=start, end_datetime=end, desk=desk_bar)
|
|
# exclude second day
|
|
start = (localtime(now()) + datetime.timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
end = (localtime(now()) + datetime.timedelta(days=2)).replace(
|
|
hour=23, minute=59, second=59, microsecond=0
|
|
)
|
|
TimePeriodException.objects.create(start_datetime=start, end_datetime=end, desk=desk_foo)
|
|
TimePeriodException.objects.create(start_datetime=start, end_datetime=end, desk=desk_bar)
|
|
|
|
# 4 slots each day * 1 day
|
|
resp = app.get(foo_api_url)
|
|
assert len(resp.json['data']) == 4
|
|
# same thing bar agenda
|
|
resp = app.get(bar_api_url)
|
|
assert len(resp.json['data']) == 4
|
|
# same thing on the virtual agenda
|
|
resp = app.get(virtual_api_url)
|
|
assert len(resp.json['data']) == 4
|
|
|
|
|
|
def test_virtual_agendas_meetings_datetimes_delays_api(app, mock_now):
|
|
foo_agenda = Agenda.objects.create(label='Foo Meeting', kind='meetings', maximal_booking_delay=7)
|
|
MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
|
|
foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
|
|
bar_agenda = Agenda.objects.create(label='Bar Meeting', kind='meetings', maximal_booking_delay=7)
|
|
MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
|
|
bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=2,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=3,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
|
|
virt_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
|
|
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
|
|
virt_meeting_type = virt_agenda.iter_meetingtypes()[0]
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, virt_meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
# 8 slots for m each agenda
|
|
assert len(resp.json['data']) == 16
|
|
|
|
# restrict foo's minimal_booking_delay : only bar's slots are left
|
|
foo_agenda.minimal_booking_delay = 6
|
|
foo_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 8
|
|
|
|
# restrict bar's maximal_booking_delay : only half of bar's slots are left
|
|
bar_agenda.maximal_booking_delay = 5
|
|
bar_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
|
|
# put back very slots from foo
|
|
foo_agenda.minimal_booking_delay = 1
|
|
foo_agenda.maximal_booking_delay = 7
|
|
foo_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
|
|
|
|
def test_virtual_agendas_meetings_datetimes_exluded_periods(app, mock_now):
|
|
foo_agenda = Agenda.objects.create(label='Foo Meeting', kind='meetings', maximal_booking_delay=7)
|
|
MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
|
|
foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
virt_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
|
|
|
|
api_url = '/api/agenda/%s/meetings/meeting-type/datetimes/' % (virt_agenda.slug)
|
|
resp = app.get(api_url)
|
|
# 8 slots
|
|
data = resp.json['data']
|
|
assert len(data) == 8
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
assert data[2]['datetime'] == '2017-05-22 11:00:00'
|
|
|
|
# exclude one hour the first day
|
|
tp1 = TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0), agenda=virt_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 6
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
# no more slots the 22 thanks to the exclusion period
|
|
assert data[2]['datetime'] == '2017-05-23 10:00:00'
|
|
|
|
# exclude the second day
|
|
tp2 = TimePeriod.objects.create(
|
|
weekday=1, start_time=datetime.time(9, 0), end_time=datetime.time(18, 0), agenda=virt_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
|
|
# go back to no restriction
|
|
tp1.delete()
|
|
tp2.delete()
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 8
|
|
|
|
# excluded period applies to every desk
|
|
foo_desk_2 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 2')
|
|
TimePeriod.objects.create(
|
|
weekday=3,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_2,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=4,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_2,
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 16
|
|
|
|
# exclude one hour the first day
|
|
tp1 = TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0), agenda=virt_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 14
|
|
|
|
# exclude one hour the last day
|
|
tp2 = TimePeriod.objects.create(
|
|
weekday=4, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0), agenda=virt_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 12
|
|
|
|
# go back to no restriction
|
|
tp1.delete()
|
|
tp2.delete()
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 16
|
|
|
|
# add a second real agenda
|
|
bar_agenda = Agenda.objects.create(label='Bar Meeting', kind='meetings', maximal_booking_delay=7)
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
|
|
MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
|
|
bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
|
|
bar_desk_2 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 2')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(14, 0),
|
|
end_time=datetime.time(16, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(14, 0),
|
|
end_time=datetime.time(16, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=2,
|
|
start_time=datetime.time(14, 0),
|
|
end_time=datetime.time(16, 0),
|
|
desk=bar_desk_2,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=3,
|
|
start_time=datetime.time(14, 0),
|
|
end_time=datetime.time(16, 0),
|
|
desk=bar_desk_2,
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 32
|
|
|
|
# exclude the first day, 11 to 15 : 4 slots
|
|
tp1 = TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(11, 0), end_time=datetime.time(15, 0), agenda=virt_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 28
|
|
|
|
|
|
def test_virtual_agendas_meetings_exception(app, user, virtual_meetings_agenda):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
real_agenda = virtual_meetings_agenda.real_agendas.first()
|
|
desk = real_agenda.desk_set.first()
|
|
virt_meeting_type = virtual_meetings_agenda.iter_meetingtypes()[0]
|
|
datetimes_url = '/api/agenda/%s/meetings/%s/datetimes/' % (
|
|
virtual_meetings_agenda.slug,
|
|
virt_meeting_type.slug,
|
|
)
|
|
resp = app.get(datetimes_url)
|
|
|
|
# test exception at the lowest limit
|
|
excp1 = TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
resp2 = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 4
|
|
|
|
# test exception at the highest limit
|
|
excp1.end_datetime = make_aware(datetime.datetime(2017, 5, 22, 11, 0))
|
|
excp1.save()
|
|
resp2 = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 2
|
|
|
|
# add an exception with an end datetime less than excp1 end datetime
|
|
# and make sure that excp1 end datetime preveil
|
|
excp1.end_datetime = make_aware(datetime.datetime(2017, 5, 23, 11, 0))
|
|
excp1.save()
|
|
|
|
TimePeriodException.objects.create(
|
|
desk=excp1.desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 15, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 23, 9, 0)),
|
|
)
|
|
|
|
resp2 = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 6
|
|
|
|
# with a second desk
|
|
desk2 = Desk.objects.create(label='Desk 2', agenda=real_agenda)
|
|
time_period = desk.timeperiod_set.first()
|
|
TimePeriod.objects.create(
|
|
desk=desk2,
|
|
start_time=time_period.start_time,
|
|
end_time=time_period.end_time,
|
|
weekday=time_period.weekday,
|
|
)
|
|
resp3 = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == len(resp3.json['data']) + 2 # +2 because excp1 changed
|
|
|
|
|
|
def test_virtual_agendas_meetings_datetimes_multiple_agendas(app, mock_now):
|
|
foo_agenda = Agenda.objects.create(
|
|
label='Foo Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=5
|
|
)
|
|
foo_meeting_type = MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
|
|
foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
|
|
|
|
test_1st_weekday = (localtime(now()).weekday() + 2) % 7
|
|
test_2nd_weekday = (localtime(now()).weekday() + 3) % 7
|
|
test_3rd_weekday = (localtime(now()).weekday() + 4) % 7
|
|
test_4th_weekday = (localtime(now()).weekday() + 5) % 7
|
|
|
|
def create_time_perdiods(desk, end=12):
|
|
TimePeriod.objects.create(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(end, 0),
|
|
desk=desk,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=test_2nd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(end, 0),
|
|
desk=desk,
|
|
)
|
|
|
|
create_time_perdiods(foo_desk_1)
|
|
virt_agenda = Agenda.objects.create(
|
|
label='Virtual Agenda', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=6
|
|
)
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
|
|
virt_meeting_type = virt_agenda.iter_meetingtypes()[0]
|
|
|
|
# We are saturday and we can book for next monday and tuesday, 4 slots available each day
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, virt_meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 8
|
|
assert resp.json['data'][0]['id'] == 'meeting-type:2017-05-22-1000'
|
|
|
|
virt_agenda.maximal_booking_delay = 10 # another monday comes in
|
|
virt_agenda.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
|
|
# Back to next monday and tuesday restriction
|
|
virt_agenda.maximal_booking_delay = 6
|
|
virt_agenda.save()
|
|
|
|
# Add another agenda
|
|
bar_agenda = Agenda.objects.create(
|
|
label='Bar Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=5
|
|
)
|
|
bar_meeting_type = MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
|
|
bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
|
|
create_time_perdiods(bar_desk_1, end=13) # bar_agenda has two more slots each day
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
assert len(ctx.captured_queries) == 10
|
|
|
|
# simulate booking
|
|
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event.objects.create(
|
|
agenda=foo_agenda,
|
|
meeting_type=foo_meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=foo_desk_1,
|
|
)
|
|
booking1 = Booking.objects.create(event=ev)
|
|
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
# No disabled slot, because the booked slot is still available in second agenda
|
|
for slot in resp.json['data']:
|
|
assert slot['disabled'] is False
|
|
|
|
ev = Event.objects.create(
|
|
agenda=bar_agenda,
|
|
meeting_type=bar_meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=bar_desk_1,
|
|
)
|
|
booking2 = Booking.objects.create(event=ev)
|
|
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
# now one slot is disabled
|
|
for i, slot in enumerate(resp.json['data']):
|
|
if i == 2:
|
|
assert slot['disabled']
|
|
else:
|
|
assert slot['disabled'] is False
|
|
|
|
# Cancel booking, every slot available
|
|
booking1.cancel()
|
|
booking2.cancel()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
for slot in resp.json['data']:
|
|
assert slot['disabled'] is False
|
|
|
|
# Add new desk on foo_agenda, open on wednesday
|
|
foo_desk_2 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 2')
|
|
TimePeriod.objects.create(
|
|
weekday=test_3rd_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_2,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 16
|
|
|
|
# Add new desk on bar_agenda, open on thursday
|
|
bar_desk_2 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 2')
|
|
TimePeriod.objects.create(
|
|
weekday=test_4th_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_2,
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 20
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-25')
|
|
def test_virtual_agendas_meetings_datetimes_exclude_slots(app):
|
|
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()
|
|
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)
|
|
|
|
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')
|
|
event2 = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
start_datetime=localtime(tomorrow).replace(hour=10, minute=0),
|
|
desk=desk,
|
|
)
|
|
cancelled = Booking.objects.create(event=event2, user_external_id='35')
|
|
cancelled.cancel()
|
|
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, meeting_type.slug))
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '35'},
|
|
)
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '42'},
|
|
)
|
|
assert len(ctx.captured_queries) == 11
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
virt_agenda.minimal_booking_delay = None
|
|
virt_agenda.maximal_booking_delay = None
|
|
virt_agenda.save()
|
|
resp = app.get(
|
|
'/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, meeting_type.slug),
|
|
params={'exclude_user_external_id': '42'},
|
|
)
|
|
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
|
|
|
|
@pytest.mark.freeze_time('2017-05-21')
|
|
def test_unavailabilitycalendar_meetings_datetimes(app, user):
|
|
meetings_agenda = Agenda.objects.create(label='Meeting', kind='meetings', maximal_booking_delay=7)
|
|
desk = Desk.objects.create(agenda=meetings_agenda, label='desk 1')
|
|
meeting_type = MeetingType.objects.create(agenda=meetings_agenda, label='Meeting Type', duration=30)
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(9, 0),
|
|
end_time=datetime.time(18, 0),
|
|
desk=desk,
|
|
)
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
datetimes_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meetings_agenda.slug, meeting_type.slug)
|
|
resp = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == 18
|
|
|
|
# create an unvalailability calendar
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='foo holydays')
|
|
TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 11, 0)),
|
|
)
|
|
unavailability_calendar.desks.add(desk)
|
|
# link unavailability calendar to a desk of another agenda
|
|
other_agenda = Agenda.objects.create(label='Meeting 2', kind='meetings', maximal_booking_delay=7)
|
|
other_desk = Desk.objects.create(agenda=other_agenda, label='desk 1')
|
|
unavailability_calendar.desks.add(other_desk)
|
|
unavailability_calendar2 = UnavailabilityCalendar.objects.create(label='bar holydays')
|
|
unavailability_calendar2.desks.add(desk)
|
|
|
|
# 2 slots are gone
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp2 = app.get(datetimes_url)
|
|
assert len(ctx.captured_queries) == 10
|
|
assert len(resp.json['data']) == len(resp2.json['data']) + 2
|
|
|
|
# add a standard desk exception
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 11, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
# 4 slots are gone
|
|
resp3 = app.get(datetimes_url)
|
|
assert len(resp.json['data']) == len(resp3.json['data']) + 4
|
|
|
|
|
|
def test_unavailabilitycalendar_on_virtual_datetimes(app, user, mock_now):
|
|
foo_agenda = Agenda.objects.create(label='Foo Meeting', kind='meetings', maximal_booking_delay=7)
|
|
MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
|
|
foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=foo_desk_1,
|
|
)
|
|
virt_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
|
|
|
|
api_url = '/api/agenda/%s/meetings/meeting-type/datetimes/' % (virt_agenda.slug)
|
|
resp = app.get(api_url)
|
|
# 8 slots
|
|
data = resp.json['data']
|
|
assert len(data) == 8
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
assert data[2]['datetime'] == '2017-05-22 11:00:00'
|
|
|
|
# exclude one hour the first day through an unvalailability calendar on the foo agenda
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='foo holydays')
|
|
TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 11, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
unavailability_calendar.desks.add(foo_desk_1)
|
|
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 6
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
# no more slots the 22 thanks to the unavailability calendar
|
|
assert data[2]['datetime'] == '2017-05-23 10:00:00'
|
|
|
|
# exclude the second day
|
|
TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 23, 9, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 23, 18, 0)),
|
|
)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[1]['datetime'] == '2017-05-22 10:30:00'
|
|
|
|
# add a second real agenda
|
|
bar_agenda = Agenda.objects.create(label='Bar Meeting', kind='meetings', maximal_booking_delay=7)
|
|
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
|
|
MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
|
|
bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
|
|
bar_desk_2 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 2')
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_1,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_2,
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=1,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=bar_desk_2,
|
|
)
|
|
|
|
# bar_agenda has the same time periods than foo_agenda, but no unavailability calendar
|
|
# so we are back at the start : 8 slots
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 8
|
|
|
|
# exclude one hour the second day through another unvalailability calendar on the bar agenda
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='bar holydays')
|
|
TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 23, 11, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 23, 12, 0)),
|
|
)
|
|
unavailability_calendar.desks.add(bar_desk_1, bar_desk_2)
|
|
|
|
# 2 slots are gone
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 6
|
|
assert data[0]['datetime'] == '2017-05-22 10:00:00'
|
|
assert data[-1]['datetime'] == '2017-05-23 10:30:00'
|
|
|
|
|
|
@pytest.mark.parametrize('test_datetime', (None, '2020-11-11 23:50', '2020-12-06 10:14'))
|
|
def test_datetimes_maximal_booking_delay(app, user, freezer, test_datetime):
|
|
if test_datetime:
|
|
freezer.move_to(test_datetime)
|
|
foo_agenda = Agenda.objects.create(
|
|
label='Foo Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=1
|
|
)
|
|
MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
|
|
foo_desk = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
|
|
weekday1 = ((localtime(now())).weekday() + 1) % 7
|
|
weekday2 = ((localtime(now())).weekday() + 2) % 7
|
|
TimePeriod.objects.create(
|
|
weekday=weekday1, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=weekday2, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk
|
|
)
|
|
|
|
api_url = '/api/agenda/%s/meetings/meeting-type/datetimes/' % (foo_agenda.slug)
|
|
resp = app.get(api_url)
|
|
# minimal_booking_delay=1 and maximal_booking_delay=1 so no slots
|
|
data = resp.json['data']
|
|
assert len(data) == 0
|
|
|
|
foo_agenda.maximal_booking_delay = 2
|
|
foo_agenda.save()
|
|
# 4 slots each day * 1 day (because minimal_booking_delay=1 and maximal_booking_delay=2)
|
|
resp = app.get(api_url)
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
|
|
|
|
def test_meetings_and_virtual_datetimes_date_filter(app):
|
|
agenda_foo = Agenda.objects.create(
|
|
label='Agenda Foo', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=7
|
|
)
|
|
meeting_type = MeetingType.objects.create(agenda=agenda_foo, label='Meeting Type', duration=30)
|
|
desk_foo = Desk.objects.create(agenda=agenda_foo, label='Desk 1')
|
|
weekday1 = ((localtime(now())).weekday() + 1) % 7
|
|
weekday2 = ((localtime(now())).weekday() + 2) % 7
|
|
weekday3 = ((localtime(now())).weekday() + 3) % 7
|
|
weekday4 = ((localtime(now())).weekday() + 4) % 7
|
|
weekday5 = ((localtime(now())).weekday() + 5) % 7
|
|
weekday6 = ((localtime(now())).weekday() + 6) % 7
|
|
for weekday in (weekday1, weekday2, weekday3, weekday4, weekday5, weekday6):
|
|
TimePeriod.objects.create(
|
|
weekday=weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk_foo,
|
|
)
|
|
|
|
virtual_agenda = Agenda.objects.create(
|
|
label='Agenda Virtual', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=7
|
|
)
|
|
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_foo)
|
|
|
|
# 4 slots each day * 6 days
|
|
foo_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda_foo.slug, meeting_type.slug)
|
|
resp = app.get(foo_api_url)
|
|
assert len(resp.json['data']) == 24
|
|
virtual_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
|
resp = app.get(virtual_api_url)
|
|
assert len(resp.json['data']) == 24
|
|
|
|
for value in ['foo', '2017-05-42']:
|
|
params = {'date_start': value}
|
|
resp = app.get(foo_api_url, params=params, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_start'] == [
|
|
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
|
|
]
|
|
|
|
for value in ['foo', '2017-05-42']:
|
|
params = {'date_end': value}
|
|
resp = app.get(foo_api_url, params=params, status=400)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_end'] == [
|
|
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
|
|
]
|
|
|
|
# exclude weekday1 through date_start, 4 slots each day * 5 days
|
|
params = {'date_start': localtime(now() + datetime.timedelta(days=2)).date().isoformat()}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 20
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 20
|
|
|
|
params = {
|
|
'date_start': localtime(now() + datetime.timedelta(days=2))
|
|
.replace(hour=12, minute=0, second=0, microsecond=0)
|
|
.isoformat()
|
|
}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
|
|
params = {
|
|
'date_start': localtime(now() + datetime.timedelta(days=2))
|
|
.replace(hour=11, minute=0, second=0, microsecond=0)
|
|
.isoformat()
|
|
}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 18
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 18
|
|
|
|
# minimal_booking_delay (which exclude weekday1 and wekkday2 ) takes precedence
|
|
# 4 slots each day * 4 days
|
|
agenda_foo.minimal_booking_delay = 3
|
|
agenda_foo.save()
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
# also on virtual agenda
|
|
virtual_agenda.minimal_booking_delay = 3
|
|
virtual_agenda.save()
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
|
|
# reset
|
|
agenda_foo.minimal_booking_delay = 1
|
|
virtual_agenda.minimal_booking_delay = 1
|
|
agenda_foo.save()
|
|
virtual_agenda.save()
|
|
|
|
# exclude weekday6 through date_end, 4 slots each day * 5 days
|
|
params = {'date_end': localtime(now() + datetime.timedelta(days=6)).date().isoformat()}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 20
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 20
|
|
|
|
params = {
|
|
'date_end': localtime(now() + datetime.timedelta(days=6))
|
|
.replace(hour=11, minute=0, second=0, microsecond=0)
|
|
.isoformat()
|
|
}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 22
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 22
|
|
|
|
# maximal_booking_delay (which exclude weekday5 and weekday6 ) takes precedence
|
|
# 4 slots each day * 4 days
|
|
agenda_foo.maximal_booking_delay = 5
|
|
agenda_foo.save()
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
# also on virtual agenda
|
|
virtual_agenda.maximal_booking_delay = 5
|
|
virtual_agenda.save()
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 16
|
|
|
|
# now check with exceptions in DB
|
|
TimePeriodException.objects.create(
|
|
desk=desk_foo,
|
|
start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2017, 5, 22, 12, 0)),
|
|
)
|
|
|
|
params = {
|
|
'date_start': localtime(now() + datetime.timedelta(days=2))
|
|
.replace(hour=12, minute=0, second=0, microsecond=0)
|
|
.isoformat()
|
|
}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 8
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 8
|
|
|
|
params = {
|
|
'date_end': localtime(now() + datetime.timedelta(days=2))
|
|
.replace(hour=11, minute=0, second=0, microsecond=0)
|
|
.isoformat()
|
|
}
|
|
resp = app.get(foo_api_url, params=params)
|
|
assert len(resp.json['data']) == 6
|
|
resp = app.get(virtual_api_url, params=params)
|
|
assert len(resp.json['data']) == 6
|
|
|
|
|
|
def test_datetimes_api_meetings_agenda_meta(app, freezer):
|
|
# 2017-05-20 -> saturday
|
|
freezer.move_to(make_aware(datetime.datetime(year=2017, month=5, day=20, hour=1, minute=12)))
|
|
meetings_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='meetings', maximal_booking_delay=3)
|
|
meeting_type = MeetingType(agenda=meetings_agenda, label='Blah', duration=30)
|
|
meeting_type.save()
|
|
|
|
desk1 = Desk.objects.create(agenda=meetings_agenda, label='Desk 1')
|
|
desk2 = Desk.objects.create(agenda=meetings_agenda, label='Desk 2')
|
|
test_1st_weekday = (localtime(now()).weekday() + 2) % 7
|
|
for desk in desk1, desk2:
|
|
TimePeriod(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
).save()
|
|
|
|
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meeting_type.agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 4,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
def simulate_booking(slot, desk):
|
|
dt = datetime.datetime.strptime(slot['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event(
|
|
agenda=meetings_agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=desk,
|
|
)
|
|
ev.save()
|
|
booking = Booking(event=ev, user_external_id='42')
|
|
booking.save()
|
|
|
|
simulate_booking(resp.json['meta']['first_bookable_slot'], desk1)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 4,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
resp = app.get(api_url, params={'exclude_user_external_id': '42'})
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
simulate_booking(resp.json['data'][0], desk2)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
for idx in range(1, 4):
|
|
simulate_booking(resp.json['data'][idx], desk1)
|
|
simulate_booking(resp.json['data'][idx], desk2)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': True,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 0,
|
|
'first_bookable_slot': None,
|
|
}
|
|
|
|
|
|
def test_datetimes_api_virtual_meetings_agenda_meta(app, freezer):
|
|
# 2017-05-20 -> saturday
|
|
freezer.move_to(make_aware(datetime.datetime(year=2017, month=5, day=20, hour=1, minute=12)))
|
|
meetings_agenda1 = Agenda.objects.create(label='Foo Meeting', kind='meetings', maximal_booking_delay=3)
|
|
meetings_agenda2 = Agenda.objects.create(label='Bar Meeting', kind='meetings', maximal_booking_delay=3)
|
|
virtual_agenda = Agenda.objects.create(label='Agenda Virtual', kind='virtual', maximal_booking_delay=3)
|
|
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=meetings_agenda1)
|
|
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=meetings_agenda2)
|
|
desk1 = Desk.objects.create(agenda=meetings_agenda1, label='Desk 1')
|
|
desk2 = Desk.objects.create(agenda=meetings_agenda2, label='Desk 2')
|
|
|
|
test_1st_weekday = (localtime(now()).weekday() + 2) % 7
|
|
for agenda, desk in zip((meetings_agenda1, meetings_agenda2), (desk1, desk2)):
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Blah', duration=30)
|
|
TimePeriod(
|
|
weekday=test_1st_weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
).save()
|
|
|
|
virt_meeting_type = virtual_agenda.iter_meetingtypes()[0]
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, virt_meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][2]['disabled'] is False
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 4,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
def simulate_booking(slot, agenda, desk):
|
|
dt = datetime.datetime.strptime(slot['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
|
ev = Event(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
full=False,
|
|
start_datetime=make_aware(dt),
|
|
desk=desk,
|
|
)
|
|
ev.save()
|
|
booking = Booking(event=ev, user_external_id='42')
|
|
booking.save()
|
|
|
|
simulate_booking(resp.json['data'][0], meetings_agenda1, desk1)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 4,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
resp = app.get(api_url, params={'exclude_user_external_id': '42'})
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
simulate_booking(resp.json['data'][0], meetings_agenda2, desk2)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
for idx in range(1, 4):
|
|
simulate_booking(resp.json['data'][idx], meetings_agenda1, desk1)
|
|
simulate_booking(resp.json['data'][idx], meetings_agenda2, desk2)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': True,
|
|
'bookable_datetimes_number_total': 4,
|
|
'bookable_datetimes_number_available': 0,
|
|
'first_bookable_slot': None,
|
|
}
|
|
|
|
|
|
def test_date_filter_overlapping_events(app):
|
|
# Create a meeting of 30 minutes from 09:45 to 10:15 and look for available
|
|
# 5 minutes meeting between 10:00 and 10:30, there should be only 3 if the
|
|
# exclusion from 30 minutes event is enforced.
|
|
agenda = Agenda.objects.create(label='foo', kind='meetings', minimal_booking_delay=0)
|
|
mt30 = MeetingType.objects.create(agenda=agenda, label='mt30', duration=30)
|
|
MeetingType.objects.create(agenda=agenda, label='mt5', duration=5)
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
|
|
for weekday in range(7):
|
|
TimePeriod.objects.create(
|
|
weekday=weekday,
|
|
start_time=datetime.time(10, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
)
|
|
|
|
# base_date, today at midnight
|
|
base_date = localtime(now() + datetime.timedelta(days=1))
|
|
base_date = base_date.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
def make_date(hour, minute):
|
|
return base_date.replace(hour=hour, minute=minute).strftime('%Y-%m-%d %H:%M:00')
|
|
|
|
def make_date_filters(h1, m1, h2, m2):
|
|
return {'hide_disabled': 'true', 'date_start': make_date(h1, m1), 'date_end': make_date(h2, m2)}
|
|
|
|
Event.objects.create(
|
|
agenda=agenda,
|
|
slug='wtf',
|
|
meeting_type=mt30,
|
|
start_datetime=base_date.replace(hour=9, minute=45),
|
|
full=False,
|
|
places=1,
|
|
desk=desk,
|
|
)
|
|
|
|
resp = app.get('/api/agenda/foo/meetings/mt5/datetimes/', params=make_date_filters(10, 0, 10, 30))
|
|
assert len(resp.json['data']) == 3
|
|
|
|
|
|
def test_virtual_agendas_time_change(app, freezer):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar Meeting', kind='meetings', minimal_booking_delay=10, maximal_booking_delay=20
|
|
)
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Blah', duration=15)
|
|
desk, _ = Desk.objects.get_or_create(agenda=agenda, label='Desk 1')
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2022, 4, 4, 8, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2022, 4, 4, 12, 0)),
|
|
)
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(8, 30),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
)
|
|
dt = datetime.datetime.strptime('2022-03-28-08:30', '%Y-%m-%d-%H:%M')
|
|
ev = Event.objects.create(
|
|
agenda=agenda,
|
|
meeting_type=meeting_type,
|
|
places=1,
|
|
start_datetime=make_aware(dt),
|
|
desk=desk,
|
|
)
|
|
Booking.objects.create(event=ev)
|
|
|
|
freezer.move_to(make_aware(datetime.datetime(2022, 3, 8, 7, 0)))
|
|
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
for slot in resp.json['data']:
|
|
if slot['datetime'] == '2022-03-28 08:30:00':
|
|
assert False, 'slot should not appear due to maximal_booking_delay'
|
|
|
|
# now got through virtual agenda
|
|
virtual_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='virtual')
|
|
virtual_agenda.real_agendas.add(agenda)
|
|
assert virtual_agenda.minimal_booking_delay is None
|
|
assert virtual_agenda.maximal_booking_delay is None
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
for slot in resp.json['data']:
|
|
if slot['datetime'] == '2022-03-28 08:30:00':
|
|
assert (
|
|
False
|
|
), 'slot should not appear due to maximal_booking_delay of the real agenda (and no maximal_booking_delay) is defined on the real agenda'
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-01-20 14:00') # Thursday
|
|
def test_datetimes_api_meetings_agenda_weekday_indexes(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=60
|
|
)
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
|
|
time_period = TimePeriod.objects.create(
|
|
weekday=3, # Thursday
|
|
start_time=datetime.time(11, 0),
|
|
end_time=datetime.time(12, 0),
|
|
desk=desk,
|
|
)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
|
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 16
|
|
assert [x['datetime'] for x in resp.json['data']][:6] == [
|
|
'2022-01-27 11:00:00',
|
|
'2022-01-27 11:30:00',
|
|
'2022-02-03 11:00:00',
|
|
'2022-02-03 11:30:00',
|
|
'2022-02-10 11:00:00',
|
|
'2022-02-10 11:30:00',
|
|
]
|
|
every_weeks_resp = resp
|
|
|
|
time_period.weekday_indexes = [1]
|
|
time_period.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-03 11:00:00',
|
|
'2022-02-03 11:30:00',
|
|
'2022-03-03 11:00:00',
|
|
'2022-03-03 11:30:00',
|
|
]
|
|
|
|
time_period.weekday_indexes = [1, 3]
|
|
time_period.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 8
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-03 11:00:00',
|
|
'2022-02-03 11:30:00',
|
|
'2022-02-17 11:00:00',
|
|
'2022-02-17 11:30:00',
|
|
'2022-03-03 11:00:00',
|
|
'2022-03-03 11:30:00',
|
|
'2022-03-17 11:00:00',
|
|
'2022-03-17 11:30:00',
|
|
]
|
|
|
|
time_period.weekday_indexes = [1, 2, 3, 4, 5]
|
|
time_period.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json == every_weeks_resp.json
|
|
|
|
# there are five Mondays this month
|
|
time_period.weekday = 0
|
|
time_period.weekday_indexes = [5]
|
|
time_period.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 2
|
|
assert [x['datetime'] for x in resp.json['data']] == ['2022-01-31 11:00:00', '2022-01-31 11:30:00']
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-01-20 14:00') # Thursday
|
|
def test_datetimes_api_meetings_virtual_agenda_weekday_indexes(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=60
|
|
)
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
|
virtual_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='virtual')
|
|
virtual_agenda.real_agendas.add(agenda)
|
|
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
weekday_indexes=[1, 2],
|
|
start_time=datetime.time(11, 0),
|
|
end_time=datetime.time(12, 30),
|
|
desk=desk,
|
|
)
|
|
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 12
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-07 11:00:00',
|
|
'2022-02-07 11:30:00',
|
|
'2022-02-07 12:00:00',
|
|
'2022-02-14 11:00:00',
|
|
'2022-02-14 11:30:00',
|
|
'2022-02-14 12:00:00',
|
|
'2022-03-07 11:00:00',
|
|
'2022-03-07 11:30:00',
|
|
'2022-03-07 12:00:00',
|
|
'2022-03-14 11:00:00',
|
|
'2022-03-14 11:30:00',
|
|
'2022-03-14 12:00:00',
|
|
]
|
|
|
|
# add exclusion period on virtual agenda
|
|
exclusion_period = TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(11, 30), end_time=datetime.time(12, 30), agenda=virtual_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 4
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-07 11:00:00',
|
|
'2022-02-14 11:00:00',
|
|
'2022-03-07 11:00:00',
|
|
'2022-03-14 11:00:00',
|
|
]
|
|
|
|
exclusion_period.start_time = datetime.time(10, 30)
|
|
exclusion_period.end_time = datetime.time(11, 30)
|
|
exclusion_period.save()
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 8
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-07 11:30:00',
|
|
'2022-02-07 12:00:00',
|
|
'2022-02-14 11:30:00',
|
|
'2022-02-14 12:00:00',
|
|
'2022-03-07 11:30:00',
|
|
'2022-03-07 12:00:00',
|
|
'2022-03-14 11:30:00',
|
|
'2022-03-14 12:00:00',
|
|
]
|
|
|
|
# add second exclusion period on virtual agenda
|
|
TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(12, 00), end_time=datetime.time(12, 30), agenda=virtual_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-02-07 11:30:00',
|
|
'2022-02-14 11:30:00',
|
|
'2022-03-07 11:30:00',
|
|
'2022-03-14 11:30:00',
|
|
]
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-10-24 10:00')
|
|
def test_datetimes_api_meetings_agenda_date_time_period(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=8
|
|
)
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
|
|
TimePeriod.objects.create(
|
|
date=datetime.date(2022, 10, 24),
|
|
start_time=datetime.time(12, 0),
|
|
end_time=datetime.time(14, 0),
|
|
desk=desk,
|
|
)
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
|
|
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-10-24 12:00:00',
|
|
'2022-10-24 12:30:00',
|
|
'2022-10-24 13:00:00',
|
|
'2022-10-24 13:30:00',
|
|
]
|
|
|
|
resp = app.get(api_url, params={'date_start': '2022-10-25'})
|
|
assert resp.json['data'] == []
|
|
|
|
# mix with repeating period
|
|
TimePeriod.objects.create(
|
|
weekday=0,
|
|
start_time=datetime.time(13, 0),
|
|
end_time=datetime.time(15, 0),
|
|
desk=desk,
|
|
)
|
|
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-10-24 12:00:00',
|
|
'2022-10-24 12:30:00',
|
|
'2022-10-24 13:00:00',
|
|
'2022-10-24 13:30:00',
|
|
'2022-10-24 14:00:00',
|
|
'2022-10-24 14:30:00',
|
|
'2022-10-31 13:00:00',
|
|
'2022-10-31 13:30:00',
|
|
'2022-10-31 14:00:00',
|
|
'2022-10-31 14:30:00',
|
|
]
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-10-24 10:00')
|
|
def test_datetimes_api_meetings_virtual_agenda_date_time_period(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Plop', duration=30)
|
|
virtual_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='virtual')
|
|
virtual_agenda.real_agendas.add(agenda)
|
|
|
|
TimePeriod.objects.create(
|
|
date=datetime.date(2022, 10, 24),
|
|
start_time=datetime.time(12, 0),
|
|
end_time=datetime.time(14, 0),
|
|
desk=desk,
|
|
)
|
|
|
|
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-10-24 12:00:00',
|
|
'2022-10-24 12:30:00',
|
|
'2022-10-24 13:00:00',
|
|
'2022-10-24 13:30:00',
|
|
]
|
|
|
|
# add exclusion period on virtual agenda
|
|
TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(12, 00), end_time=datetime.time(13, 00), agenda=virtual_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-10-24 13:00:00',
|
|
'2022-10-24 13:30:00',
|
|
]
|
|
|
|
# add second exclusion period on virtual agenda
|
|
TimePeriod.objects.create(
|
|
weekday=0, start_time=datetime.time(13, 30), end_time=datetime.time(14, 00), agenda=virtual_agenda
|
|
)
|
|
resp = app.get(api_url)
|
|
assert [x['datetime'] for x in resp.json['data']] == [
|
|
'2022-10-24 13:00:00',
|
|
]
|