input('notify'); if (! is_array($notify)) { return [ 'success' => false, 'message' => 'Select at least one teacher to notify.', 'status' => 422, ]; } $missingItemsPayload = $request->input('missing_items', []); $schoolYear = $this->shared->getSchoolYear($request->input('school_year')); $semester = $this->shared->getSemester($request->input('semester')); $targets = $this->extractTargets($notify, $schoolYear, $semester); if (empty($targets)) { return [ 'success' => false, 'message' => 'Select at least one teacher to notify.', 'status' => 422, ]; } $teacherIds = array_values(array_unique(array_column($targets, 'teacher_id'))); $classSectionIds = array_values(array_unique(array_column($targets, 'class_section_id'))); $classSections = ClassSection::query() ->select('class_section_id', 'class_section_name') ->whereIn('class_section_id', $classSectionIds) ->get() ->keyBy('class_section_id'); $teachers = User::query() ->select('id', 'firstname', 'lastname', 'email') ->whereIn('id', $teacherIds) ->get() ->keyBy('id'); $adminUser = User::find($adminId); $adminName = trim(($adminUser->firstname ?? '').' '.($adminUser->lastname ?? '')) ?: 'Administrator'; $scoreUrl = $this->urls->docsHomeUrl(); $sentCount = 0; $failCount = 0; foreach ($targets as $target) { $classSectionId = (int) $target['class_section_id']; $teacherId = (int) $target['teacher_id']; $teacher = $teachers->get($teacherId); $sectionName = $classSections->get($classSectionId)?->class_section_name ?? "Section {$classSectionId}"; $teacherName = trim(($teacher->firstname ?? '').' '.($teacher->lastname ?? '')) ?: 'Teacher'; $missingItems = $this->resolveMissingItems($missingItemsPayload, $classSectionId, $teacherId); $missingNote = ! empty($missingItems) ? '

Outstanding items: '.e($this->support->formatMissingItemsText($missingItems)).'.

' : '

Our records show no outstanding submissions for this section, but please verify if anything still needs attention.

'; $subject = "Reminder: Complete submissions for {$sectionName}"; $body = "

Dear {$teacherName},

" ."

Administration is gently reminding you to wrap up any remaining score submissions and/or comments for {$sectionName}.

" .$missingNote ."

Visit Teacher Score Submission to address any remaining items.

" ."

Thank you,
{$adminName}

"; $email = $teacher->email ?? ''; $status = 'failed'; if (! empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) { try { Mail::to($email)->send(new TeacherSubmissionReminderMail($subject, $body)); $status = 'sent'; } catch (\Throwable $e) { Log::error('Teacher submission notification failed: '.$e->getMessage()); } } if ($status === 'sent') { $sentCount++; } else { $failCount++; } TeacherSubmissionNotificationHistory::create([ 'teacher_id' => $teacherId, 'class_section_id' => $classSectionId, 'admin_id' => $adminId, 'notification_category' => 'teacher_submissions', 'message' => $this->support->truncateNotificationMessage($body), 'status' => $status, 'school_year' => $schoolYear, 'semester' => $semester, 'sent_at' => now(), ]); } $parts = []; if ($sentCount > 0) { $parts[] = $sentCount.' reminder'.($sentCount === 1 ? '' : 's').' sent'; } if ($failCount > 0) { $parts[] = $failCount.' reminder'.($failCount === 1 ? '' : 's').' failed'; } return [ 'success' => $failCount === 0, 'message' => ! empty($parts) ? implode(' and ', $parts) : 'No notifications were sent.', 'sent' => $sentCount, 'failed' => $failCount, 'status' => $failCount === 0 ? 200 : 207, ]; } protected function extractTargets(array $notify, string $schoolYear, string $semester): array { if ($this->isFlatTeacherIdList($notify)) { $teacherIds = array_values(array_unique(array_map('intval', array_filter($notify, static fn ($value) => (int) $value > 0)))); if (empty($teacherIds)) { return []; } $query = ClassSection::query() ->select('teacher_class.class_section_id', 'teacher_class.teacher_id') ->join('teacher_class', 'teacher_class.class_section_id', '=', 'classSection.class_section_id') ->whereIn('teacher_class.teacher_id', $teacherIds) ->where('teacher_class.school_year', $schoolYear) ->orderBy('teacher_class.class_section_id'); if ($this->shared->teacherClassSupportsSemester() && $semester !== '') { $query->where('teacher_class.semester', $semester); } return $query ->get() ->map(static fn ($row): array => [ 'class_section_id' => (int) $row->class_section_id, 'teacher_id' => (int) $row->teacher_id, ]) ->filter(static fn (array $row): bool => $row['class_section_id'] > 0 && $row['teacher_id'] > 0) ->values() ->all(); } $targets = []; foreach ($notify as $sectionIdRaw => $teachers) { $sectionId = (int) $sectionIdRaw; if ($sectionId <= 0 || ! is_array($teachers)) { continue; } foreach ($teachers as $teacherIdRaw => $value) { $teacherId = (int) $teacherIdRaw; if ($teacherId <= 0 || $value === null || $value === '') { continue; } $targets["{$sectionId}_{$teacherId}"] = [ 'class_section_id' => $sectionId, 'teacher_id' => $teacherId, ]; } } return array_values($targets); } protected function isFlatTeacherIdList(array $notify): bool { foreach ($notify as $value) { if (is_array($value)) { return false; } } return true; } protected function resolveMissingItems($payload, int $classSectionId, int $teacherId): array { if (! is_array($payload)) { return []; } if (isset($payload[$classSectionId]) && is_array($payload[$classSectionId])) { $sectionPayload = $payload[$classSectionId]; if (array_key_exists($teacherId, $sectionPayload) || array_key_exists((string) $teacherId, $sectionPayload)) { $value = $sectionPayload[$teacherId] ?? $sectionPayload[(string) $teacherId] ?? null; return $this->support->parseMissingItemsPayload($value); } } if (array_key_exists($teacherId, $payload) || array_key_exists((string) $teacherId, $payload)) { $value = $payload[$teacherId] ?? $payload[(string) $teacherId] ?? null; return $this->support->parseMissingItemsPayload($value); } return []; } }