Fix semester context, attendance rosters, and billing workflows
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 31s
Tests / PHPUnit (push) Failing after 55s

- load global semester helpers consistently and use date-based semester defaults
- fix grading and daily attendance duplicate student/section rows
- keep attendance violations scoped to the current semester by default
- update invoice, refund, discount, payment, and financial aid flows
- add configuration cleanup migrations for duplicate calendar/semester keys
- refresh parent registration/report-card and print request handling
- update related models, services, views, cron notes, and test coverage
This commit is contained in:
root
2026-08-16 17:41:11 -04:00
parent 36c7e3fc6d
commit 0ac3a8375e
99 changed files with 1598 additions and 814 deletions
+11 -5
View File
@@ -63,7 +63,7 @@ class AttendanceController extends Controller
$this->calendarModel = model(CalendarModel::class);
$this->userRoleModel = new UserRoleModel();
$this->semesterScoreService = service('semesterScoreService');
$this->semester = $this->configModel->getConfig('semester');
$this->semester = getSemester();
$this->schoolYear = $this->currentSchoolYearName();
$this->enableAttendance = $this->configModel->getConfig('enable_attendance');
$this->semesterRangeService = new SemesterRangeService($this->configModel);
@@ -534,19 +534,19 @@ public function showUpdateAttendanceForm()
// If there are no assignments yet for the requested semester (e.g., Spring roster not populated),
// fall back to the school year only so the roster still renders and can be used for the new term.
$classSections = $this->classSectionModel
->select('classSection.id, classSection.class_id, classSection.class_section_id, classSection.class_section_name')
->select('MIN(classSection.id) AS id, classSection.class_id, classSection.class_section_id, classSection.class_section_name', false)
->join('student_class sc', 'sc.class_section_id = classSection.class_section_id', 'inner')
->where('sc.school_year', $termYear)
->groupBy(['classSection.id', 'classSection.class_id', 'classSection.class_section_id', 'classSection.class_section_name'])
->groupBy(['classSection.class_id', 'classSection.class_section_id', 'classSection.class_section_name'])
->findAll();
$useRosterFallback = false;
if (empty($classSections) && $termYear !== '') {
$classSections = $this->classSectionModel
->select('classSection.id, classSection.class_id, classSection.class_section_id, classSection.class_section_name')
->select('MIN(classSection.id) AS id, classSection.class_id, classSection.class_section_id, classSection.class_section_name', false)
->join('student_class sc', 'sc.class_section_id = classSection.class_section_id', 'inner')
->where('sc.school_year', $termYear)
->groupBy(['classSection.id', 'classSection.class_id', 'classSection.class_section_id', 'classSection.class_section_name'])
->groupBy(['classSection.class_id', 'classSection.class_section_id', 'classSection.class_section_name'])
->findAll();
$useRosterFallback = !empty($classSections);
}
@@ -588,9 +588,15 @@ public function showUpdateAttendanceForm()
}
$hasRoster = false;
$seenStudentIds = [];
foreach ($students as $sc) {
$studentId = (int)$sc['student_id'];
if ($studentId <= 0 || isset($seenStudentIds[$studentId])) {
continue;
}
$seenStudentIds[$studentId] = true;
$student = $this->studentModel
->select('id, firstname, lastname, school_id')
->where('id', $studentId)