This commit is contained in:
@@ -699,7 +699,10 @@ class AdministratorController extends BaseController
|
||||
public function teacherSubmissionsReport()
|
||||
{
|
||||
$semester = (string)($this->configModel->getConfig('semester') ?? $this->semester ?? '');
|
||||
$schoolYear = (string)($this->configModel->getConfig('school_year') ?? $this->schoolYear ?? '');
|
||||
$schoolYear = trim((string) ($this->request->getGet('school_year') ?? ''));
|
||||
if ($schoolYear === '') {
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
}
|
||||
$semesterResolver = new SemesterRangeService($this->configModel);
|
||||
$semesterNorm = $semesterResolver->normalizeSemester($semester);
|
||||
$semesterFilter = $semesterNorm !== '' ? $semesterNorm : $semester;
|
||||
@@ -1099,9 +1102,9 @@ class AdministratorController extends BaseController
|
||||
}
|
||||
|
||||
$semesterResolver = new SemesterRangeService($this->configModel);
|
||||
$schoolYear = (string)($this->configModel->getConfig('school_year') ?? '');
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
$semester = (string)($this->configModel->getConfig('semester') ?? '');
|
||||
$schoolYearForRange = $schoolYear !== '' ? $schoolYear : (string)($this->configModel->getConfig('school_year') ?? '');
|
||||
$schoolYearForRange = $schoolYear !== '' ? $schoolYear : $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
[$rangeStart, $rangeEnd] = $semesterResolver->getSchoolYearRange($schoolYearForRange);
|
||||
$semesterNorm = $semesterResolver->normalizeSemester($semester);
|
||||
if ($semesterNorm !== '' && $schoolYearForRange !== '') {
|
||||
@@ -2295,22 +2298,10 @@ class AdministratorController extends BaseController
|
||||
public function showEnrollmentWithdrawalPage()
|
||||
{
|
||||
try {
|
||||
$selectedYear = trim((string)($this->request->getGet('schoolYear') ?? ''));
|
||||
if ($selectedYear === '') {
|
||||
$selectedYear = (string)$this->schoolYear;
|
||||
}
|
||||
$schoolYears = $this->availableSchoolYears();
|
||||
$selectedYear = $this->selectedEnrollmentSchoolYear($schoolYears);
|
||||
|
||||
// Distinct school years from enrollments (for selector)
|
||||
$yearsRows = $this->db->table('enrollments')
|
||||
->distinct()
|
||||
->select('school_year')
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()->getResultArray();
|
||||
$schoolYears = array_values(array_filter(array_map(static function ($r) {
|
||||
return isset($r['school_year']) ? (string)$r['school_year'] : null;
|
||||
}, $yearsRows)));
|
||||
|
||||
$students = $this->studentModel->getStudentsWithClassAndEnrollment();
|
||||
$students = $this->studentModel->getStudentsWithClassAndEnrollment($selectedYear);
|
||||
|
||||
$selectedStartYear = $this->getSchoolYearStartYear((string)$selectedYear);
|
||||
$removedPriorIds = [];
|
||||
@@ -2326,6 +2317,7 @@ class AdministratorController extends BaseController
|
||||
}
|
||||
}
|
||||
}
|
||||
$returningStudentIds = $this->priorYearStudentIds($selectedYear);
|
||||
|
||||
foreach ($students as &$s) {
|
||||
// ===== Ensure IDs needed by the modal =====
|
||||
@@ -2360,6 +2352,9 @@ class AdministratorController extends BaseController
|
||||
|
||||
// ===== New-student flags =====
|
||||
$s['is_new'] = (int) ($s['is_new'] ?? 0);
|
||||
if (isset($returningStudentIds[$s['student_id']])) {
|
||||
$s['is_new'] = 0;
|
||||
}
|
||||
$s['new_student'] = $s['is_new'] === 1 ? 'Yes' : 'No';
|
||||
|
||||
// ===== Admission override =====
|
||||
@@ -2369,6 +2364,9 @@ class AdministratorController extends BaseController
|
||||
$s['enrollment_status'] = $statusForYear;
|
||||
} elseif (($s['admission_status'] ?? null) === 'denied') {
|
||||
$s['enrollment_status'] = 'denied';
|
||||
} else {
|
||||
$s['enrollment_status'] = 'admission under review';
|
||||
$s['admission_status'] = 'pending';
|
||||
}
|
||||
|
||||
// ===== Class section name for the selected year =====
|
||||
@@ -2396,22 +2394,7 @@ class AdministratorController extends BaseController
|
||||
return strcasecmp($pa, $pb);
|
||||
});
|
||||
|
||||
// ===== Provide classes for the modal select (like studentClassAssignment) =====
|
||||
// Filter to current term; loosen if your table doesn’t store these fields.
|
||||
$classes = $this->classSectionModel
|
||||
->select('id, class_section_id, class_section_name, school_year, semester')
|
||||
->where('school_year', (string)$selectedYear)
|
||||
->where('semester', (string)$this->semester)
|
||||
->orderBy('class_section_name', 'ASC')
|
||||
->findAll();
|
||||
|
||||
// Fallback so the dropdown never shows empty if filters are too strict
|
||||
if (empty($classes)) {
|
||||
$classes = $this->classSectionModel
|
||||
->select('id, class_section_id, class_section_name')
|
||||
->orderBy('class_section_name', 'ASC')
|
||||
->findAll();
|
||||
}
|
||||
$classes = $this->enrollmentClassOptions((string)$selectedYear);
|
||||
|
||||
return view('enroll_withdraw/enrollment_withdrawal', [
|
||||
'students' => $students,
|
||||
@@ -2432,22 +2415,10 @@ class AdministratorController extends BaseController
|
||||
public function enrollmentWithdrawalData()
|
||||
{
|
||||
try {
|
||||
$selectedYear = trim((string)($this->request->getGet('schoolYear') ?? ''));
|
||||
if ($selectedYear === '') {
|
||||
$selectedYear = (string)$this->schoolYear;
|
||||
}
|
||||
$schoolYears = $this->availableSchoolYears();
|
||||
$selectedYear = $this->selectedEnrollmentSchoolYear($schoolYears);
|
||||
|
||||
// Distinct school years
|
||||
$yearsRows = $this->db->table('enrollments')
|
||||
->distinct()
|
||||
->select('school_year')
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()->getResultArray();
|
||||
$schoolYears = array_values(array_filter(array_map(static function ($r) {
|
||||
return isset($r['school_year']) ? (string)$r['school_year'] : null;
|
||||
}, $yearsRows)));
|
||||
|
||||
$students = $this->studentModel->getStudentsWithClassAndEnrollment();
|
||||
$students = $this->studentModel->getStudentsWithClassAndEnrollment($selectedYear);
|
||||
|
||||
$selectedStartYear = $this->getSchoolYearStartYear((string)$selectedYear);
|
||||
$removedPriorIds = [];
|
||||
@@ -2463,6 +2434,7 @@ class AdministratorController extends BaseController
|
||||
}
|
||||
}
|
||||
}
|
||||
$returningStudentIds = $this->priorYearStudentIds($selectedYear);
|
||||
|
||||
foreach ($students as &$s) {
|
||||
$s['student_id'] = (int)($s['id'] ?? 0);
|
||||
@@ -2485,6 +2457,9 @@ class AdministratorController extends BaseController
|
||||
$s['parent_sort'] = trim(($pl !== '' ? $pl : $pf) . ' ' . $pf) ?: 'ZZZ Unknown Parent';
|
||||
|
||||
$s['is_new'] = (int) ($s['is_new'] ?? 0);
|
||||
if (isset($returningStudentIds[$s['student_id']])) {
|
||||
$s['is_new'] = 0;
|
||||
}
|
||||
$s['new_student'] = $s['is_new'] === 1 ? 'Yes' : 'No';
|
||||
|
||||
$statusForYear = $this->enrollmentModel->getEnrollmentStatus((int)$s['student_id'], $selectedYear);
|
||||
@@ -2492,6 +2467,9 @@ class AdministratorController extends BaseController
|
||||
$s['enrollment_status'] = $statusForYear;
|
||||
} elseif (($s['admission_status'] ?? null) === 'denied') {
|
||||
$s['enrollment_status'] = 'denied';
|
||||
} else {
|
||||
$s['enrollment_status'] = 'admission under review';
|
||||
$s['admission_status'] = 'pending';
|
||||
}
|
||||
|
||||
$className = $this->studentClassModel->getClassSectionsByStudentId((int)$s['student_id'], $selectedYear);
|
||||
@@ -2516,18 +2494,7 @@ class AdministratorController extends BaseController
|
||||
return strcasecmp($pa, $pb);
|
||||
});
|
||||
|
||||
$classes = $this->classSectionModel
|
||||
->select('id, class_section_id, class_section_name, school_year, semester')
|
||||
->where('school_year', (string)$selectedYear)
|
||||
->where('semester', (string)$this->semester)
|
||||
->orderBy('class_section_name', 'ASC')
|
||||
->findAll();
|
||||
if (empty($classes)) {
|
||||
$classes = $this->classSectionModel
|
||||
->select('id, class_section_id, class_section_name')
|
||||
->orderBy('class_section_name', 'ASC')
|
||||
->findAll();
|
||||
}
|
||||
$classes = $this->enrollmentClassOptions((string)$selectedYear);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'students' => $students,
|
||||
@@ -2543,6 +2510,138 @@ class AdministratorController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
private function availableSchoolYears(): array
|
||||
{
|
||||
$years = [];
|
||||
$addYear = static function (mixed $value) use (&$years): void {
|
||||
$year = trim((string) $value);
|
||||
if ($year !== '' && !in_array($year, $years, true)) {
|
||||
$years[] = $year;
|
||||
}
|
||||
};
|
||||
|
||||
$addYear($this->schoolYear ?? null);
|
||||
|
||||
if ($this->db->tableExists('school_years')) {
|
||||
$rows = $this->db->table('school_years')
|
||||
->select('name')
|
||||
->orderBy('name', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$addYear($row['name'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('enrollments')) {
|
||||
$rows = $this->db->table('enrollments')
|
||||
->distinct()
|
||||
->select('school_year')
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$addYear($row['school_year'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
usort($years, static fn(string $a, string $b): int => strnatcasecmp($b, $a));
|
||||
|
||||
$activeYear = trim((string) ($this->schoolYear ?? ''));
|
||||
if ($activeYear !== '') {
|
||||
$years = array_values(array_filter($years, static fn(string $year): bool => $year !== $activeYear));
|
||||
array_unshift($years, $activeYear);
|
||||
}
|
||||
|
||||
return $years;
|
||||
}
|
||||
|
||||
private function selectedEnrollmentSchoolYear(array $schoolYears): string
|
||||
{
|
||||
$requestedYear = trim((string) ($this->request->getGet('schoolYear') ?? ''));
|
||||
if ($requestedYear !== '' && in_array($requestedYear, $schoolYears, true)) {
|
||||
return $requestedYear;
|
||||
}
|
||||
|
||||
$activeYear = trim((string) ($this->schoolYear ?? ''));
|
||||
if ($activeYear !== '') {
|
||||
return $activeYear;
|
||||
}
|
||||
|
||||
return (string) ($schoolYears[0] ?? '');
|
||||
}
|
||||
|
||||
private function enrollmentClassOptions(string $selectedYear): array
|
||||
{
|
||||
$select = ['id', 'class_section_id', 'class_section_name'];
|
||||
$hasSchoolYear = $this->db->fieldExists('school_year', 'classSection');
|
||||
$hasSemester = $this->db->fieldExists('semester', 'classSection');
|
||||
|
||||
if ($hasSchoolYear) {
|
||||
$select[] = 'school_year';
|
||||
}
|
||||
if ($hasSemester) {
|
||||
$select[] = 'semester';
|
||||
}
|
||||
|
||||
$query = $this->classSectionModel
|
||||
->select(implode(', ', $select))
|
||||
->orderBy('class_section_name', 'ASC');
|
||||
|
||||
if ($hasSchoolYear && $selectedYear !== '') {
|
||||
$query->where('school_year', $selectedYear);
|
||||
}
|
||||
if ($hasSemester) {
|
||||
$query->where('semester', (string)$this->semester);
|
||||
}
|
||||
|
||||
$classes = $query->findAll();
|
||||
|
||||
if (! empty($classes) || (! $hasSchoolYear && ! $hasSemester)) {
|
||||
return $classes;
|
||||
}
|
||||
|
||||
return $this->classSectionModel
|
||||
->select('id, class_section_id, class_section_name')
|
||||
->orderBy('class_section_name', 'ASC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
private function priorYearStudentIds(string $selectedYear): array
|
||||
{
|
||||
$selectedStartYear = $this->getSchoolYearStartYear($selectedYear);
|
||||
if ($selectedStartYear === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$studentIds = [];
|
||||
foreach (['enrollments', 'student_class'] as $table) {
|
||||
if (! $this->db->tableExists($table) || ! $this->db->fieldExists('school_year', $table)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rows = $this->db->table($table)
|
||||
->select('student_id, school_year')
|
||||
->where('student_id IS NOT NULL', null, false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$rowStartYear = $this->getSchoolYearStartYear((string) ($row['school_year'] ?? ''));
|
||||
$studentId = (int) ($row['student_id'] ?? 0);
|
||||
if ($studentId > 0 && $rowStartYear !== null && $rowStartYear < $selectedStartYear) {
|
||||
$studentIds[$studentId] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $studentIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show only newly registered students, with contact modal support.
|
||||
*
|
||||
|
||||
@@ -46,7 +46,7 @@ class AssignmentController extends BaseController
|
||||
|
||||
// Apply school year filter (default to current config) but avoid semester filtering so the full year is visible
|
||||
$selectedSemester = (string)($this->request->getGet('semester') ?? $this->semester ?? '');
|
||||
$year = (string)($this->request->getGet('school_year') ?? $this->schoolYear ?? '');
|
||||
$year = (string)($this->schoolYear ?? '');
|
||||
|
||||
$tcQ = $this->teacherClassModel;
|
||||
if ($year !== '') {
|
||||
@@ -172,11 +172,11 @@ class AssignmentController extends BaseController
|
||||
}
|
||||
|
||||
$schoolYearsList = [];
|
||||
try {
|
||||
$db = Database::connect();
|
||||
$yearsQuery = $db->table('teacher_class')
|
||||
->select('DISTINCT school_year', false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
try {
|
||||
$db = Database::connect();
|
||||
$yearsQuery = $db->table('teacher_class')
|
||||
->select('DISTINCT school_year', false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
@@ -189,8 +189,8 @@ class AssignmentController extends BaseController
|
||||
} catch (\Throwable $e) {
|
||||
// ignore fallback below
|
||||
}
|
||||
if (empty($schoolYearsList) && $this->schoolYear !== null && $this->schoolYear !== '') {
|
||||
$schoolYearsList[] = (string)$this->schoolYear;
|
||||
if ($this->schoolYear !== null && $this->schoolYear !== '' && !in_array((string)$this->schoolYear, $schoolYearsList, true)) {
|
||||
array_unshift($schoolYearsList, (string)$this->schoolYear);
|
||||
}
|
||||
|
||||
// Sort sections
|
||||
|
||||
@@ -64,11 +64,20 @@ class AttendanceController extends Controller
|
||||
$this->userRoleModel = new UserRoleModel();
|
||||
$this->semesterScoreService = service('semesterScoreService');
|
||||
$this->semester = $this->configModel->getConfig('semester');
|
||||
$this->schoolYear = $this->configModel->getConfig('school_year');
|
||||
$this->schoolYear = $this->currentSchoolYearName();
|
||||
$this->enableAttendance = $this->configModel->getConfig('enable_attendance');
|
||||
$this->semesterRangeService = new SemesterRangeService($this->configModel);
|
||||
}
|
||||
|
||||
private function currentSchoolYearName(): string
|
||||
{
|
||||
try {
|
||||
return service('schoolYearContext')->resolve(service('request'))->yearName();
|
||||
} catch (\Throwable $e) {
|
||||
return (string) ($this->configModel->getConfig('school_year') ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GET: filter + grid for a single date/section.
|
||||
|
||||
@@ -70,28 +70,6 @@ class AttendanceTrackingController extends BaseController
|
||||
->findAll();
|
||||
$debugInfo['class_students'] = count($classStudents);
|
||||
|
||||
// Fallback: if the configured school_year has no class assignments, look up the latest term
|
||||
if (empty($classStudents)) {
|
||||
$latestTerm = $this->db->table('student_class')
|
||||
->select('school_year, semester')
|
||||
->orderBy('id', 'DESC')
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($latestTerm && !empty($latestTerm['school_year'])) {
|
||||
$schoolYear = (string)$latestTerm['school_year'];
|
||||
if (!empty($latestTerm['semester'])) {
|
||||
$semester = (string)$latestTerm['semester'];
|
||||
}
|
||||
|
||||
$classStudents = $this->studentClassModel
|
||||
->active()
|
||||
->where('student_class.school_year', $schoolYear)
|
||||
->findAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Gather candidate student identifiers (numeric IDs and code-like IDs)
|
||||
$studentIds = [];
|
||||
$studentCodes = [];
|
||||
|
||||
@@ -62,7 +62,7 @@ class EventController extends ResourceController
|
||||
$this->parentModel = new ParentModel();
|
||||
$this->emailService = new EmailService();
|
||||
|
||||
$this->schoolYear = $this->configModel->getConfig('school_year');
|
||||
$this->schoolYear = $this->currentSchoolYearName();
|
||||
$this->semester = $this->configModel->getConfig('semester');
|
||||
$this->categories = [
|
||||
'workshops',
|
||||
@@ -88,6 +88,15 @@ class EventController extends ResourceController
|
||||
return $this->eventChargesHasCreatedBy;
|
||||
}
|
||||
|
||||
private function currentSchoolYearName(): string
|
||||
{
|
||||
try {
|
||||
return service('schoolYearContext')->resolve(service('request'))->yearName();
|
||||
} catch (\Throwable $e) {
|
||||
return (string) ($this->configModel->getConfig('school_year') ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
private function eventChargesSupportsWaiverSigned(): bool
|
||||
{
|
||||
if ($this->eventChargesHasWaiverSigned !== null) {
|
||||
|
||||
@@ -20,6 +20,60 @@ class FinancialController extends BaseController
|
||||
$accept = strtolower((string)($this->request->getHeaderLine('Accept') ?? ''));
|
||||
return $this->request->isAJAX() || str_contains($accept, 'application/json');
|
||||
}
|
||||
|
||||
private function selectedSchoolYear(): string
|
||||
{
|
||||
$requested = trim((string) ($this->request->getGet('school_year') ?? ''));
|
||||
if ($requested !== '') {
|
||||
return $requested;
|
||||
}
|
||||
|
||||
return $this->currentSchoolYearName();
|
||||
}
|
||||
|
||||
private function financialSchoolYearOptions(?string $selectedYear = null): array
|
||||
{
|
||||
$schoolYears = [];
|
||||
$addYear = static function (mixed $value) use (&$schoolYears): void {
|
||||
$year = trim((string) $value);
|
||||
if ($year !== '' && ! in_array($year, $schoolYears, true)) {
|
||||
$schoolYears[] = $year;
|
||||
}
|
||||
};
|
||||
|
||||
$addYear($selectedYear);
|
||||
$addYear($this->currentSchoolYearName());
|
||||
|
||||
try {
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if ($db->tableExists('school_years')) {
|
||||
$rows = $db->table('school_years')
|
||||
->select('name')
|
||||
->orderBy('name', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
foreach ($rows as $row) {
|
||||
$addYear($row['name'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
if ($db->tableExists('invoices') && $db->fieldExists('school_year', 'invoices')) {
|
||||
$rows = $db->table('invoices')
|
||||
->select('DISTINCT school_year', false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
foreach ($rows as $row) {
|
||||
$addYear($row['school_year'] ?? '');
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
|
||||
return $schoolYears;
|
||||
}
|
||||
|
||||
public function financialReport()
|
||||
{
|
||||
@@ -32,7 +86,7 @@ public function financialReport()
|
||||
|
||||
$dateFrom = $this->request->getGet('date_from');
|
||||
$dateTo = $this->request->getGet('date_to');
|
||||
$schoolYear = $this->request->getGet('school_year');
|
||||
$schoolYear = $this->selectedSchoolYear();
|
||||
|
||||
// === Apply filters to models (invoice/refund/discount/expense/reimb) ===
|
||||
if ($schoolYear) {
|
||||
@@ -235,22 +289,7 @@ public function financialReport()
|
||||
->findAll();
|
||||
|
||||
// --- School year options (for detailed view & JSON) ---
|
||||
$schoolYears = [];
|
||||
try {
|
||||
$db = \Config\Database::connect();
|
||||
$rows = $db->table('invoices')
|
||||
->select('DISTINCT school_year', false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()->getResultArray();
|
||||
foreach ($rows as $r) {
|
||||
$val = (string)($r['school_year'] ?? '');
|
||||
if ($val !== '' && !in_array($val, $schoolYears, true)) $schoolYears[] = $val;
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
if (empty($schoolYears) && !empty($schoolYear)) {
|
||||
$schoolYears[] = (string)$schoolYear;
|
||||
}
|
||||
$schoolYears = $this->financialSchoolYearOptions($schoolYear);
|
||||
|
||||
$eventFeesTotal = $this->getEventFeesTotal($schoolYear, $dateFrom, $dateTo);
|
||||
|
||||
@@ -298,28 +337,11 @@ public function financialReport()
|
||||
{
|
||||
$dateFrom = $this->request->getGet('date_from');
|
||||
$dateTo = $this->request->getGet('date_to');
|
||||
$schoolYear = $this->request->getGet('school_year');
|
||||
$schoolYear = $this->selectedSchoolYear();
|
||||
|
||||
$data = $this->getFinancialSummary($dateFrom, $dateTo, $schoolYear);
|
||||
|
||||
// Build school year options from invoices table (fallback to configured year)
|
||||
$schoolYears = [];
|
||||
try {
|
||||
$db = \Config\Database::connect();
|
||||
$rows = $db->table('invoices')
|
||||
->select('DISTINCT school_year', false)
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()->getResultArray();
|
||||
foreach ($rows as $r) {
|
||||
$val = (string)($r['school_year'] ?? '');
|
||||
if ($val !== '' && !in_array($val, $schoolYears, true)) $schoolYears[] = $val;
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
if (empty($schoolYears) && !empty($data['schoolYear'])) {
|
||||
$schoolYears[] = (string)$data['schoolYear'];
|
||||
}
|
||||
$data['schoolYears'] = $schoolYears;
|
||||
$data['schoolYears'] = $this->financialSchoolYearOptions((string)($data['schoolYear'] ?? $schoolYear));
|
||||
if ($this->wantsJson() || strtolower((string)($this->request->getGet('format') ?? '')) === 'json') {
|
||||
return $this->response->setJSON(['ok' => true] + $data + [
|
||||
'csrf_token' => csrf_token(),
|
||||
@@ -524,7 +546,7 @@ public function financialReport()
|
||||
private function getFinancialSummaryDetailSections(?string $dateFrom = null, ?string $dateTo = null, ?string $schoolYear = null): array
|
||||
{
|
||||
$configModel = new \App\Models\ConfigurationModel();
|
||||
$schoolYear = $schoolYear ?: $configModel->getConfig('school_year');
|
||||
$schoolYear = $schoolYear ?: $this->currentSchoolYearName();
|
||||
|
||||
$derivedDateFrom = null;
|
||||
$derivedDateTo = null;
|
||||
@@ -1612,7 +1634,7 @@ public function financialReport()
|
||||
$additionalModel = new \App\Models\AdditionalChargeModel();
|
||||
|
||||
// Allow override via parameter; fallback to configured year
|
||||
$schoolYear = $schoolYear ?: $configModel->getConfig('school_year');
|
||||
$schoolYear = $schoolYear ?: $this->currentSchoolYearName();
|
||||
$derivedDateFrom = null;
|
||||
$derivedDateTo = null;
|
||||
if (!empty($schoolYear) && empty($dateFrom) && empty($dateTo)) {
|
||||
@@ -2068,7 +2090,7 @@ public function financialReport()
|
||||
$configModel = new \App\Models\ConfigurationModel();
|
||||
$schoolYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
||||
if ($schoolYear === '') {
|
||||
$schoolYear = (string) ($configModel->getConfig('school_year') ?? date('Y'));
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($configModel->getConfig('school_year') ?? date('Y')));
|
||||
}
|
||||
|
||||
// Build school year options from invoices
|
||||
|
||||
@@ -35,8 +35,11 @@ class FlagController extends Controller
|
||||
$grades = [];
|
||||
|
||||
// Retrieve flags and class sections that currently have active students
|
||||
$flags = $currentFlagModel->findAll();
|
||||
$schoolYear = $configModel->getConfig('school_year');
|
||||
if ((string)$schoolYear !== '' && $this->db->fieldExists('school_year', 'current_flag')) {
|
||||
$currentFlagModel->where('school_year', (string)$schoolYear);
|
||||
}
|
||||
$flags = $currentFlagModel->findAll();
|
||||
$studentCounts = $studentClassModel->getStudentCountsBySection($schoolYear);
|
||||
$classSections = [];
|
||||
|
||||
|
||||
@@ -67,17 +67,17 @@ class InvoiceController extends ResourceController
|
||||
$this->chargesModel = new EventChargesModel();
|
||||
$this->discountUsageModel = new DiscountUsageModel();
|
||||
$this->refundModel = new RefundModel();
|
||||
$this->db = \Config\Database::connect();
|
||||
$this->request = \Config\Services::request();
|
||||
|
||||
$this->gradeFee = $this->configModel->getConfig('grade_fee');
|
||||
$this->schoolYear = $this->configModel->getConfig('school_year');
|
||||
$this->schoolYear = $this->currentSchoolYearName();
|
||||
$this->semester = $this->configModel->getConfig('semester');
|
||||
$this->dueDate = $this->configModel->getConfig('due_date');
|
||||
$this->firstStudentFee = (float) ($this->configModel->getConfig('first_student_fee') ?? 350);
|
||||
$this->secondStudentFee = (float) ($this->configModel->getConfig('second_student_fee') ?? 200);
|
||||
$this->youthFee = (float) ($this->configModel->getConfig('youth_fee') ?? 200);
|
||||
$this->refundDeadline = date('Y-m-d', strtotime($this->configModel->getConfig('refund_deadline')));
|
||||
$this->db = \Config\Database::connect();
|
||||
$this->request = \Config\Services::request();
|
||||
}
|
||||
|
||||
public function index($schoolYear = null)
|
||||
@@ -213,6 +213,15 @@ class InvoiceController extends ResourceController
|
||||
]);
|
||||
}
|
||||
|
||||
private function currentSchoolYearName(): string
|
||||
{
|
||||
try {
|
||||
return service('schoolYearContext')->resolve($this->request)->yearName();
|
||||
} catch (\Throwable $e) {
|
||||
return (string) ($this->configModel->getConfig('school_year') ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API: Invoice management composite data (used by invoice_management view)
|
||||
* Returns the same structure previously rendered server-side in index().
|
||||
@@ -221,7 +230,7 @@ class InvoiceController extends ResourceController
|
||||
{
|
||||
$schoolYear = trim((string)($this->request->getGet('schoolYear') ?? $this->request->getGet('year') ?? ''));
|
||||
if ($schoolYear === '') {
|
||||
$schoolYear = $this->schoolYear;
|
||||
$schoolYear = $this->currentSchoolYearName();
|
||||
}
|
||||
|
||||
$invoiceData = [];
|
||||
|
||||
@@ -21,7 +21,7 @@ class LateSlipLogsController extends BaseController
|
||||
{
|
||||
$req = $this->request;
|
||||
|
||||
$defaultYear = (string) ($this->configModel->getConfig('school_year') ?? '');
|
||||
$defaultYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
$defaultSem = (string) ($this->configModel->getConfig('semester') ?? '');
|
||||
$schoolYear = trim((string) ($req->getGet('school_year') ?? $defaultYear));
|
||||
$semester = trim((string) ($req->getGet('semester') ?? $defaultSem));
|
||||
|
||||
@@ -149,6 +149,11 @@ class NotificationsController extends BaseController
|
||||
$targetGroup = null;
|
||||
}
|
||||
|
||||
$schoolYear = (string) ((new \App\Models\ConfigurationModel())->getConfig('school_year') ?? '');
|
||||
if ($schoolYear !== '' && db_connect()->fieldExists('school_year', 'notifications')) {
|
||||
$this->notificationModel->where('school_year', $schoolYear);
|
||||
}
|
||||
|
||||
$rows = $this->notificationModel->getActiveNotifications($targetGroup);
|
||||
if (!is_array($rows)) {
|
||||
$rows = [];
|
||||
|
||||
@@ -164,8 +164,7 @@ class ParentController extends BaseController
|
||||
return redirect()->back()->with('error', 'Parent session not found.');
|
||||
}
|
||||
|
||||
// Get current school year from config
|
||||
$currentSchoolYear = $this->configModel->getConfig('school_year');
|
||||
$currentSchoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
|
||||
// Get selected school year (no semester filter on parent view)
|
||||
$selectedYear = $this->request->getVar('school_year') ?? $currentSchoolYear;
|
||||
@@ -1784,7 +1783,7 @@ $existing = $this->studentModel
|
||||
|
||||
public function parentEventPage()
|
||||
{
|
||||
$schoolYear = session()->get('school_year');
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
$semester = session()->get('semester');
|
||||
$parentId = session()->get('user_id');
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class PaymentController extends ResourceController
|
||||
$this->enrollmentModel = new EnrollmentModel();
|
||||
$this->studentModel = new StudentModel();
|
||||
$this->studentClassModel = new StudentClassModel();
|
||||
$this->schoolYear = $this->configModel->getConfig('school_year');
|
||||
$this->schoolYear = $this->currentSchoolYearName();
|
||||
$this->semester = $this->configModel->getConfig('semester'); //installment_date
|
||||
$this->installmentDate = $this->configModel->getConfig('installment_date');
|
||||
$this->discountUsageModel = new DiscountUsageModel();
|
||||
@@ -137,11 +137,20 @@ class PaymentController extends ResourceController
|
||||
|
||||
private function getSelectedPaymentHistoryYear(): ?string
|
||||
{
|
||||
$selectedYear = $this->request->getGet('school_year') ?? $this->schoolYear;
|
||||
$selectedYear = $this->request->getGet('school_year') ?? $this->currentSchoolYearName();
|
||||
|
||||
return $selectedYear !== '' ? $selectedYear : null;
|
||||
}
|
||||
|
||||
private function currentSchoolYearName(): string
|
||||
{
|
||||
try {
|
||||
return service('schoolYearContext')->resolve($this->request)->yearName();
|
||||
} catch (\Throwable $e) {
|
||||
return (string) ($this->configModel->getConfig('school_year') ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
// View: Create a new payment plan
|
||||
public function create()
|
||||
{
|
||||
@@ -204,7 +213,7 @@ class PaymentController extends ResourceController
|
||||
public function eventChargesShow()
|
||||
{
|
||||
$parents = $this->userModel->getParents();
|
||||
$school_Year = $this->request->getGet('school_year') ?? $this->schoolYear;
|
||||
$school_Year = $this->request->getGet('school_year') ?? $this->currentSchoolYearName();
|
||||
$seme_ster = $this->request->getGet('semester') ?? $this->semester;
|
||||
|
||||
// Join with users and students for full info
|
||||
|
||||
@@ -1235,6 +1235,10 @@ public function updateBatchAssignment()
|
||||
$status = $this->request->getGet('status') ?: null;
|
||||
$filterYear = $this->request->getGet('school_year') ?: $this->schoolYear;
|
||||
$userId = $this->request->getGet('user_id') ?: null;
|
||||
$hasBatchSchoolYear = $this->db->fieldExists('school_year', 'reimbursement_batches');
|
||||
$hasExpenseSchoolYear = $this->db->fieldExists('school_year', 'expenses');
|
||||
$hasExpenseSemester = $this->db->fieldExists('semester', 'expenses');
|
||||
$hasReimbursementSchoolYear = $this->db->fieldExists('school_year', 'reimbursements');
|
||||
|
||||
$filters = [
|
||||
'school_year' => $filterYear,
|
||||
@@ -1251,13 +1255,11 @@ public function updateBatchAssignment()
|
||||
// Build closed batch summaries/details (all closed batches)
|
||||
$batchSummaries = [];
|
||||
$batchDetails = [];
|
||||
$batchQuery = $this->db->table('reimbursement_batches b')
|
||||
->select("
|
||||
$batchSelect = "
|
||||
b.id AS batch_id,
|
||||
b.title AS batch_title,
|
||||
b.yearly_batch_number,
|
||||
b.closed_at,
|
||||
b.school_year AS batch_school_year,
|
||||
e.id AS expense_id,
|
||||
e.amount AS expense_amount,
|
||||
e.description,
|
||||
@@ -1268,7 +1270,13 @@ public function updateBatchAssignment()
|
||||
u.firstname AS purchaser_firstname,
|
||||
u.lastname AS purchaser_lastname,
|
||||
r.amount AS reimb_amount
|
||||
")
|
||||
";
|
||||
if ($hasBatchSchoolYear) {
|
||||
$batchSelect .= ', b.school_year AS batch_school_year';
|
||||
}
|
||||
|
||||
$batchQuery = $this->db->table('reimbursement_batches b')
|
||||
->select($batchSelect)
|
||||
->join('reimbursement_batch_items bi', 'bi.batch_id = b.id', 'inner')
|
||||
->join('expenses e', 'e.id = bi.expense_id', 'inner')
|
||||
->join('users u', 'u.id = e.purchased_by', 'left')
|
||||
@@ -1277,10 +1285,16 @@ public function updateBatchAssignment()
|
||||
->where('bi.unassigned_at IS NULL', null, false);
|
||||
|
||||
if (!empty($filterYear)) {
|
||||
$batchQuery->groupStart()
|
||||
->where('b.school_year', $filterYear)
|
||||
->orWhere('e.school_year', $filterYear)
|
||||
->groupEnd();
|
||||
if ($hasBatchSchoolYear && $hasExpenseSchoolYear) {
|
||||
$batchQuery->groupStart()
|
||||
->where('b.school_year', $filterYear)
|
||||
->orWhere('e.school_year', $filterYear)
|
||||
->groupEnd();
|
||||
} elseif ($hasBatchSchoolYear) {
|
||||
$batchQuery->where('b.school_year', $filterYear);
|
||||
} elseif ($hasExpenseSchoolYear) {
|
||||
$batchQuery->where('e.school_year', $filterYear);
|
||||
}
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$batchQuery->where('e.purchased_by', $userId);
|
||||
@@ -1401,27 +1415,33 @@ public function updateBatchAssignment()
|
||||
'items' => [],
|
||||
'checks' => [],
|
||||
];
|
||||
$donationQuery = $this->db->table('expenses e')
|
||||
->select('
|
||||
$donationSelect = '
|
||||
e.id AS expense_id,
|
||||
e.amount AS expense_amount,
|
||||
e.description,
|
||||
e.retailor,
|
||||
e.receipt_path AS expense_receipt,
|
||||
e.purchased_by,
|
||||
e.school_year,
|
||||
e.semester,
|
||||
e.status,
|
||||
u.firstname AS purchaser_firstname,
|
||||
u.lastname AS purchaser_lastname
|
||||
')
|
||||
';
|
||||
if ($hasExpenseSchoolYear) {
|
||||
$donationSelect .= ', e.school_year';
|
||||
}
|
||||
if ($hasExpenseSemester) {
|
||||
$donationSelect .= ', e.semester';
|
||||
}
|
||||
|
||||
$donationQuery = $this->db->table('expenses e')
|
||||
->select($donationSelect)
|
||||
->join('users u', 'u.id = e.purchased_by', 'left')
|
||||
->where('e.category', 'Donation');
|
||||
|
||||
if (!empty($filterYear)) {
|
||||
if (!empty($filterYear) && $hasExpenseSchoolYear) {
|
||||
$donationQuery->where('e.school_year', $filterYear);
|
||||
}
|
||||
if (!empty($semester)) {
|
||||
if (!empty($semester) && $hasExpenseSemester) {
|
||||
$donationQuery->where('e.semester', $semester);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
@@ -1488,13 +1508,25 @@ public function updateBatchAssignment()
|
||||
|
||||
$users = $this->recipientOptions();
|
||||
|
||||
$years = $this->db->table('reimbursements')
|
||||
->select('school_year')
|
||||
->distinct()
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
$schoolYears = array_column($years, 'school_year');
|
||||
$schoolYears = [];
|
||||
if ($hasReimbursementSchoolYear) {
|
||||
$years = $this->db->table('reimbursements')
|
||||
->select('school_year')
|
||||
->distinct()
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
$schoolYears = array_column($years, 'school_year');
|
||||
} elseif ($hasExpenseSchoolYear) {
|
||||
$years = $this->db->table('expenses')
|
||||
->select('school_year')
|
||||
->distinct()
|
||||
->where('school_year IS NOT NULL', null, false)
|
||||
->orderBy('school_year', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
$schoolYears = array_column($years, 'school_year');
|
||||
}
|
||||
|
||||
// Add school years from fallback expenses (closed batches without reimbursements)
|
||||
if (!empty($fallbackRows)) {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\View;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
final class SchoolYearSelectionController extends BaseController
|
||||
{
|
||||
public function select(): RedirectResponse
|
||||
{
|
||||
$schoolYearId = (int) ($this->request->getPost('school_year_id') ?? 0);
|
||||
$returnTo = (string) ($this->request->getPost('return_to') ?? '');
|
||||
|
||||
if ($schoolYearId <= 0) {
|
||||
return redirect()->to($this->safeReturnTo($returnTo))
|
||||
->with('error', 'Please select a valid school year.');
|
||||
}
|
||||
|
||||
try {
|
||||
service('schoolYearContext')->select($schoolYearId);
|
||||
return redirect()->to($this->safeReturnTo($returnTo));
|
||||
} catch (\Throwable $e) {
|
||||
log_message('warning', 'School-year selection failed: {message}', [
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return redirect()->to($this->safeReturnTo($returnTo))
|
||||
->with('error', 'The selected school year is not available.');
|
||||
}
|
||||
}
|
||||
|
||||
public function reset(): RedirectResponse
|
||||
{
|
||||
service('schoolYearContext')->clearSelection();
|
||||
|
||||
return redirect()->to($this->safeReturnTo((string) ($this->request->getPost('return_to') ?? '')));
|
||||
}
|
||||
|
||||
private function safeReturnTo(string $returnTo): string
|
||||
{
|
||||
$fallback = $this->dashboardRoute();
|
||||
$returnTo = trim($returnTo);
|
||||
|
||||
if ($returnTo === '') {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$parts = parse_url($returnTo);
|
||||
if ($parts === false) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
if (isset($parts['host']) && strcasecmp((string) $parts['host'], (string) $this->request->getUri()->getHost()) !== 0) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$path = '/' . ltrim((string) ($parts['path'] ?? ''), '/');
|
||||
if ($path === '/' || str_starts_with($path, '//')) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$query = [];
|
||||
if (! empty($parts['query'])) {
|
||||
parse_str((string) $parts['query'], $query);
|
||||
foreach (['school_year_id', 'school_year', 'schoolYear', 'year'] as $key) {
|
||||
unset($query[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$cleanQuery = http_build_query($query);
|
||||
|
||||
return $path . ($cleanQuery !== '' ? '?' . $cleanQuery : '');
|
||||
}
|
||||
|
||||
private function dashboardRoute(): string
|
||||
{
|
||||
try {
|
||||
return service('roleService')->bestDashboardRouteFor((array) session()->get('roles'));
|
||||
} catch (\Throwable) {
|
||||
return '/landing_page/guest_dashboard';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
namespace App\Controllers\View;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\ClassSectionModel;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class ScorePredictor extends Controller
|
||||
class ScorePredictor extends BaseController
|
||||
{
|
||||
protected $db;
|
||||
protected $configModel;
|
||||
@@ -60,17 +59,30 @@ class ScorePredictor extends Controller
|
||||
public function combinedReport()
|
||||
{
|
||||
$request = service('request');
|
||||
$currentSchoolYear = $this->schoolYear;
|
||||
$currentSchoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
|
||||
$selectedYear = $request->getVar('school_year') ?? $currentSchoolYear;
|
||||
$classSectionId = $request->getVar('class_section_id');
|
||||
$yearEsc = $this->db->escape($selectedYear);
|
||||
$acceptedEnrollmentStatuses = ['payment pending', 'enrolled'];
|
||||
// Only show class sections that have at least one student in the selected year
|
||||
$classSections = $this->db->table('classSection cs')
|
||||
->select('cs.*')
|
||||
->distinct()
|
||||
->join('student_class sc', 'sc.class_section_id = cs.class_section_id', 'inner')
|
||||
->join('enrollments e', 'e.student_id = sc.student_id AND e.school_year = ' . $yearEsc, 'inner')
|
||||
->where('sc.school_year', $selectedYear)
|
||||
->whereIn('e.enrollment_status', $acceptedEnrollmentStatuses)
|
||||
->where('e.admission_status', 'accepted')
|
||||
->groupStart()
|
||||
->where('e.is_withdrawn', 0)
|
||||
->orWhere('e.is_withdrawn', null)
|
||||
->groupEnd()
|
||||
->groupStart()
|
||||
->where('sc.is_event_only', 0)
|
||||
->orWhere('sc.is_event_only', null)
|
||||
->groupEnd()
|
||||
->notLike('cs.class_section_name', 'KG', 'after')
|
||||
->groupBy('cs.id')
|
||||
->orderBy('cs.class_section_name', 'ASC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
@@ -85,12 +97,23 @@ class ScorePredictor extends Controller
|
||||
MAX(spring.semester_score) as spring_score');
|
||||
// Reduce duplication from restored students while keeping a stable class section.
|
||||
$builder->select('MAX(sc.class_section_id) as class_section_id');
|
||||
$yearEsc = $this->db->escape($selectedYear);
|
||||
$builder->join('student_class sc', 'sc.student_id = s.id AND sc.school_year = ' . $yearEsc, 'left');
|
||||
$builder->join('student_class sc', 'sc.student_id = s.id AND sc.school_year = ' . $yearEsc, 'inner');
|
||||
$builder->join('enrollments e', 'e.student_id = s.id AND e.school_year = ' . $yearEsc, 'inner');
|
||||
$builder->join('classSection cs', 'cs.class_section_id = sc.class_section_id', 'left');
|
||||
$builder->join('semester_scores fall', 'fall.student_id = s.id AND fall.semester = "fall" AND fall.school_year = "' . $selectedYear . '"', 'left');
|
||||
$builder->join('semester_scores spring', 'spring.student_id = s.id AND spring.semester = "spring" AND spring.school_year = "' . $selectedYear . '"', 'left');
|
||||
$builder->join('semester_scores fall', 'fall.student_id = s.id AND fall.semester = "fall" AND fall.school_year = ' . $yearEsc, 'left');
|
||||
$builder->join('semester_scores spring', 'spring.student_id = s.id AND spring.semester = "spring" AND spring.school_year = ' . $yearEsc, 'left');
|
||||
$builder->where('s.is_active', 1);
|
||||
$builder->where('sc.class_section_id IS NOT NULL', null, false);
|
||||
$builder->whereIn('e.enrollment_status', $acceptedEnrollmentStatuses);
|
||||
$builder->where('e.admission_status', 'accepted');
|
||||
$builder->groupStart()
|
||||
->where('e.is_withdrawn', 0)
|
||||
->orWhere('e.is_withdrawn', null)
|
||||
->groupEnd();
|
||||
$builder->groupStart()
|
||||
->where('sc.is_event_only', 0)
|
||||
->orWhere('sc.is_event_only', null)
|
||||
->groupEnd();
|
||||
$builder->groupStart()
|
||||
->where('cs.class_section_name IS NULL')
|
||||
->orNotLike('cs.class_section_name', 'KG', 'after')
|
||||
@@ -106,11 +129,22 @@ class ScorePredictor extends Controller
|
||||
// Stats for spring
|
||||
$springStatsQuery = $this->db->table('semester_scores')
|
||||
->select('AVG(semester_scores.semester_score) as mean, STDDEV(semester_scores.semester_score) as std')
|
||||
->join('student_class', 'student_class.student_id = semester_scores.student_id')
|
||||
->join('student_class', 'student_class.student_id = semester_scores.student_id AND student_class.school_year = ' . $yearEsc)
|
||||
->join('enrollments e', 'e.student_id = semester_scores.student_id AND e.school_year = ' . $yearEsc, 'inner')
|
||||
->join('classSection cs', 'cs.class_section_id = student_class.class_section_id', 'left')
|
||||
->where('semester_scores.semester', 'spring')
|
||||
->where('semester_scores.school_year', $selectedYear)
|
||||
->where('student_class.school_year', $selectedYear)
|
||||
->where('student_class.class_section_id IS NOT NULL', null, false)
|
||||
->whereIn('e.enrollment_status', $acceptedEnrollmentStatuses)
|
||||
->where('e.admission_status', 'accepted')
|
||||
->groupStart()
|
||||
->where('e.is_withdrawn', 0)
|
||||
->orWhere('e.is_withdrawn', null)
|
||||
->groupEnd()
|
||||
->groupStart()
|
||||
->where('student_class.is_event_only', 0)
|
||||
->orWhere('student_class.is_event_only', null)
|
||||
->groupEnd()
|
||||
->groupStart()
|
||||
->where('cs.class_section_name IS NULL')
|
||||
->orNotLike('cs.class_section_name', 'KG', 'after')
|
||||
|
||||
@@ -386,21 +386,8 @@ class StudentController extends BaseController
|
||||
{
|
||||
$schoolYear = (string)($this->schoolYear ?? '');
|
||||
|
||||
$activeStudents = $this->studentModel
|
||||
->select('id, school_id, firstname, lastname, gender, age')
|
||||
->where('is_active', 1)
|
||||
->orderBy('lastname', 'ASC')
|
||||
->orderBy('firstname', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$removedStudents = $this->studentModel
|
||||
->select('id, school_id, firstname, lastname, gender, age')
|
||||
->where('is_active', 0)
|
||||
->orderBy('lastname', 'ASC')
|
||||
->orderBy('firstname', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$classMap = [];
|
||||
$activeYearStudentIds = [];
|
||||
$classQuery = $this->db->table('student_class sc')
|
||||
->select('sc.student_id, cs.class_section_name')
|
||||
->join('classSection cs', 'cs.class_section_id = sc.class_section_id', 'left');
|
||||
@@ -411,11 +398,35 @@ class StudentController extends BaseController
|
||||
|
||||
foreach ($classRows as $row) {
|
||||
$sid = (int)($row['student_id'] ?? 0);
|
||||
if ($sid > 0) {
|
||||
$activeYearStudentIds[$sid] = true;
|
||||
}
|
||||
|
||||
$name = trim((string)($row['class_section_name'] ?? ''));
|
||||
if ($sid <= 0 || $name === '') continue;
|
||||
$classMap[$sid][] = $name;
|
||||
}
|
||||
|
||||
$students = $this->studentModel
|
||||
->select('id, school_id, firstname, lastname, gender, age, is_active')
|
||||
->orderBy('lastname', 'ASC')
|
||||
->orderBy('firstname', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$activeStudents = [];
|
||||
$removedStudents = [];
|
||||
foreach ($students as $student) {
|
||||
$studentId = (int)($student['id'] ?? 0);
|
||||
$isGloballyActive = (int)($student['is_active'] ?? 0) === 1;
|
||||
$hasSelectedYearClass = $studentId > 0 && isset($activeYearStudentIds[$studentId]);
|
||||
|
||||
if ($isGloballyActive && $hasSelectedYearClass) {
|
||||
$activeStudents[] = $student;
|
||||
} else {
|
||||
$removedStudents[] = $student;
|
||||
}
|
||||
}
|
||||
|
||||
$attachClassNames = static function (array $students) use ($classMap): array {
|
||||
foreach ($students as &$student) {
|
||||
$sid = (int)($student['id'] ?? 0);
|
||||
@@ -432,6 +443,7 @@ class StudentController extends BaseController
|
||||
'active_students' => $attachClassNames($activeStudents),
|
||||
'removed_students' => $attachClassNames($removedStudents),
|
||||
'school_year' => $schoolYear,
|
||||
'active_school_year' => (string)($this->schoolYear ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1671,8 +1683,7 @@ class StudentController extends BaseController
|
||||
->findAll();
|
||||
}
|
||||
} elseif (in_array($role, ['teacher', 'teacher_assistant', 'teacher_dashboard'], true)) {
|
||||
$configModel = new \App\Models\ConfigurationModel();
|
||||
$schoolYear = session()->get('school_year') ?? $configModel->getConfig('school_year');
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
$classSectionId = (int)(session()->get('class_section_id') ?? 0);
|
||||
|
||||
if ($classSectionId > 0 && !empty($schoolYear)) {
|
||||
|
||||
@@ -20,7 +20,7 @@ class TrophyController extends BaseController
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$currentYear = $this->configModel->getConfig('school_year') ?? '';
|
||||
$currentYear = $this->currentSchoolYearName();
|
||||
$selectedYear = $this->request->getGet('school_year') ?? $currentYear;
|
||||
|
||||
$percentile = (float) ($this->request->getGet('percentile') ?? 75);
|
||||
@@ -166,7 +166,7 @@ class TrophyController extends BaseController
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$currentYear = $this->configModel->getConfig('school_year') ?? '';
|
||||
$currentYear = $this->currentSchoolYearName();
|
||||
$selectedYear = $this->request->getGet('school_year') ?? $currentYear;
|
||||
$percentile = (float) ($this->request->getGet('percentile') ?? 75);
|
||||
$percentile = max(1.0, min(99.0, $percentile));
|
||||
@@ -283,7 +283,7 @@ class TrophyController extends BaseController
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$currentYear = $this->configModel->getConfig('school_year') ?? '';
|
||||
$currentYear = $this->currentSchoolYearName();
|
||||
$selectedYear = $this->request->getGet('school_year') ?? $currentYear;
|
||||
$percentile = (float) ($this->request->getGet('percentile') ?? 75);
|
||||
$percentile = max(1.0, min(99.0, $percentile));
|
||||
|
||||
@@ -961,12 +961,18 @@ class UserController extends BaseController
|
||||
$perPage = max(1, min($perPage, 200));
|
||||
$page = max(1, $page);
|
||||
|
||||
$totalActivities = (int) $this->loginActivityModel->countAll();
|
||||
$activities = $this->loginActivityModel
|
||||
$schoolYear = (string) ((new \App\Models\ConfigurationModel())->getConfig('school_year') ?? '');
|
||||
$activityModel = $this->loginActivityModel;
|
||||
if ($schoolYear !== '' && db_connect()->fieldExists('school_year', 'login_activity')) {
|
||||
$activityModel->where('school_year', $schoolYear);
|
||||
}
|
||||
|
||||
$totalActivities = (int) $activityModel->countAllResults(false);
|
||||
$activities = $activityModel
|
||||
->orderBy('login_time', 'DESC')
|
||||
->paginate($perPage, 'loginActivity', $page) ?? [];
|
||||
|
||||
$pager = $this->loginActivityModel->pager;
|
||||
$pager = $activityModel->pager;
|
||||
$currentPage = $pager ? (int) $pager->getCurrentPage('loginActivity') : $page;
|
||||
$pageCount = $pager ? (int) $pager->getPageCount('loginActivity') : (int) max(1, ceil($totalActivities / $perPage));
|
||||
|
||||
|
||||
@@ -103,24 +103,14 @@ class WhatsappController extends BaseController
|
||||
$sectionName = $row['class_section_name'] ?? ('Section ' . $sectionId);
|
||||
}
|
||||
|
||||
$existing = $this->linkModel->where([
|
||||
'class_section_id' => $sectionId,
|
||||
'school_year' => $this->schoolYear,
|
||||
])->first();
|
||||
|
||||
$payload = [
|
||||
'class_section_id' => $sectionId,
|
||||
'class_section_name' => $sectionName,
|
||||
'school_year' => $this->schoolYear,
|
||||
'invite_link' => trim($inviteLink),
|
||||
'active' => $active,
|
||||
];
|
||||
|
||||
if ($existing) {
|
||||
$this->linkModel->update($existing['id'], $payload);
|
||||
} else {
|
||||
$this->linkModel->insert($payload);
|
||||
}
|
||||
$this->linkModel->upsertLinkForSection(
|
||||
$sectionId,
|
||||
$sectionName,
|
||||
(string) $this->schoolYear,
|
||||
'',
|
||||
$inviteLink,
|
||||
$active === 1
|
||||
);
|
||||
|
||||
return redirect()->back()->with('success', 'WhatsApp group link saved.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user