Fix Pint formatting
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\AttendanceTracking;
|
||||
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 App\Models\AttendanceTracking;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\ParentNotification;
|
||||
use App\Models\Student;
|
||||
use App\Models\StudentClass;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -19,8 +19,11 @@ use Throwable;
|
||||
class AttendanceTrackingService
|
||||
{
|
||||
protected string $semester;
|
||||
|
||||
protected string $schoolYear;
|
||||
|
||||
protected array $debugCompute = [];
|
||||
|
||||
protected ?array $attendanceReportedColumns = null;
|
||||
|
||||
public function __construct(
|
||||
@@ -40,19 +43,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();
|
||||
@@ -73,9 +76,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;
|
||||
}
|
||||
|
||||
@@ -106,7 +109,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();
|
||||
|
||||
@@ -123,7 +126,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)
|
||||
@@ -138,11 +141,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)
|
||||
@@ -157,7 +160,7 @@ class AttendanceTrackingService
|
||||
|
||||
$studentCodes = array_values(array_filter(
|
||||
$studentCodes,
|
||||
static fn ($code) => $code !== '' && !isset($inactiveCodeSet[$code])
|
||||
static fn ($code) => $code !== '' && ! isset($inactiveCodeSet[$code])
|
||||
));
|
||||
}
|
||||
|
||||
@@ -174,7 +177,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
|
||||
$students = [];
|
||||
if (!empty($studentIds)) {
|
||||
if (! empty($studentIds)) {
|
||||
$students = $this->studentModel->query()
|
||||
->whereIn('id', $studentIds)
|
||||
->where('is_active', 1)
|
||||
@@ -182,7 +185,7 @@ class AttendanceTrackingService
|
||||
->toArray();
|
||||
}
|
||||
|
||||
if (!empty($studentCodes)) {
|
||||
if (! empty($studentCodes)) {
|
||||
$byCode = $this->studentModel->query()
|
||||
->whereIn('school_id', $studentCodes)
|
||||
->where('is_active', 1)
|
||||
@@ -192,7 +195,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;
|
||||
}
|
||||
@@ -208,7 +211,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,
|
||||
@@ -244,7 +247,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,
|
||||
@@ -257,7 +260,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,
|
||||
@@ -295,14 +298,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);
|
||||
@@ -322,16 +325,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;
|
||||
|
||||
@@ -354,14 +357,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);
|
||||
@@ -392,7 +395,7 @@ class AttendanceTrackingService
|
||||
$attendanceRows = [];
|
||||
foreach ($termRows as $row) {
|
||||
$dStr = $row['date'] ?? null;
|
||||
if (!$dStr) {
|
||||
if (! $dStr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -402,7 +405,7 @@ class AttendanceTrackingService
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($d->lt($start) || !$d->lt($endEx)) {
|
||||
if ($d->lt($start) || ! $d->lt($endEx)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -418,7 +421,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,
|
||||
@@ -443,7 +446,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']),
|
||||
@@ -495,13 +498,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.',
|
||||
@@ -552,7 +555,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']);
|
||||
}
|
||||
|
||||
@@ -562,7 +565,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,
|
||||
@@ -582,7 +585,7 @@ class AttendanceTrackingService
|
||||
?string $semesterFilter = null
|
||||
): array {
|
||||
$student = $this->studentModel->query()->find($studentId);
|
||||
if (!$student) {
|
||||
if (! $student) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Student not found',
|
||||
@@ -591,7 +594,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 : '';
|
||||
@@ -656,7 +659,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);
|
||||
}
|
||||
})
|
||||
@@ -674,7 +677,7 @@ class AttendanceTrackingService
|
||||
if ($pendingOnly) {
|
||||
$this->applyUnreportedAttendanceFilter($qb);
|
||||
|
||||
if (!$includeNotified) {
|
||||
if (! $includeNotified) {
|
||||
$qb->whereRaw("(LOWER(TRIM(COALESCE(is_notified, ''))) NOT IN ('yes','1'))");
|
||||
}
|
||||
}
|
||||
@@ -700,11 +703,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'];
|
||||
}
|
||||
|
||||
@@ -782,15 +785,17 @@ 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;
|
||||
}
|
||||
|
||||
@@ -811,7 +816,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',
|
||||
@@ -819,14 +824,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;
|
||||
}
|
||||
@@ -849,7 +854,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 {
|
||||
@@ -875,7 +880,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) {
|
||||
@@ -895,10 +900,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)) {
|
||||
@@ -1034,7 +1039,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 ?? ''),
|
||||
@@ -1049,7 +1054,7 @@ class AttendanceTrackingService
|
||||
$mergedData = [];
|
||||
foreach ($trackingData as $row) {
|
||||
$sid = (int) ($row['student_id'] ?? 0);
|
||||
if (!isset($studentMap[$sid])) {
|
||||
if (! isset($studentMap[$sid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1057,7 +1062,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'];
|
||||
}
|
||||
|
||||
@@ -1101,7 +1106,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,
|
||||
@@ -1110,7 +1115,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}).",
|
||||
@@ -1188,7 +1193,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,
|
||||
@@ -1206,7 +1211,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
}
|
||||
|
||||
if (!$anyOk) {
|
||||
if (! $anyOk) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Failed to send email.',
|
||||
@@ -1251,7 +1256,7 @@ class AttendanceTrackingService
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
'message' => 'Error: '.$e->getMessage(),
|
||||
'status' => 500,
|
||||
];
|
||||
}
|
||||
@@ -1273,7 +1278,7 @@ class AttendanceTrackingService
|
||||
->where('id', $studentId)
|
||||
->first();
|
||||
|
||||
if (!$stu) {
|
||||
if (! $stu) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Student not found',
|
||||
@@ -1298,7 +1303,7 @@ class AttendanceTrackingService
|
||||
] : null;
|
||||
|
||||
$pb = DB::table('parents')->where('firstparent_id', $primaryId);
|
||||
if (!empty($schoolYear)) {
|
||||
if (! empty($schoolYear)) {
|
||||
$pb->where('school_year', $schoolYear);
|
||||
}
|
||||
|
||||
@@ -1325,7 +1330,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
}
|
||||
|
||||
if (!$secondary) {
|
||||
if (! $secondary) {
|
||||
$fallbackEmail = (string) ($pRow->secondparent_email ?? '');
|
||||
$fallbackPhone = (string) ($pRow->secondparent_phone ?? '');
|
||||
$fallbackFirst = (string) ($pRow->secondparent_firstname ?? '');
|
||||
@@ -1351,7 +1356,7 @@ class AttendanceTrackingService
|
||||
],
|
||||
];
|
||||
} catch (Throwable $e) {
|
||||
Log::error('parentsInfo() failed: ' . $e->getMessage());
|
||||
Log::error('parentsInfo() failed: '.$e->getMessage());
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
@@ -1379,11 +1384,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)
|
||||
@@ -1394,7 +1399,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([
|
||||
@@ -1426,7 +1431,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,
|
||||
];
|
||||
}
|
||||
@@ -1450,13 +1455,14 @@ 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;
|
||||
}
|
||||
}
|
||||
@@ -1479,7 +1485,7 @@ class AttendanceTrackingService
|
||||
'channel' => $channel,
|
||||
];
|
||||
|
||||
if (!empty($to)) {
|
||||
if (! empty($to)) {
|
||||
$where['to_address'] = $to;
|
||||
}
|
||||
|
||||
@@ -1488,7 +1494,7 @@ class AttendanceTrackingService
|
||||
->orderByDesc('id')
|
||||
->first();
|
||||
|
||||
if ($existing && !empty($existing->id)) {
|
||||
if ($existing && ! empty($existing->id)) {
|
||||
$existing->update([
|
||||
'subject' => $subject,
|
||||
'status' => $status,
|
||||
@@ -1512,7 +1518,7 @@ class AttendanceTrackingService
|
||||
]);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Log::debug('logNotification(): ' . $e->getMessage());
|
||||
Log::debug('logNotification(): '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1524,7 +1530,7 @@ class AttendanceTrackingService
|
||||
->where('s.id', $studentId)
|
||||
->first();
|
||||
|
||||
if (!$row || empty($row->user_id)) {
|
||||
if (! $row || empty($row->user_id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1544,7 +1550,7 @@ class AttendanceTrackingService
|
||||
->where('id', $studentId)
|
||||
->first();
|
||||
|
||||
if (!$stu) {
|
||||
if (! $stu) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1557,7 +1563,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
|
||||
$pRow = $pb->orderByDesc('updated_at')->first();
|
||||
if (!$pRow) {
|
||||
if (! $pRow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1568,11 +1574,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 ?? ''),
|
||||
];
|
||||
}
|
||||
@@ -1587,12 +1593,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;
|
||||
@@ -1631,7 +1637,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;
|
||||
}
|
||||
|
||||
@@ -1643,10 +1649,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;
|
||||
}
|
||||
@@ -1679,6 +1685,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
$out = array_values(array_unique($out));
|
||||
rsort($out);
|
||||
|
||||
return $out;
|
||||
};
|
||||
|
||||
@@ -1689,7 +1696,7 @@ class AttendanceTrackingService
|
||||
$students
|
||||
)));
|
||||
|
||||
if (!empty($studentIdsForClass)) {
|
||||
if (! empty($studentIdsForClass)) {
|
||||
$rows = DB::table('student_class as sc')
|
||||
->select([
|
||||
'sc.student_id',
|
||||
@@ -1707,7 +1714,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 ?? ''),
|
||||
@@ -1718,7 +1725,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Log::debug('computeViolations(): class prefetch failed: ' . $e->getMessage());
|
||||
Log::debug('computeViolations(): class prefetch failed: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$out = [];
|
||||
@@ -1727,7 +1734,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'] ?? []));
|
||||
@@ -1745,7 +1752,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);
|
||||
@@ -1792,7 +1799,7 @@ class AttendanceTrackingService
|
||||
}
|
||||
|
||||
$lateViolation = null;
|
||||
if (!empty($lateDates)) {
|
||||
if (! empty($lateDates)) {
|
||||
$lastLateDate = $lateDates[0];
|
||||
|
||||
$L2row = $this->hasNConsecutiveItems($lateDates, 2, 7);
|
||||
@@ -1807,7 +1814,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;
|
||||
}
|
||||
@@ -1858,7 +1865,7 @@ class AttendanceTrackingService
|
||||
|
||||
$chosen = $this->chooseHigherSeverity($absenceViolation, $lateViolation);
|
||||
|
||||
if (!$chosen && count($absDates) === 1) {
|
||||
if (! $chosen && count($absDates) === 1) {
|
||||
$chosen = [
|
||||
'type' => 'absence',
|
||||
'code' => 'ABS_1',
|
||||
@@ -1871,7 +1878,7 @@ class AttendanceTrackingService
|
||||
];
|
||||
}
|
||||
|
||||
if (!$chosen) {
|
||||
if (! $chosen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1883,7 +1890,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);
|
||||
@@ -1897,7 +1904,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'];
|
||||
}
|
||||
|
||||
@@ -1947,6 +1954,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1976,11 +1984,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'))");
|
||||
}
|
||||
|
||||
@@ -2002,9 +2010,10 @@ 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',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2024,9 +2033,10 @@ 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)];
|
||||
}
|
||||
|
||||
@@ -2066,7 +2076,7 @@ class AttendanceTrackingService
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
|
||||
if (!$row) {
|
||||
if (! $row) {
|
||||
$row = $this->attendanceEmailTemplateModel->query()
|
||||
->where('code', $code)
|
||||
->where('variant', 'default')
|
||||
@@ -2077,7 +2087,7 @@ class AttendanceTrackingService
|
||||
$row = $row?->toArray();
|
||||
}
|
||||
|
||||
if (!$row) {
|
||||
if (! $row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2135,10 +2145,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);
|
||||
@@ -2195,25 +2205,38 @@ 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');
|
||||
}
|
||||
|
||||
@@ -2234,14 +2257,15 @@ 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]);
|
||||
@@ -2265,7 +2289,9 @@ 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);
|
||||
@@ -2278,7 +2304,9 @@ class AttendanceTrackingService
|
||||
|
||||
if ($diff === $daysApart) {
|
||||
$run++;
|
||||
if ($run >= $n) return true;
|
||||
if ($run >= $n) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$run = 1;
|
||||
}
|
||||
@@ -2290,7 +2318,9 @@ 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++) {
|
||||
@@ -2307,7 +2337,9 @@ 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;
|
||||
@@ -2322,6 +2354,7 @@ class AttendanceTrackingService
|
||||
if ($L[$iL2] > $windowEnd) {
|
||||
$iL1++;
|
||||
$iL2 = $iL1 + 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2342,4 +2375,4 @@ class AttendanceTrackingService
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user