TIFNJK_E41221880/app/Http/Controllers/PermissionController.php

283 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Enums\NotificationType;
use App\Models\AttendanceHistory;
use App\Models\AttendanceHistoryDaily;
use App\Models\Notification;
use Illuminate\Http\Request;
use App\Models\Permission;
use App\Models\Schedule;
use App\Models\Student;
use App\Services\NotificationHelperService;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
class PermissionController extends Controller
{
protected NotificationHelperService $notificationHelper;
public $latOfAttendance;
public $lonOfAttendance;
public function __construct(NotificationHelperService $notificationHelper)
{
$this->notificationHelper = $notificationHelper;
$this->initCoordinatesFromConfig();
}
private function initCoordinatesFromConfig(): void
{
$coordinate = config('coordinate.coordinate', '-7.604032330848524, 112.10176449791652');
[$lat, $lon] = array_map('trim', explode(',', $coordinate));
$this->latOfAttendance = (float) $lat;
$this->lonOfAttendance = (float) $lon;
}
public function index()
{
$permissions = Permission::all();
return view('pages.perizinan.perizinan', compact('permissions'));
}
public function permissionAccept(Request $request, int $id): RedirectResponse
{
try {
// session-auth user for web controller
$user = $request->user();
if (!$user) {
return redirect()->back()->with('error', 'Unauthorized');
}
// find permission by id
$permission = Permission::find($id);
if (!$permission) {
return redirect()->back()->with('error', 'Data perizinan tidak ditemukan');
}
// permission must be processed only, if already accepted or rejected, cannot be processed again.
if ($permission->status === 'diterima') {
return redirect()->back()->with('warning', 'Perizinan sudah diterima sebelumnya');
}
if ($permission->status === 'ditolak') {
return redirect()->back()->with('warning', 'Perizinan sudah ditolak sebelumnya');
}
$student = Student::find($permission->id_student);
if (!$student) {
return redirect()->back()->with('error', 'Data siswa tidak ditemukan');
}
DB::transaction(function () use ($permission, $user, $request, $student) {
// update status to accepted
$permission->status = 'diterima';
$permission->approved_by = $user->id; // set approved by teacher id
$permission->feedback = $request->input('feedback', null); // optional feedback message from teacher
$permission->save();
// * create attendance record history to related date (only fill with schedule that has active academic period, and match with date permission).
$permissionReason = $permission->reason; // contoh: 'sakit', 'izin', 'dispen', 'lainnya'
if ($permissionReason === 'lainnya') {
$permissionReason = 'izin';
}
$permissionDate = Carbon::parse($permission->date_permission)->startOfDay();
$permissionTimePeriod = (int) $permission->time_period;
$createdSchoolDays = 0;
$currentDate = $permissionDate->copy();
// Count time_period as school days; weekend days are skipped and replaced by the next weekday.
while ($createdSchoolDays < $permissionTimePeriod) {
if ($currentDate->isWeekend()) {
$currentDate->addDay();
continue;
}
$dayName = strtolower($currentDate->locale('id')->dayName);
$dayIndex = $currentDate->dayOfWeekIso; // 1..7
// search related schedule with day_of_week same and active academic period
$schedules = Schedule::query()
->where('id_class', $student->id_class)
->whereHas('academicPeriods', function ($q) {
$q->where('is_active', 1);
})
->where(function ($q) use ($dayName, $dayIndex) {
$q->where('day_of_week', $dayName)
->orWhere('day_of_week', (string) $dayIndex);
})
->get();
foreach ($schedules as $schedule) {
AttendanceHistory::updateOrCreate(
[
'id_schedule' => $schedule->id,
'id_student' => $student->id,
'attendance_date' => $currentDate->toDateString(),
],
[
'id_class' => $schedule->id_class,
'period_number' => $schedule->period_start,
'coordinate' => $this->latOfAttendance . ', ' . $this->lonOfAttendance,
'status' => $permissionReason,
]
);
}
// update attendancehistorydaily to 'izin'
// Cari berdasarkan id_student, id_class, dan tanggal dari created_at
// Jika ada, update. Jika tidak ada, create
$attendanceDaily = AttendanceHistoryDaily::whereDate('created_at', $currentDate->toDateString())
->where('id_student', $student->id)
->where('id_class', $student->id_class)
->first();
if ($attendanceDaily) {
$attendanceDaily->update([
'status' => 'izin',
'picture' => '',
]);
} else {
AttendanceHistoryDaily::create([
'id_student' => $student->id,
'id_class' => $student->id_class,
'created_at' => $currentDate,
'status' => 'izin',
'picture' => '',
]);
}
$createdSchoolDays++;
$currentDate->addDay();
}
});
// notification zone: send notification to related student after permission approved
$userStudent = $student->user;
if (!$userStudent) {
return redirect()->back()->with('error', 'User siswa tidak ditemukan untuk notifikasi');
}
$fcmToken = $userStudent->device_token;
$title = 'Perizinan Disetujui';
$body = 'Permohonan izin Anda telah disetujui.';
// Push notification is optional; database notification must still be created.
if (!empty($fcmToken)) {
try {
$template = $this->notificationHelper->templatePermissionApproval($fcmToken);
$this->notificationHelper->send($template);
$title = $template->title;
$body = $template->body;
} catch (\Throwable $th) {
// Ignore push errors so approval flow and DB notification keep working.
}
}
$createTemplate = $this->notificationHelper->createTemplateForStudent(
(int) $userStudent->id,
$title,
$body,
NotificationType::Permission,
(int) $user->id
);
Notification::create($createTemplate->toArray());
return redirect()->back()->with('success', 'Izin diterima untuk siswa ' . $student->name);
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
}
}
public function permissionReject(Request $request, int $id): RedirectResponse
{
try {
// session-auth user for web controller
$user = $request->user();
if (!$user) {
return redirect()->back()->with('error', 'Unauthorized');
}
// find permission by id
$permission = Permission::find($id);
if (!$permission) {
return redirect()->back()->with('error', 'Data perizinan tidak ditemukan');
}
// permission must be processed only, if already accepted or rejected, cannot be processed again.
if ($permission->status === 'diterima') {
return redirect()->back()->with('warning', 'Perizinan sudah diterima sebelumnya');
}
if ($permission->status === 'ditolak') {
return redirect()->back()->with('warning', 'Perizinan sudah ditolak sebelumnya');
}
$student = Student::find($permission->id_student);
if (!$student) {
return redirect()->back()->with('error', 'Data siswa tidak ditemukan');
}
DB::transaction(function () use ($permission, $user, $request) {
// update status to rejected
$permission->status = 'ditolak';
$permission->approved_by = $user->id; // set approved by teacher id
$permission->feedback = $request->input('feedback', null); // optional feedback message from teacher
$permission->save();
});
// notification zone: send notification to related student after permission rejected
$userStudent = $student->user;
if (!$userStudent) {
return redirect()->back()->with('error', 'User siswa tidak ditemukan untuk notifikasi');
}
$fcmToken = $userStudent->device_token;
// Push notification is optional; database notification must still be created.
if (!empty($fcmToken)) {
try {
$template = $this->notificationHelper->templatePermissionRejection(
$fcmToken,
$request->input('feedback', null) // optional custom message from teacher feedback
);
$this->notificationHelper->send($template);
$title = $template->title;
$body = $template->body;
} catch (\Throwable $th) {
// Ignore push errors so rejection flow and DB notification keep working.
$title = 'Perizinan Ditolak';
$body = 'Permohonan izin Anda telah ditolak.';
}
} else {
$title = 'Perizinan Ditolak';
$body = 'Permohonan izin Anda telah ditolak.';
}
$createTemplate = $this->notificationHelper->createTemplateForStudent(
(int) $userStudent->id,
$title,
$body,
NotificationType::Permission,
(int) $user->id
);
Notification::create($createTemplate->toArray());
return redirect()->back()->with('success', 'Izin ditolak untuk siswa ' . $student->name);
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
}
}
}