chrono/tests/api/datetimes/test_events_multiple_agenda...

1705 lines
67 KiB
Python

import datetime
import pytest
from django.db import connection
from django.test.utils import CaptureQueriesContext
from chrono.agendas.models import (
Agenda,
Booking,
Category,
Desk,
Event,
EventsType,
Person,
SharedCustodyAgenda,
SharedCustodyHolidayRule,
SharedCustodyPeriod,
SharedCustodyRule,
Subscription,
TimePeriodException,
TimePeriodExceptionGroup,
UnavailabilityCalendar,
)
from chrono.utils.timezone import localtime, make_aware, now
pytestmark = pytest.mark.django_db
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas(app):
first_agenda = Agenda.objects.create(
label='First agenda', kind='events', minimal_booking_delay=0, maximal_booking_delay=45
)
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
event = Event.objects.create( # base recurring event not visible in datetimes api
slug='recurring',
start_datetime=now() + datetime.timedelta(hours=1),
recurrence_days=[localtime().weekday()],
recurrence_end_date=now() + datetime.timedelta(days=15),
places=5,
agenda=first_agenda,
)
event.create_all_recurrences()
second_agenda = Agenda.objects.create(
label='Second agenda', kind='events', minimal_booking_delay=0, maximal_booking_delay=45
)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
event = Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=6),
places=5,
agenda=second_agenda,
)
Booking.objects.create(event=event)
agenda_slugs = '%s,%s' % (first_agenda.slug, second_agenda.slug)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][1]['text'] == 'May 11, 2021, 4 p.m.'
assert resp.json['data'][1]['places']['available'] == 5
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][2]['text'] == 'May 12, 2021, 4 p.m.'
assert resp.json['data'][2]['places']['available'] == 4
assert resp.json['data'][3]['id'] == 'first-agenda@recurring--2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring--2021-05-20-1700'
# check user_external_id
Booking.objects.create(event=event, user_external_id='user')
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'user_external_id': 'user'})
assert resp.json['data'][1]['places']['available'] == 5
assert 'booked_for_external_user' not in resp.json['data'][1]
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['places']['available'] == 3
assert resp.json['data'][2]['booked_for_external_user'] == 'main-list'
assert resp.json['data'][2]['disabled'] is False
# check exclude_user_external_id
resp = app.get(
'/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'exclude_user_external_id': 'user'}
)
assert 'booked_for_external_user' not in resp.json['data'][1]
assert resp.json['data'][1]['disabled'] is False
assert 'booked_for_external_user' not in resp.json['data'][2]
assert resp.json['data'][2]['disabled'] is True
# check min_places
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['disabled'] is True
# check meta
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
assert resp.json['meta']['bookable_datetimes_number_total'] == 5
assert resp.json['meta']['bookable_datetimes_number_available'] == 4
assert resp.json['meta']['first_bookable_slot'] == resp.json['data'][0]
# check date_start
date_start = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_start': date_start})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'first-agenda@recurring--2021-05-13-1700'
assert resp.json['data'][2]['id'] == 'first-agenda@recurring--2021-05-20-1700'
# check date_end
date_end = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_end': date_end})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'date_end': date_end},
)
assert len(resp.json['data']) == 0
# check delays
Agenda.objects.update(minimal_booking_delay=6, maximal_booking_delay=14)
date_end = localtime() + datetime.timedelta(days=60) # with a date end to have recurring events
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_end': date_end})
assert len(resp.json['data']) == 2
assert [d['disabled'] for d in resp.json['data']] == [False, False]
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'first-agenda@recurring--2021-05-13-1700'
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_end': date_end, 'bypass_delays': True},
)
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring--2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring--2021-05-20-1700'
assert [d['disabled'] for d in resp.json['data']] == [False, False, False, False, False]
Agenda.objects.update(minimal_booking_delay=0, maximal_booking_delay=45)
# invalid slugs
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'xxx'}, status=400)
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx'
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'first-agenda,xxx,yyy'}, status=400)
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx, yyy'
# missing agendas parameter
resp = app.get('/api/agendas/datetimes/', params={}, status=400)
assert resp.json['err_desc'] == 'invalid payload'
# it's possible to show past events
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring--2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring--2021-05-20-1700'
assert [d['disabled'] for d in resp.json['data']] == [False, False, False, False, False]
# and events out of minimal_booking_delay
Agenda.objects.update(minimal_booking_delay=6, maximal_booking_delay=14)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 4
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring--2021-05-13-1700'
assert [d['disabled'] for d in resp.json['data']] == [True, True, False, False]
Agenda.objects.update(minimal_booking_delay=0, maximal_booking_delay=45)
Event.objects.create(
slug='event-in-past',
start_datetime=now() - datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
event = Event.objects.create( # base recurrring event not visible in datetimes api
slug='recurring-in-past',
start_datetime=now() - datetime.timedelta(days=15, hours=1),
recurrence_days=[localtime().weekday()],
recurrence_end_date=now(),
places=5,
agenda=first_agenda,
)
event.create_all_recurrences()
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 8
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past--2021-04-22-1500',
'first-agenda@recurring-in-past--2021-04-29-1500',
'first-agenda@event-in-past',
'first-agenda@recurring--2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring--2021-05-13-1700',
'first-agenda@recurring--2021-05-20-1700',
]
assert [d['disabled'] for d in resp.json['data']] == [True, True, True, False, False, False, False, False]
date_start = localtime() - datetime.timedelta(days=10)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'show_past_events': True},
)
assert len(resp.json['data']) == 7
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past--2021-04-29-1500',
'first-agenda@event-in-past',
'first-agenda@recurring--2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring--2021-05-13-1700',
'first-agenda@recurring--2021-05-20-1700',
]
date_start = localtime() - datetime.timedelta(days=4)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'show_past_events': True},
)
assert len(resp.json['data']) == 5
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring--2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring--2021-05-13-1700',
'first-agenda@recurring--2021-05-20-1700',
]
date_start = localtime() - datetime.timedelta(days=30) # with a date start to have past recurring events
date_end = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 5
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past--2021-04-22-1500',
'first-agenda@recurring-in-past--2021-04-29-1500',
'first-agenda@event-in-past',
'first-agenda@recurring--2021-05-06-1700',
'first-agenda@event',
]
date_end = localtime() - datetime.timedelta(days=8)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 1
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past--2021-04-22-1500',
]
date_end = localtime() - datetime.timedelta(days=5)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 2
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past--2021-04-22-1500',
'first-agenda@recurring-in-past--2021-04-29-1500',
]
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_sort(app):
category = Category.objects.create(label='Category A')
first_agenda = Agenda.objects.create(label='First agenda', kind='events', category=category)
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(label='10-05', start_datetime=now().replace(day=10), places=5, agenda=first_agenda)
second_agenda = Agenda.objects.create(label='Second agenda', kind='events', category=category)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=second_agenda)
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=second_agenda)
category = Category.objects.create(label='Category B')
third_agenda = Agenda.objects.create(label='Third agenda', kind='events', category=category)
Desk.objects.create(agenda=third_agenda, slug='_exceptions_holder')
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=third_agenda)
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=third_agenda)
for agenda in Agenda.objects.all():
Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
# check events are ordered by start_datetime and then by agenda order in querystring
agenda_slugs = ','.join((first_agenda.slug, third_agenda.slug, second_agenda.slug))
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'second-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'third-agenda@04-05'
assert resp.json['data'][1]['id'] == 'second-agenda@04-05'
assert resp.json['data'][2]['id'] == 'third-agenda@09-05'
assert resp.json['data'][3]['id'] == 'second-agenda@09-05'
assert resp.json['data'][4]['id'] == 'first-agenda@10-05'
# check subscribed events are ordered by start_datetime
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'second-agenda@09-05'
assert resp.json['data'][1]['id'] == 'third-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
# and by category slug if specified in querystring
resp = app.get(
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'second-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
# order is stable if same date events are in the same category
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=first_agenda)
resp = app.get(
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
)
assert len(resp.json['data']) == 4
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'first-agenda@09-05'
assert resp.json['data'][2]['id'] == 'second-agenda@09-05'
assert resp.json['data'][3]['id'] == 'first-agenda@10-05'
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_queries(app):
events_type = EventsType.objects.create(label='Foo')
category = Category.objects.create(label='Category A')
for i in range(10):
agenda = Agenda.objects.create(
label=str(i), kind='events', category=category, events_type=events_type
)
Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=now() - datetime.timedelta(days=10),
date_end=now() + datetime.timedelta(days=10),
)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(start_datetime=now() - datetime.timedelta(days=5), places=5, agenda=agenda)
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': ','.join(str(i) for i in range(10)),
'show_past_events': True,
'check_overlaps': True,
},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 2
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
'show_past_events': True,
'check_overlaps': True,
},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 2
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'category-a',
'user_external_id': 'xxx',
'show_past_events': True,
'check_overlaps': True,
},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 2
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='xxx', first_name='James', last_name='Doe')
for i in range(5):
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father,
second_guardian=mother,
child=child,
date_start=now() - datetime.timedelta(days=5 + 2 * i),
date_end=now() - datetime.timedelta(days=5 + 2 * i + 1),
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='even')
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd')
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'category-a',
'user_external_id': 'xxx',
'guardian_external_id': 'mother_id',
'show_past_events': True,
'check_overlaps': True,
},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 3
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_subscribed(app):
first_agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
Event.objects.create(
slug='event-2',
start_datetime=now() + datetime.timedelta(days=20),
places=5,
agenda=first_agenda,
)
category = Category.objects.create(label='Category A')
second_agenda = Agenda.objects.create(
label='Second agenda', kind='events', category=category, maximal_booking_delay=400
)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=20),
places=5,
agenda=second_agenda,
)
Event.objects.create(
slug='next-year-event',
start_datetime=now() + datetime.timedelta(days=365),
places=5,
agenda=second_agenda,
)
Subscription.objects.create(
agenda=first_agenda,
user_external_id='yyy',
date_start=now(),
date_end=now() + datetime.timedelta(days=10),
)
# no subscription for user xxx
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
# add subscription to first agenda
subscription = Subscription.objects.create(
agenda=first_agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=5), # first event after last day
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
subscription.date_start = now() + datetime.timedelta(days=10)
subscription.date_end = now() + datetime.timedelta(days=21) # second event on subscription's last day
subscription.save()
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-2'
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
# date_start before subscription's period, and includes the first event
'date_start': now().strftime('%Y-%m-%d'),
},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-2'
subscription.date_start = now()
subscription.date_end = now() + datetime.timedelta(days=6) # first event on subscription's last day
subscription.save()
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event'
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
# date_end after subscription's period, and includes the second event
'date_end': (now() + datetime.timedelta(days=30)).strftime('%Y-%m-%d'),
},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event'
# no subscription to second agenda
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
# add subscription to second agenda
Subscription.objects.create(
agenda=second_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=15),
date_end=now() + datetime.timedelta(days=25),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'second-agenda@event'
# add new subscription (disjoint) to second agenda
Subscription.objects.create(
agenda=second_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=355),
date_end=now() + datetime.timedelta(days=375),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'second-agenda@next-year-event'
# view events from all subscriptions
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'first-agenda@event'
assert resp.json['data'][1]['id'] == 'second-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@next-year-event'
# overlapping subscription changes nothing
Subscription.objects.create(
agenda=first_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=1),
date_end=now() + datetime.timedelta(days=11),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
# check errors
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all'}, status=400)
assert 'required' in resp.json['errors']['user_external_id'][0]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'agendas': 'first-agenda', 'user_external_id': 'xxx'},
status=400,
)
assert 'mutually exclusive' in resp.json['errors']['non_field_errors'][0]
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_recurring_subscribed_dates(app):
agenda = Agenda.objects.create(label='Agenda', kind='events', minimal_booking_delay=0)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(
slug='recurring',
start_datetime=now() + datetime.timedelta(days=-15, hours=1),
recurrence_days=[localtime().weekday()],
recurrence_end_date=now() + datetime.timedelta(days=15),
places=5,
agenda=agenda,
)
event.create_all_recurrences()
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
subscription = Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=datetime.date(2021, 4, 29),
date_end=datetime.date(2021, 5, 14),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'agenda@recurring--2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'agenda@recurring--2021-05-13-1700'
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
'show_past_events': True,
'date_start': subscription.date_start.strftime('%Y-%m-%d'),
},
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'xxx', 'show_past_events': True},
)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'agenda@recurring--2021-04-29-1700'
assert resp.json['data'][1]['id'] == 'agenda@recurring--2021-05-06-1700'
assert resp.json['data'][2]['id'] == 'agenda@recurring--2021-05-13-1700'
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
'show_past_events': True,
'date_start': subscription.date_start.strftime('%Y-%m-%d'),
},
)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'agenda@recurring--2021-04-29-1700'
assert resp.json['data'][1]['id'] == 'agenda@recurring--2021-05-06-1700'
assert resp.json['data'][2]['id'] == 'agenda@recurring--2021-05-13-1700'
# date_start before subscription's period,
# date_end after subscription's period
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
'show_past_events': True,
'date_start': event.start_datetime.strftime('%Y-%m-%d'),
'date_end': (now() + datetime.timedelta(days=15)).strftime('%Y-%m-%d'),
},
)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'agenda@recurring--2021-04-29-1700'
assert resp.json['data'][1]['id'] == 'agenda@recurring--2021-05-06-1700'
assert resp.json['data'][2]['id'] == 'agenda@recurring--2021-05-13-1700'
# test subscription's limits
subscription.date_start = datetime.date(2021, 4, 29)
subscription.date_end = datetime.date(2021, 5, 13)
subscription.save()
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'xxx',
'show_past_events': True,
'date_start': event.start_datetime.strftime('%Y-%m-%d'),
'date_end': (now() + datetime.timedelta(days=15)).strftime('%Y-%m-%d'),
},
)
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'agenda@recurring--2021-04-29-1700'
assert resp.json['data'][1]['id'] == 'agenda@recurring--2021-05-06-1700'
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
def test_datetimes_multiple_agendas_shared_custody(app):
agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event-even-week',
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=10, hour=14, minute=0)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-odd-week',
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=17, hour=14, minute=0)),
places=5,
agenda=agenda,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='child_id',
date_start=now(),
date_end=now() + datetime.timedelta(days=14),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'child_id'})
assert len(resp.json['data']) == 2
# empty guardian_external_id parameter is ignored
resp = app.get(
'/api/agendas/datetimes/?guardian_external_id=',
params={'subscribed': 'all', 'user_external_id': 'child_id'},
)
assert len(resp.json['data']) == 2
# guardian_external_id parameter is ignored if there is no custody agenda for child
resp = app.get(
'/api/agendas/datetimes/?guardian_external_id=xxx',
params={'subscribed': 'all', 'user_external_id': 'child_id'},
)
assert len(resp.json['data']) == 2
# add shared custody agenda
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father, second_guardian=mother, child=child, date_start=now()
)
father_rule = SharedCustodyRule.objects.create(
agenda=agenda, guardian=father, days=list(range(7)), weeks='even'
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd')
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-even-week'
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-odd-week'
# check date_start/date_end params
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'child_id',
'guardian_external_id': 'father_id',
'date_start': '2022-03-09',
'date_end': '2022-03-20',
},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-even-week'
# add father custody period spanning odd week event
period = SharedCustodyPeriod.objects.create(
agenda=agenda,
guardian=father,
date_start=datetime.date(2022, 3, 16),
date_end=datetime.date(2022, 3, 18),
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'first-agenda@event-even-week'
assert resp.json['data'][1]['id'] == 'first-agenda@event-odd-week'
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 0
# date_start is included
period.date_start = datetime.date(2022, 3, 17)
period.save()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 2
# date_end is excluded
period.date_start = datetime.date(2022, 3, 16)
period.date_end = datetime.date(2022, 3, 17)
period.save()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 1
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
# incomplete rules make some events not bookable
father_rule.delete()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 0
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
# unknown children
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'unknown_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 0
# unknown guardian
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'unknown_id'},
)
assert len(resp.json['data']) == 0
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
def test_datetimes_multiple_agendas_shared_custody_other_rules(app):
agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event-wednesday',
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=9, hour=14, minute=0)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-thursday',
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=10, hour=14, minute=0)),
places=5,
agenda=agenda,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='child_id',
date_start=now(),
date_end=now() + datetime.timedelta(days=14),
)
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father, second_guardian=mother, child=child, date_start=now()
)
father_rule = SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=[0, 1, 2])
mother_rule = SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=[3, 4, 5, 6])
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-wednesday'
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-thursday'
father_rule.days = [0, 1]
father_rule.save()
other_father_rule = SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=[2])
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-wednesday'
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event-thursday'
other_father_rule.delete()
mother_rule.days = [2, 3, 4, 5, 6]
mother_rule.save()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 0
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 2
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
def test_datetimes_multiple_agendas_shared_custody_recurring_event(app):
event_agenda = Agenda.objects.create(label='First agenda', kind='events', maximal_booking_delay=30)
Desk.objects.create(agenda=event_agenda, slug='_exceptions_holder')
start_datetime = make_aware(datetime.datetime(year=2022, month=3, day=9, hour=14, minute=0))
wednesday_event = Event.objects.create(
slug='event-wednesday',
start_datetime=start_datetime,
recurrence_days=[2],
recurrence_end_date=start_datetime + datetime.timedelta(days=30),
places=5,
agenda=event_agenda,
)
wednesday_event.create_all_recurrences()
start_datetime = make_aware(datetime.datetime(year=2022, month=3, day=10, hour=14, minute=0))
thursday_event = Event.objects.create(
slug='event-thursday',
start_datetime=start_datetime,
recurrence_days=[3],
recurrence_end_date=start_datetime + datetime.timedelta(days=30),
places=5,
agenda=event_agenda,
)
thursday_event.create_all_recurrences()
Subscription.objects.create(
agenda=event_agenda,
user_external_id='child_id',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father, second_guardian=mother, child=child, date_start=now()
)
father_rule = SharedCustodyRule.objects.create(
agenda=agenda, guardian=father, days=list(range(7)), weeks='even'
)
mother_rule = SharedCustodyRule.objects.create(
agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd'
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-thursday--2022-03-10-1400',
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-thursday--2022-03-17-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-thursday--2022-03-24-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
'first-agenda@event-thursday--2022-03-31-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-thursday--2022-03-10-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-thursday--2022-03-24-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-thursday--2022-03-17-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
'first-agenda@event-thursday--2022-03-31-1400',
]
# add father custody period spanning odd week event
SharedCustodyPeriod.objects.create(
agenda=agenda,
guardian=father,
date_start=datetime.date(2022, 3, 16),
date_end=datetime.date(2022, 3, 18),
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-thursday--2022-03-10-1400',
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-thursday--2022-03-17-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-thursday--2022-03-24-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-30-1400',
'first-agenda@event-thursday--2022-03-31-1400',
]
# check date_start/date_end
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'child_id',
'guardian_external_id': 'father_id',
'date_start': '2022-03-16',
'date_end': '2022-03-17',
},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-16-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'child_id',
'guardian_external_id': 'father_id',
'date_start': '2022-03-17',
'date_end': '2022-03-18',
},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-thursday--2022-03-17-1400',
]
# weirder rules
father_rule.days = [0, 1]
father_rule.weeks = ''
father_rule.save()
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=[2])
mother_rule.weeks = ''
mother_rule.days = [3, 4, 5, 6]
mother_rule.save()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-thursday--2022-03-17-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-thursday--2022-03-10-1400',
'first-agenda@event-thursday--2022-03-24-1400',
'first-agenda@event-thursday--2022-03-31-1400',
]
thursday_event.delete()
wednesday_event.recurrence_week_interval = 2
wednesday_event.save()
event_agenda.update_event_recurrences()
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'child_id'})
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
]
# add mother custody period spanning even week event
SharedCustodyPeriod.objects.create(
agenda=agenda,
guardian=mother,
date_start=datetime.date(2022, 3, 9),
date_end=datetime.date(2022, 3, 10),
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-23-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
]
@pytest.mark.freeze_time('2021-12-13 14:00') # Monday of 50th week
def test_datetimes_multiple_agendas_shared_custody_holiday_rules(app):
agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event-wednesday',
start_datetime=make_aware(datetime.datetime(year=2021, month=12, day=25, hour=14, minute=0)),
places=5,
agenda=agenda,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='child_id',
date_start=now(),
date_end=now() + datetime.timedelta(days=14),
)
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father, second_guardian=mother, child=child, date_start=now()
)
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='even', guardian=father)
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='odd', guardian=mother)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 0
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
# add father custody during holidays
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
christmas_holiday = TimePeriodExceptionGroup.objects.create(
unavailability_calendar=calendar, label='Christmas', slug='christmas'
)
TimePeriodException.objects.create(
unavailability_calendar=calendar,
start_datetime=make_aware(datetime.datetime(year=2021, month=12, day=18, hour=0, minute=0)),
end_datetime=make_aware(datetime.datetime(year=2022, month=1, day=3, hour=0, minute=0)),
group=christmas_holiday,
)
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=christmas_holiday)
rule.update_or_create_periods()
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 1
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 0
# check exceptional custody periods take precedence over holiday rules
SharedCustodyPeriod.objects.create(
agenda=agenda,
guardian=mother,
date_start=datetime.date(2021, 12, 22),
date_end=datetime.date(2021, 12, 30),
)
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert len(resp.json['data']) == 0
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
def test_datetimes_multiple_agendas_shared_custody_date_start(app):
agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
start_datetime = make_aware(datetime.datetime(year=2022, month=3, day=9, hour=14, minute=0))
wednesday_event = Event.objects.create(
slug='event-wednesday',
start_datetime=start_datetime,
recurrence_days=[2],
recurrence_end_date=start_datetime + datetime.timedelta(days=30),
places=5,
agenda=agenda,
)
wednesday_event.create_all_recurrences()
Subscription.objects.create(
agenda=agenda,
user_external_id='child_id',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father, second_guardian=mother, child=child, date_start=now()
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)))
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 0
agenda.date_end = datetime.date(year=2022, month=3, day=9)
agenda.save()
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father,
second_guardian=mother,
child=child,
date_start=datetime.date(year=2022, month=3, day=10),
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)))
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
]
agenda.date_end = datetime.date(year=2022, month=3, day=16)
agenda.save()
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father,
second_guardian=mother,
child=child,
date_start=datetime.date(year=2022, month=3, day=17),
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='odd')
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='even')
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
'first-agenda@event-wednesday--2022-03-30-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
]
# check date_start/date_end params
resp = app.get(
'/api/agendas/datetimes/',
params={
'subscribed': 'all',
'user_external_id': 'child_id',
'guardian_external_id': 'father_id',
'date_start': '2022-03-09',
'date_end': '2022-03-20',
},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
]
agenda.date_end = datetime.date(year=2022, month=3, day=21)
agenda.save()
other_person = Person.objects.create(user_external_id='other_person', first_name='O', last_name='P')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=other_person,
second_guardian=mother,
child=child,
date_start=datetime.date(year=2022, month=3, day=22),
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=other_person, days=list(range(7)), weeks='odd')
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='even')
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-09-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'other_person'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-30-1400',
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-16-1400',
'first-agenda@event-wednesday--2022-03-23-1400',
]
@pytest.mark.freeze_time('2022-03-01 14:00')
def test_datetimes_multiple_agendas_shared_custody_date_boundaries(app):
agenda = Agenda.objects.create(label='First agenda', kind='events', maximal_booking_delay=0)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
start_datetime = make_aware(datetime.datetime(year=2022, month=3, day=2, hour=14, minute=0))
wednesday_event = Event.objects.create(
slug='event-wednesday',
start_datetime=start_datetime,
recurrence_days=[2],
recurrence_end_date=datetime.datetime(year=2022, month=5, day=15),
places=5,
agenda=agenda,
)
wednesday_event.create_all_recurrences()
Subscription.objects.create(
agenda=agenda,
user_external_id='child_id',
date_start=wednesday_event.start_datetime,
date_end=wednesday_event.recurrence_end_date,
)
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father,
second_guardian=mother,
child=child,
date_start=datetime.datetime(year=2022, month=3, day=15), # 15 days after recurring event start
date_end=datetime.datetime(year=2022, month=3, day=30), # 30 days after recurring event start
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)))
agenda = SharedCustodyAgenda.objects.create(
first_guardian=father,
second_guardian=mother,
child=child,
date_start=datetime.datetime(year=2022, month=4, day=13), # 45 days after recurring event start
date_end=datetime.datetime(year=2022, month=4, day=28), # 60 days after recurring event start
)
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)))
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-02-1400', # no custody agenda
'first-agenda@event-wednesday--2022-03-09-1400', # no custody agenda
'first-agenda@event-wednesday--2022-03-16-1400', # has custody
'first-agenda@event-wednesday--2022-03-23-1400', # has custody
'first-agenda@event-wednesday--2022-03-30-1400', # has custody
'first-agenda@event-wednesday--2022-04-06-1400', # no custody agenda
'first-agenda@event-wednesday--2022-05-04-1400', # no custody agenda
'first-agenda@event-wednesday--2022-05-11-1400', # no custody agenda
]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-wednesday--2022-03-02-1400', # no custody agenda
'first-agenda@event-wednesday--2022-03-09-1400', # no custody agenda
'first-agenda@event-wednesday--2022-04-06-1400', # no custody agenda
'first-agenda@event-wednesday--2022-04-13-1400', # has custody
'first-agenda@event-wednesday--2022-04-20-1400', # has custody
'first-agenda@event-wednesday--2022-04-27-1400', # has custody
'first-agenda@event-wednesday--2022-05-04-1400', # no custody agenda
'first-agenda@event-wednesday--2022-05-11-1400', # no custody agenda
]
def test_datetimes_multiple_agendas_with_status(app):
agenda = Agenda.objects.create(label='agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event_booked = Event.objects.create(
slug='event-booked',
start_datetime=now() - datetime.timedelta(days=15),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_booked, user_external_id='xxx')
Event.objects.create(
slug='event-free',
start_datetime=now() - datetime.timedelta(days=14),
places=5,
agenda=agenda,
)
event_cancelled = Event.objects.create(
slug='event-cancelled',
start_datetime=now() - datetime.timedelta(days=13),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_cancelled, user_external_id='xxx', cancellation_datetime=now())
event_absence = Event.objects.create(
slug='event-absence',
start_datetime=now() - datetime.timedelta(days=12),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_absence, user_external_id='xxx', user_was_present=False)
event_absence_with_reason = Event.objects.create(
slug='event-absence_with_reason',
start_datetime=now() - datetime.timedelta(days=11),
places=5,
agenda=agenda,
)
Booking.objects.create(
event=event_absence_with_reason,
user_external_id='xxx',
user_was_present=False,
user_check_type_slug='foo-reason',
)
event_presence = Event.objects.create(
slug='event-presence',
start_datetime=now() - datetime.timedelta(days=10),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_presence, user_external_id='xxx', user_was_present=True)
event_presence_with_reason = Event.objects.create(
slug='event-presence_with_reason',
start_datetime=now() - datetime.timedelta(days=9),
places=5,
agenda=agenda,
)
Booking.objects.create(
event=event_presence_with_reason,
user_external_id='xxx',
user_was_present=True,
user_check_type_slug='foo-reason',
)
event_booked_future = Event.objects.create(
slug='event-booked-future',
start_datetime=now() + datetime.timedelta(days=1),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_booked_future, user_external_id='xxx')
Event.objects.create(
slug='event-free-future',
start_datetime=now() + datetime.timedelta(days=2),
places=5,
agenda=agenda,
)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': 'agenda', 'show_past_events': True, 'user_external_id': 'xxx'},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-presence_with_reason',
'agenda@event-booked-future',
'agenda@event-free-future',
]
for d in resp.json['data']:
assert 'status' not in d
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': 'agenda',
'show_past_events': True,
'user_external_id': 'xxx',
'with_status': True,
},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-presence_with_reason',
'agenda@event-booked-future',
'agenda@event-free-future',
]
assert [d['status'] for d in resp.json['data']] == [
'booked',
'free',
'cancelled',
'absence',
'absence',
'booked',
'booked',
'booked',
'free',
]
# other user
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': 'agenda',
'show_past_events': True,
'user_external_id': 'yyy',
'with_status': True,
},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-presence_with_reason',
'agenda@event-booked-future',
'agenda@event-free-future',
]
assert [d['status'] for d in resp.json['data']] == [
'free',
'free',
'free',
'free',
'free',
'free',
'free',
'free',
'free',
]
# check errors
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': 'agenda', 'show_past_events': True, 'with_status': True},
status=400,
)
assert 'required' in resp.json['errors']['user_external_id'][0]
@pytest.mark.freeze_time('2021-09-06 12:00')
def test_datetimes_multiple_agendas_overlapping_events(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Event.objects.create(
label='Event 12-14',
start_datetime=now() + datetime.timedelta(days=5),
duration=120,
places=5,
agenda=agenda,
)
Event.objects.create(
label='Event containing all events',
start_datetime=now() + datetime.timedelta(days=4, hours=23),
duration=440,
places=5,
agenda=agenda,
)
second_agenda = Agenda.objects.create(label='Foo bar 2', kind='events')
Event.objects.create(
label='Event 13-15',
start_datetime=now() + datetime.timedelta(days=5, hours=1),
duration=120,
places=5,
agenda=second_agenda,
)
Event.objects.create(
label='Event 14-16',
start_datetime=now() + datetime.timedelta(days=5, hours=2),
duration=120,
places=5,
agenda=second_agenda,
)
Event.objects.create(
label='Event no duration',
start_datetime=now() + datetime.timedelta(days=5, hours=1),
places=5,
agenda=second_agenda,
)
Event.objects.create(
label='Event other day',
start_datetime=now() + datetime.timedelta(days=6),
places=5,
agenda=second_agenda,
)
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'foo-bar,foo-bar-2', 'check_overlaps': True})
expected = [
(
'foo-bar@event-containing-all-events',
{'foo-bar@event-12-14', 'foo-bar-2@event-13-15', 'foo-bar-2@event-14-16'},
),
('foo-bar@event-12-14', {'foo-bar@event-containing-all-events', 'foo-bar-2@event-13-15'}),
(
'foo-bar-2@event-13-15',
{'foo-bar@event-containing-all-events', 'foo-bar@event-12-14', 'foo-bar-2@event-14-16'},
),
('foo-bar-2@event-no-duration', set()),
('foo-bar-2@event-14-16', {'foo-bar@event-containing-all-events', 'foo-bar-2@event-13-15'}),
('foo-bar-2@event-other-day', set()),
]
assert [(x['id'], set(x['overlaps'])) for x in resp.json['data']] == expected
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'foo-bar,foo-bar-2'})
assert ['overlaps' not in x for x in resp.json['data']]
# no subscription found for this user
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'xxx', 'check_overlaps': True},
)
assert len(resp.json['data']) == 0