def _get_day_attendances(self, day_date, start_time, end_time): """ Given a day date, return matching attendances. Those can be limited by starting and ending time objects. """ self.ensure_one() weekday = day_date.weekday() attendances = self.env['resource.calendar.attendance'] for attendance in self.attendance_ids.filtered( lambda att: int(att.dayofweek) == weekday and not ( att.date_from and fields.Date.from_string(att.date_from) > day_date) and not (att.date_to and fields.Date.from_string( att.date_to) < day_date)): if start_time and float_to_time(attendance.hour_to) < start_time: continue if end_time and float_to_time(attendance.hour_from) > end_time: continue attendances |= attendance for attendance_expt in self.attendance_ids_expt.filtered( lambda att: int(att.dayofweek) == weekday and not ( att.date_from and fields.Date.from_string(att.date_from) > day_date) and not (att.date_to and fields.Date.from_string( att.date_to) < day_date)): if start_time and float_to_time( attendance_expt.hour_to) < start_time: continues if end_time and float_to_time( attendance_expt.hour_from) > end_time: continue attendances |= attendance_expt return attendances
def _onchange_date(self): if self.fal_date_from and self.fal_date_to: domain = [('calendar_id', '=', self.fal_fix_date_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search( domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next(( att for att in attendances if int( att.dayofweek ) >= self.fal_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next(( att for att in reversed( attendances ) if int( att.dayofweek ) <= self.fal_date_to.weekday()), attendances[-1]) hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz else 'UTC' self.fal_opening_date = timezone(tz).localize( datetime.combine(self.fal_date_from, hour_from) ).astimezone(UTC).replace(tzinfo=None) self.fal_ending_date = timezone(tz).localize( datetime.combine(self.fal_date_to, hour_to) ).astimezone(UTC).replace(tzinfo=None)
def _compute_late_today(self): get_config_timekeeping = self.env['manager.attendance'].search([], limit=1) for attendance in self: if attendance.check_in and len(get_config_timekeeping) > 0: check_in = attendance.check_in.astimezone( timezone(get_config_timekeeping.time_zone)) if datetime.combine( check_in.date(), check_in.time()) < datetime.combine( check_in.date(), float_to_time(get_config_timekeeping.hour_am_to)): late_today = (datetime.combine( check_in.date(), check_in.time()) - datetime.combine( check_in.date(), float_to_time(get_config_timekeeping.hour_am_from)) ).total_seconds() / 60.0 else: late_today = (datetime.combine( check_in.date(), check_in.time()) - datetime.combine( check_in.date(), float_to_time(get_config_timekeeping.hour_pm_from)) ).total_seconds() / 60.0 attendance.late_today = round(late_today, 2) else: attendance.late_today = False
def _compute_is_in_opening_hours(self): """ Opening hours: hour_from and hour_to are given within event TZ or UTC. Now() must therefore be computed based on that TZ. """ for sponsor in self: if not sponsor.event_id.is_ongoing: sponsor.is_in_opening_hours = False elif not sponsor.hour_from or not sponsor.hour_to: sponsor.is_in_opening_hours = True else: event_tz = timezone(sponsor.event_id.date_tz) # localize now, begin and end datetimes in event tz dt_begin = sponsor.event_id.date_begin.astimezone(event_tz) dt_end = sponsor.event_id.date_end.astimezone(event_tz) now_utc = utc.localize( fields.Datetime.now().replace(microsecond=0)) now_tz = now_utc.astimezone(event_tz) # compute opening hours opening_from_tz = event_tz.localize( datetime.combine(now_tz.date(), float_to_time(sponsor.hour_from))) opening_to_tz = event_tz.localize( datetime.combine(now_tz.date(), float_to_time(sponsor.hour_to))) opening_from = max([dt_begin, opening_from_tz]) opening_to = min([dt_end, opening_to_tz]) sponsor.is_in_opening_hours = opening_from <= now_tz < opening_to
def _validate_leave_request(self): """ Timesheet will be generated on leave validation only if a timesheet_project_id and a timesheet_task_id are set on the corresponding leave type. The generated timesheet will be attached to this project/task. """ # create the timesheet on the vacation project for holiday in self.filtered( lambda request: request.holiday_type == 'employee'): work_hours_data = holiday.employee_id.list_work_time_per_day( fields.Datetime.from_string(holiday.date_from), fields.Datetime.from_string(holiday.date_to), ) # raise UserError(_(work_hours_data)) for index, (day_date, work_hours_count) in enumerate(work_hours_data): if holiday.request_unit_hours: hour_from = float_to_time( abs(holiday.request_hour_from) - 0.5 if holiday.request_hour_from < 0 else holiday. request_hour_from) hour_to = float_to_time( abs(holiday.request_hour_to) - 0.5 if holiday.request_hour_to < 0 else holiday. request_hour_to) tz = self.env.user.tz if self.env.user.tz and not holiday.request_unit_custom else 'US/Central' # custom -> already in UTC check_in = timezone(tz).localize( datetime.combine( holiday.request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) check_out = timezone(tz).localize( datetime.combine( holiday.request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) else: check_in = datetime(day_date.year, day_date.month, day_date.day, 8, 0, 0) check_out_time = 8 + int(work_hours_count) check_out = datetime(day_date.year, day_date.month, day_date.day, check_out_time, 0, 0) # raise UserError(check_out) self.env['hr.attendance'].create({ 'check_in': check_in, 'check_out': check_out, 'worked_hours': work_hours_count, 'employee_id': holiday.employee_id.id, 'hour_type': holiday.holiday_status_id.id, 'status': 'open', }) return super(HrLeaves, self)._validate_leave_request()
def _onchange_request_parameters(self, vals): if not vals.get('request_date_from', False): vals.update({'date_from': False}) return vals if vals.get('request_unit_half', False): vals.update({'request_date_to': vals.get('request_date_from')}) if not vals.get('request_date_to', False): vals.update({'date_to': False}) return vals employee_id = False if vals.get('employee_id', False): employee_id = request.env['hr.employee'].sudo().browse( [vals.get('employee_id')]) resource_calendar_id = employee_id.resource_calendar_id.id if employee_id else request.env.user.company_id.resource_calendar_id.id domain = [('calendar_id', '=', resource_calendar_id)] attendances = request.env['resource.calendar.attendance'].sudo( ).search(domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next( (att for att in attendances if int(att.dayofweek) >= vals.get('request_date_from').weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next( (att for att in reversed(attendances) if int(att.dayofweek) <= vals.get('request_date_to').weekday()), attendances[-1]) if vals.get('request_unit_half', False): hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = request.env.user.tz if request.env.user.tz else 'UTC' # custom -> already in UTC date_from = timezone(tz).localize( datetime.combine(vals.get('request_date_from'), hour_from)).astimezone(UTC).replace(tzinfo=None) date_to = timezone(tz).localize( datetime.combine(vals.get('request_date_to'), hour_to)).astimezone(UTC).replace(tzinfo=None) vals.update({'date_from': date_from}) vals.update({'date_to': date_to}) return vals
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.request_unit_half or self.request_unit_hours: self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search( domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next( (att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next( (att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1]) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: # This hack is related to the definition of the field, basically we convert # the negative integer into .5 floats hour_from = float_to_time( abs(self.request_hour_from) - 0.5 if self.request_hour_from < 0 else self.request_hour_from) hour_to = float_to_time( abs(self.request_hour_to) - 0.5 if self.request_hour_to < 0 else self.request_hour_to) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC self.date_from = timezone(tz).localize( datetime.combine(self.request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) self.date_to = timezone(tz).localize( datetime.combine(self.request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) self._onchange_leave_dates()
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.request_unit_half or self.request_unit_hours: self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search( domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next( (att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next( (att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1]) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: hour_from = float_to_time(self.request_hour_from) hour_to = float_to_time(self.request_hour_to) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC #################################################################### edit datefrom = timezone(tz).localize( datetime.combine(fields.Date.from_string(self.request_date_from), hour_from)).astimezone(UTC).replace(tzinfo=None) date_to = timezone(tz).localize( datetime.combine(fields.Date.from_string(self.request_date_to), hour_to)).astimezone(UTC).replace(tzinfo=None) self.date_from = datefrom.date() # print ("datefrom") self.date_to = date_to.date()
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.holiday_status_id and self.holiday_status_id.name in HOLIDAY_SAMEDAY_LIST: self.request_date_to = self.request_date_from if self.holiday_status_id and self.holiday_status_id.name in HOLIDAY_HALFDAY_LIST: self.request_unit_half=True else: self.request_unit_half=False if self.request_unit_half or self.request_unit_hours: self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] 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) # 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')) default_value = DummyAttendance(0, 0, 0, 'morning') # find first attendance coming after first_day attendance_from = next((att for att in attendances if int(att.dayofweek) >= self.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) <= self.request_date_to.weekday()), attendances[-1] if attendances else default_value) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: # This hack is related to the definition of the field, basically we convert # the negative integer into .5 floats hour_from = float_to_time(abs(self.request_hour_from) - 0.5 if self.request_hour_from < 0 else self.request_hour_from) hour_to = float_to_time(abs(self.request_hour_to) - 0.5 if self.request_hour_to < 0 else self.request_hour_to) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC self.date_from = timezone(tz).localize(datetime.combine(self.request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) self.date_to = timezone(tz).localize(datetime.combine(self.request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) self._onchange_leave_dates()
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 _compute_today_schedule(self): public_holidays = self.env["hr.holidays.public"] today = fields.Date.today() day_date = fields.Date.from_string(today) now = fields.Datetime.now() for record in self: domain = [ ("date_from", "<=", now), ("date_to", ">=", now), ("employee_id", "=", record.id), ("type", "=", "remove"), ("state", "=", "validate"), ] personal_holidays = self.env["hr.holidays"].search(domain, limit=1) if personal_holidays: date_from = fields.Date.context_today( self, fields.Datetime.from_string(personal_holidays.date_from), ) record.today_schedule = _( "Absent because of %s since %s" % (personal_holidays.holiday_status_id.name, date_from)) continue if public_holidays.is_public_holiday(today, record.id): record.today_schedule = _("Absent today because " "of public holidays") continue attendances = record.resource_calendar_id._get_day_attendances( day_date, False, False) if not attendances: record.today_schedule = _("This employee doesn't work today") elif len(attendances) == 1: record.today_schedule = _("Working from %s to %s") % ( float_to_time(attendances.hour_from).strftime("%H:%M"), float_to_time(attendances.hour_to).strftime("%H:%M"), ) else: message = record.today_schedule = _("Working from %s to %s") % ( float_to_time(attendances[0].hour_from).strftime("%H:%M"), float_to_time(attendances[0].hour_to).strftime("%H:%M"), ) attendances = attendances[1:] for att in attendances[:-1]: message = message + _(", from %s to %s") % ( float_to_time(att.hour_from).strftime("%H:%M"), float_to_time(att.hour_to).strftime("%H:%M"), ) record.today_schedule = message + _(" and from %s to %s") % ( float_to_time(attendances[-1].hour_from).strftime("%H:%M"), float_to_time(attendances[-1].hour_to).strftime("%H:%M"), )
def attendance_action_change(self): timez = timezone(self.env.user.tz) attendance = self._attendance_action_change() if attendance: action_time = (fields.Datetime.from_string( attendance.check_out or attendance.check_in).replace(tzinfo=utc).astimezone(timez)) work_intervals = self.resource_calendar_id._work_intervals( datetime.combine(action_time.date(), time(0, 0, 0, 0, tzinfo=timez)), datetime.combine(action_time.date(), time(23, 59, 59, 99999, tzinfo=timez)), resource=self.resource_id, ) calendar_attendances = self.env["resource.calendar.attendance"] for _, _, meta in work_intervals: if meta._name == "resource.calendar.attendance": calendar_attendances |= meta intervals = [] for att in calendar_attendances: start = timez.localize( datetime.combine(action_time.date(), float_to_time(att.hour_from))) stop = timez.localize( datetime.combine(action_time.date(), float_to_time(att.hour_to))) intervals.append((start, stop, att)) in_interval = any([ start + timedelta(minutes=-meta.margin_from or 0) <= action_time <= stop + timedelta(minutes=meta.margin_to or 0) for start, stop, meta in intervals ]) public_holiday = self.env["hr.holidays.public"].is_public_holiday( action_time.date(), self.id) if not in_interval or public_holiday: date = fields.Date.to_string(action_time.date()) self._create_warning(date=date, w_type="out_of_interval") return attendance
def _get_calendar_leaves(self): calendar_leaves = self.env['resource.calendar.leaves'] self.calendar_leaves_ids = False 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)) c_date = self.date + ' 00:00:00' duty_from = fields.Datetime.from_string(duty_from) duty_to = fields.Datetime.from_string(duty_to) duty_from = to_naive_user_tz(duty_from, self.env.user) duty_to = to_naive_user_tz(duty_to, self.env.user) date_leaves = calendar_leaves.search([ ('resource_id', '=', self.employee_id.resource_id.id), ('date_from', '<=', str(duty_from)), ('date_to', '>', str(duty_from)) ]) date_leaves |= calendar_leaves.search([ ('resource_id', '=', self.employee_id.resource_id.id), ('date_from', '<', str(duty_to)), ('date_to', '>=', str(duty_to)) ]) date_leaves |= calendar_leaves.search([ ('resource_id', '=', self.employee_id.resource_id.id), ('date_from', '>=', str(duty_from)), ('date_to', '<=', str(duty_to)) ]) self.calendar_leaves_ids = date_leaves.ids absence_type = None excuse_seconds = 0 return absence_type, excuse_seconds
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): res = [] for data in super(PlanningTemplate, self).read_group(domain, fields, groupby, offset, limit, orderby, lazy): if 'start_time' in data: data['start_time'] = float_to_time( data['start_time']).strftime('%H:%M') res.append(data) return res
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.request_unit_half or self.request_unit_hours: self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search(domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next((att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1]) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: hour_from = float_to_time(float(self.request_hour_from)) hour_to = float_to_time(float(self.request_hour_to)) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC self.date_from = timezone(tz).localize(datetime.combine(self.request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) self.date_to = timezone(tz).localize(datetime.combine(self.request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) self._onchange_leave_dates()
def _onchange_request_parameters(self): date_from = False date_to = False if not self.employee_id: return if self.request_date_from: if self.date_from: date_from = fields.Datetime.to_string( datetime.combine( fields.Date.from_string(self.request_date_from), fields.Datetime.from_string(self.date_from).time())) else: date_from = self.request_date_from if self.request_date_to: if self.date_to: date_to = fields.Datetime.to_string( datetime.combine( fields.Date.from_string(self.request_date_to), fields.Datetime.from_string(self.date_to).time())) else: date_to = self.request_date_to if not self.request_date_from or not self.request_date_to: if date_from: self.date_from = date_from if date_to: self.date_to = date_to self.number_of_days_temp = 0 return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search( domain, order='dayofweek, day_period DESC') first_day = fields.Date.from_string(date_from) last_day = fields.Date.from_string(date_to) if self.request_unit_all in ['day', 'half']: last_day = first_day # find first attendance coming after first_day attendance_from = next((att for att in attendances if int(att.dayofweek) >= first_day.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= last_day.weekday()), attendances[-1]) if self.request_unit_all == 'day' or (self.request_unit_all == 'period' and self.leave_type_request_unit == 'day'): hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_all == 'half': hour_from = float_to_time( attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_to.hour_from) hour_to = float_to_time( attendance_from.hour_to if self.request_date_from_period == 'am' else attendance_to.hour_to) elif self.request_unit_all == 'period' and self.leave_type_request_unit == 'half': hour_from = float_to_time( attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_from.hour_to) hour_to = float_to_time( attendance_to.hour_from if self.request_date_to_period == 'am' else attendance_to.hour_to) if self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period': date_from = fields.Datetime.from_string(date_from) date_to = fields.Datetime.from_string(date_to) else: tz = self.env.user.tz or 'UTC' date_from = timezone(tz).localize( datetime.combine(first_day, hour_from)).astimezone(UTC) date_to = timezone(tz).localize(datetime.combine( last_day, hour_to)).astimezone(UTC) self.date_from = date_from self.date_to = date_to if not (self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period'): date_from = date_from date_to = date_to self.number_of_days_temp = self._get_number_of_days( date_from, date_to, self.employee_id.id)
def compute_and_validate_dates(self, **kwargs): date_to = date_from = fields.Datetime DummyAttendance = namedtuple( 'DummyAttendance', 'hour_from, hour_to, dayofweek, day_period, week_type') request_date_from_period = kwargs.get('request_date_from_period') request_hour_from = kwargs.get('request_hour_from') request_hour_to = kwargs.get('request_hour_to') request_date_from = datetime.strptime(kwargs.get('request_date_from'), "%Y-%m-%d").date() if kwargs.get('request_date_to'): request_date_to = datetime.strptime(kwargs.get('request_date_to'), "%Y-%m-%d").date() else: request_date_to = False request_unit_half = False if kwargs.get( 'request_unit_half') == 'false' else True request_unit_hours = False if kwargs.get( 'request_unit_hours') == 'false' else True request_unit_custom = False if kwargs.get( 'request_unit_custom') == 'false' else True number_of_hours_text = kwargs.get('number_of_hours_text') employee_id = request.env['hr.employee'].sudo().search([ ('user_id.id', '=', request.uid) ]) or request.env['hr.employee'].sudo().search( [('address_home_id', '=', request.env['res.users'].sudo().search( [('id', '=', request.uid)]).partner_id.id)]) number_of_days = 0.0 number_of_hours = 0 if request_date_from and request_date_to and \ request_date_from > request_date_to: request_date_to = request_date_from if not request_date_from: date_from = False elif not request_unit_half and not request_unit_hours and not \ request_date_to: date_to = False else: if request_unit_half or request_unit_hours: request_date_to = request_date_from company = request.env.company resource_calendar_id = employee_id.resource_calendar_id or \ company.resource_calendar_id domain = [('calendar_id', '=', resource_calendar_id.id), ('display_type', '=', False)] attendances = request.env[ 'resource.calendar.attendance'].with_user( SUPERUSER_ID).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) 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: start_week_type = int( math.floor((request_date_from.toordinal() - 1) / 7) % 2) 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 ] attendance_filtered = [ att for att in attendance_actual_week if int(att.dayofweek) >= request_date_from.weekday() ] attendance_filtered += list(attendance_actual_next_week) attendance_filtered += list(attendance_actual_week) end_week_type = int( math.floor((request_date_to.toordinal() - 1) / 7) % 2) 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_filtered_reversed = list( reversed([ att for att in attendance_actual_week if int(att.dayofweek) <= request_date_to.weekday() ])) attendance_filtered_reversed += list( reversed(attendance_actual_next_week)) attendance_filtered_reversed += list( reversed(attendance_actual_week)) attendance_from = attendance_filtered[0] attendance_to = attendance_filtered_reversed[0] else: attendance_from = next( (att for att in attendances if int(att.dayofweek) >= request_date_from.weekday()), attendances[0] if attendances else default_value) attendance_to = next( (att for att in reversed(attendances) if int(att.dayofweek) <= request_date_to.weekday()), attendances[-1] if attendances else default_value) compensated_request_date_from = request_date_from compensated_request_date_to = request_date_to if request_unit_half: if request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif request_unit_hours: hour_from = float_to_time(float(request_hour_from)) hour_to = float_to_time(float(request_hour_to)) elif request_unit_custom: hour_from = datetime.combine(request_date_from, datetime.min.time()).time() hour_to = datetime.combine(request_date_to, datetime.max.time()).time() user_tz = timezone( request.env.user.tz if request.env.user.tz else 'UTC') request_date_from_utc = UTC.localize( datetime.combine(request_date_from, time( 0, 0, 0))).astimezone(user_tz).replace(tzinfo=None) if request_date_from_utc.date() < request_date_from: compensated_request_date_from = request_date_from + \ timedelta(days=1) elif request_date_from_utc.date() > request_date_from: compensated_request_date_from = request_date_from - \ timedelta(days=1) else: compensated_request_date_from = request_date_from request_date_to_utc = UTC.localize( datetime.combine(request_date_to, time( 0, 0, 0))).astimezone(user_tz).replace(tzinfo=None) if request_date_to_utc.date() < request_date_to: compensated_request_date_to = request_date_to + \ timedelta(days=1) elif request_date_to_utc.date() > request_date_to: compensated_request_date_to = request_date_to - \ timedelta(days=1) else: compensated_request_date_to = request_date_to else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) date_from = timezone(request.env.user.tz).localize( datetime.combine( compensated_request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) date_to = timezone(request.env.user.tz).localize( datetime.combine(compensated_request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) if request_unit_half: result = employee_id._get_work_days_data_batch( date_from, date_to)[employee_id.id] result['days'] = 0.5 number_of_days = result['days'] number_of_hours = result['hours'] else: company = request.env.company today_hours = company.resource_calendar_id.get_work_hours_count( datetime.combine(date_from.date(), time.min), datetime.combine(date_from.date(), time.max), False) if request_unit_custom: hours = company.resource_calendar_id.get_work_hours_count( date_from, date_to, False) days = hours / (today_hours or HOURS_PER_DAY) number_of_days = days number_of_hours = hours else: number_of_hours = float(kwargs.get('number_of_hours')) number_of_days = number_of_hours / 8 number_of_hours_text = '%s%g %s%s' % ( '' if request_unit_half or request_unit_hours else '(', float_round(number_of_hours, precision_digits=2), _('Hours'), '' if request_unit_half or request_unit_hours else ')') hr_leave = request.env['hr.leave'].sudo() check_error = {} domain = [ ('date_from', '<', date_to), ('date_to', '>', date_from), ('employee_id', '=', employee_id.id), ('state', 'not in', ['cancel', 'refuse']), ] number_of_holidays = hr_leave.search_count(domain) if number_of_holidays: check_error = { 'checks': "exists", } holiday_status_id = int(kwargs.get('holiday_status_id')) hr_leave_type = request.env['hr.leave.type'].sudo().browse( holiday_status_id) mapped_days = hr_leave_type.get_employees_days( request.env['hr.employee'].sudo().browse(employee_id.id).ids) leave_days = mapped_days[employee_id.id][holiday_status_id] if hr_leave_type.allocation_type != 'no': if request_unit_custom and hr_leave_type.request_unit == 'day': if leave_days['virtual_remaining_leaves'] < number_of_days: check_error = { 'checks': "over", } else: if leave_days['virtual_remaining_leaves'] < number_of_hours: check_error = { 'checks': "over", } date_data = { 'date_from': date_from, 'date_to': date_to, 'number_of_days': number_of_days, 'number_of_hours': number_of_hours, 'number_of_hours_text': number_of_hours_text, 'checks': "", } date_data.update(check_error) return date_data
def _onchange_request_parameters(self): date_from = False date_to = False if not self.employee_id: return if self.request_date_from: if self.date_from: date_from = fields.Datetime.to_string(datetime.combine(fields.Date.from_string(self.request_date_from), fields.Datetime.from_string(self.date_from).time())) else: date_from = datetime.combine(self.request_date_from, time.min) if self.request_date_to: if self.date_to: date_to = fields.Datetime.to_string(datetime.combine(fields.Date.from_string(self.request_date_to), fields.Datetime.from_string(self.date_to).time())) else: date_to = datetime.combine(self.request_date_to, time.max) if not self.request_date_from or not self.request_date_to: if date_from: self.date_from = date_from if date_to: self.date_to = date_to self.number_of_days_temp = 0 return domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search(domain, order='dayofweek, day_period DESC') first_day = fields.Date.from_string(date_from) last_day = fields.Date.from_string(date_to) if self.request_unit_all in ['day', 'half']: last_day = first_day # find first attendance coming after first_day attendance_from = next((att for att in attendances if int(att.dayofweek) >= first_day.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= last_day.weekday()), attendances[-1]) if self.request_unit_all == 'day' or (self.request_unit_all == 'period' and self.leave_type_request_unit == 'day'): hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_all == 'half': hour_from = float_to_time(attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_to.hour_from) hour_to = float_to_time(attendance_from.hour_to if self.request_date_from_period == 'am' else attendance_to.hour_to) elif self.request_unit_all == 'period' and self.leave_type_request_unit == 'half': hour_from = float_to_time(attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_from.hour_to) hour_to = float_to_time(attendance_to.hour_from if self.request_date_to_period == 'am' else attendance_to.hour_to) if self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period': date_from = fields.Datetime.from_string(date_from) date_to = fields.Datetime.from_string(date_to) else: tz = self.env.user.tz or 'UTC' date_from = timezone(tz).localize(datetime.combine(first_day, hour_from)).astimezone(UTC) date_to = timezone(tz).localize(datetime.combine(last_day, hour_to)).astimezone(UTC) self.date_from = date_from self.date_to = date_to if not (self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period'): date_from = date_from date_to = date_to self.number_of_days_temp = self._get_number_of_days(date_from, date_to, self.employee_id.id)
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.request_unit_half or self.request_unit_hours: self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return 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'].search(domain, order='dayofweek, day_period DESC') 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) # 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())) # 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_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) >= self.request_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1]) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_from.hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: hour_from = float_to_time(float(self.request_hour_from)) hour_to = float_to_time(float(self.request_hour_to)) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC self.date_from = timezone(tz).localize(datetime.combine(self.request_date_from, hour_from)).astimezone(UTC).replace(tzinfo=None) self.date_to = timezone(tz).localize(datetime.combine(self.request_date_to, hour_to)).astimezone(UTC).replace(tzinfo=None) self._onchange_leave_dates()
def _onchange_request_parameters(self): if not self.request_date_from: self.date_from = False return if self.request_unit_half or self.request_unit_hours: print() # comment below line because when we select half day it change the to date # self.request_date_to = self.request_date_from if not self.request_date_to: self.date_to = False return # roster_id = self.env['hr.attendance.roster'].search([('employee_id','=',self.employee_id.id),('date','=',self.date_from.date())],limit=1) # # print("-------------roster_id", roster_id) # if roster_id and roster_id.shift_id: # if roster_id.shift_id.night_shift: # self.night_shift = True # else: # self.night_shift = False # domain =[('calendar_id', '=',roster_id.shift_id.id)] # else: # if self.employee_id.resource_calendar_id.night_shift or self.env.user.company_id.resource_calendar_id.night_shift: # self.night_shift = True # else: # self.night_shift = False domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)] attendances = self.env['resource.calendar.attendance'].search(domain, order='dayofweek, day_period DESC') # find first attendance coming after first_day attendance_from = next((att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0]) # find last attendance coming before last_day attendance_to = next( (att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1]) if self.request_unit_half: if self.request_date_from_period == 'am': hour_from = float_to_time(attendance_from.hour_from) # print("hour_fromhour_fromhour_fromhour_from",hour_from) hour_to = float_to_time(attendance_from.hour_to) # print("???????//hour_fromhour_fromhour_from",hour_to) else: hour_from = float_to_time(attendance_to.hour_from) hour_to = float_to_time(attendance_to.hour_to) elif self.request_unit_hours: # This hack is related to the definition of the field, basically we convert # the negative integer into .5 floats hour_from = float_to_time( abs(self.request_hour_from) - 0.5 if self.request_hour_from < 0 else self.request_hour_from) # print("111111111111111111111111111111111",hour_from) hour_to = float_to_time( abs(self.request_hour_to) - 0.5 if self.request_hour_to < 0 else self.request_hour_to) # print("22222222222222222222222222222",hour_to) elif self.request_unit_custom: hour_from = self.date_from.time() hour_to = self.date_to.time() else: hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) tz = self.env.user.tz if self.env.user.tz and not self.request_unit_custom else 'UTC' # custom -> already in UTC self.date_from = timezone(tz).localize(datetime.combine(self.request_date_from, hour_from)).astimezone( UTC).replace(tzinfo=None) self.date_to = timezone(tz).localize(datetime.combine(self.request_date_to, hour_to)).astimezone(UTC).replace( tzinfo=None)
def _get_attendance_log(self): self.day_log = False att_log = self.env['hr.attendance.log'] start_date = self.date + ' 00:00:00' end_date = self.date + ' 23:59:59' attendance_log_ids = att_log.search([ ('employee_id', '=', self.employee_id.id), ('action_datetime', '>=', start_date), ('action_datetime', '<=', end_date), ('state', 'in', ['approved', 'fetched']) ]) attendances = self._get_attendances(self.employee_id, self.date) attendances_recs = self.search([('date', '=', self.date), ('duty_time', 'in', attendances.ids)]) morning_duty = attendances_recs.filtered( lambda x: x.duty_time.shift == 'morning') evening_duty = attendances_recs.filtered( lambda x: x.duty_time.shift == 'evening') if morning_duty: morning_duty = morning_duty[0] or False shift_from = self.date + ' ' + str( float_to_time(morning_duty.duty_time.hour_from)) shift_to = self.date + ' ' + str( float_to_time(morning_duty.duty_time.hour_to)) shift_from = fields.Datetime.from_string(shift_from) shift_to = fields.Datetime.from_string(shift_to) if not evening_duty: morning_signs = attendance_log_ids if evening_duty: evening_shift_from = self.date + ' ' + str( float_to_time(evening_duty[0].duty_time.hour_from)) evening_shift_from = fields.Datetime.from_string( evening_shift_from) morning_signs = attendance_log_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.action_datetime), self. env.user) <= shift_to or (to_naive_user_tz( fields.Datetime.from_string(x.action_datetime), self.env.user) < evening_shift_from and x.action == 'check_out')) morning_signs.write({'attendance_id': morning_duty.id}) if evening_duty: evening_duty = evening_duty[0] or False shift_from = self.date + ' ' + str( float_to_time(evening_duty.duty_time.hour_from)) shift_to = self.date + ' ' + str( float_to_time(evening_duty.duty_time.hour_to)) shift_from = fields.Datetime.from_string(shift_from) shift_to = fields.Datetime.from_string(shift_to) if not morning_duty: evening_signs = attendance_log_ids if morning_duty: morning_shift_to = self.date + ' ' + str( float_to_time(morning_duty[0].duty_time.hour_to)) morning_shift_to = fields.Datetime.from_string( morning_shift_to) evening_signs = attendance_log_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.action_datetime), self. env.user) >= shift_from or (to_naive_user_tz( fields.Datetime.from_string(x.action_datetime), self.env.user) > morning_shift_to and x.action == 'chech_in')) evening_signs.write({'attendance_id': evening_duty.id}) return True
def _get_late(self): signin = signout = False 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) excuse = float_to_time(self.duty_time.calendar_id.excuse) excuse = excuse.hour * 3600 + excuse.minute * 60 + excuse.second max_late = float_to_time(self.duty_time.calendar_id.max_late) max_late = max_late.hour * 3600 + max_late.minute * 60 + max_late.second if self.check_in: signin = self.check_in signin = fields.Datetime.from_string(signin) signin = to_naive_user_tz(signin, self.env.user) if self.check_out: signout = self.check_out signout = fields.Datetime.from_string(signout) signout = to_naive_user_tz(signout, self.env.user) leaves_duration = self._get_leaves_durations() absence_type = False late = 0.0 diff_from_duety = 0.0 leave_signin = False leave_signout = False #there is at least one leave if leaves_duration: (leave_signin, leave_signout), temp_absence_type = leaves_duration.popitem() if not signin or leave_signin < signin: signin = leave_signin if not signout or leave_signout > signout: signout = leave_signout if not signin or not signout: self.absence_type = 'absent' self.total_delay = (duty_to - duty_from).seconds / 3600.0 self.diff_from_duety = (duty_to - duty_from).seconds / 3600.0 return delta = 0.0 if signin > duty_from: delta += (signin - duty_from).seconds if duty_to > signout: delta += (duty_to - signout).seconds if delta > excuse: diff_from_duety = delta - excuse if diff_from_duety > max_late: self.absence_type = 'absent' self.total_delay = (duty_to - duty_from).seconds / 3600.0 self.diff_from_duety = (duty_to - duty_from).seconds / 3600.0 return if not absence_type: if delta == 0: absence_type = 'no_delay' if delta > 0: absence_type = 'delay' self.absence_type = absence_type self.total_delay = delta / 3600.0 self.diff_from_duety = diff_from_duety / 3600.0 return
def _get_leaves_durations(self): 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) date_leaves_dicts = {} date_leaves = self.calendar_leaves_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.date_from), self.env.user ) <= duty_from and to_naive_user_tz( fields.Datetime.from_string(x.date_to), self.env.user ) >= duty_to) date_leaves_dicts.update({(duty_from, duty_to): x.type for x in date_leaves}) date_leaves = self.calendar_leaves_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.date_from), self.env.user ) <= duty_from and to_naive_user_tz( fields.Datetime.from_string(x.date_to), self.env.user ) < duty_to) date_leaves_dicts.update({ (duty_from, to_naive_user_tz(fields.Datetime.from_string(x.date_to), self.env.user)): x.type for x in date_leaves }) date_leaves = self.calendar_leaves_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.date_from), self.env.user ) > duty_from and to_naive_user_tz( fields.Datetime.from_string(x.date_to), self.env.user ) < duty_to) date_leaves_dicts.update({ (to_naive_user_tz(fields.Datetime.from_string(x.date_from), self.env.user), to_naive_user_tz(fields.Datetime.from_string(x.date_to), self.env.user)): x.type for x in date_leaves }) date_leaves = self.calendar_leaves_ids.filtered( lambda x: to_naive_user_tz( fields.Datetime.from_string(x.date_from), self.env.user ) > duty_from and to_naive_user_tz( fields.Datetime.from_string(x.date_to), self.env.user ) > duty_to) date_leaves_dicts.update({ (to_naive_user_tz(fields.Datetime.from_string(x.date_from), self.env.user), duty_to): x.type for x in date_leaves }) if date_leaves_dicts: #get the leave with the most duration keys = date_leaves_dicts.keys() keys = {(x[1] - x[0]).seconds: x for x in keys} #get the max key using diffrence max_key = max(keys.keys()) #get the max key using keys dict max_key = keys[max_key] #get the max key using date_leaves_dicts dict return {max_key: date_leaves_dicts[max_key]} return {}