recreate project
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEventCategoryToEvents extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = $this->db->getFieldNames('events');
|
||||
|
||||
if (!in_array('event_category', $fields, true)) {
|
||||
$this->forge->addColumn('events', [
|
||||
'event_category' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 100,
|
||||
'null' => true,
|
||||
'after' => 'event_name',
|
||||
'comment' => 'Admin-only category label',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$fields = $this->db->getFieldNames('events');
|
||||
|
||||
if (in_array('event_category', $fields, true)) {
|
||||
$this->forge->dropColumn('events', 'event_category');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddBatchNumberToReimbursements extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'batch_number' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'default' => 0,
|
||||
'null' => false,
|
||||
'after' => 'reimbursement_method',
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addColumn('reimbursements', $fields);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('reimbursements', 'batch_number');
|
||||
}
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddYearlyBatchNumberToReimbursementBatches extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'yearly_batch_number' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'default' => 0,
|
||||
'null' => false,
|
||||
'after' => 'title',
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addColumn('reimbursement_batches', $fields);
|
||||
|
||||
$this->fillExistingBatchNumbers();
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('reimbursement_batches', 'yearly_batch_number');
|
||||
}
|
||||
|
||||
private function fillExistingBatchNumbers(): void
|
||||
{
|
||||
$this->db->query("SET @prev_school_year := '', @row_number := 0");
|
||||
$this->db->query(
|
||||
'UPDATE reimbursement_batches b
|
||||
JOIN (
|
||||
SELECT id,
|
||||
(@row_number := IF(@prev_school_year = COALESCE(school_year, \'\'), @row_number + 1, 1)) AS seq,
|
||||
@prev_school_year := COALESCE(school_year, \'\') AS school_year_marker
|
||||
FROM reimbursement_batches
|
||||
ORDER BY COALESCE(school_year, \'\'), COALESCE(opened_at, \'1970-01-01 00:00:00\'), id
|
||||
) ranks ON b.id = ranks.id
|
||||
SET b.yearly_batch_number = ranks.seq'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateInventoryTables extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// --------- inventory_categories ----------
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'type' => ['type' => 'ENUM("classroom","book","office","kitchen")', 'null' => false, 'default' => 'office'],
|
||||
'name' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => false],
|
||||
'description' => ['type' => 'TEXT', 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['type', 'name']); // unique per type
|
||||
$this->forge->createTable('inventory_categories', true, [
|
||||
'ENGINE' => 'InnoDB',
|
||||
]);
|
||||
|
||||
// --------- inventory_items ----------
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'type' => ['type' => 'ENUM("classroom","book","office","kitchen")', 'null' => false],
|
||||
'category_id' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
|
||||
|
||||
'name' => ['type' => 'VARCHAR', 'constraint' => 190, 'null' => false],
|
||||
'description' => ['type' => 'TEXT', 'null' => true],
|
||||
|
||||
'quantity' => ['type' => 'INT', 'unsigned' => true, 'default' => 0],
|
||||
'unit' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true, 'default' => null],
|
||||
|
||||
// Classroom-only condition
|
||||
'condition' => ['type' => 'ENUM("good","needs_repair","need_replace","cannot_find")', 'null' => true, 'default' => null],
|
||||
|
||||
// Book extras (author removed earlier)
|
||||
'isbn' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true],
|
||||
'edition' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true],
|
||||
|
||||
// Misc
|
||||
'sku' => ['type' => 'VARCHAR', 'constraint' => 64, 'null' => true],
|
||||
'notes' => ['type' => 'TEXT', 'null' => true],
|
||||
|
||||
// Academic tagging
|
||||
'semester' => ['type' => 'ENUM("Spring","Fall")', 'null' => true],
|
||||
'school_year' => ['type' => 'VARCHAR', 'constraint' => 16, 'null' => true], // e.g. 2025-2026
|
||||
|
||||
// Audit
|
||||
'updated_by' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
|
||||
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
// Indexes
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['type', 'name']);
|
||||
$this->forge->addKey(['school_year', 'semester']);
|
||||
$this->forge->addKey('category_id'); // ensure indexed for FK
|
||||
$this->forge->addKey('updated_by'); // ensure indexed for FK
|
||||
|
||||
// Category FK (safe; category table we just created with InnoDB)
|
||||
$this->forge->addForeignKey('category_id', 'inventory_categories', 'id', 'SET NULL', 'CASCADE');
|
||||
|
||||
// Create items table first, then add users FK conditionally
|
||||
$this->forge->createTable('inventory_items', true, [
|
||||
'ENGINE' => 'InnoDB',
|
||||
]);
|
||||
|
||||
// ---- Add updated_by → users(id) FK conditionally & safely ----
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if ($db->tableExists('users')) {
|
||||
// Confirm users is InnoDB and id is an unsigned INT
|
||||
$engineRow = $db->query("
|
||||
SELECT ENGINE FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users'
|
||||
")->getFirstRow('array');
|
||||
|
||||
$colRow = $db->query("
|
||||
SELECT COLUMN_TYPE, IS_NULLABLE
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'id'
|
||||
")->getFirstRow('array');
|
||||
|
||||
$isInno = isset($engineRow['ENGINE']) && strtoupper($engineRow['ENGINE']) === 'INNODB';
|
||||
$isUint = isset($colRow['COLUMN_TYPE']) && stripos($colRow['COLUMN_TYPE'], 'int') !== false && stripos($colRow['COLUMN_TYPE'], 'unsigned') !== false;
|
||||
|
||||
if ($isInno && $isUint) {
|
||||
// Add the FK now (separate ALTER avoids "incorrectly formed" during CREATE)
|
||||
$db->query("
|
||||
ALTER TABLE inventory_items
|
||||
ADD CONSTRAINT fk_inventory_items_updated_by
|
||||
FOREIGN KEY (updated_by) REFERENCES users(id)
|
||||
ON DELETE SET NULL ON UPDATE CASCADE
|
||||
");
|
||||
}
|
||||
// If not compatible, we skip the FK to avoid migration failure.
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Drop children first
|
||||
$db = \Config\Database::connect();
|
||||
if ($db->tableExists('inventory_items')) {
|
||||
// drop conditional FK if exists
|
||||
try { $db->query("ALTER TABLE inventory_items DROP FOREIGN KEY fk_inventory_items_updated_by"); } catch (\Throwable $e) {}
|
||||
}
|
||||
|
||||
$this->forge->dropTable('inventory_items', true);
|
||||
$this->forge->dropTable('inventory_categories', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateInventoryMovements extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
|
||||
'item_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
|
||||
'qty_change' => ['type'=>'INT','null'=>false], // +in / -out
|
||||
'movement_type' => ['type'=>'ENUM("initial","in","out","adjust","distribution")','null'=>false,'default'=>'adjust'],
|
||||
'reason' => ['type'=>'VARCHAR','constraint'=>120,'null'=>true],
|
||||
'note' => ['type'=>'TEXT','null'=>true],
|
||||
|
||||
// tagging
|
||||
'semester' => ['type'=>'ENUM("Spring","Fall")','null'=>true],
|
||||
'school_year' => ['type'=>'VARCHAR','constraint'=>16,'null'=>true], // e.g. 2025-2026
|
||||
|
||||
// who/for whom
|
||||
'performed_by' => ['type'=>'INT','unsigned'=>true,'null'=>true], // user id
|
||||
'teacher_id' => ['type'=>'INT','unsigned'=>true,'null'=>true],
|
||||
'student_id' => ['type'=>'INT','unsigned'=>true,'null'=>true],
|
||||
'class_section_id'=> ['type'=>'INT','unsigned'=>true,'null'=>true],
|
||||
|
||||
'created_at' => ['type'=>'DATETIME','null'=>true],
|
||||
'updated_at' => ['type'=>'DATETIME','null'=>true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('item_id');
|
||||
$this->forge->addKey(['school_year','semester']);
|
||||
$this->forge->addKey('movement_type');
|
||||
|
||||
$this->forge->addForeignKey('item_id', 'inventory_items', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Create table as InnoDB
|
||||
$this->forge->createTable('inventory_movements', true, ['ENGINE'=>'InnoDB']);
|
||||
|
||||
// Optional FKs to users if compatible
|
||||
$db = \Config\Database::connect();
|
||||
if ($db->tableExists('users')) {
|
||||
// try add FK; ignore failures (engine/type mismatch)
|
||||
try {
|
||||
$db->query("ALTER TABLE inventory_movements
|
||||
ADD CONSTRAINT fk_inv_mov_performed_by FOREIGN KEY (performed_by) REFERENCES users(id)
|
||||
ON DELETE SET NULL ON UPDATE CASCADE");
|
||||
} catch (\Throwable $e) {}
|
||||
try {
|
||||
$db->query("ALTER TABLE inventory_movements
|
||||
ADD CONSTRAINT fk_inv_mov_teacher FOREIGN KEY (teacher_id) REFERENCES users(id)
|
||||
ON DELETE SET NULL ON UPDATE CASCADE");
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('inventory_movements', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddClassroomConditionBuckets extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
// --- Ensure columns exist on inventory_items ---
|
||||
$cols = $db->getFieldNames('inventory_items');
|
||||
|
||||
// 1) Academic tagging
|
||||
$addAcademic = [];
|
||||
if (!in_array('school_year', $cols, true)) {
|
||||
$addAcademic['school_year'] = ['type' => 'VARCHAR', 'constraint' => 16, 'null' => true];
|
||||
}
|
||||
if (!in_array('semester', $cols, true)) {
|
||||
$addAcademic['semester'] = ['type' => 'ENUM("Spring","Fall")', 'null' => true];
|
||||
}
|
||||
if ($addAcademic) {
|
||||
$this->forge->addColumn('inventory_items', $addAcademic);
|
||||
}
|
||||
|
||||
// 2) Condition buckets (classroom)
|
||||
$addBuckets = [];
|
||||
if (!in_array('good_qty', $cols, true)) $addBuckets['good_qty'] = ['type'=>'INT','unsigned'=>true,'default'=>0,'null'=>false,'after'=>'quantity'];
|
||||
if (!in_array('needs_repair_qty', $cols, true)) $addBuckets['needs_repair_qty'] = ['type'=>'INT','unsigned'=>true,'default'=>0,'null'=>false,'after'=>'good_qty'];
|
||||
if (!in_array('need_replace_qty', $cols, true)) $addBuckets['need_replace_qty'] = ['type'=>'INT','unsigned'=>true,'default'=>0,'null'=>false,'after'=>'needs_repair_qty'];
|
||||
if (!in_array('cannot_find_qty', $cols, true)) $addBuckets['cannot_find_qty'] = ['type'=>'INT','unsigned'=>true,'default'=>0,'null'=>false,'after'=>'need_replace_qty'];
|
||||
|
||||
if ($addBuckets) {
|
||||
$this->forge->addColumn('inventory_items', $addBuckets);
|
||||
}
|
||||
|
||||
// 3) Backfill school_year/semester from configuration (or fallback)
|
||||
[$sem, $yr] = $this->resolveCurrentAcademic($db);
|
||||
|
||||
// Only fill when missing
|
||||
$db->query("
|
||||
UPDATE inventory_items
|
||||
SET school_year = COALESCE(NULLIF(school_year, ''), ?),
|
||||
semester = COALESCE(semester, ?)
|
||||
WHERE school_year IS NULL OR school_year = '' OR semester IS NULL
|
||||
", [$yr, $sem]);
|
||||
|
||||
// 4) Backfill buckets for classroom rows (first-time init)
|
||||
$db->query("
|
||||
UPDATE inventory_items
|
||||
SET
|
||||
good_qty = quantity,
|
||||
needs_repair_qty = COALESCE(needs_repair_qty,0),
|
||||
need_replace_qty = COALESCE(need_replace_qty,0),
|
||||
cannot_find_qty = COALESCE(cannot_find_qty,0)
|
||||
WHERE type='classroom'
|
||||
AND (COALESCE(good_qty,0) = 0
|
||||
AND COALESCE(needs_repair_qty,0) = 0
|
||||
AND COALESCE(need_replace_qty,0) = 0
|
||||
AND COALESCE(cannot_find_qty,0) = 0)
|
||||
");
|
||||
|
||||
// 5) Add index on (school_year, semester) if not present
|
||||
$idx = $db->query("
|
||||
SELECT 1
|
||||
FROM information_schema.statistics
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'inventory_items'
|
||||
AND INDEX_NAME = 'idx_items_schoolyear_semester'
|
||||
LIMIT 1
|
||||
")->getFirstRow();
|
||||
|
||||
if (!$idx) {
|
||||
$db->query("ALTER TABLE inventory_items ADD INDEX idx_items_schoolyear_semester (school_year, semester)");
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Buckets can be dropped safely
|
||||
try { $this->forge->dropColumn('inventory_items', 'good_qty'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_items', 'needs_repair_qty'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_items', 'need_replace_qty'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_items', 'cannot_find_qty'); } catch (\Throwable $e) {}
|
||||
|
||||
// school_year/semester may be used elsewhere; drop only if you really want to
|
||||
try { $this->forge->dropColumn('inventory_items', 'school_year'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_items', 'semester'); } catch (\Throwable $e) {}
|
||||
|
||||
// Drop index if it exists
|
||||
$db = \Config\Database::connect();
|
||||
try { $db->query("ALTER TABLE inventory_items DROP INDEX idx_items_schoolyear_semester"); } catch (\Throwable $e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve current academic year/semester from configuration table,
|
||||
* fallback to date-based inference if not set.
|
||||
*/
|
||||
private function resolveCurrentAcademic($db): array
|
||||
{
|
||||
$sem = null; $yr = null;
|
||||
|
||||
if ($db->tableExists('configuration')) {
|
||||
$sem = $db->table('configuration')->select('config_value')
|
||||
->where('config_key','semester')->get()->getRow('config_value');
|
||||
$yr = $db->table('configuration')->select('config_value')
|
||||
->where('config_key','school_year')->get()->getRow('config_value');
|
||||
}
|
||||
|
||||
if (!$sem || !$yr) {
|
||||
$now = new \DateTime('now', new \DateTimeZone('America/New_York'));
|
||||
$y = (int)$now->format('Y');
|
||||
$m = (int)$now->format('n');
|
||||
|
||||
// Adjust these rules if your academic calendar differs
|
||||
$sem = $sem ?: (($m >= 2 && $m <= 5) ? 'Spring' : 'Fall');
|
||||
$yr = $yr ?: (($m >= 6) ? sprintf('%d-%d', $y, $y+1) : sprintf('%d-%d', $y-1, $y));
|
||||
}
|
||||
|
||||
return [$sem, $yr];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddGradeRangeToBookCategories extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$cols = $db->getFieldNames('inventory_categories');
|
||||
|
||||
$fields = [];
|
||||
if (!in_array('grade_min', $cols, true)) {
|
||||
$fields['grade_min'] = ['type' => 'TINYINT', 'unsigned' => true, 'null' => true, 'after' => 'description'];
|
||||
}
|
||||
if (!in_array('grade_max', $cols, true)) {
|
||||
$fields['grade_max'] = ['type' => 'TINYINT', 'unsigned' => true, 'null' => true, 'after' => 'grade_min'];
|
||||
}
|
||||
|
||||
if ($fields) {
|
||||
$this->forge->addColumn('inventory_categories', $fields);
|
||||
}
|
||||
|
||||
// Optional: composite index to speed up book-category lookups by range
|
||||
$idx = $db->query("
|
||||
SELECT 1 FROM information_schema.statistics
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME='inventory_categories'
|
||||
AND INDEX_NAME='idx_cat_type_grade_range'
|
||||
LIMIT 1
|
||||
")->getFirstRow();
|
||||
if (!$idx) {
|
||||
$db->query("ALTER TABLE inventory_categories ADD INDEX idx_cat_type_grade_range (type, grade_min, grade_max)");
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
try { $db->query("ALTER TABLE inventory_categories DROP INDEX idx_cat_type_grade_range"); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_categories', 'grade_min'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('inventory_categories', 'grade_max'); } catch (\Throwable $e) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateStaffAttendance extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
|
||||
'user_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
|
||||
'role_name' => ['type'=>'VARCHAR','constraint'=>64,'null'=>true],
|
||||
'date' => ['type'=>'DATE','null'=>false],
|
||||
'semester' => ['type'=>'VARCHAR','constraint'=>32,'null'=>false],
|
||||
'school_year' => ['type'=>'VARCHAR','constraint'=>16,'null'=>false],
|
||||
'status' => ['type'=>'ENUM','constraint'=>['present','absent','late'],'null'=>false,'default'=>'present'],
|
||||
'reason' => ['type'=>'VARCHAR','constraint'=>255,'null'=>true],
|
||||
'created_at' => ['type'=>'DATETIME','null'=>true],
|
||||
'updated_at' => ['type'=>'DATETIME','null'=>true],
|
||||
'created_by' => ['type'=>'INT','unsigned'=>true,'null'=>true],
|
||||
'updated_by' => ['type'=>'INT','unsigned'=>true,'null'=>true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['user_id','date','semester','school_year']);
|
||||
$this->forge->addForeignKey('user_id','users','id','CASCADE','CASCADE');
|
||||
$this->forge->createTable('staff_attendance', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('staff_attendance', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateBadgePrintLogs extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Defensive: only create if not exists
|
||||
if ($this->db->tableExists('badge_print_logs')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'user_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => false,
|
||||
],
|
||||
'printed_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => true,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'printed_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
'role' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 128,
|
||||
'null' => true,
|
||||
],
|
||||
'class_section_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => true,
|
||||
],
|
||||
'copies' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => false,
|
||||
'default' => 1,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['user_id']);
|
||||
$this->forge->addKey(['school_year']);
|
||||
$this->forge->createTable('badge_print_logs', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('badge_print_logs')) {
|
||||
$this->forge->dropTable('badge_print_logs', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateFamiliesTables extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// families
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'family_code' => ['type' => 'VARCHAR', 'constraint' => 64, 'null' => false],
|
||||
'household_name' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => true],
|
||||
'address_line1' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => true],
|
||||
'address_line2' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => true],
|
||||
'city' => ['type' => 'VARCHAR', 'constraint' => 64, 'null' => true],
|
||||
'state' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true],
|
||||
'postal_code' => ['type' => 'VARCHAR', 'constraint' => 16, 'null' => true],
|
||||
'country' => ['type' => 'VARCHAR', 'constraint' => 64, 'null' => true],
|
||||
'primary_phone' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true],
|
||||
'preferred_lang' => ['type' => 'VARCHAR', 'constraint' => 16, 'null' => true],
|
||||
'preferred_contact_method' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => true],
|
||||
'is_active' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'null' => false],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey('family_code');
|
||||
$this->forge->createTable('families', true);
|
||||
|
||||
// family_students
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'family_id' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
'student_id' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
'is_primary_home' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'null' => false],
|
||||
'notes' => ['type' => 'TEXT', 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['family_id', 'student_id']);
|
||||
$this->forge->addForeignKey('family_id', 'families', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('family_students', true);
|
||||
|
||||
// family_guardians
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'family_id' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
'user_id' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
'relation' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => false, 'default' => 'guardian'],
|
||||
'is_primary' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'null' => false],
|
||||
'receive_emails' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'null' => false],
|
||||
'receive_sms' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'null' => false],
|
||||
'custody_notes' => ['type' => 'TEXT', 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['family_id', 'user_id']);
|
||||
$this->forge->addForeignKey('family_id', 'families', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('family_guardians', true);
|
||||
|
||||
// family_comm_prefs
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
|
||||
'family_id' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
'category' => ['type' => 'VARCHAR', 'constraint' => 32, 'null' => false],
|
||||
'via_email' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'null' => false],
|
||||
'via_sms' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'null' => false],
|
||||
'cc_all_guardians' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1, 'null' => false],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['family_id', 'category']);
|
||||
$this->forge->addForeignKey('family_id', 'families', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('family_comm_prefs', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('family_comm_prefs', true);
|
||||
$this->forge->dropTable('family_guardians', true);
|
||||
$this->forge->dropTable('family_students', true);
|
||||
$this->forge->dropTable('families', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddNoSchoolToCalendarEvents extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$cols = [];
|
||||
try {
|
||||
$cols = $db->getFieldNames('calendar_events');
|
||||
} catch (\Throwable $e) {
|
||||
$cols = [];
|
||||
}
|
||||
|
||||
if (!in_array('no_school', $cols, true)) {
|
||||
$this->forge->addColumn('calendar_events', [
|
||||
'no_school' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'null' => false,
|
||||
'default' => 0,
|
||||
'after' => 'notify_teacher',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
try {
|
||||
$this->forge->dropColumn('calendar_events', 'no_school');
|
||||
} catch (\Throwable $e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Forge; // optional
|
||||
use CodeIgniter\Database\RawSql;
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateWhatsappGroupMemberships extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => false,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 25,
|
||||
'null' => false,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'null' => false,
|
||||
],
|
||||
'subject_type' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['primary', 'second'],
|
||||
'null' => false,
|
||||
'default' => 'primary',
|
||||
],
|
||||
'subject_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => false,
|
||||
'comment' => 'users.id for primary; parents.id for second',
|
||||
],
|
||||
'is_member' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'null' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'verified_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => true,
|
||||
],
|
||||
'verified_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$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');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('whatsapp_group_memberships', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateLateSlipLogs extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('late_slip_logs')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'student_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => false,
|
||||
],
|
||||
'slip_date' => [
|
||||
'type' => 'DATE',
|
||||
'null' => true,
|
||||
],
|
||||
'time_in' => [
|
||||
'type' => 'TIME',
|
||||
'null' => true,
|
||||
],
|
||||
'grade' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 64,
|
||||
'null' => true,
|
||||
],
|
||||
'reason' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'admin_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => true,
|
||||
],
|
||||
'printed_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => true,
|
||||
],
|
||||
'printed_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['school_year']);
|
||||
$this->forge->addKey(['student_name']);
|
||||
$this->forge->createTable('late_slip_logs', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('late_slip_logs')) {
|
||||
$this->forge->dropTable('late_slip_logs', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePaymentNotificationLogs extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('payment_notification_logs')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'parent_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'invoice_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'period_year' => [
|
||||
'type' => 'SMALLINT',
|
||||
'constraint' => 4,
|
||||
'null' => false,
|
||||
],
|
||||
'period_month' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 2,
|
||||
'null' => false,
|
||||
],
|
||||
'type' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['no_payment', 'installment'],
|
||||
'default' => 'installment',
|
||||
],
|
||||
'to_email' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => true,
|
||||
],
|
||||
'cc_email' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => true,
|
||||
],
|
||||
'head_fa_notified' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
],
|
||||
'subject' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'body' => [
|
||||
'type' => 'MEDIUMTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['sent', 'failed'],
|
||||
'default' => 'sent',
|
||||
],
|
||||
'error_message' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'balance_snapshot' => [
|
||||
'type' => 'DECIMAL',
|
||||
'constraint' => '10,2',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'sent_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['parent_id']);
|
||||
$this->forge->addKey(['invoice_id']);
|
||||
$this->forge->addKey(['school_year']);
|
||||
$this->forge->addKey(['period_year', 'period_month']);
|
||||
// Unique combination to prevent duplicate sends per period/type
|
||||
$this->forge->addKey(['parent_id', 'period_year', 'period_month', 'type'], false, true);
|
||||
|
||||
$this->forge->createTable('payment_notification_logs', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('payment_notification_logs')) {
|
||||
$this->forge->dropTable('payment_notification_logs', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateParentAttendanceReports extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('parent_attendance_reports')) {
|
||||
return; // already created
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'parent_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
'comment' => 'users.id of the reporting parent (primary parent id)'
|
||||
],
|
||||
'student_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'report_date' => [
|
||||
'type' => 'DATE',
|
||||
'null' => false,
|
||||
],
|
||||
'type' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['absent', 'late', 'early_dismissal'],
|
||||
'default' => 'absent',
|
||||
'null' => false,
|
||||
],
|
||||
'arrival_time' => [
|
||||
'type' => 'TIME', // for late
|
||||
'null' => true,
|
||||
],
|
||||
'dismiss_time' => [
|
||||
'type' => 'TIME', // for early dismissal
|
||||
'null' => true,
|
||||
],
|
||||
'reason' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 16,
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['new','seen','processed'],
|
||||
'default' => 'new',
|
||||
'null' => false,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['report_date']);
|
||||
$this->forge->addKey(['student_id', 'report_date']);
|
||||
$this->forge->addForeignKey('parent_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('parent_attendance_reports', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('parent_attendance_reports')) {
|
||||
$this->forge->dropTable('parent_attendance_reports', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddSemesterToLateSlipLogs extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Add nullable semester column and an index with school_year if not present
|
||||
if ($this->db->tableExists('late_slip_logs')) {
|
||||
$fields = $this->db->getFieldNames('late_slip_logs');
|
||||
if (!in_array('semester', $fields, true)) {
|
||||
$this->forge->addColumn('late_slip_logs', [
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
'after' => 'school_year',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Best-effort: add composite index if missing
|
||||
try {
|
||||
$sql = "SHOW INDEX FROM late_slip_logs WHERE Key_name = 'idx_late_slip_year_sem'";
|
||||
$exists = $this->db->query($sql)->getResultArray();
|
||||
if (empty($exists)) {
|
||||
$this->db->query('ALTER TABLE late_slip_logs ADD INDEX idx_late_slip_year_sem (school_year, semester)');
|
||||
}
|
||||
} catch (\Throwable $e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('late_slip_logs')) {
|
||||
try { $this->db->query('ALTER TABLE late_slip_logs DROP INDEX idx_late_slip_year_sem'); } catch (\Throwable $e) {}
|
||||
try { $this->forge->dropColumn('late_slip_logs', 'semester'); } catch (\Throwable $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePromotionQueue extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'student_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'from_class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
],
|
||||
'to_class_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'to_class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
],
|
||||
'school_year_from' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 9,
|
||||
'null' => false,
|
||||
],
|
||||
'school_year_to' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 9,
|
||||
'null' => false,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['queued','assigned','applied','cancelled'],
|
||||
'default' => 'queued',
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
],
|
||||
'updated_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['student_id', 'school_year_to'], false, true, 'uq_student_year_to');
|
||||
$this->forge->addKey('to_class_id');
|
||||
$this->forge->createTable('promotion_queue', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('promotion_queue', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateEarlyDismissalSignatures extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('early_dismissal_signatures')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'report_date' => [
|
||||
'type' => 'DATE',
|
||||
'null' => false,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 16,
|
||||
'null' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'filename' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
],
|
||||
'original_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'mime_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 128,
|
||||
'null' => true,
|
||||
],
|
||||
'file_size' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'uploaded_by' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['report_date']);
|
||||
$this->forge->addUniqueKey(['report_date', 'school_year', 'semester'], 'uniq_early_dismissal_signature');
|
||||
$this->forge->createTable('early_dismissal_signatures', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('early_dismissal_signatures')) {
|
||||
$this->forge->dropTable('early_dismissal_signatures', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddTimezoneToPreferencesAndSettings extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// user_preferences.timezone
|
||||
if ($this->db->tableExists('user_preferences') && ! $this->db->fieldExists('timezone', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'timezone' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 64,
|
||||
'null' => true,
|
||||
'after' => 'language',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// settings.timezone (only if table exists)
|
||||
if ($this->db->tableExists('settings') && ! $this->db->fieldExists('timezone', 'settings')) {
|
||||
$this->forge->addColumn('settings', [
|
||||
'timezone' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 64,
|
||||
'null' => true,
|
||||
'after' => 'name',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('user_preferences') && $this->db->fieldExists('timezone', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'timezone');
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('settings') && $this->db->fieldExists('timezone', 'settings')) {
|
||||
$this->forge->dropColumn('settings', 'timezone');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddDonationCategoryToExpenses extends Migration
|
||||
{
|
||||
/**
|
||||
* Allow marking expenses as non-reimbursable donations.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$this->forge->modifyColumn('expenses', [
|
||||
'category' => [
|
||||
'type' => "ENUM('Expense','Purchase','Reimbursement','Donation')",
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert to the original enum; donation rows are coerced back to Expense.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// Convert any donation rows to Expense to keep rollback safe.
|
||||
$this->db->table('expenses')
|
||||
->where('category', 'Donation')
|
||||
->set('category', 'Expense')
|
||||
->update();
|
||||
|
||||
$this->forge->modifyColumn('expenses', [
|
||||
'category' => [
|
||||
'type' => "ENUM('Expense','Purchase','Reimbursement')",
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateReimbursementBatchAdminFiles extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'batch_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'admin_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'filename' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
],
|
||||
'original_filename' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'uploaded_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
'uploaded_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addField($fields);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('batch_id');
|
||||
$this->forge->addKey('admin_id');
|
||||
$this->forge->addUniqueKey(['batch_id', 'admin_id']);
|
||||
$this->forge->createTable('reimbursement_batch_admin_files');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('reimbursement_batch_admin_files', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddReviewFieldsToScoreComments extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('score_comments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('score_comments');
|
||||
|
||||
if (!in_array('comment_review', $fields, true)) {
|
||||
$this->forge->addColumn('score_comments', [
|
||||
'comment_review' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
'after' => 'comment',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if (!in_array('reviewed_by', $fields, true)) {
|
||||
$this->forge->addColumn('score_comments', [
|
||||
'reviewed_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'comment_review',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Allow comments to be nullable so reviewers can attach feedback without a comment body
|
||||
if (in_array('comment', $fields, true)) {
|
||||
try {
|
||||
$this->forge->modifyColumn('score_comments', [
|
||||
'comment' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
// Best effort only
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('score_comments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->modifyColumn('score_comments', [
|
||||
'comment' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore rollback errors
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->dropColumn('score_comments', 'reviewed_by');
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore rollback errors
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->dropColumn('score_comments', 'comment_review');
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore rollback errors
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateAttendanceCommentTemplates extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('attendance_comment_template')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'min_score' => [
|
||||
'type' => 'DECIMAL',
|
||||
'constraint' => '5,2',
|
||||
'null' => false,
|
||||
],
|
||||
'max_score' => [
|
||||
'type' => 'DECIMAL',
|
||||
'constraint' => '5,2',
|
||||
'null' => false,
|
||||
],
|
||||
'template_text' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => false,
|
||||
],
|
||||
'is_active' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 1,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['min_score', 'max_score']);
|
||||
$this->forge->addKey('is_active');
|
||||
$this->forge->createTable('attendance_comment_template', true);
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$rows = [
|
||||
[
|
||||
'min_score' => 100.00,
|
||||
'max_score' => 100.00,
|
||||
'template_text' => '{name} has maintained perfect attendance this semester, showing exceptional commitment and reliability. Outstanding consistency in attending every class session without fail. Keep it up and stay strong - bravo!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 95.00,
|
||||
'max_score' => 99.99,
|
||||
'template_text' => '{name} has maintained excellent attendance this semester, demonstrating strong commitment and reliability. Only rare absences, with a consistent routine of being present for class. Keep up the great consistency - well done!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 90.00,
|
||||
'max_score' => 94.99,
|
||||
'template_text' => '{name} has demonstrated very good attendance this semester, reflecting dependable responsibility. Missed only a few class sessions and remains consistent overall. Keep striving for even stronger attendance - great work!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 85.00,
|
||||
'max_score' => 89.99,
|
||||
'template_text' => '{name} has maintained good attendance this semester and displays responsible habits. A few absences were noted, yet overall consistency is solid. Aim for even fewer missed days to strengthen your routine - keep it going!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 80.00,
|
||||
'max_score' => 84.99,
|
||||
'template_text' => '{name}\'s attendance has been fairly consistent this semester, with some missed class sessions. Being present more regularly will support steady progress. You\'re on the right track - keep improving!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 75.00,
|
||||
'max_score' => 79.99,
|
||||
'template_text' => '{name}\'s attendance has been moderate this semester, with several absences impacting consistency. Prioritizing attendance will help strengthen routines and lead to success. Let\'s keep improving week by week - you\'ve got this!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 70.00,
|
||||
'max_score' => 74.99,
|
||||
'template_text' => '{name}\'s attendance has been somewhat inconsistent this semester, with missed sessions creating noticeable gaps. Focusing on regular attendance will help build a steady and reliable routine. Keep working on it - you can do it!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 65.00,
|
||||
'max_score' => 69.99,
|
||||
'template_text' => '{name}\'s attendance needs improvement this semester due to several missed classes. A renewed focus on being present regularly will help build stronger habits and lead to a successful finish. Keep going - you\'ve got this!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 60.00,
|
||||
'max_score' => 64.99,
|
||||
'template_text' => '{name}\'s attendance has been a concern this semester, with many missed classes. Making a consistent effort to attend regularly will help strengthen routines and keep learning on track. Stay focused - you can do this!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 55.00,
|
||||
'max_score' => 59.99,
|
||||
'template_text' => '{name}\'s attendance has been challenging this semester, with numerous absences recorded. A stronger commitment to being present each week will help build better habits and steady progress. Keep pushing forward!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 50.00,
|
||||
'max_score' => 54.99,
|
||||
'template_text' => '{name}\'s attendance has been inconsistent this semester, with many missed sessions. Prioritizing daily attendance will help rebuild consistency, strengthen learning routines, and support steady progress. You\'ve got this - stay committed!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 45.00,
|
||||
'max_score' => 49.99,
|
||||
'template_text' => '{name}\'s attendance has been irregular this semester, with several missed classes. Refocusing on regular attendance will help restore consistency and lay the foundation for success. Keep at it - you\'re capable!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
[
|
||||
'min_score' => 0.00,
|
||||
'max_score' => 44.99,
|
||||
'template_text' => '{name}\'s attendance has been significantly limited this semester, with many absences. Starting fresh with consistent attendance can help you rebuild strong habits and finish the term successfully. A new start - let\'s go!',
|
||||
'is_active' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
];
|
||||
|
||||
$this->db->table('attendance_comment_template')->insertBatch($rows);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('attendance_comment_template')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropTable('attendance_comment_template', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePrintRequests extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'teacher_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'admin_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'class_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'file_path' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '255',
|
||||
],
|
||||
'num_copies' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
],
|
||||
'required_by' => [
|
||||
'type' => 'DATETIME',
|
||||
],
|
||||
'pickup_method' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '255',
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['not_assigned', 'assigned', 'done', 'delivered'],
|
||||
'default' => 'not_assigned',
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addForeignKey('teacher_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('admin_id', 'users', 'id', 'CASCADE', 'SET NULL');
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('print_requests');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class FixPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Drop the old foreign key if it exists
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
|
||||
// Add the new foreign key
|
||||
$this->forge->addForeignKey('class_id', 'class_sections', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Process the modifications
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Drop the new foreign key
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Process the modifications
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class RevertPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Drop the old foreign key if it exists
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
|
||||
// Add the new foreign key
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Process the modifications
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Drop the new foreign key
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'class_sections', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Process the modifications
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class DropPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// Drop the old foreign key if it exists
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'class_sections', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
// Process the modifications
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class FixPrintRequestsForeignKeyOnceAndForAll extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$keys = $db->getForeignKeyData('print_requests');
|
||||
foreach ($keys as $key) {
|
||||
if ($key->constraint_name === 'print_requests_class_id_foreign') {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->forge->addForeignKey('class_id', 'classSection', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class FixPrintRequestsForeignKeyAgain extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$keys = $db->getForeignKeyData('print_requests');
|
||||
foreach ($keys as $key) {
|
||||
if ($key->constraint_name === 'print_requests_class_id_foreign') {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->forge->addForeignKey('class_id', 'classSection', 'class_id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateCompetitions extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'title' => ['type' => 'VARCHAR', 'constraint' => 150],
|
||||
'semester' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => true],
|
||||
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
|
||||
'class_section_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
'start_date' => ['type' => 'DATE', 'null' => true],
|
||||
'end_date' => ['type' => 'DATE', 'null' => true],
|
||||
'winners_count' => ['type' => 'INT', 'constraint' => 11, 'default' => 3],
|
||||
'prize_per_point' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'default' => 1],
|
||||
'is_published' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
|
||||
'published_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'created_by' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'deleted_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_section_id']);
|
||||
$this->forge->addKey(['is_published']);
|
||||
$this->forge->createTable('competitions', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('competitions', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateCompetitionScores extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'competition_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'class_section_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
'score' => ['type' => 'DECIMAL', 'constraint' => '6,2', 'default' => 0],
|
||||
'notes' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
|
||||
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['competition_id']);
|
||||
$this->forge->addKey(['student_id']);
|
||||
$this->forge->addKey(['class_section_id']);
|
||||
$this->forge->addUniqueKey(['competition_id', 'student_id', 'class_section_id']);
|
||||
$this->forge->createTable('competition_scores', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('competition_scores', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateCompetitionWinners extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'competition_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'class_section_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
'rank' => ['type' => 'INT', 'constraint' => 11],
|
||||
'score' => ['type' => 'DECIMAL', 'constraint' => '6,2', 'default' => 0],
|
||||
'prize_amount' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'default' => 0],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['competition_id']);
|
||||
$this->forge->addKey(['class_section_id']);
|
||||
$this->forge->addUniqueKey(['competition_id', 'class_section_id', 'rank']);
|
||||
$this->forge->addUniqueKey(['competition_id', 'class_section_id', 'student_id']);
|
||||
$this->forge->createTable('competition_winners', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('competition_winners', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddCompetitionNavItems extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('nav_items')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parentColumn = null;
|
||||
if ($db->fieldExists('menu_parent_id', 'nav_items')) {
|
||||
$parentColumn = 'menu_parent_id';
|
||||
} elseif ($db->fieldExists('parent_id', 'nav_items')) {
|
||||
$parentColumn = 'parent_id';
|
||||
}
|
||||
|
||||
if ($parentColumn === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$navBuilder = $db->table('nav_items');
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
$eventRow = $navBuilder
|
||||
->select('id')
|
||||
->where('label', 'Event Management')
|
||||
->where($parentColumn, null)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($eventRow) {
|
||||
$eventId = (int) $eventRow['id'];
|
||||
} else {
|
||||
$navBuilder->insert([
|
||||
$parentColumn => null,
|
||||
'label' => 'Event Management',
|
||||
'url' => null,
|
||||
'sort_order' => 110,
|
||||
'is_enabled' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$eventId = (int) $db->insertID();
|
||||
}
|
||||
|
||||
$competitionUrl = 'admin/competition-winners';
|
||||
$existing = $navBuilder->select('id')
|
||||
->where('url', $competitionUrl)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!$existing) {
|
||||
$navBuilder->insert([
|
||||
$parentColumn => $eventId ?: null,
|
||||
'label' => 'Competition Winners',
|
||||
'url' => $competitionUrl,
|
||||
'sort_order' => 3,
|
||||
'is_enabled' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$competitionId = (int) $db->insertID();
|
||||
} else {
|
||||
$competitionId = (int) $existing['id'];
|
||||
}
|
||||
|
||||
if (!$db->tableExists('role_nav_items') || !$db->tableExists('roles')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($competitionId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roleRows = $db->table('roles')
|
||||
->select('id, name')
|
||||
->whereIn('name', ['administrator', 'principal', 'vice_principal'])
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$roleMap = $db->table('role_nav_items');
|
||||
foreach ($roleRows as $role) {
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
if ($roleId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$exists = $roleMap
|
||||
->where('role_id', $roleId)
|
||||
->where('nav_item_id', $competitionId)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$roleMap->insert([
|
||||
'role_id' => $roleId,
|
||||
'nav_item_id' => $competitionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('nav_items')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$competitionUrl = 'admin/competition-winners';
|
||||
$row = $db->table('nav_items')
|
||||
->select('id')
|
||||
->where('url', $competitionUrl)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($row && $db->tableExists('role_nav_items')) {
|
||||
$db->table('role_nav_items')
|
||||
->where('nav_item_id', (int) $row['id'])
|
||||
->delete();
|
||||
}
|
||||
|
||||
$db->table('nav_items')
|
||||
->where('url', $competitionUrl)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateCompetitionClassWinners extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'competition_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'class_section_id' => ['type' => 'INT', 'constraint' => 11],
|
||||
'winners_override' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
'question_count' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
'prize_1' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_2' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_3' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_4' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_5' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_6' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['competition_id', 'class_section_id']);
|
||||
$this->forge->createTable('competition_class_winners', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('competition_class_winners', true);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddQuestionCountToCompetitionClassWinners extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
if ($db->fieldExists('question_count', 'competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('competition_class_winners', [
|
||||
'question_count' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
if (!$db->fieldExists('question_count', 'competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropColumn('competition_class_winners', 'question_count');
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddPrizeColumnsToCompetitionClassWinners extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = [
|
||||
'prize_1' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_2' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_3' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_4' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_5' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
'prize_6' => ['type' => 'DECIMAL', 'constraint' => '10,2', 'null' => true],
|
||||
];
|
||||
|
||||
$add = [];
|
||||
foreach ($columns as $name => $def) {
|
||||
if (!$db->fieldExists($name, 'competition_class_winners')) {
|
||||
$add[$name] = $def;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($add)) {
|
||||
$this->forge->addColumn('competition_class_winners', $add);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_class_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$names = ['prize_1','prize_2','prize_3','prize_4','prize_5','prize_6'];
|
||||
foreach ($names as $name) {
|
||||
if ($db->fieldExists($name, 'competition_class_winners')) {
|
||||
$this->forge->dropColumn('competition_class_winners', $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AllowCompetitionWinnerRankTies extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($db->indexExists('competition_winners', 'competition_id_class_section_id_rank')) {
|
||||
$db->query('DROP INDEX competition_id_class_section_id_rank ON competition_winners');
|
||||
}
|
||||
|
||||
if (!$db->indexExists('competition_winners', 'competition_id_class_section_id_rank')) {
|
||||
$db->query(
|
||||
'CREATE INDEX competition_id_class_section_id_rank ON competition_winners (competition_id, class_section_id, rank)'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (!$db->tableExists('competition_winners')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($db->indexExists('competition_winners', 'competition_id_class_section_id_rank')) {
|
||||
$db->query('DROP INDEX competition_id_class_section_id_rank ON competition_winners');
|
||||
}
|
||||
|
||||
$db->query(
|
||||
'ALTER TABLE competition_winners ADD UNIQUE KEY competition_id_class_section_id_rank (competition_id, class_section_id, rank)'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateAdminNotificationSubjects extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('admin_notification_subjects')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'admin_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'subject' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 100,
|
||||
'null' => false,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('admin_id');
|
||||
$this->forge->addUniqueKey(['admin_id', 'subject']);
|
||||
$this->forge->createTable('admin_notification_subjects', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('admin_notification_subjects')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropTable('admin_notification_subjects', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddCompetitionLockFields extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('competitions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
if (!$db->fieldExists('is_locked', 'competitions')) {
|
||||
$fields['is_locked'] = ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0];
|
||||
}
|
||||
if (!$db->fieldExists('locked_at', 'competitions')) {
|
||||
$fields['locked_at'] = ['type' => 'DATETIME', 'null' => true];
|
||||
}
|
||||
if (!$db->fieldExists('locked_by', 'competitions')) {
|
||||
$fields['locked_by'] = ['type' => 'INT', 'constraint' => 11, 'null' => true];
|
||||
}
|
||||
|
||||
if (!empty($fields)) {
|
||||
$this->forge->addColumn('competitions', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('competitions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = [];
|
||||
foreach (['is_locked', 'locked_at', 'locked_by'] as $column) {
|
||||
if ($db->fieldExists($column, 'competitions')) {
|
||||
$columns[] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($columns)) {
|
||||
$this->forge->dropColumn('competitions', $columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddStudentActiveFlag extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('students')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$db->fieldExists('is_active', 'students')) {
|
||||
$this->forge->addColumn('students', [
|
||||
'is_active' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 1,
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->tableExists('students')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($db->fieldExists('is_active', 'students')) {
|
||||
$this->forge->dropColumn('students', 'is_active');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateClassProgressReports extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('class_progress_reports')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'class_section_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'teacher_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'week_start' => ['type' => 'DATE'],
|
||||
'week_end' => ['type' => 'DATE'],
|
||||
'subject' => ['type' => 'VARCHAR', 'constraint' => 160, 'null' => true],
|
||||
'unit_title' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => true],
|
||||
'covered' => ['type' => 'TEXT'],
|
||||
'homework' => ['type' => 'TEXT', 'null' => true],
|
||||
'assessment' => ['type' => 'TEXT', 'null' => true],
|
||||
'status' => ['type' => 'VARCHAR', 'constraint' => 20],
|
||||
'status_notes' => ['type' => 'VARCHAR', 'constraint' => 200, 'null' => true],
|
||||
'class_notes' => ['type' => 'TEXT', 'null' => true],
|
||||
'next_week_plan' => ['type' => 'TEXT'],
|
||||
'support_needed' => ['type' => 'TEXT', 'null' => true],
|
||||
'flags_json' => ['type' => 'TEXT', 'null' => true],
|
||||
'attachment_path' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
'updated_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_section_id', 'week_start', 'week_end']);
|
||||
$this->forge->createTable('class_progress_reports');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('class_progress_reports', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateSubjectCurriculumItems extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('subject_curriculum_items')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'class_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'subject' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['islamic', 'quran'],
|
||||
'default' => 'islamic',
|
||||
],
|
||||
'unit_number' => [
|
||||
'type' => 'SMALLINT',
|
||||
'null' => true,
|
||||
],
|
||||
'unit_title' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'chapter_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_id', 'subject']);
|
||||
$this->forge->createTable('subject_curriculum_items');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('subject_curriculum_items', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class RemoveClassAssignmentSemester extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('teacher_class')) {
|
||||
$this->forge->dropColumn('teacher_class', 'semester');
|
||||
}
|
||||
if ($this->db->tableExists('student_class')) {
|
||||
$this->forge->dropColumn('student_class', 'semester');
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('teacher_class')) {
|
||||
$this->forge->addColumn('teacher_class', [
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 25,
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
if ($this->db->tableExists('student_class')) {
|
||||
$this->forge->addColumn('student_class', [
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateTeacherSubmissionNotificationHistory extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'teacher_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'admin_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'notification_category' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 64,
|
||||
'default' => 'teacher_submissions',
|
||||
],
|
||||
'message' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'default' => 'sent',
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'sent_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['teacher_id', 'class_section_id']);
|
||||
$this->forge->createTable('teacher_submission_notification_history');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('teacher_submission_notification_history');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEventTypeToCalendarEvents extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
if (!$db->fieldExists('event_type', 'calendar_events')) {
|
||||
$this->forge->addColumn('calendar_events', [
|
||||
'event_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'after' => 'description',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if ($db->fieldExists('event_type', 'calendar_events')) {
|
||||
$this->forge->dropColumn('calendar_events', 'event_type');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateExamDraftSubmissions extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'teacher_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => false,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => false,
|
||||
],
|
||||
'exam_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 64,
|
||||
'null' => true,
|
||||
],
|
||||
'draft_title' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 191,
|
||||
'null' => false,
|
||||
],
|
||||
'description' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'teacher_file' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 512,
|
||||
'null' => true,
|
||||
],
|
||||
'teacher_filename' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 512,
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'default' => 'pending',
|
||||
],
|
||||
'admin_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'admin_comments' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'reviewed_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'final_file' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 512,
|
||||
'null' => true,
|
||||
],
|
||||
'final_filename' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 512,
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['teacher_id', 'class_section_id']);
|
||||
$this->forge->createTable('exam_drafts');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('exam_drafts');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddVersionToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'version' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'default' => 1,
|
||||
],
|
||||
'previous_draft_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('version');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('exam_drafts', ['version', 'previous_draft_id']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddFinalPdfToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'final_pdf_file' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
'after' => 'final_filename',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('exam_drafts', 'final_pdf_file');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddIsLegacyToExamDrafts extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addColumn('exam_drafts', [
|
||||
'is_legacy' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
'after' => 'admin_id',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('exam_drafts', 'is_legacy');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddClassSectionIdToScoreComments extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('score_comments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('score_comments');
|
||||
|
||||
if (!in_array('class_section_id', $fields, true)) {
|
||||
$this->forge->addColumn('score_comments', [
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'student_id',
|
||||
],
|
||||
]);
|
||||
try {
|
||||
$this->db->query('CREATE INDEX idx_score_comments_class_section ON score_comments(class_section_id)');
|
||||
} catch (\Throwable $e) {
|
||||
// Index may already exist; ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('subject_id', $fields, true)) {
|
||||
try {
|
||||
$this->forge->dropColumn('score_comments', 'subject_id');
|
||||
} catch (\Throwable $e) {
|
||||
// ignore if drop fails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('score_comments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('score_comments');
|
||||
|
||||
if (!in_array('subject_id', $fields, true)) {
|
||||
$this->forge->addColumn('score_comments', [
|
||||
'subject_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'student_id',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if (in_array('class_section_id', $fields, true)) {
|
||||
try {
|
||||
$this->forge->dropColumn('score_comments', 'class_section_id');
|
||||
} catch (\Throwable $e) {
|
||||
// ignore if drop fails
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateParentMeetingSchedules extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('parent_meeting_schedules')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'student_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'parent_user_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'parent_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 200,
|
||||
'null' => true,
|
||||
],
|
||||
'student_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 200,
|
||||
'null' => true,
|
||||
],
|
||||
'class_section_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 200,
|
||||
'null' => true,
|
||||
],
|
||||
'date' => [
|
||||
'type' => 'DATE',
|
||||
],
|
||||
'time' => [
|
||||
'type' => 'TIME',
|
||||
'null' => true,
|
||||
],
|
||||
'notes' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'null' => true,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'default' => 'scheduled',
|
||||
],
|
||||
'created_by' => [
|
||||
'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('student_id');
|
||||
$this->forge->addKey('parent_user_id');
|
||||
$this->forge->addKey('date');
|
||||
|
||||
$this->forge->createTable('parent_meeting_schedules', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('parent_meeting_schedules')) {
|
||||
$this->forge->dropTable('parent_meeting_schedules', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateClassProgressAttachments extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('class_progress_attachments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'report_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'file_path' => ['type' => 'VARCHAR', 'constraint' => 255],
|
||||
'original_name' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
|
||||
'mime_type' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => true],
|
||||
'file_size' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'created_at' => ['type' => 'DATETIME', 'null' => true],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('report_id');
|
||||
$this->forge->createTable('class_progress_attachments');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('class_progress_attachments', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePlacementLevels extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('placement_levels')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'level' => ['type' => 'SMALLINT', 'constraint' => 3, 'unsigned' => true],
|
||||
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
|
||||
'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'updated_by' => ['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(['student_id', 'school_year'], true);
|
||||
$this->forge->addKey('school_year');
|
||||
$this->forge->createTable('placement_levels');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('placement_levels', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class UpdatePlacementLevelRange extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('placement_levels')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('placement_levels');
|
||||
if (!in_array('level', $fields, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->modifyColumn('placement_levels', [
|
||||
'level' => ['type' => 'SMALLINT', 'constraint' => 3, 'unsigned' => true],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('placement_levels')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('placement_levels');
|
||||
if (!in_array('level', $fields, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->modifyColumn('placement_levels', [
|
||||
'level' => ['type' => 'TINYINT', 'constraint' => 1, 'unsigned' => true],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePlacementBatches extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('placement_batches')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'placement_test' => ['type' => 'VARCHAR', 'constraint' => 30],
|
||||
'school_year' => ['type' => 'VARCHAR', 'constraint' => 20],
|
||||
'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'updated_by' => ['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(['placement_test', 'school_year']);
|
||||
$this->forge->createTable('placement_batches');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('placement_batches', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePlacementScores extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('placement_scores')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
|
||||
'batch_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'student_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
|
||||
'score' => ['type' => 'SMALLINT', 'constraint' => 3, 'unsigned' => true],
|
||||
'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
|
||||
'updated_by' => ['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(['batch_id', 'student_id'], true);
|
||||
$this->forge->addKey('batch_id');
|
||||
$this->forge->createTable('placement_scores');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('placement_scores', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEventOnlyToStudentClass extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('student_class')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('student_class');
|
||||
if (in_array('is_event_only', $fields, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('student_class', [
|
||||
'is_event_only' => ['type' => 'TINYINT', 'constraint' => 1, 'unsigned' => true, 'default' => 0],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('student_class')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('student_class');
|
||||
if (!in_array('is_event_only', $fields, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropColumn('student_class', 'is_event_only');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateGradingLocks extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('grading_locks')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 9,
|
||||
],
|
||||
'is_locked' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
],
|
||||
'locked_by' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => true,
|
||||
],
|
||||
'locked_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['class_section_id', 'semester', 'school_year'], false, false, 'idx_grading_locks_section_term');
|
||||
$this->forge->addUniqueKey(['class_section_id', 'semester', 'school_year'], 'uniq_grading_locks_section_term');
|
||||
$this->forge->createTable('grading_locks', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('grading_locks', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateMissingScoreOverrides extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'student_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
],
|
||||
'semester' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
],
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
],
|
||||
'item_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 30,
|
||||
],
|
||||
'item_index' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => true,
|
||||
],
|
||||
'is_allowed' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
],
|
||||
'updated_by' => [
|
||||
'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(['class_section_id', 'semester', 'school_year', 'item_type'], false, 'missing_score_overrides_scope');
|
||||
$this->forge->addKey(['student_id', 'class_section_id', 'semester', 'school_year', 'item_type', 'item_index'], true, 'missing_score_overrides_unique');
|
||||
$this->forge->createTable('missing_score_overrides', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('missing_score_overrides', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Print all
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddStyleToPreferences extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('user_preferences')) {
|
||||
if (! $this->db->fieldExists('style_color', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'style_color' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
'after' => 'timezone',
|
||||
],
|
||||
]);
|
||||
}
|
||||
if (! $this->db->fieldExists('menu_color', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'menu_color' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
'after' => 'style_color',
|
||||
],
|
||||
]);
|
||||
}
|
||||
if (! $this->db->fieldExists('menu_custom_bg', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'menu_custom_bg' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 16,
|
||||
'null' => true,
|
||||
'after' => 'menu_color',
|
||||
],
|
||||
]);
|
||||
}
|
||||
if (! $this->db->fieldExists('menu_custom_text', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'menu_custom_text' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 16,
|
||||
'null' => true,
|
||||
'after' => 'menu_custom_bg',
|
||||
],
|
||||
]);
|
||||
}
|
||||
if (! $this->db->fieldExists('menu_custom_mode', 'user_preferences')) {
|
||||
$this->forge->addColumn('user_preferences', [
|
||||
'menu_custom_mode' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 8,
|
||||
'null' => true,
|
||||
'after' => 'menu_custom_text',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('user_preferences')) {
|
||||
if ($this->db->fieldExists('menu_custom_mode', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'menu_custom_mode');
|
||||
}
|
||||
if ($this->db->fieldExists('menu_custom_text', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'menu_custom_text');
|
||||
}
|
||||
if ($this->db->fieldExists('menu_custom_bg', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'menu_custom_bg');
|
||||
}
|
||||
if ($this->db->fieldExists('menu_color', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'menu_color');
|
||||
}
|
||||
if ($this->db->fieldExists('style_color', 'user_preferences')) {
|
||||
$this->forge->dropColumn('user_preferences', 'style_color');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class ExtendStaffAttendanceForTeachers extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addColumn('staff_attendance', [
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'user_id',
|
||||
],
|
||||
'position' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['main','ta'],
|
||||
'null' => true,
|
||||
'after' => 'class_section_id',
|
||||
],
|
||||
]);
|
||||
|
||||
// Unique constraint: 1 record per user per date
|
||||
$this->db->query("
|
||||
ALTER TABLE staff_attendance
|
||||
ADD UNIQUE KEY uniq_user_date (user_id, date)
|
||||
");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('staff_attendance', 'class_section_id');
|
||||
$this->forge->dropColumn('staff_attendance', 'position');
|
||||
$this->db->query("ALTER TABLE staff_attendance DROP INDEX uniq_user_date");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user