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
+149 -74
View File
@@ -1,12 +1,15 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Jurnal extends CI_Controller {
class Jurnal extends MY_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('DynamicModel', 'dm');
$this->load->library('JournalService');
$this->load->library('NumberingService');
$this->load->library('JournalWorkflowService');
if (!$this->session->userdata('logged_in')) {
redirect('auth');
@@ -37,10 +40,10 @@ class Jurnal extends CI_Controller {
$search = $_POST['search']['value'];
// ================= TOTAL ALL
$totalAll = $this->db->count_all('journals');
$totalAll = $this->db->where('company_id',$this->companycontext->id())->count_all_results('journals');
// ================= QUERY FILTERED (HITUNG)
$this->db->from('journals');
$this->db->from('journals')->where('company_id',$this->companycontext->id());
if(!empty($search)){
$this->db->group_start();
@@ -58,11 +61,14 @@ class Jurnal extends CI_Controller {
journals.tanggal,
journals.no_ref,
journals.keterangan,
journals.status,
journals.is_reversed,
COALESCE(SUM(journal_details.debit),0) as total_debit,
COALESCE(SUM(journal_details.kredit),0) as total_kredit
');
$this->db->from('journals');
$this->db->join('journal_details','journal_details.journal_id = journals.id','LEFT');
$this->db->where('journals.company_id',$this->companycontext->id());
if(!empty($search)){
$this->db->group_start();
@@ -86,19 +92,22 @@ class Jurnal extends CI_Controller {
foreach ($query as $row) {
$no++;
if($this->session->userdata('role') != 'Admin'){
$aksi = '
<button class="btn btn-sm btn-info btn-detail" data-id="'.$row->id.'">Detail</button>
';
$isAdmin = $this->session->userdata('role') === 'Admin';
$aksi = '<button class="btn btn-sm btn-info btn-detail" data-id="'.$row->id.'">Detail</button> ';
if ($row->status === 'draft') {
$aksi .= '<button class="btn btn-sm btn-primary btn-submit" data-id="'.$row->id.'">Submit</button> ';
if ($isAdmin) $aksi .= '<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Hapus</button> ';
}
else {
$aksi = '
<button class="btn btn-sm btn-info btn-detail" data-id="'.$row->id.'">Detail</button>
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
';
if ($isAdmin && $row->status === 'submitted') {
$aksi .= '<button class="btn btn-sm btn-success btn-approve" data-id="'.$row->id.'">Approve</button> ';
$aksi .= '<button class="btn btn-sm btn-outline-danger btn-reject" data-id="'.$row->id.'">Reject</button> ';
}
if ($isAdmin && $row->status === 'posted') {
$aksi .= '<button class="btn btn-sm btn-outline-warning btn-reverse" data-id="'.$row->id.'">Reverse</button>';
}
$statusClass = array('draft'=>'secondary','submitted'=>'info','approved'=>'primary','posted'=>'success','rejected'=>'danger','reversed'=>'warning');
$badge = '<span class="badge bg-'.(isset($statusClass[$row->status]) ? $statusClass[$row->status] : 'secondary').'">'.htmlspecialchars(strtoupper($row->status), ENT_QUOTES, 'UTF-8').'</span>';
$data[] = [
$no,
@@ -107,6 +116,7 @@ class Jurnal extends CI_Controller {
$row->keterangan,
number_format($row->total_debit,0,',','.'),
number_format($row->total_kredit,0,',','.'),
$badge,
$aksi
];
}
@@ -124,7 +134,7 @@ class Jurnal extends CI_Controller {
// =========================
public function get_accounts()
{
$data = $this->db->order_by('kode_akun','ASC')->get('accounts')->result();
$data = $this->db->where(['company_id'=>$this->companycontext->id(),'is_active'=>1,'allow_posting'=>1])->order_by('kode_akun','ASC')->get('accounts')->result();
echo json_encode($data);
}
@@ -133,68 +143,59 @@ class Jurnal extends CI_Controller {
// =========================
public function save()
{
$tanggal = $this->input->post('tanggal');
$no_ref = 'JR-' . date('YmdHis');
$keterangan = $this->input->post('keterangan');
$tanggal = (string) $this->input->post('tanggal', true);
$keterangan = trim((string) $this->input->post('keterangan', true));
$accounts = (array) $this->input->post('account_id');
$debit = (array) $this->input->post('debit');
$kredit = (array) $this->input->post('kredit');
$accounts = $this->input->post('account_id');
$debit = $this->input->post('debit');
$kredit = $this->input->post('kredit');
try {
$noRef = $this->numberingservice->next('journal', $tanggal);
$lines = array();
foreach ($accounts as $index => $accountId) {
$lineDebit = isset($debit[$index]) ? $this->parseNominal($debit[$index]) : 0;
$lineCredit = isset($kredit[$index]) ? $this->parseNominal($kredit[$index]) : 0;
if ($lineDebit <= 0 && $lineCredit <= 0) continue;
$lines[] = array(
'account_id' => $accountId,
'debit' => $lineDebit,
'kredit' => $lineCredit
);
}
if (array_sum($debit) != array_sum($kredit)) {
echo json_encode([
'status'=>false,
'message'=>'Debit & Kredit tidak balance!'
]);
return;
}
$journalId = $this->journalservice->create(array(
'tanggal' => $tanggal,
'no_ref' => $noRef,
'keterangan' => $keterangan,
'ref_type' => 'manual_journal',
'created_by' => (int) $this->session->userdata('user_id')
), $lines);
$this->db->trans_start();
$this->db->insert('journals', [
'tanggal' => $tanggal,
'no_ref' => $no_ref,
'keterangan' => $keterangan,
'created_by' => $this->session->userdata('user_id')
]);
$journal_id = $this->db->insert_id();
for ($i=0; $i<count($accounts); $i++) {
if ($accounts[$i] == '') continue;
$this->db->insert('journal_details', [
'journal_id' => $journal_id,
'account_id' => $accounts[$i],
'debit' => $debit[$i] ?: 0,
'kredit' => $kredit[$i] ?: 0
]);
log_activity('Jurnal', 'create', 'Membuat jurnal No Ref: ' . $noRef, 'success');
return json_response(true, 'Jurnal berhasil disimpan.', array(
'journal_id' => $journalId,
'no_ref' => $noRef
));
} catch (Throwable $exception) {
return business_exception_response($exception);
}
}
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
echo json_encode([
'status'=>false,
'message'=>'Gagal simpan jurnal'
]);
return;
/** Menerima nominal raw maupun berformat 20,000 / 20.000 / 20.000,50. */
private function parseNominal($value)
{
$value = trim(str_ireplace(array('Rp', ' '), '', (string) $value));
if ($value === '') return 0.0;
$comma = strrpos($value, ','); $dot = strrpos($value, '.');
if ($comma !== false && $dot !== false) {
$value = $comma > $dot ? str_replace(',', '.', str_replace('.', '', $value)) : str_replace(',', '', $value);
} elseif ($comma !== false) {
$decimal = strlen($value) - $comma - 1;
$value = $decimal > 0 && $decimal <= 2 ? str_replace(',', '.', $value) : str_replace(',', '', $value);
} elseif ($dot !== false && strlen($value) - $dot - 1 === 3) {
$value = str_replace('.', '', $value);
}
// ================= LOG ACTIVITY =================
log_activity(
'Jurnal',
'create',
'Membuat jurnal No Ref: '.$no_ref,
'success'
);
echo json_encode([
'status'=>true,
'message'=>'Jurnal berhasil disimpan'
]);
return is_numeric($value) ? round((float) $value, 2) : 0.0;
}
// =========================
@@ -202,7 +203,8 @@ class Jurnal extends CI_Controller {
// =========================
public function detail($id)
{
$header = $this->db->get_where('journals',['id'=>$id])->row();
$header = $this->db->get_where('journals',['id'=>$id,'company_id'=>$this->companycontext->id()])->row();
if (!$header) return json_response(false, 'Jurnal tidak ditemukan.', array(), 404);
$detail = $this->db
->select('accounts.kode_akun, accounts.nama_akun, journal_details.*')
@@ -220,10 +222,19 @@ class Jurnal extends CI_Controller {
->get('users')
->row();
$history = $this->db
->select('journal_status_histories.*, users.nama changed_by_name')
->from('journal_status_histories')
->join('users', 'users.id = journal_status_histories.changed_by', 'left')
->where('journal_id', $id)
->order_by('journal_status_histories.id', 'ASC')
->get()->result();
echo json_encode([
'header'=>$header,
'detail'=>$detail,
'user' =>$user
'user' =>$user,
'history'=>$history
]);
}
@@ -232,6 +243,10 @@ class Jurnal extends CI_Controller {
// =========================
public function delete($id)
{
if (strtoupper($this->input->method()) !== 'POST') {
return json_response(false, 'Metode request tidak diizinkan.', array(), 405);
}
$this->requireAdmin();
$journal = $this->db->get_where('journals', ['id' => $id])->row();
// VALIDASI
@@ -243,6 +258,10 @@ class Jurnal extends CI_Controller {
return;
}
if (!in_array($journal->status, array('draft', 'rejected'), true)) {
return json_response(false, 'Hanya jurnal draft atau rejected yang dapat dihapus.', array(), 422);
}
$this->db->trans_start();
// =========================
@@ -301,6 +320,62 @@ class Jurnal extends CI_Controller {
]);
}
public function submit($id)
{
return $this->workflowAction(function () use ($id) {
return $this->journalworkflowservice->submit($id, $this->session->userdata('user_id'));
}, 'Jurnal berhasil diajukan.');
}
public function approve($id)
{
$this->requireAdmin();
return $this->workflowAction(function () use ($id) {
return $this->journalworkflowservice->approve($id, $this->session->userdata('user_id'));
}, 'Approval jurnal berhasil diproses. Setelah approval final, jurnal otomatis diposting.');
}
public function post($id)
{
$this->requireAdmin();
return $this->workflowAction(function () use ($id) {
return $this->journalworkflowservice->post($id, $this->session->userdata('user_id'));
}, 'Jurnal berhasil diposting.');
}
public function reject($id)
{
$this->requireAdmin();
$reason = $this->input->post('reason', true);
return $this->workflowAction(function () use ($id, $reason) {
return $this->journalworkflowservice->reject($id, $this->session->userdata('user_id'), $reason);
}, 'Jurnal berhasil ditolak.');
}
public function reverse($id)
{
$this->requireAdmin();
$date = $this->input->post('date', true);
$reason = $this->input->post('reason', true);
return $this->workflowAction(function () use ($id, $date, $reason) {
return $this->journalworkflowservice->reverse($id, $date, $this->session->userdata('user_id'), $reason);
}, 'Reversal jurnal berhasil dibuat.');
}
private function workflowAction(callable $callback, $message)
{
if (strtoupper($this->input->method()) !== 'POST') {
return json_response(false, 'Metode request tidak diizinkan.', array(), 405);
}
try {
$result = $callback();
log_activity('Jurnal', 'workflow', $message, 'success');
return json_response(true, $message, array('result' => $result));
} catch (Throwable $exception) {
return business_exception_response($exception);
}
}
public function get_base_jurnal()
{
echo json_encode(
@@ -330,4 +405,4 @@ class Jurnal extends CI_Controller {
'stok' => $stok
]);
}
}
}