select(['course_classes.id', 'course_classes.course_id', 'course_classes.lecturer_id', 'course_classes.academic_term_id']) ->withCount('enrollments') ->with([ 'course:id,code,name', 'academicTerm:id,academic_year,semester,start_date,end_date', 'attendances' => fn ($q) => $q->select('course_class_id', 'meeting_number')->distinct(), ]) ->when($user->hasRole('dosen'), fn ($q) => $q->where('lecturer_id', $user->lecturer?->id)) ->when($academicTermId, fn ($q) => $q->where('academic_term_id', $academicTermId)) ->orderBy('course_id') ->get() ->each(function (CourseClass $courseClass) { $courseClass->setAttribute('meetings_count', $courseClass->attendances->count()); $courseClass->unsetRelation('attendances'); }); } /** * Every meeting recorded so far for a single class. */ public function sessionsForClass(CourseClass $courseClass): Collection { return Attendance::query() ->select(['meeting_number', 'date']) ->selectRaw('COUNT(*) as total_count') ->selectRaw("SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present_count") ->where('course_class_id', $courseClass->id) ->groupBy('meeting_number', 'date') ->orderByDesc('meeting_number') ->get(); } /** * The meeting number a new session for this class should default to. */ public function nextMeetingNumber(CourseClass $courseClass): int { return (Attendance::query()->where('course_class_id', $courseClass->id)->max('meeting_number') ?? 0) + 1; } public function session(CourseClass $courseClass, int $meetingNumber): array { $existing = Attendance::query() ->where('course_class_id', $courseClass->id) ->where('meeting_number', $meetingNumber) ->get() ->keyBy('student_id'); $roster = $courseClass->enrollments() ->with('student.user.profile') ->get() ->map(function ($enrollment) use ($existing) { $attendance = $existing->get($enrollment->student_id); return [ 'student_id' => $enrollment->student_id, 'student' => $enrollment->student, 'status' => $attendance?->status?->value ?? AttendanceStatus::Absent->value, ]; }) ->values(); return [ 'roster' => $roster, 'date' => $existing->first()?->date?->format('Y-m-d'), ]; } public function saveSession(int $courseClassId, int $meetingNumber, string $date, array $records): void { foreach ($records as $record) { Attendance::updateOrCreate( [ 'course_class_id' => $courseClassId, 'student_id' => $record['student_id'], 'meeting_number' => $meetingNumber, ], [ 'date' => $date, 'status' => $record['status'], 'recorded_at' => now(), ], ); } } public function deleteSession(int $courseClassId, int $meetingNumber): void { Attendance::query() ->where('course_class_id', $courseClassId) ->where('meeting_number', $meetingNumber) ->delete(); } }