add confirm/refuse in ticket mail
This commit is contained in:
parent
8474bd97a1
commit
7217a83e33
|
|
@ -364,8 +364,10 @@ class TicketController extends Controller
|
|||
$admins = Admin::where('permission', 'like', '%admin%')->get();
|
||||
foreach ($admins as $key => $value) {
|
||||
$data = array(
|
||||
"ticket_id" => $ticket->id,
|
||||
"email_template" => "email.notification_tickets",
|
||||
"email" => $user->email,
|
||||
"admin_email" => $value->email,
|
||||
"name" => $user->name,
|
||||
"date" => optional($dataMasterStartPeriod)->c_name . " (" . $formattedStartDate . ") - " . optional($dataMasterEndPeriod)->c_name . " (" . $formattedEndDate . ")",
|
||||
"type" => optional($dataMasterType)->c_name,
|
||||
|
|
@ -984,6 +986,297 @@ class TicketController extends Controller
|
|||
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)
|
||||
{
|
||||
|
||||
$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
|
||||
$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;
|
||||
$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';
|
||||
$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));
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Đảm bảo $startDate và $endDate là đối tượng Carbon
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Route::middleware('api')
|
|||
Route::post('login', [AdminController::class, 'login']);
|
||||
Route::post('reset-password', [AdminController::class, 'resetPassword']);
|
||||
Route::get('forgot-password', [AdminController::class, 'forgotPassword']);
|
||||
Route::get('/email-handle-ticket', [TicketController::class, 'handleTicketEmail'])->name('email.ticket.handle');
|
||||
});
|
||||
|
||||
// NOTE after login
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ return [
|
|||
|
||||
'asset_url' => env('ASSET_URL'),
|
||||
|
||||
'client_url' => env('ADMIN_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ class RenameLdDayToLdDayTotalInLeaveDaysTable extends Migration
|
|||
public function up()
|
||||
{
|
||||
Schema::table('leave_days', function (Blueprint $table) {
|
||||
$table->renameColumn('ld_day_total', 'ld_day_total');
|
||||
$table->renameColumn('ld_day', 'ld_day_total');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leave_days', function (Blueprint $table) {
|
||||
$table->renameColumn('ld_day_total', 'ld_day_total');
|
||||
$table->renameColumn('ld_day_total', 'ld_day');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,29 +98,109 @@
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<p style="margin:0 0 16px;padding:5px;margin: 5px;text-align: center;">
|
||||
<a href='{{ config('app.url') . $data['link'] }}'
|
||||
style="
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
background-color: rgba(68,115,196);
|
||||
background-image: linear-gradient(to top left,rgba(0,0,0,.2),rgba(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;
|
||||
">
|
||||
Check now</a>
|
||||
</p>
|
||||
<p
|
||||
style="
|
||||
margin: 0 0 16px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
text-align: center;
|
||||
"
|
||||
>
|
||||
<a
|
||||
href="{{ config('app.client_url') . $data['link'] }}"
|
||||
style="
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
background-color: rgba(68, 115, 196);
|
||||
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;
|
||||
"
|
||||
>
|
||||
Check now</a
|
||||
>
|
||||
</p>
|
||||
|
||||
<p style="text-align: center">
|
||||
Or you can quick
|
||||
<span style="font-weight: bold">Confirm</span> or
|
||||
<span style="font-weight: bold">Refuse</span> here:
|
||||
</p>
|
||||
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
"
|
||||
>
|
||||
<a
|
||||
href="{{ route('email.ticket.handle', ['ticket_id' => $data['ticket_id'], 'action' => 'confirm', 'admin_email' => $data['admin_email']]) }}"
|
||||
style="
|
||||
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</a
|
||||
>
|
||||
|
||||
<a
|
||||
href="{{ route('email.ticket.handle', ['ticket_id' => $data['ticket_id'], 'action' => 'refuse', 'admin_email' => $data['admin_email']]) }}"
|
||||
style="
|
||||
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</a
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
Loading…
Reference in New Issue