fix attendance coemment in report card

This commit is contained in:
root
2026-05-30 17:12:10 -04:00
parent 95bcefc3a9
commit 090cb88573
+113 -17
View File
@@ -317,18 +317,27 @@ class ReportCardsController extends PrintablesBaseController
$examCommentTypes = $isSecond $examCommentTypes = $isSecond
? ['final'] ? ['final']
: ($isFirst ? ['midterm'] : ['midterm', 'final']); : ($isFirst ? ['midterm'] : ['midterm', 'final']);
$commentTypes = array_merge($examCommentTypes, ['ptap', 'attendance', 'attendance_comment']); $wantedCommentTypes = array_merge($examCommentTypes, ['ptap', 'attendance']);
$hasCommentReview = $this->db->fieldExists('comment_review', 'score_comments'); $hasCommentReview = $this->db->fieldExists('comment_review', 'score_comments');
$commentSelect = $hasCommentReview $hasCommentSemester = $this->db->fieldExists('semester', 'score_comments');
? 'student_id, score_type, comment, comment_review' $hasCommentUpdatedAt = $this->db->fieldExists('updated_at', 'score_comments');
: 'student_id, score_type, comment'; $commentSelectParts = ['student_id', 'score_type', 'comment'];
if ($hasCommentReview) {
$commentSelectParts[] = 'comment_review';
}
if ($hasCommentSemester) {
$commentSelectParts[] = 'semester';
}
// Do NOT filter comments by score_type or semester here.
// A single bad row like "Attendance Comment", "attendance-comment", or a blank semester
// should not make one student look incomplete while the PDF can still print the comment.
$commentBuilder = $this->scoreCommentModel $commentBuilder = $this->scoreCommentModel
->select($commentSelect) ->select(implode(', ', $commentSelectParts))
->whereIn('student_id', $studentIds) ->whereIn('student_id', $studentIds)
->where('school_year', $year) ->where('school_year', $year);
->whereIn('score_type', $commentTypes); if ($hasCommentUpdatedAt) {
if ($sem !== '') { $commentBuilder->orderBy('updated_at', 'DESC');
$this->applySemesterFilter($commentBuilder, $sem, 'semester');
} }
$commentRows = []; $commentRows = [];
try { try {
@@ -336,25 +345,92 @@ class ReportCardsController extends PrintablesBaseController
} catch (\Throwable $e) { } catch (\Throwable $e) {
} }
$cleanComment = static function ($value): string {
$text = (string)($value ?? '');
$text = str_replace("\xc2\xa0", ' ', $text); // normalize non-breaking spaces
return trim($text);
};
$normalizeCommentType = static function ($value) use ($cleanComment): string {
$type = strtolower($cleanComment($value));
$type = preg_replace('/[^a-z0-9]+/', '_', $type);
$type = trim((string)$type, '_');
$map = [
'attendance_comment' => 'attendance',
'attendance_comments' => 'attendance',
'attendance' => 'attendance',
'attendence' => 'attendance',
'attendence_comment' => 'attendance',
'attendence_comments' => 'attendance',
'ptap_comment' => 'ptap',
'ptap_comments' => 'ptap',
'ptap' => 'ptap',
'midterm_comment' => 'midterm',
'midterm_comments' => 'midterm',
'midterm' => 'midterm',
'final_comment' => 'final',
'final_comments' => 'final',
'final' => 'final',
];
return $map[$type] ?? $type;
};
$normalizeSemester = static function ($value) use ($cleanComment): string {
$v = strtolower($cleanComment($value));
$v = preg_replace('/[^a-z0-9]+/', ' ', $v);
$v = trim((string)$v);
if (in_array($v, ['fall', 'first', 'first semester', 'semester 1', '1'], true)) {
return 'fall';
}
if (in_array($v, ['spring', 'second', 'second semester', 'semester 2', '2'], true)) {
return 'spring';
}
return $v;
};
$wantedSemester = $normalizeSemester($sem);
$commentsByStudent = []; $commentsByStudent = [];
$commentPriorityByStudent = [];
foreach ($commentRows as $row) { foreach ($commentRows as $row) {
$sid = (int)($row['student_id'] ?? 0); $sid = (int)($row['student_id'] ?? 0);
if ($sid <= 0) { if ($sid <= 0) {
continue; continue;
} }
$typeRaw = strtolower(trim((string)($row['score_type'] ?? '')));
if ($typeRaw === '') { $typeRaw = $normalizeCommentType($row['score_type'] ?? '');
if ($typeRaw === '' || !in_array($typeRaw, $wantedCommentTypes, true)) {
continue; continue;
} }
if ($typeRaw === 'attendance_comment') {
$typeRaw = 'attendance'; $rawVal = $cleanComment($row['comment'] ?? '');
if ($typeRaw === 'attendance') {
// Attendance comments are stored in score_comments.comment.
// Do not use comment_review here, because it can be blank while the PDF comment exists.
$commentVal = $rawVal;
} else {
// For non-attendance comments, prefer reviewed text but fall back to the saved comment.
$reviewVal = $hasCommentReview ? $cleanComment($row['comment_review'] ?? '') : '';
$commentVal = $reviewVal !== '' ? $reviewVal : $rawVal;
} }
$reviewVal = $hasCommentReview ? trim((string)($row['comment_review'] ?? '')) : '';
$commentVal = $hasCommentReview ? $reviewVal : trim((string)($row['comment'] ?? ''));
if ($commentVal === '') { if ($commentVal === '') {
continue; continue;
} }
$rowSemester = $hasCommentSemester ? $normalizeSemester($row['semester'] ?? '') : '';
$priority = 1;
if ($wantedSemester !== '' && $rowSemester === $wantedSemester) {
$priority = 3;
} elseif ($rowSemester === '') {
$priority = 2;
}
$existingPriority = $commentPriorityByStudent[$sid][$typeRaw] ?? 0;
if (!isset($commentsByStudent[$sid][$typeRaw]) || $priority >= $existingPriority) {
$commentsByStudent[$sid][$typeRaw] = $commentVal; $commentsByStudent[$sid][$typeRaw] = $commentVal;
$commentPriorityByStudent[$sid][$typeRaw] = $priority;
}
} }
$isNumeric = static fn($v) => $v !== null && $v !== '' && is_numeric($v); $isNumeric = static fn($v) => $v !== null && $v !== '' && is_numeric($v);
@@ -467,6 +543,20 @@ class ReportCardsController extends PrintablesBaseController
if (trim((string)($commentSet['ptap'] ?? '')) === '') { if (trim((string)($commentSet['ptap'] ?? '')) === '') {
$missing[] = 'PTAP comment'; $missing[] = 'PTAP comment';
} }
// Keep completeness consistent with the PDF report generation:
// the report can auto-generate an attendance comment from attendance_score.
if (trim((string)($commentSet['attendance'] ?? '')) === '' && $isNumeric($attendanceScore)) {
$autoAttendance = attendance_comment_from_score(
(float)$attendanceScore,
trim((string)($student['firstname'] ?? ''))
);
if ($autoAttendance !== null && trim((string)$autoAttendance) !== '') {
$commentSet['attendance'] = $autoAttendance;
$warnings[] = 'Attendance comment computed from attendance score';
}
}
if (trim((string)($commentSet['attendance'] ?? '')) === '') { if (trim((string)($commentSet['attendance'] ?? '')) === '') {
$missing[] = 'Attendance comment'; $missing[] = 'Attendance comment';
} }
@@ -1531,10 +1621,16 @@ $scoresEndY = $pdf->GetY();
if ($typeRaw === 'attendance_comment') { if ($typeRaw === 'attendance_comment') {
$typeRaw = 'attendance'; $typeRaw = 'attendance';
} }
$rawComment = trim((string)($row['comment'] ?? ''));
if ($typeRaw === 'attendance') {
// Attendance comments must come from score_comments.comment.
$commentVal = $rawComment;
} else {
$reviewVal = trim((string)($row['comment_review'] ?? '')); $reviewVal = trim((string)($row['comment_review'] ?? ''));
$commentVal = $this->db->fieldExists('comment_review', 'score_comments') $commentVal = $this->db->fieldExists('comment_review', 'score_comments') && $reviewVal !== ''
? $reviewVal ? $reviewVal
: trim((string)($row['comment'] ?? '')); : $rawComment;
}
if ($commentVal === '') { if ($commentVal === '') {
continue; continue;
} }