fix enrollment for the new school-year
Tests / PHPUnit (push) Successful in 1m26s

This commit is contained in:
root
2026-08-07 23:43:31 -04:00
parent b6f3b14e7b
commit 1ef2800f12
66 changed files with 8997 additions and 498 deletions
@@ -0,0 +1,188 @@
<?php
namespace App\Database\Migrations;
use App\Support\Enrollment\DeliberationDecision;
use CodeIgniter\Database\Migration;
class AddSchoolYearTransitionEnrollmentFields extends Migration
{
public function up()
{
if ($this->db->tableExists('student_decisions') && ! $this->db->fieldExists('deliberation_decision_standard', 'student_decisions')) {
$this->forge->addColumn('student_decisions', [
'deliberation_decision_standard' => [
'type' => 'VARCHAR',
'constraint' => 40,
'null' => true,
'after' => 'decision',
],
]);
}
if ($this->db->tableExists('student_decisions') && $this->db->fieldExists('deliberation_decision_standard', 'student_decisions')) {
$rows = $this->db->table('student_decisions')
->select('id, decision')
->get()
->getResultArray();
foreach ($rows as $row) {
$standard = DeliberationDecision::normalize($row['decision'] ?? null);
if ($standard === null) {
continue;
}
$this->db->table('student_decisions')
->where('id', (int) $row['id'])
->update(['deliberation_decision_standard' => $standard]);
}
}
if (! $this->db->tableExists('enrollments')) {
return;
}
$fields = [];
$this->addFieldIfMissing($fields, 'source_school_year', [
'type' => 'VARCHAR',
'constraint' => 20,
'null' => true,
'after' => 'school_year',
]);
$this->addFieldIfMissing($fields, 'deliberation_decision', [
'type' => 'VARCHAR',
'constraint' => 40,
'null' => true,
'after' => 'source_school_year',
]);
$this->addFieldIfMissing($fields, 'source_grade_id', [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => true,
'after' => 'deliberation_decision',
]);
$this->addFieldIfMissing($fields, 'assigned_grade_id', [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => true,
'after' => 'source_grade_id',
]);
$this->addFieldIfMissing($fields, 'source_class_section_id', [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => true,
'after' => 'assigned_grade_id',
]);
$this->addFieldIfMissing($fields, 'assigned_class_section_id', [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => true,
'after' => 'source_class_section_id',
]);
$this->addFieldIfMissing($fields, 'placement_status', [
'type' => 'VARCHAR',
'constraint' => 40,
'null' => true,
'after' => 'assigned_class_section_id',
]);
$this->addFieldIfMissing($fields, 'age_reference_date', [
'type' => 'DATE',
'null' => true,
'after' => 'placement_status',
]);
$this->addFieldIfMissing($fields, 'age_on_reference_date', [
'type' => 'INT',
'constraint' => 3,
'null' => true,
'after' => 'age_reference_date',
]);
$this->addFieldIfMissing($fields, 'adult_student', [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'after' => 'age_on_reference_date',
]);
$this->addFieldIfMissing($fields, 'parent_enrollment_allowed', [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 1,
'after' => 'adult_student',
]);
$this->addFieldIfMissing($fields, 'student_self_enrollment_allowed', [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'after' => 'parent_enrollment_allowed',
]);
$this->addFieldIfMissing($fields, 'exception_required', [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'after' => 'student_self_enrollment_allowed',
]);
$this->addFieldIfMissing($fields, 'exception_reason', [
'type' => 'TEXT',
'null' => true,
'after' => 'exception_required',
]);
$this->addFieldIfMissing($fields, 'registration_submitted_at', [
'type' => 'DATETIME',
'null' => true,
'after' => 'exception_reason',
]);
$this->addFieldIfMissing($fields, 'registration_confirmed_at', [
'type' => 'DATETIME',
'null' => true,
'after' => 'registration_submitted_at',
]);
if ($fields !== []) {
$this->forge->addColumn('enrollments', $fields);
}
}
public function down()
{
if ($this->db->tableExists('student_decisions') && $this->db->fieldExists('deliberation_decision_standard', 'student_decisions')) {
$this->forge->dropColumn('student_decisions', 'deliberation_decision_standard');
}
if (! $this->db->tableExists('enrollments')) {
return;
}
foreach ([
'source_school_year',
'deliberation_decision',
'source_grade_id',
'assigned_grade_id',
'source_class_section_id',
'assigned_class_section_id',
'placement_status',
'age_reference_date',
'age_on_reference_date',
'adult_student',
'parent_enrollment_allowed',
'student_self_enrollment_allowed',
'exception_required',
'exception_reason',
'registration_submitted_at',
'registration_confirmed_at',
] as $field) {
if ($this->db->fieldExists($field, 'enrollments')) {
$this->forge->dropColumn('enrollments', $field);
}
}
}
private function addFieldIfMissing(array &$fields, string $name, array $definition): void
{
if (! $this->db->fieldExists($name, 'enrollments')) {
$fields[$name] = $definition;
}
}
}
@@ -0,0 +1,114 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateEnrollmentPhaseTwoTables extends Migration
{
public function up()
{
if ($this->db->tableExists('school_years')) {
$schoolYearFields = [];
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'registration_opens_at', ['type' => 'DATETIME', 'null' => true, 'after' => 'registration_starts_on']);
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'registration_deadline_at', ['type' => 'DATETIME', 'null' => true, 'after' => 'registration_ends_on']);
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'late_registration_blocked', ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'after' => 'registration_deadline_at']);
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'administrative_exceptions_permitted', ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'after' => 'late_registration_blocked']);
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'registration_exception_roles', ['type' => 'TEXT', 'null' => true, 'after' => 'administrative_exceptions_permitted']);
$this->addColumnIfMissing($schoolYearFields, 'school_years', 'adult_student_registration_enabled', ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'after' => 'registration_exception_roles']);
if ($schoolYearFields !== []) {
$this->forge->addColumn('school_years', $schoolYearFields);
}
}
if (! $this->db->tableExists('enrollment_age_rules')) {
$this->forge->addField([
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
'campus' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
'grade_class_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'education_level' => ['type' => 'VARCHAR', 'constraint' => 80, 'null' => true],
'minimum_age' => ['type' => 'INT', 'constraint' => 3, 'null' => true],
'maximum_age' => ['type' => 'INT', 'constraint' => 3, 'null' => true],
'age_reference_date' => ['type' => 'DATE', 'null' => true],
'behavior' => ['type' => 'VARCHAR', 'constraint' => 20, 'default' => 'blocking'],
'exceptions_allowed' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
'exception_roles' => ['type' => 'TEXT', 'null' => true],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'updated_at' => ['type' => 'DATETIME', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addKey(['school_year', 'grade_class_id']);
$this->forge->createTable('enrollment_age_rules');
}
if (! $this->db->tableExists('enrollment_flags')) {
$this->forge->addField([
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'flag_type' => ['type' => 'VARCHAR', 'constraint' => 80],
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
'source_school_year' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
'status' => ['type' => 'VARCHAR', 'constraint' => 40, 'default' => 'open'],
'priority' => ['type' => 'VARCHAR', 'constraint' => 20, 'default' => 'normal'],
'assigned_to' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'details_json' => ['type' => 'TEXT', 'null' => true],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'resolved_at' => ['type' => 'DATETIME', 'null' => true],
'resolution_notes' => ['type' => 'TEXT', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addKey(['student_id', 'school_year', 'flag_type']);
$this->forge->createTable('enrollment_flags');
}
if (! $this->db->tableExists('enrollment_transition_audits')) {
$this->forge->addField([
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
'source_school_year' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
'action' => ['type' => 'VARCHAR', 'constraint' => 80],
'performed_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'original_values_json' => ['type' => 'TEXT', 'null' => true],
'new_values_json' => ['type' => 'TEXT', 'null' => true],
'reason' => ['type' => 'TEXT', 'null' => true],
'created_at' => ['type' => 'DATETIME', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addKey(['student_id', 'school_year', 'created_at']);
$this->forge->createTable('enrollment_transition_audits');
}
}
public function down()
{
$this->forge->dropTable('enrollment_transition_audits', true);
$this->forge->dropTable('enrollment_flags', true);
$this->forge->dropTable('enrollment_age_rules', true);
if (! $this->db->tableExists('school_years')) {
return;
}
foreach ([
'registration_opens_at',
'registration_deadline_at',
'late_registration_blocked',
'administrative_exceptions_permitted',
'registration_exception_roles',
'adult_student_registration_enabled',
] as $field) {
if ($this->db->fieldExists($field, 'school_years')) {
$this->forge->dropColumn('school_years', $field);
}
}
}
private function addColumnIfMissing(array &$fields, string $table, string $name, array $definition): void
{
if (! $this->db->fieldExists($name, $table)) {
$fields[$name] = $definition;
}
}
}
@@ -0,0 +1,54 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddRegistrationExperienceFinancialFields extends Migration
{
public function up()
{
if (! $this->db->tableExists('school_years')) {
return;
}
$fields = [];
$this->addColumnIfMissing($fields, 'registration_fee', ['type' => 'DECIMAL', 'constraint' => '10,2', 'default' => 0, 'after' => 'adult_student_registration_enabled']);
$this->addColumnIfMissing($fields, 'tuition_due_at_registration', ['type' => 'DECIMAL', 'constraint' => '10,2', 'default' => 0, 'after' => 'registration_fee']);
$this->addColumnIfMissing($fields, 'mandatory_fees', ['type' => 'DECIMAL', 'constraint' => '10,2', 'default' => 0, 'after' => 'tuition_due_at_registration']);
$this->addColumnIfMissing($fields, 'carry_over_balance_behavior', ['type' => 'VARCHAR', 'constraint' => 60, 'default' => 'information_only', 'after' => 'mandatory_fees']);
$this->addColumnIfMissing($fields, 'financial_policy_message', ['type' => 'TEXT', 'null' => true, 'after' => 'carry_over_balance_behavior']);
$this->addColumnIfMissing($fields, 'payment_plan_available', ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'after' => 'financial_policy_message']);
if ($fields !== []) {
$this->forge->addColumn('school_years', $fields);
}
}
public function down()
{
if (! $this->db->tableExists('school_years')) {
return;
}
foreach ([
'registration_fee',
'tuition_due_at_registration',
'mandatory_fees',
'carry_over_balance_behavior',
'financial_policy_message',
'payment_plan_available',
] as $field) {
if ($this->db->fieldExists($field, 'school_years')) {
$this->forge->dropColumn('school_years', $field);
}
}
}
private function addColumnIfMissing(array &$fields, string $name, array $definition): void
{
if (! $this->db->fieldExists($name, 'school_years')) {
$fields[$name] = $definition;
}
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateEnrollmentEmailRecords extends Migration
{
public function up()
{
if ($this->db->tableExists('school_years')) {
$fields = [];
$this->addSchoolYearColumnIfMissing($fields, 'registration_launch_approved_at', ['type' => 'DATETIME', 'null' => true, 'after' => 'payment_plan_available']);
$this->addSchoolYearColumnIfMissing($fields, 'registration_launch_approved_by', ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true, 'after' => 'registration_launch_approved_at']);
$this->addSchoolYearColumnIfMissing($fields, 'registration_email_template_version', ['type' => 'VARCHAR', 'constraint' => 80, 'null' => true, 'after' => 'registration_launch_approved_by']);
if ($fields !== []) {
$this->forge->addColumn('school_years', $fields);
}
}
if ($this->db->tableExists('enrollment_email_records')) {
return;
}
$this->forge->addField([
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
'school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'family_account_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'parent_user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'recipient_addresses_json' => ['type' => 'TEXT'],
'template_version' => ['type' => 'VARCHAR', 'constraint' => 80, 'null' => true],
'generated_subject' => ['type' => 'VARCHAR', 'constraint' => 255],
'generated_body' => ['type' => 'LONGTEXT'],
'student_ids_included_json' => ['type' => 'TEXT', 'null' => true],
'generated_at' => ['type' => 'DATETIME', 'null' => true],
'sent_at' => ['type' => 'DATETIME', 'null' => true],
'delivery_status' => ['type' => 'VARCHAR', 'constraint' => 40, 'default' => 'generated'],
'failure_reason' => ['type' => 'TEXT', 'null' => true],
'retry_count' => ['type' => 'INT', 'constraint' => 11, 'default' => 0],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'updated_at' => ['type' => 'DATETIME', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addKey(['school_year', 'parent_user_id']);
$this->forge->createTable('enrollment_email_records');
}
public function down()
{
$this->forge->dropTable('enrollment_email_records', true);
if (! $this->db->tableExists('school_years')) {
return;
}
foreach (['registration_launch_approved_at', 'registration_launch_approved_by', 'registration_email_template_version'] as $field) {
if ($this->db->fieldExists($field, 'school_years')) {
$this->forge->dropColumn('school_years', $field);
}
}
}
private function addSchoolYearColumnIfMissing(array &$fields, string $name, array $definition): void
{
if (! $this->db->fieldExists($name, 'school_years')) {
$fields[$name] = $definition;
}
}
}
@@ -0,0 +1,190 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddEnrollmentAdministrationNavItem extends Migration
{
private string $label = 'Enrollment Administration';
private string $url = 'administrator/enrollment-admin';
public function up(): void
{
if (! $this->db->tableExists('nav_items')) {
return;
}
$parentColumn = $this->parentColumn();
$parent = $this->studentAffairsParent($parentColumn);
$navItemId = $this->navItemId($parentColumn, $parent);
if ($navItemId <= 0) {
return;
}
$this->grantRoles($navItemId, [
'administrator',
'principal',
'vice_principal',
'head of department (education)',
]);
cache()->clean();
}
public function down(): void
{
if (! $this->db->tableExists('nav_items')) {
return;
}
$row = $this->db->table('nav_items')
->where('url', $this->url)
->get()
->getRowArray();
if ($row === null) {
return;
}
if ($this->db->tableExists('role_nav_items')) {
$this->db->table('role_nav_items')
->where('nav_item_id', (int) $row['id'])
->delete();
}
$this->db->table('nav_items')
->where('id', (int) $row['id'])
->delete();
cache()->clean();
}
private function navItemId(?string $parentColumn, ?array $parent): int
{
$existing = $this->db->table('nav_items')
->where('url', $this->url)
->get()
->getRowArray();
if ($existing !== null) {
$updates = [
'label' => $this->label,
'is_enabled' => 1,
'updated_at' => date('Y-m-d H:i:s'),
];
if ($parentColumn !== null && ! empty($parent['id'])) {
$updates[$parentColumn] = (int) $parent['id'];
}
$this->db->table('nav_items')
->where('id', (int) $existing['id'])
->update($updates);
return (int) $existing['id'];
}
$insert = [
'label' => $this->label,
'url' => $this->url,
'sort_order' => 6,
'is_enabled' => 1,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
];
if ($this->db->fieldExists('icon_class', 'nav_items')) {
$insert['icon_class'] = 'bi bi-diagram-3';
}
if ($parentColumn !== null && ! empty($parent['id'])) {
$insert[$parentColumn] = (int) $parent['id'];
}
$this->db->table('nav_items')->insert($insert);
return (int) $this->db->insertID();
}
private function studentAffairsParent(?string $parentColumn): ?array
{
$builder = $this->db->table('nav_items')->where('label', 'Student-Affairs');
if ($parentColumn !== null) {
$builder->where($parentColumn, null);
}
return $builder->get()->getRowArray();
}
private function grantRoles(int $navItemId, array $roleNames): void
{
if (! $this->db->tableExists('role_nav_items')) {
return;
}
if ($this->db->fieldExists('role_id', 'role_nav_items') && $this->db->tableExists('roles')) {
foreach ($roleNames as $roleName) {
$roleBuilder = $this->db->table('roles')->select('id');
$roleBuilder->groupStart()
->where('LOWER(name)', strtolower($roleName));
if ($this->db->fieldExists('slug', 'roles')) {
$roleBuilder->orWhere('LOWER(slug)', strtolower($roleName));
}
$role = $roleBuilder->groupEnd()
->limit(1)
->get()
->getRowArray();
if ($role === null) {
continue;
}
$exists = $this->db->table('role_nav_items')
->where('role_id', (int) $role['id'])
->where('nav_item_id', $navItemId)
->countAllResults() > 0;
if (! $exists) {
$this->db->table('role_nav_items')->insert([
'role_id' => (int) $role['id'],
'nav_item_id' => $navItemId,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
}
}
return;
}
if (! $this->db->fieldExists('role', 'role_nav_items')) {
return;
}
foreach ($roleNames as $roleName) {
$roleName = strtolower($roleName);
$exists = $this->db->table('role_nav_items')
->where('role', $roleName)
->where('nav_item_id', $navItemId)
->countAllResults() > 0;
if (! $exists) {
$this->db->table('role_nav_items')->insert([
'role' => $roleName,
'nav_item_id' => $navItemId,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
}
}
}
private function parentColumn(): ?string
{
if ($this->db->fieldExists('menu_parent_id', 'nav_items')) {
return 'menu_parent_id';
}
if ($this->db->fieldExists('parent_id', 'nav_items')) {
return 'parent_id';
}
return null;
}
}
@@ -0,0 +1,77 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class SyncEnrollmentAdministrationNavRoles extends Migration
{
public function up(): void
{
if (! $this->db->tableExists('nav_items') || ! $this->db->tableExists('role_nav_items')) {
return;
}
$nav = $this->db->table('nav_items')
->select('id')
->where('url', 'administrator/enrollment-admin')
->limit(1)
->get()
->getRowArray();
if ($nav === null) {
return;
}
$this->grantRoles((int) $nav['id'], [
'administrator',
'principal',
'vice_principal',
'head of department (education)',
]);
cache()->clean();
}
public function down(): void
{
}
private function grantRoles(int $navItemId, array $roleNames): void
{
if (! $this->db->fieldExists('role_id', 'role_nav_items') || ! $this->db->tableExists('roles')) {
return;
}
foreach ($roleNames as $roleName) {
$roleBuilder = $this->db->table('roles')->select('id');
$roleBuilder->groupStart()
->where('LOWER(name)', strtolower($roleName));
if ($this->db->fieldExists('slug', 'roles')) {
$roleBuilder->orWhere('LOWER(slug)', strtolower($roleName));
}
$role = $roleBuilder->groupEnd()
->limit(1)
->get()
->getRowArray();
if ($role === null) {
continue;
}
$exists = $this->db->table('role_nav_items')
->where('role_id', (int) $role['id'])
->where('nav_item_id', $navItemId)
->countAllResults() > 0;
if (! $exists) {
$this->db->table('role_nav_items')->insert([
'role_id' => (int) $role['id'],
'nav_item_id' => $navItemId,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
}
}
}
}
@@ -0,0 +1,63 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddReviewDecisionEnrollmentStatus extends Migration
{
private const STATUSES_WITH_REVIEW_DECISION = [
'admission under review',
'review & decision',
'payment pending',
'enrolled',
'withdraw under review',
'refund pending',
'withdrawn',
'waitlist',
'denied',
];
private const STATUSES_WITHOUT_REVIEW_DECISION = [
'admission under review',
'payment pending',
'enrolled',
'withdraw under review',
'refund pending',
'withdrawn',
'waitlist',
'denied',
];
public function up()
{
$this->modifyEnrollmentStatusEnum(self::STATUSES_WITH_REVIEW_DECISION);
}
public function down()
{
if ($this->db->tableExists('enrollments')) {
$this->db->table('enrollments')
->where('enrollment_status', 'review & decision')
->update(['enrollment_status' => 'admission under review']);
}
$this->modifyEnrollmentStatusEnum(self::STATUSES_WITHOUT_REVIEW_DECISION);
}
private function modifyEnrollmentStatusEnum(array $statuses): void
{
if (! $this->db->tableExists('enrollments') || ! $this->db->fieldExists('enrollment_status', 'enrollments')) {
return;
}
if (! in_array($this->db->DBDriver, ['MySQLi', 'MySQL'], true)) {
return;
}
$enumValues = implode(',', array_map(static fn (string $status): string => "'" . str_replace("'", "''", $status) . "'", $statuses));
$this->db->query(
"ALTER TABLE `enrollments` MODIFY `enrollment_status` ENUM({$enumValues}) NOT NULL DEFAULT 'admission under review'"
);
}
}
+9 -8
View File
@@ -67,13 +67,14 @@ class NavSeeder extends Seeder
['parent'=>'Student-Affairs','label'=>'Attendance Scans','url'=>'rfid_coming_soon','sort_order'=>3],
['parent'=>'Student-Affairs','label'=>'Classes List','url'=>'administrator/class_assignment','sort_order'=>4],
['parent'=>'Student-Affairs','label'=>'Emergency Contact','url'=>'administrator/emergency_contact','sort_order'=>5],
['parent'=>'Student-Affairs','label'=>'Enrollment-Withdrawal','url'=>'enroll_withdraw/enrollment_withdrawal','sort_order'=>6],
['parent'=>'Student-Affairs','label'=>'Flags Management','url'=>'flags/flags_management','sort_order'=>7],
['parent'=>'Student-Affairs','label'=>'School Calendar','url'=>'administrator/calendar_view','sort_order'=>8],
['parent'=>'Student-Affairs','label'=>'Score Analysis','url'=>'report/combined','sort_order'=>9],
['parent'=>'Student-Affairs','label'=>'Score Management','url'=>'grading','sort_order'=>10],
['parent'=>'Student-Affairs','label'=>'Student Class Assignment','url'=>'administrator/student_class_assignment','sort_order'=>11],
['parent'=>'Student-Affairs','label'=>'Student Profile','url'=>'administrator/student_profiles','sort_order'=>12],
['parent'=>'Student-Affairs','label'=>'Enrollment Administration','url'=>'administrator/enrollment-admin','sort_order'=>6],
['parent'=>'Student-Affairs','label'=>'Enrollment-Withdrawal','url'=>'enroll_withdraw/enrollment_withdrawal','sort_order'=>7],
['parent'=>'Student-Affairs','label'=>'Flags Management','url'=>'flags/flags_management','sort_order'=>8],
['parent'=>'Student-Affairs','label'=>'School Calendar','url'=>'administrator/calendar_view','sort_order'=>9],
['parent'=>'Student-Affairs','label'=>'Score Analysis','url'=>'report/combined','sort_order'=>10],
['parent'=>'Student-Affairs','label'=>'Score Management','url'=>'grading','sort_order'=>11],
['parent'=>'Student-Affairs','label'=>'Student Class Assignment','url'=>'administrator/student_class_assignment','sort_order'=>12],
['parent'=>'Student-Affairs','label'=>'Student Profile','url'=>'administrator/student_profiles','sort_order'=>13],
// Classes
['parent'=>'Classes','label'=>'Classes List','url'=>'administrator/class_assignment','sort_order'=>1],
@@ -155,7 +156,7 @@ class NavSeeder extends Seeder
}
// Example: HOD Education (Student-Affairs group)
$hodEduLabels = ['Student-Affairs','Attendance Management','Classes List','Emergency Contact','Enrollment-Withdrawal','Flags Management','School Calendar','Score Analysis','Score Management','Student Class Assignment','Student Profile'];
$hodEduLabels = ['Student-Affairs','Attendance Management','Classes List','Emergency Contact','Enrollment Administration','Enrollment-Withdrawal','Flags Management','School Calendar','Score Analysis','Score Management','Student Class Assignment','Student Profile'];
foreach ($navRows as $row) {
if (in_array($row['label'], $hodEduLabels, true)) {
$roleMap->insert([