Update besar apk finance

This commit is contained in:
Wian Drs
2026-09-11 16:03:00 +07:00
parent d42483b350
commit 4ef15c22ae
897 changed files with 98056 additions and 15979 deletions
+89
View File
@@ -0,0 +1,89 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH.'exceptions/BusinessException.php';
class ApprovalService
{
private $CI;
public function __construct() { $this->CI =& get_instance(); }
public function create($module, $entityType, $entityId, $amount, $userId, $snapshot)
{
$existing = $this->CI->db->where(array('entity_type'=>$entityType,'entity_id'=>(int)$entityId,'status'=>'pending'))->get('approval_requests')->row();
if ($existing) return $existing;
$workflow = $this->CI->db->where(array('module'=>$module,'entity_type'=>$entityType,'is_active'=>1))
->group_start()->where('min_amount IS NULL', null, false)->or_where('min_amount <=', $amount)->group_end()
->group_start()->where('max_amount IS NULL', null, false)->or_where('max_amount >=', $amount)->group_end()
->order_by('min_amount','DESC')->get('approval_workflows')->row();
if (!$workflow) throw new BusinessException('Workflow persetujuan belum dikonfigurasi.');
$requestNo = 'APR-'.date('Ymd-His').'-'.$entityId.'-'.random_int(100,999);
$this->CI->db->insert('approval_requests', array('request_no'=>$requestNo,'workflow_id'=>$workflow->id,'entity_type'=>$entityType,'entity_id'=>(int)$entityId,'amount'=>$amount,'requested_by'=>(int)$userId,'requested_at'=>date('Y-m-d H:i:s'),'current_step'=>1,'status'=>'pending','snapshot'=>json_encode($snapshot, JSON_UNESCAPED_UNICODE)));
$id = $this->CI->db->insert_id();
$this->CI->db->insert('approval_actions', array('request_id'=>$id,'step_order'=>0,'action'=>'submitted','user_id'=>(int)$userId,'created_at'=>date('Y-m-d H:i:s')));
return $this->find($id);
}
public function act($requestId, $action, $userId, $roleId, $notes = null)
{
$request = $this->CI->db->query('SELECT * FROM approval_requests WHERE id=? FOR UPDATE', array((int)$requestId))->row();
if (!$request || $request->status !== 'pending') throw new BusinessException('Permintaan approval tidak aktif.');
$step = $this->CI->db->get_where('approval_workflow_steps', array('workflow_id'=>$request->workflow_id,'step_order'=>$request->current_step))->row();
$role = $this->CI->db->get_where('roles', array('id'=>(int)$roleId))->row();
$masterAdmin = $role && (!empty($role->is_super_admin) || $role->nama_role === 'Admin');
if (!$step || (!$masterAdmin && (($step->approver_user_id && (int)$step->approver_user_id !== (int)$userId) || (!$step->approver_user_id && (int)$step->approver_role_id !== (int)$roleId)))) throw new BusinessException('Anda bukan approver pada tahap ini.', array(), 403);
$workflow = $this->CI->db->get_where('approval_workflows', array('id'=>$request->workflow_id))->row();
if (!$masterAdmin && $workflow->require_separation && (int)$request->requested_by === (int)$userId) throw new BusinessException('Pembuat transaksi tidak boleh menyetujui transaksinya sendiri.');
if (!in_array($action,array('approved','rejected'),true)) throw new BusinessException('Tindakan approval tidak valid.');
if ($action === 'rejected' && trim((string)$notes) === '') throw new BusinessException('Alasan penolakan wajib diisi.');
$this->CI->db->insert('approval_actions', array('request_id'=>$request->id,'step_order'=>$request->current_step,'action'=>$action,'user_id'=>(int)$userId,'notes'=>$notes,'created_at'=>date('Y-m-d H:i:s')));
$next = $this->CI->db->get_where('approval_workflow_steps',array('workflow_id'=>$request->workflow_id,'step_order'=>$request->current_step+1))->row();
$final = $action === 'rejected' ? 'rejected' : ($next ? 'pending' : 'approved');
$update = array('status'=>$final);
if ($next) $update['current_step'] = $request->current_step+1;
if ($final !== 'pending') $update['completed_at'] = date('Y-m-d H:i:s');
$this->CI->db->where('id',$request->id)->update('approval_requests',$update);
return $this->find($request->id);
}
public function pendingFor($userId, $roleId)
{
$role=$this->CI->db->get_where('roles',array('id'=>(int)$roleId))->row();
$masterAdmin=$role&&(!empty($role->is_super_admin)||$role->nama_role==='Admin');
if($masterAdmin){$rows=$this->CI->db->select('approval_requests.*, approval_workflows.name workflow_name, approval_workflows.module workflow_module, users.nama requester_name')->from('approval_requests')->join('approval_workflows','approval_workflows.id=approval_requests.workflow_id')->join('users','users.id=approval_requests.requested_by','left')->where('approval_requests.status','pending')->order_by('approval_requests.requested_at','ASC')->get()->result();return $this->withDestinations($rows);}
$rows=$this->CI->db->select('approval_requests.*, approval_workflows.name workflow_name, approval_workflows.module workflow_module, users.nama requester_name')
->from('approval_requests')->join('approval_workflows','approval_workflows.id=approval_requests.workflow_id')
->join('approval_workflow_steps','approval_workflow_steps.workflow_id=approval_requests.workflow_id AND approval_workflow_steps.step_order=approval_requests.current_step')
->join('users','users.id=approval_requests.requested_by','left')->where('approval_requests.status','pending')
->group_start()->where('approval_workflow_steps.approver_user_id',(int)$userId)->or_group_start()->where('approval_workflow_steps.approver_user_id IS NULL',null,false)->where('approval_workflow_steps.approver_role_id',(int)$roleId)->group_end()->group_end()
->order_by('approval_requests.requested_at','ASC')->get()->result();
return $this->withDestinations($rows);
}
private function withDestinations(array $rows)
{
foreach($rows as $row){$destination=$this->destinationFor($row->entity_type,$row->entity_id,$row->workflow_module);$row->destination_url=base_url($destination[0]);$row->destination_label=$destination[1];}
return $rows;
}
private function destinationFor($type,$id,$module)
{
$id=(int)$id;
$map=array(
'journal'=>array('jurnal?focus='.$id,'Buka Jurnal'),
'invoice'=>array('invoices/detail/'.$id,'Buka Invoice'),
'purchase_request'=>array('purchases?step=request&focus='.$id,'Buka Purchase Request'),
'purchase_order'=>array('purchases?step=order&focus='.$id,'Buka Purchase Order'),
'purchase_return'=>array('purchases/returns?section=return&focus='.$id,'Buka Pengajuan Retur'),
'supplier_refund'=>array('purchases/returns?section=refund&focus='.$id,'Buka Pengajuan Refund'),
'supplier_invoice'=>array('purchases?step=invoice&focus='.$id,'Buka Tagihan Supplier'),
'stock_document'=>array('inventoryprofessional?focus='.$id,'Buka Dokumen Persediaan'),
'cash_transaction'=>array('cashbank?focus='.$id,'Buka Transaksi Kas/Bank'),
'payroll_period'=>array('hrpayroll?focus='.$id,'Buka Payroll'),
'attendance_correction'=>array('attendancemonitoring?focus='.$id,'Buka Koreksi Absensi'),
'budget'=>array('budgets?focus='.$id,'Buka Budget')
);
if(isset($map[$type]))return $map[$type];
$fallback=array('purchase'=>'purchases','payable'=>'purchases?step=invoice','inventory'=>'inventoryprofessional','invoice'=>'invoices','journal'=>'jurnal','cash_bank'=>'cashbank','payroll'=>'hrpayroll','hr'=>'attendancemonitoring','budget'=>'budgets');
return array(isset($fallback[$module])?$fallback[$module]:'dashboard','Buka Dokumen');
}
public function find($id) { return $this->CI->db->get_where('approval_requests',array('id'=>(int)$id))->row(); }
public function pendingForEntity($type,$id) { return $this->CI->db->where(array('entity_type'=>$type,'entity_id'=>(int)$id,'status'=>'pending'))->get('approval_requests')->row(); }
}