436 lines
16 KiB
Python
436 lines
16 KiB
Python
import datetime
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
import vobject
|
|
from django.utils.html import escape
|
|
|
|
from eo_gestion.eo_conges.views import ReportError
|
|
|
|
from .utils import login
|
|
|
|
|
|
@pytest.fixture
|
|
def events():
|
|
with mock.patch('caldav.davclient.DAVClient.principal') as mocked_principal:
|
|
mocked_principal.side_effet = FakePrincipal()
|
|
yield
|
|
|
|
|
|
def get_event(summary, start, end, category='Congés'):
|
|
event = vobject.newFromBehavior('vevent')
|
|
event = event.transformToNative()
|
|
event.add('summary').value = summary
|
|
event.add('dtstart').value = start
|
|
event.add('dtend').value = end
|
|
event.add('categories').value = [category]
|
|
return event
|
|
|
|
|
|
def test_conges_redirect(app, settings):
|
|
login(app)
|
|
resp = app.get('/conges/')
|
|
assert resp.location == '/conges/2019/1/'
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
events = mocked_get_events.return_value = []
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert [x.text for x in resp.pyquery('.worker span')] == [
|
|
'Jean Dupont (matricule 42)',
|
|
'Tickets restaurant : 19 tickets de 8 euros',
|
|
'Congés : 0.',
|
|
]
|
|
|
|
assert '/conges/2022/12/' in resp.text
|
|
assert '/conges/2023/2/' in resp.text
|
|
|
|
events.append(
|
|
get_event('Jean', datetime.datetime(2023, 1, 2, 8, 00), datetime.datetime(2023, 1, 2, 18, 00))
|
|
)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert [x.text for x in resp.pyquery('.worker span')] == [
|
|
'Jean Dupont (matricule 42)',
|
|
'Tickets restaurant : 19 tickets de 8 euros',
|
|
'Congés : le 02/01.',
|
|
]
|
|
|
|
events += [
|
|
# one day, using dates
|
|
get_event('Jean', datetime.date(2023, 1, 4), datetime.date(2023, 1, 5)),
|
|
# two days range, using mixed date/datetimes
|
|
get_event('Jean', datetime.datetime(2023, 1, 10, 8, 00), datetime.datetime(2023, 1, 11)),
|
|
# two days range, using dates
|
|
get_event('Jean', datetime.date(2023, 1, 12), datetime.date(2023, 1, 14)),
|
|
# 4 days range, using dates
|
|
get_event('Jean', datetime.date(2023, 1, 16), datetime.date(2023, 1, 20)),
|
|
# only morning
|
|
get_event('Jean', datetime.datetime(2023, 1, 23, 8, 00), datetime.datetime(2023, 1, 23, 14, 00)),
|
|
# only afternoon
|
|
get_event('Jean', datetime.datetime(2023, 1, 24, 14, 00), datetime.datetime(2023, 1, 24, 18, 00)),
|
|
]
|
|
|
|
# 6 days range, using rrule
|
|
event = get_event('Jean', datetime.date(2023, 1, 25), datetime.date(2023, 1, 26))
|
|
event.add('rrule').value = 'FREQ=DAILY;UNTIL=20230131'
|
|
events.append(event)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == (
|
|
'Congés : le 02/01, le 04/01, les 10 et 11/01, les 12 et 13/01, du 16 au 19/01, 0,5j le 23/01, '
|
|
'0,5j le 24/01, du 25 au 31/01.'
|
|
)
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_fatal_errors(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
mocked_get_events.side_effect = ReportError('Error xxx')
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Error xxx' in resp.text
|
|
|
|
app.get('/conges/2023/42/', status=404)
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_multiple_match_error(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
{'username': 'jdurand', 'display_name': 'Jean Durand', 'number': 43},
|
|
]
|
|
|
|
mocked_get_events.return_value = [
|
|
get_event('Jean', datetime.date(2023, 1, 6), datetime.date(2023, 1, 10)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert (
|
|
escape("L'évènement Jean correspond à plusieurs coopérateurices : jdurand et jdupont.") in resp.text
|
|
)
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_no_match_error(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
mocked_get_events.return_value = [
|
|
get_event('Jean', datetime.date(2023, 1, 6), datetime.date(2023, 1, 7)),
|
|
get_event('xxx', datetime.date(2023, 1, 8), datetime.date(2023, 1, 9)),
|
|
get_event('yyy', datetime.date(2023, 1, 8), datetime.date(2023, 1, 9)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert escape('Aucun·e coopérateurice trouvé·e pour les évènements : xxx, yyy') in resp.text
|
|
assert 'le 06/01' in resp.text
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_day_off_error(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
mocked_get_events.return_value = []
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert escape("Jean Dupont n'a pas de jour off.") in resp.text
|
|
|
|
ev1 = get_event('Jean off', datetime.date(2023, 1, 6), datetime.date(2023, 1, 7), category='Journées off')
|
|
ev1.add('rrule').value = 'FREQ=WEEKLY;BYDAY=MO'
|
|
ev2 = get_event(
|
|
'Jean off 2', datetime.date(2023, 1, 8), datetime.date(2023, 1, 9), category='Journées off'
|
|
)
|
|
ev2.add('rrule').value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
mocked_get_events.return_value = [ev1, ev2]
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Jean Dupont a trop de jours off : Jean off, Jean off 2.' in resp.text
|
|
|
|
ev1.dtstart.value = datetime.datetime(2023, 1, 6, 8, 0)
|
|
ev1.dtend.value = datetime.datetime(2023, 1, 6, 13, 0)
|
|
ev2.dtstart.value = datetime.datetime(2023, 1, 9, 14, 0)
|
|
ev2.dtend.value = datetime.datetime(2023, 1, 9, 19, 0)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Jean Dupont a trop de jours off' not in resp.text
|
|
|
|
ev3 = get_event(
|
|
'Jean off 3',
|
|
datetime.datetime(2023, 1, 9, 14, 0),
|
|
datetime.datetime(2023, 1, 10, 19, 0),
|
|
category='Journées off',
|
|
)
|
|
ev3.add('rrule').value = 'FREQ=WEEKLY;BYDAY=TH'
|
|
mocked_get_events.return_value.append(ev3)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Jean Dupont a trop de jours off : Jean off, Jean off 2, Jean off 3.' in resp.text
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_is_parisian(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
mocked_get_events.return_value = []
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Carte transport Paris 50%' not in resp.text
|
|
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'][0]['is_parisian'] = True
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Carte transport Paris 50%' in resp.text
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_ignored_workers(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
{'username': 'lmichel', 'display_name': 'Louise Michel', 'number': 0, 'ignore': True},
|
|
]
|
|
mocked_get_events.return_value = [
|
|
get_event('congés jdupont', datetime.date(2023, 1, 2), datetime.date(2023, 1, 3)),
|
|
get_event('congés lmichel', datetime.date(2023, 1, 3), datetime.date(2023, 1, 4)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert 'Jean' in resp.text
|
|
assert 'Louise' not in resp.text
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_worker_possible_names(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
{'username': 'jmartin', 'display_name': 'Jean Martin', 'number': 43, 'aliases': ['Jeannot']},
|
|
]
|
|
|
|
mocked_get_events.return_value = [
|
|
get_event('congés jdupont', datetime.date(2023, 1, 2), datetime.date(2023, 1, 3)),
|
|
get_event('Jeannot en vacances', datetime.date(2023, 1, 3), datetime.date(2023, 1, 4)),
|
|
get_event('congés JD', datetime.date(2023, 1, 5), datetime.date(2023, 1, 6)),
|
|
get_event('JeanM', datetime.date(2023, 1, 6), datetime.date(2023, 1, 7)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert [x.text for x in resp.pyquery('.worker span.holidays')] == [
|
|
'Congés : le 02/01, le 05/01.',
|
|
'Congés : le 03/01, le 06/01.',
|
|
]
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_strip_weekend(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
mocked_get_events.return_value = [
|
|
# starts friday, ends monday
|
|
get_event('Jean', datetime.date(2023, 1, 6), datetime.date(2023, 1, 10)),
|
|
# start saturday, ends sunday next week
|
|
get_event('Jean', datetime.date(2023, 1, 14), datetime.date(2023, 1, 23)),
|
|
# two days of weekend
|
|
get_event('Jean', datetime.date(2023, 1, 28), datetime.date(2023, 1, 30)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 06 au 09/01, du 16 au 20/01.'
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_month_span(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
mocked_get_events.return_value = [
|
|
# starts in december
|
|
get_event('Jean', datetime.date(2022, 12, 25), datetime.date(2023, 1, 5)),
|
|
# ends in february
|
|
get_event('Jean', datetime.date(2023, 1, 30), datetime.date(2023, 2, 10)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 02 au 04/01, les 30 et 31/01.'
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_split_on_day_off(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
holidays = get_event('Jean', datetime.date(2023, 1, 2), datetime.date(2023, 1, 7))
|
|
events = mocked_get_events.return_value = [holidays]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 02 au 06/01.'
|
|
|
|
# off on wednesday, holidays split in half
|
|
event = get_event('Jean', datetime.date(2023, 1, 4), datetime.date(2023, 1, 5), category='Journées off')
|
|
event.add('rrule').value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
events.append(event)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : les 02 et 03/01, les 05 et 06/01.'
|
|
|
|
# off on friday, holidays end one day sooner
|
|
event.rrule.value = 'FREQ=WEEKLY;BYDAY=FR'
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 02 au 05/01.'
|
|
|
|
# off on monday, holidays start one day later
|
|
event.rrule.value = 'FREQ=WEEKLY;BYDAY=MO'
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 03 au 06/01.'
|
|
|
|
# long holidays get split multiple times
|
|
holidays.dtend.value = datetime.date(2023, 1, 21)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert (
|
|
resp.pyquery('.worker span.holidays').text()
|
|
== 'Congés : du 03 au 06/01, du 10 au 13/01, du 17 au 20/01.'
|
|
)
|
|
|
|
# split on wednesday
|
|
event.rrule.value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert (
|
|
resp.pyquery('.worker span.holidays').text()
|
|
== 'Congés : les 02 et 03/01, du 05 au 10/01, du 12 au 17/01, les 19 et 20/01.'
|
|
)
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_split_on_multiple_days_off(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
holidays = get_event('Jean', datetime.date(2023, 1, 2), datetime.date(2023, 1, 7))
|
|
events = mocked_get_events.return_value = [holidays]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : du 02 au 06/01.'
|
|
|
|
ev1 = get_event(
|
|
'Jean off lundi matin',
|
|
datetime.datetime(2023, 1, 6, 8, 0),
|
|
datetime.datetime(2023, 1, 6, 13, 0),
|
|
category='Journées off',
|
|
)
|
|
ev1.add('rrule').value = 'FREQ=WEEKLY;BYDAY=MO'
|
|
ev2 = get_event(
|
|
'Jean off mercredi aprem',
|
|
datetime.datetime(2023, 1, 9, 14, 0),
|
|
datetime.datetime(2023, 1, 9, 19, 0),
|
|
category='Journées off',
|
|
)
|
|
ev2.add('rrule').value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
mocked_get_events.return_value += [ev1, ev2]
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert (
|
|
resp.pyquery('.worker span.holidays').text()
|
|
== 'Congés : 0,5j le 02/01, le 03/01, 0,5j le 04/01, les 05 et 06/01.'
|
|
)
|
|
|
|
# long holidays get split multiple times
|
|
holidays.dtend.value = datetime.date(2023, 1, 14)
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == (
|
|
'Congés : 0,5j le 02/01, le 03/01, 0,5j le 04/01, les 05 et 06/01, 0,5j le 09/01, '
|
|
'le 10/01, 0,5j le 11/01, les 12 et 13/01.'
|
|
)
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_split_on_day_off_single_day(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
# off on wednesday
|
|
off_event = get_event(
|
|
'Jean', datetime.date(2023, 1, 4), datetime.date(2023, 1, 5), category='Journées off'
|
|
)
|
|
off_event.add('rrule').value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
|
|
mocked_get_events.return_value = [
|
|
off_event,
|
|
# holidays on monday
|
|
get_event('Jean', datetime.date(2023, 1, 2), datetime.date(2023, 1, 3)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : le 02/01.'
|
|
|
|
# off on monday
|
|
off_event.rrule.value = 'FREQ=WEEKLY;BYDAY=MO'
|
|
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : 0.'
|
|
|
|
|
|
@mock.patch('eo_gestion.eo_conges.views.WorkersMonthlyReport.get_events')
|
|
def test_conges_split_on_multiple_days_off_single_day(mocked_get_events, app, settings):
|
|
settings.WORKERS_CALENDAR_CONFIG['workers'] = [
|
|
{'username': 'jdupont', 'display_name': 'Jean Dupont', 'number': 42},
|
|
]
|
|
|
|
ev1 = get_event(
|
|
'Jean off lundi matin',
|
|
datetime.datetime(2023, 1, 6, 8, 0),
|
|
datetime.datetime(2023, 1, 6, 13, 0),
|
|
category='Journées off',
|
|
)
|
|
ev1.add('rrule').value = 'FREQ=WEEKLY;BYDAY=MO'
|
|
ev2 = get_event(
|
|
'Jean off mercredi aprem',
|
|
datetime.datetime(2023, 1, 9, 14, 0),
|
|
datetime.datetime(2023, 1, 9, 19, 0),
|
|
category='Journées off',
|
|
)
|
|
ev2.add('rrule').value = 'FREQ=WEEKLY;BYDAY=WE'
|
|
|
|
mocked_get_events.return_value = [
|
|
ev1,
|
|
ev2,
|
|
# holidays on monday
|
|
get_event('Jean', datetime.date(2023, 1, 2), datetime.date(2023, 1, 3)),
|
|
]
|
|
|
|
login(app)
|
|
resp = app.get('/conges/2023/01/')
|
|
assert resp.pyquery('.worker span.holidays').text() == 'Congés : 0,5j le 02/01.'
|