from odoo import fields, api, models from datetime import datetime class AttendanceAttendance(models.Model): _name = "attendance.attendance" date = fields.Date(string='Date', default=fields.Date.today, required=True) work_location_id = fields.Many2one('hr.work.location', default=lambda self: self.env.company.id) attendance_data = fields.One2many('attendance.data','attendance_id', string="Attendance Data") _sql_constraints = [ ('name_date_work_location_id_unique', 'unique(date, work_location_id)', 'The combination of date and work_location_id should be unique.') ] def get_attendance_for_date(self, rec_date, employee_id): # Convert rec.date to a datetime object for filtering start_of_day = fields.Datetime.to_string( fields.Datetime.from_string(rec_date).replace(hour=0, minute=0, second=0)) end_of_day = fields.Datetime.to_string( fields.Datetime.from_string(rec_date).replace(hour=23, minute=59, second=59)) # Filter attendance records for the given employee and date range attendance_records = self.env['hr.attendance'].sudo().search([ ('employee_id', '=', employee_id), ('check_in', '>=', start_of_day), ('check_in', '<=', end_of_day) ],order='check_in asc') if not attendance_records: return False, False, False # Initialize variables to track min check_in and max check_out min_check_in = None max_check_out = None for record in attendance_records: if min_check_in is None or record.check_in < min_check_in: min_check_in = record.check_in if max_check_out is None or (record.check_out and record.check_out > max_check_out): max_check_out = record.check_out # If no check_out found, set max_check_out to current time if not max_check_out: max_check_out = False total_worked_hours = sum(record.worked_hours for record in attendance_records) # Return the min_check_in and max_check_out return min_check_in, max_check_out, total_worked_hours def update_attendance_data(self): for rec in self: if rec.date and rec.work_location_id: rec.attendance_data.unlink() emp_work_location_history = self.env['emp.work.location.history'].sudo().search([('employee_id.company_id','=',self.env.company.id),('employee_id.work_location_id','=',rec.work_location_id.id),('start_date','<=',rec.date),'|',('end_date','=',False),('end_date','>=',rec.date)]).employee_id.ids employees = self.env['hr.employee'].sudo().search([('id','not in',emp_work_location_history),('work_location_id','=',rec.work_location_id.id)]).ids all_employees = self.env['hr.employee'].sudo().search([('id','in',list(set(emp_work_location_history) | set(employees)))]) attendance_data = list() for emp in all_employees: leaves = self.env['hr.leave'].search([('employee_id','=',emp.id),('request_date_from', '<=', rec.date),('request_date_to', '>=', rec.date),('state','=','validate')]) check_in, check_out, worked_hours = self.get_attendance_for_date(rec.date,emp.id) if leaves: status = 'leave' elif check_in or check_out: status = 'present' else: status = 'no_info' if not leaves and (check_in and check_out): # Calculate total hours between check_in and check_out in float format total_hours = (check_out - check_in).total_seconds() / 3600 # Convert seconds to hours # Calculate out_time as the difference between total_hours and worked_hours out_time = total_hours - (worked_hours if worked_hours else 0) else: total_hours = 0 out_time = 0 data = self.env['attendance.data'].sudo().create({ 'employee_id': emp.id, 'min_check_in': check_in if check_in else False, 'max_check_out': check_out if check_out else False, 'worked_hours': worked_hours if worked_hours else False, 'out_time': out_time if out_time else False, 'status': status, 'attendance_id': rec.id }) attendance_data.append(data.id) rec.attendance_data = [(6, 0, attendance_data)] def update_hr_attendance_check_out(self): attendance = self.env['hr.attendance'].sudo().search([('check_in','!=', False),('check_out','=',False)]) for rec in attendance: rec.check_out = fields.Datetime.to_string( fields.Datetime.from_string(rec.check_in).replace(hour=21, minute=0, second=59)) class AttendanceData(models.Model): _name = 'attendance.data' employee_id = fields.Many2one('hr.employee') min_check_in = fields.Datetime(string="Check In") max_check_out = fields.Datetime(string="Check Out") out_time = fields.Float() worked_hours = fields.Float() # extra_hours = fields.Float() status = fields.Selection([('leave','On Leave'),('present','Present'),('no_info','No Information')]) attendance_id = fields.Many2one('attendance.attendance')