diff --git a/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php b/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php index 4d1bdbd..bc14288 100644 --- a/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php +++ b/BACKEND/Modules/Admin/app/Http/Controllers/TicketController.php @@ -452,142 +452,196 @@ class TicketController extends Controller // Tổng giới hạn ngày nghỉ có phép tối đa trong tháng $maxDaysPerMonth = $this->getMaxLeaveDaysPerMonth(); + $monthIndex = 0; + $onleaveTmp = 0; // Ngày phép trừ tạm (tính phép cho nhiều tháng) - foreach ($requestMonths as $monthKey => $monthData) { + foreach ($requestMonths as $monthData) { if ($monthsInfoWaiting) { - // dd($requestMonths, $monthsInfoWaiting); foreach ($monthsInfoWaiting as $monthInfo) { if ($monthInfo['month'] == $monthData['month'] && $monthInfo['year'] == $monthData['year']) { $remainingDaysInMonthIsUsed += $monthInfo['remaining_days_in_month_remaining']; - // dd($remainingDaysInMonthIsUsed); } } } - // Tổng số ngày nghỉ có phép trong tháng - $usedDaysInMonth = $this->getUsedLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], 'ONLEAVE'); - // Tổng số ngày nghỉ không phép trong tháng - $usedDaysInMonthWithoutPay = $this->getUsedLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], 'LEAVE_WITHOUT_PAY'); + // Số ngày nghỉ trong tháng + $onleaveDaysInMonth = $this->getUsedLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], 'ONLEAVE'); // Có phép + $nopayDaysInMonth = $this->getUsedLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], 'LEAVE_WITHOUT_PAY'); // Không phép + $usedDaysInMonth = $onleaveDaysInMonth + $nopayDaysInMonth; // Tổng - // Tổng số ngày nghỉ trong tháng = tổng ngày nghỉ có phép + tổng ngày nghỉ không phép + tổng ngày yêu cầu - $totalDaysInMonth = $usedDaysInMonth + $usedDaysInMonthWithoutPay + $monthData['days_requested']; + // Tổng ngày nghỉ sẽ dùng trong tháng + $willUsedDaysInMonth = $usedDaysInMonth + $monthData['days_requested']; - // Tổng phép có trong tháng - $totalLeaveDaysInMonth = $this->getTotalLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], $isAccept); + // Ngày phép + $onleaveDaysTotal = $this->getTotalLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], $isAccept); // Tổng phép của user + $usedOnleaveDaysTotal = $this->getTotalLeaveDaysInMonthToMonth($user, $monthData['year'], $monthData['month']); // Phép đã dùng + $remainingOnleaveDays = $onleaveDaysTotal - $usedOnleaveDaysTotal - $onleaveTmp; // Phép còn lại - // Tính tổng số ngày nghỉ có phép đến tháng hiện tại - $totalLeaveDaysInMonthToMonth = $this->getTotalLeaveDaysInMonthToMonth($user, $monthData['year'], $monthData['month']); + // Tổng ngày phép còn lại trong tháng + $remainingOnleaveDaysInMonth = $remainingOnleaveDays - $remainingDaysInMonthIsUsed; - //Ngày phép còn lại trong tháng - $remainingDaysInMonth = $totalLeaveDaysInMonth - $totalLeaveDaysInMonthToMonth; - - $remainingDaysInMonthRemaining = $remainingDaysInMonth - $remainingDaysInMonthIsUsed; - // if ($monthsInfoWaiting) { - // dd( - // "Ngày phép còn lại trong tháng: " . $remainingDaysInMonthRemaining, - // "Ngày phép còn lại: " . $remainingDaysInMonth, - // "Ngày phép đã sử dụng: " . $remainingDaysInMonthIsUsed, - // "Ngày phép yêu cầu: " . $monthData['days_requested'], - // "Tổng ngày nghỉ trong tháng: " . $totalDaysInMonth, - // "Ngày phép đã sử dụng: " . $usedDaysInMonth, - // ); - // } + // Log::debug( + // "📊 Thống kê ngày phép:\n" . + // " - Tháng: {$monthData['month']}\n" . + // " - Tổng ngày nghỉ có phép trong tháng: $onleaveDaysInMonth\n" . + // " - Tổng ngày nghỉ không phép trong tháng: $nopayDaysInMonth\n" . + // " - Tổng ngày nghỉ đã dùng trong tháng: $usedDaysInMonth\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" . + // " - Tổng ngày phép còn lại trong tháng: $remainingOnleaveDaysInMonth\n" + // ); $month_data_status = 'ok'; - $days_will_use = 0; - $days_will_use_without_pay = 0; - // Xử lý các trường hợp thiếu ngày phép - if ($remainingDaysInMonthRemaining <= 0) { //hết phép + $onleave_days_will_use = 0; // Ngày phép sẽ dùng trong tháng + $nopay_days_will_use = 0; // Ngày ko phép sẽ dùng trong tháng + + // Ngày phép còn lại <= 0 (Hết phép) + if ($remainingOnleaveDaysInMonth <= 0) { $hasInsufficientDays = true; $month_data_status = 'no_days_left'; - $monthMessage = "* Hiện tại bạn đã hết phép nghỉ trong tháng {$monthData['month']}/{$monthData['year']}\n - Bạn sẽ nộp: " . $monthData['days_requested'] . " ngày không phép."; + $onleave_days_will_use = 0; + $nopay_days_will_use = $monthData['days_requested']; + + // Message cảnh báo nghỉ ko phép + $monthMessage = $this->buildMonthlyLeaveMessage( + $monthIndex, + $maxDaysPerMonth, + $monthData, + $remainingOnleaveDaysInMonth, + $onleaveDaysInMonth, + $nopayDaysInMonth, + $onleave_days_will_use, + $nopay_days_will_use + ); $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; - $days_will_use = 0; - $days_will_use_without_pay = $monthData['days_requested']; - } else if ($remainingDaysInMonthRemaining < $monthData['days_requested']) { // không đủ ngày phép - if ( - $remainingDaysInMonthRemaining >= $maxDaysPerMonth - ) { + Log::debug("--- Hết phép trong tháng ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); + } + + // Ngày phép còn lại < ngày yêu cầu (Không đủ phép) + else if ($remainingOnleaveDaysInMonth < $monthData['days_requested']) { + // Vượt limit + if ($remainingOnleaveDaysInMonth >= $maxDaysPerMonth) { $hasInsufficientDays = true; $month_data_status = 'exceed_max_days'; - $daysNotEnough = $monthData['days_requested'] - $maxDaysPerMonth; - $monthMessage = "* Theo quy định ngày phép tối đa mỗi tháng là {$maxDaysPerMonth} ngày. \nTháng {$monthData['month']}/{$monthData['year']}: \n - Bạn đã sử dụng {$usedDaysInMonth} ngày phép, còn lại {$remainingDaysInMonthRemaining} ngày phép.\n - Bạn sẽ sử dụng {$maxDaysPerMonth} ngày phép và {$daysNotEnough} ngày không phép."; - $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; - $days_will_use = $maxDaysPerMonth; - $days_will_use_without_pay = $monthData['days_requested'] - $maxDaysPerMonth; - } else { + $onleave_days_will_use = $maxDaysPerMonth - $onleaveDaysInMonth; + $nopay_days_will_use = $monthData['days_requested'] - $maxDaysPerMonth + $onleaveDaysInMonth; + + Log::debug("--- Không đủ phép trong tháng, vượt quá limit ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); + } + // Không vượt limit + else { $hasInsufficientDays = true; $month_data_status = 'insufficient_days'; - $daysNotEnough = $monthData['days_requested'] - $remainingDaysInMonthRemaining; - $monthMessage = "* Tháng {$monthData['month']}/{$monthData['year']}: \n - Số ngày phép còn lại: {$remainingDaysInMonthRemaining}, Số ngày yêu cầu: {$monthData['days_requested']}.\n - Bạn sẽ sử dụng {$remainingDaysInMonthRemaining} ngày phép và {$daysNotEnough} ngày không phép."; - $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; - $remainingDaysInMonthIsUsed = $remainingDaysInMonth; // lấy số ngày phép còn lại của tháng đó + $onleave_days_will_use = $remainingOnleaveDaysInMonth; + $nopay_days_will_use = $monthData['days_requested'] - $remainingOnleaveDaysInMonth; - $days_will_use = $remainingDaysInMonthRemaining; - $days_will_use_without_pay = $daysNotEnough; + Log::debug("--- Không đủ phép trong tháng, ko vượt limit ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); } - } else if ( - $remainingDaysInMonthRemaining >= $monthData['days_requested'] - ) { // Đủ ngày phép ở tháng đó - // 1. Check thêm rule 1 tháng chỉ được nghỉ tối đa $maxDaysPerMonth ngày có phép, ngày vượt sẽ là ngày không phép - if ($totalDaysInMonth > $maxDaysPerMonth) { - $daysWithoutPermission = $totalDaysInMonth - $maxDaysPerMonth; - $daysWillUse = $maxDaysPerMonth - $usedDaysInMonth; // số ngày phép sẽ sử dụng + // Message cảnh báo nghỉ ko phép + $monthMessage = $this->buildMonthlyLeaveMessage( + $monthIndex, + $maxDaysPerMonth, + $monthData, + $remainingOnleaveDaysInMonth, + $onleaveDaysInMonth, + $nopayDaysInMonth, + $onleave_days_will_use, + $nopay_days_will_use + ); + $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; + } + + // Ngày phép còn lại >= ngày yêu cầu (Đủ phép) + else { + // Vượt limit + if ($willUsedDaysInMonth > $maxDaysPerMonth) { $hasInsufficientDays = true; $month_data_status = 'exceed_max_days'; + $onleave_days_will_use = $maxDaysPerMonth - $onleaveDaysInMonth; + $nopay_days_will_use = $willUsedDaysInMonth - $maxDaysPerMonth - $nopayDaysInMonth; - $monthMessage = "* Theo quy định ngày phép tối đa mỗi tháng là {$maxDaysPerMonth} ngày. \nTháng {$monthData['month']}/{$monthData['year']}: \n - Bạn đã sử dụng {$usedDaysInMonth} ngày phép, còn lại {$remainingDaysInMonthRemaining} ngày phép.\n - Bạn sẽ sử dụng " . $daysWillUse . " ngày phép và {$daysWithoutPermission} ngày không phép."; - - $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; - $days_will_use = $daysWillUse; - $days_will_use_without_pay = $daysWithoutPermission; - } else if ($monthData['days_requested'] + $remainingDaysInMonthIsUsed > $maxDaysPerMonth) { + Log::debug("--- Đủ phép, vượt limit ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); + } + // Waiting ticket + else if ($monthData['days_requested'] + $remainingDaysInMonthIsUsed > $maxDaysPerMonth) { if ($remainingDaysInMonthIsUsed > 0) { - - $daysWillUse = $maxDaysPerMonth - $remainingDaysInMonthIsUsed; // số ngày phép sẽ sử dụng - $daysWithoutPermission = $monthData['days_requested'] - $daysWillUse; - - $monthMessage = "* Theo quy định ngày phép tối đa mỗi tháng là {$maxDaysPerMonth} ngày. \nTháng {$monthData['month']}/{$monthData['year']}: \n - Bạn đã sử dụng {$remainingDaysInMonthIsUsed} ngày phép, còn lại {$remainingDaysInMonthRemaining} ngày phép.\n - Bạn sẽ sử dụng " . $daysWillUse . " ngày phép và {$daysWithoutPermission} ngày không phép."; + $onleave_days_will_use = $maxDaysPerMonth - $remainingDaysInMonthIsUsed; + $nopay_days_will_use = $monthData['days_requested'] - $onleave_days_will_use; } else { - $daysWithoutPermission = $monthData['days_requested'] - $maxDaysPerMonth; - $monthMessage = "* Theo quy định ngày phép tối đa mỗi tháng là {$maxDaysPerMonth} ngày. \nTháng {$monthData['month']}/{$monthData['year']}: \n - Số ngày phép còn lại: {$remainingDaysInMonthRemaining}, Số ngày yêu cầu: {$monthData['days_requested']}.\n - Bạn sẽ sử dụng {$maxDaysPerMonth} ngày phép và {$daysWithoutPermission} ngày không phép."; + $onleave_days_will_use = $maxDaysPerMonth; + $nopay_days_will_use = $monthData['days_requested'] - $maxDaysPerMonth; } $hasInsufficientDays = true; $month_data_status = 'exceed_max_days'; - $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; - - $days_will_use = $maxDaysPerMonth; - $days_will_use_without_pay = $daysWithoutPermission; - } else { - $days_will_use = $monthData['days_requested']; - $days_will_use_without_pay = 0; + Log::debug("--- Đủ phép, Waiting ticket ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); } - $remainingDaysInMonthRemaining = $monthData['days_requested']; - } else { - $days_will_use = $monthData['days_requested']; - $days_will_use_without_pay = 0; + // Đủ phép + else { + $onleave_days_will_use = $monthData['days_requested']; + $nopay_days_will_use = 0; + + Log::debug("--- Đủ phép ---", [ + "Phep" => $onleave_days_will_use, + "Khong Phep" => $nopay_days_will_use + ]); + } + + // Message cảnh báo nghỉ ko phép + $monthMessage = $this->buildMonthlyLeaveMessage( + $monthIndex, + $maxDaysPerMonth, + $monthData, + $remainingOnleaveDaysInMonth, + $onleaveDaysInMonth, + $nopayDaysInMonth, + $onleave_days_will_use, + $nopay_days_will_use + ); + $errorMessage .= $errorMessage ? "\n\n" . $monthMessage : $monthMessage; + + $remainingOnleaveDaysInMonth = $monthData['days_requested']; } $month_data = [ 'year' => $monthData['year'], 'month' => $monthData['month'], - 'total_leave_days_in_month' => $totalLeaveDaysInMonth, //tổng số ngày phép - 'total_leave_days_in_month_to_month' => $totalLeaveDaysInMonthToMonth, //tổng ngày nghỉ có phép đã nghỉ - 'remaining_days_in_month' => $remainingDaysInMonth, //số ngày phép còn lại - 'days_used' => $usedDaysInMonth, //tổng số ngày nghỉ có phép đã nghỉ ở tháng hiện tại - 'days_used_without_pay' => $usedDaysInMonthWithoutPay, //tổng số ngày nghỉ không phép đã nghỉ ở tháng hiện tại - 'days_requested' => $monthData['days_requested'], //số ngày yêu cầu nghỉ của tháng - 'remaining_days_in_month_remaining' => $remainingDaysInMonthRemaining, - 'days_will_use' => $days_will_use, //Số ngày phép sẽ sử dụng - 'days_will_use_without_pay' => $days_will_use_without_pay, //Số ngày không phép sẽ sử dụng - 'status' => $month_data_status, // mặc định là ok + 'total_leave_days_in_month' => $onleaveDaysTotal, // tổng số ngày phép + 'total_leave_days_in_month_to_month' => $usedOnleaveDaysTotal, // tổng ngày nghỉ có phép đã nghỉ + 'remaining_days_in_month' => $remainingOnleaveDays, // số ngày phép còn lại + 'days_used' => $onleaveDaysInMonth, // tổng số ngày nghỉ có phép đã nghỉ ở tháng hiện tại + 'days_used_without_pay' => $nopayDaysInMonth, // tổng số ngày nghỉ không phép đã nghỉ ở tháng hiện tại + 'days_requested' => $monthData['days_requested'], // số ngày yêu cầu nghỉ của tháng + 'remaining_days_in_month_remaining' => $remainingOnleaveDaysInMonth, + 'days_will_use' => $onleave_days_will_use, //Số ngày phép sẽ sử dụng + 'days_will_use_without_pay' => $nopay_days_will_use, //Số ngày không phép sẽ sử dụng + 'status' => $month_data_status, // mặc định là ok ]; // Thêm thông tin tháng vào mảng kết quả $monthsInfo[] = $month_data; + $monthIndex++; + $onleaveTmp += $onleave_days_will_use; // Cộng ngày phép dùng tạm trong tháng } + // Trả về kết quả tổng hợp if ($hasInsufficientDays) { return [ @@ -777,7 +831,7 @@ class TicketController extends Controller if (!$ticket || $ticket->status !== "WAITING") { // No ticket found or already confirmed or refused - return redirect()->to(config('app.client_url') . '/tickets-management'); + return redirect()->to(config('app.client_url') . '/404'); } $dataMasterTypeNotes = CategoryController::getListMasterByType("REASON_NOTES"); @@ -785,13 +839,14 @@ class TicketController extends Controller $leaveWithoutPay = null; if ($dataMasterTypeNotes) { - // get nghỉ phép, nghỉ không phép + // 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; } + // Không tìm được ngày phép, ko phép if ($onleave == null || $leaveWithoutPay == null) { - return redirect()->to(config('app.client_url') . '/tickets-management'); + return redirect()->to(config('app.client_url') . '/404'); } if ($action == "confirm") { @@ -1234,6 +1289,51 @@ class TicketController extends Controller return $results; } + private function buildMonthlyLeaveMessage( + $index, + $max, + $monthData, + $totalLeave, + $usedLeave, + $usedNoPay, + $willUseLeave, + $willUseNoPay + ): string { + $message = ""; + + if ($index === 0) { + $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"; + } + + // Hiển thị cộng phép nếu gửi ticket trong tương lai + $monthValue = $monthData['year'] . '-' . sprintf('%02d', $monthData['month']); + $currentMonth = date('Y-m'); + if ($monthValue > $currentMonth && $index !== 0) { + $message .= "* Bạn được cộng 1 phép\n"; + } + + // In mỗi tháng + $message .= "Tháng {$monthData['month']}/{$monthData['year']}:\n"; + if ($usedLeave > 0 || $usedNoPay > 0) { + $message .= " - Bạn đã sử dụng: "; + $usedParts = []; + if ($usedLeave > 0) $usedParts[] = "{$usedLeave} phép"; + if ($usedNoPay > 0) $usedParts[] = "{$usedNoPay} không phép"; + $message .= implode(', ', $usedParts) . "\n"; + } + + if ($willUseLeave > 0 || $willUseNoPay > 0) { + $message .= " - Bạn sẽ sử dụng: "; + $usedParts = []; + if ($willUseLeave > 0) $usedParts[] = "{$willUseLeave} phép"; + if ($willUseNoPay > 0) $usedParts[] = "{$willUseNoPay} không phép"; + $message .= implode(', ', $usedParts); + } + + return $message; + } + /** * Tính tổng số ngày nghỉ từ mảng các khoảng thời gian. * 'ALL' = 1 ngày, 'S'/'C' = 0.5 ngày. diff --git a/BACKEND/resources/views/email/notification_tickets.blade.php b/BACKEND/resources/views/email/notification_tickets.blade.php index 08a39e7..f9c4d13 100644 --- a/BACKEND/resources/views/email/notification_tickets.blade.php +++ b/BACKEND/resources/views/email/notification_tickets.blade.php @@ -1,4 +1,3 @@ - @@ -37,199 +36,167 @@ {{ $data['subject'] }} - - - - - - + +
- + + - - - + + + - - - + + + - -
+ - - - -
- - Logo - -
-
- + + Logo + + + +
+
+ - - - - - - - - - - - + + + - - + + + + + + + + - -
-

