with([ 'currentLeader.lecturer.user.profile', 'leaderships' => fn ($q) => $q->orderByRaw('ended_at IS NULL DESC')->orderByDesc('started_at'), 'leaderships.lecturer.user.profile', ]) ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%")) ->latest() ->paginate($perPage, ['id', 'code', 'name', 'degree_level']); } public function create(array $data): Department { $department = Department::create([ 'code' => $data['code'], 'name' => $data['name'], 'degree_level' => $data['degree_level'] ?? null, ]); $this->syncLeadership($department, $data['lecturer_id'] ?? null, $data['leadership_started_at'] ?? null); return $department; } public function update(Department $department, array $data): Department { $department->update([ 'code' => $data['code'], 'name' => $data['name'], 'degree_level' => $data['degree_level'] ?? null, ]); $this->syncLeadership($department, $data['lecturer_id'] ?? null, $data['leadership_started_at'] ?? null); return $department; } public function delete(Department $department): bool { return $department->delete(); } public function getAllForSelect(): Collection { return Department::get(['id', 'code', 'name', 'degree_level']); } private function syncLeadership(Department $department, ?int $lecturerId, ?string $startedAt): void { $currentLeader = DepartmentLeadership::query() ->where('department_id', $department->id) ->whereNull('ended_at') ->first(); if (! $lecturerId) { if ($currentLeader) { $currentLeader->update(['ended_at' => now()]); $this->revokeKaprodiRoleIfNoLongerLeading($currentLeader->lecturer_id); } return; } if ($currentLeader && $currentLeader->lecturer_id === $lecturerId) { $currentLeader->update(['started_at' => $startedAt ?? $currentLeader->started_at]); $this->grantKaprodiRole($lecturerId); return; } if ($currentLeader) { $currentLeader->update(['ended_at' => now()]); $this->revokeKaprodiRoleIfNoLongerLeading($currentLeader->lecturer_id); } $department->leaderships()->create([ 'lecturer_id' => $lecturerId, 'started_at' => $startedAt ?? now(), ]); $this->grantKaprodiRole($lecturerId); } private function grantKaprodiRole(int $lecturerId): void { $user = Lecturer::find($lecturerId)?->user; if ($user && ! $user->hasRole(UserRole::Kaprodi->value)) { $user->assignRole(UserRole::Kaprodi->value); } } private function revokeKaprodiRoleIfNoLongerLeading(int $lecturerId): void { $stillLeadsAnyDepartment = DepartmentLeadership::query() ->where('lecturer_id', $lecturerId) ->whereNull('ended_at') ->exists(); if (! $stillLeadsAnyDepartment) { Lecturer::find($lecturerId)?->user?->removeRole(UserRole::Kaprodi->value); } } }