Files
alrahma_sunday_school_api/app/Services/Administrator/TeacherSubmissionReportService.php
T
2026-06-11 11:46:12 -04:00

293 lines
11 KiB
PHP

<?php
namespace App\Services\Administrator;
use App\Models\AttendanceDay;
use App\Models\ScoreComment;
use App\Models\SemesterScore;
use App\Models\TeacherSubmissionNotificationHistory;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class TeacherSubmissionReportService
{
public function __construct(
protected AdministratorSharedService $shared,
protected TeacherSubmissionSupportService $support
) {}
public function report(array $filters = []): array
{
$semester = $this->shared->getSemester($filters['semester'] ?? null);
$schoolYear = $this->shared->getSchoolYear($filters['school_year'] ?? null);
$teacherClassSupportsSemester = $this->shared->teacherClassSupportsSemester();
$assignmentQuery = DB::table('teacher_class as tc')
->select([
'tc.class_section_id',
'cs.class_section_name',
'tc.teacher_id',
'u.firstname',
'u.lastname',
'tc.position',
])
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
->leftJoin('users as u', 'u.id', '=', 'tc.teacher_id')
->where('tc.school_year', $schoolYear)
->orderBy('cs.class_section_name');
if ($teacherClassSupportsSemester && $semester !== '') {
$assignmentQuery->where('tc.semester', $semester);
}
$assignmentRows = $assignmentQuery
->get()
->map(fn ($r) => (array) $r)
->all();
$teachersBySection = [];
foreach ($assignmentRows as $assignment) {
$sectionId = (int) ($assignment['class_section_id'] ?? 0);
if ($sectionId <= 0) {
continue;
}
$positionKey = strtolower(trim((string) ($assignment['position'] ?? '')));
$roleKey = $positionKey !== '' ? $positionKey : 'teacher';
$positionLabel = match ($roleKey) {
'ta' => 'TA',
'main' => 'Main',
default => $roleKey !== '' ? ucfirst($roleKey) : 'Teacher',
};
$teacherFullName = trim(($assignment['firstname'] ?? '').' '.($assignment['lastname'] ?? ''));
$teacherId = (int) ($assignment['teacher_id'] ?? 0);
if ($teacherFullName === '' || $teacherId <= 0) {
continue;
}
if (! isset($teachersBySection[$sectionId])) {
$teachersBySection[$sectionId] = [
'class_section' => $assignment['class_section_name'] ?? "Section {$sectionId}",
'teachers' => [],
];
}
$teachersBySection[$sectionId]['teachers'][] = [
'id' => $teacherId,
'label' => "{$positionLabel}: {$teacherFullName}",
'role_key' => $roleKey,
];
}
$today = now()->format('Y-m-d');
$rows = [];
$totalStatuses = 0;
$missingItemCount = 0;
$allTeacherIds = [];
$allClassSectionIds = [];
foreach ($teachersBySection as $classSectionId => $section) {
$classSectionId = (int) $classSectionId;
if ($classSectionId <= 0) {
continue;
}
$studentIds = DB::table('student_class')
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear)
->pluck('student_id')
->map(fn ($id) => (int) $id)
->filter()
->values()
->all();
$expected = count($studentIds);
$midtermStudents = [];
$participationStudents = [];
$scoreRecords = SemesterScore::query()
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear)
->get();
foreach ($scoreRecords as $score) {
$sid = (int) ($score->student_id ?? 0);
if ($sid <= 0 || ($expected > 0 && ! in_array($sid, $studentIds, true))) {
continue;
}
if (trim((string) ($score->midterm_exam_score ?? '')) !== '') {
$midtermStudents[$sid] = true;
}
if (trim((string) ($score->participation_score ?? '')) !== '') {
$participationStudents[$sid] = true;
}
}
$midtermCommentStudents = [];
$ptapCommentStudents = [];
if (! empty($studentIds)) {
$comments = ScoreComment::query()
->select('student_id', 'score_type', 'comment')
->whereIn('student_id', $studentIds)
->where('semester', $semester)
->where('school_year', $schoolYear)
->whereIn('score_type', ['midterm', 'ptap'])
->get();
foreach ($comments as $comment) {
$sid = (int) ($comment->student_id ?? 0);
if ($sid <= 0) {
continue;
}
$text = trim((string) ($comment->comment ?? ''));
if ($text === '') {
continue;
}
$type = strtolower(trim((string) ($comment->score_type ?? '')));
if ($type === 'midterm') {
$midtermCommentStudents[$sid] = true;
}
if ($type === 'ptap') {
$ptapCommentStudents[$sid] = true;
}
}
}
$attendanceRow = AttendanceDay::query()
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear)
->whereDate('date', $today)
->first();
$attendanceSubmitted = $attendanceRow
&& in_array(strtolower((string) ($attendanceRow->status ?? '')), ['submitted', 'published', 'finalized'], true);
$teacherList = $section['teachers'] ?? [];
usort(
$teacherList,
fn ($a, $b) => $this->support->teacherRolePriority($a['role_key'] ?? 'teacher')
<=> $this->support->teacherRolePriority($b['role_key'] ?? 'teacher')
);
foreach ($teacherList as $teacherEntry) {
if (! empty($teacherEntry['id'])) {
$allTeacherIds[] = $teacherEntry['id'];
}
}
$allClassSectionIds[] = $classSectionId;
$midtermScoreStatus = $this->support->submissionStatus(count($midtermStudents), $expected);
$midtermCommentStatus = $this->support->submissionStatus(count($midtermCommentStudents), $expected);
$participationStatus = $this->support->submissionStatus(count($participationStudents), $expected);
$ptapCommentStatus = $this->support->submissionStatus(count($ptapCommentStudents), $expected);
$attendanceStatus = $this->support->attendanceStatus($attendanceSubmitted, $expected);
$statusDetails = [
'midterm_score_status' => $midtermScoreStatus,
'midterm_comment_status' => $midtermCommentStatus,
'participation_status' => $participationStatus,
'ptap_comment_status' => $ptapCommentStatus,
'attendance_status' => $attendanceStatus,
];
$missingItemsForSection = $this->support->buildMissingItems($statusDetails);
$missingItemCount += count($missingItemsForSection);
$totalStatuses += count($statusDetails);
$rows[] = [
'class_section' => $section['class_section'] ?? "Section {$classSectionId}",
'class_section_id' => $classSectionId,
'teachers' => array_values($teacherList),
'midterm_score_status' => $midtermScoreStatus,
'midterm_comment_status' => $midtermCommentStatus,
'participation_status' => $participationStatus,
'ptap_comment_status' => $ptapCommentStatus,
'attendance_status' => $attendanceStatus,
'missing_items' => $missingItemsForSection,
'student_count' => $expected,
];
}
$historyMap = $this->notificationHistoryMap($allTeacherIds, $allClassSectionIds);
$summary = [
'total_items' => $totalStatuses,
'missing_items' => $missingItemCount,
'submitted_items' => max(0, $totalStatuses - $missingItemCount),
'submission_percentage' => $totalStatuses > 0
? (int) round((($totalStatuses - $missingItemCount) / $totalStatuses) * 100)
: 100,
];
return [
'rows' => $rows,
'semester' => $semester,
'schoolYear' => $schoolYear,
'currentSemester' => $this->shared->getSemester(),
'currentSchoolYear' => $this->shared->getSchoolYear(),
'notificationHistory' => $historyMap,
'summary' => $summary,
];
}
protected function notificationHistoryMap(array $allTeacherIds, array $allClassSectionIds): array
{
$historyMap = [];
$teacherIds = array_values(array_unique($allTeacherIds));
$classSectionIds = array_values(array_unique($allClassSectionIds));
if (empty($teacherIds) || empty($classSectionIds)) {
return $historyMap;
}
$historyRecords = TeacherSubmissionNotificationHistory::query()
->select('teacher_submission_notification_history.*', 'u.firstname', 'u.lastname')
->leftJoin('users as u', 'u.id', '=', 'teacher_submission_notification_history.admin_id')
->where('notification_category', 'teacher_submissions')
->whereIn('teacher_submission_notification_history.teacher_id', $teacherIds)
->whereIn('teacher_submission_notification_history.class_section_id', $classSectionIds)
->orderByDesc('sent_at')
->get();
foreach ($historyRecords as $record) {
$sectionId = (int) ($record->class_section_id ?? 0);
$teacherId = (int) ($record->teacher_id ?? 0);
if ($sectionId <= 0 || $teacherId <= 0) {
continue;
}
$adminName = trim(($record->firstname ?? '').' '.($record->lastname ?? ''));
if ($adminName === '') {
$adminName = 'Administrator';
}
$historyMap[$sectionId][$teacherId][] = [
'sent_at_text' => $record->sent_at ? Carbon::parse($record->sent_at)->format('M j, Y g:i A') : '',
'admin_name' => $adminName,
'status' => strtolower((string) ($record->status ?? 'sent')),
];
}
foreach ($historyMap as &$teachersHistory) {
foreach ($teachersHistory as &$entries) {
$entries = array_slice($entries, 0, 3);
}
}
return $historyMap;
}
}