assertModelCanInsertAndRetrieve(StudentModel::class); } public function testCanUpdate() { $this->assertModelCanUpdate(StudentModel::class); } public function testCanDelete() { $this->assertModelCanDelete(StudentModel::class); } public function testNewStudentQueryIncludesStudentsWithoutClassAssignment(): void { $db = Database::connect('tests'); $schoolYear = $this->validSchoolYear(); $parentId = $this->insertParent($db, 'parent-with-new-student@example.test'); $newStudentId = $this->insertStudent($db, $parentId, 'Unassigned', 'New'); $returningStudentId = $this->insertStudent($db, $parentId, 'Assigned', 'Returning'); $db->table('student_year_status')->insert([ 'student_id' => $newStudentId, 'school_year' => $schoolYear, 'is_new' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $db->table('student_year_status')->insert([ 'student_id' => $returningStudentId, 'school_year' => $schoolYear, 'is_new' => 0, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $rows = (new StudentModel())->getStudentsWithParentsAndEmergency($schoolYear, 1); $ids = array_map(static fn (array $row): int => (int) $row['id'], $rows); $this->assertContains($newStudentId, $ids); $this->assertNotContains($returningStudentId, $ids); } public function testEnrollmentWithdrawalRosterExcludesRegisteredOnlyStudents(): void { $db = Database::connect('tests'); $schoolYear = $this->validSchoolYear(); $parentId = $this->insertParent($db, 'parent-roster-filter@example.test'); $registeredOnlyId = $this->insertStudent($db, $parentId, 'Registered', 'Only'); $enrolledId = $this->insertStudent($db, $parentId, 'Roster', 'Student'); $db->table('student_year_status')->insert([ 'student_id' => $registeredOnlyId, 'school_year' => $schoolYear, 'is_new' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $db->table('student_year_status')->insert([ 'student_id' => $enrolledId, 'school_year' => $schoolYear, 'is_new' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $db->table('enrollments')->insert([ 'student_id' => $enrolledId, 'class_section_id' => null, 'parent_id' => $parentId, 'enrollment_date' => date('Y-m-d'), 'enrollment_status' => 'admission under review', 'withdrawal_date' => null, 'is_withdrawn' => 0, 'admission_status' => 'pending', 'semester' => 'Fall', 'school_year' => $schoolYear, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $rows = (new StudentModel())->getStudentsWithClassAndEnrollment($schoolYear); $ids = array_map(static fn (array $row): int => (int) $row['id'], $rows); $this->assertNotContains($registeredOnlyId, $ids); $this->assertContains($enrolledId, $ids); } private function insertParent($db, string $email): int { $db->table('users')->insert([ 'school_id' => random_int(100000, 999999), 'firstname' => 'Test', 'lastname' => 'Parent', 'gender' => 'Male', 'cellphone' => '555-0100', 'email' => $email, 'address_street' => '1 Test St', 'city' => 'Lowell', 'state' => 'MA', 'zip' => '01852', 'accept_school_policy' => 1, 'is_verified' => 1, 'status' => 'Active', 'password' => password_hash('password', PASSWORD_DEFAULT), 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); return (int) $db->insertID(); } private function insertStudent($db, int $parentId, string $firstname, string $lastname): int { $db->table('students')->insert([ 'school_id' => uniqid('STU', false), 'firstname' => $firstname, 'lastname' => $lastname, 'dob' => '2018-01-01', 'age' => 8, 'gender' => 'Male', 'is_active' => 1, 'registration_grade' => '1', 'is_new' => 1, 'photo_consent' => 1, 'parent_id' => $parentId, 'registration_date' => date('Y-m-d H:i:s'), 'tuition_paid' => 0, 'year_of_registration' => '2026', ]); return (int) $db->insertID(); } }