644 lines
20 KiB
PHP
644 lines
20 KiB
PHP
<?php
|
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
|
|
|
class Scheduler extends CI_Controller {
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->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
|
|
]
|
|
);
|
|
}
|
|
} |