Bổ sung xóa ngày phép
This commit is contained in:
parent
ca766fc293
commit
7dc31bf75b
|
|
@ -14,7 +14,7 @@ class CategoryController extends Controller
|
|||
* @param Request $request The HTTP request object.
|
||||
* @return \Illuminate\Http\JsonResponse The JSON response containing the list of master data.
|
||||
*/
|
||||
public function getListMaster(Request $request)
|
||||
public static function getListMaster(Request $request)
|
||||
{
|
||||
$data = Category::where('c_type', '=', $request->type)->where('c_active', '=', 1)->select('id', 'c_code', 'c_name', 'c_value', 'c_type')->get();
|
||||
return AbstractController::ResultSuccess($data);
|
||||
|
|
@ -24,4 +24,9 @@ class CategoryController extends Controller
|
|||
$data = Category::where('c_type', '=', $type)->where('c_code', '=', $code)->where('c_active', '=', 1)->select('id', 'c_code', 'c_name', 'c_value', 'c_type')->first();
|
||||
return $data;
|
||||
}
|
||||
public static function getListMasterByType($type)
|
||||
{
|
||||
$data = Category::where('c_type', '=', $type)->where('c_active', '=', 1)->select('id', 'c_code', 'c_name', 'c_value', 'c_type')->get();
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class LeaveManagementController extends Controller
|
|||
})
|
||||
->leftJoin("categories as reason", function ($join) {
|
||||
$join->on('n_reason', '=', 'reason.c_code');
|
||||
$join->on('reason.c_type', DB::raw("CONCAT('REASON')"));
|
||||
$join->on('reason.c_type', DB::raw("CONCAT('REASON_NOTES')"));
|
||||
})
|
||||
->select(
|
||||
DB::raw('notes.n_user_id as n_user_id'),
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ class TicketController extends Controller
|
|||
->paginate($request->get('per_page'))->toArray(),
|
||||
['status' => true]
|
||||
);
|
||||
|
||||
return response()->json($responseData);
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +227,7 @@ class TicketController extends Controller
|
|||
if (empty($dataListPeriod)) {
|
||||
return AbstractController::ResultError('Không thể tính toán khoảng thời gian nghỉ hợp lệ.');
|
||||
}
|
||||
// Lây thông tin tickets đang ở trạng thái WAITING
|
||||
// Lấy thông tin tickets nghỉ phép đang ở trạng thái WAITING
|
||||
$ticketsWaiting = Ticket::where('user_id', $user->id)->where('status', 'WAITING')->where('type', 'ONLEAVE')
|
||||
->get();
|
||||
$dataListPeriodWaiting = [];
|
||||
|
|
@ -238,9 +237,9 @@ class TicketController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
// Lấy thông tin tickets đang ở trạng thái CONFIRMED
|
||||
// Lấy thông tin tickets nghỉ phép đang ở trạng thái CONFIRMED
|
||||
$ticketsConfirmed = Ticket::where('user_id', $user->id)->where('status', 'CONFIRMED')
|
||||
->whereIn('type', ['ONLEAVE', 'LEAVE_WITHOUT_PAY'])
|
||||
->whereIn('type', ['ONLEAVE'])
|
||||
->where(DB::raw('DATE(start_date)'), '>=', $start_date->toDateString())
|
||||
->where(DB::raw('DATE(end_date)'), '<=', $end_date->toDateString())
|
||||
->get();
|
||||
|
|
@ -288,7 +287,7 @@ class TicketController extends Controller
|
|||
if (count(array_intersect($periodStrings, $waitingPeriodStrings)) > 0) {
|
||||
return AbstractController::ResultError('Đã có ticket đang chờ duyệt trong thời gian này, không thể tạo ticket mới!');
|
||||
}
|
||||
|
||||
|
||||
// Kiểm tra xem có sự trùng lặp giữa request mới và tickets đã được duyệt
|
||||
if (count(array_intersect($periodStrings, $confirmedPeriodStrings)) > 0) {
|
||||
return AbstractController::ResultError('Đã có ticket được duyệt trong thời gian này, không thể tạo ticket mới!');
|
||||
|
|
@ -298,7 +297,6 @@ class TicketController extends Controller
|
|||
$waitingTicketsMessage = '';
|
||||
if (!empty($dataListPeriodWaiting)) {
|
||||
// Kiểm tra số dư ngày phép cho tickets waiting
|
||||
$totalWaitingDays = $this->calculateTotalLeaveDays($dataListPeriodWaiting);
|
||||
$waitingTicketsMessage = "Bạn đang có " . $ticketsWaiting->count() . " yêu cầu nghỉ phép chưa được duyệt";
|
||||
|
||||
// Nếu muốn thêm chi tiết từng ticket waiting
|
||||
|
|
@ -466,8 +464,12 @@ class TicketController extends Controller
|
|||
$usedDaysInMonthWithoutPay = $this->getUsedLeaveDaysInMonth($user, $monthData['year'], $monthData['month'], 'LEAVE_WITHOUT_PAY');
|
||||
|
||||
// Tính tổng giới hạn ngày nghỉ có phép tối đa trong tháng
|
||||
|
||||
$maxDaysPerMonth = $this->getMaxLeaveDaysPerMonth();
|
||||
|
||||
$days_will_use = 0;
|
||||
$days_will_use_without_pay = 0;
|
||||
|
||||
// Tính tổng số ngày nghỉ trong tháng
|
||||
$totalDaysInMonth = $usedDaysInMonth + $usedDaysInMonthWithoutPay + $monthData['days_requested'];
|
||||
|
||||
|
|
@ -487,14 +489,19 @@ class TicketController extends Controller
|
|||
$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.";
|
||||
$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
|
||||
$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 đó
|
||||
|
||||
$days_will_use = $remainingDaysInMonthRemaining;
|
||||
$days_will_use_without_pay = $daysNotEnough;
|
||||
} 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
|
||||
|
|
@ -504,20 +511,31 @@ class TicketController extends Controller
|
|||
$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.";
|
||||
$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;
|
||||
}
|
||||
$remainingDaysInMonthRemaining = $monthData['days_requested'];
|
||||
} else {
|
||||
$days_will_use = $monthData['days_requested'];
|
||||
$days_will_use_without_pay = 0;
|
||||
}
|
||||
|
||||
$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
|
||||
'remaining_days_in_month' => $remainingDaysInMonth, //ngày phép còn lại
|
||||
'days_used' => $usedDaysInMonth, //tổng số ngày nghỉ có phép ở tháng hiện tại
|
||||
'days_used_without_pay' => $usedDaysInMonthWithoutPay, //tổng số ngày nghỉ không phép ở tháng hiện tại
|
||||
'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' => 'ok', // mặc định là ok
|
||||
];
|
||||
|
||||
|
|
@ -660,18 +678,12 @@ class TicketController extends Controller
|
|||
if (!$ticket || $ticket->status !== "WAITING") {
|
||||
return response()->json(['message' => "Ticket not found", 'status' => false]);
|
||||
}
|
||||
$results = $this->getAllPeriod($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period);
|
||||
|
||||
// $admin->id != user_id of ticket ---> continue
|
||||
// Confirm
|
||||
// Add records to the notes table like function Timekeeping.addNoteForUser() based on the $results array
|
||||
|
||||
// Update updated_by and admin_note in tickets table
|
||||
// Refuse
|
||||
// Update updated_by and admin_note in tickets table
|
||||
|
||||
// Send notification email to users
|
||||
|
||||
// Refuse
|
||||
// Update updated_by and admin_note in tickets table
|
||||
$startDate = $ticket->start_date; //Start day
|
||||
$startPeriod = $ticket->start_period; //The session begins
|
||||
$endDate = $ticket->end_date; //End date
|
||||
|
|
@ -682,25 +694,171 @@ class TicketController extends Controller
|
|||
$dataMasterEndPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $endPeriod);
|
||||
$dataMasterType = CategoryController::getListMasterByCodeAndType("REASON", $type);
|
||||
|
||||
$dataMasterTypeNotes = CategoryController::getListMasterByType("REASON_NOTES");
|
||||
$onleave = null;
|
||||
$leaveWithoutPay = 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;
|
||||
}
|
||||
|
||||
$formattedStartDate = Carbon::createFromFormat('Y-m-d', $startDate)->format('d/m/Y');
|
||||
$formattedEndDate = Carbon::createFromFormat('Y-m-d', $endDate)->format('d/m/Y');
|
||||
|
||||
$user = Admin::find($ticket->user_id);
|
||||
|
||||
if ($action == "confirm") {
|
||||
foreach ($results as $result) {
|
||||
list($year, $month, $day) = explode('-', $result['date']);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => $result['period'],
|
||||
'n_reason' => $ticket->type,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
if ($onleave == null || $leaveWithoutPay == null) {
|
||||
return response()->json(['message' => "Data reason notes not found", 'status' => false]);
|
||||
}
|
||||
|
||||
if ($ticket->type == "WFH") {
|
||||
if ($action == "confirm") {
|
||||
if ($ticket->type == "ONLEAVE") {
|
||||
$dataListPeriod = $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period);
|
||||
$balanceCheckResult = $this->checkLeaveBalance($user, $dataListPeriod);
|
||||
// dd($balanceCheckResult,$dataListPeriod);
|
||||
if ($balanceCheckResult['success'] == false) {
|
||||
if ($balanceCheckResult['months_info']) {
|
||||
foreach ($balanceCheckResult['months_info'] as $monthInfo) {
|
||||
// Lọc các ngày thuộc đúng tháng/năm này
|
||||
$daysInMonth = array_filter($dataListPeriod, function ($item) use ($monthInfo) {
|
||||
$date = \Carbon\Carbon::parse($item['date']);
|
||||
return $date->year == $monthInfo['year'] && $date->month == $monthInfo['month'];
|
||||
});
|
||||
|
||||
$daysWillUse = $monthInfo['days_will_use'] ?? 0;
|
||||
$daysWillUseWithoutPay = $monthInfo['days_will_use_without_pay'] ?? 0;
|
||||
// dd($daysWillUse,$daysWillUseWithoutPay,$daysInMonth);
|
||||
foreach ($daysInMonth as $item) {
|
||||
list($year, $month, $day) = explode('-', $item['date']);
|
||||
$period = $item['period'];
|
||||
$value = ($period === 'ALL') ? 1.0 : 0.5;
|
||||
|
||||
if ($period === 'ALL' && $daysWillUse == 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' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => 'S',
|
||||
'n_reason' => $onleave,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => 'C',
|
||||
'n_reason' => $leaveWithoutPay,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
$daysWillUse = 0;
|
||||
$daysWillUseWithoutPay -= 0.5;
|
||||
} elseif ($daysWillUse > 0) {
|
||||
// Dùng ngày phép trước
|
||||
$use = min($daysWillUse, $value);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => $period,
|
||||
'n_reason' => $onleave,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
$daysWillUse -= $use;
|
||||
} elseif ($daysWillUseWithoutPay > 0) {
|
||||
// Hết phép, chuyển sang không phép
|
||||
$use = min($daysWillUseWithoutPay, $value);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => $period,
|
||||
'n_reason' => $leaveWithoutPay,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
$daysWillUseWithoutPay -= $use;
|
||||
}
|
||||
// Nếu cả hai đều hết thì thôi, không tạo nữa
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Đủ phép
|
||||
foreach ($dataListPeriod as $result) {
|
||||
list($year, $month, $day) = explode('-', $result['date']);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => $result['period'],
|
||||
'n_reason' => $onleave, // có phép
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$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 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})");
|
||||
|
||||
// Cập nhật cột ld_day_total với số ngày đã làm tròn
|
||||
if ($roundedExcessDays > 0) {
|
||||
$leaveDaysInfo->ld_day_total += $roundedExcessDays;
|
||||
$leaveDaysInfo->save();
|
||||
|
||||
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) {
|
||||
list($year, $month, $day) = explode('-', $result['date']);
|
||||
Notes::create([
|
||||
'n_user_id' => $ticket->user_id,
|
||||
'n_day' => $day,
|
||||
'n_month' => $month,
|
||||
'n_year' => $year,
|
||||
'n_time_type' => $result['period'],
|
||||
'n_reason' => $ticket->type,
|
||||
'n_note' => $ticket->reason
|
||||
]);
|
||||
|
||||
|
||||
//WFH - start tracking
|
||||
$type = $result['period'];
|
||||
$date = Carbon::create($year, $month, $day)->setTimezone(env('TIME_ZONE'));
|
||||
|
||||
|
|
@ -730,6 +888,7 @@ class TicketController extends Controller
|
|||
'created_at' => $end->setTimezone('UTC')
|
||||
]
|
||||
]);
|
||||
//WFH - end tracking
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -814,6 +973,13 @@ class TicketController extends Controller
|
|||
// Parse the date string from c_code to a Carbon instance for proper comparison
|
||||
return Carbon::createFromFormat('d-m-Y', $item->c_code);
|
||||
});
|
||||
// get day work special
|
||||
$day_work_special = Category::where('c_type', 'DAY_WORK_SPECIAL')
|
||||
->get()
|
||||
->sortByDesc(function ($item) {
|
||||
return Carbon::createFromFormat('d-m-Y', $item->c_code);
|
||||
});
|
||||
|
||||
|
||||
// Get the most recent schedule date (first item after sorting)
|
||||
$latest_schedule = $saturday_work_schedules->first();
|
||||
|
|
@ -825,26 +991,33 @@ class TicketController extends Controller
|
|||
return []; // Return empty or throw exception
|
||||
}
|
||||
|
||||
$special_dates = [];
|
||||
foreach ($day_work_special as $item) {
|
||||
$special_dates[] = Carbon::createFromFormat('d-m-Y', $item->c_code)->toDateString();
|
||||
}
|
||||
foreach ($period as $date) {
|
||||
// Check if the current day is a Saturday
|
||||
if ($date->dayOfWeek === Carbon::SATURDAY) {
|
||||
// Check phải ngày thứ 7 đặc biệt thì tính như ngày bình thường
|
||||
if (in_array($date->toDateString(), $special_dates)) {
|
||||
} else {
|
||||
// Check if the current day is a Saturday
|
||||
if ($date->dayOfWeek === Carbon::SATURDAY) {
|
||||
if ($latest_schedule) {
|
||||
$weeksDifference = $latestScheduleDate->startOfDay()->diffInWeeks($date->copy()->startOfDay());
|
||||
$isSaturdayWorkDay = ($weeksDifference % 2 === 0);
|
||||
|
||||
if ($latest_schedule) {
|
||||
$weeksDifference = $latestScheduleDate->startOfDay()->diffInWeeks($date->copy()->startOfDay());
|
||||
$isSaturdayWorkDay = ($weeksDifference % 2 === 0);
|
||||
// echo $date->toDateString() . ' - ' . ($isSaturdayWorkDay ? 'Làm việc' : 'Nghỉ') . "<br>";
|
||||
}
|
||||
|
||||
// echo $date->toDateString() . ' - ' . ($isSaturdayWorkDay ? 'Làm việc' : 'Nghỉ') . "<br>";
|
||||
if ($isSaturdayWorkDay) {
|
||||
$results[] = ['date' => $date->toDateString(), 'period' => "S"];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isSaturdayWorkDay) {
|
||||
$results[] = ['date' => $date->toDateString(), 'period' => "S"];
|
||||
// Skip Sundays entirely
|
||||
else if ($date->dayOfWeek === Carbon::SUNDAY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
// Skip Sundays entirely
|
||||
else if ($date->dayOfWeek === Carbon::SUNDAY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($date->isSameDay($startDate)) {
|
||||
|
|
|
|||
|
|
@ -152,8 +152,6 @@ class TimekeepingController extends Controller
|
|||
return response()->json(['status' => true, 'message' => 'Add successfully']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function updateCacheMonth(Request $request)
|
||||
{
|
||||
$month = $request->month;
|
||||
|
|
@ -180,6 +178,71 @@ class TimekeepingController extends Controller
|
|||
|
||||
$note = Notes::find($id);
|
||||
if ($note) {
|
||||
$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]);
|
||||
|
|
@ -206,10 +269,10 @@ class TimekeepingController extends Controller
|
|||
}
|
||||
|
||||
// Lọc chỉ lấy user có permission bao gồm staff
|
||||
$staffData = array_filter($responseData['data'], function($user) {
|
||||
$staffData = array_filter($responseData['data'], function ($user) {
|
||||
return isset($user['user']['permission']) && strpos($user['user']['permission'], 'staff') !== false;
|
||||
});
|
||||
|
||||
|
||||
$currentDate = date('d_His');
|
||||
return Excel::download(
|
||||
new TimekeepingExport(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@ class Notes extends Model
|
|||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'n_user_id', 'n_day', 'n_month', 'n_year', 'n_time_type', 'n_reason', 'n_note',
|
||||
'n_user_id',
|
||||
'n_day',
|
||||
'n_month',
|
||||
'n_year',
|
||||
'n_time_type',
|
||||
'n_reason',
|
||||
'n_note',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -25,7 +31,7 @@ class Notes extends Model
|
|||
{
|
||||
return self::leftJoin("categories as reason", function ($join) {
|
||||
$join->on('n_reason', '=', 'reason.c_code');
|
||||
$join->on('reason.c_type', DB::raw("CONCAT('REASON')"));
|
||||
$join->on('reason.c_type', DB::raw("CONCAT('REASON_NOTES')"));
|
||||
})
|
||||
->leftJoin("categories as timeTypes", function ($join) {
|
||||
$join->on('n_time_type', '=', 'timeTypes.c_code');
|
||||
|
|
@ -47,4 +53,18 @@ class Notes extends Model
|
|||
)
|
||||
->get();
|
||||
}
|
||||
|
||||
public static function getNotesByMonthAndYearAndUserId($month, $year, $userId, $idNote)
|
||||
{
|
||||
return self::where('n_reason', 'ONLEAVE')->where('n_month', $month)->where('n_year', $year)
|
||||
->where('n_user_id', $userId)
|
||||
->where('id', '!=', $idNote)->get();
|
||||
}
|
||||
|
||||
public static function getNotesByMonthAndYearAndUserIdAndReason($month, $year, $userId, $reason)
|
||||
{
|
||||
return self::where('n_reason', $reason)->where('n_month', $month)->where('n_year', $year)
|
||||
->where('n_user_id', $userId)
|
||||
->orderBy('n_day', 'asc')->orderBy('n_time_type', 'desc')->get();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UpdateLeaveCategories extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// Xóa item với type REASON và code LEAVE_WITHOUT_PAY
|
||||
DB::table('categories')
|
||||
->where('c_type', 'REASON')
|
||||
->where('c_code', 'LEAVE_WITHOUT_PAY')
|
||||
->delete();
|
||||
|
||||
// Cập nhật tên "Nghỉ phép năm" thành "Nghỉ phép"
|
||||
DB::table('categories')
|
||||
->where('c_name', 'Nghỉ phép năm')
|
||||
->update(['c_name' => 'Nghỉ phép']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// Khôi phục item đã xóa
|
||||
DB::table('categories')->insert([
|
||||
'c_code' => 'LEAVE_WITHOUT_PAY',
|
||||
'c_name' => 'Không phép',
|
||||
'c_type' => 'REASON',
|
||||
'c_value' => "",
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
// Khôi phục tên cũ
|
||||
DB::table('categories')
|
||||
->where('c_name', 'Nghỉ phép')
|
||||
->update(['c_name' => 'Nghỉ phép năm']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AddLimitLeaveMonthCategory extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::table('categories')->insert([
|
||||
'c_code' => 'LIMIT',
|
||||
'c_name' => 'Giới hạn số ngày nghỉ có phép/tháng',
|
||||
'c_type' => 'LIMIT_LEAVE_MONTH',
|
||||
'c_value' => '3',
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
DB::table('categories')
|
||||
->where('c_code', 'LIMIT')
|
||||
->where('c_type', 'LIMIT_LEAVE_MONTH')
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AddSaturdayWorkScheduleCategory extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::table('categories')->insert([
|
||||
'c_code' => '10-05-2025',
|
||||
'c_name' => 'Ngày bắt đầu làm việc thứ 7 trong năm',
|
||||
'c_type' => 'SATURDAY_WORK_SCHEDULE',
|
||||
'c_value' => '2025',
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
DB::table('categories')
|
||||
->where('c_code', '10-05-2025')
|
||||
->where('c_type', 'SATURDAY_WORK_SCHEDULE')
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AddLeaveCategories extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::table('categories')->insert([
|
||||
[
|
||||
'c_code' => 'LEAVE_WITHOUT_PAY',
|
||||
'c_name' => 'Không phép',
|
||||
'c_type' => 'REASON_NOTES',
|
||||
'c_value' => "",
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'c_code' => 'WFH',
|
||||
'c_name' => 'Work From Home',
|
||||
'c_type' => 'REASON_NOTES',
|
||||
'c_value' => "",
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'c_code' => 'ONLEAVE',
|
||||
'c_name' => 'Nghỉ phép',
|
||||
'c_type' => 'REASON_NOTES',
|
||||
'c_value' => "",
|
||||
'c_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
DB::table('categories')
|
||||
->whereIn('c_code', ['LEAVE_WITHOUT_PAY', 'WFH', 'ONLEAVE'])
|
||||
->where('c_type', 'REASON_NOTES')
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -114,6 +114,10 @@ const LeaveManagement = () => {
|
|||
const [dataTimeType, setDataTimeType] = useState<DataTimeType[]>([])
|
||||
const [dataReason, setDataReason] = useState<DataReason[]>([])
|
||||
|
||||
const now = new Date()
|
||||
const currentMonth = now.getMonth() + 1 // getMonth() trả về 0-11
|
||||
const currentYear = now.getFullYear()
|
||||
|
||||
const getListMasterByType = async (type: string) => {
|
||||
try {
|
||||
const params = {
|
||||
|
|
@ -361,8 +365,8 @@ const LeaveManagement = () => {
|
|||
})
|
||||
}
|
||||
}}
|
||||
label={'Total Leave'}
|
||||
placeholder="Input total leave days"
|
||||
label={'Phép năm'}
|
||||
placeholder="Nhập số ngày phép năm"
|
||||
/>
|
||||
<TextInput
|
||||
mb={'md'}
|
||||
|
|
@ -388,8 +392,8 @@ const LeaveManagement = () => {
|
|||
})
|
||||
}
|
||||
}}
|
||||
label={'Day additional leave'}
|
||||
placeholder="Input additional leave days"
|
||||
label={'Phép năm cũ'}
|
||||
placeholder="Nhập số ngày phép năm cũ"
|
||||
/>
|
||||
<TextInput
|
||||
mb={'md'}
|
||||
|
|
@ -415,8 +419,8 @@ const LeaveManagement = () => {
|
|||
})
|
||||
}
|
||||
}}
|
||||
label={'Day special leave'}
|
||||
placeholder="Input special leave days"
|
||||
label={'Phép đặc biệt'}
|
||||
placeholder="Nhập số ngày phép đặc biệt"
|
||||
/>
|
||||
<Textarea
|
||||
mb={'md'}
|
||||
|
|
@ -525,12 +529,20 @@ const LeaveManagement = () => {
|
|||
<Table.Th ta={'center'} style={{ width: '40px' }}></Table.Th>
|
||||
<Table.Th>User</Table.Th>
|
||||
{monthInYear.map((d) => {
|
||||
const isCurrentMonth =
|
||||
Number(date.year) === currentYear && d.value === currentMonth
|
||||
return (
|
||||
<Menu width={200} shadow="md" key={d.value}>
|
||||
<Menu.Target>
|
||||
<Table.Th
|
||||
ta={'center'}
|
||||
style={{ cursor: 'pointer', width: '40px' }}
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
width: '40px',
|
||||
backgroundColor: isCurrentMonth ? '#ffe066' : undefined,
|
||||
color: isCurrentMonth ? '#000' : undefined,
|
||||
fontWeight: isCurrentMonth ? 'bold' : undefined,
|
||||
}}
|
||||
>
|
||||
<span>{d.name}</span>
|
||||
</Table.Th>
|
||||
|
|
@ -590,6 +602,8 @@ const LeaveManagement = () => {
|
|||
</Table.Td>
|
||||
|
||||
{monthInYear.map((d, i) => {
|
||||
const isCurrentMonth =
|
||||
Number(date.year) === currentYear && d.value === currentMonth
|
||||
let leaveDataByMonth = getDetailLeaveDay(
|
||||
user.monthlyLeaveDays,
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue