Files
accounting_dev_v2/application/libraries/ChartOfAccountsService.php
T
2026-09-11 16:03:00 +07:00

113 lines
5.3 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH . 'exceptions/BusinessException.php';
class ChartOfAccountsService
{
private $CI;
public function __construct()
{
$this->CI =& get_instance();
$this->CI->load->library('AuditService');
}
public function save(array $input, $id = null, $userId = null)
{
$code = trim(isset($input['kode_akun']) ? $input['kode_akun'] : '');
$name = trim(isset($input['nama_akun']) ? $input['nama_akun'] : '');
$type = isset($input['tipe']) ? $input['tipe'] : '';
$parentId = !empty($input['parent_id']) ? (int) $input['parent_id'] : null;
$isHeader = !empty($input['is_header']) ? 1 : 0;
$allowPosting = $isHeader ? 0 : (!empty($input['allow_posting']) ? 1 : 0);
if ($code === '' || $name === '') {
throw new BusinessException('Kode dan nama akun wajib diisi.');
}
if (!preg_match('/^[0-9]{4}$/', $code)) {
throw new BusinessException('Kode akun wajib terdiri dari tepat 4 angka.');
}
if (!in_array($type, array('asset', 'liability', 'equity', 'revenue', 'expense'), true)) {
throw new BusinessException('Tipe akun tidak valid.');
}
$duplicateQuery = $this->CI->db->where('kode_akun', $code);
if ($id) $duplicateQuery->where('id !=', (int) $id);
if ($duplicateQuery->count_all_results('accounts') > 0) {
throw new BusinessException('Kode akun sudah digunakan.');
}
if ($parentId) {
if ($id && $parentId === (int) $id) {
throw new BusinessException('Akun tidak dapat menjadi parent untuk dirinya sendiri.');
}
$parent = $this->CI->db->get_where('accounts', array('id' => $parentId))->row();
if (!$parent) {
throw new BusinessException('Parent akun tidak ditemukan.');
}
if ($id && $this->wouldCreateCycle((int) $id, $parentId)) {
throw new BusinessException('Parent akun tersebut akan membentuk hierarki melingkar.');
}
}
if ($id && $isHeader && $this->CI->db->where('account_id', (int) $id)->count_all_results('journal_details') > 0) {
throw new BusinessException('Akun yang sudah mempunyai transaksi tidak dapat diubah menjadi akun header.');
}
$data = array(
'kode_akun' => $code,
'nama_akun' => $name,
'tipe' => $type,
'posisi' => in_array($type, array('asset', 'expense'), true) ? 'debit' : 'kredit',
'kategori' => in_array($type, array('asset', 'liability', 'equity'), true) ? 'neraca' : 'laba_rugi',
'parent_id' => $parentId,
'priority' => isset($input['priority']) && $input['priority'] !== '' ? (int) $input['priority'] : null,
'is_header' => $isHeader,
'allow_posting' => $allowPosting,
'is_active' => isset($input['is_active']) ? (!empty($input['is_active']) ? 1 : 0) : 1,
'is_hidden' => !empty($input['is_hidden']) ? 1 : 0,
'updated_at' => date('Y-m-d H:i:s'),
'updated_by' => $userId ? (int) $userId : null
);
if ($id) {
$before = $this->CI->db->get_where('accounts', array('id'=>(int)$id))->row();
$this->CI->db->where('id', (int) $id)->update('accounts', $data);
$this->CI->auditservice->record('chart_of_accounts','account',(int)$id,'update',$before,$this->CI->db->get_where('accounts',array('id'=>(int)$id))->row(),$userId);
return (int) $id;
}
$this->CI->db->insert('accounts', $data);
$newId=(int)$this->CI->db->insert_id();
$this->CI->auditservice->record('chart_of_accounts','account',$newId,'create',null,$this->CI->db->get_where('accounts',array('id'=>$newId))->row(),$userId);
return $newId;
}
public function delete($id, $userId = null)
{
$id = (int) $id;
if ($this->CI->db->where('parent_id', $id)->count_all_results('accounts') > 0) {
throw new BusinessException('Akun memiliki child dan tidak dapat dihapus.');
}
if ($this->CI->db->where('account_id', $id)->count_all_results('journal_details') > 0) {
throw new BusinessException('Akun sudah mempunyai transaksi dan tidak dapat dihapus. Nonaktifkan akun sebagai gantinya.');
}
if ($this->CI->db->where('account_id', $id)->count_all_results('system_account_mappings') > 0) {
throw new BusinessException('Akun masih digunakan sebagai mapping akun sistem.');
}
$before=$this->CI->db->get_where('accounts',array('id'=>$id))->row();
$result=$this->CI->db->where('id', $id)->delete('accounts');
if($result) $this->CI->auditservice->record('chart_of_accounts','account',$id,'delete',$before,null,$userId);
return $result;
}
private function wouldCreateCycle($accountId, $parentId)
{
$visited = array();
while ($parentId) {
if ($parentId === $accountId || isset($visited[$parentId])) return true;
$visited[$parentId] = true;
$row = $this->CI->db->select('parent_id')->get_where('accounts', array('id' => $parentId))->row();
$parentId = $row && $row->parent_id ? (int) $row->parent_id : null;
}
return false;
}
}