eo_conges: add support for half days off (#72676)
gitea/barbacompta/pipeline/head This commit looks good Details

This commit is contained in:
Valentin Deniaud 2023-08-03 10:31:26 +02:00
parent 7f25841bce
commit 00bc42b98a
2 changed files with 123 additions and 11 deletions

View File

@ -149,16 +149,25 @@ class WorkersMonthlyReport(MonthMixin, YearMixin, TemplateView):
worker_possible_names = [slugify(x) for x in worker_possible_names]
errors = []
day_off = None
days_off = None
days_off = [x for x in day_off_events if self.is_event_for_worker(x, worker_possible_names)]
if len(days_off) > 1:
half_days_off = [
x
for x in days_off
if hasattr(x.dtstart.value, 'time')
and (
x.dtstart.value.time() > datetime.time(12, 00)
or x.dtend.value.time() <= datetime.time(15, 00)
)
]
if len(days_off) > 2 or len(days_off) == 2 and len(half_days_off) != 2:
errors.append(
'%s a plusieurs jours off : %s.' % (name, ', '.join(x.summary.value for x in days_off))
'%s a trop de jours off : %s.' % (name, ', '.join(x.summary.value for x in days_off))
)
elif not days_off:
errors.append("%s n'a pas de jour off." % name)
else:
day_off = days_off[0].getrruleset()[0].weekday()
days_off = [x.getrruleset()[0].weekday() for x in days_off]
def get_date_end(event):
if hasattr(event, 'rrule'):
@ -171,7 +180,7 @@ class WorkersMonthlyReport(MonthMixin, YearMixin, TemplateView):
for x in holidays_events
if self.is_event_for_worker(x, worker_possible_names)
]
holidays = self.normalize_holidays(holidays, day_off)
holidays = self.normalize_holidays(holidays, days_off)
ignore = worker.get('ignore', False)
if not ignore:
@ -199,7 +208,7 @@ class WorkersMonthlyReport(MonthMixin, YearMixin, TemplateView):
return worker_match
def normalize_holidays(self, worker_holidays, day_off=None):
def normalize_holidays(self, worker_holidays, days_off=None):
def make_holiday(start, end):
if type(start) != type(end):
start = start.date() if hasattr(start, 'date') else start
@ -225,18 +234,23 @@ class WorkersMonthlyReport(MonthMixin, YearMixin, TemplateView):
def split_holidays_on_day_off(holiday):
start, end = holiday.start, holiday.end
if start == end:
if start.weekday() != day_off:
if start.weekday() not in days_off:
yield holiday
elif len(days_off) == 2:
holiday.half = True
yield holiday
return
if start.weekday() == day_off:
if len(days_off) == 1 and start.weekday() == days_off[0]:
start += datetime.timedelta(days=1)
interval_start = start
for i in range((end - start).days + 1):
interval_end = start + datetime.timedelta(days=i)
if interval_end.weekday() == day_off:
if interval_end.weekday() in days_off:
yield Holiday(interval_start, interval_end - datetime.timedelta(days=1))
if len(days_off) == 2:
yield Holiday(interval_end, interval_end, half=True)
interval_start = interval_end + datetime.timedelta(days=1)
if interval_start <= interval_end:
@ -252,7 +266,7 @@ class WorkersMonthlyReport(MonthMixin, YearMixin, TemplateView):
worker_holidays = [make_holiday(*dates) for dates in worker_holidays]
if day_off is not None:
if days_off is not None:
worker_holidays = [
sub_holiday
for holiday in worker_holidays

View File

@ -159,7 +159,27 @@ def test_conges_day_off_error(mocked_get_events, app, settings):
mocked_get_events.return_value = [ev1, ev2]
resp = app.get('/conges/2023/01/')
assert 'Jean Dupont a plusieurs jours off : Jean off, Jean off 2.' in resp.text
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')
@ -308,6 +328,51 @@ def test_conges_split_on_day_off(mocked_get_events, app, settings):
)
@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'] = [
@ -335,3 +400,36 @@ def test_conges_split_on_day_off_single_day(mocked_get_events, app, settings):
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.'