load->database(); date_default_timezone_set('Asia/Jakarta'); } // ===================================================== // PROCESS ATTENDANCE LOG // ===================================================== public function process_attendance() { echo "PROCESS ATTENDANCE START\n"; // ============================================= // GET PENDING LOG // ============================================= $logs = $this->db ->where('process_status','pending') ->order_by('check_time','ASC') ->limit(1000) ->get('k_attendance_logs') ->result(); foreach($logs as $log){ try{ // ===================================== // GET EMPLOYEE // ===================================== $employee = $this->db ->where( 'fingerprint_user_id', $log->user_id ) ->where('is_active',1) ->get('k_employees') ->row(); if(!$employee){ $this->updateLogStatus( $log->id, 'failed' ); echo "FAILED EMPLOYEE : {$log->user_id}\n"; continue; } // ===================================== // UPDATE EMPLOYEE ID // ===================================== $this->db ->where('id',$log->id) ->update( 'k_attendance_logs', [ 'employee_id' => $employee->id ] ); $logDateTime = date( 'Y-m-d H:i:s', strtotime($log->check_time) ); // ===================================== // FIND SCHEDULE // SUPPORT SHIFT MALAM // ===================================== $this->db->from( 'k_employee_shift_schedules' ); $this->db->where( 'employee_id', $employee->id ); $this->db->where( 'status', 'published' ); // ===================================== // RANGE SHIFT // ===================================== $this->db->where(" '{$logDateTime}' BETWEEN DATE_SUB(start_datetime, INTERVAL 3 HOUR) AND DATE_ADD(end_datetime, INTERVAL 6 HOUR) ", null, false); $this->db->order_by( 'start_datetime', 'DESC' ); $schedule = $this->db->get()->row(); // ===================================== // SCHEDULE NOT FOUND // ===================================== if(!$schedule){ $this->updateLogStatus( $log->id, 'failed' ); echo "FAILED SCHEDULE : {$logDateTime}\n"; continue; } // ===================================== // GET SHIFT // ===================================== $shift = $this->db ->where('id',$schedule->shift_id) ->get('k_shifts') ->row(); if(!$shift){ $this->updateLogStatus( $log->id, 'failed' ); echo "FAILED SHIFT : {$schedule->shift_id}\n"; continue; } // ===================================== // ATTENDANCE DATE // ===================================== $attendance_date = date( 'Y-m-d', strtotime($schedule->start_datetime) ); // ===================================== // GET ATTENDANCE // ===================================== $attendance = $this->db ->where( 'employee_id', $employee->id ) ->where( 'attendance_date', $attendance_date ) ->get('k_attendances') ->row(); // ===================================== // CHECK LATE // ===================================== $late_minutes = 0; $maxCheckin = strtotime( $schedule->start_datetime ) + ( $shift->late_tolerance_minutes * 60 ); if( strtotime($logDateTime) > $maxCheckin ){ $late_minutes = floor( ( strtotime($logDateTime) - strtotime($schedule->start_datetime) ) / 60 ); if($late_minutes < 0){ $late_minutes = 0; } } // ===================================== // INSERT CHECKIN // ===================================== if(!$attendance){ $this->db->insert( 'k_attendances', [ 'employee_id' => $employee->id, 'attendance_date' => $attendance_date, 'checkin_time' => $logDateTime, 'late_minutes' => $late_minutes, 'attendance_status' => ( $late_minutes > 0 ? 'late' : 'present' ), 'shift_id' => $shift->id, 'attendance_log_in_id' => $log->id, 'created_at' => date('Y-m-d H:i:s') ] ); echo "CHECKIN : {$employee->full_name}\n"; } else { // ================================= // SUDAH ADA CHECKOUT // ================================= if(!empty($attendance->checkout_time)){ $this->updateLogStatus( $log->id, 'processed' ); echo "SKIP LOG (SUDAH CHECKOUT)\n"; continue; } // ================================= // CEK SELISIH JAM // ================================= $diffMinutes = floor( ( strtotime($logDateTime) - strtotime($attendance->checkin_time) ) / 60 ); // ================================= // MINIMAL 2 JAM // BARU DIANGGAP CHECKOUT // ================================= if($diffMinutes < 120){ $this->updateLogStatus( $log->id, 'processed' ); echo "SKIP DUPLICATE LOG : {$employee->full_name}\n"; continue; } // ================================= // WORK HOURS // ================================= $workHours = ( strtotime($logDateTime) - strtotime($attendance->checkin_time) ) / 3600; if($workHours < 0){ $workHours = 0; } // ================================= // EARLY LEAVE // ================================= $early_leave_minutes = 0; if( strtotime($logDateTime) < strtotime($schedule->end_datetime) ){ $early_leave_minutes = floor( ( strtotime($schedule->end_datetime) - strtotime($logDateTime) ) / 60 ); if($early_leave_minutes < 0){ $early_leave_minutes = 0; } } // ================================= // OVERTIME // ================================= $overtime_hours = 0; if( strtotime($logDateTime) > strtotime($schedule->end_datetime) ){ $overtime_hours = round( ( strtotime($logDateTime) - strtotime($schedule->end_datetime) ) / 3600, 2 ); if($overtime_hours < 0){ $overtime_hours = 0; } } // ================================= // UPDATE CHECKOUT // ================================= $this->db ->where( 'id', $attendance->id ) ->update( 'k_attendances', [ 'checkout_time' => $logDateTime, 'attendance_log_out_id' => $log->id, 'work_hours' => round($workHours,2), 'early_leave_minutes' => $early_leave_minutes, 'overtime_hours' => $overtime_hours ] ); echo "CHECKOUT : {$employee->full_name}\n"; } // ===================================== // UPDATE LOG STATUS // ===================================== $this->updateLogStatus( $log->id, 'processed' ); echo "SUCCESS LOG ID : {$log->id}\n"; } catch(Exception $e){ $this->updateLogStatus( $log->id, 'failed' ); echo "ERROR : " . $e->getMessage() . "\n"; } } echo "PROCESS ATTENDANCE DONE\n"; } // ===================================================== // AUTO CLOSE ATTENDANCE // ===================================================== public function auto_close_attendance() { echo "AUTO CLOSE START\n"; // ============================================= // AMBIL ATTENDANCE BELUM CHECKOUT // ============================================= $attendances = $this->db ->where('checkout_time IS NULL', null, false) ->get('k_attendances') ->result(); foreach($attendances as $attendance){ // ========================================= // GET SCHEDULE // ========================================= $schedule = $this->db ->where( 'employee_id', $attendance->employee_id ) ->where( 'shift_id', $attendance->shift_id ) ->where( 'DATE(start_datetime)', $attendance->attendance_date ) ->get('k_employee_shift_schedules') ->row(); if(!$schedule){ continue; } // ========================================= // AUTO CLOSE // END SHIFT + 4 JAM // ========================================= $autoCloseTime = date( 'Y-m-d H:i:s', strtotime( $schedule->end_datetime . ' +4 hours' ) ); // ========================================= // BELUM WAKTUNYA // ========================================= if( strtotime(date('Y-m-d H:i:s')) < strtotime($autoCloseTime) ){ continue; } // ========================================= // WORK HOURS // ========================================= $workHours = ( strtotime($schedule->end_datetime) - strtotime($attendance->checkin_time) ) / 3600; if($workHours < 0){ $workHours = 0; } // ========================================= // AUTO CHECKOUT // ========================================= $this->db ->where('id',$attendance->id) ->update( 'k_attendances', [ 'checkout_time' => $schedule->end_datetime, 'work_hours' => round($workHours,2), 'notes' => 'Auto checkout by system' ] ); echo "AUTO CLOSE EMPLOYEE : {$attendance->employee_id}\n"; } echo "AUTO CLOSE DONE\n"; } // ===================================================== // GENERATE DAILY ATTENDANCE // ===================================================== public function generate_daily_attendance() { echo "GENERATE DAILY START\n"; // ============================================= // GENERATE HARI KEMARIN // ============================================= $date = date( 'Y-m-d', strtotime('-1 day') ); // ============================================= // GET ALL SCHEDULE // ============================================= $schedules = $this->db ->where('schedule_date', $date) ->where('status','published') ->get('k_employee_shift_schedules') ->result(); foreach($schedules as $schedule){ // ========================================= // CHECK ATTENDANCE EXIST // ========================================= $attendance = $this->db ->where( 'employee_id', $schedule->employee_id ) ->where( 'attendance_date', $date ) ->get('k_attendances') ->row(); if($attendance){ continue; } // ========================================= // CHECK HOLIDAY // ========================================= $holiday = $this->db ->where('holiday_date',$date) ->get('k_holidays') ->row(); if($holiday){ $this->db->insert( 'k_attendances', [ 'employee_id' => $schedule->employee_id, 'attendance_date' => $date, 'attendance_status' => 'holiday', 'is_holiday' => 1, 'shift_id' => $schedule->shift_id, 'notes' => $holiday->holiday_name ] ); continue; } // ========================================= // CHECK LEAVE // ========================================= $leave = $this->db ->where( 'employee_id', $schedule->employee_id ) ->where( 'approval_status', 'approved' ) ->where('start_date <=',$date) ->where('end_date >=',$date) ->get('k_leave_requests') ->row(); if($leave){ $this->db->insert( 'k_attendances', [ 'employee_id' => $schedule->employee_id, 'attendance_date' => $date, 'attendance_status' => $leave->leave_type, 'shift_id' => $schedule->shift_id, 'notes' => $leave->reason ] ); continue; } // ========================================= // DEFAULT ALPHA // ========================================= $this->db->insert( 'k_attendances', [ 'employee_id' => $schedule->employee_id, 'attendance_date' => $date, 'attendance_status' => 'alpha', 'shift_id' => $schedule->shift_id, 'notes' => 'Tidak hadir' ] ); echo "GENERATE EMPLOYEE : {$schedule->employee_id}\n"; } echo "GENERATE DAILY DONE\n"; } // ===================================================== // UPDATE LOG STATUS // ===================================================== private function updateLogStatus( $id, $status ){ $this->db ->where('id',$id) ->update( 'k_attendance_logs', [ 'process_status' => $status ] ); } }