fix enrollment logic, add financial aid, fix class distribution
Tests / PHPUnit (push) Failing after 1m6s
Tests / PHPUnit (push) Failing after 1m6s
This commit is contained in:
@@ -73,7 +73,7 @@ class CreateWhatsappGroupMemberships extends Migration
|
||||
$this->forge->addKey(['class_section_id', 'school_year', 'semester']);
|
||||
$this->forge->addUniqueKey(['class_section_id', 'school_year', 'semester', 'subject_type', 'subject_id'], 'uniq_whatsapp_membership');
|
||||
|
||||
$this->forge->createTable('whatsapp_group_memberships');
|
||||
$this->forge->createTable('whatsapp_group_memberships', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -55,7 +55,7 @@ class CreateReimbursementBatchAdminFiles extends Migration
|
||||
$this->forge->addKey('batch_id');
|
||||
$this->forge->addKey('admin_id');
|
||||
$this->forge->addUniqueKey(['batch_id', 'admin_id']);
|
||||
$this->forge->createTable('reimbursement_batch_admin_files');
|
||||
$this->forge->createTable('reimbursement_batch_admin_files', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -68,7 +68,7 @@ class CreatePrintRequests extends Migration
|
||||
if ($this->db->tableExists('classes')) {
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
$this->forge->createTable('print_requests');
|
||||
$this->forge->createTable('print_requests', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -30,6 +30,16 @@ class RevertPrintRequestsForeignKey extends Migration
|
||||
return;
|
||||
}
|
||||
|
||||
$orphanCount = (int) $db->table('print_requests pr')
|
||||
->join('classes c', 'c.id = pr.class_id', 'left')
|
||||
->where('pr.class_id IS NOT NULL', null, false)
|
||||
->where('c.id IS NULL', null, false)
|
||||
->countAllResults();
|
||||
|
||||
if ($orphanCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new foreign key
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
|
||||
@@ -29,6 +29,16 @@ class FixPrintRequestsForeignKeyOnceAndForAll extends Migration
|
||||
return;
|
||||
}
|
||||
|
||||
$orphanCount = (int) $db->table('print_requests pr')
|
||||
->join('classSection cs', 'cs.id = pr.class_id', 'left')
|
||||
->where('pr.class_id IS NOT NULL', null, false)
|
||||
->where('cs.id IS NULL', null, false)
|
||||
->countAllResults();
|
||||
|
||||
if ($orphanCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addForeignKey('class_id', 'classSection', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@ class FixPrintRequestsForeignKeyAgain extends Migration
|
||||
}
|
||||
}
|
||||
|
||||
$orphanCount = (int) $db->table('print_requests pr')
|
||||
->join('classSection cs', 'cs.class_id = pr.class_id', 'left')
|
||||
->where('pr.class_id IS NOT NULL', null, false)
|
||||
->where('cs.class_id IS NULL', null, false)
|
||||
->countAllResults();
|
||||
|
||||
if ($orphanCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addForeignKey('class_id', 'classSection', 'class_id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class CreateClassProgressReports extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_section_id', 'week_start', 'week_end']);
|
||||
$this->forge->createTable('class_progress_reports');
|
||||
$this->forge->createTable('class_progress_reports', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -54,7 +54,7 @@ class CreateSubjectCurriculumItems extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_id', 'subject']);
|
||||
$this->forge->createTable('subject_curriculum_items');
|
||||
$this->forge->createTable('subject_curriculum_items', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ class CreateTeacherSubmissionNotificationHistory extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['teacher_id', 'class_section_id']);
|
||||
$this->forge->createTable('teacher_submission_notification_history');
|
||||
$this->forge->createTable('teacher_submission_notification_history', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -100,7 +100,7 @@ class CreateExamDraftSubmissions extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['teacher_id', 'class_section_id']);
|
||||
$this->forge->createTable('exam_drafts');
|
||||
$this->forge->createTable('exam_drafts', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -8,19 +8,27 @@ class AddVersionToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'version' => [
|
||||
$fields = [];
|
||||
|
||||
if (! $this->db->fieldExists('version', 'exam_drafts')) {
|
||||
$fields['version'] = [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'default' => 1,
|
||||
],
|
||||
'previous_draft_id' => [
|
||||
];
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('previous_draft_id', 'exam_drafts')) {
|
||||
$fields['previous_draft_id'] = [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('version');
|
||||
];
|
||||
}
|
||||
|
||||
if ($fields !== []) {
|
||||
$this->forge->addColumn('exam_drafts', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddFinalPdfToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->fieldExists('final_pdf_file', 'exam_drafts')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'final_pdf_file' => [
|
||||
'type' => 'VARCHAR',
|
||||
@@ -20,7 +24,8 @@ class AddFinalPdfToExamDrafts extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('exam_drafts', 'final_pdf_file');
|
||||
if ($this->db->fieldExists('final_pdf_file', 'exam_drafts')) {
|
||||
$this->forge->dropColumn('exam_drafts', 'final_pdf_file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddIsLegacyToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->fieldExists('is_legacy', 'exam_drafts')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'is_legacy' => [
|
||||
'type' => 'TINYINT',
|
||||
@@ -20,7 +24,8 @@ class AddIsLegacyToExamDrafts extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('exam_drafts', 'is_legacy');
|
||||
if ($this->db->fieldExists('is_legacy', 'exam_drafts')) {
|
||||
$this->forge->dropColumn('exam_drafts', 'is_legacy');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class CreateClassProgressAttachments extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('report_id');
|
||||
$this->forge->createTable('class_progress_attachments');
|
||||
$this->forge->createTable('class_progress_attachments', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -26,7 +26,7 @@ class CreatePlacementLevels extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['student_id', 'school_year'], 'unique_student_school_year');
|
||||
$this->forge->addKey('school_year');
|
||||
$this->forge->createTable('placement_levels');
|
||||
$this->forge->createTable('placement_levels', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -24,7 +24,7 @@ class CreatePlacementBatches extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['placement_test', 'school_year']);
|
||||
$this->forge->createTable('placement_batches');
|
||||
$this->forge->createTable('placement_batches', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -26,7 +26,7 @@ class CreatePlacementScores extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['batch_id', 'student_id'], 'unique_batch_student');
|
||||
$this->forge->addKey('batch_id');
|
||||
$this->forge->createTable('placement_scores');
|
||||
$this->forge->createTable('placement_scores', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -67,7 +67,7 @@ class CreateReportCardAcknowledgements extends Migration
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['parent_id', 'student_id', 'school_year', 'semester'], false, true);
|
||||
$this->forge->createTable('report_card_acknowledgements');
|
||||
$this->forge->createTable('report_card_acknowledgements', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -75,7 +75,7 @@ class CreateCertificateRecords extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey('certificate_number');
|
||||
$this->forge->addKey(['school_year', 'student_id']);
|
||||
$this->forge->createTable('certificate_records');
|
||||
$this->forge->createTable('certificate_records', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -60,7 +60,7 @@ class CreateBelowSixtyDecisions extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['student_id', 'semester', 'school_year']);
|
||||
$this->forge->addKey(['school_year', 'semester']);
|
||||
$this->forge->createTable('below_sixty_decisions');
|
||||
$this->forge->createTable('below_sixty_decisions', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -75,7 +75,7 @@ class CreateStudentDecisions extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['student_id', 'semester', 'school_year']);
|
||||
$this->forge->addKey(['school_year', 'semester']);
|
||||
$this->forge->createTable('student_decisions');
|
||||
$this->forge->createTable('student_decisions', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
+15
-2
@@ -40,8 +40,10 @@ class AddVerificationTokenToCertificateRecords extends Migration
|
||||
->update(['verification_token' => $this->generateToken()]);
|
||||
}
|
||||
|
||||
$this->forge->addUniqueKey('verification_token', self::INDEX_NAME);
|
||||
$this->forge->processIndexes('certificate_records');
|
||||
if (! $this->indexExists('certificate_records', self::INDEX_NAME)) {
|
||||
$this->forge->addUniqueKey('verification_token', self::INDEX_NAME);
|
||||
$this->forge->processIndexes('certificate_records');
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
@@ -70,4 +72,15 @@ class AddVerificationTokenToCertificateRecords extends Migration
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
private function indexExists(string $table, string $indexName): bool
|
||||
{
|
||||
foreach ($this->db->getIndexData($table) as $index) {
|
||||
if (($index->name ?? '') === $indexName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,11 +149,11 @@ class FinancialSystemLedgerCleanup extends Migration
|
||||
|
||||
$defaults = [
|
||||
'tuition_calculator_version' => 'old',
|
||||
'youth_fee' => '200.00',
|
||||
'new_tuition_full_amount' => '370.00',
|
||||
'new_tuition_youth_amount' => '200.00',
|
||||
'new_tuition_second_student_discount' => '50.00',
|
||||
'new_tuition_third_student_discount' => '50.00',
|
||||
'youth_fee' => '380.00',
|
||||
'new_tuition_full_amount' => '380.00',
|
||||
'new_tuition_youth_amount' => '380.00',
|
||||
'new_tuition_second_student_discount' => '100.00',
|
||||
'new_tuition_third_student_discount' => '100.00',
|
||||
'new_tuition_fourth_plus_discount' => '100.00',
|
||||
];
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class CreateSchoolYears extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('name', false, true);
|
||||
$this->forge->addKey('status');
|
||||
$this->forge->createTable('school_years');
|
||||
$this->forge->createTable('school_years', true);
|
||||
} else {
|
||||
$this->ensureSchoolYearColumns();
|
||||
}
|
||||
@@ -193,7 +193,7 @@ class CreateSchoolYears extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['source_school_year_id', 'status']);
|
||||
$this->forge->createTable('school_year_closing_batches');
|
||||
$this->forge->createTable('school_year_closing_batches', true);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('school_year_closing_items')) {
|
||||
@@ -214,7 +214,7 @@ class CreateSchoolYears extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['closing_batch_id', 'family_id'], false, true);
|
||||
$this->forge->createTable('school_year_closing_items');
|
||||
$this->forge->createTable('school_year_closing_items', true);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('school_year_transition_logs')) {
|
||||
@@ -230,7 +230,7 @@ class CreateSchoolYears extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['school_year_id', 'created_at']);
|
||||
$this->forge->createTable('school_year_transition_logs');
|
||||
$this->forge->createTable('school_year_transition_logs', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class CreateStudentSectionDistributionDrafts extends Migration
|
||||
$this->forge->addUniqueKey(['student_id', 'school_year'], 'unique_distribution_draft_student_year');
|
||||
$this->forge->addKey(['class_id', 'school_year', 'status'], false, false, 'distribution_draft_class_year_status');
|
||||
$this->forge->addKey(['class_section_id', 'school_year'], false, false, 'distribution_draft_section_year');
|
||||
$this->forge->createTable('student_section_distribution_drafts');
|
||||
$this->forge->createTable('student_section_distribution_drafts', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -63,7 +63,7 @@ class CreateParentPolicyAcceptances extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['parent_id', 'school_year'], 'uq_parent_policy_year');
|
||||
$this->forge->addKey('school_year');
|
||||
$this->forge->createTable('parent_policy_acceptances');
|
||||
$this->forge->createTable('parent_policy_acceptances', true);
|
||||
|
||||
$this->backfillExistingAcceptances();
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class CreateEnrollmentPhaseTwoTables extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['school_year', 'grade_class_id']);
|
||||
$this->forge->createTable('enrollment_age_rules');
|
||||
$this->forge->createTable('enrollment_age_rules', true);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('enrollment_flags')) {
|
||||
@@ -59,7 +59,7 @@ class CreateEnrollmentPhaseTwoTables extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['student_id', 'school_year', 'flag_type']);
|
||||
$this->forge->createTable('enrollment_flags');
|
||||
$this->forge->createTable('enrollment_flags', true);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('enrollment_transition_audits')) {
|
||||
@@ -77,7 +77,7 @@ class CreateEnrollmentPhaseTwoTables extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['student_id', 'school_year', 'created_at']);
|
||||
$this->forge->createTable('enrollment_transition_audits');
|
||||
$this->forge->createTable('enrollment_transition_audits', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class CreateEnrollmentEmailRecords extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['school_year', 'parent_user_id']);
|
||||
$this->forge->createTable('enrollment_email_records');
|
||||
$this->forge->createTable('enrollment_email_records', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateEnrollmentExceptions extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('enrollment_exceptions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'parent_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'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' => 20, 'default' => 'active'],
|
||||
'reason_code' => ['type' => 'VARCHAR', 'constraint' => 80],
|
||||
'reason_note' => ['type' => 'TEXT'],
|
||||
'bypassed_rule_codes_json' => ['type' => 'TEXT', 'null' => true],
|
||||
'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'approved_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'starts_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'expires_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'used_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'enrollment_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'revoked_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'revoked_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'revocation_reason' => ['type' => 'TEXT', 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['parent_id', 'student_id', 'school_year', 'status'], false, false, 'idx_enrollment_exceptions_scope_status');
|
||||
$this->forge->addKey(['student_id', 'school_year'], false, false, 'idx_enrollment_exceptions_student_year');
|
||||
$this->forge->addKey(['status', 'expires_at'], false, false, 'idx_enrollment_exceptions_status_expiry');
|
||||
$this->forge->createTable('enrollment_exceptions', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('enrollment_exceptions', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class GrantEnrollmentExceptionPermission extends Migration
|
||||
{
|
||||
private string $permissionName = 'enrollment.exception.manage';
|
||||
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('permissions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$permission = $this->db->table('permissions')
|
||||
->where('name', $this->permissionName)
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($permission === null) {
|
||||
$insert = [
|
||||
'name' => $this->permissionName,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
if ($this->db->fieldExists('description', 'permissions')) {
|
||||
$insert['description'] = 'Manage scoped enrollment eligibility exceptions.';
|
||||
}
|
||||
$this->db->table('permissions')->insert($insert);
|
||||
$permissionId = (int) $this->db->insertID();
|
||||
} else {
|
||||
$permissionId = (int) $permission['id'];
|
||||
}
|
||||
|
||||
// The plan requires a narrow permission but not an automatic broad role grant.
|
||||
// Assign enrollment.exception.manage through the existing role-permission UI.
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('permissions') || ! $this->db->tableExists('role_permissions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$permission = $this->db->table('permissions')
|
||||
->where('name', $this->permissionName)
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
if ($permission === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->table('role_permissions')
|
||||
->where('permission_id', (int) $permission['id'])
|
||||
->delete();
|
||||
$this->db->table('permissions')
|
||||
->where('id', (int) $permission['id'])
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class UpdateTuitionFeeDefaults extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('configuration')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forceConfig('first_student_fee', '380.00');
|
||||
$this->forceConfig('second_student_fee', '280.00');
|
||||
$this->forceConfig('new_tuition_full_amount', '380.00');
|
||||
$this->forceConfig('new_tuition_second_student_discount', '100.00');
|
||||
$this->aliasAndForceConfig('Youth_fee', 'youth_fee', '380.00');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('configuration')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->rollbackConfig('first_student_fee', '370.00');
|
||||
$this->rollbackConfig('second_student_fee', '200.00');
|
||||
$this->rollbackConfig('youth_fee', '200.00');
|
||||
$this->rollbackConfig('new_tuition_full_amount', '370.00');
|
||||
$this->rollbackConfig('new_tuition_second_student_discount', '50.00');
|
||||
}
|
||||
|
||||
protected function aliasAndForceConfig(string $legacyKey, string $canonicalKey, string $value): void
|
||||
{
|
||||
$legacy = $this->db->table('configuration')
|
||||
->select('id, config_value')
|
||||
->where('config_key', $legacyKey)
|
||||
->orderBy('id', 'ASC')
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($legacy && strcasecmp($legacyKey, $canonicalKey) !== 0) {
|
||||
$this->db->table('configuration')
|
||||
->where('id', (int) $legacy['id'])
|
||||
->update(['config_key' => $canonicalKey, 'config_value' => $value]);
|
||||
}
|
||||
|
||||
$this->forceConfig($canonicalKey, $value);
|
||||
}
|
||||
|
||||
protected function forceConfig(string $key, string $value): void
|
||||
{
|
||||
$row = $this->db->table('configuration')
|
||||
->select('id')
|
||||
->where('config_key', $key)
|
||||
->orderBy('id', 'ASC')
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!$row) {
|
||||
$this->db->table('configuration')->insert([
|
||||
'config_key' => $key,
|
||||
'config_value' => $value,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->table('configuration')
|
||||
->where('config_key', $key)
|
||||
->update(['config_value' => $value]);
|
||||
}
|
||||
|
||||
protected function upsertConfig(string $key, string $value, array $legacyValues): void
|
||||
{
|
||||
$row = $this->db->table('configuration')
|
||||
->select('id, config_value')
|
||||
->where('config_key', $key)
|
||||
->orderBy('id', 'ASC')
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!$row) {
|
||||
$this->db->table('configuration')->insert([
|
||||
'config_key' => $key,
|
||||
'config_value' => $value,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$current = trim((string) ($row['config_value'] ?? ''));
|
||||
if (in_array($current, $legacyValues, true)) {
|
||||
$this->db->table('configuration')
|
||||
->where('config_key', $key)
|
||||
->update(['config_value' => $value]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function rollbackConfig(string $key, string $value): void
|
||||
{
|
||||
$this->db->table('configuration')
|
||||
->where('config_key', $key)
|
||||
->where('config_value', '380.00')
|
||||
->update(['config_value' => $value]);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class EnrollmentCarryOverAndExceptionUniqueness extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('school_years') && $this->db->fieldExists('carry_over_balance_behavior', 'school_years')) {
|
||||
$this->db->table('school_years')
|
||||
->groupStart()
|
||||
->where('carry_over_balance_behavior', 'information_only')
|
||||
->orWhere('carry_over_balance_behavior', null)
|
||||
->orWhere('carry_over_balance_behavior', '')
|
||||
->groupEnd()
|
||||
->update(['carry_over_balance_behavior' => 'submission_blocked_until_payment']);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('enrollment_exceptions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$indexes = $this->db->query('SHOW INDEX FROM enrollment_exceptions')->getResultArray();
|
||||
$names = array_map(static fn (array $row): string => (string) ($row['Key_name'] ?? ''), $indexes);
|
||||
if (in_array('uniq_enrollment_exceptions_scope_status', $names, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->db->query(
|
||||
'ALTER TABLE enrollment_exceptions ADD UNIQUE INDEX uniq_enrollment_exceptions_scope_status (parent_id, student_id, school_year, status)'
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Unable to add unique enrollment exception index: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('enrollment_exceptions')) {
|
||||
try {
|
||||
$this->db->query('ALTER TABLE enrollment_exceptions DROP INDEX uniq_enrollment_exceptions_scope_status');
|
||||
} catch (\Throwable $e) {
|
||||
// Index may not exist.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateFinancialAidRequests extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('financial_aid_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'parent_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
|
||||
'student_ids_json' => ['type' => 'TEXT', 'null' => true],
|
||||
'household_size' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'need_statement' => ['type' => 'TEXT'],
|
||||
'requested_amount' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'status' => ['type' => 'VARCHAR', 'constraint' => 20, 'default' => 'submitted'],
|
||||
'admin_amount' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'admin_note' => ['type' => 'TEXT', 'null' => true],
|
||||
'reviewed_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'reviewed_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'invoice_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'discount_usage_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'voucher_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['parent_id', 'school_year', 'status'], false, false, 'idx_financial_aid_parent_year_status');
|
||||
$this->forge->addKey(['school_year', 'status'], false, false, 'idx_financial_aid_year_status');
|
||||
$this->forge->createTable('financial_aid_requests', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('financial_aid_requests', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddFinancialAidNavItem extends Migration
|
||||
{
|
||||
private string $url = 'administrator/financial-aid';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('nav_items')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parentColumn = $this->parentColumn();
|
||||
$existingQuery = $this->db->table('nav_items')
|
||||
->where('url', $this->url)
|
||||
->get();
|
||||
|
||||
$existing = $existingQuery !== false ? $existingQuery->getRowArray() : null;
|
||||
if ($existing !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parentBuilder = $this->db->table('nav_items')
|
||||
->where('label', 'Financial');
|
||||
|
||||
if ($parentColumn !== null) {
|
||||
$parentBuilder->where($parentColumn, null);
|
||||
}
|
||||
|
||||
$parentQuery = $parentBuilder->get();
|
||||
$parent = $parentQuery !== false ? $parentQuery->getRowArray() : null;
|
||||
|
||||
$insert = [
|
||||
'label' => 'Financial Aid',
|
||||
'url' => $this->url,
|
||||
'sort_order' => 9,
|
||||
'is_enabled' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
if ($parentColumn !== null) {
|
||||
$insert[$parentColumn] = $parent['id'] ?? null;
|
||||
}
|
||||
|
||||
$this->db->table('nav_items')->insert($insert);
|
||||
|
||||
$navItemId = (int) $this->db->insertID();
|
||||
if (
|
||||
$navItemId <= 0
|
||||
|| ! $this->db->tableExists('role_nav_items')
|
||||
|| ! $this->db->fieldExists('role', 'role_nav_items')
|
||||
|| ! $this->db->fieldExists('nav_item_id', 'role_nav_items')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (['administrator', 'principal', 'vice_principal'] as $role) {
|
||||
$this->db->table('role_nav_items')->insert([
|
||||
'role' => $role,
|
||||
'nav_item_id' => $navItemId,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! $this->db->tableExists('nav_items')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db->table('nav_items')
|
||||
->where('url', $this->url)
|
||||
->get();
|
||||
|
||||
$row = $query !== false ? $query->getRowArray() : null;
|
||||
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();
|
||||
}
|
||||
|
||||
private function parentColumn(): ?string
|
||||
{
|
||||
if ($this->db->fieldExists('parent_id', 'nav_items')) {
|
||||
return 'parent_id';
|
||||
}
|
||||
|
||||
if ($this->db->fieldExists('menu_parent_id', 'nav_items')) {
|
||||
return 'menu_parent_id';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEnrollmentExceptionFamilyStudentIds extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('enrollment_exceptions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->db->fieldExists('family_student_ids_json', 'enrollment_exceptions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('enrollment_exceptions', [
|
||||
'family_student_ids_json' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
'after' => 'bypassed_rule_codes_json',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! $this->db->tableExists('enrollment_exceptions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->db->fieldExists('family_student_ids_json', 'enrollment_exceptions')) {
|
||||
$this->forge->dropColumn('enrollment_exceptions', 'family_student_ids_json');
|
||||
}
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class GrantEnrollmentExceptionPermissionToAdminRoles extends Migration
|
||||
{
|
||||
private string $permissionName = 'enrollment.exception.manage';
|
||||
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private array $roleNames = [
|
||||
'administrator',
|
||||
'admin',
|
||||
'principal',
|
||||
'vice principal',
|
||||
'vice_principal',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if (
|
||||
! $this->db->tableExists('roles')
|
||||
|| ! $this->db->tableExists('permissions')
|
||||
|| ! $this->db->tableExists('role_permissions')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$permission = $this->db->table('permissions')
|
||||
->select('id')
|
||||
->where('name', $this->permissionName)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($permission === null) {
|
||||
$insert = [
|
||||
'name' => $this->permissionName,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
if ($this->db->fieldExists('description', 'permissions')) {
|
||||
$insert['description'] = 'Manage scoped enrollment eligibility exceptions.';
|
||||
}
|
||||
|
||||
$this->db->table('permissions')->insert($insert);
|
||||
$permissionId = (int) $this->db->insertID();
|
||||
} else {
|
||||
$permissionId = (int) $permission['id'];
|
||||
}
|
||||
|
||||
if ($permissionId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roles = $this->db->table('roles')
|
||||
->select('id')
|
||||
->whereIn('name', $this->roleNames)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
if ($roleId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing = $this->db->table('role_permissions')
|
||||
->where('role_id', $roleId)
|
||||
->where('permission_id', $permissionId)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
$grant = [
|
||||
'can_create' => 1,
|
||||
'can_read' => 1,
|
||||
'can_update' => 1,
|
||||
'can_delete' => 1,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($this->db->fieldExists('can_manage', 'role_permissions')) {
|
||||
$grant['can_manage'] = 1;
|
||||
}
|
||||
|
||||
if ($existing === null) {
|
||||
$grant['role_id'] = $roleId;
|
||||
$grant['permission_id'] = $permissionId;
|
||||
$grant['created_at'] = $now;
|
||||
|
||||
$this->db->table('role_permissions')->insert($grant);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->db->table('role_permissions')
|
||||
->where('id', (int) $existing['id'])
|
||||
->update($grant);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (
|
||||
! $this->db->tableExists('roles')
|
||||
|| ! $this->db->tableExists('permissions')
|
||||
|| ! $this->db->tableExists('role_permissions')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$permission = $this->db->table('permissions')
|
||||
->select('id')
|
||||
->where('name', $this->permissionName)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($permission === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roles = $this->db->table('roles')
|
||||
->select('id')
|
||||
->whereIn('name', $this->roleNames)
|
||||
->get()
|
||||
->getResultArray();
|
||||
$roleIds = array_values(array_filter(array_map(static fn (array $role): int => (int) ($role['id'] ?? 0), $roles)));
|
||||
|
||||
if ($roleIds === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->table('role_permissions')
|
||||
->where('permission_id', (int) $permission['id'])
|
||||
->whereIn('role_id', $roleIds)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user