Update besar apk finance
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
class Migration_Create_hr_payroll_professional extends CI_Migration
|
||||
{
|
||||
private function col($t,$c,$sql){if($this->db->table_exists($t)&&!$this->db->field_exists($c,$t))$this->db->query("ALTER TABLE `$t` ADD `$c` $sql");}
|
||||
public function up(){
|
||||
foreach(array('tax_status'=>'VARCHAR(20) NULL','tax_number'=>'VARCHAR(50) NULL','benefit_profile_id'=>'BIGINT UNSIGNED NULL','confidentiality_level'=>"ENUM('normal','restricted') NOT NULL DEFAULT 'restricted'",'version'=>'INT NOT NULL DEFAULT 1')as$c=>$s)$this->col('k_employees',$c,$s);
|
||||
foreach(array('workflow_status'=>"ENUM('draft','reviewed','approved','final','posted','paid','cancelled') NOT NULL DEFAULT 'draft'",'reviewed_by'=>'INT NULL','reviewed_at'=>'DATETIME NULL','approved_by'=>'INT NULL','approved_at'=>'DATETIME NULL','finalized_by'=>'INT NULL','finalized_at'=>'DATETIME NULL','journal_id'=>'INT NULL','payment_transaction_id'=>'BIGINT UNSIGNED NULL','cancelled_by'=>'INT NULL','cancelled_at'=>'DATETIME NULL','cancellation_reason'=>'TEXT NULL','calculation_hash'=>'CHAR(64) NULL')as$c=>$s)$this->col('k_payroll_periods',$c,$s);
|
||||
$this->col('k_payrolls','gross_salary','DECIMAL(18,2) NOT NULL DEFAULT 0');$this->col('k_payrolls','total_deductions','DECIMAL(18,2) NOT NULL DEFAULT 0');$this->col('k_payrolls','calculation_snapshot','LONGTEXT NULL');$this->col('k_payrolls','version','INT NOT NULL DEFAULT 1');
|
||||
$tables=array(
|
||||
'employee_employment_history'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,employee_id INT NOT NULL,effective_from DATE NOT NULL,effective_to DATE NULL,department_id INT NULL,position_id INT NULL,branch_id INT NULL,employment_status VARCHAR(30) NOT NULL,contract_no VARCHAR(80) NULL,contract_start DATE NULL,contract_end DATE NULL,basic_salary DECIMAL(18,2) NOT NULL DEFAULT 0,reason VARCHAR(255) NULL,created_by INT NULL,created_at DATETIME NOT NULL,KEY idx_employee_history(employee_id,effective_from)",
|
||||
'employee_documents'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,employee_id INT NOT NULL,document_type VARCHAR(50) NOT NULL,document_no VARCHAR(100) NULL,expiry_date DATE NULL,original_name VARCHAR(255) NOT NULL,stored_name VARCHAR(255) NOT NULL,mime_type VARCHAR(100) NOT NULL,file_size BIGINT UNSIGNED NOT NULL,sha256 CHAR(64) NOT NULL,access_level ENUM('hr','payroll_admin') NOT NULL DEFAULT 'hr',uploaded_by INT NULL,created_at DATETIME NOT NULL,KEY idx_employee_document(employee_id,document_type)",
|
||||
'attendance_devices'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,serial_no VARCHAR(100) NOT NULL,name VARCHAR(120) NULL,branch_id INT NULL,secret_hash CHAR(64) NULL,is_active TINYINT(1) NOT NULL DEFAULT 1,last_seen_at DATETIME NULL,UNIQUE KEY uq_attendance_device(serial_no)",
|
||||
'attendance_raw_logs'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,device_id BIGINT UNSIGNED NOT NULL,employee_pin VARCHAR(80) NOT NULL,check_time DATETIME NOT NULL,event_type VARCHAR(30) NULL,raw_payload TEXT NULL,payload_hash CHAR(64) NOT NULL,validation_status ENUM('valid','invalid','duplicate','unknown_employee') NOT NULL DEFAULT 'valid',processed_attendance_id BIGINT UNSIGNED NULL,received_at DATETIME NOT NULL,UNIQUE KEY uq_attendance_raw(device_id,payload_hash),KEY idx_raw_employee_time(employee_pin,check_time)",
|
||||
'attendance_corrections'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,attendance_id INT NOT NULL,requested_checkin DATETIME NULL,requested_checkout DATETIME NULL,requested_status VARCHAR(30) NULL,reason TEXT NOT NULL,status ENUM('submitted','approved','rejected','applied') NOT NULL DEFAULT 'submitted',requested_by INT NOT NULL,requested_at DATETIME NOT NULL,approved_by INT NULL,approved_at DATETIME NULL,applied_at DATETIME NULL,UNIQUE KEY uq_attendance_pending(attendance_id,status)",
|
||||
'attendance_period_locks'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,period CHAR(7) NOT NULL,branch_id INT NULL,status ENUM('open','locked') NOT NULL DEFAULT 'open',locked_by INT NULL,locked_at DATETIME NULL,notes TEXT NULL,UNIQUE KEY uq_attendance_lock(period,branch_id)",
|
||||
'overtime_requests'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,employee_id INT NOT NULL,overtime_date DATE NOT NULL,start_time TIME NOT NULL,end_time TIME NOT NULL,hours DECIMAL(8,2) NOT NULL,reason TEXT NOT NULL,status ENUM('submitted','approved','rejected','paid') NOT NULL DEFAULT 'submitted',requested_by INT NULL,approved_by INT NULL,approved_at DATETIME NULL,UNIQUE KEY uq_overtime_employee(employee_id,overtime_date,start_time)",
|
||||
'payroll_components'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,code VARCHAR(40) NOT NULL,name VARCHAR(120) NOT NULL,component_type ENUM('earning','deduction','employer_cost') NOT NULL,category ENUM('basic','allowance','overtime','unpaid_leave','loan','bpjs','tax','thr','bonus','other') NOT NULL,formula_expression VARCHAR(500) NULL,fixed_amount DECIMAL(18,2) NULL,taxable TINYINT(1) NOT NULL DEFAULT 1,prorated TINYINT(1) NOT NULL DEFAULT 0,expense_account_id INT NULL,liability_account_id INT NULL,is_active TINYINT(1) NOT NULL DEFAULT 1,UNIQUE KEY uq_payroll_component(code)",
|
||||
'employee_payroll_components'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,employee_id INT NOT NULL,component_id BIGINT UNSIGNED NOT NULL,amount_override DECIMAL(18,2) NULL,effective_from DATE NOT NULL,effective_to DATE NULL,is_active TINYINT(1) NOT NULL DEFAULT 1,UNIQUE KEY uq_employee_component(employee_id,component_id,effective_from)",
|
||||
'payroll_calculation_lines'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,payroll_id INT NOT NULL,component_id BIGINT UNSIGNED NULL,component_code VARCHAR(40) NOT NULL,component_name VARCHAR(120) NOT NULL,component_type ENUM('earning','deduction','employer_cost') NOT NULL,base_amount DECIMAL(18,2) NOT NULL DEFAULT 0,rate DECIMAL(18,6) NULL,quantity DECIMAL(18,4) NULL,amount DECIMAL(18,2) NOT NULL,formula_snapshot VARCHAR(500) NULL,expense_account_id INT NULL,liability_account_id INT NULL,UNIQUE KEY uq_payroll_component_line(payroll_id,component_code)",
|
||||
'employee_loans'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,loan_no VARCHAR(60) NOT NULL,employee_id INT NOT NULL,loan_date DATE NOT NULL,principal DECIMAL(18,2) NOT NULL,balance DECIMAL(18,2) NOT NULL,installment_amount DECIMAL(18,2) NOT NULL,status ENUM('active','paid','cancelled') NOT NULL DEFAULT 'active',receivable_account_id INT NULL,created_by INT NULL,UNIQUE KEY uq_employee_loan(loan_no)",
|
||||
'payroll_payments'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,payroll_period_id INT NOT NULL,payment_no VARCHAR(60) NOT NULL,payment_date DATE NOT NULL,cash_account_id BIGINT UNSIGNED NOT NULL,total_amount DECIMAL(18,2) NOT NULL,status ENUM('draft','submitted','approved','posted','rejected','reversed') NOT NULL DEFAULT 'draft',journal_id INT NULL,created_by INT NULL,approved_by INT NULL,posted_at DATETIME NULL,UNIQUE KEY uq_payroll_payment_no(payment_no),UNIQUE KEY uq_payroll_period_payment(payroll_period_id)",
|
||||
'payroll_cancellations'=>"id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,payroll_period_id INT NOT NULL,reason TEXT NOT NULL,reversal_journal_id INT NULL,status ENUM('submitted','approved','rejected','posted') NOT NULL DEFAULT 'submitted',requested_by INT NOT NULL,requested_at DATETIME NOT NULL,approved_by INT NULL,approved_at DATETIME NULL"
|
||||
);foreach($tables as$t=>$s)$this->db->query("CREATE TABLE IF NOT EXISTS `$t`($s) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
||||
$this->db->query("INSERT IGNORE INTO employee_employment_history(employee_id,effective_from,department_id,position_id,branch_id,employment_status,basic_salary,reason,created_at) SELECT id,join_date,department_id,position_id,branch_id,employment_status,basic_salary,'Backfill data aktif Tahap 10',NOW() FROM k_employees");
|
||||
foreach(array(array('BASIC','Gaji Pokok','earning','basic','basic_salary',null,1,1),array('OVERTIME','Lembur','earning','overtime','overtime_hours * overtime_rate',null,1,0),array('UNPAID_LEAVE','Cuti Tidak Dibayar','deduction','unpaid_leave','unpaid_days * daily_rate',null,0,0),array('THR','THR','earning','thr',null,null,1,0),array('BONUS','Bonus','earning','bonus',null,null,1,0),array('BPJS','BPJS Karyawan','deduction','bpjs',null,null,0,0),array('PPh21','PPh 21','deduction','tax',null,null,0,0),array('LOAN','Cicilan Pinjaman','deduction','loan',null,null,0,0))as$d)if(!$this->db->where('code',$d[0])->count_all_results('payroll_components'))$this->db->insert('payroll_components',array('code'=>$d[0],'name'=>$d[1],'component_type'=>$d[2],'category'=>$d[3],'formula_expression'=>$d[4],'fixed_amount'=>$d[5],'taxable'=>$d[6],'prorated'=>$d[7]));
|
||||
$this->db->query("UPDATE k_payroll_periods SET workflow_status=IF(status='draft','draft',IF(status IN('final','closed'),'final','draft'))");
|
||||
$this->db->query('DROP TRIGGER IF EXISTS trg_final_payroll_no_update');$this->db->query("CREATE TRIGGER trg_final_payroll_no_update BEFORE UPDATE ON k_payrolls FOR EACH ROW BEGIN DECLARE s VARCHAR(20); SELECT workflow_status INTO s FROM k_payroll_periods WHERE id=OLD.payroll_period_id; IF s IN('final','posted','paid') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Final payroll is locked'; END IF; END");
|
||||
$admin=$this->db->where('nama_role','Admin')->get('roles')->row();foreach(array(array('ATTENDANCE_CORRECTION','hr','attendance_correction','Koreksi Absensi'),array('PAYROLL_FINAL','payroll','payroll_period','Finalisasi Payroll'))as$w)if(!$this->db->where('code',$w[0])->count_all_results('approval_workflows')){$this->db->insert('approval_workflows',array('code'=>$w[0],'module'=>$w[1],'entity_type'=>$w[2],'name'=>$w[3],'require_separation'=>1,'is_active'=>1,'created_at'=>date('Y-m-d H:i:s')));if($admin)$this->db->insert('approval_workflow_steps',array('workflow_id'=>$this->db->insert_id(),'step_order'=>1,'name'=>'Persetujuan Admin','approver_role_id'=>$admin->id));}
|
||||
}
|
||||
public function down(){throw new RuntimeException('Gunakan backup untuk rollback Tahap 10.');}
|
||||
}
|
||||
Reference in New Issue
Block a user