fix delibration and below 60

This commit is contained in:
root
2026-05-30 15:00:16 -04:00
parent 89913d7473
commit f24f4311e8
9 changed files with 333 additions and 160 deletions
+200 -73
View File
@@ -1068,37 +1068,67 @@ class GradingController extends Controller
return $scores;
}
public function belowSixty()
{
$configuredYear = (string) $this->schoolYear;
public function belowSixty()
{
$configuredYear = (string) $this->schoolYear;
$requestedSemester = strtolower(trim((string)($this->request->getGet('semester') ?? '')));
$requestedYear = trim((string)($this->request->getGet('school_year') ?? ''));
$schoolYear = trim((string)($this->request->getGet('school_year') ?? ''));
// This page intentionally supports only Fall and Whole Year.
// Spring is still used internally for the Whole Year calculation, but it is not selectable here.
$isYearMode = ($requestedSemester === 'year');
$semester = $isYearMode ? 'year' : 'Fall';
$schoolYear = $requestedYear !== '' ? $requestedYear : $configuredYear;
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
$canViewGrading = $this->userHasMenuUrl('grading');
return view('grading/below_sixty', [
'rows' => $rows,
'semester' => $semester,
'schoolYear' => $schoolYear,
'schoolYears' => $schoolYears,
'canViewGrading' => $canViewGrading,
'isYearMode' => $isYearMode,
'semesterOptions' => ['Fall'],
'showAllSemesterOption' => true,
]);
if ($schoolYear === '') {
$schoolYear = $configuredYear;
}
// This page is Fall only.
$semester = 'fall';
$isYearMode = false;
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
/*
* Use your existing below-60 fetcher.
* Do NOT query below_sixty_status. That table does not exist.
*/
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
/*
* Hard guard:
* Keep only Fall semester rows with semester_score < 60.
* This prevents whole-year rows or accidental other semester rows
* from sneaking into this Fall-only page.
*/
$rows = array_values(array_filter($rows, static function ($row) {
$semesterValue = strtolower(trim((string)($row['semester'] ?? 'fall')));
$scoreRaw = $row['semester_score'] ?? null;
if ($semesterValue !== '' && $semesterValue !== 'fall') {
return false;
}
if (!is_numeric($scoreRaw)) {
return false;
}
return (float)$scoreRaw < 60;
}));
foreach ($rows as &$row) {
$row['status'] = $row['status'] ?? 'Open';
$row['note'] = $row['note'] ?? '';
}
unset($row);
$canViewGrading = $this->userHasMenuUrl('grading');
return view('grading/below_sixty', [
'rows' => $rows,
'semester' => $semester,
'schoolYear' => $schoolYear,
'schoolYears' => $schoolYears,
'isYearMode' => $isYearMode,
'canViewGrading' => $canViewGrading,
]);
}
public function editBelowSixtyEmail()
{
$studentId = (int)$this->request->getGet('student_id');
@@ -2298,87 +2328,185 @@ class GradingController extends Controller
return 50000;
}
public function belowSixtyDecisions()
public function belowSixtyDecisions()
{
$configuredSemester = (string) $this->semester;
$configuredYear = (string) $this->schoolYear;
$configuredYear = (string) $this->schoolYear;
$semester = trim((string)($this->request->getGet('semester') ?? ''));
$schoolYear = trim((string)($this->request->getGet('school_year') ?? ''));
if ($semester === '') {
$semester = $configuredSemester !== '' ? $configuredSemester : 'Fall';
}
if ($schoolYear === '') {
$schoolYear = $configuredYear;
}
// This page is whole-year only.
$semester = 'year';
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
$studentIds = array_values(array_unique(array_filter(
array_map(static fn($r) => (int)($r['student_id'] ?? 0), $rows),
static fn($id) => $id > 0
)));
$db = $this->db;
// ── Load manual below-60 semester decisions ─────────────────────────────
//
// This table still uses semester, because below-60 decisions are tied to
// the selected below-60 screen/term.
$decisionModel = new BelowSixtyDecisionModel();
/*
* Whole-year score source:
* Fall semester_score + Spring semester_score / 2
*
* Only students with BOTH Fall and Spring scores are included.
* Only students with year_score < 60 are listed.
*/
$scoreRows = $db->table('semester_scores ss')
->select([
's.id AS student_id',
's.firstname',
's.lastname',
's.school_id',
'cs.class_section_name',
'LOWER(TRIM(ss.semester)) AS sem_key',
'ss.semester_score',
])
->join('students s', 's.id = ss.student_id', 'inner')
->join('classSection cs', 'cs.class_section_id = ss.class_section_id', 'left')
->where('s.is_active', 1)
->where('ss.school_year', $schoolYear)
->whereIn('LOWER(TRIM(ss.semester))', ['fall', 'spring'])
->where('ss.semester_score IS NOT NULL', null, false)
->orderBy('cs.class_section_name', 'ASC')
->orderBy('s.lastname', 'ASC')
->orderBy('s.firstname', 'ASC')
->get()
->getResultArray();
$decisionMap = [];
$studentMap = [];
if (!empty($studentIds)) {
$dRows = $decisionModel
->whereIn('student_id', $studentIds)
->where('semester', $semester)
->where('school_year', $schoolYear)
->findAll();
foreach ($scoreRows as $row) {
$sid = (int)($row['student_id'] ?? 0);
foreach ($dRows as $d) {
$decisionMap[(int)$d['student_id']] = $d;
if ($sid <= 0) {
continue;
}
if (!isset($studentMap[$sid])) {
$studentMap[$sid] = [
'student_id' => $sid,
'school_id' => $row['school_id'] ?? '',
'firstname' => $row['firstname'] ?? '',
'lastname' => $row['lastname'] ?? '',
'class_section_name' => $row['class_section_name'] ?? '',
'fall_score' => null,
'spring_score' => null,
'year_score' => null,
];
}
$semKey = strtolower(trim((string)($row['sem_key'] ?? '')));
$score = is_numeric($row['semester_score']) ? (float)$row['semester_score'] : null;
if ($score === null) {
continue;
}
if ($semKey === 'fall') {
$studentMap[$sid]['fall_score'] = $score;
} elseif ($semKey === 'spring') {
$studentMap[$sid]['spring_score'] = $score;
}
}
foreach ($rows as &$row) {
$sid = (int)($row['student_id'] ?? 0);
$rows = [];
foreach ($studentMap as $sid => $student) {
$fall = $student['fall_score'];
$spring = $student['spring_score'];
// Whole-year result requires both semesters.
if ($fall === null || $spring === null) {
continue;
}
$yearScore = round(($fall + $spring) / 2, 2);
if ($yearScore >= 60) {
continue;
}
$student['year_score'] = $yearScore;
$rows[$sid] = $student;
}
$studentIds = array_keys($rows);
/*
* Load saved below-60 manual decisions.
* These are year-level decisions now.
*/
$decisionMap = [];
if (!empty($studentIds)) {
$belowDecModel = new BelowSixtyDecisionModel();
$decisionRows = $belowDecModel
->whereIn('student_id', $studentIds)
->where('semester', 'year')
->where('school_year', $schoolYear)
->findAll();
foreach ($decisionRows as $d) {
$sid = (int)($d['student_id'] ?? 0);
if ($sid > 0) {
$decisionMap[$sid] = $d;
}
}
}
foreach ($rows as $sid => &$row) {
$row['decision'] = $decisionMap[$sid]['decision'] ?? '';
$row['decision_notes'] = $decisionMap[$sid]['notes'] ?? '';
}
unset($row);
// ── Load consolidated YEAR decisions from student_decisions ─────────────
//
// IMPORTANT:
// student_decisions no longer has semester or semester_score.
// It is now one row per student per school_year using year_score.
$sdMap = [];
/*
* Load final generated whole-year decisions from student_decisions.
* This table is now year-based, so do NOT filter by semester.
*/
$finalDecisionMap = [];
if (!empty($studentIds)) {
$sdRows = $this->db->table('student_decisions')
$finalRows = $db->table('student_decisions')
->whereIn('student_id', $studentIds)
->where('school_year', $schoolYear)
->get()
->getResultArray();
foreach ($sdRows as $sd) {
$sid = (int)($sd['student_id'] ?? 0);
foreach ($finalRows as $fr) {
$sid = (int)($fr['student_id'] ?? 0);
if ($sid > 0) {
$sdMap[$sid] = $sd;
$finalDecisionMap[$sid] = $fr;
}
}
}
// ── Load the most recent certificate per student for this school year ───
foreach ($rows as $sid => &$row) {
$row['consolidated_decision'] = $finalDecisionMap[$sid]['decision'] ?? null;
if (
isset($finalDecisionMap[$sid]['year_score'])
&& $finalDecisionMap[$sid]['year_score'] !== ''
&& is_numeric($finalDecisionMap[$sid]['year_score'])
) {
$row['year_score'] = round((float)$finalDecisionMap[$sid]['year_score'], 2);
}
}
unset($row);
/*
* Load certificate numbers.
*/
$certMap = [];
if (!empty($studentIds)) {
$certRows = $this->db->table('certificate_records')
$certRows = $db->table('certificate_records')
->select('student_id, certificate_number, issued_at')
->where('school_year', $schoolYear)
->whereIn('student_id', $studentIds)
@@ -2395,16 +2523,15 @@ class GradingController extends Controller
}
}
foreach ($rows as &$row) {
$sid = (int)($row['student_id'] ?? 0);
$row['consolidated_decision'] = $sdMap[$sid]['decision'] ?? null;
$row['year_score'] = $sdMap[$sid]['year_score'] ?? null;
$row['certificate_number'] = $certMap[$sid] ?? '';
foreach ($rows as $sid => &$row) {
$row['certificate_number'] = $certMap[$sid] ?? '';
}
unset($row);
// Re-index for the view.
$rows = array_values($rows);
$canViewGrading = $this->userHasMenuUrl('grading');
return view('grading/below_sixty_decisions', [