Files
accounting_dev_v2/application/migrations/20260906001100_finalize_budget_dimensions.php
2026-09-11 16:03:00 +07:00

143 lines
7.0 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Migration_Finalize_budget_dimensions extends CI_Migration
{
private function column($table, $column, $definition)
{
if ($this->tableExists($table) && !$this->fieldExists($table, $column)) {
$this->db->query("ALTER TABLE `{$table}` ADD `{$column}` {$definition}");
}
}
private function hasIndex($table, $name)
{
if (!$this->tableExists($table)) return false;
foreach ($this->db->query("SHOW INDEX FROM `{$table}`")->result() as $index) {
if ($index->Key_name === $name) return true;
}
return false;
}
private function tableExists($table)
{
return (bool) $this->db->query(
'SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=? LIMIT 1',
array($table)
)->row();
}
private function fieldExists($table, $column)
{
return (bool) $this->db->query(
'SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name=? AND column_name=? LIMIT 1',
array($table, $column)
)->row();
}
public function up()
{
foreach (array(
'company_id' => 'BIGINT UNSIGNED NULL AFTER `id`',
'description' => 'TEXT NULL AFTER `control_mode`',
'revision_no' => 'INT NOT NULL DEFAULT 1 AFTER `version_no`',
'parent_budget_id' => 'BIGINT UNSIGNED NULL AFTER `revision_no`',
'submitted_by' => 'INT NULL AFTER `created_by`',
'submitted_at' => 'DATETIME NULL AFTER `submitted_by`',
'rejected_by' => 'INT NULL AFTER `approved_at`',
'rejected_at' => 'DATETIME NULL AFTER `rejected_by`',
'rejection_reason' => 'TEXT NULL AFTER `rejected_at`',
'updated_by' => 'INT NULL AFTER `created_at`',
'updated_at' => 'DATETIME NULL AFTER `updated_by`'
) as $column => $definition) $this->column('budgets', $column, $definition);
foreach (array(
'company_id' => 'BIGINT UNSIGNED NULL AFTER `id`',
'salesperson_id' => 'BIGINT UNSIGNED NULL AFTER `profit_center_id`',
'updated_by' => 'INT NULL AFTER `notes`',
'created_at' => 'DATETIME NULL AFTER `updated_by`',
'updated_at' => 'DATETIME NULL AFTER `created_at`'
) as $column => $definition) $this->column('budget_lines', $column, $definition);
foreach (array(
'company_id' => 'BIGINT UNSIGNED NULL AFTER `id`',
'description' => 'VARCHAR(255) NULL AFTER `name`',
'source_type' => 'VARCHAR(40) NULL AFTER `parent_id`',
'source_id' => 'BIGINT UNSIGNED NULL AFTER `source_type`',
'created_by' => 'INT NULL AFTER `is_active`',
'updated_by' => 'INT NULL AFTER `created_by`',
'updated_at' => 'DATETIME NULL AFTER `created_at`'
) as $column => $definition) $this->column('business_dimensions', $column, $definition);
foreach (array('require_branch','require_department','require_project','require_cost_center','require_profit_center') as $column) {
$this->column('accounts', $column, 'TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_hidden`');
}
foreach (array('branch_id','department_id','profit_center_id','salesperson_id') as $column) {
$this->column('purchase_order_lines', $column, 'BIGINT UNSIGNED NULL AFTER `budget_account_id`');
}
if (!$this->tableExists('budget_commitments')) {
$this->db->query("CREATE TABLE `budget_commitments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`company_id` BIGINT UNSIGNED NOT NULL,
`source_type` VARCHAR(50) NOT NULL,
`source_id` BIGINT UNSIGNED NOT NULL,
`source_line_id` BIGINT UNSIGNED NULL,
`account_id` INT NOT NULL,
`period` CHAR(7) NOT NULL,
`branch_id` BIGINT UNSIGNED NULL,
`department_id` BIGINT UNSIGNED NULL,
`project_id` BIGINT UNSIGNED NULL,
`cost_center_id` BIGINT UNSIGNED NULL,
`profit_center_id` BIGINT UNSIGNED NULL,
`salesperson_id` BIGINT UNSIGNED NULL,
`original_amount` DECIMAL(18,2) NOT NULL DEFAULT 0,
`realized_amount` DECIMAL(18,2) NOT NULL DEFAULT 0,
`released_amount` DECIMAL(18,2) NOT NULL DEFAULT 0,
`status` ENUM('active','partially_realized','realized','released') NOT NULL DEFAULT 'active',
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_budget_commitment_source` (`company_id`,`source_type`,`source_line_id`),
KEY `idx_budget_commitment_report` (`company_id`,`period`,`account_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
}
if (!$this->tableExists('budget_audit_logs')) {
$this->db->query("CREATE TABLE `budget_audit_logs` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`company_id` BIGINT UNSIGNED NOT NULL,
`budget_id` BIGINT UNSIGNED NULL,
`entity_type` VARCHAR(40) NOT NULL,
`entity_id` BIGINT UNSIGNED NULL,
`action` VARCHAR(50) NOT NULL,
`old_values` LONGTEXT NULL,
`new_values` LONGTEXT NULL,
`reason` TEXT NULL,
`created_by` INT NULL,
`created_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_budget_audit_entity` (`company_id`,`entity_type`,`entity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
}
if (!$this->hasIndex('budgets', 'idx_budget_company_year_status'))
$this->db->query('ALTER TABLE `budgets` ADD KEY `idx_budget_company_year_status` (`company_id`,`fiscal_year`,`status`)');
if (!$this->hasIndex('budget_lines', 'idx_budget_line_report'))
$this->db->query('ALTER TABLE `budget_lines` ADD KEY `idx_budget_line_report` (`company_id`,`period`,`account_id`)');
if (!$this->hasIndex('business_dimensions', 'idx_dimension_lookup'))
$this->db->query('ALTER TABLE `business_dimensions` ADD KEY `idx_dimension_lookup` (`company_id`,`dimension_type`,`is_active`,`name`)');
$this->db->query('UPDATE `budgets` SET `revision_no`=`version_no` WHERE `revision_no`=1 AND `version_no`>1');
if ($this->tableExists('k_departments')) {
$this->db->query("UPDATE business_dimensions bd JOIN k_departments d ON bd.dimension_type='department' AND bd.code=CONCAT('DEP-',d.id) SET bd.source_type='k_departments',bd.source_id=d.id,bd.name=d.department_name,bd.description=d.description WHERE bd.source_id IS NULL");
}
}
public function down()
{
throw new RuntimeException('Gunakan backup database untuk rollback finalisasi Budget & Dimensi.');
}
}