diff --git a/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php b/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php index 6e122bc..a0d8286 100644 --- a/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php +++ b/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php @@ -7,13 +7,18 @@ use App\Http\Controllers\Controller; use App\Jobs\InitializeLeaveDays; use App\Models\LeaveDays; use App\Models\Notes; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use Maatwebsite\Excel\Facades\Excel; +use Modules\Admin\app\Models\Ticket; +use App\Traits\AnalyzeData; class LeaveManagementController extends Controller { + use AnalyzeData; + public function get(Request $request) { $yearNow = $request->query('year', now()->year); @@ -166,6 +171,16 @@ class LeaveManagementController extends Controller $note->n_reason = $reason; $note->save(); + + // Clear Timekeeping cache + $ticket = Ticket::find($note->ticket_id); + if ($ticket) { + $this->createOrUpdateRecordForCurrentMonth(Carbon::parse($ticket->start_date)->month, Carbon::parse($ticket->start_date)->year); + $this->createOrUpdateRecordForCurrentMonth(Carbon::parse($ticket->end_date)->month, Carbon::parse($ticket->end_date)->year); + } else { + $this->createOrUpdateRecordForCurrentMonth(Carbon::parse($note->created_at)->month, Carbon::parse($note->created_at)->year); + } + return response()->json(data: ['message' => 'Update success', 'status' => true]); } diff --git a/BACKEND/Modules/Auth/app/Http/Controllers/UserController.php b/BACKEND/Modules/Auth/app/Http/Controllers/UserController.php index 565b368..5120b52 100755 --- a/BACKEND/Modules/Auth/app/Http/Controllers/UserController.php +++ b/BACKEND/Modules/Auth/app/Http/Controllers/UserController.php @@ -39,7 +39,7 @@ class UserController extends Controller ]); if ($request->has('id')) { - $payload = $request->only(['name', 'email', 'permission', 'is_permanent']); + $payload = $request->only(['name', 'email', 'permission', 'is_permanent', 'is_separated']); $user = User::find($request->id); // Không cho chuyển từ chính thức thành lại thử việc @@ -47,6 +47,10 @@ class UserController extends Controller return response()->json(['status' => false, 'message' => 'You cannot change an employee from permanent to probationary.']); } + if (!$request->is_separated && $user->is_separated) { + return response()->json(['status' => false, 'message' => 'You cannot change status of separated employee.']); + } + // Thêm ngày phép khi thành nhân viên chính thức if ($request->is_permanent && !$user->is_permanent) { $userLeaveDay = LeaveDays::where('ld_user_id', $user->id) @@ -78,7 +82,8 @@ class UserController extends Controller 'email' => $request->email, 'password' => bcrypt('Work@1234'), 'permission' => $request->permission, - 'is_permanent' => false + 'is_permanent' => false, + 'is_separated' => false ]); // Khởi tạo LeaveDays cho nhân viên mới diff --git a/BACKEND/Modules/Auth/app/Models/User.php b/BACKEND/Modules/Auth/app/Models/User.php index 4347eca..d6a7de4 100755 --- a/BACKEND/Modules/Auth/app/Models/User.php +++ b/BACKEND/Modules/Auth/app/Models/User.php @@ -27,6 +27,7 @@ class User extends Authenticatable implements JWTSubject 'password', 'permission', 'is_permanent', + 'is_separated', 'permanent_date' ]; diff --git a/BACKEND/app/Console/Commands/InitializeLeaveDaysCommand.php b/BACKEND/app/Console/Commands/InitializeLeaveDaysCommand.php index bf74a72..b68abf8 100644 --- a/BACKEND/app/Console/Commands/InitializeLeaveDaysCommand.php +++ b/BACKEND/app/Console/Commands/InitializeLeaveDaysCommand.php @@ -17,8 +17,6 @@ class InitializeLeaveDaysCommand extends Command public function handle() { - $year = $this->argument('year'); - // Không sử dụng nữa, theo rule mới - // InitializeLeaveDays::dispatch($year); + InitializeLeaveDays::dispatch(); } } diff --git a/BACKEND/app/Jobs/AddMonthlyLeaveDays.php b/BACKEND/app/Jobs/AddMonthlyLeaveDays.php index 15372f4..e70192b 100644 --- a/BACKEND/app/Jobs/AddMonthlyLeaveDays.php +++ b/BACKEND/app/Jobs/AddMonthlyLeaveDays.php @@ -37,6 +37,11 @@ class AddMonthlyLeaveDays implements ShouldQueue continue; } + // Nếu là nhân viên nghỉ việc, ko cộng phép + if ($user->is_separated) { + continue; + } + $leaveDay = LeaveDays::where('ld_user_id', $user->id) ->where('ld_year', $this->year) ->first(); diff --git a/BACKEND/app/Jobs/CheckUserAttendanceJob.php b/BACKEND/app/Jobs/CheckUserAttendanceJob.php index fe42331..7be15c7 100644 --- a/BACKEND/app/Jobs/CheckUserAttendanceJob.php +++ b/BACKEND/app/Jobs/CheckUserAttendanceJob.php @@ -38,11 +38,14 @@ class CheckUserAttendanceJob implements ShouldQueue { // Lấy tất cả người dùng $users = User::where('permission', 'not like', '%admin%') - ->where('permission', 'not like', '%accountant%')->get(); + ->where('permission', 'not like', '%accountant%')->get(); + foreach ($users as $key => $user) { - // if ($user->id != 4) { - // continue; - // } + // 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); @@ -128,14 +131,19 @@ class CheckUserAttendanceJob implements ShouldQueue $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]) - ->get(); - $hasCheckIndateNow = $dateNow->where('status', 'check in')->isNotEmpty(); - $hasCheckOutdateNow = $dateNow->where('status', 'check out')->isNotEmpty(); + $dateNow = Tracking::whereBetween('time_string', [$startTime, $endTime])->exists(); - // Nếu không có check-in hoặc check-out, và chưa có ticket, tạo ticket mới - if (($hasCheckIndateNow && $hasCheckOutdateNow) && !$hasCheckIn && !$hasCheckOut && !$existingTicket) { - Ticket::create([ + // 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, @@ -159,8 +167,10 @@ class CheckUserAttendanceJob implements ShouldQueue $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, diff --git a/BACKEND/app/Jobs/InitializeLeaveDays.php b/BACKEND/app/Jobs/InitializeLeaveDays.php index 424745c..5f40b47 100644 --- a/BACKEND/app/Jobs/InitializeLeaveDays.php +++ b/BACKEND/app/Jobs/InitializeLeaveDays.php @@ -37,6 +37,11 @@ class InitializeLeaveDays implements ShouldQueue $ld_day_total = Carbon::now()->month; // Khởi tạo phép hiện có bằng tháng hiện tại foreach ($users as $user) { + // Check nhân viên nghỉ việc + if ($user->is_separated) { + continue; + } + // Kiểm tra xem dữ liệu của user này đã tồn tại cho năm hiện tại chưa $existingData = LeaveDays::where('ld_user_id', $user->id) ->where('ld_year', $this->year) diff --git a/BACKEND/database/migrations/2025_08_05_098764_add_separated_users_table.php b/BACKEND/database/migrations/2025_08_05_098764_add_separated_users_table.php new file mode 100644 index 0000000..716823e --- /dev/null +++ b/BACKEND/database/migrations/2025_08_05_098764_add_separated_users_table.php @@ -0,0 +1,29 @@ +boolean('is_separated')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('is_separated'); + }); + } +}; diff --git a/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx b/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx index 1791eed..963e2b0 100644 --- a/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx +++ b/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx @@ -853,7 +853,13 @@ const LeaveManagement = () => { return (