semester = (string) ($this->configModel->getConfig('semester') ?? ''); $this->schoolYear = (string) ($this->configModel->getConfig('school_year') ?? ''); } public function compose( int $studentId, string $code = 'ABS_1', string $variant = 'default', ?string $incidentDate = null ): array { if ($studentId <= 0) { return [ 'success' => false, 'message' => 'Missing student_id.', 'status' => 422, ]; } $student = $this->studentModel->query()->find($studentId)?->toArray() ?? []; $parent = $this->parentLookupService->getPrimaryParentForStudent($studentId); $secondary = $this->parentLookupService->getSecondaryParentForStudent($studentId, $this->schoolYear); $result = $this->emailComposerService->composePreview( $studentId, $student, $parent, $secondary, $code, $variant, $incidentDate ); if (($result['success'] ?? false) && isset($result['data'])) { $result['data']['semester'] = $this->semester; $result['data']['school_year'] = $this->schoolYear; } return $result; } public function parentsInfo(int $studentId): array { return $this->parentLookupService->parentsInfo($studentId, $this->schoolYear); } public function getViolationDatesForStudent(int $studentId, string $code, ?string $incidentDate = null): array { $code = strtoupper(trim($code)); $statuses = ['absent', 'late']; if (str_starts_with($code, 'ABS')) { $statuses = ['absent']; } elseif (str_starts_with($code, 'LATE')) { $statuses = ['late']; } elseif (str_starts_with($code, 'MIX')) { $statuses = ['absent', 'late']; } if (method_exists($this->attendanceDataModel, 'getRecentUnreportedDates')) { return $this->attendanceDataModel->getRecentUnreportedDates( $studentId, $statuses, $incidentDate, 35, $this->semester, $this->schoolYear ); } return $this->attendanceDataModel->query() ->where('student_id', $studentId) ->whereIn(DB::raw('LOWER(TRIM(status))'), $statuses) ->when($incidentDate, fn ($q) => $q->where('date', '<=', $incidentDate)) ->orderByDesc('date') ->limit(35) ->pluck('date') ->map(fn ($d) => substr((string) $d, 0, 10)) ->unique() ->values() ->all(); } }