From 81c8a0564d54c981e65a6ed3b2c70dd792d59a46 Mon Sep 17 00:00:00 2001 From: Philippe Wauthy Date: Fri, 12 Nov 2021 15:23:32 +0000 Subject: [PATCH] [FIX] hr_holidays: round the number of days of a time off When the user is set in another timezone than the context timezone, the first or last work interval retrieved to calculate the number of days between two dates is starting later or ending earlier depending on the user timezone. The number of days displayed between two dates is therefore not an integer. e.g. A time off taken between 08/06/2021 and 10/06/2021 (timezone in the context is Europe/Brussels) will give: - Number of days: 3 days if the user is in Europe/Brussels - Number of days: 2.69 if the user is in Asia/Calcutta (first work interval starting later) - Number of days: 2.5 if the user is in US/Pacific (last work interval ending earlier) task-2646655 closes odoo/odoo#77036 Related: odoo/upgrade#3486 Signed-off-by: Kevin Baptiste --- addons/hr_holidays/models/hr_leave.py | 226 +++++++++++------- .../time_off_calendar_model.js | 10 +- addons/hr_holidays/tests/common.py | 1 + .../hr_holidays/tests/test_company_leave.py | 2 +- .../hr_holidays/tests/test_leave_requests.py | 30 +-- addons/hr_holidays/views/hr_leave_views.xml | 5 - 6 files changed, 165 insertions(+), 109 deletions(-) diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index e13de639204..021bfb635db 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -89,25 +89,34 @@ class HolidaysRequest(models.Model): lt = self.env['hr.leave.type'].browse(defaults.get('holiday_status_id')) defaults['state'] = 'confirm' + if 'date_from' and 'date_to' in fields_list: + now = fields.Datetime.now() + if 'date_from' not in defaults: + defaults['date_from'] = now.replace(hour=0, minute=0, second=0) + if 'date_to' not in defaults: + defaults['date_to'] = now.replace(hour=23, minute=59, second=59) + if (not self._context.get('leave_compute_date_from_to') and defaults['date_from'].time() == time(0, 0, 0) and + defaults['date_to'].time() == time(23, 59, 59)): + employee = self.env['hr.employee'].browse(defaults['employee_id']) if defaults.get('employee_id') else self.env.user.employee_id + + date_from = defaults['date_from'].date() + date_to = defaults['date_to'].date() + + attendance_from, attendance_to = self._get_attendances(employee, date_from, date_to) + + defaults['date_from'] = self._get_start_or_end_from_attendance(attendance_from.hour_from, date_from, employee) + defaults['date_to'] = self._get_start_or_end_from_attendance(attendance_to.hour_to, date_to, employee) + + defaults = self._default_get_request_parameters(defaults) + return defaults def _default_get_request_parameters(self, values): new_values = dict(values) - global_from, global_to = False, False - # TDE FIXME: consider a mapping on several days that is not the standard - # calendar widget 7-19 in user's TZ is some custom input if values.get('date_from'): - user_tz = self.env.user.tz or 'UTC' - localized_dt = timezone('UTC').localize(values['date_from']).astimezone(timezone(user_tz)) - global_from = localized_dt.time().hour == 7 and localized_dt.time().minute == 0 - new_values['request_date_from'] = localized_dt.date() + new_values['request_date_from'] = values['date_from'].date() if values.get('date_to'): - user_tz = self.env.user.tz or 'UTC' - localized_dt = timezone('UTC').localize(values['date_to']).astimezone(timezone(user_tz)) - global_to = localized_dt.time().hour == 19 and localized_dt.time().minute == 0 - new_values['request_date_to'] = localized_dt.date() - if global_from and global_to: - new_values['request_unit_custom'] = True + new_values['request_date_to'] = values['date_to'].date() return new_values active = fields.Boolean(default=True) @@ -275,7 +284,6 @@ class HolidaysRequest(models.Model): # request type request_unit_half = fields.Boolean('Half Day', compute='_compute_request_unit_half', store=True, readonly=False) request_unit_hours = fields.Boolean('Custom Hours', compute='_compute_request_unit_hours', store=True, readonly=False) - request_unit_custom = fields.Boolean('Days-long custom hours', compute='_compute_request_unit_custom', store=True, readonly=False) # view is_hatched = fields.Boolean('Hatched', compute='_compute_is_hatched') is_striked = fields.Boolean('Striked', compute='_compute_is_hatched') @@ -391,7 +399,7 @@ class HolidaysRequest(models.Model): leave.holiday_allocation_id = False @api.depends('request_date_from_period', 'request_hour_from', 'request_hour_to', 'request_date_from', 'request_date_to', - 'request_unit_half', 'request_unit_hours', 'request_unit_custom', 'employee_id') + 'request_unit_half', 'request_unit_hours', 'employee_id') def _compute_date_from_to(self): for holiday in self: if holiday.request_date_from and holiday.request_date_to and holiday.request_date_from > holiday.request_date_to: @@ -403,86 +411,41 @@ class HolidaysRequest(models.Model): else: if holiday.request_unit_half or holiday.request_unit_hours: holiday.request_date_to = holiday.request_date_from - resource_calendar_id = holiday.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)', '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'], group['week_type']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != '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 = self.env['resource.calendar.attendance'].get_week_type(holiday.request_date_from) - 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 = [att for att in attendance_actual_week if int(att.dayofweek) >= holiday.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 = self.env['resource.calendar.attendance'].get_week_type(holiday.request_date_to) - 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) <= holiday.request_date_to.weekday()])) - attendance_filtred_reversed += list(reversed(attendance_actual_next_week)) - attendance_filtred_reversed += list(reversed(attendance_actual_week)) - - # find first attendance coming after first_day - attendance_from = attendance_filtred[0] - # find last attendance coming before last_day - attendance_to = attendance_filtred_reversed[0] - else: - # find first attendance coming after first_day - attendance_from = next((att for att in attendances if int(att.dayofweek) >= holiday.request_date_from.weekday()), attendances[0] if attendances else default_value) - # find last attendance coming before last_day - attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= holiday.request_date_to.weekday()), attendances[-1] if attendances else default_value) + attendance_from, attendance_to = holiday._get_attendances(holiday.employee_id, holiday.request_date_from, holiday.request_date_to) compensated_request_date_from = holiday.request_date_from compensated_request_date_to = holiday.request_date_to if holiday.request_unit_half: if holiday.request_date_from_period == 'am': - hour_from = float_to_time(attendance_from.hour_from) - hour_to = float_to_time(attendance_from.hour_to) + hour_from = attendance_from.hour_from + hour_to = attendance_from.hour_to else: - hour_from = float_to_time(attendance_to.hour_from) - hour_to = float_to_time(attendance_to.hour_to) + hour_from = attendance_to.hour_from + hour_to = attendance_to.hour_to elif holiday.request_unit_hours: - hour_from = float_to_time(float(holiday.request_hour_from)) - hour_to = float_to_time(float(holiday.request_hour_to)) - elif holiday.request_unit_custom: - hour_from = holiday.date_from.time() - hour_to = holiday.date_to.time() - compensated_request_date_from = holiday._adjust_date_based_on_tz(holiday.request_date_from, hour_from) - compensated_request_date_to = holiday._adjust_date_based_on_tz(holiday.request_date_to, hour_to) + hour_from = holiday.request_hour_from + hour_to = holiday.request_hour_to else: - hour_from = float_to_time(attendance_from.hour_from) - hour_to = float_to_time(attendance_to.hour_to) + hour_from = attendance_from.hour_from + hour_to = attendance_to.hour_to - holiday.date_from = timezone(holiday.tz).localize(datetime.combine(compensated_request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) - holiday.date_to = timezone(holiday.tz).localize(datetime.combine(compensated_request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) + holiday.date_from = self._get_start_or_end_from_attendance(hour_from, compensated_request_date_from, holiday.employee_id or holiday) + holiday.date_to = self._get_start_or_end_from_attendance(hour_to, compensated_request_date_to, holiday.employee_id or holiday) - @api.depends('holiday_status_id', 'request_unit_hours', 'request_unit_custom') + @api.depends('holiday_status_id', 'request_unit_hours') def _compute_request_unit_half(self): for holiday in self: - if holiday.holiday_status_id or holiday.request_unit_hours or holiday.request_unit_custom: + if holiday.holiday_status_id or holiday.request_unit_hours: holiday.request_unit_half = False - @api.depends('holiday_status_id', 'request_unit_half', 'request_unit_custom') + @api.depends('holiday_status_id', 'request_unit_half') def _compute_request_unit_hours(self): for holiday in self: - if holiday.holiday_status_id or holiday.request_unit_half or holiday.request_unit_custom: + if holiday.holiday_status_id or holiday.request_unit_half: holiday.request_unit_hours = False - @api.depends('holiday_status_id', 'request_unit_half', 'request_unit_hours') - def _compute_request_unit_custom(self): - for holiday in self: - if holiday.holiday_status_id or holiday.request_unit_half or holiday.request_unit_hours: - holiday.request_unit_custom = False - @api.depends('employee_ids') def _compute_from_employee_ids(self): for holiday in self: @@ -577,13 +540,11 @@ class HolidaysRequest(models.Model): for leave in self: leave.tz_mismatch = leave.tz != self.env.user.tz - @api.depends('request_unit_custom', 'employee_id', 'holiday_type', 'department_id.company_id.resource_calendar_id.tz', 'mode_company_id.resource_calendar_id.tz') + @api.depends('employee_id', 'holiday_type', 'department_id.company_id.resource_calendar_id.tz', 'mode_company_id.resource_calendar_id.tz') def _compute_tz(self): for leave in self: tz = False - if leave.request_unit_custom: - tz = 'UTC' # custom -> already in UTC - elif leave.holiday_type == 'employee': + if leave.holiday_type == 'employee': tz = leave.employee_id.tz elif leave.holiday_type == 'department': tz = leave.department_id.company_id.resource_calendar_id.tz @@ -780,16 +741,22 @@ class HolidaysRequest(models.Model): if holiday.state in ['cancel', 'refuse', 'validate1', 'validate']: raise ValidationError(_("This modification is not allowed in the current state.")) + def _get_number_of_days_batch(self, date_from, date_to, employee_ids): + """ Returns a float equals to the timedelta between two dates given as string.""" + employee = self.env['hr.employee'].browse(employee_ids) + # We force the company in the domain as we are more than likely in a compute_sudo + domain = [('company_id', 'in', self.env.company.ids + self.env.context.get('allowed_company_ids', []))] + + result = employee._get_work_days_data_batch(date_from, date_to, domain=domain) + for employee_id in result: + if self.request_unit_half and result[employee_id]['hours'] > 0: + result[employee_id]['days'] = 0.5 + return result + def _get_number_of_days(self, date_from, date_to, employee_id): """ Returns a float equals to the timedelta between two dates given as string.""" if employee_id: - employee = self.env['hr.employee'].browse(employee_id) - # We force the company in the domain as we are more than likely in a compute_sudo - domain = [('company_id', 'in', self.env.company.ids + self.env.context.get('allowed_company_ids', []))] - result = employee._get_work_days_data_batch(date_from, date_to, domain=domain)[employee.id] - if self.request_unit_half and result['hours'] > 0: - result['days'] = 0.5 - return result + return self._get_number_of_days_batch(date_from, date_to, employee_id)[employee_id] today_hours = self.env.company.resource_calendar_id.get_work_hours_count( datetime.combine(date_from.date(), time.min), @@ -966,6 +933,38 @@ class HolidaysRequest(models.Model): @api.model_create_multi def create(self, vals_list): + leave_date_employees = defaultdict(list) + employee_ids = [] + for values in vals_list: + if values.get('employee_id'): + employee_ids.append(values['employee_id']) + if values.get('date_from') and values.get('date_to'): + date_from = fields.Datetime.to_datetime(values['date_from']) + date_to = fields.Datetime.to_datetime(values['date_to']) + if values['employee_id'] not in leave_date_employees[(date_from, date_to)]: + leave_date_employees[(date_from, date_to)].append(values['employee_id']) + employees = self.env['hr.employee'].browse(employee_ids) + if self._context.get('leave_compute_date_from_to') and employees: + employee_leave_date_duration = defaultdict(dict) + for (date_from, date_to), employee_ids in leave_date_employees.items(): + employee_leave_date_duration[(date_from, date_to)] = self._get_number_of_days_batch(date_from, date_to, employee_ids) + for values in vals_list: + employee_id = values.get('employee_id') + if employee_id and values.get('date_from') and values.get('date_to'): + date_from = values.get('date_from') + date_to = values.get('date_to') + employee = employees.filtered(lambda emp: emp.id == employee_id) + attendance_from, attendance_to = self._get_attendances(employee, date_from.date(), date_to.date()) + hour_from = max(values['date_from'].replace(tzinfo=UTC).astimezone(timezone(self.env.user.tz)).time(), float_to_time(attendance_from.hour_from)) + hour_to = min(values['date_to'].replace(tzinfo=UTC).astimezone(timezone(self.env.user.tz)).time(), float_to_time(attendance_to.hour_to)) + hour_from = hour_from.hour + hour_from.minute / 60 + hour_to = hour_to.hour + hour_to.minute / 60 + + values['date_from'] = self._get_start_or_end_from_attendance(hour_from, date_from.date(), employee) + values['date_to'] = self._get_start_or_end_from_attendance(hour_to, date_to.date(), employee) + values['request_date_from'], values['request_date_to'] = values['date_from'].date(), values['date_to'].date() + values['number_of_days'] = employee_leave_date_duration[(date_from, date_to)][values['employee_id']]['days'] + """ Override to avoid automatic logging of creation """ if not self._context.get('leave_fast_create'): leave_types = self.env['hr.leave.type'].browse([values.get('holiday_status_id') for values in vals_list if values.get('holiday_status_id')]) @@ -976,7 +975,7 @@ class HolidaysRequest(models.Model): leave_type_id = values.get('holiday_status_id') # Handle automatic department_id if not values.get('department_id'): - values.update({'department_id': self.env['hr.employee'].browse(employee_id).department_id.id}) + values.update({'department_id': employees.filtered(lambda emp: emp.id == employee_id).department_id.id}) # Handle no_validation if mapped_validation_type[leave_type_id] == 'no_validation': @@ -1358,6 +1357,10 @@ class HolidaysRequest(models.Model): leave_fast_create=True, no_calendar_sync=True, leave_skip_state_check=True, + # date_from and date_to are computed based on the employee tz + # If _compute_date_from_to is used instead, it will trigger _compute_number_of_days + # and create a conflict on the number of days calculation between the different leaves + leave_compute_date_from_to=True, ).create(values) leaves._validate_leave_request() @@ -1559,3 +1562,52 @@ class HolidaysRequest(models.Model): @api.model def get_unusual_days(self, date_from, date_to=None): return self.env.user.employee_id.sudo(False)._get_unusual_days(date_from, date_to) + + def _get_start_or_end_from_attendance(self, hour, date, employee): + hour = float_to_time(float(hour)) + compensated_request_date = self._adjust_date_based_on_tz(date, hour) + holiday_tz = timezone(employee.tz or self.env.user.tz) + return holiday_tz.localize(datetime.combine(compensated_request_date, hour)).astimezone(UTC).replace(tzinfo=None) + + def _get_attendances(self, employee, request_date_from, request_date_to): + resource_calendar_id = employee.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)', + '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'], group['week_type']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != '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 = self.env['resource.calendar.attendance'].get_week_type(request_date_from) + 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 = [att for att in attendance_actual_week if int(att.dayofweek) >= 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 = self.env['resource.calendar.attendance'].get_week_type(request_date_to) + 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) <= request_date_to.weekday()])) + attendance_filtred_reversed += list(reversed(attendance_actual_next_week)) + attendance_filtred_reversed += list(reversed(attendance_actual_week)) + + # find first attendance coming after first_day + attendance_from = attendance_filtred[0] + # find last attendance coming before last_day + attendance_to = attendance_filtred_reversed[0] + else: + # find first attendance coming after first_day + attendance_from = next((att for att in attendances if int(att.dayofweek) >= request_date_from.weekday()), attendances[0] if attendances else default_value) + # find last attendance coming before last_day + attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= request_date_to.weekday()), attendances[-1] if attendances else default_value) + + return (attendance_from, attendance_to) diff --git a/addons/hr_holidays/static/src/js/time_off_calendar/time_off_calendar_model.js b/addons/hr_holidays/static/src/js/time_off_calendar/time_off_calendar_model.js index 2d4d5ab338a..f67566fb9db 100644 --- a/addons/hr_holidays/static/src/js/time_off_calendar/time_off_calendar_model.js +++ b/addons/hr_holidays/static/src/js/time_off_calendar/time_off_calendar_model.js @@ -2,10 +2,18 @@ import CalendarModel from "web.CalendarModel"; - export const TimeOffCalendarModel = CalendarModel.extend({ _getFilterDomain: function() { const company_domain = [['user_id.company_id', 'in', this.data.context.allowed_company_ids]]; return this._super().concat(company_domain); }, + + calendarEventToRecord(event) { + const data = this._super(...arguments); + if (event.allDay) { + data.date_from = data.date_from.utc().startOf('day'); + data.date_to = data.date_to.utc().endOf('day'); + } + return data; + }, }); diff --git a/addons/hr_holidays/tests/common.py b/addons/hr_holidays/tests/common.py index 72497b1b6a4..7fb8745a9d6 100644 --- a/addons/hr_holidays/tests/common.py +++ b/addons/hr_holidays/tests/common.py @@ -18,6 +18,7 @@ class TestHrHolidaysCommon(common.TransactionCase): cls.user_hrmanager = mail_new_test_user(cls.env, login='bastien', groups='base.group_user,hr_holidays.group_hr_holidays_manager') cls.user_hrmanager_id = cls.user_hrmanager.id + cls.user_hrmanager.tz = 'Europe/Brussels' cls.user_employee = mail_new_test_user(cls.env, login='david', groups='base.group_user') cls.user_employee_id = cls.user_employee.id diff --git a/addons/hr_holidays/tests/test_company_leave.py b/addons/hr_holidays/tests/test_company_leave.py index 56009e01fff..15d7e3567e3 100644 --- a/addons/hr_holidays/tests/test_company_leave.py +++ b/addons/hr_holidays/tests/test_company_leave.py @@ -323,7 +323,7 @@ class TestCompanyLeave(TransactionCase): }) company_leave._compute_date_from_to() - with self.assertQueryCount(__system__=250, admin=865): # 249 community + with self.assertQueryCount(__system__=353, admin=865): # Original query count: 1987 # Without tracking/activity context keys: 5154 company_leave.action_validate() diff --git a/addons/hr_holidays/tests/test_leave_requests.py b/addons/hr_holidays/tests/test_leave_requests.py index 0f32a080f1b..b598f87cc91 100644 --- a/addons/hr_holidays/tests/test_leave_requests.py +++ b/addons/hr_holidays/tests/test_leave_requests.py @@ -249,8 +249,8 @@ class TestLeaveRequests(TestHrHolidaysCommon): 'request_hour_from': '8', # 8:00 AM in the company's timezone 'request_hour_to': '17', # 5:00 PM in the company's timezone }) - self.assertEqual(leave.date_from, datetime(2019, 5, 5, 20, 0, 0), "It should have been localized before saving in UTC") - self.assertEqual(leave.date_to, datetime(2019, 5, 6, 5, 0, 0), "It should have been localized before saving in UTC") + self.assertEqual(leave.date_from, datetime(2019, 5, 6, 6, 0, 0), "It should have been localized in the Employee timezone") + self.assertEqual(leave.date_to, datetime(2019, 5, 6, 15, 0, 0), "It should have been localized in the Employee timezone") @mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail') def test_timezone_company_validated(self): @@ -264,13 +264,15 @@ class TestLeaveRequests(TestHrHolidaysCommon): leave_form.holiday_status_id = self.holidays_type_1 leave_form.request_date_from = date(2019, 5, 6) leave_form.request_date_to = date(2019, 5, 6) + leave_form.date_from = datetime(2019, 5, 6, 0, 0, 0) + leave_form.date_to = datetime(2019, 5, 6, 23, 59, 59) leave = leave_form.save() leave.state = 'confirm' leave.action_validate() employee_leave = self.env['hr.leave'].search([('employee_id', '=', employee.id)]) self.assertEqual( - employee_leave.request_date_from, date(2019, 5, 6), - "Timezone should be kept between company and employee leave" + employee_leave.request_date_from, date(2019, 5, 5), + "Timezone should be be adapted on the employee leave" ) @mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail') @@ -290,8 +292,8 @@ class TestLeaveRequests(TestHrHolidaysCommon): 'request_hour_from': '8', # 8:00 AM in the department's timezone 'request_hour_to': '17', # 5:00 PM in the department's timezone }) - self.assertEqual(leave.date_from, datetime(2019, 5, 5, 20, 0, 0), "It should have been localized before saving in UTC") - self.assertEqual(leave.date_to, datetime(2019, 5, 6, 5, 0, 0), "It should have been localized before saving in UTC") + self.assertEqual(leave.date_from, datetime(2019, 5, 6, 6, 0, 0), "It should have been localized in the Employee timezone") + self.assertEqual(leave.date_to, datetime(2019, 5, 6, 15, 0, 0), "It should have been localized in the Employee timezone") def test_number_of_hours_display(self): # Test that the field number_of_hours_dispay doesn't change @@ -416,12 +418,10 @@ class TestLeaveRequests(TestHrHolidaysCommon): tz = timezone(tz) # Mimic what is done by the calendar widget when clicking on a day. It - # will take the local datetime from 7:00 to 19:00 and then convert it - # to UTC before sending it. Values here are for PST (UTC -8) and - # represent a leave on 2019/1/1 from 7:00 to 19:00 local time. + # will take the local datetime from 0:00 to 23:59 values = { - 'date_from': tz.localize(local_date_from).astimezone(UTC).replace(tzinfo=None), - 'date_to': tz.localize(local_date_to).astimezone(UTC).replace(tzinfo=None), # note that this can be the next day in UTC + 'date_from': local_date_from, + 'date_to': local_date_to, # note that this can be the next day in UTC } values.update(self.env['hr.leave'].with_user(self.user_employee_id)._default_get_request_parameters(values)) @@ -449,14 +449,14 @@ class TestLeaveRequests(TestHrHolidaysCommon): # 12 13 14 15 16 17 18 # 19 20 21 22 23 24 25 # 26 27 28 29 30 31 - local_date_from = datetime(2020, 1, 1, 7, 0, 0) - local_date_to = datetime(2020, 1, 1, 19, 0, 0) + local_date_from = datetime(2020, 1, 1, 0, 0, 0) + local_date_to = datetime(2020, 1, 1, 23, 59, 59) for tz in timezones_to_test: self._test_leave_with_tz(tz, local_date_from, local_date_to, 1) # We, Th, Fr, Mo, Tu, We => 6 days - local_date_from = datetime(2020, 1, 1, 7, 0, 0) - local_date_to = datetime(2020, 1, 8, 19, 0, 0) + local_date_from = datetime(2020, 1, 1, 0, 0, 0) + local_date_to = datetime(2020, 1, 8, 23, 59, 59) for tz in timezones_to_test: self._test_leave_with_tz(tz, local_date_from, local_date_to, 6)#TODO JUD check why this fails diff --git a/addons/hr_holidays/views/hr_leave_views.xml b/addons/hr_holidays/views/hr_leave_views.xml index 9d33734baac..5e217c929c7 100644 --- a/addons/hr_holidays/views/hr_leave_views.xml +++ b/addons/hr_holidays/views/hr_leave_views.xml @@ -316,11 +316,6 @@