def setUp(self): super(TestGlobalLeaves, self).setUp() self.Leave = self.env['resource.calendar.leaves'] # This leave has a timezone of False : UTC should be used as default self.global_no_tz = self.Leave.create({ 'name': 'global no timezone', 'calendar_id': self.calendar.id, 'date_from': to_naive_utc(Datetime.from_string('2018-12-25 08:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2018-12-25 23:00:00'), self.env.user), 'tz': False, }) # This leave has no timezone defined : should default to user timezone (here UTC) self.global_user_tz = self.Leave.create({ 'name': 'global user timezone', 'calendar_id': self.calendar.id, 'date_from': to_naive_utc(Datetime.from_string('2018-05-01 08:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2018-05-01 23:00:00'), self.env.user), }) # This leave has been taken in Japan timezone # Leave from 8:00 to 13:00 but we have to adapt cause we define it in UTC self.global_spec_tz = self.Leave.create({ 'name': 'global specific timezone', 'calendar_id': self.calendar.id, 'date_from': Datetime.from_string('2018-04-05 23:00:00'), 'date_to': Datetime.from_string('2018-04-06 04:00:00'), 'tz' : 'Japan', # UTC+9 })
def test_calendar_timezone(self): # user in timezone UTC-9 asks for work hours # Limits: between 2013-02-19 10:00:00 and 2013-02-26 15:30:00 (User TZ) # between 2013-02-19 19:00:00 and 2013-02-27 00:30:00 (UTC) # Leaves: between 2013-02-21 10:00:00 and 2013-02-26 12:00:00 (User TZ) # res: 19/02 (10-16 (beginning)) + 22/02 (0 (leave)) + 26/02 (12-15.30 (leave+ending)) self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) res = self.calendar.get_work_hours_count( to_naive_utc(Datetime.from_string('2013-02-19 10:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id, compute_leaves=True) self.assertEqual(res, 9.5)
def test_calendar_hours_scheduling_timezone(self): # user in timezone UTC-9 asks for work hours self.env.user.tz = 'US/Alaska' res = self.calendar.plan_hours( 42, to_naive_utc(Datetime.from_string('2013-02-12 09:25:00'), self.env.user)) self.assertEqual(res, to_naive_utc(Datetime.from_string('2013-02-26 11:25:00'), self.env.user))
def test_calendar_work_days_intervals_timezone(self): # _get_day_work_intervals converts from the timezone # of the user into UTC self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-26'), time(10), time(18), False, self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 19:00:00'), Datetime.from_string('2013-02-27 01:00:00'))) intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-26'), time(10), time(18), True, self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 21:00:00'), Datetime.from_string('2013-02-27 01:00:00'))) self.env.user.tz = 'Japan' intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-26'), time(10), time(18), False, self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 01:00:00'), Datetime.from_string('2013-02-26 07:00:00'))) intervals = self.calendar._get_day_work_intervals(Date.from_string('2013-02-26'), time(10), time(18), True, self.resource1_id) self.assertEqual(to_tuple(intervals[0]), (Datetime.from_string('2013-02-26 03:00:00'), Datetime.from_string('2013-02-26 07:00:00')))
def test_work_days_count(self): # user in timezone UTC-9 asks for work hours self.env.user.tz = 'US/Alaska' res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 23:00:00'), self.env.user)) self.assertEqual(res, 3.75) # generic leaves, 3 hours res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user)) self.assertEqual(res, 3.5) # last day is truncated of 3 hours on 12) self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-13 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-17 12:00:00'), self.env.user) }) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user)) self.assertEqual(res, 2.5) # one day is on leave and last day is truncated of 3 hours on 12)
def test_calendar_hours_scheduling_timezone_2(self): # Call schedule_hours for a user in Autralia, Sydney (GMT+10) # Two cases: # - start at 2013-02-15 08:00:00 => 2013-02-14 21:00:00 in UTC # - start at 2013-02-15 11:00:00 => 2013-02-15 00:00:00 in UTC self.env.user.tz = 'Australia/Sydney' self.env['resource.calendar.attendance'].create({ 'name': 'Day3 - 1', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'calendar_id': self.calendar.id, }) self.env['resource.calendar.attendance'].create({ 'name': 'Day3 - 2', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'calendar_id': self.calendar.id, }) hours = 1.0/60.0 for test_date in ['2013-02-15 08:00:00', '2013-02-15 11:00:00']: start_dt = Datetime.from_string(test_date) start_dt_utc = to_naive_utc(start_dt, self.env.user) res = self.calendar._schedule_hours(hours, start_dt_utc) self.assertEqual( [(start_dt_utc, start_dt_utc.replace(minute=1))], res, 'resource_calendar: wrong schedule_hours computation')
def test_calendar_days_scheduling_timezone(self): self.env.user.tz = 'US/Alaska' res = self.calendar.plan_days( 5, to_naive_utc(Datetime.from_string('2013-02-12 09:08:07'), self.env.user)) self.assertEqual( to_naive_user_tz(res, self.env.user).date(), Datetime.from_string('2013-02-26 00:00:00').date())
def _set_check_in_out(self): signin = signout = False self.early_hours = 0.0 self.late_hours = 0.0 self.worked_hours = 0.0 duty_from = self.date + ' ' + str( float_to_time(self.duty_time.hour_from)) duty_to = self.date + ' ' + str(float_to_time(self.duty_time.hour_to)) duty_from = fields.Datetime.from_string(duty_from) duty_to = fields.Datetime.from_string(duty_to) self.plan_hours = (duty_to - duty_from).seconds / 3600 check_in = self.day_log.filtered(lambda log: log.action == 'check_in') if check_in: signin = min([ to_naive_user_tz( fields.Datetime.from_string(str(x.action_datetime)), self.env.user) for x in check_in ]) if duty_from > signin: self.early_hours = (duty_from - signin).seconds / 3600 signin = to_naive_utc(signin, self.env.user) self.check_in = str(signin) check_out = self.day_log.filtered( lambda log: log.action == 'check_out') if check_out: signout = max([ to_naive_user_tz( fields.Datetime.from_string(str(x.action_datetime)), self.env.user) for x in check_out ]) if signout > duty_to: self.late_hours = (signout > duty_to).seconds / 3600 signout = to_naive_utc(signout, self.env.user) self.check_out = str(signout) if signin and signout: self.worked_hours = (signout - signin).seconds / 3600
def test_days_count_with_domain(self): self.test.resource_id.write({ 'user_id': self.lost_user.id, }) self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'first', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2018-02-05 08:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2018-02-09 18:00:00'), self.lost_user) }) self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'second', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2018-01-12 08:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2018-01-13 18:00:00'), self.lost_user) }) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', '')] ) self.assertEqual(res, 3.0) res = self.test.get_work_days_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', 'first')] ) self.assertEqual(res, 1.0) res = self.test.get_leaves_day_count( to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user), domain=[('name', '=', 'first')] ) self.assertEqual(res, 2.0)
def _check_worked_hours_within_after(self, date): """ Recomputes overtime hours affected by this public holiday """ if isinstance(date, str): date = fields.Date.from_string(date) HrAttendance = self.env['hr.attendance'] # UTC/TZ problem: datetime_from and datetime_and are expressed taking into account user tx, because # worked_hours_within_after_recalculation uses attendance intervals un UTC. # E.g. with Europe/Madrid TZ, the public holiday 2019-03-19 (winter) actually starts # at 2019-03-18 23:00:00 UTC and finishes at 2019-03-19 22:59:59.99999 UTC # in order to make comparisons with hr.attendance intervals # We use the user TZ for this (manager users should be in the same TZ of the employees) datetime_from = fields.Datetime.to_string( to_naive_utc(datetime.combine(date, time(0, 0, 0)), self.env.user)) datetime_to = fields.Datetime.to_string( to_naive_utc(datetime.combine(date, time(23, 59, 59, 99999)), self.env.user)) for calendar in self.env['resource.calendar'].search([]): HrAttendance.worked_hours_within_after_recalculation( datetime_from=datetime_from, datetime_to=datetime_to, calendar_id=calendar.id)
def test_work_days_count_timezones_ultra(self): # user in timezone UTC+4 is attached to the resource and create leaves self.test.resource_id.write({ 'user_id': self.lost_user.id, }) reunion_leave = self.env['resource.calendar.leaves'].sudo(self.lost_user).create({ 'name': 'Timezoned Leaves', 'calendar_id': self.test.resource_calendar_id.id, 'resource_id': self.test.resource_id.id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-12 10:00:00'), self.lost_user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-12 12:00:00'), self.lost_user) }) self.assertEqual(reunion_leave.tz, 'Indian/Reunion') # user in timezone UTC-9 read and manipulate leaves self.env.user.tz = 'US/Alaska' res = self.test.get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0) # user in timezone UTC+4 read and manipulate leaves res = self.test.sudo(self.lost_user).get_work_days_data( to_naive_utc(Datetime.from_string('2013-02-12 06:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-12 20:00:00'), self.env.user)) self.assertEqual(res['days'], 0.75) self.assertEqual(res['hours'], 6.0)
def _get_day_work_intervals(self, day_date, start_time=None, end_time=None, compute_leaves=False, resource_id=None): """Return fake work intervals for full day when asking for rest days included through ``_get_weekdays``. """ if self.env.context.get('include_rest_days'): real_weekdays = self.with_context( include_rest_days=False, )._get_weekdays() if day_date.weekday() not in real_weekdays: user = self.env.user return [ self._interval_new( to_naive_utc( datetime.combine( day_date, time(hour=0, minute=0, second=0), ), user), to_naive_utc( datetime.combine( day_date, time(hour=23, minute=59, second=59), ), user), {}, ) ] return super()._get_day_work_intervals( day_date, start_time=start_time, end_time=end_time, compute_leaves=compute_leaves, resource_id=resource_id, )
def time_to_string_utc_datetime(time): return str(to_naive_utc(datetime.combine(day, time), self.workcenter_1.resource_id))
def time_to_string_utc_datetime(time): return str( to_naive_utc(datetime.combine(day, time), self.workcenter_1.resource_id))
def test_calendar_days_scheduling_timezone(self): self.env.user.tz = 'US/Alaska' res = self.calendar.plan_days(5, to_naive_utc(Datetime.from_string('2013-02-12 09:08:07'), self.env.user)) self.assertEqual(to_naive_user_tz(res, self.env.user).date(), Datetime.from_string('2013-02-26 00:00:00').date())
def test_calendar_leave_intervals_timezone(self): # _iter_leave_intervals takes UTC and outputs UTC # Leave is taken by user in US/Alaska timezone # It should be visible at the right time for every timezone self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) # Checking for 'Europe/Brussels' self.env.user.tz = 'Europe/Brussels' leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-26 07:00:00'), Datetime.from_string('2013-02-26 10:00:00'))) leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-22 07:00:00'), Datetime.from_string('2013-02-22 12:00:00'))) # Checking for 'Japan' self.env.user.tz = 'Japan' leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-25 23:00:00'), Datetime.from_string('2013-02-26 02:00:00'))) leaves = list(self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-21 23:00:00'), Datetime.from_string('2013-02-22 04:00:00')))
def test_calendar_leave_intervals_timezone(self): # _iter_leave_intervals takes UTC and outputs UTC # Leave is taken by user in US/Alaska timezone # It should be visible at the right time for every timezone self.env.user.tz = 'US/Alaska' (self.leave1 | self.leave2 | self.leave3).unlink() leave = self.env['resource.calendar.leaves'].create({ 'name': 'Timezoned Leaves', 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': to_naive_utc(Datetime.from_string('2013-02-21 10:00:00'), self.env.user), 'date_to': to_naive_utc(Datetime.from_string('2013-02-26 12:00:00'), self.env.user) }) def to_tuple(interval): return (interval.start_datetime, interval.end_datetime) # Checking for 'Europe/Brussels' self.env.user.tz = 'Europe/Brussels' leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-26 07:00:00'), Datetime.from_string('2013-02-26 10:00:00'))) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-22 07:00:00'), Datetime.from_string('2013-02-22 12:00:00'))) # Checking for 'Japan' self.env.user.tz = 'Japan' leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 14:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 15:30:00'), self.env.user), self.resource1_id)) self.assertEqual(len(leaves), 0) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-26 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-26 11:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 1) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-25 23:00:00'), Datetime.from_string('2013-02-26 02:00:00'))) leaves = list( self.calendar._iter_leave_intervals( to_naive_utc(Datetime.from_string('2013-02-22 08:00:00'), self.env.user), to_naive_utc(Datetime.from_string('2013-02-22 20:00:00'), self.env.user), self.resource1_id))[0] self.assertEqual(len(leaves), 2) self.assertEqual(to_tuple(leaves[0]), (Datetime.from_string('2013-02-21 23:00:00'), Datetime.from_string('2013-02-22 04:00:00')))