From 7fa50478ccdaffa5f2ed45575385a072a4f109fa Mon Sep 17 00:00:00 2001 From: Truong Vo <41848815+vmtruong301296@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:26:33 +0700 Subject: [PATCH 1/3] =?UTF-8?q?T=E1=BA=A1o=20ticket=20t=E1=BB=B1=20=C4=91?= =?UTF-8?q?=E1=BB=99ng=20cho=20user=20khi=20user=20kh=C3=B4ng=20check=20in?= =?UTF-8?q?,=20check=20out?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/CheckUserAttendanceCommand.php | 33 +++++ BACKEND/app/Console/Kernel.php | 6 + BACKEND/app/Jobs/CheckUserAttendanceJob.php | 126 ++++++++++++++++++ BACKEND/app/Jobs/DeductLeaveDays.php | 2 +- 4 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 BACKEND/app/Console/Commands/CheckUserAttendanceCommand.php create mode 100644 BACKEND/app/Jobs/CheckUserAttendanceJob.php diff --git a/BACKEND/app/Console/Commands/CheckUserAttendanceCommand.php b/BACKEND/app/Console/Commands/CheckUserAttendanceCommand.php new file mode 100644 index 0000000..6b8b17e --- /dev/null +++ b/BACKEND/app/Console/Commands/CheckUserAttendanceCommand.php @@ -0,0 +1,33 @@ +argument('period'); + + // Dispatch job để kiểm tra check in và check out + CheckUserAttendanceJob::dispatch($period); + } +} diff --git a/BACKEND/app/Console/Kernel.php b/BACKEND/app/Console/Kernel.php index 2af3d1e..6d56e12 100755 --- a/BACKEND/app/Console/Kernel.php +++ b/BACKEND/app/Console/Kernel.php @@ -26,6 +26,12 @@ class Kernel extends ConsoleKernel // Chạy command vào ngày 31/12 lúc 23:59:59 mỗi năm $schedule->command('initialize:leavedays')->yearlyOn(12, 31, '23:59:59'); $schedule->command('leave:deduct')->yearlyOn(3, 31, '23:59:59'); + + // Chạy buổi sáng lúc 12:00 + $schedule->command('attendance:check S')->dailyAt('12:00'); + + // Chạy buổi chiều lúc 17:30 + $schedule->command('attendance:check C')->dailyAt('17:30'); } /** diff --git a/BACKEND/app/Jobs/CheckUserAttendanceJob.php b/BACKEND/app/Jobs/CheckUserAttendanceJob.php new file mode 100644 index 0000000..d93388d --- /dev/null +++ b/BACKEND/app/Jobs/CheckUserAttendanceJob.php @@ -0,0 +1,126 @@ +period = $period; + } + + /** + * Execute the job. + */ + public function handle() + { + // Lấy tất cả người dùng + $users = User::all(); + + foreach ($users as $key => $user) { + // if($user->id != 2){ + // continue; + // } + // Kiểm tra dựa trên period (Sáng 'S' hoặc Chiều 'C') + if ($this->period === 'S') { + $this->checkMorning($user->id); + } elseif ($this->period === 'C') { + $this->checkAfternoon($user->id); + } else { + // Nếu không có period, kiểm tra cả sáng và chiều + $this->checkMorning($user->id); + $this->checkAfternoon($user->id); + } + } + } + + /** + * 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($userId) + { + $morningCheckIn = Carbon::createFromTime(7, 30); + $morningCheckOut = Carbon::createFromTime(11, 30); + $checkDeadline = Carbon::createFromTime(12, 0); // Hạn kiểm tra cho buổi sáng + $today = Carbon::today(); + + // Lấy tất cả tracking của user cho buổi sáng (từ 7:30 đến 12:00) + $morningRecords = Tracking::where('user_id', $userId) + ->whereBetween('time_string', [$today->copy()->setTime(7, 30), $checkDeadline]) + ->get(); + + $hasMorningCheckIn = $morningRecords->where('status', 'check in')->isNotEmpty(); + $hasMorningCheckOut = $morningRecords->where('status', 'check out')->isNotEmpty(); + + // Nếu không có check-in hoặc check-out, tạo ticket + if (!$hasMorningCheckIn && !$hasMorningCheckOut) { + Ticket::create([ + 'user_id' => $userId, + 'start_date' => $today->format('Y-m-d'), + 'start_period' => 'S', // Morning + 'end_date' => $today->format('Y-m-d'), + 'end_period' => 'S', // Morning + 'type' => 'UNAUTHORIZEDLEAVE', + 'reason' => 'No check in/out for morning', + 'status' => 'WAITING', + 'created_at' => Carbon::now(), + 'updated_at' => Carbon::now() + ]); + } + } + + /** + * 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($userId) + { + $afternoonCheckIn = Carbon::createFromTime(13, 0); + $afternoonCheckOut = Carbon::createFromTime(17, 0); + $checkDeadline = Carbon::createFromTime(17, 30); // Hạn kiểm tra cho buổi chiều + $today = Carbon::today(); + + // Lấy tất cả tracking của user cho buổi chiều (từ 13:00 đến 17:30) + $afternoonRecords = Tracking::where('user_id', $userId) + ->whereBetween('time_string', [$today->copy()->setTime(13, 0), $checkDeadline]) + ->get(); + + $hasAfternoonCheckIn = $afternoonRecords->where('status', 'check in')->isNotEmpty(); + $hasAfternoonCheckOut = $afternoonRecords->where('status', 'check out')->isNotEmpty(); + + // Nếu không có check-in hoặc check-out, tạo ticket + if (!$hasAfternoonCheckIn && !$hasAfternoonCheckOut) { + Ticket::create([ + 'user_id' => $userId, + 'start_date' => $today->format('Y-m-d'), + 'start_period' => 'C', // Afternoon + 'end_date' => $today->format('Y-m-d'), + 'end_period' => 'C', // Afternoon + 'type' => 'UNAUTHORIZEDLEAVE', + 'reason' => 'No check in/out for afternoon', + 'status' => 'WAITING', + 'created_at' => Carbon::now(), + 'updated_at' => Carbon::now() + ]); + } + } +} diff --git a/BACKEND/app/Jobs/DeductLeaveDays.php b/BACKEND/app/Jobs/DeductLeaveDays.php index 94c7383..86dc3b0 100644 --- a/BACKEND/app/Jobs/DeductLeaveDays.php +++ b/BACKEND/app/Jobs/DeductLeaveDays.php @@ -67,7 +67,7 @@ class DeductLeaveDays implements ShouldQueue ]); } } else { - //Nếu không sử dụng ngày nghỉ còn lại ở nằm rồi thì xóa => theo luật ld + //Nếu không sử dụng ngày nghỉ còn lại ở năm rồi thì xóa => theo luật ld LeaveDays::where('ld_year', $this->year) ->where('ld_user_id', $user->id) ->update([ From d0c1b6894b0b76a0a127ed5d16ef75e8346d32a8 Mon Sep 17 00:00:00 2001 From: Truong Vo <41848815+vmtruong301296@users.noreply.github.com> Date: Mon, 14 Oct 2024 10:09:04 +0700 Subject: [PATCH 2/3] =?UTF-8?q?T=E1=BA=A1o=20ticket=20t=E1=BB=B1=20=C4=91?= =?UTF-8?q?=E1=BB=99ng=20cho=20user=20khi=20user=20kh=C3=B4ng=20check=20in?= =?UTF-8?q?,=20check=20out?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BACKEND/app/Jobs/CheckUserAttendanceJob.php | 146 +++++++++++--------- 1 file changed, 82 insertions(+), 64 deletions(-) diff --git a/BACKEND/app/Jobs/CheckUserAttendanceJob.php b/BACKEND/app/Jobs/CheckUserAttendanceJob.php index d93388d..d6d85a1 100644 --- a/BACKEND/app/Jobs/CheckUserAttendanceJob.php +++ b/BACKEND/app/Jobs/CheckUserAttendanceJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Mail\TicketMail; use App\Models\User; use Carbon\Carbon; use Illuminate\Bus\Queueable; @@ -9,6 +10,9 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Mail; +use Modules\Admin\app\Http\Controllers\CategoryController; +use Modules\Admin\app\Models\Admin; use Modules\Admin\app\Models\Ticket; use Modules\Admin\app\Models\Tracking; @@ -36,18 +40,82 @@ class CheckUserAttendanceJob implements ShouldQueue $users = User::all(); foreach ($users as $key => $user) { - // if($user->id != 2){ + // if ($user->id != 2) { // continue; // } // Kiểm tra dựa trên period (Sáng 'S' hoặc Chiều 'C') if ($this->period === 'S') { - $this->checkMorning($user->id); + $this->checkMorning($user); } elseif ($this->period === 'C') { - $this->checkAfternoon($user->id); + $this->checkAfternoon($user); } else { - // Nếu không có period, kiểm tra cả sáng và chiều - $this->checkMorning($user->id); - $this->checkAfternoon($user->id); + 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 + $existingTicket = Ticket::where('user_id', $userId) + ->where('start_date', $today->format('Y-m-d')) + ->where('start_period', $periodCode) + ->where('end_date', $today->format('Y-m-d')) + ->where('end_period', $periodCode) + ->whereIn('status', ['WAITING', 'CONFIRMED']) + ->first(); + $type = 'ONLEAVE'; + $reason = 'KHONG PHEP'; + // Nếu không có check-in hoặc check-out, và chưa có ticket, tạo ticket mới + if (!$hasCheckIn && !$hasCheckOut && !$existingTicket) { + 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( + "email_template" => "email.notification_tickets", + "email" => $user->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)); } } } @@ -56,71 +124,21 @@ class CheckUserAttendanceJob implements ShouldQueue * 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($userId) + public function checkMorning($user) { - $morningCheckIn = Carbon::createFromTime(7, 30); - $morningCheckOut = Carbon::createFromTime(11, 30); - $checkDeadline = Carbon::createFromTime(12, 0); // Hạn kiểm tra cho buổi sáng - $today = Carbon::today(); - - // Lấy tất cả tracking của user cho buổi sáng (từ 7:30 đến 12:00) - $morningRecords = Tracking::where('user_id', $userId) - ->whereBetween('time_string', [$today->copy()->setTime(7, 30), $checkDeadline]) - ->get(); - - $hasMorningCheckIn = $morningRecords->where('status', 'check in')->isNotEmpty(); - $hasMorningCheckOut = $morningRecords->where('status', 'check out')->isNotEmpty(); - - // Nếu không có check-in hoặc check-out, tạo ticket - if (!$hasMorningCheckIn && !$hasMorningCheckOut) { - Ticket::create([ - 'user_id' => $userId, - 'start_date' => $today->format('Y-m-d'), - 'start_period' => 'S', // Morning - 'end_date' => $today->format('Y-m-d'), - 'end_period' => 'S', // Morning - 'type' => 'UNAUTHORIZEDLEAVE', - 'reason' => 'No check in/out for morning', - 'status' => 'WAITING', - 'created_at' => Carbon::now(), - 'updated_at' => Carbon::now() - ]); - } + $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($userId) + public function checkAfternoon($user) { - $afternoonCheckIn = Carbon::createFromTime(13, 0); - $afternoonCheckOut = Carbon::createFromTime(17, 0); - $checkDeadline = Carbon::createFromTime(17, 30); // Hạn kiểm tra cho buổi chiều - $today = Carbon::today(); - - // Lấy tất cả tracking của user cho buổi chiều (từ 13:00 đến 17:30) - $afternoonRecords = Tracking::where('user_id', $userId) - ->whereBetween('time_string', [$today->copy()->setTime(13, 0), $checkDeadline]) - ->get(); - - $hasAfternoonCheckIn = $afternoonRecords->where('status', 'check in')->isNotEmpty(); - $hasAfternoonCheckOut = $afternoonRecords->where('status', 'check out')->isNotEmpty(); - - // Nếu không có check-in hoặc check-out, tạo ticket - if (!$hasAfternoonCheckIn && !$hasAfternoonCheckOut) { - Ticket::create([ - 'user_id' => $userId, - 'start_date' => $today->format('Y-m-d'), - 'start_period' => 'C', // Afternoon - 'end_date' => $today->format('Y-m-d'), - 'end_period' => 'C', // Afternoon - 'type' => 'UNAUTHORIZEDLEAVE', - 'reason' => 'No check in/out for afternoon', - 'status' => 'WAITING', - 'created_at' => Carbon::now(), - 'updated_at' => Carbon::now() - ]); - } + $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); } } From 46d4ffa339b66b7edfc37f990efa92691f9a16d2 Mon Sep 17 00:00:00 2001 From: Truong Vo <41848815+vmtruong301296@users.noreply.github.com> Date: Mon, 14 Oct 2024 10:11:59 +0700 Subject: [PATCH 3/3] =?UTF-8?q?T=E1=BA=A1o=20ticket=20t=E1=BB=B1=20=C4=91?= =?UTF-8?q?=E1=BB=99ng=20cho=20user=20khi=20user=20kh=C3=B4ng=20check=20in?= =?UTF-8?q?,=20check=20out?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BACKEND/app/Jobs/CheckUserAttendanceJob.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BACKEND/app/Jobs/CheckUserAttendanceJob.php b/BACKEND/app/Jobs/CheckUserAttendanceJob.php index d6d85a1..04ba727 100644 --- a/BACKEND/app/Jobs/CheckUserAttendanceJob.php +++ b/BACKEND/app/Jobs/CheckUserAttendanceJob.php @@ -37,8 +37,7 @@ class CheckUserAttendanceJob implements ShouldQueue public function handle() { // Lấy tất cả người dùng - $users = User::all(); - + $users = User::where('permission', 'not like', '%admin%')->get(); foreach ($users as $key => $user) { // if ($user->id != 2) { // continue;