period = $period; } /** * Execute the job. */ public function handle() { // Lấy tất cả người dùng $users = User::where('permission', 'not like', '%admin%') ->where('permission', 'not like', '%accountant%')->get(); foreach ($users as $key => $user) { // Check nhân viên nghỉ việc if ($user->is_separated) { continue; } // Kiểm tra dựa trên period (Sáng 'S' hoặc Chiều 'C') if ($this->period === 'S') { $this->checkMorning($user); } elseif ($this->period === 'C') { $this->checkAfternoon($user); } else { if ($this->period == null) { // Nếu không có period, kiểm tra cả sáng và chiều $this->checkMorning($user); $this->checkAfternoon($user); } } } } private function checkAttendance($user, $periodCode, $startTime, $endTime) { $today = Carbon::today(); $userId = $user->id; // Lấy tất cả tracking của user trong khoảng thời gian được chỉ định $records = Tracking::where('user_id', $userId) ->whereBetween('time_string', [$startTime, $endTime]) ->get(); $hasCheckIn = $records->where('status', 'check in')->isNotEmpty(); $hasCheckOut = $records->where('status', 'check out')->isNotEmpty(); // Kiểm tra nếu đã có ticket chờ xử lý hoặc đã được xác nhận, cho cả sáng và chiều $existingTicket = Ticket::where('user_id', $userId) ->where(function ($query) use ($today, $periodCode) { // Check for tickets that exactly cover the current day and period $query->where(function ($subQuery) use ($today, $periodCode) { $subQuery->where('start_date', $today->format('Y-m-d')) ->where('end_date', $today->format('Y-m-d')) ->where(function ($periodQuery) use ($periodCode) { // Check if the ticket covers the current period $periodQuery->where('start_period', $periodCode) ->orWhere(function ($query) { // Check for a full-day ticket (S -> C) $query->where('start_period', 'S') ->where('end_period', 'C'); }); }); }) // Check for tickets that span multiple days ->orWhere(function ($subQuery) use ($today, $periodCode) { $subQuery->where('start_date', '<=', $today->format('Y-m-d')) ->where('end_date', '>=', $today->format('Y-m-d')) ->where(function ($periodQuery) use ($periodCode, $today) { $periodQuery->where(function ($query) use ($today) { $query->where('start_date', '<', $today->format('Y-m-d')) ->where('end_date', '>', $today->format('Y-m-d')); }) ->orWhere(function ($query) use ($today, $periodCode) { $query->where(function ($queryDateStart) use ($today, $periodCode) { $queryDateStart->where('start_date', '=', $today->format('Y-m-d')) ->where('end_date', '>', $today->format('Y-m-d')) ->where(function ($queryDateStartChild) use ($periodCode) { $queryDateStartChild->where('start_period', $periodCode) ->orWhere(function ($query) { $query->where('start_period', 'S'); }); }); }) ->orWhere(function ($queryDateEnd) use ($today, $periodCode) { $queryDateEnd->where('end_date', '=', $today->format('Y-m-d')) ->where('start_date', '<', $today->format('Y-m-d')) ->where(function ($queryDateStartChild) use ($periodCode) { $queryDateStartChild->where('end_period', $periodCode) ->orWhere(function ($query) { $query->where('end_period', 'C'); }); }); }); }); }); }); }) ->whereIn('status', ['WAITING', 'CONFIRMED']) ->first(); $type = 'ONLEAVE'; $reason = 'KHONG PHEP'; //Check ngày hợp lệ nếu có check và check out của user khác $dateNow = Tracking::whereBetween('time_string', [$startTime, $endTime])->exists(); // Nếu không có check in/out, không gửi ticket và có check in/out của người khác => tạo ticket không phép if ($hasCheckIn || $hasCheckOut) { return; } if ($existingTicket) { return; } if ($dateNow) { $ticket = Ticket::create([ 'user_id' => $userId, 'start_date' => $today->format('Y-m-d'), 'start_period' => $periodCode, 'end_date' => $today->format('Y-m-d'), 'end_period' => $periodCode, 'type' => $type, 'reason' => $reason, 'status' => 'WAITING', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now() ]); //Send mail $dataMasterStartPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $periodCode); $dataMasterEndPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $periodCode); $dataMasterType = CategoryController::getListMasterByCodeAndType("REASON", $type); $formattedStartDate = $today->format('d/m/Y'); $formattedEndDate = $today->format('d/m/Y'); $admins = Admin::where('permission', 'like', '%admin%')->get(); foreach ($admins as $key => $value) { $data = array( "ticket_id" => $ticket->id, "email_template" => "email.notification_tickets", "email" => $user->email, "admin_email" => $value->email, "name" => $user->name, "date" => $dataMasterStartPeriod->c_name . " (" . $formattedStartDate . ") - " . $dataMasterEndPeriod->c_name . " (" . $formattedEndDate . ")", "type" => $dataMasterType->c_name, "note" => $reason, "link" => "/tickets-management", //link đến page admin "subject" => "[Ticket request] Ticket From " . $user->name ); Mail::to($value->email)->send(new TicketMail($data)); } } } /** * Kiểm tra check-in/check-out buổi sáng và tạo ticket nếu thiếu. * @param int $userId */ public function checkMorning($user) { $startTime = Carbon::today()->setTime(6, 0); // Thời gian bắt đầu buổi sáng $endTime = Carbon::createFromTime(12, 0); // Thời gian kết thúc buổi sáng $this->checkAttendance($user, 'S', $startTime, $endTime); } /** * Kiểm tra check-in/check-out buổi chiều và tạo ticket nếu thiếu. * @param int $userId */ public function checkAfternoon($user) { $startTime = Carbon::today()->setTime(12, 0); // Thời gian bắt đầu buổi chiều $endTime = Carbon::createFromTime(17, 30); // Thời gian kết thúc buổi chiều $this->checkAttendance($user, 'C', $startTime, $endTime); } }