fix gitlab tests

This commit is contained in:
root
2026-06-09 02:32:58 -04:00
parent 20a0b6c4e5
commit 6def9993da
1489 changed files with 10449 additions and 11356 deletions
@@ -2,13 +2,13 @@
namespace App\Services;
use App\Models\AttendanceData;
use App\Models\AttendanceEmailTemplate;
use App\Models\AttendanceTracking;
use App\Models\Configuration;
use App\Models\ParentNotification;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\Student;
use App\Models\Configuration;
use App\Models\AttendanceData;
use App\Models\ParentNotification;
use App\Models\AttendanceEmailTemplate;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
@@ -19,11 +19,8 @@ use Throwable;
class AttendanceTrackingService
{
protected string $semester;
protected string $schoolYear;
protected array $debugCompute = [];
protected ?array $attendanceReportedColumns = null;
public function __construct(
@@ -43,19 +40,19 @@ class AttendanceTrackingService
public function getPendingViolations(?string $schoolYearParam = null, ?string $semesterParam = null): array
{
$schoolYear = filled($schoolYearParam) ? (string) $schoolYearParam : (string) $this->schoolYear;
$semester = filled($semesterParam) ? (string) $semesterParam : null; // disabled like legacy
$semester = filled($semesterParam) ? (string) $semesterParam : null; // disabled like legacy
$debugInfo = [
'school_year_param' => $schoolYear,
'semester_param' => $semester,
'class_students' => 0,
'student_ids' => 0,
'attendance_rows' => 0,
'filtered_rows' => 0,
'violations' => 0,
'active_weeks' => 0,
'abs_last5' => 0,
'late_last5' => 0,
'semester_param' => $semester,
'class_students' => 0,
'student_ids' => 0,
'attendance_rows' => 0,
'filtered_rows' => 0,
'violations' => 0,
'active_weeks' => 0,
'abs_last5' => 0,
'late_last5' => 0,
];
$classStudentsQuery = $this->studentClassModel->query();
@@ -76,9 +73,9 @@ class AttendanceTrackingService
->orderByDesc('id')
->first();
if ($latestTerm && ! empty($latestTerm->school_year)) {
if ($latestTerm && !empty($latestTerm->school_year)) {
$schoolYear = (string) $latestTerm->school_year;
if (! empty($latestTerm->semester)) {
if (!empty($latestTerm->semester)) {
$semester = (string) $latestTerm->semester;
}
@@ -109,7 +106,7 @@ class AttendanceTrackingService
if (empty($studentIds) && empty($studentCodes)) {
$attendanceStudents = DB::table('attendance_data')
->selectRaw('DISTINCT student_id')
->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->orderBy('student_id')
->get();
@@ -126,7 +123,7 @@ class AttendanceTrackingService
$studentIds = array_values(array_unique(array_filter($studentIds, fn ($v) => $v > 0)));
$studentCodes = array_values(array_unique(array_filter($studentCodes, fn ($v) => $v !== '')));
if (! empty($studentIds)) {
if (!empty($studentIds)) {
$inactiveRows = $this->studentModel->query()
->select('id')
->whereIn('id', $studentIds)
@@ -141,11 +138,11 @@ class AttendanceTrackingService
$studentIds = array_values(array_filter(
$studentIds,
static fn ($id) => ! isset($inactiveIdSet[$id])
static fn ($id) => !isset($inactiveIdSet[$id])
));
}
if (! empty($studentCodes)) {
if (!empty($studentCodes)) {
$inactiveCodeRows = $this->studentModel->query()
->select('school_id')
->whereIn('school_id', $studentCodes)
@@ -160,7 +157,7 @@ class AttendanceTrackingService
$studentCodes = array_values(array_filter(
$studentCodes,
static fn ($code) => $code !== '' && ! isset($inactiveCodeSet[$code])
static fn ($code) => $code !== '' && !isset($inactiveCodeSet[$code])
));
}
@@ -177,7 +174,7 @@ class AttendanceTrackingService
}
$students = [];
if (! empty($studentIds)) {
if (!empty($studentIds)) {
$students = $this->studentModel->query()
->whereIn('id', $studentIds)
->where('is_active', 1)
@@ -185,7 +182,7 @@ class AttendanceTrackingService
->toArray();
}
if (! empty($studentCodes)) {
if (!empty($studentCodes)) {
$byCode = $this->studentModel->query()
->whereIn('school_id', $studentCodes)
->where('is_active', 1)
@@ -195,7 +192,7 @@ class AttendanceTrackingService
$seen = array_flip(array_map(fn ($s) => (int) ($s['id'] ?? 0), $students));
foreach ($byCode as $s) {
$sid = (int) ($s['id'] ?? 0);
if ($sid > 0 && ! isset($seen[$sid])) {
if ($sid > 0 && !isset($seen[$sid])) {
$students[] = $s;
$seen[$sid] = true;
}
@@ -211,7 +208,7 @@ class AttendanceTrackingService
}
foreach ($studentCodes as $code) {
if (! isset($knownCodes[$code])) {
if (!isset($knownCodes[$code])) {
$virtualId = abs(crc32($code)) ?: random_int(1000000, 1999999);
$students[] = [
'id' => $virtualId,
@@ -247,7 +244,7 @@ class AttendanceTrackingService
foreach (array_merge($studentIds, $studentCodes) as $sidOrCode) {
if (is_numeric($sidOrCode)) {
$sid = (int) $sidOrCode;
if ($sid > 0 && ! isset($existingIds[$sid])) {
if ($sid > 0 && !isset($existingIds[$sid])) {
$students[] = [
'id' => $sid,
'school_id' => (string) $sid,
@@ -260,7 +257,7 @@ class AttendanceTrackingService
}
} else {
$code = (string) $sidOrCode;
if ($code !== '' && ! isset($studentCodeToId[$code])) {
if ($code !== '' && !isset($studentCodeToId[$code])) {
$virtualId = abs(crc32($code)) ?: random_int(2000000, 2999999);
$students[] = [
'id' => $virtualId,
@@ -298,14 +295,14 @@ class AttendanceTrackingService
'is_reported',
'is_notified',
])
->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(! empty($semester), fn ($q) => $q->where('semester', $semester))
->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(!empty($semester), fn ($q) => $q->where('semester', $semester))
->where(function ($q) use ($studentIds, $studentCodes) {
if (! empty($studentIds)) {
if (!empty($studentIds)) {
$q->whereIn('student_id', $studentIds);
}
if (! empty($studentCodes)) {
if (! empty($studentIds)) {
if (!empty($studentCodes)) {
if (!empty($studentIds)) {
$q->orWhereIn('student_id', $studentCodes);
} else {
$q->whereIn('student_id', $studentCodes);
@@ -325,16 +322,16 @@ class AttendanceTrackingService
if (empty($termRows)) {
$latestAttendanceTerm = DB::table('attendance_data')
->select('school_year', 'semester', 'date')
->when(! empty($studentIds), fn ($q) => $q->whereIn('student_id', $studentIds))
->when(!empty($studentIds), fn ($q) => $q->whereIn('student_id', $studentIds))
->orderByDesc('date')
->first();
if ($latestAttendanceTerm) {
$schoolYear = ! empty($latestAttendanceTerm->school_year)
$schoolYear = !empty($latestAttendanceTerm->school_year)
? (string) $latestAttendanceTerm->school_year
: $schoolYear;
$semester = ! empty($latestAttendanceTerm->semester)
$semester = !empty($latestAttendanceTerm->semester)
? (string) $latestAttendanceTerm->semester
: $semester;
@@ -357,14 +354,14 @@ class AttendanceTrackingService
'is_reported',
'is_notified',
])
->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(! empty($semester), fn ($q) => $q->where('semester', $semester))
->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(!empty($semester), fn ($q) => $q->where('semester', $semester))
->where(function ($q) use ($studentIds, $studentCodes) {
if (! empty($studentIds)) {
if (!empty($studentIds)) {
$q->whereIn('student_id', $studentIds);
}
if (! empty($studentCodes)) {
if (! empty($studentIds)) {
if (!empty($studentCodes)) {
if (!empty($studentIds)) {
$q->orWhereIn('student_id', $studentCodes);
} else {
$q->whereIn('student_id', $studentCodes);
@@ -395,7 +392,7 @@ class AttendanceTrackingService
$attendanceRows = [];
foreach ($termRows as $row) {
$dStr = $row['date'] ?? null;
if (! $dStr) {
if (!$dStr) {
continue;
}
@@ -405,7 +402,7 @@ class AttendanceTrackingService
continue;
}
if ($d->lt($start) || ! $d->lt($endEx)) {
if ($d->lt($start) || !$d->lt($endEx)) {
continue;
}
@@ -421,7 +418,7 @@ class AttendanceTrackingService
if ($sid === null) {
$sid = abs(crc32($code)) ?: random_int(3000000, 3999999);
$studentCodeToId[$code] = $sid;
if (! isset($existingIds[$sid])) {
if (!isset($existingIds[$sid])) {
$students[] = [
'id' => $sid,
'school_id' => $code,
@@ -446,7 +443,7 @@ class AttendanceTrackingService
foreach ($attendanceRows as $arow) {
$sid = (int) ($arow['student_id'] ?? 0);
if ($sid > 0 && ! isset($existingIds[$sid])) {
if ($sid > 0 && !isset($existingIds[$sid])) {
$students[] = [
'id' => $sid,
'school_id' => (string) ($arow['student_code'] ?? $arow['student_id']),
@@ -498,13 +495,13 @@ class AttendanceTrackingService
$parentEmail = $data['parent_email'] ?? '';
$parentName = $data['parent_name'] ?? '';
if (! $parentEmail) {
if (!$parentEmail) {
$parent = $this->getPrimaryParentForStudent($sid) ?? [];
$parentEmail = $parent['email'] ?? '';
$parentName = $parent['parent_name'] ?? '';
}
if (! $parentEmail) {
if (!$parentEmail) {
return [
'success' => false,
'message' => 'No parent email found for this student.',
@@ -555,7 +552,7 @@ class AttendanceTrackingService
try {
$this->attendanceMailerService->queueAttendanceEvent($payload);
if ($row && ! empty($row['id']) && method_exists($this->attendanceTrackingModel, 'markAsNotified')) {
if ($row && !empty($row['id']) && method_exists($this->attendanceTrackingModel, 'markAsNotified')) {
$this->attendanceTrackingModel->markAsNotified((int) $row['id']);
}
@@ -565,7 +562,7 @@ class AttendanceTrackingService
'data' => $payload,
];
} catch (Throwable $e) {
Log::error('Attendance record queue failed: '.$e->getMessage());
Log::error('Attendance record queue failed: ' . $e->getMessage());
return [
'success' => false,
@@ -585,7 +582,7 @@ class AttendanceTrackingService
?string $semesterFilter = null
): array {
$student = $this->studentModel->query()->find($studentId);
if (! $student) {
if (!$student) {
return [
'success' => false,
'message' => 'Student not found',
@@ -594,7 +591,7 @@ class AttendanceTrackingService
}
$student = $student->toArray();
$student['name'] = trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? ''));
$student['name'] = trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? ''));
$codeParam = strtoupper((string) ($codeParam ?? ''));
$incidentDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) $incidentDate) ? (string) $incidentDate : '';
@@ -659,7 +656,7 @@ class AttendanceTrackingService
])
->where(function ($q) use ($studentIdValues, $studentCodeValues) {
$q->whereIn('student_id', $studentIdValues);
if (! empty($studentCodeValues)) {
if (!empty($studentCodeValues)) {
$q->orWhereIn('student_id', $studentCodeValues);
}
})
@@ -677,7 +674,7 @@ class AttendanceTrackingService
if ($pendingOnly) {
$this->applyUnreportedAttendanceFilter($qb);
if (! $includeNotified) {
if (!$includeNotified) {
$qb->whereRaw("(LOWER(TRIM(COALESCE(is_notified, ''))) NOT IN ('yes','1'))");
}
}
@@ -703,11 +700,11 @@ class AttendanceTrackingService
'semester' => $semester,
];
if ($data['violation_date'] === '' && ! empty($data['attendance'][0]['date'])) {
if ($data['violation_date'] === '' && !empty($data['attendance'][0]['date'])) {
$data['violation_date'] = substr((string) $data['attendance'][0]['date'], 0, 10);
}
if (! empty($data['attendance'][0]['is_notified'])) {
if (!empty($data['attendance'][0]['is_notified'])) {
$data['violation_notified'] = $data['attendance'][0]['is_notified'];
}
@@ -785,17 +782,15 @@ class AttendanceTrackingService
$to = trim((string) ($v['parent_email'] ?? ''));
$pname = (string) ($v['parent_name'] ?? '');
if ($sid <= 0 || ! $code || ! $date || ! $to) {
if ($sid <= 0 || !$code || !$date || !$to) {
$errors++;
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'missing data'];
continue;
}
if ($this->notificationAlreadySent($sid, $code, $date, 'email', $to)) {
$skipped++;
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'duplicate'];
continue;
}
@@ -816,7 +811,7 @@ class AttendanceTrackingService
$tpl = $this->renderTemplate($code, $variant, $context);
if (! $tpl) {
if (!$tpl) {
$subject = match ($code) {
'ABS_1' => 'Attendance Notice: Unreported Absence',
'LATE_2' => 'Attendance Notice: Repeated Lateness',
@@ -824,14 +819,14 @@ class AttendanceTrackingService
};
$studentName = (string) ($v['name'] ?? '');
$body = '<p>Dear '.($pname ?: 'Parent/Guardian').'</p>'
."<p>We'd like to inform you about your student's recent attendance:</p>"
.'<ul>'
."<li><strong>Student:</strong> {$studentName}</li>"
.'<li><strong>Issue:</strong> '.(string) ($v['violation'] ?? '').'</li>'
."<li><strong>As of:</strong> {$date}</li>"
.'</ul>'
.'<p>If you have any questions, please contact the school office.</p>';
$body = "<p>Dear " . ($pname ?: 'Parent/Guardian') . "</p>"
. "<p>We'd like to inform you about your student's recent attendance:</p>"
. "<ul>"
. "<li><strong>Student:</strong> {$studentName}</li>"
. "<li><strong>Issue:</strong> " . (string) ($v['violation'] ?? '') . "</li>"
. "<li><strong>As of:</strong> {$date}</li>"
. "</ul>"
. "<p>If you have any questions, please contact the school office.</p>";
} else {
[$subject, $body] = $tpl;
}
@@ -854,7 +849,7 @@ class AttendanceTrackingService
} catch (Throwable $e) {
$errors++;
$this->logNotification($sid, $code, $date, 'email', $to, $subject, 'failed', $e->getMessage());
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: '.$e->getMessage()];
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: ' . $e->getMessage()];
}
try {
@@ -880,7 +875,7 @@ class AttendanceTrackingService
}
} catch (Throwable $e) {
$errors++;
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: '.$e->getMessage()];
$details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: ' . $e->getMessage()];
}
if ($anyOk) {
@@ -900,10 +895,10 @@ class AttendanceTrackingService
$absDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['absences'] ?? []));
$lateDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['lates'] ?? []));
if (! empty($absDates)) {
if (!empty($absDates)) {
$allDates = array_merge($allDates, $absDates);
}
if (! empty($lateDates)) {
if (!empty($lateDates)) {
$allDates = array_merge($allDates, $lateDates);
}
if (empty($allDates)) {
@@ -1039,7 +1034,7 @@ class AttendanceTrackingService
foreach ($rows as $row) {
$sid = (int) ($row->student_id ?? 0);
if ($sid > 0 && ! isset($classByStudent[$sid])) {
if ($sid > 0 && !isset($classByStudent[$sid])) {
$classByStudent[$sid] = [
'class_section_id' => $row->class_section_id ?? null,
'class_section_name' => (string) ($row->class_section_name ?? ''),
@@ -1054,7 +1049,7 @@ class AttendanceTrackingService
$mergedData = [];
foreach ($trackingData as $row) {
$sid = (int) ($row['student_id'] ?? 0);
if (! isset($studentMap[$sid])) {
if (!isset($studentMap[$sid])) {
continue;
}
@@ -1062,7 +1057,7 @@ class AttendanceTrackingService
if (isset($classByStudent[$sid])) {
$merged['class_section_name'] = (string) ($classByStudent[$sid]['class_section_name'] ?? '');
$merged['class_name'] = (string) ($classByStudent[$sid]['class_name'] ?? '');
} elseif (! empty($merged['registration_grade'])) {
} elseif (!empty($merged['registration_grade'])) {
$merged['grade'] = (string) $merged['registration_grade'];
}
@@ -1106,7 +1101,7 @@ class AttendanceTrackingService
$violation = [
'id' => $studentId,
'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')),
'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
'last_date' => $lastDate,
'violation' => $code,
'violation_code' => $code,
@@ -1115,7 +1110,7 @@ class AttendanceTrackingService
$ctx = $this->buildTemplateContext($violation, $parent);
$rendered = $this->renderTemplate($code, $variant, $ctx);
if (! $rendered) {
if (!$rendered) {
return [
'success' => false,
'message' => "Template not found for {$code} ({$variant}).",
@@ -1193,7 +1188,7 @@ class AttendanceTrackingService
$sec = $this->getSecondaryParentForStudent($sid);
$to2 = trim((string) ($sec['email'] ?? ''));
if ($to2 !== '' && strcasecmp($to2, $to) !== 0) {
if (! $this->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) {
if (!$this->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) {
$ok2 = $this->attendanceMailerService->send($to2, $subject, $wrapped);
$this->logNotification(
$sid,
@@ -1211,7 +1206,7 @@ class AttendanceTrackingService
}
}
if (! $anyOk) {
if (!$anyOk) {
return [
'success' => false,
'message' => 'Failed to send email.',
@@ -1256,7 +1251,7 @@ class AttendanceTrackingService
return [
'success' => false,
'message' => 'Error: '.$e->getMessage(),
'message' => 'Error: ' . $e->getMessage(),
'status' => 500,
];
}
@@ -1278,7 +1273,7 @@ class AttendanceTrackingService
->where('id', $studentId)
->first();
if (! $stu) {
if (!$stu) {
return [
'success' => false,
'message' => 'Student not found',
@@ -1303,7 +1298,7 @@ class AttendanceTrackingService
] : null;
$pb = DB::table('parents')->where('firstparent_id', $primaryId);
if (! empty($schoolYear)) {
if (!empty($schoolYear)) {
$pb->where('school_year', $schoolYear);
}
@@ -1330,7 +1325,7 @@ class AttendanceTrackingService
}
}
if (! $secondary) {
if (!$secondary) {
$fallbackEmail = (string) ($pRow->secondparent_email ?? '');
$fallbackPhone = (string) ($pRow->secondparent_phone ?? '');
$fallbackFirst = (string) ($pRow->secondparent_firstname ?? '');
@@ -1356,7 +1351,7 @@ class AttendanceTrackingService
],
];
} catch (Throwable $e) {
Log::error('parentsInfo() failed: '.$e->getMessage());
Log::error('parentsInfo() failed: ' . $e->getMessage());
return [
'success' => false,
@@ -1384,11 +1379,11 @@ class AttendanceTrackingService
->where('school_year', $this->schoolYear)
->where('date', '>=', $start)
->where('date', '<', $end)
->where('reason', 'like', '%'.$code.'%')
->where('reason', 'like', '%' . $code . '%')
->orderByDesc('date')
->first();
if (! $row) {
if (!$row) {
$row = $this->attendanceTrackingModel->query()
->where('student_id', $sid)
->where('semester', $this->semester)
@@ -1399,7 +1394,7 @@ class AttendanceTrackingService
->first();
}
if ($row && ! empty($row->id)) {
if ($row && !empty($row->id)) {
DB::table($this->attendanceTrackingModel->getTable())
->where('id', (int) $row->id)
->update([
@@ -1431,7 +1426,7 @@ class AttendanceTrackingService
} catch (Throwable $e) {
return [
'success' => false,
'message' => 'Failed to save note: '.$e->getMessage(),
'message' => 'Failed to save note: ' . $e->getMessage(),
'status' => 500,
];
}
@@ -1455,14 +1450,13 @@ class AttendanceTrackingService
->where('incident_date', $ymd)
->where('channel', $channel);
if (! empty($to)) {
if (!empty($to)) {
$query->where('to_address', $to);
}
return $query->exists();
} catch (Throwable $e) {
Log::debug('notificationAlreadySent(): '.$e->getMessage());
Log::debug('notificationAlreadySent(): ' . $e->getMessage());
return false;
}
}
@@ -1485,7 +1479,7 @@ class AttendanceTrackingService
'channel' => $channel,
];
if (! empty($to)) {
if (!empty($to)) {
$where['to_address'] = $to;
}
@@ -1494,7 +1488,7 @@ class AttendanceTrackingService
->orderByDesc('id')
->first();
if ($existing && ! empty($existing->id)) {
if ($existing && !empty($existing->id)) {
$existing->update([
'subject' => $subject,
'status' => $status,
@@ -1518,7 +1512,7 @@ class AttendanceTrackingService
]);
}
} catch (Throwable $e) {
Log::debug('logNotification(): '.$e->getMessage());
Log::debug('logNotification(): ' . $e->getMessage());
}
}
@@ -1530,7 +1524,7 @@ class AttendanceTrackingService
->where('s.id', $studentId)
->first();
if (! $row || empty($row->user_id)) {
if (!$row || empty($row->user_id)) {
return null;
}
@@ -1550,7 +1544,7 @@ class AttendanceTrackingService
->where('id', $studentId)
->first();
if (! $stu) {
if (!$stu) {
return null;
}
@@ -1563,7 +1557,7 @@ class AttendanceTrackingService
}
$pRow = $pb->orderByDesc('updated_at')->first();
if (! $pRow) {
if (!$pRow) {
return null;
}
@@ -1574,11 +1568,11 @@ class AttendanceTrackingService
->where('id', $secondId)
->first();
if ($u2 && ! empty($u2->email)) {
if ($u2 && !empty($u2->email)) {
return [
'user_id' => (int) $u2->id,
'email' => (string) $u2->email,
'parent_name' => trim(($u2->firstname ?? '').' '.($u2->lastname ?? '')),
'parent_name' => trim(($u2->firstname ?? '') . ' ' . ($u2->lastname ?? '')),
'phone' => (string) ($u2->cellphone ?? ''),
];
}
@@ -1593,12 +1587,12 @@ class AttendanceTrackingService
return [
'user_id' => $secondId ?: null,
'email' => $fallbackEmail,
'parent_name' => trim($fallbackFirst.' '.$fallbackLast) ?: null,
'parent_name' => trim($fallbackFirst . ' ' . $fallbackLast) ?: null,
'phone' => $fallbackPhone,
];
}
} catch (Throwable $e) {
Log::error('getSecondaryParentForStudent() failed: '.$e->getMessage());
Log::error('getSecondaryParentForStudent() failed: ' . $e->getMessage());
}
return null;
@@ -1637,7 +1631,7 @@ class AttendanceTrackingService
$ymd = substr((string) ($r['date'] ?? ''), 0, 10);
$stat = strtolower(trim((string) ($r['status'] ?? '')));
if (! in_array($stat, ['absent', 'late'], true)) {
if (!in_array($stat, ['absent', 'late'], true)) {
continue;
}
@@ -1649,10 +1643,10 @@ class AttendanceTrackingService
[$syStart, $syEnd] = $this->deriveSchoolYearBounds($schoolYear);
$weekRowsSource = null;
if (! empty($weekRowsFallback)) {
if (!empty($weekRowsFallback)) {
foreach ($weekRowsFallback as $r) {
$st = strtolower(trim((string) ($r['status'] ?? '')));
if ($st !== '' && ! in_array($st, ['absent', 'late'], true)) {
if ($st !== '' && !in_array($st, ['absent', 'late'], true)) {
$weekRowsSource = $weekRowsFallback;
break;
}
@@ -1685,7 +1679,6 @@ class AttendanceTrackingService
}
$out = array_values(array_unique($out));
rsort($out);
return $out;
};
@@ -1696,7 +1689,7 @@ class AttendanceTrackingService
$students
)));
if (! empty($studentIdsForClass)) {
if (!empty($studentIdsForClass)) {
$rows = DB::table('student_class as sc')
->select([
'sc.student_id',
@@ -1714,7 +1707,7 @@ class AttendanceTrackingService
foreach ($rows as $row) {
$sid = (int) ($row->student_id ?? 0);
if ($sid > 0 && ! isset($classByStudent[$sid])) {
if ($sid > 0 && !isset($classByStudent[$sid])) {
$classByStudent[$sid] = [
'class_section_id' => $row->class_section_id ?? null,
'class_section_name' => (string) ($row->class_section_name ?? ''),
@@ -1725,7 +1718,7 @@ class AttendanceTrackingService
}
}
} catch (Throwable $e) {
Log::debug('computeViolations(): class prefetch failed: '.$e->getMessage());
Log::debug('computeViolations(): class prefetch failed: ' . $e->getMessage());
}
$out = [];
@@ -1734,7 +1727,7 @@ class AttendanceTrackingService
foreach ($students as $stu) {
$sid = (int) ($stu['id'] ?? 0);
$name = trim(($stu['firstname'] ?? '').' '.($stu['lastname'] ?? ''));
$name = trim(($stu['firstname'] ?? '') . ' ' . ($stu['lastname'] ?? ''));
$absDatesAll = array_values(array_unique($byStudent[$sid]['absent'] ?? []));
$lateDatesAll = array_values(array_unique($byStudent[$sid]['late'] ?? []));
@@ -1752,7 +1745,7 @@ class AttendanceTrackingService
$lateCountLast5 += count($lateDates);
$absenceViolation = null;
if (! empty($absDates)) {
if (!empty($absDates)) {
$lastAbsDate = $absDates[0];
$A2row = $this->hasNConsecutiveItems($absDates, 2, 7);
$A3row = $this->hasNConsecutiveItems($absDates, 3, 7);
@@ -1799,7 +1792,7 @@ class AttendanceTrackingService
}
$lateViolation = null;
if (! empty($lateDates)) {
if (!empty($lateDates)) {
$lastLateDate = $lateDates[0];
$L2row = $this->hasNConsecutiveItems($lateDates, 2, 7);
@@ -1814,7 +1807,7 @@ class AttendanceTrackingService
$lateWeeksSet = array_flip($lateWeekIdx);
$lateCoversAllWindowWeeks = true;
for ($i = $windowStartIdx; $i <= $currentWeekIdx; $i++) {
if (! isset($lateWeeksSet[$i])) {
if (!isset($lateWeeksSet[$i])) {
$lateCoversAllWindowWeeks = false;
break;
}
@@ -1865,7 +1858,7 @@ class AttendanceTrackingService
$chosen = $this->chooseHigherSeverity($absenceViolation, $lateViolation);
if (! $chosen && count($absDates) === 1) {
if (!$chosen && count($absDates) === 1) {
$chosen = [
'type' => 'absence',
'code' => 'ABS_1',
@@ -1878,7 +1871,7 @@ class AttendanceTrackingService
];
}
if (! $chosen) {
if (!$chosen) {
continue;
}
@@ -1890,7 +1883,7 @@ class AttendanceTrackingService
->where('school_year', $schoolYear)
->where('date', '>=', $start)
->where('date', '<', $end)
->where('reason', 'like', '%'.$chosen['code'].'%');
->where('reason', 'like', '%' . $chosen['code'] . '%');
if ($semester !== null) {
$trackingQ->where('semester', $semester);
@@ -1904,7 +1897,7 @@ class AttendanceTrackingService
$cls = $classByStudent[$sid] ?? [];
$classLabel = (string) ($cls['class_section_name'] ?? '');
if ($classLabel === '' && ! empty($cls['class_name'])) {
if ($classLabel === '' && !empty($cls['class_name'])) {
$classLabel = (string) $cls['class_name'];
}
@@ -1954,7 +1947,6 @@ class AttendanceTrackingService
if ($a && $b) {
if ($a['severity'] === $b['severity']) {
$prio = ['expel_notify' => 3, 'team_notify' => 2, 'auto_email' => 1];
return ($prio[$a['action']] ?? 0) >= ($prio[$b['action']] ?? 0) ? $a : $b;
}
@@ -1984,11 +1976,11 @@ class AttendanceTrackingService
{
$cols = $this->attendanceReportedColumns();
if (! empty($cols['is_reported'])) {
if (!empty($cols['is_reported'])) {
$qb->whereRaw("(LOWER(TRIM(COALESCE(is_reported, ''))) NOT IN ('yes','1','true','y','on'))");
}
if (! empty($cols['reported'])) {
if (!empty($cols['reported'])) {
$qb->whereRaw("(LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on'))");
}
@@ -2010,10 +2002,9 @@ class AttendanceTrackingService
protected function dayBounds(string $ymd): array
{
$d = substr($ymd, 0, 10);
return [
$d.' 00:00:00',
date('Y-m-d', strtotime($d.' +1 day')).' 00:00:00',
$d . ' 00:00:00',
date('Y-m-d', strtotime($d . ' +1 day')) . ' 00:00:00',
];
}
@@ -2033,10 +2024,9 @@ class AttendanceTrackingService
protected function deriveSchoolYearBounds(string $schoolYear): array
{
if (! preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) {
if (!preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) {
$y = (int) date('Y');
$startY = (int) (date('n') >= 8 ? $y : $y - 1);
return [sprintf('%d-08-01', $startY), sprintf('%d-07-31', $startY + 1)];
}
@@ -2076,7 +2066,7 @@ class AttendanceTrackingService
->where('is_active', 1)
->first();
if (! $row) {
if (!$row) {
$row = $this->attendanceEmailTemplateModel->query()
->where('code', $code)
->where('variant', 'default')
@@ -2087,7 +2077,7 @@ class AttendanceTrackingService
$row = $row?->toArray();
}
if (! $row) {
if (!$row) {
return null;
}
@@ -2145,10 +2135,10 @@ class AttendanceTrackingService
$semester = ($semester !== null && $semester !== '') ? (string) $semester : null;
$weeks = [];
if (! empty($weekRowsFallback)) {
if (!empty($weekRowsFallback)) {
foreach ($weekRowsFallback as $r) {
$d = $r['date'] ?? null;
if (! $d) {
if (!$d) {
continue;
}
$ts = strtotime($d);
@@ -2205,38 +2195,25 @@ class AttendanceTrackingService
}
$idx = array_keys($set);
sort($idx);
return $idx;
}
protected function windowWeeksForViolationCode(string $code): int
{
$code = strtoupper(trim($code));
if ($code === '') {
return 5;
}
if (Str::startsWith($code, 'ABS_2') || Str::startsWith($code, 'LATE_2')) {
return 3;
}
if (Str::startsWith($code, 'ABS_3') || Str::startsWith($code, 'LATE_3') || Str::startsWith($code, 'MIX')) {
return 4;
}
if (Str::startsWith($code, 'LATE_4')) {
return 4;
}
if (Str::startsWith($code, 'ABS_4')) {
return 5;
}
if ($code === '') return 5;
if (Str::startsWith($code, 'ABS_2') || Str::startsWith($code, 'LATE_2')) return 3;
if (Str::startsWith($code, 'ABS_3') || Str::startsWith($code, 'LATE_3') || Str::startsWith($code, 'MIX')) return 4;
if (Str::startsWith($code, 'LATE_4')) return 4;
if (Str::startsWith($code, 'ABS_4')) return 5;
return 5;
}
protected function isoWeekStartYmd(string $weekKey): string
{
if (preg_match('/^(\d{4})-W(\d{2})$/', $weekKey, $m)) {
return date('Y-m-d', strtotime($m[1].'-W'.$m[2].'-1'));
return date('Y-m-d', strtotime($m[1] . '-W' . $m[2] . '-1'));
}
return date('Y-m-d');
}
@@ -2257,15 +2234,14 @@ class AttendanceTrackingService
if (empty($activeWeekKeys)) {
$days = ($windowWeeks * 7) - 1;
return date('Y-m-d', strtotime($endBound.' -'.$days.' days'));
return date('Y-m-d', strtotime($endBound . ' -' . $days . ' days'));
}
$activeWeekKeys = array_values($activeWeekKeys);
$weekIndex = array_flip($activeWeekKeys);
$endWeekKey = date('o-\WW', strtotime($endBound));
if (! isset($weekIndex[$endWeekKey])) {
if (!isset($weekIndex[$endWeekKey])) {
$endWeekKey = null;
for ($i = count($activeWeekKeys) - 1; $i >= 0; $i--) {
$wkStart = $this->isoWeekStartYmd($activeWeekKeys[$i]);
@@ -2289,9 +2265,7 @@ class AttendanceTrackingService
protected function hasNConsecutiveItems(array $datesDesc, int $n, int $daysApart): bool
{
$N = count($datesDesc);
if ($N < $n) {
return false;
}
if ($N < $n) return false;
$dates = $datesDesc;
sort($dates);
@@ -2304,9 +2278,7 @@ class AttendanceTrackingService
if ($diff === $daysApart) {
$run++;
if ($run >= $n) {
return true;
}
if ($run >= $n) return true;
} else {
$run = 1;
}
@@ -2318,9 +2290,7 @@ class AttendanceTrackingService
protected function hasNInWActiveWeeks(array $weekIdx, int $n, int $w): bool
{
$N = count($weekIdx);
if ($N < $n) {
return false;
}
if ($N < $n) return false;
$l = 0;
for ($r = 0; $r < $N; $r++) {
@@ -2337,9 +2307,7 @@ class AttendanceTrackingService
protected function twoLatesOneAbsInWWeeks(array $lateIdx, array $absIdx, int $w): bool
{
if (count($lateIdx) < 2 || count($absIdx) < 1) {
return false;
}
if (count($lateIdx) < 2 || count($absIdx) < 1) return false;
$L = $lateIdx;
$A = $absIdx;
@@ -2354,7 +2322,6 @@ class AttendanceTrackingService
if ($L[$iL2] > $windowEnd) {
$iL1++;
$iL2 = $iL1 + 1;
continue;
}
@@ -2375,4 +2342,4 @@ class AttendanceTrackingService
return false;
}
}
}