load->database(); $this->load->helper(['url', 'file']); if (!$this->session->userdata('logged_in')) { redirect('auth'); } date_default_timezone_set('Asia/Jakarta'); } // ========================================================= // INDEX // ========================================================= public function index() { $data = [ "active_menu" => "employees", "can_manage_all_salary" => $this->canManageAllSalary(), "employee_permissions" => array( 'create'=>$this->canEmployee('can_create'), 'update'=>$this->canEmployee('can_update'), 'delete'=>$this->canEmployee('can_delete') ) ]; $data['departments'] = $this->db ->where('is_active',1) ->order_by('department_name','ASC') ->get('k_departments') ->result(); $data['positions'] = $this->db ->where('is_active',1) ->order_by('position_name','ASC') ->get('k_positions') ->result(); $data['branches'] = $this->db ->order_by('branch_name','ASC') ->get('k_branches') ->result(); $this->load->view('partials/header', $data); $this->load->view('employees/employees', $data); $this->load->view('partials/footer'); } // ========================================================= // GET ALL // ========================================================= public function getAll() { try { $query = $this->db ->select(" e.*, d.department_name, p.position_name, b.branch_name ") ->from('k_employees e') ->join( 'k_departments d', 'd.id = e.department_id', 'left' ) ->join( 'k_positions p', 'p.id = e.position_id', 'left' ) ->join( 'k_branches b', 'b.id = e.branch_id', 'left' ) ->order_by('e.department_id','ASC'); if ($this->db->field_exists('company_id','k_employees')) $query->where('e.company_id',(int)$this->session->userdata('company_id')); $data = $query->get()->result(); foreach ($data as $employee) $this->maskRestrictedSalary($employee); return $this->json([ 'status' => true, 'data' => $data ]); } catch (Exception $e) { return $this->json([ 'status' => false, 'message' => $e->getMessage(), 'data' => [] ]); } } // ========================================================= // DETAIL // ========================================================= public function detail($id = null) { try { $data = $this->db ->select(" e.*, d.department_name, p.position_name, b.branch_name ") ->from('k_employees e') ->join( 'k_departments d', 'd.id = e.department_id', 'left' ) ->join( 'k_positions p', 'p.id = e.position_id', 'left' ) ->join( 'k_branches b', 'b.id = e.branch_id', 'left' ) ->where('e.id',$id); if ($this->db->field_exists('company_id','k_employees')) $this->db->where('e.company_id',(int)$this->session->userdata('company_id')); $data = $this->db ->get() ->row(); if (!$data) { return $this->json([ 'status' => false, 'message' => 'Data tidak ditemukan' ]); } $this->maskRestrictedSalary($data); return $this->json([ 'status' => true, 'data' => $data ]); } catch (Exception $e) { return $this->json([ 'status' => false, 'message' => $e->getMessage() ]); } } // ========================================================= // STORE // ========================================================= public function store() { try { if (empty(trim($this->input->post('full_name')))) { return $this->json([ 'status' => false, 'message'=> 'Nama wajib diisi' ]); } if (empty($this->input->post('join_date'))) { return $this->json([ 'status' => false, 'message'=> 'Tanggal masuk wajib diisi' ]); } $employee_code = $this->generateEmployeeCode(); $photo = $this->uploadPhoto(); $data = $this->prepareData(); $data['employee_code'] = $employee_code; $data['photo'] = $photo; if ($this->db->field_exists('company_id','k_employees')) $data['company_id']=(int)$this->session->userdata('company_id'); $this->db->insert('k_employees',$data); $employee_id = $this->db->insert_id(); log_activity( 'employees', 'create', 'Menambah karyawan: '.$data['full_name'].' (ID: '.$employee_id.')', 'success' ); return $this->json([ 'status' => true, 'message' => 'Berhasil simpan data' ]); } catch (Exception $e) { return $this->json([ 'status' => false, 'message' => $e->getMessage() ]); } } // ========================================================= // UPDATE // ========================================================= public function update($id = null) { try { $employee = $this->db ->get_where('k_employees',['id'=>$id]) ->row(); if (!$employee) { return $this->json([ 'status' => false, 'message' => 'Data tidak ditemukan' ]); } if (!empty($employee->salary_restricted) && !$this->canManageAllSalary()) { return $this->json(['status'=>false,'message'=>'Gaji karyawan ini bersifat terbatas. Anda memerlukan permission Manage All Gaji untuk mengubah datanya.']); } $data = $this->prepareData(); if (!empty($_FILES['photo_file']['name'])) { $photo = $this->uploadPhoto(); if ( !empty($employee->photo) && file_exists(FCPATH . $employee->photo) ) { unlink(FCPATH . $employee->photo); } $data['photo'] = $photo; } $this->db ->where('id',$id) ->update('k_employees',$data); log_activity( 'employees', 'update', 'Update karyawan ID: '.$id.' Nama: '.($data['full_name'] ?? '-'), 'success' ); return $this->json([ 'status' => true, 'message' => 'Berhasil update data' ]); } catch (Exception $e) { return $this->json([ 'status' => false, 'message' => $e->getMessage() ]); } } // ========================================================= // DELETE // ========================================================= public function delete($id = null) { try { $employee = $this->db ->get_where('k_employees',['id'=>$id]) ->row(); if (!$employee) { return $this->json([ 'status' => false, 'message' => 'Data tidak ditemukan' ]); } if (!empty($employee->salary_restricted) && !$this->canManageAllSalary()) { return $this->json(['status'=>false,'message'=>'Karyawan dengan gaji terbatas hanya dapat dihapus oleh pengguna dengan permission Manage All Gaji.']); } if ( !empty($employee->photo) && file_exists(FCPATH . $employee->photo) ) { unlink(FCPATH . $employee->photo); } $this->db->delete('k_employees',[ 'id'=>$id ]); log_activity( 'employees', 'delete', 'Hapus karyawan ID: '.$id.' Nama: '.($employee->full_name ?? '-'), 'success' ); return $this->json([ 'status' => true, 'message' => 'Berhasil hapus data' ]); } catch (Exception $e) { return $this->json([ 'status' => false, 'message' => $e->getMessage() ]); } } // ========================================================= // GENERATE CODE // ========================================================= private function generateEmployeeCode() { $last = $this->db ->order_by('id','DESC') ->get('k_employees') ->row(); $number = $last ? $last->id + 1 : 1; return 'RJN-' . str_pad($number,5,'0',STR_PAD_LEFT); } // ========================================================= // UPLOAD PHOTO // ========================================================= private function uploadPhoto() { if (empty($_FILES['photo_file']['name'])) { return null; } $path = FCPATH . 'uploads/karyawan/'; if (!is_dir($path)) { mkdir($path,0777,true); } $config['upload_path'] = './uploads/karyawan/'; $config['allowed_types'] = 'jpg|jpeg|png|webp'; $config['max_size'] = 2048; $config['encrypt_name'] = true; $this->load->library('upload',$config); if (!$this->upload->do_upload('photo_file')) { throw new Exception( strip_tags( $this->upload->display_errors() ) ); } $upload = $this->upload->data(); return 'uploads/karyawan/' . $upload['file_name']; } // ========================================================= // PREPARE DATA // ========================================================= private function prepareData() { $nullableText = function ($value) { $value = trim((string) $value); return $value === '' || in_array(strtolower($value), array('undefined', 'null'), true) ? null : $value; }; $nullableId = function ($value) { $value = (int) $value; return $value > 0 ? $value : null; }; $data = [ 'nik' => $nullableText($this->input->post('nik')), 'full_name' => trim( $this->input->post('full_name') ), 'gender' => $nullableText($this->input->post('gender')), 'birth_place' => $nullableText($this->input->post('birth_place')), 'birth_date' => $nullableText($this->input->post('birth_date')), 'phone' => $nullableText($this->input->post('phone')), 'email' => $nullableText($this->input->post('email')), 'address' => $nullableText($this->input->post('address')), 'join_date' => $this->input->post('join_date'), 'resign_date' => $nullableText($this->input->post('resign_date')), 'employment_status' => $this->input->post('employment_status'), 'marital_status' => $this->input->post('marital_status'), 'religion' => $nullableText($this->input->post('religion')), 'department_id' => $nullableId($this->input->post('department_id')), 'position_id' => $nullableId($this->input->post('position_id')), 'branch_id' => $nullableId($this->input->post('branch_id')), 'bank_name' => $nullableText($this->input->post('bank_name')), 'bank_account_number' => $nullableText($this->input->post('bank_account_number')), 'bank_account_name' => $nullableText($this->input->post('bank_account_name')), 'bpjs_kesehatan_number' => $nullableText($this->input->post('bpjs_kesehatan_number')), 'bpjs_ketenagakerjaan_number' => $nullableText($this->input->post('bpjs_ketenagakerjaan_number')), 'fingerprint_user_id' => $nullableText($this->input->post('fingerprint_user_id')), 'is_active' => $this->input->post('is_active') === '0' ? 0 : 1 ]; if ($this->db->field_exists('salary_restricted','k_employees') && $this->canManageAllSalary()) { $data['salary_restricted'] = $this->input->post('salary_restricted') ? 1 : 0; } return $data; } private function canManageAllSalary() { return is_master_admin_user() || check_permission('payroll','can_manage_all_salary'); } private function canEmployee($action) { return $this->session->userdata('role') === 'Admin' || is_master_admin_user() || check_permission('hr_employees',$action) || check_permission('employees',$action); } private function maskRestrictedSalary($employee) { if (!$employee || empty($employee->salary_restricted) || $this->canManageAllSalary()) return; $employee->basic_salary = null; $employee->bank_name = null; $employee->bank_account_number = null; $employee->bank_account_name = null; $employee->salary_hidden = true; } // ========================================================= // JSON // ========================================================= private function json($data) { return $this->output ->set_content_type('application/json') ->set_output(json_encode($data)); } }