diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 6bda0bdb3ee..da3a5eeea59 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -22,7 +22,7 @@ _logger = logging.getLogger(__name__) # Used to agglomerate the attendances in order to find the hour_from and hour_to # See _onchange_request_parameters -DummyAttendance = namedtuple('DummyAttendance', 'hour_from, hour_to, dayofweek, day_period') +DummyAttendance = namedtuple('DummyAttendance', 'hour_from, hour_to, dayofweek, day_period, week_type') class HolidaysRequest(models.Model): """ Leave Requests Access specifications @@ -284,29 +284,29 @@ class HolidaysRequest(models.Model): resource_calendar_id = self.employee_id.resource_calendar_id or self.env.company.resource_calendar_id domain = [('calendar_id', '=', resource_calendar_id.id), ('display_type', '=', False)] - attendances = self.env['resource.calendar.attendance'].read_group(domain, ['ids:array_agg(id)', 'hour_from:min(hour_from)', 'hour_to:max(hour_to)', 'dayofweek', 'day_period'], ['dayofweek', 'day_period'], lazy=False) + attendances = self.env['resource.calendar.attendance'].read_group(domain, ['ids:array_agg(id)', 'hour_from:min(hour_from)', 'hour_to:max(hour_to)', 'week_type', 'dayofweek', 'day_period'], ['week_type', 'dayofweek', 'day_period'], lazy=False) # Must be sorted by dayofweek ASC and day_period DESC - attendances = sorted([DummyAttendance(group['hour_from'], group['hour_to'], group['dayofweek'], group['day_period']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != 'morning')) + attendances = sorted([DummyAttendance(group['hour_from'], group['hour_to'], group['dayofweek'], group['day_period'], group['week_type']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != 'morning')) - default_value = DummyAttendance(0, 0, 0, 'morning') + default_value = DummyAttendance(0, 0, 0, 'morning', False) if resource_calendar_id.two_weeks_calendar: # find week type of start_date start_week_type = int(math.floor((self.request_date_from.toordinal() - 1) / 7) % 2) - attendance_actual_week = attendances.filtered(lambda att: att.week_type is False or int(att.week_type) == start_week_type) - attendance_actual_next_week = attendances.filtered(lambda att: att.week_type is False or int(att.week_type) != start_week_type) + attendance_actual_week = [att for att in attendances if att.week_type is False or int(att.week_type) == start_week_type] + attendance_actual_next_week = [att for att in attendances if att.week_type is False or int(att.week_type) != start_week_type] # First, add days of actual week coming after date_from - attendance_filtred = list(attendance_actual_week.filtered(lambda att: int(att.dayofweek) >= self.request_date_from.weekday())) + attendance_filtred = [att for att in attendance_actual_week if int(att.dayofweek) >= self.request_date_from.weekday()] # Second, add days of the other type of week attendance_filtred += list(attendance_actual_next_week) # Third, add days of actual week (to consider days that we have remove first because they coming before date_from) attendance_filtred += list(attendance_actual_week) end_week_type = int(math.floor((self.request_date_to.toordinal() - 1) / 7) % 2) - attendance_actual_week = attendances.filtered(lambda att: att.week_type is False or int(att.week_type) == end_week_type) - attendance_actual_next_week = attendances.filtered(lambda att: att.week_type is False or int(att.week_type) != end_week_type) - attendance_filtred_reversed = list(reversed(attendance_actual_week.filtered(lambda att: int(att.dayofweek) <= self.request_date_to.weekday()))) + attendance_actual_week = [att for att in attendances if att.week_type is False or int(att.week_type) == end_week_type] + attendance_actual_next_week = [att for att in attendances if att.week_type is False or int(att.week_type) != end_week_type] + attendance_filtred_reversed = list(reversed([att for att in attendance_actual_week if int(att.dayofweek) <= self.request_date_to.weekday()])) attendance_filtred_reversed += list(reversed(attendance_actual_next_week)) attendance_filtred_reversed += list(reversed(attendance_actual_week)) diff --git a/addons/hr_holidays/tests/test_automatic_leave_dates.py b/addons/hr_holidays/tests/test_automatic_leave_dates.py index 5b39259d053..a709be09f9a 100644 --- a/addons/hr_holidays/tests/test_automatic_leave_dates.py +++ b/addons/hr_holidays/tests/test_automatic_leave_dates.py @@ -210,3 +210,87 @@ class TestAutomaticLeaveDates(TestHrHolidaysBase): self.assertEqual(leave_form.number_of_hours_display, 0) self.assertEqual(leave_form.date_from, datetime(2019, 9, 3, 6, 0, 0)) self.assertEqual(leave_form.date_to, datetime(2019, 9, 3, 10, 0, 0)) + + def test_2weeks_calendar(self): + calendar = self.env['resource.calendar'].create({ + 'name': 'auto next day', + 'two_weeks_calendar': True, + 'attendance_ids': [(5, 0, 0), + (0, 0, { + 'name': 'monday morning odd week', + 'hour_from': 8, + 'hour_to': 12, + 'day_period': 'morning', + 'dayofweek': '0', + 'week_type': '0', + }), + (0, 0, { + 'name': 'monday morning even week', + 'hour_from': 10, + 'hour_to': 12, + 'day_period': 'morning', + 'dayofweek': '0', + 'week_type': '1', + })] + }) + employee = self.employee_emp + employee.resource_calendar_id = calendar + + with Form(self.env['hr.leave']) as leave_form: + leave_form.employee_id = employee + leave_form.holiday_status_id = self.leave_type + # even week, works 2 hours + leave_form.request_date_from = date(2019, 9, 2) + leave_form.request_date_to = date(2019, 9, 2) + leave_form.request_unit_half = True + leave_form.request_date_from_period = 'am' + + self.assertEqual(leave_form.number_of_days_display, 1) + self.assertEqual(leave_form.number_of_hours_display, 2) + self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 8, 0, 0)) + self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0)) + + with Form(self.env['hr.leave']) as leave_form: + leave_form.employee_id = employee + leave_form.holiday_status_id = self.leave_type + # odd week, works 4 hours + leave_form.request_date_from = date(2019, 9, 9) + leave_form.request_date_to = date(2019, 9, 9) + leave_form.request_unit_half = True + leave_form.request_date_from_period = 'am' + + self.assertEqual(leave_form.number_of_days_display, 1) + self.assertEqual(leave_form.number_of_hours_display, 4) + self.assertEqual(leave_form.date_from, datetime(2019, 9, 9, 6, 0, 0)) + self.assertEqual(leave_form.date_to, datetime(2019, 9, 9, 10, 0, 0)) + + def test_2weeks_calendar_next_week(self): + calendar = self.env['resource.calendar'].create({ + 'name': 'auto next day', + 'two_weeks_calendar': True, + 'attendance_ids': [(5, 0, 0), + (0, 0, { + 'name': 'monday morning odd week', + 'hour_from': 8, + 'hour_to': 12, + 'day_period': 'morning', + 'dayofweek': '0', + 'week_type': '0', + })] + }) + employee = self.employee_emp + employee.resource_calendar_id = calendar + + with Form(self.env['hr.leave']) as leave_form: + leave_form.employee_id = employee + leave_form.holiday_status_id = self.leave_type + # even week, does not work + leave_form.request_date_from = date(2019, 9, 2) + leave_form.request_date_to = date(2019, 9, 2) + leave_form.request_unit_half = True + leave_form.request_date_from_period = 'am' + + self.assertEqual(leave_form.number_of_days_display, 0) + self.assertEqual(leave_form.number_of_hours_display, 0) + self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0)) + self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))