Files
accounting_dev_v2/application/controllers/Budgets.php
T
2026-09-17 00:51:53 +07:00

56 lines
10 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Budgets extends MY_Controller
{
private$userId;
public function __construct(){parent::__construct();$this->load->database();$this->load->library(array('CompanyContext','BudgetService'));$this->userId=(int)$this->session->userdata('user_id');}
public function index()
{
$company=$this->companycontext->id();$tab=$this->input->get('tab')==='accounts'?'accounts':'list';
$filters=array('from'=>$this->input->get('from')?:date('Y-m'),'to'=>$this->input->get('to')?:date('Y-m'),'account_id'=>(int)$this->input->get('account_id'));
$listAccount=(int)$this->input->get('list_account_id');
$accounts=$this->db->where(array('company_id'=>$company,'is_active'=>1))->order_by('kode_akun')->get('accounts')->result();
$budgetAccounts=$this->db->select('a.id,a.kode_akun,a.nama_akun,a.tipe')->distinct()->from('accounts a')->join('account_budget_entries e','e.account_id=a.id')->where(array('e.company_id'=>$company,'e.is_active'=>1))->order_by('a.kode_akun')->get()->result();
$entries=$this->budgetservice->entries($listAccount);$reportRows=$tab==='accounts'?$this->budgetservice->report($filters):array();
$listTotal=array_sum(array_map(function($entry){return(float)$entry->amount;},$entries));
$accountTotal=array_sum(array_map(function($row){return(float)$row['budget'];},$reportRows));
$data=array('active_menu'=>'budgets','active_tab'=>$tab,'accounts'=>$accounts,'budget_accounts'=>$budgetAccounts,'budget_account_count'=>count($budgetAccounts),'entries'=>$entries,'list_total_budget'=>$listTotal,'reminders'=>$this->budgetservice->currentReminders(),'list_account_id'=>$listAccount,'filters'=>$filters,'report_rows'=>$reportRows,'account_total_budget'=>$accountTotal,'can_create'=>$this->allowed('can_create'),'can_update'=>$this->allowed('can_update'),'can_delete'=>$this->allowed('can_delete'),'can_export'=>$this->allowed('can_export'));
$this->load->view('partials/header',$data);$this->load->view('budgets/index',$data);$this->load->view('partials/footer');
}
public function save_entry()
{
$id=(int)$this->input->post('id');return$this->handle(fn()=>$this->budgetservice->saveEntry($this->input->post(),$this->userId),$id?'Budget berhasil diperbarui.':'Budget berhasil ditambahkan.',$id?'can_update':'can_create');
}
public function delete_entry($id){return$this->handle(fn()=>$this->budgetservice->deleteEntry($id,$this->userId),'Budget berhasil dinonaktifkan.','can_delete');}
public function complete_reminder($id){return$this->handle(fn()=>$this->budgetservice->completeReminder($id,$this->userId),'Pengingat pembayaran bulan ini ditandai selesai.','can_update');}
public function export_list($format='excel')
{
$this->requirePermission('budgets','can_export');$accountId=(int)$this->input->get('list_account_id');$rows=array();
$states=array('completed'=>'Selesai bulan ini','overdue'=>'Terlambat','due'=>'Jatuh tempo hari ini','upcoming'=>'Segera jatuh tempo','scheduled'=>'Terjadwal','future'=>'Belum berlaku','inactive_period'=>'Bukan bulan berjalan','none'=>'Tidak ada');
foreach($this->budgetservice->entries($accountId)as$entry)$rows[]=array('title'=>$entry->title,'account'=>$entry->kode_akun.' - '.$entry->nama_akun,'type'=>$entry->entry_type==='recurring'?'Berulang setiap bulan':'Khusus satu bulan','period'=>$entry->period,'amount'=>(float)$entry->amount,'reminder'=>(int)$entry->reminder_enabled?(($entry->entry_type==='recurring'?'Setiap tanggal ':'Tanggal ').$entry->reminder_day):'Tidak ada','reminder_status'=>$states[$entry->reminder_state]??'-','notes'=>$entry->notes?:'-');
return$this->deliverExport($format,'Daftar Budget',$accountId?'Filter satu akun':'Semua akun',array('title'=>'Nama Budget','account'=>'Akun','type'=>'Pola','period'=>'Mulai / Bulan','amount'=>'Nominal Budget','reminder'=>'Pengingat Pembayaran','reminder_status'=>'Status Pengingat','notes'=>'Keterangan'),$rows,array('amount'),'Daftar-Budget');
}
public function export_accounts($format='excel')
{
$this->requirePermission('budgets','can_export');$filters=$this->filters();$rows=array();$types=array('asset'=>'Aset','liability'=>'Liabilitas','equity'=>'Ekuitas','revenue'=>'Pendapatan','expense'=>'Beban');
foreach($this->budgetservice->report($filters)as$row)$rows[]=array('account'=>$row['kode_akun'].' - '.$row['nama_akun'],'type'=>$types[$row['tipe']]??ucfirst($row['tipe']),'budget'=>$row['budget'],'actual'=>$row['actual'],'commitment'=>$row['commitment'],'usage'=>$row['usage'],'remaining'=>$row['remaining'],'percentage'=>$row['percentage'],'condition'=>$row['indicator']==='over'?'Melebihi':($row['indicator']==='warning'?'Mendekati Batas':'Aman'));
return$this->deliverExport($format,'Budget Per Akun','Periode '.$filters['from'].' s.d. '.$filters['to'],array('account'=>'Akun','type'=>'Jenis Akun','budget'=>'Akumulasi Budget','actual'=>'Realisasi','commitment'=>'Komitmen PO','usage'=>'Total Pemakaian','remaining'=>'Sisa Budget','percentage'=>'Persentase (%)','condition'=>'Kondisi'),$rows,array('budget','actual','commitment','usage','remaining'),'Budget-Per-Akun-'.$filters['from'].'-'.$filters['to']);
}
public function create(){return$this->handle(fn()=>$this->budgetservice->create($this->input->post(),$this->userId),'Budget Draft berhasil dibuat.','can_create',true);}
public function save_lines($id){return$this->handle(fn()=>$this->budgetservice->saveAnnualLines($id,(array)$this->input->post('rows'),$this->userId),'Budget bulanan berhasil disimpan.','can_update');}
public function workflow($id,$action){return$this->handle(fn()=>$this->budgetservice->workflow($id,$action,$this->userId,$this->input->post('reason',true)),'Status budget berhasil diperbarui.',$action==='submit'?'can_create':'can_approve');}
public function revise($id){return$this->handle(fn()=>$this->budgetservice->revise($id,$this->input->post('reason',true),$this->userId),'Draft revisi berhasil dibuat.','can_update',true);}
public function detail($id){$budget=$this->budgetservice->find($id);if(!$budget)return json_response(false,'Budget tidak ditemukan.',array(),404);return json_response(true,'Detail budget ditemukan.',array('result'=>array('budget'=>$budget,'lines'=>$this->budgetservice->lines($id))));}
public function export(){$this->requirePermission('budgets','can_export');$f=$this->filters();$rows=$this->budgetservice->report($f);$this->output->set_content_type('text/csv')->set_header('Content-Disposition: attachment; filename="budget-'.$f['to'].'.csv"');$h=fopen('php://output','w');fputcsv($h,array('Kode Akun','Nama Akun','Budget','Realisasi','Komitmen','Pemakaian','Sisa','Persentase'));foreach($rows as$r)fputcsv($h,array($r['kode_akun'],$r['nama_akun'],$r['budget'],$r['actual'],$r['commitment'],$r['usage'],$r['remaining'],$r['percentage']));fclose($h);}
public function pdf($id){$this->requirePermission('budgets','can_export');$budget=$this->budgetservice->find($id);if(!$budget)show_404();$html=$this->load->view('budgets/pdf',array('budget'=>$budget,'lines'=>$this->budgetservice->lines($id),'company'=>$this->db->get_where('companies',array('id'=>$this->companycontext->id()))->row()),true);require_once FCPATH.'vendor/autoload.php';$pdf=new Dompdf\Dompdf();$pdf->loadHtml($html);$pdf->setPaper('A4','landscape');$pdf->render();$pdf->stream($budget->budget_no.'.pdf',array('Attachment'=>false));}
private function filters(){return array('from'=>$this->input->get_post('from')?:date('Y-m'),'to'=>$this->input->get_post('to')?:date('Y-m'),'account_id'=>(int)$this->input->get_post('account_id'));}
private function deliverExport($format,$title,$subtitle,array$columns,array$rows,array$moneyColumns,$filename)
{
$format=strtolower((string)$format);if(!in_array($format,array('pdf','excel'),true))show_404();$company=$this->db->get_where('companies',array('id'=>$this->companycontext->id()))->row();
if($format==='pdf'){$html=$this->load->view('budgets/export_pdf',array('title'=>$title,'subtitle'=>$subtitle,'columns'=>$columns,'rows'=>$rows,'money_columns'=>$moneyColumns,'company'=>$company),true);require_once FCPATH.'vendor/autoload.php';$pdf=new Dompdf\Dompdf();$pdf->loadHtml($html);$pdf->setPaper('A4','landscape');$pdf->render();$pdf->stream($filename.'.pdf',array('Attachment'=>false));return;}
require_once FCPATH.'vendor/autoload.php';$book=new\PhpOffice\PhpSpreadsheet\Spreadsheet();$sheet=$book->getActiveSheet();$sheet->setTitle(substr(preg_replace('/[^A-Za-z0-9 ]/','',$title),0,31));$last=\PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex(count($columns));$companyName=$company?($company->name??$company->company_name??'Perusahaan'):'Perusahaan';$sheet->setCellValue('A1',$companyName)->mergeCells('A1:'.$last.'1');$sheet->setCellValue('A2',$title)->mergeCells('A2:'.$last.'2');$sheet->setCellValue('A3',$subtitle)->mergeCells('A3:'.$last.'3');$column=1;foreach($columns as$label)$sheet->setCellValueByColumnAndRow($column++,5,$label);$rowNumber=6;foreach($rows as$row){$column=1;foreach($columns as$key=>$label){$sheet->setCellValueByColumnAndRow($column,$rowNumber,$row[$key]??null);if(in_array($key,$moneyColumns,true))$sheet->getStyleByColumnAndRow($column,$rowNumber)->getNumberFormat()->setFormatCode('#,##0.00');$column++;}$rowNumber++;}$sheet->getStyle('A1:'.$last.'2')->getFont()->setBold(true);$sheet->getStyle('A5:'.$last.'5')->getFont()->setBold(true);$sheet->freezePane('A6');if($rows)$sheet->setAutoFilter('A5:'.$last.($rowNumber-1));for($i=1;$i<=count($columns);$i++)$sheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($i))->setAutoSize(true);while(ob_get_level()>0)ob_end_clean();header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');header('Content-Disposition: attachment; filename="'.$filename.'-'.date('Ymd-His').'.xlsx"');header('Cache-Control: max-age=0');\PhpOffice\PhpSpreadsheet\IOFactory::createWriter($book,'Xlsx')->save('php://output');$book->disconnectWorksheets();exit;
}
private function handle(callable$fn,$message,$permission,$open=false){if(strtoupper($this->input->method())!=='POST')return json_response(false,'Metode request tidak diizinkan.',array(),405);$this->requirePermission('budgets',$permission);try{$result=$fn();if($this->input->is_ajax_request())return json_response(true,$message,array('result'=>$result));$this->session->set_flashdata('success',$message);redirect('budgets'.($open&&is_numeric($result)?'?budget_id='.$result:''));}catch(Throwable$e){if($this->input->is_ajax_request())return business_exception_response($e);$this->session->set_flashdata('error',$e->getMessage());redirect('budgets');}}
private function allowed($action){return is_master_admin_user()||check_permission('budgets',$action);}
}