load->database(); date_default_timezone_set('Asia/Jakarta'); } // ===================================================== // INDEX // ===================================================== public function index() { $data = [ 'active_menu' => 'payroll' ]; $this->load->view('partials/header',$data); $this->load->view('employees/payroll'); $this->load->view('partials/footer'); } // ===================================================== // GET DATA // ===================================================== public function get_data() { $month = $this->input->post('month'); $this->db->select(" p.*, e.full_name, pp.period_name, pp.start_date, pp.end_date "); $this->db->from('k_payrolls p'); $this->db->join( 'k_employees e', 'e.id = p.employee_id' ); $this->db->join( 'k_payroll_periods pp', 'pp.id = p.payroll_period_id' ); if($month){ $this->db->where( 'DATE_FORMAT(pp.start_date,"%Y-%m")', $month ); } $this->db->order_by( 'e.full_name', 'ASC' ); $rows = $this->db->get()->result(); $data = []; $no = 1; foreach($rows as $row){ $pendapatan = ( $row->allowance_amount + $row->bonus_amount + $row->overtime_amount ); $potongan = ( $row->deduction_amount + $row->bpjs_kesehatan_amount + $row->bpjs_ketenagakerjaan_amount + $row->tax_amount + $row->attendance_cut_amount ); $status = ''; if($row->payment_status == 'paid'){ $status = ' Paid '; } else { $status = ' Draft '; } $data[] = [ $no++, $row->full_name, 'Rp '.number_format( $row->basic_salary, 0, ',', '.' ), 'Rp '.number_format( $pendapatan, 0, ',', '.' ), 'Rp '.number_format( $potongan, 0, ',', '.' ), 'Rp '.number_format( $row->total_salary, 0, ',', '.' ), $status, ' ' ]; } echo json_encode([ 'data' => $data ]); } // ===================================================== // DETAIL // ===================================================== public function detail($id) { $this->db->select(" p.*, e.full_name "); $this->db->from('k_payrolls p'); $this->db->join( 'k_employees e', 'e.id = p.employee_id' ); $this->db->where( 'p.id', $id ); $payroll = $this->db->get()->row(); if(!$payroll){ echo json_encode([ 'status' => false, 'message' => 'Payroll tidak ditemukan' ]); return; } $items = $this->db ->where('payroll_id',$id) ->order_by('id','ASC') ->get('k_payroll_items') ->result(); echo json_encode([ 'status' => true, 'payroll' => $payroll, 'employee' => [ 'full_name' => $payroll->full_name ], 'items' => $items ]); } // ===================================================== // SAVE ITEMS // ===================================================== public function save_items() { $payrollId = $this->input->post('payroll_id'); $items = $this->input->post('items'); $payroll = $this->db ->where('id',$payrollId) ->get('k_payrolls') ->row(); if(!$payroll){ echo json_encode([ 'status' => false, 'message' => 'Payroll tidak ditemukan' ]); return; } // ========================================= // DELETE OLD ITEMS // ========================================= $this->db ->where('payroll_id',$payrollId) ->delete('k_payroll_items'); $allowance = 0; $bonus = 0; $overtime = 0; $deduction = 0; $bpjs = 0; $tax = 0; if($items){ foreach($items as $item){ $amount = (float)$item['amount']; $insert = [ 'payroll_id' => $payrollId, 'item_type' => $item['item_type'], 'item_name' => $item['item_name'], 'amount' => $amount ]; $this->db->insert( 'k_payroll_items', $insert ); switch($item['item_type']){ case 'allowance': $allowance += $amount; break; case 'bonus': $bonus += $amount; break; case 'overtime': $overtime += $amount; break; case 'deduction': $deduction += $amount; break; case 'bpjs': $bpjs += $amount; break; case 'tax': $tax += $amount; break; } } } // ========================================= // TOTAL // ========================================= $totalSalary = ( $payroll->basic_salary + $allowance + $bonus + $overtime ) - ( $deduction + $bpjs + $tax + $payroll->attendance_cut_amount ); // ========================================= // UPDATE PAYROLL // ========================================= $this->db ->where('id',$payrollId) ->update( 'k_payrolls', [ 'allowance_amount' => $allowance, 'bonus_amount' => $bonus, 'overtime_amount' => $overtime, 'deduction_amount' => $deduction, 'bpjs_kesehatan_amount' => $bpjs, 'tax_amount' => $tax, 'total_salary' => $totalSalary ] ); echo json_encode([ 'status' => true, 'message' => 'Payroll berhasil disimpan' ]); } // ===================================================== // GENERATE PAYROLL // ===================================================== public function generate_payroll() { $month = $this->input->post('month'); if(!$month){ echo json_encode([ 'status' => false, 'message' => 'Bulan wajib dipilih' ]); return; } $startDate = date( 'Y-m-01', strtotime($month) ); $endDate = date( 'Y-m-t', strtotime($month) ); // ========================================= // PERIOD // ========================================= $period = $this->db ->where('start_date',$startDate) ->where('end_date',$endDate) ->get('k_payroll_periods') ->row(); if(!$period){ $this->db->insert( 'k_payroll_periods', [ 'period_name' => date( 'F Y', strtotime($startDate) ), 'start_date' => $startDate, 'end_date' => $endDate, 'status' => 'draft', 'generated_at' => date('Y-m-d H:i:s') ] ); $periodId = $this->db->insert_id(); } else { $periodId = $period->id; } // ========================================= // EMPLOYEES // ========================================= $employees = $this->db ->where('is_active',1) ->get('k_employees') ->result(); foreach($employees as $employee){ // ===================================== // ATTENDANCE // ===================================== $attendance = $this->db ->select(" COUNT(*) as total_work_days, SUM(attendance_status='present') as total_present, SUM(attendance_status='alpha') as total_alpha, SUM(overtime_hours) as total_overtime_hours ") ->where('employee_id',$employee->id) ->where('attendance_date >=',$startDate) ->where('attendance_date <=',$endDate) ->get('k_attendances') ->row(); $dailySalary = $employee->basic_salary / 30; $alphaCut = ( $attendance->total_alpha * $dailySalary ); $overtimeRate = 25000; $overtimeAmount = ( $attendance->total_overtime_hours * $overtimeRate ); $totalSalary = ( $employee->basic_salary + $overtimeAmount ) - $alphaCut; $exist = $this->db ->where( 'payroll_period_id', $periodId ) ->where( 'employee_id', $employee->id ) ->get('k_payrolls') ->row(); $data = [ 'payroll_period_id' => $periodId, 'employee_id' => $employee->id, 'basic_salary' => $employee->basic_salary, 'total_work_days' => ( $attendance->total_work_days ?? 0 ), 'total_present' => ( $attendance->total_present ?? 0 ), 'total_alpha' => ( $attendance->total_alpha ?? 0 ), 'total_overtime_hours' => ( $attendance->total_overtime_hours ?? 0 ), 'attendance_cut_amount' => $alphaCut, 'overtime_amount' => $overtimeAmount, 'total_salary' => $totalSalary ]; if($exist){ $this->db ->where('id',$exist->id) ->update( 'k_payrolls', $data ); } else { $this->db->insert( 'k_payrolls', $data ); $payrollId = $this->db->insert_id(); // ================================= // AUTO ITEM OVERTIME // ================================= if($overtimeAmount > 0){ $this->db->insert( 'k_payroll_items', [ 'payroll_id' => $payrollId, 'item_type' => 'overtime', 'item_name' => 'Lembur', 'amount' => $overtimeAmount ] ); } // ================================= // AUTO ITEM ALPHA // ================================= if($alphaCut > 0){ $this->db->insert( 'k_payroll_items', [ 'payroll_id' => $payrollId, 'item_type' => 'deduction', 'item_name' => 'Potongan Alpha', 'amount' => $alphaCut ] ); } } } echo json_encode([ 'status' => true, 'message' => 'Payroll berhasil digenerate' ]); } }