refactor create, handle ticket

This commit is contained in:
dbdbd9 2025-06-17 15:44:44 +07:00
parent 172af363de
commit 1b35f8481b
1 changed files with 305 additions and 653 deletions

View File

@ -2,9 +2,7 @@
namespace Modules\Admin\app\Http\Controllers;
use App\Helper\Cache\CurrentMonthTimekeeping;
use App\Http\Controllers\Controller;
use App\Mail\ContactMail;
use App\Mail\TicketMail;
use App\Models\Notes;
use App\Traits\AnalyzeData;
@ -22,7 +20,6 @@ use Modules\Admin\app\Models\Ticket;
use Modules\Admin\app\Models\Tracking;
use Illuminate\Support\Facades\Log;
use App\Models\LeaveDays;
use Illuminate\Http\JsonResponse;
use App\Models\Admin as UserModel;
class TicketController extends Controller
@ -194,7 +191,7 @@ class TicketController extends Controller
public function createTicket(Request $request)
{
// Define validation rules
// Validate input
$rules = [
'start_date' => 'required|date',
'start_period' => 'required|string',
@ -202,12 +199,9 @@ class TicketController extends Controller
'end_period' => 'required|string',
'type' => 'required|string',
];
// Validate the request
$request->validate($rules);
// return $request;
// Get data from request
// Get input data
$startDate = $request->input('start_date');
$startPeriod = $request->input('start_period');
$endDate = $request->input('end_date');
@ -215,42 +209,19 @@ class TicketController extends Controller
$type = $request->input('type');
$reason = $request->input('reason');
$isAccept = $request->input('is_accept') ?? false;
$user = auth('admins')->user(); // user create ticket
$user = auth('admins')->user();
$start_date = Carbon::create($startDate)->setTimezone(env('TIME_ZONE'));
$end_date = Carbon::create($endDate)->setTimezone(env('TIME_ZONE'));
// Get mảng ngày nghỉ
$dataListPeriod = $this->getAllPeriodNew($start_date, $startPeriod, $end_date, $endPeriod);
if (empty($dataListPeriod)) {
return AbstractController::ResultError('Không thể tính toán khoảng thời gian nghỉ hợp lệ.');
}
// --- Chỉ kiểm tra ngày phép khi loại là ONLEAVE ---
if ($type === 'ONLEAVE' && !$isAccept) {
// 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')->whereIn('type', ['ONLEAVE'])
->get();
$dataListPeriodWaiting = [];
if ($ticketsWaiting->count() > 0) {
foreach ($ticketsWaiting as $ticket) {
$dataListPeriodWaiting = array_merge($dataListPeriodWaiting, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
$ticketsWaitingWFH = Ticket::where('user_id', $user->id)->where('status', 'WAITING')->whereIn('type', ['WFH'])
->get();
$dataListPeriodWaitingWFH = [];
if ($ticketsWaitingWFH->count() > 0) {
foreach ($ticketsWaitingWFH as $ticket) {
$dataListPeriodWaitingWFH = array_merge($dataListPeriodWaitingWFH, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
// 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', 'WFH'])
// Lấy các ticket của user trong thời gian request
$userTickets = Ticket::where('user_id', $user->id)
->whereIn('status', ['WAITING', 'CONFIRMED'])
->where(function ($query) use ($start_date, $end_date) {
$query->where(function ($q) use ($start_date, $end_date) {
// Trường hợp 1: start_date nằm trong khoảng
@ -267,69 +238,49 @@ class TicketController extends Controller
});
})
->get();
$userTicketListPeriod = [];
if ($userTickets->count() > 0) {
foreach ($userTickets as $ticket) {
$userTicketListPeriod = array_merge($userTicketListPeriod, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
$dataListPeriodConfirmed = [];
if ($ticketsConfirmed->count() > 0) {
foreach ($ticketsConfirmed as $ticket) {
$dataListPeriodConfirmed = array_merge($dataListPeriodConfirmed, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
// dd($dataListPeriodConfirmed,$ticketsConfirmed,$start_date->toDateString(),$end_date->toDateString());
// Chuyển đổi mảng đa chiều thành mảng chuỗi để có thể so sánh
// Kiểm tra ticket tạo có trùng thời gian với các ticket cũ
$periodStrings = [];
$waitingPeriodStrings = [];
$waitingPeriodStringsWFH = [];
$confirmedPeriodStrings = [];
$userTicketPeriodStrings = [];
foreach ($dataListPeriod as $period) {
if ($period['period'] == 'ALL') {
$periodStrings[] = $period['date'] . '_S';
$periodStrings[] = $period['date'] . '_C';
} else {
continue;
}
$periodStrings[] = $period['date'] . '_' . $period['period'];
}
}
foreach ($dataListPeriodWaiting as $period) {
foreach ($userTicketListPeriod as $period) {
if ($period['period'] == 'ALL') {
$waitingPeriodStrings[] = $period['date'] . '_S';
$waitingPeriodStrings[] = $period['date'] . '_C';
} else {
$waitingPeriodStrings[] = $period['date'] . '_' . $period['period'];
}
$userTicketPeriodStrings[] = $period['date'] . '_S';
$userTicketPeriodStrings[] = $period['date'] . '_C';
continue;
}
foreach ($dataListPeriodWaitingWFH as $period) {
if ($period['period'] == 'ALL') {
$waitingPeriodStringsWFH[] = $period['date'] . '_S';
$waitingPeriodStringsWFH[] = $period['date'] . '_C';
} else {
$waitingPeriodStringsWFH[] = $period['date'] . '_' . $period['period'];
}
$userTicketPeriodStrings[] = $period['date'] . '_' . $period['period'];
}
foreach ($dataListPeriodConfirmed as $period) {
if ($period['period'] == 'ALL') {
$confirmedPeriodStrings[] = $period['date'] . '_S';
$confirmedPeriodStrings[] = $period['date'] . '_C';
} else {
$confirmedPeriodStrings[] = $period['date'] . '_' . $period['period'];
}
if (count(array_intersect($periodStrings, $userTicketPeriodStrings)) > 0) {
return AbstractController::ResultError('Đã có ticket được tạo 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 đang chờ duyệt
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 khi type = ONLEAVE (nghỉ phép)
if ($type === 'ONLEAVE' && !$isAccept) {
// Lấy 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 = [];
if ($ticketsWaiting->count() > 0) {
foreach ($ticketsWaiting as $ticket) {
$dataListPeriodWaiting = array_merge($dataListPeriodWaiting, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
// Kiểm tra xem có sự trùng lặp giữa request mới và tickets đang chờ duyệt WFH
if (count(array_intersect($periodStrings, $waitingPeriodStringsWFH)) > 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!');
}
// Tạo thông báo về tickets waiting nếu có
@ -365,7 +316,7 @@ class TicketController extends Controller
$balanceCheckResult = $this->checkLeaveBalance($user, $dataListPeriod);
}
// dd($balanceCheckResult);
// Nếu không đủ ngày phép, trả về thông báo và không tạo ticket
// Nếu không đủ ngày phép, trả về thông báo và chưa tạo ticket
if (!$balanceCheckResult['success']) {
$finalMessage = $waitingTicketsMessage;
if (!empty($finalMessage)) {
@ -377,89 +328,13 @@ class TicketController extends Controller
return AbstractController::ResultError("Không thỏa mãn điều kiện ngày phép", $balanceCheckResult);
}
} else if ($type === 'WFH') {
// 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')->whereIn('type', ['WFH', 'ONLEAVE'])
->get();
$dataListPeriodWaiting = [];
if ($ticketsWaiting->count() > 0) {
foreach ($ticketsWaiting as $ticket) {
$dataListPeriodWaiting = array_merge($dataListPeriodWaiting, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
// 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', 'WFH'])
->where(function ($query) use ($start_date, $end_date) {
$query->where(function ($q) use ($start_date, $end_date) {
// Trường hợp 1: start_date nằm trong khoảng
$q->whereBetween(DB::raw('DATE(start_date)'), [$start_date->toDateString(), $end_date->toDateString()]);
})
->orWhere(function ($q) use ($start_date, $end_date) {
// Trường hợp 2: end_date nằm trong khoảng
$q->whereBetween(DB::raw('DATE(end_date)'), [$start_date->toDateString(), $end_date->toDateString()]);
})
->orWhere(function ($q) use ($start_date, $end_date) {
// Trường hợp 3: Khoảng thời gian được chọn nằm trong khoảng của ticket
$q->where(DB::raw('DATE(start_date)'), '<=', $start_date->toDateString())
->where(DB::raw('DATE(end_date)'), '>=', $end_date->toDateString());
});
})
->get();
$dataListPeriodConfirmed = [];
if ($ticketsConfirmed->count() > 0) {
foreach ($ticketsConfirmed as $ticket) {
$dataListPeriodConfirmed = array_merge($dataListPeriodConfirmed, $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period));
}
}
// dd($dataListPeriodConfirmed,$ticketsConfirmed,$start_date->toDateString(),$end_date->toDateString());
// Chuyển đổi mảng đa chiều thành mảng chuỗi để có thể so sánh
$periodStrings = [];
$waitingPeriodStrings = [];
$confirmedPeriodStrings = [];
foreach ($dataListPeriod as $period) {
if ($period['period'] == 'ALL') {
$periodStrings[] = $period['date'] . '_S';
$periodStrings[] = $period['date'] . '_C';
} else {
$periodStrings[] = $period['date'] . '_' . $period['period'];
}
}
foreach ($dataListPeriodConfirmed as $period) {
if ($period['period'] == 'ALL') {
$confirmedPeriodStrings[] = $period['date'] . '_S';
$confirmedPeriodStrings[] = $period['date'] . '_C';
} else {
$confirmedPeriodStrings[] = $period['date'] . '_' . $period['period'];
}
}
foreach ($dataListPeriodWaiting as $period) {
if ($period['period'] == 'ALL') {
$waitingPeriodStrings[] = $period['date'] . '_S';
$waitingPeriodStrings[] = $period['date'] . '_C';
} else {
$waitingPeriodStrings[] = $period['date'] . '_' . $period['period'];
}
}
// Kiểm tra xem có sự trùng lặp giữa request mới và tickets đang chờ duyệt
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!');
}
}
// --- Kết thúc kiểm tra ---
// Nếu đủ ngày phép (hoặc loại ticket không phải ONLEAVE), tiếp tục tạo ticket
// Tạo ticket mới khi:
// - Ticket được tạo không trùng ngày
// - User có đủ phép
// - User không đủ phép nhưng vẫn đồng ý tạo
$ticket = Ticket::create([
'start_date' => $start_date->toDateString(),
'start_period' => $startPeriod,
@ -495,7 +370,7 @@ class TicketController extends Controller
);
// Thêm kiểm tra null trước khi gửi mail
if ($dataMasterStartPeriod && $dataMasterEndPeriod && $dataMasterType) {
Mail::to($value->email)->send(new TicketMail($data));
Mail::to($value->email)->queue(new TicketMail($data));
} else {
Log::error("Missing category data for ticket ID: {$ticket->id}. Mail not sent.");
}
@ -837,11 +712,9 @@ class TicketController extends Controller
public function handleTicket(Request $request)
{
$rules = [
'ticket_id' => 'required',
'action' => 'required',
// 'admin_note' => 'required'
];
// Validate the request
@ -856,21 +729,6 @@ class TicketController extends Controller
if (!$ticket || $ticket->status !== "WAITING") {
return response()->json(['message' => "Ticket not found", 'status' => false]);
}
// Confirm
// Update updated_by and admin_note in tickets table
// Refuse
// Update updated_by and admin_note in tickets table
// Send notification email to users
$startDate = $ticket->start_date; //Start day
$startPeriod = $ticket->start_period; //The session begins
$endDate = $ticket->end_date; //End date
$endPeriod = $ticket->end_period; //Session ends
$type = $ticket->type;
$dataMasterStartPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $startPeriod);
$dataMasterEndPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $endPeriod);
$dataMasterType = CategoryController::getListMasterByCodeAndType("REASON", $type);
$dataMasterTypeNotes = CategoryController::getListMasterByType("REASON_NOTES");
$onleave = null;
@ -882,16 +740,91 @@ class TicketController extends Controller
$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 ($onleave == null || $leaveWithoutPay == null) {
return response()->json(['message' => "Data reason notes not found", 'status' => false]);
}
if ($action == "confirm") {
$this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay);
return response()->json(['message' => "confirmed", 'status' => true]);
}
if ($action == "refuse") {
$this->handleRefuseTicket($ticket, $admin, $admin_note);
return response()->json(['message' => "refused", 'status' => true]);
}
return response()->json(['message' => "failed", 'status' => false]);
}
public function handleTicketEmail(Request $request)
{
$rules = [
'ticket_id' => 'required',
'action' => 'required',
'admin_email' => 'required' // Need Admin Email
];
// Validate the request
$request->validate($rules);
$ticket_id = $request->input('ticket_id');
$admin_note = $request->input('admin_note');
$admin_email = $request->input('admin_email');
$action = $request->input('action'); // 'confirm' or 'refuse'
$admin = Admin::where('email', $admin_email)->first(); // Get admin by email not token
$ticket = Ticket::find($ticket_id);
if (!$ticket || $ticket->status !== "WAITING") {
// No ticket found or already confirmed or refused
return redirect()->to(config('app.client_url') . '/tickets-management');
}
$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;
}
if ($onleave == null || $leaveWithoutPay == null) {
return redirect()->to(config('app.client_url') . '/tickets-management');
}
if ($action == "confirm") {
$this->handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay);
return redirect()->to(config('app.client_url') . '/tickets-management');
}
if ($action == "refuse") {
$this->handleRefuseTicket($ticket, $admin, $admin_note);
return redirect()->to(config('app.client_url') . '/tickets-management');
}
// Failed
return redirect()->to(config('app.client_url') . '/tickets-management');
}
private function handleConfirmTicket($ticket, $admin, $admin_note, $onleave, $leaveWithoutPay)
{
$startDate = $ticket->start_date; //Start day
$startPeriod = $ticket->start_period; //The session begins
$endDate = $ticket->end_date; //End date
$endPeriod = $ticket->end_period; //Session ends
$type = $ticket->type;
$dataMasterStartPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $startPeriod);
$dataMasterEndPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $endPeriod);
$dataMasterType = CategoryController::getListMasterByCodeAndType("REASON", $type);
$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 ($ticket->type == "ONLEAVE") {
$dataListPeriod = $this->getAllPeriodNew($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period);
$balanceCheckResult = $this->checkLeaveBalance($user, $dataListPeriod, null, true);
@ -1090,62 +1023,10 @@ class TicketController extends Controller
"subject" => "[Ticket response] Ticket From " . $admin->name
);
Mail::to($user->email)->send(new TicketMail($data));
return response()->json(['message' => "confirmed", 'status' => true]);
}
if ($action == "refuse") {
$ticket['updated_by'] = $admin->name;
$ticket['admin_note'] = $admin_note;
$ticket['status'] = 'REFUSED';
$ticket->save();
$data = array(
"email_template" => "email.notification_tickets_user",
"user_name" => $user->name,
"email" => $user->email,
"name" => $admin->name, //name admin duyệt
"date" => $dataMasterStartPeriod->c_name . " (" . $formattedStartDate . ") - " . $dataMasterEndPeriod->c_name . " (" . $formattedEndDate . ")",
"type" => $dataMasterType->c_name,
"note" => $ticket->reason,
"admin_note" => $admin_note,
"link" => "/tickets", //link đến page admin
"status" => "refused",
"subject" => "[Ticket response] Ticket From " . $admin->name
);
Mail::to($user->email)->send(new TicketMail($data));
return response()->json(['message' => "refused", 'status' => true]);
}
return response()->json(['message' => "failed", 'status' => false]);
}
// Handle Logic same as HandleTicket, but need email to identify admin and redirect to Management page
public function handleTicketEmail(Request $request)
private function handleRefuseTicket($ticket, $admin, $admin_note)
{
$rules = [
'ticket_id' => 'required',
'action' => 'required',
'admin_email' => 'required' // Need Admin Email
];
// Validate the request
$request->validate($rules);
$ticket_id = $request->input('ticket_id');
$admin_note = $request->input('admin_note');
$admin_email = $request->input('admin_email');
$action = $request->input('action'); // 'confirm' or 'refuse'
$admin = Admin::where('email', $admin_email)->first(); // Get admin by email not token
$ticket = Ticket::find($ticket_id);
if (!$ticket || $ticket->status !== "WAITING") {
// No ticket found or already confirmed or refused
return redirect()->to(config('app.client_url') . '/tickets-management');
}
// Send notification email to users
$startDate = $ticket->start_date; //Start day
$startPeriod = $ticket->start_period; //The session begins
$endDate = $ticket->end_date; //End date
@ -1156,233 +1037,11 @@ 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 ($onleave == null || $leaveWithoutPay == null) {
// Data reason notes not found
return redirect()->to(config('app.client_url') . '/tickets-management');
}
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'));
//Default: ALL
$start = $date->copy()->setTime(7, 30, 0);
$end = $date->copy()->setTime(17, 0, 0);
if ($type == 'S') {
$end = $date->copy()->setTime(11, 30, 0);
} else if ($type == 'C') {
$start = $date->copy()->setTime(11, 30, 0);
}
Tracking::insert([
[
'name' => $user->name,
'user_id' => $user->id,
'status' => 'check in',
'time_string' => $start->format('Y-m-d H:i:s'),
'created_at' => $start->setTimezone('UTC')
],
[
'name' => $user->name,
'user_id' => $user->id,
'status' => 'check out',
'time_string' => $end->format('Y-m-d H:i:s'),
'created_at' => $end->setTimezone('UTC')
]
]);
//WFH - end tracking
}
}
$ticket['updated_by'] = $admin->name;
$ticket['admin_note'] = $admin_note;
$ticket['status'] = 'CONFIRMED';
$ticket->save();
$this->createOrUpdateRecordForCurrentMonth($month, $year);
// Send notification email to users
$data = array(
"email_template" => "email.notification_tickets_user",
"user_name" => $user->name,
"email" => $user->email,
"name" => $admin->name, //name admin duyệt
"date" => $dataMasterStartPeriod->c_name . " (" . $formattedStartDate . ") - " . $dataMasterEndPeriod->c_name . " (" . $formattedEndDate . ")",
"type" => $dataMasterType->c_name,
"note" => $ticket->reason,
"admin_note" => $admin_note,
"link" => "/tickets", //link đến page admin
"status" => "confirmed",
"subject" => "[Ticket response] Ticket From " . $admin->name
);
Mail::to($user->email)->send(new TicketMail($data));
// Confirm Success
return redirect()->to(config('app.client_url') . '/tickets-management');
}
if ($action == "refuse") {
$ticket['updated_by'] = $admin->name;
$ticket['admin_note'] = $admin_note;
$ticket['status'] = 'REFUSED';
@ -1402,13 +1061,6 @@ class TicketController extends Controller
"subject" => "[Ticket response] Ticket From " . $admin->name
);
Mail::to($user->email)->send(new TicketMail($data));
// Refuse Success
return redirect()->to(config('app.client_url') . '/tickets-management');
}
// Failed
return redirect()->to(config('app.client_url') . '/tickets-management');
}
private function getAllPeriodNew($startDate, $startPeriod, $endDate, $endPeriod)