'integer', 'class_section_id' => 'integer', 'school_id' => 'integer', 'student_id' => 'integer', 'reported' => 'string', 'is_reported' => 'string', 'is_notified' => 'string', 'date' => 'date', 'created_at' => 'datetime', 'updated_at' => 'datetime' ]; private ?array $reportedColumns = null; /* |-------------------------------------------------------------------------- | Relationships |-------------------------------------------------------------------------- */ public function student() { return $this->belongsTo(Student::class, 'student_id'); } public function class() { return $this->belongsTo(ClassModel::class, 'class_id'); } public function section() { return $this->belongsTo(ClassSection::class, 'class_section_id'); } /* |-------------------------------------------------------------------------- | Methods Converted from CI4 |-------------------------------------------------------------------------- */ /** CI => getAttendanceByClass */ public function getAttendanceByClass(int $classId, int $classSectionId, string $date) { return self::where('class_id', $classId) ->where('class_section_id', $classSectionId) ->where('date', $date) ->get() ->toArray(); } /** CI => unreportedTermRows */ public function unreportedTermRows(array $studentIds, string $schoolYear, ?string $semester): array { $qb = DB::table($this->table) ->select( 'id', 'student_id', 'class_id', 'class_section_id', 'date', 'status', 'reason', 'school_year', 'semester', 'is_reported' ) ->where('school_year', $schoolYear); if ($semester !== null && $semester !== '') { $qb->where('semester', $semester); } if (!empty($studentIds)) { $qb->whereIn('student_id', $studentIds); } $this->applyUnreportedFilter($qb); return $qb->orderBy('date', 'DESC') ->get() ->map(static function ($row) { return (array) $row; }) ->all(); } /** CI => updateAttendance */ public function updateAttendance(int $id, array $data) { return self::where('id', $id)->update($data) > 0; } /** CI => getAttendance */ public function getAttendance(int $studentId, int $classSectionId, string $date) { $row = self::where([ 'student_id' => $studentId, 'class_section_id' => $classSectionId, 'date' => $date ])->first(); return $row ? $row->toArray() : null; } /** CI => getReportedAttendance */ public function getReportedAttendance(string $startDate, ?string $endDate = null) { $query = self::where(function ($q) { $q->where('is_reported', 1) ->orWhere('is_reported', 'yes'); }); if ($endDate) { $query->whereBetween('date', [$startDate, $endDate]); } else { $query->where('date', $startDate); } return $query->get()->toArray(); } /** CI => getTodayAbsentees */ public function getTodayAbsentees(?int $classSectionId = null, ?string $schoolYear = null, ?string $semester = null) { $query = self::where('status', 'Absent') ->where('date', now()->toDateString()); if ($classSectionId !== null) { $query->where('class_section_id', $classSectionId); } if ($schoolYear !== null) { $query->where('school_year', $schoolYear); } if ($semester !== null) { $query->where('semester', $semester); } return $query->get()->toArray(); } /** CI => getTodayLates */ public function getTodayLates(?int $classSectionId = null, ?string $schoolYear = null, ?string $semester = null) { $query = self::where('status', 'Late') ->where('date', now()->toDateString()); if ($classSectionId !== null) { $query->where('class_section_id', $classSectionId); } if ($schoolYear !== null) { $query->where('school_year', $schoolYear); } if ($semester !== null) { $query->where('semester', $semester); } return $query->get()->toArray(); } /** CI => getAbsencesByClassSection */ public function getAbsencesByClassSection($classSectionId, $schoolYear, $semester) { return self::where('status', 'absent') ->where('class_section_id', $classSectionId) ->where('school_year', $schoolYear) ->where('semester', $semester) ->orderBy('date', 'DESC') ->get() ->toArray(); } /** CI => getStudentAttendance */ public function getStudentAttendance( int $studentId, ?string $startDate = null, ?string $endDate = null, ?string $schoolYear = null, ?string $semester = null ): array { $query = self::where('student_id', $studentId); if ($startDate) { $query->where('date', '>=', $startDate); } if ($endDate) { $query->where('date', '<=', $endDate); } if ($schoolYear) { $query->where('school_year', $schoolYear); } if ($semester) { $query->where('semester', $semester); } return $query->orderBy('date', 'DESC')->get()->toArray(); } /** CI => getStudentAttendanceOnDate */ public function getStudentAttendanceOnDate(int $studentId, string $date): ?array { $row = self::where('student_id', $studentId) ->where('date', $date) ->first(); return $row ? $row->toArray() : null; } /* |-------------------------------------------------------------------------- | CI Complex Function => getUnreportedAbsencesAndLates() |-------------------------------------------------------------------------- */ public function getUnreportedAbsencesAndLates(?string $schoolYear = null, ?string $semester = null): array { $query = DB::table($this->table) ->select('id', 'student_id', 'class_id', 'class_section_id', 'date', 'status', 'reason', 'school_year', 'semester', 'is_reported') ->whereNotNull('student_id'); $this->applyUnreportedFilter($query); $query->where(function ($q) { $q->where('is_notified', 0) ->orWhere('is_notified', '0') ->orWhereNull('is_notified') ->orWhereRaw("LOWER(TRIM(COALESCE(is_notified, ''))) != 'yes'"); }); if ($schoolYear) { $query->where('school_year', $schoolYear); } if ($semester) { $query->where('semester', $semester); } // Status filter $query->where(function ($q) { $q->whereIn('status', ['ABS', 'ABSENT', 'LATE', 'A', 'L']) ->orWhere('status', 'like', 'ABS%') ->orWhere('status', 'like', 'LATE%'); }); $rows = $query->orderBy('student_id', 'ASC') ->orderBy('date', 'DESC') ->get() ->toArray(); // Now group output like original CI function $out = []; foreach ($rows as $r) { $sid = (int) $r->student_id; if (!isset($out[$sid])) { $out[$sid] = [ 'absences' => [], 'lates' => [], 'counts' => ['absences' => 0, 'lates' => 0, 'total' => 0], ]; } $status = strtoupper($r->status); $isAbs = $status === 'ABS' || $status === 'ABSENT' || $status === 'A' || str_starts_with($status, 'ABS'); $isLate = $status === 'LATE' || $status === 'L' || str_starts_with($status, 'LATE'); $rec = [ 'id' => $r->id, 'date' => $r->date, 'status' => $r->status, 'reason' => $r->reason, 'class_id' => $r->class_id, 'class_section_id' => $r->class_section_id, 'school_year' => $r->school_year, 'semester' => $r->semester, ]; if ($isAbs) { $out[$sid]['absences'][] = $rec; $out[$sid]['counts']['absences']++; } elseif ($isLate) { $out[$sid]['lates'][] = $rec; $out[$sid]['counts']['lates']++; } $out[$sid]['counts']['total'] = $out[$sid]['counts']['absences'] + $out[$sid]['counts']['lates']; } return $out; } /* |-------------------------------------------------------------------------- | CI => markRuleAsNotifiedData() |-------------------------------------------------------------------------- */ public function markRuleAsNotifiedData(int $studentId, string $date, ?string $semester = null, ?string $schoolYear = null): bool { $day = substr($date, 0, 10); $start = $day . ' 00:00:00'; $endEx = date('Y-m-d', strtotime($day . ' +1 day')) . ' 00:00:00'; $query = DB::table($this->table) ->where('student_id', $studentId) ->where('date >=', $start) ->where('date <', $endEx); if (!empty($semester)) { $query->where('semester', $semester); } if (!empty($schoolYear)) { $query->where('school_year', $schoolYear); } return $query->update([ 'is_notified' => 'yes', 'updated_at' => utc_now(), ]) > 0; } public function markReportedAndNotified(int $studentId, array $dates, ?string $semester = null, ?string $schoolYear = null): bool { $dates = array_values(array_unique(array_filter($dates, static function ($d) { return is_string($d) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $d); }))); if (empty($dates)) { return true; } $builder = DB::table($this->table) ->where('student_id', $studentId) ->whereIn('date', $dates) ->whereRaw("LOWER(TRIM(status)) IN ('absent','late')"); if (!empty($semester)) { $builder->where('semester', $semester); } if (!empty($schoolYear)) { $builder->where('school_year', $schoolYear); } $cols = $this->reportedColumns(); $updates = [ 'updated_at' => utc_now(), ]; if (!empty($cols['is_reported'])) { $updates['is_reported'] = 'yes'; } if (!empty($cols['reported'])) { $updates['reported'] = 1; } if (Schema::hasColumn($this->table, 'is_notified')) { $updates['is_notified'] = 'yes'; } return $builder->update($updates) > 0; } public function getRecentUnreportedDates( int $studentId, array $statuses, ?string $incidentDate = null, int $lookbackDays = 35, ?string $semester = null, ?string $schoolYear = null ): array { if ($studentId <= 0 || empty($statuses)) { return []; } $statuses = array_map('strtolower', $statuses); $day = $incidentDate && preg_match('/^\d{4}-\d{2}-\d{2}$/', $incidentDate) ? $incidentDate : date('Y-m-d'); $start = date('Y-m-d', strtotime($day . ' -' . max(0, $lookbackDays) . ' days')); $placeholders = implode(',', array_fill(0, count($statuses), '?')); $qb = DB::table($this->table) ->select('date') ->where('student_id', $studentId) ->where('date >=', $start) ->where('date <=', $day) ->whereRaw("LOWER(TRIM(status)) IN ({$placeholders})", $statuses); $this->applyUnreportedFilter($qb); if (!empty($semester)) { $qb->where('semester', $semester); } if (!empty($schoolYear)) { $qb->where('school_year', $schoolYear); } $rows = $qb->orderBy('date', 'DESC')->get()->toArray(); return array_values(array_unique(array_map(static function ($r) { return substr((string) ($r->date ?? ''), 0, 10); }, $rows))); } private function reportedColumns(): array { if ($this->reportedColumns !== null) { return $this->reportedColumns; } $this->reportedColumns = [ 'is_reported' => Schema::hasColumn($this->table, 'is_reported'), 'reported' => Schema::hasColumn($this->table, 'reported'), ]; return $this->reportedColumns; } private function applyUnreportedFilter($qb): void { $cols = $this->reportedColumns(); if (!empty($cols['is_reported'])) { $qb->where(function ($q) { $q->where('is_reported', 'no') ->orWhere('is_reported', 0) ->orWhere('is_reported', '0') ->orWhereNull('is_reported'); }); } if (!empty($cols['reported'])) { $qb->whereRaw("LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on')"); } } }