hr dan payroll

This commit is contained in:
Wian Drs
2026-09-15 10:38:43 +07:00
parent 5e1fd11410
commit 8fedd39d8f
47 changed files with 1409 additions and 370 deletions
+30 -4
View File
@@ -3,7 +3,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
class Companies extends MY_Admin_Controller
{
public function __construct(){parent::__construct();$this->load->database();$this->load->library(array('CompanyContext','MultiCurrencyService'));}
public function __construct(){parent::__construct();$this->load->database();$this->load->library(array('CompanyContext','MultiCurrencyService','AuditService'));}
public function index()
{
@@ -13,7 +13,8 @@ class Companies extends MY_Admin_Controller
$d['companies']=$this->db->order_by('name')->get('companies')->result();
$d['currencies']=$this->db->order_by('code')->get('currencies')->result();
$d['active_currencies']=$this->db->where('is_active',1)->order_by('code')->get('currencies')->result();
$d['bank_accounts']=$this->db->table_exists('company_bank_accounts')?$this->db->where('company_id',$companyId)->order_by('is_primary','DESC')->order_by('id')->get('company_bank_accounts')->result():array();
$d['bank_accounts']=$this->db->table_exists('company_bank_accounts')?$this->db->select('b.*,a.kode_akun,a.nama_akun')->from('company_bank_accounts b')->join('accounts a','a.id=b.gl_account_id AND a.company_id=b.company_id','left')->where('b.company_id',$companyId)->order_by('b.is_primary','DESC')->order_by('b.id')->get()->result():array();
$d['bank_gl_accounts']=$this->db->where(array('company_id'=>$companyId,'tipe'=>'asset','is_active'=>1,'allow_posting'=>1))->order_by('kode_akun')->get('accounts')->result();
$d['rates']=$this->db->select('r.*,c.name company_name')->from('exchange_rates r')->join('companies c','c.id=r.company_id')->where('r.company_id',$companyId)->order_by('rate_date','DESC')->limit(100)->get()->result();
$this->load->view('partials/header',$d);$this->load->view('companies/index',$d);$this->load->view('partials/footer',$d);
}
@@ -39,12 +40,36 @@ class Companies extends MY_Admin_Controller
public function save_bank()
{
$this->postOnly();$company=(int)$this->companycontext->id();try{$id=(int)$this->input->post('id');$row=array('company_id'=>$company,'bank_name'=>trim((string)$this->input->post('bank_name',true)),'account_number'=>trim((string)$this->input->post('account_number',true)),'account_holder'=>trim((string)$this->input->post('account_holder',true)),'currency'=>strtoupper(trim((string)$this->input->post('currency',true))),'is_primary'=>$this->input->post('is_primary')?1:0,'is_active'=>1,'updated_at'=>date('Y-m-d H:i:s'));if($row['bank_name']===''||$row['account_number']===''||$row['account_holder']==='')throw new RuntimeException('Nama bank, nomor rekening, dan nama pemilik wajib diisi.');if($row['is_primary'])$this->db->where('company_id',$company)->update('company_bank_accounts',array('is_primary'=>0));if($id){if(!$this->db->get_where('company_bank_accounts',array('id'=>$id,'company_id'=>$company))->row())throw new RuntimeException('Rekening perusahaan tidak ditemukan.');$this->db->where(array('id'=>$id,'company_id'=>$company))->update('company_bank_accounts',$row);}else{$row['created_at']=date('Y-m-d H:i:s');$this->db->insert('company_bank_accounts',$row);}$this->session->set_flashdata('success','Rekening perusahaan berhasil disimpan.');}catch(Throwable$e){$this->session->set_flashdata('error',$e->getMessage());}redirect('companies');
$this->postOnly();$company=(int)$this->companycontext->id();$transactionStarted=false;
try{
$id=(int)$this->input->post('id');$type=(string)$this->input->post('account_type',true);$opened=(string)$this->input->post('opened_at',true);$maturity=(string)$this->input->post('maturity_date',true);$interest=max(0,round((float)$this->input->post('interest_rate'),4));$gl=(int)$this->input->post('gl_account_id');
if(!in_array($type,array('savings','deposit'),true))throw new RuntimeException('Jenis rekening tidak valid.');
if(!$this->validDate($opened))throw new RuntimeException('Tanggal pembukaan rekening wajib diisi dengan benar.');
if($type==='deposit'&&!$this->validDate($maturity))throw new RuntimeException('Tanggal jatuh tempo wajib untuk rekening Deposito.');
if($type==='savings')$maturity=null;
if($maturity!==null&&$maturity<$opened)throw new RuntimeException('Tanggal jatuh tempo tidak boleh sebelum tanggal pembukaan.');
$coa=$this->db->get_where('accounts',array('id'=>$gl,'company_id'=>$company,'tipe'=>'asset','is_active'=>1,'allow_posting'=>1))->row();if(!$coa)throw new RuntimeException('Akun COA bank tidak valid atau bukan akun Aktiva aktif.');
$row=array('company_id'=>$company,'bank_name'=>trim((string)$this->input->post('bank_name',true)),'account_number'=>trim((string)$this->input->post('account_number',true)),'account_holder'=>trim((string)$this->input->post('account_holder',true)),'product_name'=>trim((string)$this->input->post('product_name',true)),'account_type'=>$type,'interest_rate'=>$interest,'opened_at'=>$opened,'maturity_date'=>$maturity,'currency'=>strtoupper(trim((string)$this->input->post('currency',true))),'gl_account_id'=>$gl,'is_primary'=>$this->input->post('is_primary')?1:0,'updated_at'=>date('Y-m-d H:i:s'));
if($row['bank_name']===''||$row['account_number']===''||$row['account_holder']===''||$row['product_name']==='')throw new RuntimeException('Nama bank, nomor rekening, pemilik, dan produk bank wajib diisi.');
if(!$this->db->get_where('currencies',array('code'=>$row['currency'],'is_active'=>1))->row())throw new RuntimeException('Mata uang rekening tidak valid.');
$this->db->where(array('company_id'=>$company,'account_number'=>$row['account_number']));if($id)$this->db->where('id !=',$id);if($this->db->count_all_results('company_bank_accounts'))throw new RuntimeException('Nomor rekening sudah terdaftar pada perusahaan ini.');
$before=null;$this->db->trans_begin();$transactionStarted=true;
if($row['is_primary'])$this->db->where('company_id',$company)->update('company_bank_accounts',array('is_primary'=>0,'updated_at'=>date('Y-m-d H:i:s')));
if($id){$before=$this->db->get_where('company_bank_accounts',array('id'=>$id,'company_id'=>$company))->row();if(!$before)throw new RuntimeException('Rekening perusahaan tidak ditemukan.');$this->db->where(array('id'=>$id,'company_id'=>$company))->update('company_bank_accounts',$row);$bankId=$id;}else{$row['is_active']=1;$row['created_at']=date('Y-m-d H:i:s');$this->db->insert('company_bank_accounts',$row);$bankId=(int)$this->db->insert_id();}
$after=$this->db->get_where('company_bank_accounts',array('id'=>$bankId,'company_id'=>$company))->row();$this->auditservice->record('company','company_bank_account',$bankId,$id?'update':'create',$before,$after,(int)$this->session->userdata('user_id'));if(!$this->db->trans_status())throw new RuntimeException('Rekening perusahaan gagal disimpan.');$this->db->trans_commit();$transactionStarted=false;$this->session->set_flashdata('success','Rekening perusahaan berhasil disimpan.');
}catch(Throwable$e){if($transactionStarted)$this->db->trans_rollback();$this->session->set_flashdata('error',$e->getMessage());}
redirect('companies#companyBanks');
}
public function toggle_bank($id)
{
$this->postOnly();$company=(int)$this->companycontext->id();$bank=$this->db->get_where('company_bank_accounts',array('id'=>(int)$id,'company_id'=>$company))->row();if($bank)$this->db->where(array('id'=>$bank->id,'company_id'=>$company))->update('company_bank_accounts',array('is_active'=>$bank->is_active?0:1,'is_primary'=>0,'updated_at'=>date('Y-m-d H:i:s')));$this->session->set_flashdata('success','Status rekening perusahaan diperbarui.');redirect('companies');
$this->postOnly();$company=(int)$this->companycontext->id();$this->db->trans_begin();
try{$bank=$this->db->query('SELECT * FROM company_bank_accounts WHERE id=? AND company_id=? FOR UPDATE',array((int)$id,$company))->row();if(!$bank)throw new RuntimeException('Rekening perusahaan tidak ditemukan.');$update=array('is_active'=>$bank->is_active?0:1,'is_primary'=>0,'updated_at'=>date('Y-m-d H:i:s'));$this->db->where(array('id'=>$bank->id,'company_id'=>$company))->update('company_bank_accounts',$update);$after=$this->db->get_where('company_bank_accounts',array('id'=>$bank->id,'company_id'=>$company))->row();$this->auditservice->record('company','company_bank_account',$bank->id,'change_status',$bank,$after,(int)$this->session->userdata('user_id'));if(!$this->db->trans_status())throw new RuntimeException('Status rekening perusahaan gagal diperbarui.');$this->db->trans_commit();$this->session->set_flashdata('success','Status rekening perusahaan diperbarui.');}catch(Throwable$e){$this->db->trans_rollback();$this->session->set_flashdata('error',$e->getMessage());}redirect('companies#companyBanks');
}
public function bank_export()
{
$company=(int)$this->companycontext->id();$this->db->select('b.bank_name,b.account_number,b.account_holder,b.product_name,b.account_type,b.interest_rate,b.opened_at,b.maturity_date,b.currency,b.is_active,a.kode_akun,a.nama_akun')->from('company_bank_accounts b')->join('accounts a','a.id=b.gl_account_id AND a.company_id=b.company_id','left')->where('b.company_id',$company);$bank=trim((string)$this->input->get('bank',true));$type=trim((string)$this->input->get('type',true));$status=$this->input->get('status');$from=trim((string)$this->input->get('maturity_from',true));$to=trim((string)$this->input->get('maturity_to',true));if($bank!=='')$this->db->like('b.bank_name',$bank);if(in_array($type,array('savings','deposit'),true))$this->db->where('b.account_type',$type);if($status==='0'||$status==='1')$this->db->where('b.is_active',(int)$status);if($this->validDate($from))$this->db->where('b.maturity_date >=',$from);if($this->validDate($to))$this->db->where('b.maturity_date <=',$to);$rows=$this->db->order_by('b.bank_name')->order_by('b.account_number')->get()->result_array();$this->output->set_content_type('text/csv')->set_header('Content-Disposition: attachment; filename="rekening-perusahaan-'.date('Ymd').'.csv"');$out=fopen('php://output','w');fputcsv($out,array('Nama Bank','Nomor Rekening','Pemilik','Produk','Jenis','Bunga (%)','Tanggal Pembukaan','Jatuh Tempo','Mata Uang','Status','Kode COA','Nama COA'));foreach($rows as$row){$row['account_type']=$row['account_type']==='deposit'?'Deposito':'Tabungan';$row['is_active']=$row['is_active']?'Aktif':'Nonaktif';fputcsv($out,array_values($row));}fclose($out);
}
public function save_currency()
@@ -64,4 +89,5 @@ class Companies extends MY_Admin_Controller
if(empty($_FILES['logo'])||$_FILES['logo']['error']===UPLOAD_ERR_NO_FILE)return$current;if($_FILES['logo']['error']!==UPLOAD_ERR_OK)throw new RuntimeException('Logo perusahaan gagal diunggah.');if((int)$_FILES['logo']['size']>2*1024*1024)throw new RuntimeException('Ukuran logo maksimal 2 MB.');$mime=(new finfo(FILEINFO_MIME_TYPE))->file($_FILES['logo']['tmp_name']);$allowed=array('image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp');if(!isset($allowed[$mime]))throw new RuntimeException('Logo hanya menerima JPG, PNG, atau WEBP.');$dir=FCPATH.'uploads/accounting/company/';if(!is_dir($dir)&&!mkdir($dir,0755,true))throw new RuntimeException('Folder logo perusahaan tidak dapat dibuat.');$relative='uploads/accounting/company/'.bin2hex(random_bytes(16)).'.'.$allowed[$mime];if(!move_uploaded_file($_FILES['logo']['tmp_name'],FCPATH.$relative))throw new RuntimeException('Logo perusahaan tidak dapat disimpan.');return$relative;
}
private function postOnly(){if(strtoupper($this->input->method())!=='POST')show_error('Metode tidak diizinkan.',405);}
private function validDate($value){$date=DateTime::createFromFormat('Y-m-d',(string)$value);return$date&&$date->format('Y-m-d')===$value;}
}