diff --git a/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php b/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php index 2aca157..a8b1863 100644 --- a/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php +++ b/BACKEND/Modules/Admin/app/Http/Controllers/LeaveManagementController.php @@ -51,7 +51,7 @@ class LeaveManagementController extends Controller ) // ->where('notes.n_user_id', "1") ->where('notes.n_year', $year) - ->whereIn('notes.n_reason', ['ONLEAVE', 'LEAVE_WITHOUT_PAY']) + ->whereIn('notes.n_reason', ['ONLEAVE', 'LEAVE_WITHOUT_PAY', 'TEMPORARY_ONLEAVE']) // ->groupBy("notes.n_user_id") ->orderBy('notes.n_month') ->orderBy('notes.n_day') @@ -155,7 +155,7 @@ class LeaveManagementController extends Controller } // Lọc chỉ lấy user có permission bao gồm staff - $staffData = $leaveDays->filter(function($user) { + $staffData = $leaveDays->filter(function ($user) { return isset($user['user']['permission']) && strpos($user['user']['permission'], 'staff') !== false; }); diff --git a/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php b/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php index cac2408..158cf84 100644 --- a/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php +++ b/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php @@ -402,6 +402,10 @@ class TicketController extends Controller $ticket->updated_by = $admin->name; $ticket->admin_note = $request->admin_note; + + // Clear Timekeeping cache + $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); $ticket->save(); return AbstractController::ResultSuccess($ticket, "Ticket updated successfully!"); @@ -717,6 +721,7 @@ class TicketController extends Controller ->first(); $totalAllocated = 0; + // Xử lý gửi ticket sau tháng hiện tại if ($leaveDaysInfo && $user->is_permanent) { $currentMonth = Carbon::now()->month; $totalAllocated = $leaveDaysInfo->ld_day_total; @@ -837,19 +842,21 @@ class TicketController extends Controller $dataMasterTypeNotes = CategoryController::getListMasterByType("REASON_NOTES"); $onleave = null; $leaveWithoutPay = null; + $temporaryOnleave = null; if ($dataMasterTypeNotes) { // get nghỉ phép, nghỉ không phép $onleave = optional($dataMasterTypeNotes->where('c_code', 'ONLEAVE')->first())->c_code; $leaveWithoutPay = optional($dataMasterTypeNotes->where('c_code', 'LEAVE_WITHOUT_PAY')->first())->c_code; + $temporaryOnleave = optional($dataMasterTypeNotes->where('c_code', 'TEMPORARY_ONLEAVE')->first())->c_code; } - if ($onleave == null || $leaveWithoutPay == null) { + if ($onleave == null || $leaveWithoutPay == null || $temporaryOnleave == null) { return response()->json(['message' => "Data reason notes not found", 'status' => false]); } if ($action == "confirm") { - $this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay); + $this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay, $temporaryOnleave); return response()->json(['message' => "confirmed", 'status' => true]); } @@ -887,20 +894,22 @@ class TicketController extends Controller $dataMasterTypeNotes = CategoryController::getListMasterByType("REASON_NOTES"); $onleave = null; $leaveWithoutPay = null; + $temporaryOnleave = null; if ($dataMasterTypeNotes) { // Get nghỉ phép, nghỉ không phép $onleave = optional($dataMasterTypeNotes->where('c_code', 'ONLEAVE')->first())->c_code; $leaveWithoutPay = optional($dataMasterTypeNotes->where('c_code', 'LEAVE_WITHOUT_PAY')->first())->c_code; + $temporaryOnleave = optional($dataMasterTypeNotes->where('c_code', 'TEMPORARY_ONLEAVE')->first())->c_code; } // Không tìm được ngày phép, ko phép - if ($onleave == null || $leaveWithoutPay == null) { + if ($onleave == null || $leaveWithoutPay == null || $temporaryOnleave == null) { return redirect()->to(config('app.client_url') . '/404'); } if ($action == "confirm") { - $this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay); + $this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay, $temporaryOnleave); return redirect()->to(config('app.client_url') . '/tickets-management'); } @@ -913,7 +922,7 @@ class TicketController extends Controller return redirect()->to(config('app.client_url') . '/tickets-management'); } - private function handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay) + private function handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay, $temporaryOnleave) { $startDate = $ticket->start_date; //Start day $startPeriod = $ticket->start_period; //The session begins @@ -934,6 +943,7 @@ class TicketController extends Controller $dataListPeriod = $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period); $balanceCheckResult = $this->checkLeaveBalance($user, $dataListPeriod, null, true); // dd($balanceCheckResult, $dataListPeriod); + $currentMonth = Carbon::now()->month; if ($balanceCheckResult['success'] == false) { if ($balanceCheckResult['months_info']) { foreach ($balanceCheckResult['months_info'] as $monthInfo) { @@ -960,7 +970,7 @@ class TicketController extends Controller 'n_month' => $month, 'n_year' => $year, 'n_time_type' => 'S', - 'n_reason' => $onleave, + 'n_reason' => $month > $currentMonth ? $temporaryOnleave : $onleave, 'n_note' => $ticket->reason, 'ticket_id' => $ticket->id ]); @@ -970,7 +980,7 @@ class TicketController extends Controller 'n_month' => $month, 'n_year' => $year, 'n_time_type' => 'C', - 'n_reason' => $leaveWithoutPay, + 'n_reason' => $month > $currentMonth ? $temporaryOnleave : $leaveWithoutPay, 'n_note' => $ticket->reason, 'ticket_id' => $ticket->id ]); @@ -985,7 +995,7 @@ class TicketController extends Controller 'n_month' => $month, 'n_year' => $year, 'n_time_type' => $period, - 'n_reason' => $onleave, + 'n_reason' => $month > $currentMonth ? $temporaryOnleave : $onleave, 'n_note' => $ticket->reason, 'ticket_id' => $ticket->id ]); @@ -999,7 +1009,7 @@ class TicketController extends Controller 'n_month' => $month, 'n_year' => $year, 'n_time_type' => $period, - 'n_reason' => $leaveWithoutPay, + 'n_reason' => $month > $currentMonth ? $temporaryOnleave : $leaveWithoutPay, 'n_note' => $ticket->reason, 'ticket_id' => $ticket->id ]); @@ -1019,49 +1029,49 @@ class TicketController extends Controller 'n_month' => $month, 'n_year' => $year, 'n_time_type' => $result['period'], - 'n_reason' => $onleave, // có phép + 'n_reason' => $month > $currentMonth ? $temporaryOnleave : $onleave, 'n_note' => $ticket->reason, 'ticket_id' => $ticket->id ]); } } - $yearCheck = Carbon::parse($endDate)->year; - // Check giá trị ld_day_total của bảng leave_days thuộc user id đó với giá trị của list item note trong bảng notes của user id đó - $leaveDaysInfo = LeaveDays::where('ld_user_id', $ticket->user_id) - ->where('ld_year', $yearCheck) - ->first(); - if ($leaveDaysInfo) { - // Tính tổng số ngày nghỉ có phép đã sử dụng trong năm - $totalUsedLeaveDays = Notes::join('categories', function ($join) { - $join->on('notes.n_time_type', '=', 'categories.c_code') - ->where('categories.c_type', 'TIME_TYPE'); - }) - ->where('n_user_id', $ticket->user_id) - ->where('n_year', $yearCheck) - ->where('n_reason', 'ONLEAVE') - ->sum('categories.c_value'); + // $yearCheck = Carbon::parse($endDate)->year; + // // Check giá trị ld_day_total của bảng leave_days thuộc user id đó với giá trị của list item note trong bảng notes của user id đó + // $leaveDaysInfo = LeaveDays::where('ld_user_id', $ticket->user_id) + // ->where('ld_year', $yearCheck) + // ->first(); + // if ($leaveDaysInfo) { + // // Tính tổng số ngày nghỉ có phép đã sử dụng trong năm + // $totalUsedLeaveDays = Notes::join('categories', function ($join) { + // $join->on('notes.n_time_type', '=', 'categories.c_code') + // ->where('categories.c_type', 'TIME_TYPE'); + // }) + // ->where('n_user_id', $ticket->user_id) + // ->where('n_year', $yearCheck) + // ->where('n_reason', 'ONLEAVE') + // ->sum('categories.c_value'); - // Tính tổng số ngày phép được cấp - $totalAllocatedDays = $leaveDaysInfo->ld_day_total + - $leaveDaysInfo->ld_additional_day + - $leaveDaysInfo->ld_special_leave_day; + // // Tính tổng số ngày phép được cấp + // $totalAllocatedDays = $leaveDaysInfo->ld_day_total + + // $leaveDaysInfo->ld_additional_day + + // $leaveDaysInfo->ld_special_leave_day; - // Tính số ngày vượt quá và làm tròn lên - $excessDays = $totalUsedLeaveDays - $totalAllocatedDays; - $roundedExcessDays = ceil($excessDays); // Làm tròn lên số nguyên gần nhất + // // Tính số ngày vượt quá và làm tròn lên + // $excessDays = $totalUsedLeaveDays - $totalAllocatedDays; + // $roundedExcessDays = ceil($excessDays); // Làm tròn lên số nguyên gần nhất - // Kiểm tra nếu số ngày đã sử dụng vượt quá số ngày được cấp - if ($roundedExcessDays > 0) { - Log::warning("User ID: {$ticket->user_id} has used more leave days ({$totalUsedLeaveDays}) than allocated ({$totalAllocatedDays})"); + // // Kiểm tra nếu số ngày đã sử dụng vượt quá số ngày được cấp + // if ($roundedExcessDays > 0) { + // Log::warning("User ID: {$ticket->user_id} has used more leave days ({$totalUsedLeaveDays}) than allocated ({$totalAllocatedDays})"); - // Cập nhật cột ld_day_total với số ngày đã làm tròn - $leaveDaysInfo->ld_day_total += $roundedExcessDays; - $leaveDaysInfo->save(); + // // Cập nhật cột ld_day_total với số ngày đã làm tròn + // $leaveDaysInfo->ld_day_total += $roundedExcessDays; + // $leaveDaysInfo->save(); - Log::info("Updated leave days for User ID: {$ticket->user_id}. Added {$roundedExcessDays} days (rounded from {$excessDays})"); - } - } + // Log::info("Updated leave days for User ID: {$ticket->user_id}. Added {$roundedExcessDays} days (rounded from {$excessDays})"); + // } + // } } else if ($ticket->type == "WFH") { $dataListPeriod = $this->getAllPeriod($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period); foreach ($dataListPeriod as $result) { @@ -1117,7 +1127,8 @@ class TicketController extends Controller $ticket['status'] = 'CONFIRMED'; $ticket->save(); - $this->createOrUpdateRecordForCurrentMonth($month, $year); + $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); // Send notification email to users $data = array( @@ -1358,8 +1369,9 @@ class TicketController extends Controller $message = ""; if ($index === 0) { + $showMonth = $monthData['month'] > Carbon::now()->month ? $monthData['month'] : Carbon::now()->month; $message .= "* Quy định: mỗi tháng được nghỉ tối đa {$max} ngày phép\n"; - $message .= "- Bạn đang có: {$totalLeave} ngày phép\n\n"; + $message .= "- Bạn có: {$totalLeave} ngày phép (Tính tới tháng {$showMonth})\n\n"; } // Hiển thị cộng phép nếu gửi ticket trong tương lai @@ -1380,7 +1392,7 @@ class TicketController extends Controller } if ($willUseLeave > 0 || $willUseNoPay > 0) { - $message .= " - Bạn sẽ sử dụng: "; + $message .= " - Dự kiến bạn sẽ sử dụng: "; $usedParts = []; if ($willUseLeave > 0) $usedParts[] = "{$willUseLeave} phép"; if ($willUseNoPay > 0) $usedParts[] = "{$willUseNoPay} không phép"; @@ -1478,7 +1490,6 @@ class TicketController extends Controller for ($i = 1; $i <= $month; $i++) { // Giả lập cộng phép $onleaveDaysTotal++; - $ld_note = $ld_note . "Cộng phép tháng " . $i . ".\n"; // $tmpOnleaveDaysTotal = $onleaveDaysTotal; $onleaveDaysInMonth = 0; diff --git a/BACKEND/Modules/Admin/app/Http/Controllers/TimekeepingController.php b/BACKEND/Modules/Admin/app/Http/Controllers/TimekeepingController.php index 1b33037..fe2e1f7 100644 --- a/BACKEND/Modules/Admin/app/Http/Controllers/TimekeepingController.php +++ b/BACKEND/Modules/Admin/app/Http/Controllers/TimekeepingController.php @@ -171,12 +171,8 @@ class TimekeepingController extends Controller // Validate the request $request->validate($rules); - $id = $request->input('id'); - $month = $request->month; - $year = $request->year; - $note = Notes::find($id); if (!$note) { return response()->json(['message' => 'Note not found', 'status' => false]); @@ -193,77 +189,11 @@ class TimekeepingController extends Controller $ticket->save(); Notes::where('ticket_id', $ticket->id)->delete(); - $this->createOrUpdateRecordForCurrentMonth($month, $year); + + // Clear Timekeeping cache + $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); return response()->json(['message' => 'Delete success', 'status' => true]); - - // $n_month = $note->n_month; - // $n_year = $note->n_year; - - // if ($note->n_reason == "ONLEAVE") { - // // Get note reason ONLEAVE by $n_month, $n_year not include $note->id & include $note->n_user_id - // // $onleave = Notes::getNotesByMonthAndYearAndUserId($n_month, $n_year, $note->n_user_id, $note->id); - - // // Get note reason LEAVE_WITHOUT_PAY by $n_month, $n_year & include $note->n_user_id - // $leaveWithoutPay = Notes::getNotesByMonthAndYearAndUserIdAndReason($n_month, $n_year, $note->n_user_id, 'LEAVE_WITHOUT_PAY'); - - // if (count($leaveWithoutPay) > 0) { - // $deletedValue = ($note->n_time_type === 'ALL') ? 1.0 : 0.5; - // $needUpdate = $deletedValue; - // // dd($needUpdate, $leaveWithoutPay); - // foreach ($leaveWithoutPay as $lwNote) { - // if ($needUpdate <= 0) break; - - // if ($lwNote->n_time_type === 'ALL') { - // if ($needUpdate == 1.0) { - // // Chuyển cả note ALL thành phép - // $lwNote->update(['n_reason' => 'ONLEAVE']); - // $needUpdate = 0; - // break; - // } else { // $needUpdate == 0.5 - // // Tách ALL thành 2 note S và C, chuyển S thành phép, C giữ không phép - // Notes::create([ - // 'n_user_id' => $lwNote->n_user_id, - // 'n_day' => $lwNote->n_day, - // 'n_month' => $lwNote->n_month, - // 'n_year' => $lwNote->n_year, - // 'n_time_type' => 'S', - // 'n_reason' => 'ONLEAVE', - // 'n_note' => $lwNote->n_note - // ]); - // Notes::create([ - // 'n_user_id' => $lwNote->n_user_id, - // 'n_day' => $lwNote->n_day, - // 'n_month' => $lwNote->n_month, - // 'n_year' => $lwNote->n_year, - // 'n_time_type' => 'C', - // 'n_reason' => 'LEAVE_WITHOUT_PAY', - // 'n_note' => $lwNote->n_note - // ]); - // $lwNote->delete(); - // $needUpdate = 0; - // break; - // } - // } else { - // // Nếu $lwNote->n_time_type == 'S' hoặc 'C' => 0.5 - // if ($needUpdate == 1.0) { - // // Chuyển cả note ALL thành phép - // $lwNote->update(['n_reason' => 'ONLEAVE']); - // $needUpdate -= 0.5; - // } else { // $needUpdate == 0.5 - // // S hoặc C, chỉ cần chuyển đúng 0.5 ngày - // $lwNote->update(['n_reason' => 'ONLEAVE']); - // $needUpdate = 0; - // break; - // } - // } - // } - // } else { - // // Khi note phép và k tồn tại nghỉ không phép => phép + dồn cho tháng sau - // } - // } - // $note->delete(); - // $this->createOrUpdateRecordForCurrentMonth($month, $year); - // return response()->json(['message' => 'Delete success', 'status' => true]); } public function export(Request $request) diff --git a/BACKEND/app/Console/Commands/AddMonthlyLeaveDaysCommand.php b/BACKEND/app/Console/Commands/AddMonthlyLeaveDaysCommand.php index f691d15..267c767 100644 --- a/BACKEND/app/Console/Commands/AddMonthlyLeaveDaysCommand.php +++ b/BACKEND/app/Console/Commands/AddMonthlyLeaveDaysCommand.php @@ -21,4 +21,4 @@ class AddMonthlyLeaveDaysCommand extends Command $year = $this->argument('year'); AddMonthlyLeaveDays::dispatch($month, $year); } -} \ No newline at end of file +} diff --git a/BACKEND/app/Console/Commands/UpdateTemporaryLeaveDaysCommand.php b/BACKEND/app/Console/Commands/UpdateTemporaryLeaveDaysCommand.php new file mode 100644 index 0000000..9cb2db8 --- /dev/null +++ b/BACKEND/app/Console/Commands/UpdateTemporaryLeaveDaysCommand.php @@ -0,0 +1,24 @@ +argument('month'); + $year = $this->argument('year'); + UpdateTemporaryLeaveDays::dispatch($month, $year); + } +} diff --git a/BACKEND/app/Console/Kernel.php b/BACKEND/app/Console/Kernel.php index f063914..3e9cf06 100755 --- a/BACKEND/app/Console/Kernel.php +++ b/BACKEND/app/Console/Kernel.php @@ -34,8 +34,9 @@ class Kernel extends ConsoleKernel // Chạy buổi chiều lúc 17:30 $schedule->command('attendance:check C')->dailyAt('17:30'); - // Chạy vào 00:01 ngày đầu tiên của mỗi tháng + // Chạy vào ngày đầu tiên của mỗi tháng $schedule->command('add:monthly-leavedays')->monthlyOn(1, '00:01'); + $schedule->command('update:temporary-leavedays')->monthlyOn(1, '00:05'); } /** diff --git a/BACKEND/app/Jobs/AddMonthlyLeaveDays.php b/BACKEND/app/Jobs/AddMonthlyLeaveDays.php index ee3bd2b..15372f4 100644 --- a/BACKEND/app/Jobs/AddMonthlyLeaveDays.php +++ b/BACKEND/app/Jobs/AddMonthlyLeaveDays.php @@ -65,16 +65,6 @@ class AddMonthlyLeaveDays implements ShouldQueue $permanentMonth = Carbon::parse($user->permanent_date)->month; if ($this->month > $leaveDay->ld_day_total - ($permanentDefault - $permanentMonth)) { $leaveDay->ld_day_total += self::ONLEAVE_PER_MONTH; - - // Xử lý ghi chú - $newNote = "Cộng phép tháng " . $leaveDay->ld_day_total . ".\n"; - if (!empty($leaveDay->ld_note)) { - // Nếu đã có ghi chú, thêm ghi chú mới vào và xuống dòng - $leaveDay->ld_note = $leaveDay->ld_note . "\n" . $newNote; - } else { - // Nếu chưa có ghi chú, gán ghi chú mới - $leaveDay->ld_note = $newNote; - } $leaveDay->save(); } } @@ -84,16 +74,6 @@ class AddMonthlyLeaveDays implements ShouldQueue if ($leaveDay->ld_day_total < $this->month) { // Cộng mỗi tháng 1 ngày phép cho nhân viên $leaveDay->ld_day_total += self::ONLEAVE_PER_MONTH; - - // Xử lý ghi chú - $newNote = "Cộng phép tháng " . $leaveDay->ld_day_total . ".\n"; - if (!empty($leaveDay->ld_note)) { - // Nếu đã có ghi chú, thêm ghi chú mới vào và xuống dòng - $leaveDay->ld_note = $leaveDay->ld_note . "\n" . $newNote; - } else { - // Nếu chưa có ghi chú, gán ghi chú mới - $leaveDay->ld_note = $newNote; - } $leaveDay->save(); } } diff --git a/BACKEND/app/Jobs/UpdateTemporaryLeaveDays.php b/BACKEND/app/Jobs/UpdateTemporaryLeaveDays.php new file mode 100644 index 0000000..f578d28 --- /dev/null +++ b/BACKEND/app/Jobs/UpdateTemporaryLeaveDays.php @@ -0,0 +1,220 @@ +month = $month ?? Carbon::now()->month; + $this->year = $year ?? Carbon::now()->year; + } + + /** + * Execute the job. + */ + public function handle() + { + $users = User::get(); + + foreach ($users as $user) { + $leaveDay = LeaveDays::where('ld_user_id', $user->id) + ->where('ld_year', $this->year) + ->first(); + + $notes = Notes::where('n_reason', 'TEMPORARY_ONLEAVE') + ->where('n_user_id', $user->id) + ->where('n_year', $this->year) + ->where('n_month', $this->month) + ->whereExists(function ($query) use ($user) { + $query->select(DB::raw(1)) + ->from('tickets') + ->where('tickets.user_id', $user->id) + ->where('tickets.status', 'CONFIRMED') + ->where('tickets.type', 'ONLEAVE'); + }) + ->get(); + + $maxDaysPerMonth = $this->getMaxLeaveDaysPerMonth(); + + // Tổng ngày nghỉ sẽ dùng trong tháng + $willUsedDaysInMonth = 0; + foreach ($notes as $note) { + $willUsedDaysInMonth += $note->n_time_type == 'ALL' ? 1.0 : 0.5; + } + + // Tổng phép đang có + $onleaveDaysTotal = $leaveDay->ld_day_total + $leaveDay->ld_additional_day + $leaveDay->ld_special_leave_day; + // Phép đã sử dụng tới tháng hiện tại + $usedOnleaveDaysTotal = Notes::join('categories', function ($join) { + $join->on('notes.n_time_type', '=', 'categories.c_code') + ->where('categories.c_type', 'TIME_TYPE'); + }) + ->where('n_user_id', $user->id) + ->where('n_year', $this->year) + ->where('n_month', "<=", $this->month) + ->where('n_reason', 'ONLEAVE') + ->sum('categories.c_value'); + // Phép còn lại + $remainingOnleaveDays = $onleaveDaysTotal - $usedOnleaveDaysTotal; + + // Log::debug("User {$user->name}\n"); + // Log::debug( + // "📊 Thống kê ngày phép:\n" . + // " - Tháng: {$this->month}\n" . + // " - Tổng ngày nghỉ sẽ dùng trong tháng: $willUsedDaysInMonth\n" . + // " - Tổng ngày phép: $onleaveDaysTotal\n" . + // " - Tổng ngày phép đã nghỉ: $usedOnleaveDaysTotal\n" . + // " - Tổng ngày phép còn lại: $remainingOnleaveDays\n" + // ); + + $onleave_days_will_use = 0; // Ngày phép sẽ dùng + $nopay_days_will_use = 0; // Ngày ko phép sẽ dùng + + // Ngày phép còn lại <= 0 (Hết phép) + if ($remainingOnleaveDays <= 0) { + $onleave_days_will_use = 0; + $nopay_days_will_use = $willUsedDaysInMonth; + + Log::debug("--- Hết phép trong tháng ---"); + } + + // Ngày phép còn lại < ngày yêu cầu (Không đủ phép) + else if ($remainingOnleaveDays < $willUsedDaysInMonth) { + // Vượt limit + if ($willUsedDaysInMonth > $maxDaysPerMonth) { + // Phép còn lại > limit + if ($remainingOnleaveDays > $maxDaysPerMonth) { + $onleave_days_will_use = $maxDaysPerMonth; + $nopay_days_will_use = $willUsedDaysInMonth - $maxDaysPerMonth; + } + // Phép còn lại < limit + else { + $onleave_days_will_use = $remainingOnleaveDays; + $nopay_days_will_use = $willUsedDaysInMonth - $remainingOnleaveDays; + } + + Log::debug("--- Không đủ phép trong tháng, vượt quá limit ---",); + } + // Không vượt limit + else { + $onleave_days_will_use = $remainingOnleaveDays; + $nopay_days_will_use = $willUsedDaysInMonth - $remainingOnleaveDays; + + Log::debug("--- Không đủ phép trong tháng, ko vượt limit ---"); + } + } + + // Ngày phép còn lại >= ngày yêu cầu (Đủ phép) + else { + // Vượt limit + if ($willUsedDaysInMonth > $maxDaysPerMonth) { + $onleave_days_will_use = $maxDaysPerMonth; + $nopay_days_will_use = $willUsedDaysInMonth - $maxDaysPerMonth; + + Log::debug("--- Đủ phép, vượt limit ---"); + } + // Không vượt limit + else { + $onleave_days_will_use = $willUsedDaysInMonth; + $nopay_days_will_use = 0; + + Log::debug("--- Đủ phép ---"); + } + } + + Log::debug("", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); + + // Có nghỉ không phép + if ($nopay_days_will_use > 0) { + foreach ($notes as $note) { + $value = ($note->n_time_type === 'ALL') ? 1.0 : 0.5; + + if ($note->n_time_type === 'ALL' && $onleave_days_will_use == 0.5) { + // Chỉ còn 0.5 phép, chia thành 2 bản ghi: 1 phép, 1 không phép + // Ưu tiên phép cho buổi sáng (S), không phép cho buổi chiều (C) + + Notes::create([ + 'n_user_id' => $user->id, + 'n_day' => $note->n_day, + 'n_month' => $note->n_month, + 'n_year' => $note->n_year, + 'n_time_type' => 'S', + 'n_reason' => 'ONLEAVE', + 'n_note' => $note->n_note, + 'ticket_id' => $note->ticket_id + ]); + Notes::create([ + 'n_user_id' => $user->id, + 'n_day' => $note->n_day, + 'n_month' => $note->n_month, + 'n_year' => $note->n_year, + 'n_time_type' => 'C', + 'n_reason' => 'LEAVE_WITHOUT_PAY', + 'n_note' => $note->n_note, + 'ticket_id' => $note->ticket_id + ]); + + $note->delete(); + + $onleave_days_will_use = 0; + $nopay_days_will_use -= 0.5; + } elseif ($onleave_days_will_use > 0) { + // Dùng ngày phép trước + $use = min($onleave_days_will_use, $value); + $note->update([ + 'n_reason' => "ONLEAVE" + ]); + $onleave_days_will_use -= $use; + } elseif ($nopay_days_will_use > 0) { + // Hết phép, chuyển sang không phép + $use = min($nopay_days_will_use, $value); + $note->update([ + 'n_reason' => "LEAVE_WITHOUT_PAY" + ]); + $nopay_days_will_use -= $use; + } + } + } + // Đủ phép + else { + foreach ($notes as $note) { + $note->update([ + 'n_reason' => "ONLEAVE" + ]); + } + } + } + } + + private function getMaxLeaveDaysPerMonth(): int + { + $limitLeaveMonth = Category::where('c_type', 'LIMIT_LEAVE_MONTH')->where('c_code', "LIMIT")->first(); + if ($limitLeaveMonth) { + $maxDaysPerMonth = (int)$limitLeaveMonth->c_value; + } else { + $maxDaysPerMonth = 3; // default nếu k có setting + } + return $maxDaysPerMonth; + } +} diff --git a/BACKEND/database/migrations/2025_06_27_025714_add_onleave_future_categories_table.php b/BACKEND/database/migrations/2025_06_27_025714_add_onleave_future_categories_table.php new file mode 100644 index 0000000..e1580eb --- /dev/null +++ b/BACKEND/database/migrations/2025_06_27_025714_add_onleave_future_categories_table.php @@ -0,0 +1,35 @@ +insert([ + [ + 'c_code' => 'TEMPORARY_ONLEAVE', + 'c_name' => 'Nghỉ tạm trong tương lai', + 'c_type' => 'REASON_NOTES', + 'c_value' => "", + 'c_active' => 1, + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + DB::table('categories')->where('c_code', 'TEMPORARY_ONLEAVE')->delete(); + } +}; diff --git a/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx b/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx index 63aabe1..9f58a4f 100644 --- a/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx +++ b/FRONTEND/src/pages/LeaveManagement/LeaveManagement.tsx @@ -21,7 +21,7 @@ import { } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { notifications } from '@mantine/notifications' -import { IconEdit, IconFileExcel } from '@tabler/icons-react' +import { IconEdit, IconFileExcel, IconHelpCircle } from '@tabler/icons-react' import classes from './LeaveManagement.module.css' import { @@ -294,14 +294,17 @@ const LeaveManagement = () => { return monthInYear.map((d, i) => { let totalOnLeaveMonth = 0 let totalLeaveWithoutPayMonth = 0 + let totalTempMonth = 0 monthlyLeaveDays .filter((item) => item.month === d.value) .map((item) => { if (item.reason_code === 'ONLEAVE') { totalOnLeaveMonth += Number(item.leave_days) - } else { + } else if (item.reason_code === 'LEAVE_WITHOUT_PAY') { totalLeaveWithoutPayMonth += Number(item.leave_days) + } else { + totalTempMonth += Number(item.leave_days) } }) @@ -665,9 +668,11 @@ const LeaveManagement = () => { let onleaveDaysInMonth: MonthlyLeaveDays[] = [] let nopayDaysInMonth: MonthlyLeaveDays[] = [] + let tempDaysInMonth: MonthlyLeaveDays[] = [] let totalOnLeaveMonth = 0 let totalLeaveWithoutPayMonth = 0 + let totalTempMonth = 0 let usedAdditionalDay = 0 user.monthlyLeaveDays @@ -676,9 +681,12 @@ const LeaveManagement = () => { if (item.reason_code === 'ONLEAVE') { totalOnLeaveMonth += Number(item.leave_days) onleaveDaysInMonth.push(item) - } else { + } else if (item.reason_code === 'LEAVE_WITHOUT_PAY') { totalLeaveWithoutPayMonth += Number(item.leave_days) nopayDaysInMonth.push(item) + } else { + totalTempMonth += Number(item.leave_days) + tempDaysInMonth.push(item) } }) @@ -703,6 +711,7 @@ const LeaveManagement = () => { return (
{total === 0 ? '' : total}
+