- Dear Admin, -

-
-

- Employee {{ $data['name'] }} has sent a request ticket, the specific content is as follows: -

-
-
-

Name: {{ $data['name'] }}

-

Date: {{ $data['date'] }}

-

Type: {{ $data['type'] }}

-

Note: {{ $data['note'] }}

-
-
+

+ Dear Admin, +

+
-

- - Check now +

+

+ Employee {{ $data['name'] }} has sent a request ticket, the specific content is as follows:

+
+
+

Name: {{ $data['name'] }}

+

Date: {{ $data['date'] }}

+

Type: {{ $data['type'] }}

+

Note: {{ $data['note'] }}

+
+

- Or you can quick + You can quick Confirm or Refuse here:

+ display: flex; + justify-content: center; + gap: 10px; + margin-top: 10px; + "> - Confirm + color: #fff; + border-radius: 10px; + background-color: #12b886; + background-image: linear-gradient( + to top left, + rgba(0, 0, 0, 0.2), + rgba(0, 0, 0, 0.2) 30%, + rgba(0, 0, 0, 0) + ); + text-decoration: none; + display: inline-block; + font-weight: 600; + font-size: 16px; + line-height: 150%; + text-align: center; + margin: 0; + padding: 10px 12px; + "> + Confirm - Refuse + color: #fff; + border-radius: 10px; + background-color: #f03e3e; + background-image: linear-gradient( + to top left, + rgba(0, 0, 0, 0.2), + rgba(0, 0, 0, 0.2) 30%, + rgba(0, 0, 0, 0) + ); + text-decoration: none; + display: inline-block; + font-weight: 600; + font-size: 16px; + line-height: 150%; + text-align: center; + margin: 0; + padding: 10px 12px; + "> + Refuse
-
-
- +
+

