[FIX] hr_holidays: Automatically set leave dates with 2 week calendar

Commit c7f11aa fixed computation leave length but
forgot to adapt the code when a 2 week calendar is used.
This leads to a traceback when creating a leave for an employee
with a 2 week calendar.

This commit rectifies this.

closes odoo/odoo#37566

Signed-off-by: Romain Libert (rli) <rli@odoo.com>
This commit is contained in:
Lucas Lefèvre
2019-09-30 12:29:58 +00:00
parent ad31097d8e
commit d43a63d5f6
2 changed files with 94 additions and 10 deletions
+10 -10
View File
@@ -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))
@@ -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))