itmpwk.ac.id/app/Services/Admin/AcademicClasses/AttendanceService.php

115 lines
4.0 KiB
PHP

<?php
namespace App\Services\Admin\AcademicClasses;
use App\Enums\AttendanceStatus;
use App\Models\Attendance;
use App\Models\CourseClass;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
class AttendanceService
{
/**
* Classes to show on the attendance overview: a dosen only sees classes
* they lecture, optionally narrowed down to one academic term.
*/
public function courseClassesForUser(User $user, ?int $academicTermId): Collection
{
return CourseClass::query()
->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();
}
}