feat: add graduation archive and public document services
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Models\AcademicYear;
|
||||
use App\Models\SchoolClass;
|
||||
use App\Models\Student;
|
||||
use App\Models\StudentAcademicHistory;
|
||||
use App\Models\StudentGraduation;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -19,31 +20,86 @@ class StudentPromotionController extends Controller
|
||||
{
|
||||
$fromAcademicYearId = $request->integer('from_academic_year_id') ?: AcademicYear::where('is_active', true)->value('id');
|
||||
$toAcademicYearId = $request->integer('to_academic_year_id');
|
||||
$selectedClassId = $request->integer('class_id');
|
||||
|
||||
$academicYears = AcademicYear::orderByDesc('start_year')->orderByDesc('end_year')->get();
|
||||
|
||||
$availableClasses = collect();
|
||||
$classSummaries = collect();
|
||||
$selectedClass = null;
|
||||
$students = collect();
|
||||
|
||||
if ($fromAcademicYearId) {
|
||||
$students = Student::query()
|
||||
->with(['academicYear', 'department', 'classRoom'])
|
||||
$availableClasses = SchoolClass::query()
|
||||
->with(['department'])
|
||||
->where('academic_year_id', $fromAcademicYearId)
|
||||
->where('status', 'active')
|
||||
->orderBy('full_name')
|
||||
->where('is_active', true)
|
||||
->withCount([
|
||||
'students as active_students_count' => fn ($query) => $query->where('status', 'active'),
|
||||
])
|
||||
->orderBy('level')
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->map(function (Student $student) use ($toAcademicYearId) {
|
||||
$student->promotion_recommendation = $this->buildPromotionRecommendation($student, $toAcademicYearId);
|
||||
->filter(fn (SchoolClass $classRoom) => $classRoom->active_students_count > 0)
|
||||
->values();
|
||||
|
||||
return $student;
|
||||
});
|
||||
$classSummaries = $availableClasses->map(function (SchoolClass $classRoom) use ($toAcademicYearId) {
|
||||
$sampleStudent = Student::query()
|
||||
->with(['classRoom'])
|
||||
->where('academic_year_id', $classRoom->academic_year_id)
|
||||
->where('class_id', $classRoom->id)
|
||||
->where('status', 'active')
|
||||
->orderBy('full_name')
|
||||
->first();
|
||||
|
||||
$recommendation = $sampleStudent
|
||||
? $this->buildPromotionRecommendation($sampleStudent, $toAcademicYearId)
|
||||
: [
|
||||
'label' => 'Belum ada siswa aktif',
|
||||
'target_class_name' => null,
|
||||
];
|
||||
|
||||
return (object) [
|
||||
'id' => $classRoom->id,
|
||||
'name' => $classRoom->name,
|
||||
'level' => $classRoom->level,
|
||||
'department_name' => $classRoom->department?->name,
|
||||
'active_students_count' => $classRoom->active_students_count,
|
||||
'recommendation_label' => $recommendation['label'] ?? '-',
|
||||
'recommendation_target_name' => $recommendation['target_class_name'] ?? null,
|
||||
];
|
||||
})->values();
|
||||
|
||||
if ($selectedClassId) {
|
||||
$selectedClass = $availableClasses->firstWhere('id', $selectedClassId);
|
||||
|
||||
if ($selectedClass) {
|
||||
$students = Student::query()
|
||||
->with(['academicYear', 'department', 'classRoom'])
|
||||
->where('academic_year_id', $fromAcademicYearId)
|
||||
->where('class_id', $selectedClassId)
|
||||
->where('status', 'active')
|
||||
->orderBy('full_name')
|
||||
->get()
|
||||
->map(function (Student $student) use ($toAcademicYearId) {
|
||||
$student->promotion_recommendation = $this->buildPromotionRecommendation($student, $toAcademicYearId);
|
||||
|
||||
return $student;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('student-promotions.index', [
|
||||
'academicYears' => $academicYears,
|
||||
'availableClasses' => $availableClasses,
|
||||
'classSummaries' => $classSummaries,
|
||||
'selectedClass' => $selectedClass,
|
||||
'students' => $students,
|
||||
'filters' => [
|
||||
'from_academic_year_id' => $fromAcademicYearId,
|
||||
'to_academic_year_id' => $toAcademicYearId,
|
||||
'class_id' => $selectedClassId,
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -53,6 +109,7 @@ class StudentPromotionController extends Controller
|
||||
$data = $request->validate([
|
||||
'from_academic_year_id' => ['required', 'exists:academic_years,id'],
|
||||
'to_academic_year_id' => ['required', 'exists:academic_years,id', 'different:from_academic_year_id'],
|
||||
'class_id' => ['nullable', 'exists:classes,id'],
|
||||
'promotions' => ['required', 'array', 'min:1'],
|
||||
'promotions.*.student_id' => ['required', 'exists:students,id'],
|
||||
'promotions.*.target_class_id' => ['nullable', 'exists:classes,id'],
|
||||
@@ -102,6 +159,12 @@ class StudentPromotionController extends Controller
|
||||
->withInput();
|
||||
}
|
||||
|
||||
if (! empty($data['class_id']) && (int) $student->class_id !== (int) $data['class_id']) {
|
||||
return back()
|
||||
->withErrors(["promotions.$index.student_id" => "Siswa {$student->full_name} tidak berasal dari kelas asal yang dipilih."])
|
||||
->withInput();
|
||||
}
|
||||
|
||||
if ($student->status !== 'active') {
|
||||
return back()
|
||||
->withErrors(["promotions.$index.student_id" => "Siswa {$student->full_name} tidak berstatus aktif sehingga tidak bisa diproses promosi."])
|
||||
@@ -200,6 +263,22 @@ class StudentPromotionController extends Controller
|
||||
'notes' => $promotion['notes'] ?? 'Diproses melalui modul promosi siswa.',
|
||||
]);
|
||||
|
||||
StudentGraduation::updateOrCreate(
|
||||
['student_id' => $student->id],
|
||||
[
|
||||
'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' => now()->toDateString(),
|
||||
'graduation_note' => $promotion['notes'] ?? 'Diproses melalui modul promosi siswa.',
|
||||
'status' => 'graduated',
|
||||
]
|
||||
);
|
||||
|
||||
$processed++;
|
||||
continue;
|
||||
}
|
||||
@@ -245,6 +324,7 @@ class StudentPromotionController extends Controller
|
||||
->route('student-promotions.index', [
|
||||
'from_academic_year_id' => $data['from_academic_year_id'],
|
||||
'to_academic_year_id' => $data['to_academic_year_id'],
|
||||
'class_id' => $data['class_id'] ?? null,
|
||||
])
|
||||
->with('success', $processed . ' siswa berhasil diproses melalui modul promosi.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user