1571 lines
61 KiB
Python
1571 lines
61 KiB
Python
import datetime
|
|
import urllib.parse as urlparse
|
|
|
|
import pytest
|
|
from django.db import connection
|
|
from django.test import override_settings
|
|
from django.test.utils import CaptureQueriesContext
|
|
|
|
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, TimePeriodException
|
|
from chrono.utils.timezone import localtime, make_aware, make_naive, now
|
|
from tests.utils import login
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
def test_datetimes_api(app, some_data):
|
|
agenda = Agenda.objects.filter(label='Foo bar')[0]
|
|
|
|
def check_bookability(data):
|
|
for event in data:
|
|
assert Event.objects.get(slug=event['id']).in_bookable_period()
|
|
for event in agenda.event_set.all():
|
|
if not event.in_bookable_period():
|
|
assert event.slug not in [x['id'] for x in data]
|
|
|
|
resp = app.get('/api/agenda/xxx/datetimes/', status=404)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert 'data' in resp.json
|
|
assert len(resp.json['data']) == 3
|
|
check_bookability(resp.json['data'])
|
|
assert app.get('/api/agenda/%s/datetimes/' % agenda.id).json == resp.json
|
|
|
|
agenda.minimal_booking_delay = 5
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 0
|
|
check_bookability(resp.json['data'])
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
|
|
assert len(resp.json['data']) == 3
|
|
|
|
agenda.minimal_booking_delay = 2
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 2
|
|
check_bookability(resp.json['data'])
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
|
|
assert len(resp.json['data']) == 3
|
|
|
|
agenda.minimal_booking_delay = 0
|
|
agenda.maximal_booking_delay = 3
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 2
|
|
check_bookability(resp.json['data'])
|
|
assert resp.json['data'][0]['description'] is None
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
|
|
assert len(resp.json['data']) == 3
|
|
|
|
agenda.event_set.update(publication_datetime=now() + datetime.timedelta(minutes=1))
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 0
|
|
check_bookability(resp.json['data'])
|
|
|
|
agenda.event_set.update(publication_datetime=now())
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 2
|
|
check_bookability(resp.json['data'])
|
|
|
|
# add description, URL and pricing to events
|
|
for i, event in enumerate(agenda.event_set.all()):
|
|
event.description = 'Description %s' % i
|
|
event.url = 'https://www.example.net/%s' % i
|
|
event.pricing = '%s €' % i
|
|
event.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['description']
|
|
|
|
|
|
def test_datetimes_api_wrong_kind(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
app.get('/api/agenda/%s/datetimes/' % agenda.slug, status=404)
|
|
|
|
|
|
@pytest.mark.freeze_time('2023-03-10')
|
|
def test_datetimes_sort(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=localtime(now() + datetime.timedelta(days=5)).replace(hour=17, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-2',
|
|
start_datetime=localtime(now() + datetime.timedelta(days=4)).replace(hour=17, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['datetime'] == '2023-03-14 17:00:00'
|
|
assert resp.json['data'][1]['datetime'] == '2023-03-15 17:00:00'
|
|
|
|
|
|
def test_datetime_api_fr(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=localtime(now() + datetime.timedelta(days=5)).replace(hour=17, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
with override_settings(LANGUAGE_CODE='fr-fr'):
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
# no seconds, hh:mm in 24-hour formats
|
|
assert resp.json['data'][0]['text'].endswith(' 17:00')
|
|
assert resp.json['data'][0]['datetime'].endswith(' 17:00:00')
|
|
assert 'data' in resp.json
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-05-06 14:00')
|
|
def test_datetime_api_label(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
event = Event.objects.create(
|
|
label='Hello world',
|
|
slug='event-slug',
|
|
start_datetime=(now() + datetime.timedelta(days=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['text'] == 'Hello world'
|
|
assert resp.json['data'][0]['label'] == 'Hello world'
|
|
|
|
agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['text'] == 'Hello world - May 7, 2021, 4 p.m.'
|
|
assert resp.json['data'][0]['label'] == 'Hello world'
|
|
|
|
Booking.objects.create(event=event)
|
|
agenda.event_display_template = (
|
|
'{{ event.label }} ({{ event.remaining_places }}/{{ event.places }} places remaining)'
|
|
)
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['text'] == 'Hello world (4/5 places remaining)'
|
|
|
|
# invalid template yields default text
|
|
invalid_templates = [
|
|
'{{ syntax error }}',
|
|
'{{ event.label|invalidfilter }}',
|
|
'{{ event.label|default:notexist }}',
|
|
]
|
|
for template in invalid_templates:
|
|
agenda.event_display_template = template
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['text'] == 'Hello world'
|
|
|
|
|
|
def test_datetime_api_urls(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
|
|
places=5,
|
|
waiting_list_places=5,
|
|
agenda=agenda,
|
|
)
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
for datum in resp.json['data']:
|
|
assert urlparse.urlparse(datum['api']['bookings_url']).path == '/api/agenda/%s/bookings/%s/' % (
|
|
agenda.slug,
|
|
event.slug,
|
|
)
|
|
assert urlparse.urlparse(datum['api']['fillslot_url']).path == '/api/agenda/%s/fillslot/%s/' % (
|
|
agenda.slug,
|
|
event.slug,
|
|
)
|
|
assert urlparse.urlparse(datum['api']['status_url']).path == '/api/agenda/%s/status/%s/' % (
|
|
agenda.slug,
|
|
event.slug,
|
|
)
|
|
|
|
|
|
def test_datetime_api_backoffice_url(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
event = Event.objects.create(
|
|
label='Example Event', start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda
|
|
)
|
|
app = login(app)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
url = resp.json['data'][0]['api']['backoffice_url']
|
|
assert urlparse.urlparse(url).path == '/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk)
|
|
assert event.label in app.get(url).text
|
|
|
|
|
|
def test_datetimes_api_min_places(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
|
event = Event.objects.create(start_datetime=now() + datetime.timedelta(days=7), places=5, agenda=agenda)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert not resp.json['data'][0]['disabled']
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/?min_places=5' % agenda.slug)
|
|
assert not resp.json['data'][0]['disabled']
|
|
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/api/agenda/%s/datetimes/?min_places=5' % agenda.slug)
|
|
assert resp.json['data'][0]['disabled']
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/?min_places=' % agenda.slug)
|
|
assert not resp.json['data'][0]['disabled']
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/?min_places=wrong' % agenda.slug, status=400)
|
|
assert resp.json['err'] == 1
|
|
|
|
|
|
def test_datetimes_api_(app):
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
custom_fields=[
|
|
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
|
|
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
|
|
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
|
|
],
|
|
)
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', events_type=events_type)
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=localtime(now() + datetime.timedelta(days=5)).replace(hour=17, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
custom_fields={
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
},
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(ctx.captured_queries) == 2
|
|
assert resp.json['data'][0]['custom_field_text'] == 'foo'
|
|
assert resp.json['data'][0]['custom_field_textarea'] == 'foo bar'
|
|
assert resp.json['data'][0]['custom_field_bool'] is True
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-23')
|
|
def test_datetimes_api_exclude_slots(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
|
)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=localtime().replace(hour=10, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Booking.objects.create(event=event, user_external_id='42')
|
|
cancelled = Booking.objects.create(event=event, user_external_id='35')
|
|
cancelled.cancel()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '35'})
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert resp.json['meta']['first_bookable_slot'] is None
|
|
assert resp.json['meta']['no_bookable_datetimes'] is True
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
event.delete()
|
|
|
|
# recurrent event
|
|
start_datetime = localtime().replace(hour=12, minute=0)
|
|
event = Event.objects.create(
|
|
slug='recurrent',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.weekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=15),
|
|
places=2,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is False
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is False
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
|
|
first_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
|
|
Booking.objects.create(event=first_recurrence, user_external_id='42')
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is False
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is False
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
|
|
Booking.objects.create(event=first_recurrence)
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
|
|
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-23')
|
|
def test_datetimes_api_user_external_id(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
|
)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=localtime().replace(hour=10, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
booking = Booking.objects.create(event=event, user_external_id='42')
|
|
cancelled = Booking.objects.create(event=event, user_external_id='35')
|
|
cancelled.cancel()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '35'})
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert resp.json['data'][0]['booked_for_external_user'] == 'main-list'
|
|
assert resp.json['data'][0]['disabled'] is False
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'user_external_id': '42', 'exclude_user_external_id': '42'},
|
|
)
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
|
|
booking.in_waiting_list = True
|
|
booking.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert resp.json['data'][0]['booked_for_external_user'] == 'waiting-list'
|
|
booking.cancel()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
event.delete()
|
|
|
|
# recurrent event
|
|
start_datetime = localtime().replace(hour=12, minute=0)
|
|
event = Event.objects.create(
|
|
slug='recurrent',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.weekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=15),
|
|
places=2,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
|
|
first_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
|
|
booking = Booking.objects.create(event=first_recurrence, user_external_id='42')
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert 'booked_for_external_user' not in resp.json['data'][0]
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert resp.json['data'][0]['booked_for_external_user'] == 'main-list'
|
|
|
|
booking.in_waiting_list = True
|
|
booking.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
|
|
assert resp.json['data'][0]['booked_for_external_user'] == 'waiting-list'
|
|
|
|
# mix with exclude_user_external_id
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'user_external_id': '42', 'exclude_user_external_id': '35'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['user_external_id'] == [
|
|
'user_external_id and exclude_user_external_id have different values'
|
|
]
|
|
|
|
|
|
def test_datetimes_api_hide_disabled(app):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
|
|
)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=now() + datetime.timedelta(days=3),
|
|
places=1,
|
|
agenda=agenda,
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['id'] == 'event-slug'
|
|
assert resp.json['data'][0]['disabled'] is True
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'hide_disabled': True})
|
|
assert resp.json['data'] == []
|
|
|
|
|
|
def test_waiting_list_datetimes(app, some_data, user):
|
|
agenda_id = Agenda.objects.filter(label='Foo bar')[0].id
|
|
event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]
|
|
event.waiting_list_places = 5
|
|
event.save()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
|
|
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 3
|
|
assert event.slug in [x['id'] for x in resp.json['data']]
|
|
|
|
for _ in range(event.places):
|
|
Booking(event=event).save()
|
|
|
|
# all places are booked but all the dates are still displayed as there is a
|
|
# waiting list.
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
|
|
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 3
|
|
|
|
# fill the waiting list
|
|
for _ in range(event.waiting_list_places):
|
|
Booking(event=event, in_waiting_list=True).save()
|
|
|
|
# the event datetime should no longer be returned
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
|
|
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 2
|
|
assert event.slug not in [x['id'] for x in resp.json['data'] if not x.get('disabled')]
|
|
assert event.slug in [x['id'] for x in resp.json['data'] if x.get('disabled')]
|
|
|
|
|
|
@pytest.mark.freeze_time('2017-05-20')
|
|
def test_agenda_api_date_range(app):
|
|
# test range limitation
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
first_datetime = localtime(now()).replace(hour=20, minute=0, second=0, microsecond=0)
|
|
first_datetime += datetime.timedelta(days=1)
|
|
for i in range(2):
|
|
event = Event.objects.create(
|
|
start_datetime=first_datetime + datetime.timedelta(days=i), places=20, agenda=agenda
|
|
)
|
|
base_datetime = agenda.event_set.last().start_datetime
|
|
base_datetime = base_datetime + datetime.timedelta(days=1)
|
|
|
|
for idx in range(7, 10):
|
|
if idx == 7:
|
|
day_events = ['9:00', '10:00', '11:00']
|
|
elif idx == 8:
|
|
day_events = ['13:00', '14:00']
|
|
else:
|
|
day_events = ['8:00']
|
|
day = base_datetime.date() + datetime.timedelta(days=idx)
|
|
for event in day_events:
|
|
event_dt = datetime.datetime.combine(day, datetime.datetime.strptime(event, '%H:%M').time())
|
|
Event.objects.create(agenda=agenda, start_datetime=make_aware(event_dt), places=2)
|
|
|
|
for value in ['foo', '2017-05-42']:
|
|
params = {'date_start': value}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, 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('/api/agenda/%s/datetimes/' % agenda.slug, 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].'
|
|
]
|
|
|
|
params = {'date_start': base_datetime.date().isoformat()}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 6
|
|
date_endtime = base_datetime + datetime.timedelta(days=7)
|
|
params = {'date_end': date_endtime.date().isoformat()}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 2
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-21 20:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-22 20:00:00'
|
|
|
|
params = {
|
|
'date_start': base_datetime.date() + datetime.timedelta(days=8),
|
|
'date_end': base_datetime.date() + datetime.timedelta(days=10),
|
|
}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-31 13:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-06-01 08:00:00'
|
|
|
|
# with minimal booking delay changed
|
|
agenda.minimal_booking_delay = 3
|
|
agenda.save()
|
|
params = {'date_start': '2017-05-21'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 6
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-06-01 08:00:00'
|
|
|
|
# with maximal booking delay changed
|
|
agenda.maximal_booking_delay = 11
|
|
agenda.save()
|
|
params = {'date_end': '2017-06-01'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
|
|
|
|
# with time
|
|
params = {'date_start': '2017-05-21 foo'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, 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 start in ['2017-05-30 09:00', '2017-05-30 09:00:00']:
|
|
params = {'date_start': start}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
|
|
|
|
for start in ['2017-05-30 09:01', '2017-05-30 09:00:01', '2017-05-30 09:00:01+02:00']:
|
|
params = {'date_start': start}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 2
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 10:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
|
|
|
|
params = {'date_end': '2017-06-01 foo'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, 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].'
|
|
]
|
|
|
|
for end in ['2017-05-30 11:01', '2017-05-30 11:00:01']:
|
|
params = {'date_end': end}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
|
|
|
|
for end in ['2017-05-30 11:00', '2017-05-30 11:00:00', '2017-05-30 11:00:00+02:00']:
|
|
params = {'date_end': end}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
assert len(resp.json['data']) == 2
|
|
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2017-05-30 10:00:00'
|
|
|
|
|
|
def test_datetimes_api_meta(app, freezer):
|
|
# 2017-05-20 -> saturday
|
|
freezer.move_to(make_aware(datetime.datetime(year=2017, month=5, day=20, hour=1, minute=12)))
|
|
|
|
agenda = Agenda.objects.create(label='Foo bar')
|
|
first_date = localtime(now()).replace(hour=17, minute=0, second=0, microsecond=0)
|
|
first_date += datetime.timedelta(days=1)
|
|
for i in range(3):
|
|
event = Event(start_datetime=first_date + datetime.timedelta(days=i), places=20, agenda=agenda)
|
|
event.save()
|
|
# a date in the past
|
|
event = Event(start_datetime=first_date - datetime.timedelta(days=10), places=10, agenda=agenda)
|
|
event.save()
|
|
|
|
events = Event.objects.filter(agenda_id=agenda.id).exclude(start_datetime__lt=now())
|
|
assert len(events) == 3
|
|
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
def simulate_booking(event, nb_places):
|
|
for _ in range(nb_places):
|
|
Booking(event=event, user_external_id='42').save()
|
|
|
|
simulate_booking(events[0], 10)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 3,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
resp = app.get(api_url, params={'exclude_user_external_id': '42'})
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 2,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
resp = app.get(api_url + '?min_places=11')
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 2,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
simulate_booking(events[0], 10)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 2,
|
|
'first_bookable_slot': resp.json['data'][1],
|
|
}
|
|
|
|
simulate_booking(events[1], 20)
|
|
simulate_booking(events[2], 20)
|
|
resp = app.get(api_url)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': True,
|
|
'bookable_datetimes_number_total': 3,
|
|
'bookable_datetimes_number_available': 0,
|
|
'first_bookable_slot': None,
|
|
}
|
|
|
|
# recurring event
|
|
Event.objects.all().delete()
|
|
event = Event.objects.create(
|
|
slug='abc',
|
|
label='Test',
|
|
start_datetime=localtime(),
|
|
recurrence_days=[localtime().weekday()],
|
|
recurrence_end_date=localtime() + datetime.timedelta(days=15),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
resp = app.get(api_url)
|
|
assert resp.json['meta']['first_bookable_slot']['text'] == 'Test (May 27, 2017, 1:12 a.m.)'
|
|
|
|
|
|
def test_recurring_events_api(app, user, freezer):
|
|
freezer.move_to('2021-01-12 12:05') # Tuesday
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=1, maximal_booking_delay=30
|
|
)
|
|
base_event = Event.objects.create(
|
|
slug='abc',
|
|
label="Rock'n roll",
|
|
start_datetime=localtime(),
|
|
recurrence_days=[localtime().weekday()],
|
|
recurrence_end_date=localtime() + datetime.timedelta(days=30),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
base_event.create_all_recurrences()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
assert data[0]['id'] == 'abc--2021-01-19-1305'
|
|
assert data[0]['datetime'] == '2021-01-19 13:05:00'
|
|
assert data[0]['text'] == "Rock'n roll (Jan. 19, 2021, 1:05 p.m.)"
|
|
assert data[3]['id'] == 'abc--2021-02-09-1305'
|
|
assert Event.objects.count() == 6
|
|
|
|
fillslot_url = data[0]['api']['fillslot_url']
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# book first event
|
|
resp = app.post(fillslot_url)
|
|
assert resp.json['err'] == 0
|
|
event = Booking.objects.get(pk=resp.json['booking_id']).event
|
|
assert event.slug == 'abc--2021-01-19-1305'
|
|
|
|
# cancelled recurrences do not appear
|
|
event.cancel()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['id'] == 'abc--2021-01-26-1305'
|
|
|
|
# check querysets
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(ctx.captured_queries) == 3
|
|
|
|
# events follow agenda display template
|
|
agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['text'] == "Rock'n roll - Jan. 26, 2021, 1:05 p.m."
|
|
|
|
# check delays
|
|
base_event.recurrence_end_date += datetime.timedelta(days=30)
|
|
base_event.save()
|
|
agenda.update_event_recurrences()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 3
|
|
assert [e['disabled'] for e in resp.json['data']] == [False] * 3
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
|
|
assert len(resp.json['data']) == 8
|
|
assert [e['disabled'] for e in resp.json['data']] == [False] * 8
|
|
agenda.minimal_booking_delay = 10
|
|
agenda.mmaximal_booking_delay = 20
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 3
|
|
assert [e['disabled'] for e in resp.json['data']] == [False] * 3
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
|
|
assert len(resp.json['data']) == 8
|
|
assert [e['disabled'] for e in resp.json['data']] == [False] * 8
|
|
|
|
|
|
def test_recurring_events_api_various_times(app, user, mock_now):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
event = Event.objects.create(
|
|
slug='abc',
|
|
start_datetime=localtime(),
|
|
recurrence_days=[localtime().weekday()],
|
|
recurrence_end_date=localtime() + datetime.timedelta(days=30),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 5
|
|
fillslot_url = resp.json['data'][0]['api']['fillslot_url']
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.post(fillslot_url)
|
|
assert resp.json['err'] == 0
|
|
|
|
new_event = Booking.objects.get(pk=resp.json['booking_id']).event
|
|
assert event.start_datetime == new_event.start_datetime
|
|
|
|
|
|
def test_datetimes_dst(app, freezer):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=10
|
|
)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=make_aware(datetime.datetime(2021, 3, 28, 12, 30)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
freezer.move_to('Fri, 18 Mar 2021 23:59:39 +0100')
|
|
|
|
# maximal_booking_delay is 10days so last bookable event is on
|
|
# 2021-03-28T00:00, so event should not be bookable
|
|
assert not event.in_bookable_period()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 0
|
|
|
|
|
|
def test_recurring_events_api_exceptions(app, user, freezer):
|
|
freezer.move_to('2021-01-12 12:05') # Tuesday
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=1, maximal_booking_delay=30
|
|
)
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
event = Event.objects.create(
|
|
slug='abc',
|
|
start_datetime=localtime(),
|
|
recurrence_days=[localtime().weekday()],
|
|
recurrence_end_date=localtime() + datetime.timedelta(days=30),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
assert data[0]['datetime'] == '2021-01-19 13:05:00'
|
|
|
|
TimePeriodException.objects.create(
|
|
desk=agenda.desk_set.get(),
|
|
start_datetime=datetime.date(year=2021, month=1, day=18),
|
|
end_datetime=datetime.date(year=2021, month=1, day=20),
|
|
)
|
|
agenda.update_event_recurrences()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert len(resp.json['data']) == 3
|
|
assert resp.json['data'][0]['datetime'] == '2021-01-26 13:05:00'
|
|
|
|
# try to book excluded event
|
|
fillslot_url = data[0]['api']['fillslot_url']
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.post(fillslot_url, status=400)
|
|
assert resp.json['err'] == 1
|
|
|
|
|
|
def test_past_datetimes(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
event1 = Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event2 = Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
assert (
|
|
data[0]['api']['fillslot_url']
|
|
== 'http://testserver/api/agenda/foo-bar/fillslot/today-after-now/?events=future'
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False
|
|
assert (
|
|
data[0]['api']['fillslot_url']
|
|
== 'http://testserver/api/agenda/foo-bar/fillslot/today-before-now/?events=past'
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[1]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert (
|
|
data[0]['api']['fillslot_url']
|
|
== 'http://testserver/api/agenda/foo-bar/fillslot/today-before-now/?events=all'
|
|
)
|
|
assert (
|
|
data[1]['api']['fillslot_url']
|
|
== 'http://testserver/api/agenda/foo-bar/fillslot/today-after-now/?events=all'
|
|
)
|
|
|
|
# check canceled
|
|
event1.cancel()
|
|
event2.cancel()
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
|
|
data = resp.json['data']
|
|
assert len(data) == 0
|
|
|
|
|
|
def test_past_datetimes_meta(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 1,
|
|
'bookable_datetimes_number_available': 1,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['id'] == 'today-before-now'
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 1,
|
|
'bookable_datetimes_number_available': 1,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
|
|
assert len(resp.json['data']) == 2
|
|
assert resp.json['data'][0]['id'] == 'today-before-now'
|
|
assert resp.json['data'][1]['id'] == 'today-after-now'
|
|
assert resp.json['meta'] == {
|
|
'no_bookable_datetimes': False,
|
|
'bookable_datetimes_number_total': 2,
|
|
'bookable_datetimes_number_available': 2,
|
|
'first_bookable_slot': resp.json['data'][0],
|
|
}
|
|
|
|
|
|
def test_past_datetimes_date_range(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
Event.objects.create(
|
|
label='Yesterday 18H',
|
|
start_datetime=localtime(now() - datetime.timedelta(days=1)).replace(hour=18, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
label='Tomorrow 16H',
|
|
start_datetime=localtime(now() + datetime.timedelta(days=1)).replace(hour=16, minute=0),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
# check date_start
|
|
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[1]['id'] == 'tomorrow-16h'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
|
|
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 3
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[1]['id'] == 'today-after-now'
|
|
assert data[2]['id'] == 'tomorrow-16h'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
|
|
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'tomorrow-16h'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 0
|
|
|
|
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'tomorrow-16h'
|
|
assert data[0]['disabled'] is False
|
|
|
|
# check date_end
|
|
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['id'] == 'yesterday-18h'
|
|
assert data[1]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
|
|
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 3
|
|
assert data[0]['id'] == 'yesterday-18h'
|
|
assert data[1]['id'] == 'today-before-now'
|
|
assert data[2]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
|
|
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 0
|
|
|
|
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'yesterday-18h'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'yesterday-18h'
|
|
assert data[0]['disabled'] is False
|
|
|
|
# mix
|
|
params = {
|
|
'date_start': localtime(now() - datetime.timedelta(hours=2)),
|
|
'date_end': localtime(now() + datetime.timedelta(hours=2)),
|
|
'events': 'future',
|
|
}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {
|
|
'date_start': localtime(now() - datetime.timedelta(hours=2)),
|
|
'date_end': localtime(now() + datetime.timedelta(hours=2)),
|
|
'events': 'past',
|
|
}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False
|
|
|
|
params = {
|
|
'date_start': localtime(now() - datetime.timedelta(hours=2)),
|
|
'date_end': localtime(now() + datetime.timedelta(hours=2)),
|
|
'events': 'all',
|
|
}
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
|
|
data = resp.json['data']
|
|
assert len(data) == 2
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[1]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
|
|
|
|
def test_past_datetimes_places(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
event1 = Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=1,
|
|
agenda=agenda,
|
|
)
|
|
event2 = Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=1,
|
|
agenda=agenda,
|
|
)
|
|
Booking.objects.create(event=event1)
|
|
Booking.objects.create(event=event2)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert data[0]['disabled'] is True
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert data[0]['disabled'] is False # always available if past
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
|
|
|
|
event1.waiting_list_places = 1
|
|
event1.save()
|
|
event2.waiting_list_places = 1
|
|
event2.save()
|
|
Booking.objects.create(event=event1, in_waiting_list=True)
|
|
Booking.objects.create(event=event2, in_waiting_list=True)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert data[0]['disabled'] is True
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert resp.json['data'][0]['places']['full'] is True
|
|
assert data[0]['disabled'] is False # always available if past
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
|
|
|
|
|
|
def test_past_datetimes_min_places(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=1,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=1,
|
|
agenda=agenda,
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'min_places': 2})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is True
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'min_places': 2})
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False # always available if past
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
|
|
|
|
|
|
def test_past_datetimes_exclude_slots(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
event1 = Event.objects.create(
|
|
label='Today before now',
|
|
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event2 = Event.objects.create(
|
|
label='Today after now',
|
|
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Booking.objects.create(event=event1, user_external_id='42')
|
|
Booking.objects.create(event=event2, user_external_id='42')
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'events': 'future', 'exclude_user_external_id': '35'},
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is False
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-after-now'
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '35'}
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is False
|
|
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'events': 'future', 'exclude_user_external_id': '42'},
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-after-now'
|
|
assert data[0]['disabled'] is True
|
|
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '42'}
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'today-before-now'
|
|
assert data[0]['disabled'] is True
|
|
|
|
|
|
def test_past_datetimes_recurring_event(app, user):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
|
|
)
|
|
start_datetime = make_aware(make_naive(now()) - datetime.timedelta(days=3 * 7))
|
|
event = Event.objects.create(
|
|
label='Recurring',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.weekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=60),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
event.create_all_recurrences()
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
assert data[3]['disabled'] is False
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
assert data[3]['disabled'] is False
|
|
|
|
# same result with explicit date_start
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'events': 'past', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
|
|
)
|
|
assert resp.json['data'] == data
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
|
|
data = resp.json['data']
|
|
assert len(data) == 8
|
|
assert data[0]['disabled'] is False
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
assert data[3]['disabled'] is False
|
|
assert data[4]['disabled'] is False
|
|
assert data[5]['disabled'] is False
|
|
assert data[6]['disabled'] is False
|
|
assert data[7]['disabled'] is False
|
|
|
|
# same result with explicit date_start
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
|
|
)
|
|
assert resp.json['data'] == data
|
|
|
|
# same result with explicit date_start and date_end
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={
|
|
'events': 'all',
|
|
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
|
|
'date_end': localtime(now() + datetime.timedelta(days=6 * 7)),
|
|
},
|
|
)
|
|
assert resp.json['data'] == data
|
|
|
|
# check user_external_id
|
|
first_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
|
|
booking = Booking.objects.create(event=first_recurrence, user_external_id='42', in_waiting_list=True)
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={
|
|
'events': 'past',
|
|
'user_external_id': '42',
|
|
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
|
|
},
|
|
)
|
|
data = resp.json['data']
|
|
assert data[0]['booked_for_external_user'] == 'waiting-list'
|
|
booking.in_waiting_list = False
|
|
booking.save()
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={
|
|
'events': 'past',
|
|
'user_external_id': '42',
|
|
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
|
|
},
|
|
)
|
|
data = resp.json['data']
|
|
assert data[0]['booked_for_external_user'] == 'main-list'
|
|
|
|
# check exclude_user_external_id
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={
|
|
'events': 'past',
|
|
'exclude_user_external_id': '42',
|
|
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
|
|
},
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 4
|
|
assert data[0]['disabled'] is True
|
|
assert data[1]['disabled'] is False
|
|
assert data[2]['disabled'] is False
|
|
assert data[3]['disabled'] is False
|
|
|
|
# check canceled
|
|
first_recurrence.cancel()
|
|
resp = app.get(
|
|
'/api/agenda/%s/datetimes/' % agenda.slug,
|
|
params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
|
|
)
|
|
data = resp.json['data']
|
|
assert len(data) == 7
|
|
|
|
|
|
@pytest.mark.freeze_time('2023-04-03')
|
|
def test_events_datetimes_min_booking_datetime_with_minimal_booking_time(app):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=3, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-2',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=3, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
|
|
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
|
|
|
|
# set a minimal minimal_booking_time and check that it has no impact
|
|
agenda.minimal_booking_time = datetime.time(10, 0, 0)
|
|
agenda.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
|
|
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
|
|
|
|
# set a minimal minimal_booking_time to None check that it has no impact
|
|
agenda.minimal_booking_time = None
|
|
agenda.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
|
|
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
|
|
|
|
|
|
def test_events_datetimes_max_booking_datetime_with_minimal_booking_time(app, freezer):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-0',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-1',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-2',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-3',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-4',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-5',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
# last slots visible are the one on J + maximal_booking_delay (3) -1
|
|
freezer.move_to('2023-04-03T00:00:00+02:00')
|
|
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# # move to noon, no changes
|
|
freezer.move_to('2023-04-03T12:00:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# set a minimal minimal_booking_time earlier than current time, no changes
|
|
agenda.minimal_booking_time = datetime.time(10, 0, 0)
|
|
agenda.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# set a minimal minimal_booking_time later than current time, slots of 2023-04-05 disappear
|
|
agenda.minimal_booking_time = datetime.time(14, 0, 0)
|
|
agenda.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-04 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-04 11:00:00'
|
|
|
|
# move to a time superior to minimal_booking_time (14:00), slots of 2023-04-05 re-appear
|
|
freezer.move_to('2023-04-03T15:00:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# move to the day after, prior to minimal_booking_time (14:00), no changes
|
|
freezer.move_to('2023-04-04T12:00:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# move to the day after, after minimal_booking_time (14:00), new slots available
|
|
freezer.move_to('2023-04-04T15:00:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-06 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-06 11:00:00'
|
|
|
|
|
|
def test_events_datetimes_max_booking_datetime_with_minimal_booking_time_to_none(app, freezer):
|
|
agenda = Agenda.objects.create(
|
|
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-0',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-1',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-2',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-3',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-4',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=9)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-slug-5',
|
|
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=11)),
|
|
places=5,
|
|
agenda=agenda,
|
|
)
|
|
|
|
# last slots visible are the one on J + maximal_booking_delay (3) -1
|
|
freezer.move_to('2023-04-03T00:00:00+02:00')
|
|
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
# set a minimal minimal_booking_time to None, 2023-04-05 disappear
|
|
# because current time is 00:00 and slots starts later
|
|
agenda.minimal_booking_time = None
|
|
agenda.save()
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-04 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-04 11:00:00'
|
|
|
|
# move a few hours later, juste after the first slot time of a day
|
|
# a new slot becomes available
|
|
freezer.move_to('2023-04-03T09:01:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:00:00'
|
|
|
|
# at 12:00, every slots are available
|
|
freezer.move_to('2023-04-03T12:00:00+02:00')
|
|
resp = app.get(api_url)
|
|
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
|
|
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
|
|
|
|
|
|
@pytest.mark.freeze_time('2023-05-01')
|
|
def test_events_datetime_partial_bookings_end_datetime(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', partial_bookings=True)
|
|
start_datetime = make_aware(datetime.datetime(2023, 5, 2, 8, 0))
|
|
Event.objects.create(
|
|
label='Event', start_datetime=start_datetime, end_time=datetime.time(18, 00), places=10, agenda=agenda
|
|
)
|
|
|
|
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
|
assert resp.json['data'][0]['datetime'] == '2023-05-02 08:00:00'
|
|
assert resp.json['data'][0]['end_datetime'] == '2023-05-02 18:00:00'
|