fix is_new issue with enrollment fixes
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Failing after 1m22s

This commit is contained in:
root
2026-08-20 19:57:25 -04:00
parent 127098b87c
commit 889c037660
29 changed files with 77306 additions and 293 deletions
@@ -110,6 +110,10 @@ public function studentProfiles(string $selectedYear): array
->getResultArray();
}
if ($selectedYear !== '') {
service('studentYearStatus')->attachToStudents($students, $selectedYear);
}
$enrollmentStatusByStudentId = [];
$studentIds = array_values(array_unique(array_filter(array_map(
static fn (array $row): int => (int) ($row['id'] ?? 0),
+5 -8
View File
@@ -58,7 +58,7 @@ public function buildRoster(string $selectedYear, string $semester): array
$students = $this->studentModel->getStudentsWithClassAndEnrollment($selectedYear);
$removedPriorStatuses = $this->removedPriorYearStudentStatuses($selectedYear);
$returningStudentIds = $this->priorYearStudentIds($selectedYear);
service('studentYearStatus')->attachToStudents($students, $selectedYear);
foreach ($students as &$s) {
// ===== Ensure IDs needed by the modal =====
@@ -93,11 +93,8 @@ public function buildRoster(string $selectedYear, string $semester): array
$s['parent_sort'] = 'ZZZ Unknown Parent';
}
// ===== New-student flags =====
$s['is_new'] = (int) ($s['is_new'] ?? 0);
if (isset($returningStudentIds[$s['student_id']])) {
$s['is_new'] = 0;
}
// ===== New-student flags (year-scoped) =====
$s['is_new'] = (int) ($s['is_new'] ?? 1) === 1 ? 1 : 0;
$s['new_student'] = $s['is_new'] === 1 ? 'Yes' : 'No';
// ===== Admission override =====
@@ -158,7 +155,7 @@ public function buildRoster(string $selectedYear, string $semester): array
*/
public function newStudents(string $schoolYear): array
{
$rows = $this->studentModel->getStudentsWithParentsAndEmergency($schoolYear);
$rows = $this->studentModel->getStudentsWithParentsAndEmergency($schoolYear, 1);
$newStudents = [];
foreach ($rows as $r) {
@@ -170,7 +167,7 @@ public function newStudents(string $schoolYear): array
? $classSection
: 'Class not Assigned';
$r['is_new'] = (int) $r['is_new'];
$r['is_new'] = (int) ($r['is_new'] ?? 1) === 1 ? 1 : 0;
$r['new_student'] = $r['is_new'] === 1 ? "Yes" : "No";
$r['modalIdContact'] = 'contact_' . (int)($r['id'] ?? 0);
$r['enrollment_status'] = $enrollmentstatus;
+39 -20
View File
@@ -603,14 +603,6 @@ final class SchoolYearClosingService
->where('sc.school_year', $schoolYear)
->where('sc.class_section_id IS NOT NULL', null, false);
if ($hasEnrollments && ($hasEnrollmentStatus || $hasEnrollmentWithdrawn)) {
$builder->join(
'enrollments e',
'e.student_id = sc.student_id AND e.school_year = ' . $this->db->escape($schoolYear),
'left'
);
}
if ($hasDob) {
$builder->select('s.dob');
}
@@ -630,18 +622,12 @@ final class SchoolYearClosingService
$builder->where('s.is_active', 1);
}
if ($hasEnrollmentStatus) {
$inactiveStatuses = implode(',', array_map([$this->db, 'escape'], EnrollmentStatusService::INACTIVE_STATUSES));
$builder->where(
'(e.enrollment_status IS NULL OR LOWER(TRIM(e.enrollment_status)) NOT IN (' . $inactiveStatuses . '))',
null,
false
);
}
if ($hasEnrollmentWithdrawn) {
$builder->where('(e.is_withdrawn IS NULL OR e.is_withdrawn != 1)', null, false);
}
$this->excludeWithdrawnStudentsFromClosingBlockers(
$builder,
$schoolYear,
$hasEnrollmentStatus,
$hasEnrollmentWithdrawn
);
$assignmentRows = $builder
->orderBy('sc.student_id', 'ASC')
@@ -783,6 +769,39 @@ final class SchoolYearClosingService
];
}
private function excludeWithdrawnStudentsFromClosingBlockers(
$builder,
string $schoolYear,
bool $hasEnrollmentStatus,
bool $hasEnrollmentWithdrawn
): void {
if (! $hasEnrollmentStatus && ! $hasEnrollmentWithdrawn) {
return;
}
$conditions = [];
if ($hasEnrollmentStatus) {
$inactiveStatuses = implode(',', array_map([$this->db, 'escape'], EnrollmentStatusService::INACTIVE_STATUSES));
$conditions[] = 'LOWER(TRIM(e.enrollment_status)) IN (' . $inactiveStatuses . ')';
}
if ($hasEnrollmentWithdrawn) {
$conditions[] = 'e.is_withdrawn = 1';
}
$builder->where(
'NOT EXISTS (
SELECT 1
FROM enrollments e
WHERE e.student_id = sc.student_id
AND e.school_year = ' . $this->db->escape($schoolYear) . '
AND (' . implode(' OR ', $conditions) . ')
)',
null,
false
);
}
private function isKgStudent(array $student): bool
{
foreach (['class_name', 'class_section_name'] as $field) {
+178
View File
@@ -0,0 +1,178 @@
<?php
namespace App\Services;
use App\Models\StudentYearStatusModel;
use CodeIgniter\Database\BaseConnection;
class StudentYearStatusService
{
public function __construct(
private BaseConnection $db,
private StudentYearStatusModel $yearStatusModel,
) {
}
public function isNew(int $studentId, string $schoolYear): bool
{
if ($studentId <= 0) {
return true;
}
$schoolYear = trim($schoolYear);
if (! preg_match('/^\d{4}-\d{4}$/', $schoolYear)) {
return true;
}
if (! $this->db->tableExists('student_year_status')) {
return true;
}
$row = $this->yearStatusModel
->where('student_id', $studentId)
->where('school_year', $schoolYear)
->first();
if (! is_array($row)) {
return true;
}
return (int) ($row['is_new'] ?? 1) === 1;
}
public function upsert(int $studentId, string $schoolYear, bool $isNew): void
{
if ($studentId <= 0) {
return;
}
$schoolYear = trim($schoolYear);
if (! preg_match('/^\d{4}-\d{4}$/', $schoolYear) || ! $this->db->tableExists('student_year_status')) {
return;
}
$flag = $isNew ? 1 : 0;
$existing = $this->yearStatusModel
->where('student_id', $studentId)
->where('school_year', $schoolYear)
->first();
if (is_array($existing) && isset($existing['id'])) {
$this->yearStatusModel->update((int) $existing['id'], [
'is_new' => $flag,
]);
return;
}
$this->yearStatusModel->insert([
'student_id' => $studentId,
'school_year' => $schoolYear,
'is_new' => $flag,
]);
}
/**
* @param list<array<string, mixed>> $students
*/
public function attachToStudents(array &$students, string $schoolYear): void
{
$schoolYear = trim($schoolYear);
if ($students === [] || ! preg_match('/^\d{4}-\d{4}$/', $schoolYear)) {
return;
}
$ids = [];
foreach ($students as $student) {
$id = (int) ($student['id'] ?? $student['student_id'] ?? 0);
if ($id > 0) {
$ids[$id] = true;
}
}
$flags = $this->flagsForStudents(array_keys($ids), $schoolYear);
foreach ($students as &$student) {
$id = (int) ($student['id'] ?? $student['student_id'] ?? 0);
if ($id <= 0) {
continue;
}
$student['is_new'] = $flags[$id] ?? 1;
}
unset($student);
}
/**
* @param list<int> $studentIds
* @return array<int, int>
*/
public function flagsForStudents(array $studentIds, string $schoolYear): array
{
$studentIds = array_values(array_unique(array_filter(
array_map('intval', $studentIds),
static fn(int $id): bool => $id > 0
)));
$schoolYear = trim($schoolYear);
if ($studentIds === [] || ! preg_match('/^\d{4}-\d{4}$/', $schoolYear)) {
return [];
}
$flags = [];
foreach ($studentIds as $studentId) {
$flags[$studentId] = 1;
}
if (! $this->db->tableExists('student_year_status')) {
return $flags;
}
$rows = $this->yearStatusModel
->select('student_id, is_new')
->whereIn('student_id', $studentIds)
->where('school_year', $schoolYear)
->findAll();
foreach ($rows as $row) {
$id = (int) ($row['student_id'] ?? 0);
if ($id > 0) {
$flags[$id] = (int) ($row['is_new'] ?? 1) === 1 ? 1 : 0;
}
}
return $flags;
}
public function activeSchoolYear(): ?string
{
if ($this->db->tableExists('school_years')) {
$row = $this->db->table('school_years')
->select('name')
->where('status', 'active')
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
$name = trim((string) ($row['name'] ?? ''));
if (preg_match('/^\d{4}-\d{4}$/', $name)) {
return $name;
}
}
if (! $this->db->tableExists('configuration')) {
return null;
}
$row = $this->db->table('configuration')
->select('config_value')
->where('config_key', 'school_year')
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
$name = trim((string) ($row['config_value'] ?? ''));
return preg_match('/^\d{4}-\d{4}$/', $name) ? $name : null;
}
}