feat: add graduation archive and public document services

This commit is contained in:
2026-04-14 13:51:39 +00:00
parent d77ad72bcc
commit 58c9b47dc0
30 changed files with 2513 additions and 295 deletions
+88 -11
View File
@@ -13,6 +13,7 @@ use App\Models\Village;
use App\Models\StudentAcademicHistory;
use App\Models\StudentExit;
use App\Models\StudentTransfer;
use App\Models\StudentGraduation;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -80,7 +81,7 @@ class StudentController extends Controller
->when($academicYearId, fn ($query) => $query->where('students.academic_year_id', $academicYearId))
->when($departmentId, fn ($query) => $query->where('students.department_id', $departmentId))
->when($classId, fn ($query) => $query->where('students.class_id', $classId))
->when($viewConfig['view'] === 'all' && blank($statusFilter), fn ($query) => $query->whereNotIn('students.status', ['dropped', 'transferred']))
->when($viewConfig['view'] === 'all' && blank($statusFilter), fn ($query) => $query->where('students.status', 'active'))
->when($viewConfig['view'] === 'all' && $statusFilter === 'active', fn ($query) => $query->where('students.status', 'active'))
->when($viewConfig['view'] === 'all' && $statusFilter === 'non_active', fn ($query) => $query->whereIn('students.status', ['inactive', 'graduated', 'dropped', 'transferred']))
->when($viewConfig['view'] !== 'all' && $status, fn ($query) => $query->where('students.status', $status))
@@ -150,6 +151,29 @@ class StudentController extends Controller
return $student;
});
$summary = [
'total' => $students->total(),
'byAcademicYear' => Student::query()
->select('academic_years.name', 'academic_years.start_year', DB::raw('count(*) as total'))
->join('academic_years', 'academic_years.id', '=', 'students.academic_year_id')
->when($search !== '', function ($query) use ($search) {
$query->where(function ($subQuery) use ($search) {
$subQuery->where('students.full_name', 'like', "%{$search}%")
->orWhere('students.student_number', 'like', "%{$search}%")
->orWhere('students.nisn', 'like', "%{$search}%")
->orWhere('students.phone_number', 'like', "%{$search}%");
});
})
->when($academicYearId, fn ($query) => $query->where('students.academic_year_id', $academicYearId))
->when($departmentId, fn ($query) => $query->where('students.department_id', $departmentId))
->when($classId, fn ($query) => $query->where('students.class_id', $classId))
->where('students.status', $status ?: 'graduated')
->groupBy('academic_years.name', 'academic_years.start_year')
->orderByDesc('academic_years.start_year')
->limit(3)
->get(),
];
return view('students.index', [
'students' => $students,
'search' => $search,
@@ -162,16 +186,19 @@ class StudentController extends Controller
'academicYears' => AcademicYear::orderBy('name')->pluck('name', 'id'),
'departments' => Department::where('is_active', true)->orderBy('name')->pluck('name', 'id'),
'classes' => SchoolClass::orderBy('name')->pluck('name', 'id'),
'statuses' => [
'active' => 'Aktif',
'non_active' => 'Non Aktif',
],
'statuses' => $viewConfig['view'] === 'all'
? [
'active' => 'Aktif',
'non_active' => 'Non Aktif',
]
: [],
'studentStatusLabels' => $this->statusOptions(),
'sort' => $sort,
'direction' => $direction,
'pageTitle' => $viewConfig['title'],
'pageDescription' => $viewConfig['description'],
'viewMode' => $viewConfig['view'],
'summary' => $summary,
]);
}
@@ -188,6 +215,7 @@ class StudentController extends Controller
$this->syncAcademicHistory($student, $data);
$this->syncExitRecord($student, $data);
$this->syncTransferRecord($student, $data);
$this->syncGraduationRecord($student, $data);
Alert::success('Berhasil', 'Data siswa berhasil ditambahkan.');
@@ -261,6 +289,7 @@ class StudentController extends Controller
$this->syncAcademicHistory($student, $data);
$this->syncExitRecord($student, $data);
$this->syncTransferRecord($student, $data);
$this->syncGraduationRecord($student, $data);
Alert::success('Berhasil', 'Data siswa berhasil diperbarui.');
@@ -750,6 +779,60 @@ class StudentController extends Controller
StudentTransfer::query()->where('student_id', $student->id)->delete();
}
protected function syncGraduationRecord(Student $student, array $data): void
{
if (($data['status'] ?? null) === 'graduated') {
$graduationRecord = StudentGraduation::firstOrNew(['student_id' => $student->id]);
$graduationRecord->fill([
'student_number' => $student->student_number,
'nisn' => $student->nisn,
'full_name' => $student->full_name,
'academic_year_id' => $student->academic_year_id,
'department_id' => $student->department_id,
'class_id' => $student->class_id,
'entry_date' => $student->entry_date,
'graduation_date' => $graduationRecord->graduation_date ?? now()->toDateString(),
'graduation_note' => $student->notes,
'status' => 'graduated',
]);
if (request()->hasFile('skl_file')) {
if ($graduationRecord->skl_file_path && Storage::disk('public')->exists($graduationRecord->skl_file_path)) {
Storage::disk('public')->delete($graduationRecord->skl_file_path);
}
$file = request()->file('skl_file');
$path = $file->store("student-graduation-documents/{$student->id}/skl", 'public');
$graduationRecord->skl_file_name = $file->getClientOriginalName();
$graduationRecord->skl_file_path = $path;
$graduationRecord->skl_mime_type = $file->getMimeType();
$graduationRecord->skl_file_size = $file->getSize();
}
if (request()->hasFile('ijazah_file')) {
if ($graduationRecord->ijazah_file_path && Storage::disk('public')->exists($graduationRecord->ijazah_file_path)) {
Storage::disk('public')->delete($graduationRecord->ijazah_file_path);
}
$file = request()->file('ijazah_file');
$path = $file->store("student-graduation-documents/{$student->id}/ijazah", 'public');
$graduationRecord->ijazah_file_name = $file->getClientOriginalName();
$graduationRecord->ijazah_file_path = $path;
$graduationRecord->ijazah_mime_type = $file->getMimeType();
$graduationRecord->ijazah_file_size = $file->getSize();
}
$graduationRecord->save();
return;
}
StudentGraduation::query()->where('student_id', $student->id)->delete();
}
protected function importRules(): array
{
return [
@@ -1114,12 +1197,6 @@ class StudentController extends Controller
protected function resolveStudentViewConfig(string $viewMode, mixed $requestedStatus): array
{
return match ($viewMode) {
'graduated' => [
'view' => 'graduated',
'status' => 'graduated',
'title' => 'Data Siswa Lulus',
'description' => 'Daftar siswa yang sudah berstatus lulus.',
],
'transferred' => [
'view' => 'transferred',
'status' => 'transferred',