db->table_exists('account_budget_entries')) { $this->db->query("CREATE TABLE `account_budget_entries` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `company_id` BIGINT UNSIGNED NOT NULL, `account_id` INT NOT NULL, `period` CHAR(7) NOT NULL, `entry_type` ENUM('recurring','override') NOT NULL DEFAULT 'recurring', `amount` DECIMAL(18,2) NOT NULL DEFAULT 0, `notes` VARCHAR(255) NULL, `is_active` TINYINT(1) NOT NULL DEFAULT 1, `created_by` INT NULL, `created_at` DATETIME NOT NULL, `updated_by` INT NULL, `updated_at` DATETIME NULL, PRIMARY KEY (`id`), UNIQUE KEY `uq_account_budget_entry` (`company_id`,`account_id`,`period`,`entry_type`), KEY `idx_account_budget_period` (`company_id`,`period`,`account_id`,`is_active`), CONSTRAINT `fk_account_budget_account` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); } // Pertahankan rincian budget aktif lama sebagai nilai khusus per bulan. if ($this->db->table_exists('budgets') && $this->db->table_exists('budget_lines')) { $this->db->query("INSERT IGNORE INTO account_budget_entries (company_id,account_id,period,entry_type,amount,notes,is_active,created_by,created_at) SELECT COALESCE(bl.company_id,b.company_id),bl.account_id,bl.period,'override',bl.amount, CONCAT('Migrasi dari ',b.budget_no),1,b.created_by,COALESCE(bl.created_at,b.created_at,NOW()) FROM budget_lines bl JOIN budgets b ON b.id=bl.budget_id WHERE b.status IN('active','approved') AND COALESCE(bl.company_id,b.company_id) IS NOT NULL"); // Nilai bulan terakhir sampai bulan migrasi menjadi dasar berulang ke depan. $currentPeriod = date('Y-m'); $this->db->query("INSERT IGNORE INTO account_budget_entries (company_id,account_id,period,entry_type,amount,notes,is_active,created_by,created_at) SELECT COALESCE(bl.company_id,b.company_id),bl.account_id,?,'recurring',bl.amount, CONCAT('Budget berulang hasil migrasi ',b.budget_no),1,b.created_by,NOW() FROM budget_lines bl JOIN budgets b ON b.id=bl.budget_id JOIN ( SELECT COALESCE(bl2.company_id,b2.company_id) company_id,bl2.account_id,MAX(bl2.period) period FROM budget_lines bl2 JOIN budgets b2 ON b2.id=bl2.budget_id WHERE b2.status IN('active','approved') AND bl2.period<=? GROUP BY COALESCE(bl2.company_id,b2.company_id),bl2.account_id ) latest ON latest.company_id=COALESCE(bl.company_id,b.company_id) AND latest.account_id=bl.account_id AND latest.period=bl.period WHERE b.status IN('active','approved')", array($currentPeriod, $currentPeriod)); } } public function down() { throw new RuntimeException('Gunakan backup database untuk rollback data budget per akun.'); } }