Note: If you are redirected to a 404 page, it means:

+

1. The ticket has already been approved by another admin.

+

2. The ticket has been deleted.

+
+ + +
+
+ - - - -
-
-

© 2024 APAC Tech.

-
-
-
- +

© 2024 APAC Tech.

+ +
+ + + - + \ No newline at end of file diff --git a/FRONTEND/public/404Image.jpg b/FRONTEND/public/404Image.jpg new file mode 100644 index 0000000..76cc48b Binary files /dev/null and b/FRONTEND/public/404Image.jpg differ diff --git a/FRONTEND/src/pages/NotFound/NotFound.tsx b/FRONTEND/src/pages/NotFound/NotFound.tsx index 18581bc..fadfa51 100755 --- a/FRONTEND/src/pages/NotFound/NotFound.tsx +++ b/FRONTEND/src/pages/NotFound/NotFound.tsx @@ -1,5 +1,42 @@ -export const PageNotFound = () => { - return <>{'Not found!'} +import { + Box, + Button, + Container, + Image, + SimpleGrid, + Text, + Title, +} from '@mantine/core' +import image404 from '../../../public/404Image.jpg' +import { useNavigate } from 'react-router-dom' + +const PageNotFound = () => { + const navigate = useNavigate() + + return ( + + + + Something is not right... + + Page you are trying to open does not exist. You may have mistyped + the address, or the page has been moved to another URL. If you think + this is an error contact support. + + + + + + + + ) } export default PageNotFound