when($search, fn ($q) => $q->where('academic_year', 'like', "%{$search}%")) ->when($semester, fn ($q) => $q->where('semester', $semester)) ->when($isActive !== null, fn ($q) => $q->where('is_active', $isActive)) ->latest() ->paginate($perPage, ['id', 'academic_year', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters']); } public function create(array $data): AcademicTerm { return AcademicTerm::create([ ...$data, 'open_semesters' => $this->normalizeOpenSemesters($data['open_semesters'] ?? []), ]); } public function update(AcademicTerm $academicTerm, array $data): AcademicTerm { $academicTerm->update([ 'academic_year' => $data['academic_year'], 'semester' => $data['semester'], 'start_date' => $data['start_date'], 'end_date' => $data['end_date'], 'is_active' => $data['is_active'], 'open_semesters' => $this->normalizeOpenSemesters($data['open_semesters'] ?? []), ]); return $academicTerm; } public function delete(AcademicTerm $academicTerm): bool { return $academicTerm->delete(); } public function updateActiveStatus(AcademicTerm $academicTerm, bool $isActive): void { DB::transaction(function () use ($academicTerm, $isActive) { if ($isActive) { AcademicTerm::where('id', '!=', $academicTerm->id)->update(['is_active' => false]); } $academicTerm->update(['is_active' => $isActive]); }); } public function getAllForSelect(): Collection { return AcademicTerm::latest()->get(['id', 'academic_year', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters']); } /** * The academic term currently marked active, falling back to the one with * the latest start date if none is explicitly active. */ public function getActive(): ?AcademicTerm { return AcademicTerm::where('is_active', true)->first() ?? AcademicTerm::orderByDesc('start_date')->first(); } /** * @param array $openSemesters * @return array */ private function normalizeOpenSemesters(array $openSemesters): array { return array_values(array_unique(array_map('intval', $openSemesters))); } }