448 lines
19 KiB
Python
448 lines
19 KiB
Python
import datetime
|
||
|
||
import pytest
|
||
from django.core.files.base import ContentFile
|
||
from django.db import connection
|
||
from django.test.utils import CaptureQueriesContext
|
||
from django.utils.timezone import now
|
||
|
||
from chrono.agendas.models import (
|
||
Person,
|
||
SharedCustodyAgenda,
|
||
SharedCustodyHolidayRule,
|
||
SharedCustodyPeriod,
|
||
SharedCustodyRule,
|
||
SharedCustodySettings,
|
||
TimePeriodExceptionGroup,
|
||
UnavailabilityCalendar,
|
||
)
|
||
from tests.utils import login
|
||
|
||
pytestmark = pytest.mark.django_db
|
||
|
||
|
||
with open('tests/data/holidays.ics') as f:
|
||
ICS_HOLIDAYS = f.read()
|
||
|
||
|
||
@pytest.mark.freeze_time('2022-02-22 14:00') # Tuesday
|
||
def test_shared_custody_agenda_settings_rules(app, admin_user):
|
||
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()
|
||
)
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
resp = resp.click('Settings')
|
||
assert 'Custody agenda of John Doe and Jane Doe' in resp.text
|
||
assert 'Custody rules are not complete.' in resp.text
|
||
assert 'This agenda doesn\'t have any custody rules yet.' in resp.text
|
||
|
||
resp = resp.click('Add custody rule')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['days'] = list(range(7))
|
||
resp.form['weeks'] = 'even'
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert 'Custody rules are not complete.' in resp.text
|
||
assert 'John Doe, daily, on even weeks' in resp.text
|
||
|
||
resp = resp.click('Add custody rule')
|
||
resp.form['guardian'] = mother.pk
|
||
resp.form['days'] = list(range(7))
|
||
resp.form['weeks'] = 'odd'
|
||
resp = resp.form.submit().follow()
|
||
assert 'Custody rules are not complete.' not in resp.text
|
||
assert 'John Doe, daily, on even weeks' in resp.text
|
||
assert 'Jane Doe, daily, on odd weeks' in resp.text
|
||
|
||
resp = resp.click('John Doe, daily, on even weeks')
|
||
resp.form['days'] = list(range(6))
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert 'Custody rules are not complete.' in resp.text
|
||
|
||
resp = resp.click('John Doe, from Monday to Saturday, on even weeks')
|
||
resp.form['days'] = [0]
|
||
resp.form['weeks'] = 'odd'
|
||
resp = resp.form.submit()
|
||
assert 'Rule overlaps existing rules.' in resp.text
|
||
|
||
resp.form['weeks'] = 'even'
|
||
resp = resp.form.submit().follow()
|
||
|
||
resp = resp.click('remove', index=1)
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert SharedCustodyRule.objects.count() == 1
|
||
|
||
|
||
def test_shared_custody_agenda_settings_rules_require_days(app, admin_user):
|
||
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()
|
||
)
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
|
||
resp = resp.click('Add custody rule')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['weeks'] = 'even'
|
||
resp = resp.form.submit()
|
||
assert 'This field is required.' in resp.text
|
||
|
||
resp.form['days'] = [0]
|
||
resp.form.submit().follow()
|
||
assert SharedCustodyRule.objects.count() == 1
|
||
|
||
|
||
@pytest.mark.freeze_time('2022-02-22 14:00') # Tuesday
|
||
def test_shared_custody_agenda_settings_periods(app, admin_user):
|
||
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()
|
||
)
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
assert 'This agenda doesn\'t have any custody period.' in resp.text
|
||
|
||
resp = resp.click('Add custody period')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['date_start'] = '2022-03-01'
|
||
resp.form['date_end'] = '2022-03-03'
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:time-periods' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert 'This agenda doesn\'t have any custody period.' not in resp.text
|
||
assert 'John Doe, 03/01/2022 → 03/03/2022' in resp.text
|
||
|
||
resp = resp.click('John Doe, 03/01/2022 → 03/03/2022')
|
||
resp.form['guardian'] = mother.pk
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:time-periods' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert 'Jane Doe, 03/01/2022 → 03/03/2022' in resp.text
|
||
|
||
resp = resp.click('Add custody period')
|
||
resp.form['guardian'] = mother.pk
|
||
resp.form['date_start'] = '2022-03-05'
|
||
resp.form['date_end'] = '2022-03-03'
|
||
resp = resp.form.submit()
|
||
assert 'End date must be greater than start date.' in resp.text
|
||
|
||
resp.form['date_start'] = '2022-03-02'
|
||
resp.form['date_end'] = '2022-03-06'
|
||
resp = resp.form.submit()
|
||
assert 'Period overlaps existing periods.' in resp.text
|
||
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.click('remove', href='delete')
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:time-periods' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert not SharedCustodyPeriod.objects.exists()
|
||
|
||
|
||
@pytest.mark.freeze_time('2022-02-22 14:00') # Tuesday
|
||
def test_shared_custody_agenda_month_view(app, admin_user):
|
||
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.date(2022, 1, 1)
|
||
)
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='even')
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
assert 'Custody agenda of John Doe and Jane Doe for James Doe' in resp.text
|
||
assert 'February 2022' in resp.text
|
||
assert 'Configuration is not completed yet.' in resp.text
|
||
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd')
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
assert 'Configuration is not completed yet.' not in resp.text
|
||
|
||
assert all('Week %s' % i in resp.text for i in range(5, 10))
|
||
assert resp.pyquery('tbody tr th.today span').text() == 'Tuesday 22'
|
||
|
||
days = [x.text for x in resp.pyquery('tbody tr th span')]
|
||
assert len(days) == 7 * 5
|
||
assert days[:3] == ['Monday 31', 'Tuesday 1', 'Wednesday 2']
|
||
assert days[-3:] == ['Friday 4', 'Saturday 5', 'Sunday 6']
|
||
|
||
tds = [x.text for x in resp.pyquery('tbody tr td')]
|
||
for week_number, i in zip(range(5, 10), range(0, 29, 7)):
|
||
guardian = 'Jane Doe' if week_number % 2 else 'John Doe'
|
||
assert tds[i : i + 7] == [guardian] * 7
|
||
|
||
SharedCustodyPeriod.objects.create(
|
||
agenda=agenda,
|
||
guardian=father,
|
||
date_start=datetime.date(2022, 2, 1),
|
||
date_end=datetime.date(2022, 2, 3),
|
||
)
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
tds = [x.text for x in resp.pyquery('tbody tr td')]
|
||
assert tds[:7] == ['Jane Doe', 'John Doe', 'John Doe', 'Jane Doe', 'Jane Doe', 'Jane Doe', 'Jane Doe']
|
||
|
||
old_resp = resp
|
||
resp = resp.click('→')
|
||
assert 'March 2022' in resp.text
|
||
assert 'today' not in resp.text
|
||
assert all('Week %s' % i in resp.text for i in range(9, 14))
|
||
|
||
days = [x.text for x in resp.pyquery('tbody tr th span')]
|
||
assert len(days) == 7 * 5
|
||
assert days[:3] == ['Monday 28', 'Tuesday 1', 'Wednesday 2']
|
||
assert days[-3:] == ['Friday 1', 'Saturday 2', 'Sunday 3']
|
||
|
||
resp = resp.click('←')
|
||
assert resp.text == old_resp.text
|
||
|
||
app.get('/manage/shared-custody/%s/42/42/' % agenda.pk, status=404)
|
||
|
||
|
||
@pytest.mark.freeze_time('2022-02-01 14:00') # Tuesday
|
||
def test_shared_custody_agenda_month_view_date_start(app, admin_user):
|
||
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.date(2022, 1, 1)
|
||
)
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)))
|
||
|
||
app = login(app)
|
||
|
||
# custody for the whole month
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
assert resp.text.count('<td></td>') == 0
|
||
assert len([x.text for x in resp.pyquery('tbody tr td.guardian')]) == 35
|
||
|
||
# all days are shown
|
||
days = [x.text for x in resp.pyquery('tbody tr th span')]
|
||
assert len(days) == 7 * 5
|
||
|
||
# custody for half the month
|
||
agenda.date_start = datetime.date(2022, 2, 14)
|
||
agenda.save()
|
||
|
||
resp = app.get('/manage/shared-custody/%s/' % agenda.pk).follow()
|
||
assert resp.text.count('<td></td>') == 14
|
||
assert len([x.text for x in resp.pyquery('tbody tr td.guardian')]) == 21
|
||
|
||
# all days are still shown
|
||
new_days = [x.text for x in resp.pyquery('tbody tr th span')]
|
||
assert days == new_days
|
||
|
||
# month before date_start
|
||
resp = resp.click('←')
|
||
assert resp.text.count('<td></td>') == 42
|
||
assert len([x.text for x in resp.pyquery('tbody tr td.guardian')]) == 0
|
||
|
||
|
||
def test_shared_custody_agenda_month_view_queries(app, admin_user):
|
||
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=[0, 1, 2], weeks='even')
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=[3, 4, 5, 6], weeks='odd')
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=[0, 1, 2], weeks='odd')
|
||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=[3, 4, 5, 6], weeks='even')
|
||
|
||
for i in range(1, 10):
|
||
SharedCustodyPeriod.objects.create(
|
||
agenda=agenda,
|
||
guardian=mother,
|
||
date_start=datetime.date(year=2022, month=12, day=i),
|
||
date_end=datetime.date(year=2022, month=12, day=i + 1),
|
||
)
|
||
|
||
# configure holidays
|
||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||
SharedCustodySettings.objects.create(holidays_calendar=unavailability_calendar)
|
||
source = unavailability_calendar.timeperiodexceptionsource_set.create(
|
||
ics_filename='holidays.ics', ics_file=ContentFile(ICS_HOLIDAYS, name='holidays.ics')
|
||
)
|
||
source.refresh_timeperiod_exceptions_from_ics()
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.click('Add custody rule during holidays')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['holiday'].select(text='Vacances de Noël')
|
||
resp = resp.form.submit().follow()
|
||
|
||
with CaptureQueriesContext(connection) as ctx:
|
||
app.get('/manage/shared-custody/%s/2022/12/' % agenda.pk)
|
||
assert len(ctx.captured_queries) == 10
|
||
|
||
|
||
def test_shared_custody_agenda_holiday_rules(app, admin_user):
|
||
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()
|
||
)
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
assert 'Add custody rule during holidays' not in resp.text
|
||
assert 'Custody rules during holidays' not in resp.text
|
||
|
||
# configure holidays
|
||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||
SharedCustodySettings.objects.create(holidays_calendar=unavailability_calendar)
|
||
source = unavailability_calendar.timeperiodexceptionsource_set.create(
|
||
ics_filename='holidays.ics', ics_file=ContentFile(ICS_HOLIDAYS, name='holidays.ics')
|
||
)
|
||
source.refresh_timeperiod_exceptions_from_ics()
|
||
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.click('Add custody rule during holidays')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['holiday'].select(text='Vacances de Noël')
|
||
resp.form['years'] = 'odd'
|
||
resp.form['periodicity'] = 'first-half'
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:holidays' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||
assert SharedCustodyPeriod.objects.count() == 3
|
||
assert 'This agenda doesn\'t have any custody period.' in resp.text
|
||
|
||
resp = resp.click('John Doe, Vacances de Noël, the first half, on odd years')
|
||
resp.form['years'] = ''
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:holidays' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert 'John Doe, Vacances de Noël, the first half' in resp.text
|
||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||
assert SharedCustodyPeriod.objects.count() == 6
|
||
|
||
resp = resp.click('Add custody rule during holidays')
|
||
resp.form['guardian'] = mother.pk
|
||
resp.form['holiday'].select(text='Vacances de Noël')
|
||
resp.form['periodicity'] = 'first-half'
|
||
resp = resp.form.submit()
|
||
assert 'Rule overlaps existing rules.' in resp.text
|
||
|
||
resp.form['periodicity'] = 'second-half'
|
||
resp = resp.form.submit().follow()
|
||
assert 'Jane Doe, Vacances de Noël, the second half' in resp.text
|
||
|
||
assert SharedCustodyHolidayRule.objects.count() == 2
|
||
assert SharedCustodyPeriod.objects.count() == 12
|
||
|
||
resp = resp.click('remove', index=1)
|
||
resp = resp.form.submit()
|
||
assert resp.location.endswith('/manage/shared-custody/%s/settings/#open:holidays' % agenda.pk)
|
||
resp = resp.follow()
|
||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||
assert SharedCustodyPeriod.objects.count() == 6
|
||
|
||
resp = resp.click('Add custody rule during holidays')
|
||
resp.form['guardian'] = father.pk
|
||
resp.form['holiday'].select(text='Vacances de Noël')
|
||
resp.form['periodicity'] = 'first-and-third-quarters'
|
||
resp = resp.form.submit()
|
||
assert 'Short holidays cannot be cut into quarters.' in resp.text
|
||
|
||
resp.form['holiday'].select(text='Vacances d’Été')
|
||
resp = resp.form.submit().follow()
|
||
assert 'John Doe, Vacances d’Été, the first and third quarters' in resp.text
|
||
|
||
# if dates get deleted, rules still exist but holiday is not shown anymore
|
||
summer_holidays = TimePeriodExceptionGroup.objects.get(slug='summer_holidays')
|
||
summer_holidays.exceptions.all().delete()
|
||
|
||
assert SharedCustodyHolidayRule.objects.filter(holiday=summer_holidays).exists()
|
||
|
||
resp = resp.click('Add custody rule during holidays')
|
||
assert [x[2] for x in resp.form['holiday'].options] == ['---------', 'Vacances de Noël']
|
||
|
||
# holiday name is shown on month view
|
||
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('/manage/shared-custody/%s/2022/12/' % agenda.pk)
|
||
assert 'John Doe (Vacances de Noël)' in resp.text
|
||
|
||
# calendar cannot be deleted
|
||
resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
|
||
resp = resp.click('Delete')
|
||
resp = resp.form.submit().follow()
|
||
assert 'This calendar cannot be deleted because it is used by shared custody agendas.' in resp.text
|
||
|
||
|
||
def test_shared_custody_settings_feature_flag(app, admin_user, settings):
|
||
settings.SHARED_CUSTODY_ENABLED = False
|
||
app = login(app)
|
||
resp = app.get('/manage/')
|
||
assert 'Shared custody' not in resp.text
|
||
|
||
settings.SHARED_CUSTODY_ENABLED = True
|
||
resp = app.get('/manage/')
|
||
assert 'Shared custody' in resp.text
|
||
|
||
|
||
def test_shared_custody_settings_management_role(app, admin_user, manager_user):
|
||
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()
|
||
)
|
||
|
||
app = login(app, username='manager', password='manager')
|
||
app.get('/manage/shared-custody/%s/settings/' % agenda.pk, status=403)
|
||
|
||
app.reset()
|
||
app = login(app)
|
||
resp = app.get('/manage/')
|
||
resp = resp.click('Shared custody')
|
||
resp.form['management_role'] = manager_user.groups.all()[0].pk
|
||
resp.form.submit()
|
||
|
||
app.reset()
|
||
app = login(app, username='manager', password='manager')
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
assert 'Custody agenda of John Doe and Jane Doe' in resp.text
|
||
|
||
|
||
def test_shared_custody_agenda_delete(app, admin_user, manager_user):
|
||
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()
|
||
)
|
||
SharedCustodySettings.objects.create(management_role=manager_user.groups.all()[0])
|
||
|
||
app = login(app, username='manager', password='manager')
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
assert 'Delete' not in resp.text
|
||
|
||
app = login(app)
|
||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||
resp = resp.click('Delete')
|
||
resp = resp.form.submit().follow()
|
||
assert not SharedCustodyAgenda.objects.exists()
|