<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Kas extends CI_Controller
{
	public function __construct()
	{
		parent::__construct();
		cek_session_login();
		$this->load->model('model_cashback', 'cashback');
		$this->load->model('Report_model','report');
		$this->perPage = 10;
		$this->iduser = $this->session->idu;
		$this->title = info()['title']; 
	}

	private function _cek_akses_mutasi($mode = 'html')
	{
    // mode: html | json
		$session = $this->session->idu;

		if (!isset($session)) {
			if ($this->input->is_ajax_request()) {
				if ($mode === 'json') {
					$this->output->set_status_header(401)
					->set_content_type('application/json')
					->set_output(json_encode(['status'=>401,'msg'=>'Login required']));
				} else {
					$this->output->set_status_header(401)->set_output('Login required');
				}
				exit;
			}
			redirect(base_url());
			exit;
		}

    // Cek akses berdasarkan MENU UTAMA mutasi (bukan uri ajax)
		$link_menu = 'kas/mutasi';
		$menu = $this->db->query("SELECT idmenu FROM menuadmin WHERE link='$link_menu' AND aktif='Y'")->row_array();
    if (!$menu) return; // jika menu tidak ada, jangan mematikan sistem

    $user = $this->db->query("SELECT idmenu FROM tb_users WHERE id_user='$session' AND aktif='Y'")->row_array();
    $people = !empty($user['idmenu']) ? explode(",", $user['idmenu']) : [];

    if (!in_array($menu['idmenu'], $people)) {
    	if ($this->input->is_ajax_request()) {
    		if ($mode === 'json') {
    			$this->output->set_status_header(403)
    			->set_content_type('application/json')
    			->set_output(json_encode(['status'=>403,'msg'=>'Akses terbatas']));
    		} else {
    			$this->output->set_status_header(403)->set_output('Akses terbatas');
    		}
    		exit;
    	}
    	redirect(base_url().'errorakses');
    	exit;
    }
}



public function data()
{
	$this->_cek_akses_mutasi('html');

	$data['title'] = 'Data Kas | '.$this->title;
	$data['tanggal'] = bulan_tahun(date('Y-m-d'));
	$rekening =  $this->model_app->view('rekening_bank');
	$_sum = [];
	foreach ($rekening as $row){
		$array = array('jurnal_detail.id_akun' =>$row['id_akun']);
		$this->db->where($array);
		$journal_data =  $this->report->getData($row['id_akun']);
		if ($journal_data) :
			foreach ($journal_data as $key=>$val) :
				
				$_sum['debit'][] = ['perkiraan'=>$val['id_perkiraan'],'nama'=>$val['nama'],'nilai'=>intval($val['nilai'])];
				
			endforeach;
		endif;
	}
	if(!empty($_sum['debit'])){

		$data['kas'] = $this->kas_tunai(1);
		$data['dp'] = $this->kas_tunai(31);
		$data['kas_kecil'] = $this->kas_tunai(47);
		$data['rekening'] = $this->sum_pembukuan($_sum['debit']);

		$this->template->load('main/themes','kas/pengaturan',$data);
	}else{
		$data['kas'] = $this->kas_tunai(1);
		$data['dp']  = $this->kas_tunai(31);
		$data['kas_kecil']  = $this->kas_tunai(47);
		$data['rekening'] = [];
		$this->template->load('main/themes','kas/pengaturan',$data);
	}
}

private function kas_tunai($id)
{
	$sum_debit =[];
	$array = array('jurnal_detail.id_akun' =>$id);
	$this->db->where($array);
	$journal_data =  $this->report->getData($id);
	$nama = '';
	$nilai = 0;
	$totalDebit = 0;
	$totalKredit = 0;
	if ($journal_data) :
		foreach ($journal_data as $data) :
			$nama = $data['nama'];
			if ($data['id_perkiraan'] == 1) {
				
				$totalDebit += intval($data['nilai']);
			} else {
				
				$totalKredit += intval($data['nilai']);
			}
		endforeach;
	endif;
	$total = $totalDebit - $totalKredit;
	return ['nama'=>$nama,'nilai'=>$total];
}

private function sum_pembukuan($array)
{
	$result = array_reduce($array, function($carry, $item){ 
		$debit = $kredit = 0;
		if(!isset($carry[$item['nama']])){ 
			$carry[$item['nama']] = ['perkiraan'=>$item['perkiraan'],'nama'=>$item['nama'],'nilai'=>$item['nilai']]; 
		} else { 
			if($item['perkiraan']==1){
				$debit = $item['nilai'];
			}else{
				$kredit = $item['nilai'];
			}
			$total = $debit - $kredit;
			$carry[$item['nama']]['nilai'] += $total; 
		} 
		return $carry; 
	});
	return $result;
}


		//19:16 07/17/2023
public function simpan_withdraw(){

	cek_nput_post('GET');
	simpan_demo("Simpan");
	$id_konsumen= $this->db->escape_str($this->input->post('id_konsumen_withdraw'));
	$noin= $this->db->escape_str($this->input->post('id_invoice_withdraw'));
			//rekening dari
	$rekening_dari= $this->db->escape_str($this->input->post('rekening_dari'));
			//rekening tujuan
	$rekening= $this->db->escape_str($this->input->post('rekening'));

			// $id_bayar= $this->db->escape_str($this->input->post('id_bayar'));
	$dari_kas= $this->db->escape_str($this->input->post('dari_kas'));
	$tujuan= $this->db->escape_str($this->input->post('tujuan'));
	$jumlah= $this->db->escape_str($this->input->post('jumlah_withdraw'));

	$catatan= "WD No.".$id_konsumen;

	if(!empty($rekening_dari)){
		$rekening_dari = $rekening_dari;
	}

	if(!empty($rekening)){
		$rekening = $rekening;
	}
			// dump($_POST);
	$autoNumber = autoNumber('REF-','%05s','id_generate','kas_masuk');

	$pengeluaran = ['no_reff'=>$dari_kas,
	'id_jenis'=>$dari_kas,
	'id_sub_bayar'=>$rekening_dari,
	'id_user'=>$this->iduser,
	'id_generate'=>$autoNumber,
	'catatan'=>$catatan,
	'pengeluaran'=>convert_to_number($jumlah)];

			// print_r($pengeluaran);exit();
	$input = $this->model_app->input('kas_masuk',$pengeluaran);
	if($input['status']=='ok'){
		$ket_debet = "Cashback Penjualan No. " . $noin;
		$ket_kredit = "Kas Penjualan No. " . $noin;
		$_reffd = "C-$noin";

		$_reffk = "K-$noin";


		$this->model_jurnal->input_jurnal_debet(403,$_reffd,$jumlah,$ket_debet);
		$this->model_jurnal->input_jurnal_kredit(411,$_reffk,$jumlah,$ket_kredit);

		$input_deposit = [
			'id_user'=>$this->iduser,
			'id_konsumen'=>$id_konsumen,
			'id_konsumen'=>$noin,
			'keluar'=>$jumlah,
			'create_date'=>today(),
			'catatan'=>$catatan
		];

		$this->deposit($input_deposit);
		$data = array('status'=>200,'msg'=>'Withdraw berhasil');
	}else{
		$data = array('status'=>400,'msg'=>'Withdraw gagal');
	}
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}

		//19:24 07/17/2023
private function deposit($data)
{
	$this->model_app->input("deposit", $data);
}


public function tujuan_kas()
{
    $id = (int)$this->db->escape_str($this->input->post('id'));

    // kalau kosong
    if (empty($id)) {
        $data[] = ["id" => 0, "name" => "Pilih", "msg" => "disabled"];
        return $this->output->set_content_type('application/json')->set_output(json_encode($data));
    }

    /**
     * Catatan penting:
     * - Saat sumber BANK dipilih, mutasi.js kadang mengirim "rekening_id" (misal 1,2,3)
     *   bukan 110. Maka: selain 110/411/111 kita anggap sumbernya BANK (110).
     */
    $fromKas = (int)$id;
    if (!in_array($fromKas, [110, 411, 111], true)) {
        $fromKas = 110; // dianggap BANK
    }

    // Ambil daftar rekening bank aktif
    $bank = $this->model_app->view_where('rekening_bank', ['publish' => 'Y'])->result_array();

    // Label bank
    $bankLabel = 'Kas Bank';
    if (count($bank) === 1) {
        $inisial = !empty($bank[0]['inisial']) ? $bank[0]['inisial'] : 'BANK';
        $bankLabel = 'Bank ' . $inisial;
    } elseif (count($bank) > 1) {
        $bankLabel = 'Kas Bank (Pilih Rekening)';
    } else {
        $bankLabel = 'Kas Bank (Belum ada rekening)';
    }

    $result = [];

    // 1) Tujuan Kas Tunai (411) muncul kalau sumber bukan 411
    if ($fromKas !== 411) {
        $result[] = ['id' => 411, 'name' => 'Kas Tunai di Laci'];
    }

    // 2) Tujuan Kas Tunai di Simpan (111) muncul kalau sumber bukan 111
    if ($fromKas !== 111) {
        $result[] = ['id' => 111, 'name' => 'Kas Tunai di Simpan'];
    }

    // 3) Tujuan Bank (110)
    // - Bank -> Bank hanya valid jika rekening >= 2 (di simpan_mutasi juga sudah divalidasi harus beda rekening)
    // - Non-bank -> Bank tetap boleh walau rekening cuma 1
    if ($fromKas === 110 && count($bank) <= 1) {
        // secara UX “sebaiknya” disable untuk bank->bank kalau rekening cuma 1
        $result[] = ['id' => 110, 'name' => $bankLabel, 'msg' => 'disabled'];
    } else {
        $result[] = ['id' => 110, 'name' => $bankLabel];
    }

    return $this->output
        ->set_content_type('application/json')
        ->set_output(json_encode($result));
}





public function tujuan_kas_withdraw(){
	$id= $this->db->escape_str($this->input->post('id'));
	if(!empty($id)){
		$result = $this->model_app->view_where('jenis_kas',array('status'=>1));
		$data = array();
		foreach ($result->result() as $row)
		{
			$data[] = array("id"=>$row->id_akun,"name"=>$row->title);
		}
	}else{
		$data[] = array("id"=>0,"name"=>'Pilih','msg'=>'disabled');
	}
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}

public function jenis_pembayaran(){
	$type =  $this->db->escape_str($this->input->post('type'));
	if($type=='mutasi'){
		$where = array('kunci'=>0,'publish'=>'Y');
	}else{
		$where = array('publish'=>'Y');
	}
	$result = $this->model_app->view_where('jenis_bayar',$where);
	$data = array();
	foreach ($result->result() as $row)
	{
		$data[] = array("id"=>$row->id,"name"=>$row->nama_bayar);
	}

	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));

}

public function rekening(){
	$id_dari =  $this->db->escape_str($this->input->post('dari'));
	$id =  $this->db->escape_str($this->input->post('id'));
	$where = array('publish'=>'Y');
	if(!empty($id_dari)){
		$where = array('id!='=>$id_dari,'publish'=>'Y');
	}

	$result = $this->model_app->view_where('rekening_bank',$where);
	$data = array();
	foreach ($result->result() as $row)
	{
		$data[] = array("id"=>$row->id,"name"=>$row->inisial);
	}

	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));

}
public function pengeluaran()
{
	$this->_cek_akses_mutasi('html');

	$data['title'] = 'Pengeluaran | '.$this->title;

	$conditions['where'] = array( 
		'jenis_pengeluaran.kunci' => 0, 
		'jenis_pengeluaran.pub' => 'Y'
	); 

	$conditions['returnType'] = 'count'; 
	$totalRec = $this->model_data->getJenisPengeluaran($conditions); 

			// Pagination configuration 
	$config['target']      = '#dataJenisKas'; 
	$config['base_url']    = base_url('kas/cariJenis'); 
	$config['total_rows']  = $totalRec; 
	$config['per_page']    = 10; 
	$config['link_func']   = 'search_Jenis_Kas'; 
			// Initialize pagination library 
	$this->ajax_pagination->initialize($config); 

			// Get records 
	$conditions = array( 
		'limit' => 10 
	); 

	$conditions['where'] = array( 
		'jenis_pengeluaran.kunci' => 0, 
		'jenis_pengeluaran.pub' => 'Y'
	); 

	$data['akun'] = $this->model_app->view_where('akun',['kunci'=>0])->result(); 
	$data['result'] = $this->model_data->getJenisPengeluaran($conditions); 
	$this->template->load('main/themes','kas/jenis',$data);
}
public function edit_jenis(){
	$id= $this->db->escape_str($this->input->post('id'));
	if($id>0){
		$where = array('id_jenis' => $id);
		$row = $this->model_app->edit('jenis_pengeluaran',$where)->row_array();
		$data = array('id'=>$id,'judul'=>$row['title'],'grup'=>$row['id_akun'],'aktif'=>$row['pub'],'belanja'=>$row['status']);
	}else{
		$data = array('id'=>0,'judul'=>"","grup"=>"","aktif"=>"",'belanja'=>'');
	}
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}
public function save_jenis()
{
	simpan_demo("Simpan");
	$id= $this->db->escape_str($this->input->post('id'));
	$type= $this->db->escape_str($this->input->post('type'));
	$judul= change_case($this->db->escape_str($this->input->post('judul')));
	$grup= $this->db->escape_str($this->input->post('grup'));
	$aktif= $this->db->escape_str($this->input->post('aktif'));
	$belanja= $this->db->escape_str($this->input->post('belanja'));
	$_data = array('title'=>$judul,'id_akun'=>$grup,'pub'=>$aktif,'status'=>$belanja);
	if($id ==0 AND $type=='add'){
				///data baru
		$res= $this->model_app->input('jenis_pengeluaran',$_data);
		if($res['status']=='ok'){
			$data = array('status'=>200,'msg'=>'Data berhasil disimpan');
		}else{
			$data = array('status'=>400);
		}
	}else{
				///data update
		$res=  $this->model_app->update('jenis_pengeluaran',$_data,array('id_jenis'=>$id));
		if($res['status']=='ok'){
			$data = array('status'=>200,'msg'=>'Data berhasil update');
		}else{
			$data = array('status'=>400);
		}
	}
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}
public function hapus_jenis()
{
	simpan_demo('Hapus');
	$id = $this->db->escape_str($this->input->post('id'));
	$type = $this->db->escape_str($this->input->post('type'));
	if($id >0 AND $type=='hapus'){
		$cek2 = $this->model_app->view_where('pengeluaran_detail',array('id_biaya' => $id));
		if($cek2->num_rows() == 0){
			$where = array('id_jenis' => $id);
			$res=$this->model_app->hapus('jenis_pengeluaran',$where);
			if($res['status']=='ok'){
				$data = array('status'=>200,'msg'=>'Data berhasil dihapus');
			}else{
				$data = array('status'=>400,'msg'=>'Data gagal dihapus');
			}

		}else{
			$data = array('status'=>400,'msg'=>'Data tidak bisa dihapus');
		}
	}else{
		$data = array('status'=>400,'msg'=>'Bad request');
	}
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}
public function cariJenis(){	
	$page = $this->input->post('page'); 
	if(!$page){ 
		$offset = 0; 
	}else{ 
		$offset = $page; 
	} 

	$limits = $this->input->post('limits'); 
	if(!empty($limits)){
		$limit = $limits; 
	}else{ 
		$limit = 10; 
	} 
	$sortBy = $this->input->post('sortBy'); 
	if(!empty($sortBy)){ 
		$conditions['search']['sortBy'] = $sortBy; 
	} 

	$keywords = $this->input->post('keywords'); 
	if(!empty($keywords)){ 
		$conditions['search']['keywords'] = $keywords; 
	} 

	$jenis = $this->input->post('jenis'); 
	if(!empty($jenis)){ 
		$conditions['where'] = array(
			'jenis_cetakan.id_jenis'=>$jenis
		); 
	} 
	$conditions['where'] = array( 
		'jenis_pengeluaran.kunci' => 0, 
		'jenis_pengeluaran.pub' => 'Y'
	); 

			// Get record count 
	$conditions['returnType'] = 'count'; 
	$totalRec = $this->model_data->getJenisPengeluaran($conditions); 

			// Pagination configuration 
	$config['target']      = '#dataJenisKas'; 
	$config['base_url']    = base_url('kas/cariJenis'); 
	$config['total_rows']  = $totalRec; 
	$config['per_page']    = $limit; 
	$config['link_func']   = 'search_Jenis_Kas'; 

			// Initialize pagination library 
	$this->ajax_pagination->initialize($config); 

			// Get records 
	$conditions['start'] = $offset; 
	$conditions['limit'] = $limit;
	$conditions['where'] = array( 
		'jenis_pengeluaran.kunci' => 0, 
		'jenis_pengeluaran.pub' => 'Y'
	); 
	unset($conditions['returnType']); 
	$data['result'] = $this->model_data->getJenisPengeluaran($conditions); 

	$conditions['offset'] = $offset; 
			// Load the data list view 
	$this->load->view('kas/cari-jenis', $data, false); 
}

public function jenis_kas()
{
	$id = $this->input->post('id',TRUE);
	if($id==3){
		$id = 2;
	}else{
		$id = 1;
	}
	$result = $this->model_app->view_where_like('jenis_kas','id_akun',$id,'after')->result();
	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($result));
}
public function load_jenis_kas(){
    // sumber untuk Tambah Modal (dipakai di kas/pengaturan)
    // 411 = Kas Tunai di Laci, 110 = Kas Bank (rekening dipilih terpisah)
    $bank = $this->model_app->view_where('rekening_bank', ['publish' => 'Y'])->result_array();

    $bankLabel = 'Kas Bank';
    if (count($bank) === 1) {
        $bankLabel = 'Bank ' . $bank[0]['inisial'];
    } elseif (count($bank) > 1) {
        $bankLabel = 'Kas Bank (Pilih Rekening)';
    }

    $data = [
        ['id' => 411, 'name' => 'Kas Tunai di Laci'],
        ["id" => 111, "name" => "Kas Tunai di Simpan"],
        ['id' => 110, 'name' => $bankLabel],
    ];

    $this->output
        ->set_content_type('application/json')
        ->set_output(json_encode($data));
}

public function detail_bayar()
{
	$conditions[] ='';
	$data['result'] = $this->model_data->detailMerchant();
	$this->load->view('kas/detail_bayar', $data, false); 
}


public function cetak_laporan()
{
			// print_r($_POST);
	$periode = $this->input->post('tanggal');
			// list($bulan,$tahun) = explode(' ',$periode);
	$data['info'] = info();
	$data['user'] = $this->model_app->view_where('tb_users', array('id_user' => $this->iduser))->row_array();
	$data['logo'] = FCPATH.'uploads/'.info()['logo'];
	$data['periode'] = $periode;

	$data['kas_kecil'] = $this->model_app->sum_data_math('SUM(`kas_masuk`.`pemasukan` - `kas_masuk`.`pengeluaran`) AS `total`','kas_masuk',['no_reff'=>111],'no_reff');

	$data['kas_penjualan'] = $this->model_app->sum_data_math('SUM(`kas_masuk`.`pemasukan` - `kas_masuk`.`pengeluaran`) AS `total`','kas_masuk',['no_reff'=>411],'no_reff');

	$data['kas_bank'] = $this->model_app->sum_data_math('SUM(`kas_masuk`.`pemasukan` - `kas_masuk`.`pengeluaran`) AS `total`','kas_masuk',['no_reff'=>110],'no_reff');

	$data['total'] = $data['kas_kecil'] + $data['kas_penjualan'] + $data['kas_bank'];

	$data['waicon'] 	= ['color'=>FCPATH.'assets/img/wa_icon.png','bw'=>FCPATH.'assets/img/wa_icon_bw.png'];
	$data['mail'] 		= ['color'=>FCPATH.'assets/img/gmail_icon.png','bw'=>FCPATH.'assets/img/gmail_icon_bw.png'];
	$data['fbicon'] 	= ['color'=>FCPATH.'assets/img/fb_icon.png','bw'=>FCPATH.'assets/img/fb_icon_bw.png'];
	$data['igicon'] 	= ['color'=>FCPATH.'assets/img/ig_icon.png','bw'=>FCPATH.'assets/img/ig_icon_bw.png'];

	$data['logo_blunas']	= FCPATH.'uploads/'.info()['logo_bw'];

	$this->load->library("pdf");
	$this->pdf->setPaper("A4", "portrait");
	$this->pdf->filename = "laporan_keuangan_" . $periode;
	$this->pdf->load_view("kas/cetak_laporan", $data);
			// $this->load->view('kas/cetak_laporan', $data, false); 

}

public function simpan_modal()
{
    $this->_cek_akses_mutasi('json');
    simpan_demo("Simpan");

    $kas_code   = (int)$this->input->post('akun');
    $rekeningId = (int)$this->input->post('rekening'); // hanya dipakai kalau kas_code=110
    $jumlah     = (int)$this->_angka($this->input->post('jumlah'));
    $keterangan = trim((string)$this->input->post('keterangan'));

    if ($kas_code <= 0) {
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(['status' => 400, 'msg' => 'Akun kas belum dipilih']));
    }
    if ($jumlah <= 0) {
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(['status' => 400, 'msg' => 'Jumlah harus diisi']));
    }
    if ($keterangan === '') {
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(['status' => 400, 'msg' => 'Keterangan harus diisi']));
    }

    // resolve tujuan (kas/bank) -> akun jurnal_detail
    $dst = $this->_resolve_akun_mutasi($kas_code, ($kas_code === 110 ? $rekeningId : 0));
    if ((int)$dst['akun'] <= 0) {
        $msg = ($kas_code === 110) ? 'Rekening bank belum dipilih' : 'Akun kas tidak ditemukan';
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(['status' => 400, 'msg' => $msg]));
    }

    // set_account menyimpan id_akun, bukan nomor/prefix akun.
    $modalRow = $this->db
        ->select('akun.id_akun')
        ->from('set_account')
        ->join('akun', 'akun.id_akun = set_account.id_akun')
        ->join('kelompok_akun', 'kelompok_akun.id_kelompok_akun = akun.id_kelompok_akun')
        ->where('set_account.id_sa', 1)
        ->where('kelompok_akun.kel_akun', 310)
        ->where('akun.id_perkiraan', 2)
        ->get()
        ->row_array();
    $akun_modal = (int)($modalRow['id_akun'] ?? 0);
    if ($akun_modal <= 0) {
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(['status' => 400, 'msg' => 'Akun Modal Usaha belum dikonfigurasi dengan benar']));
    }

    $now = date('Y-m-d H:i:s');
    $tgl = date('Y-m-d');

    $id_generate = autoNumber(NOMOR_REFF, DIGIT_REFF, 'id_generate', 'kas_masuk');
    $no_trans    = $id_generate;

    $catatan_db = 'Tambah Modal: ' . $keterangan;

    $this->db->trans_begin();

    try {
        // 1) kas_masuk (pemasukan)
        $this->db->insert('kas_masuk', [
            'id_generate'  => $id_generate,
            'id_jenis'     => (int)$dst['jenis'],
            'id_parent'    => 0,
            'id_user'      => (int)$this->iduser,
            'id_bayar'     => 1,
            'id_sub_bayar' => (int)$dst['sub'],
            'no_reff'      => (string)$dst['jenis'],
            'catatan'      => $catatan_db,
            'pemasukan'    => $jumlah,
            'pengeluaran'  => 0,
            'create_date'  => $now,
        ]);

        $rowId = (int)$this->db->insert_id();
        if ($rowId > 0) {
            $this->db->where('id', $rowId)->update('kas_masuk', ['id_parent' => $rowId]);
        }

        // 2) jurnal + jurnal_detail (agar saldo di kartu Kas ikut berubah)
        if ($this->db->table_exists('jurnal') && $this->db->table_exists('jurnal_detail')) {
            $this->db->insert('jurnal', [
                'no_trans'     => $no_trans,
                'tgl'          => $tgl,
                'keterangan'   => $catatan_db . ' (' . $dst['nama'] . ')',
                'bukti'        => '',
                'id_user'      => (int)$this->iduser,
                'create_date'  => $now,
                'update_date'  => $now,
            ]);

            $id_jurnal = (int)$this->db->insert_id();

            // debit: kas/bank tujuan
            $this->db->insert('jurnal_detail', [
                'id_jurnal'      => $id_jurnal,
                'id_akun'        => (int)$dst['akun'],
                'tipe_kas'       => 1,
                'id_perkiraan'   => 1, // debit
                'nilai'          => $jumlah,
                'catatan_jurnal' => null,
            ]);

            // kredit: akun modal
            $this->db->insert('jurnal_detail', [
                'id_jurnal'      => $id_jurnal,
                'id_akun'        => (int)$akun_modal,
                'tipe_kas'       => 1,
                'id_perkiraan'   => 2, // kredit
                'nilai'          => $jumlah,
                'catatan_jurnal' => null,
            ]);
        }

        // 3) OPTIONAL: jurnal_transaksi (untuk modul pembukuan lama)
        if ($this->db->table_exists('jurnal_transaksi')) {
            $this->db->insert('jurnal_transaksi', [
                'id_user'       => (int)$this->iduser,
                'no_reff'       => (int)$dst['akun'],
                'reff'          => null,
                'tgl_input'     => $now,
                'tgl_transaksi' => $tgl,
                'jenis_saldo'   => 'debit',
                'saldo'         => $jumlah,
                'keterangan'    => $catatan_db,
            ]);

            $this->db->insert('jurnal_transaksi', [
                'id_user'       => (int)$this->iduser,
                'no_reff'       => (int)$akun_modal,
                'reff'          => null,
                'tgl_input'     => $now,
                'tgl_transaksi' => $tgl,
                'jenis_saldo'   => 'kredit',
                'saldo'         => $jumlah,
                'keterangan'    => $catatan_db,
            ]);
        }

        if ($this->db->trans_status() === false) {
            $this->db->trans_rollback();
            $out = ['status' => 400, 'msg' => 'Gagal menyimpan (DB)'];
        } else {
            $this->db->trans_commit();
            $out = ['status' => 200, 'msg' => 'Berhasil'];
        }

    } catch (Throwable $e) {
        $this->db->trans_rollback();
        $out = ['status' => 400, 'msg' => 'Error: ' . $e->getMessage()];
    }

    return $this->output
        ->set_content_type('application/json')
        ->set_output(json_encode($out));
}


private function cek_detail()
{

	$arr1 = $this->db->select('*')->group_by('id_invoice')->get('invoice_detail')->result();
	foreach($arr1 AS $val1){
		$data1[] = $val1->id_invoice;
	}

	$arr2 = $this->model_app->view('invoice');
	foreach($arr2 AS $val2){
		$data2[] = $val2['id_invoice'];
	}

	$result=array_diff($data1,$data2);
	echo '<table class="table table-bordered table-hover">';
	if(!empty($result)){
		$jumlah =0;
		foreach($result  AS $key=>$val){

			$this->model_app->delete("invoice_detail", ['id_invoice'=>$val]);
			echo "<tr>";
			echo "<td>$val</td>";
			echo "</tr>";
		}
	}
	echo "</table>";
	echo "</div>";

}

public function reset_bayar()
{
	$this->cek_detail();
	$arr1 = $this->db->select('*')->group_by('id_invoice')->get('bayar_invoice_detail')->result();
	foreach($arr1 AS $val1){
		$data1[] = $val1->id_invoice;
	}

	$arr2 = $this->model_app->view('invoice');
	foreach($arr2 AS $val2){
		$data2[] = $val2['id_invoice'];
	}

	$result=array_diff($data1,$data2);
	echo '<table class="table table-bordered table-hover">';
	if(!empty($result)){
		$jumlah =0;
		foreach($result  AS $key=>$val){
					// $cek_bayar = $this->model_app->view_where('bayar_invoice_detail',['id_invoice'=>$val])->row();
					// $jumlah += $cek_bayar->jml_bayar;
			$this->model_app->delete("bayar_invoice_detail", ['id_invoice'=>$val]);
			echo "<tr>";
			echo "<td>$val</td>";
			echo "</tr>";
		}
	}
	echo "</table>";
	echo "</div>";
			// dump($jumlah);
	$this->reset_kas();
}

private function cek_id_kas($id)
{
	$cek = $this->model_app->pilih_where('id_kas','pengeluaran',['id_pengeluaran'=>$id]);
}

private function reset_kas()
{
	$this->db->truncate('kas_masuk');
	$cek_bayar = $this->model_app->view('bayar_invoice_detail');
			// dump($cek_bayar);
	foreach($cek_bayar AS $val){

		if($val['id_bayar']==1)
		{
			$autoNumber = autoNumber(
				NOMOR_REFF,
				DIGIT_REFF,
				"id_generate",
				"kas_masuk"
			);

			$this->model_app->insert("kas_masuk", [
				"no_reff" => 411,
				"id_bayar" => $val['id_bayar'],
				"id_sub_bayar" => $val['id_sub_bayar'],
				"id_user" => $this->iduser,
				"id_generate" => $autoNumber,
				"pemasukan" => $val['jml_bayar'],
				"create_date" => $val['tgl_bayar'],
				"catatan" => "Pendapatan INVOICE NO.#" . $val['id_invoice'],
			]);

		}

		if($val['id_bayar']==2)
		{
			$autoNumber = autoNumber(
				NOMOR_REFF,
				DIGIT_REFF,
				"id_generate",
				"kas_masuk"
			);
			$this->model_app->insert("kas_masuk", [
				"no_reff" => 110,
				"id_bayar" => $val['id_bayar'],
				"id_sub_bayar" => $val['id_sub_bayar'],
				"id_user" => $this->iduser,
				"id_generate" => $autoNumber,
				"pemasukan" => $val['jml_bayar'],
				"create_date" => $val['tgl_bayar'],
				"catatan" => "Pendapatan INVOICE NO.#" . $val['id_invoice'],
			]);
		}
	}

	$cek_pengeluaran = $this->model_app->view('bayar_pengeluaran');
			// dump($cek_pengeluaran);
	foreach($cek_pengeluaran AS $val){
		$no_reff = $this->cek_id_kas($val['id_pengeluaran']);
		if($val['id_bayar']==1)
		{

			$autoNumber = autoNumber(
				NOMOR_REFF,
				DIGIT_REFF,
				"id_generate",
				"kas_masuk"
			);

			$this->model_app->insert("kas_masuk", [
				"no_reff" => $no_reff,
				"id_bayar" => $val['id_bayar'],
				"id_sub_bayar" => $val['id_sub_bayar'],
				"id_user" => $this->iduser,
				"id_generate" => $autoNumber,
				"pengeluaran" => $val['jml_bayar'],
				"create_date" => $val['tgl_bayar'],
				"catatan" => "Pengeluaran No.#" . $val['id_pengeluaran'],
			]);

		}

		if($val['id_bayar']==2)
		{
					// $where = ["no_reff"=>$no_reff,"id_sub_bayar"=>0,"catatan" => "Pengeluaran No.#" . $val['id_pengeluaran']];
					// $this->model_app->delete("kas_masuk", $where);
			$autoNumber = autoNumber(
				NOMOR_REFF,
				DIGIT_REFF,
				"id_generate",
				"kas_masuk"
			);

			$this->model_app->insert("kas_masuk", [
				"no_reff" => 110,
				"id_bayar" => $val['id_bayar'],
				"id_sub_bayar" => $val['id_sub_bayar'],
				"id_user" => $this->iduser,
				"id_generate" => $autoNumber,
				"pengeluaran" => $val['jml_bayar'],
				"create_date" => $val['tgl_bayar'],
				"catatan" => "Pengeluaran No.#" . $val['id_pengeluaran'],
			]);
		}
	}
}

public function cashback()
{

	$data['title'] = 'Cashback | '.$this->title;		

	$this->template->load('main/themes','kas/cashback',$data);		
}

public function ajaxCashback(){
	$page = $this->input->post('page'); 
	if(!$page){ 
		$offset = 0; 
	}else{ 
		$offset = $page; 
	} 

	$limits = $this->input->post('limits'); 
	if(!empty($limits)){ 
		$limit = $limits; 
	}else{ 
		$limit = $this->perPage; 
	} 
	$sortBy = $this->input->post('sortBy'); 

	if(!empty($sortBy)){ 
		$conditions['search']['sortBy'] = $sortBy; 
	} 

			// Get record count 
	$conditions['returnType'] = 'count'; 
	$totalRec = $this->cashback->getCashback($conditions); 

			// Pagination configuration 
	$config['target']      = '#dataCashback'; 
	$config['base_url']    = base_url('kas/ajaxCashback'); 
	$config['total_rows']  = $totalRec; 
	$config['per_page']    = $limit; 
	$config['link_func']   = 'FilterCashback'; 

			// Initialize pagination library 
	$this->ajax_pagination->initialize($config); 
			// Get records 

	$conditions = array( 
		'start' => $offset, 
		'limit' => $limit 
	); 


			// print_r($conditions);

	unset($conditions['returnType']); 

	$data['result'] = $this->cashback->getCashback($conditions); 

			// Load the data list view 
	$this->load->view('kas/ajax-cashback', $data); 
}

public function load_kas(){
	$id = $this->db->escape_str($this->input->post('id'));
	$data = $this->kas_tunai($id);

	$this->output
	->set_content_type('application/json')
	->set_output(json_encode($data));
}

public function total_kas_kecil()
{
			// Kas Tunai di Simpan (akun id 47)
	$val = $this->kas_tunai(47);
	$this->output->set_content_type('text/html')
	->set_output('Rp ' . number_format((float)$val['nilai'], 0, ',', '.'));
}

public function total_kas_penjualan()
{
			// DP / Kas Penjualan (akun id 31)
	$val = $this->kas_tunai(31);
	$this->output->set_content_type('text/html')
	->set_output('Rp ' . number_format((float)$val['nilai'], 0, ',', '.'));
}

public function total_kas_bank()
{
			// Total seluruh rekening bank yang publish=Y
	$total = 0;
	$q = $this->model_app->view_where('rekening_bank',[ 'publish' => 'Y' ]);
	foreach ($q->result_array() as $row){
		$idAkun = isset($row['id_akun']) ? (int)$row['id_akun'] : 0;
		if($idAkun>0){
			$hasil = $this->kas_tunai($idAkun);
			$total += (int)$hasil['nilai'];
		}
	}

	$this->output->set_content_type('text/html')
	->set_output('Rp ' . number_format((float)$total, 0, ',', '.'));
}

		/* ============================================================
 * MUTASI KAS (Kas Tunai / Kas Bank)
 * Endpoint yang dipakai: assets/js/mutasi.js
 * - kas/mutasi                (page)
 * - kas/cariMutasi/{offset}   (ajax timeline)
 * - kas/jenis_kas_mutasi      (dropdown sumber kas)
 * - kas/cek_saldo             (cek saldo sumber)
 * - kas/simpan_mutasi         (buat mutasi)
 * ============================================================ */

		public function mutasi()
		{
			$this->_cek_akses_mutasi('html');

			$data['title'] = 'Data Mutasi | '.$this->title;
			$this->template->load('main/themes','kas/mutasi',$data);
		}


/**
 * Normalisasi format tanggal dari daterangepicker (MM/DD/YYYY) ke Y-m-d
 */
private function _normalize_date($str)
{
	$str = trim((string)$str);
	if ($str === '') return '';

	// format sudah Y-m-d
	if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $str)) {
		return $str;
	}

	// format MM/DD/YYYY (daterangepicker default)
	if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $str, $m)) {
		$mm = str_pad($m[1], 2, '0', STR_PAD_LEFT);
		$dd = str_pad($m[2], 2, '0', STR_PAD_LEFT);
		$yy = $m[3];
		return $yy.'-'.$mm.'-'.$dd;
	}

	// fallback: coba strtotime
	$ts = strtotime($str);
	return $ts ? date('Y-m-d', $ts) : '';
}

/**
 * Parse tanggal dari daterangepicker / input user:
 * - support: DD/MM/YYYY, MM/DD/YYYY, YYYY-MM-DD, DD-MM-YYYY
 * - fallback: strtotime
 */
private function _parse_picker_date($str)
{
    $str = trim((string)$str);
    if ($str === '') return '';

    // sudah Y-m-d
    if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $str)) {
        return $str;
    }

    // support DD/MM/YYYY atau MM/DD/YYYY
    if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $str, $m)) {
        $a = (int)$m[1];
        $b = (int)$m[2];
        $y = (int)$m[3];

        // kalau jelas (salah satu > 12)
        if ($a > 12) { $d = $a; $mo = $b; }
        elseif ($b > 12) { $mo = $a; $d = $b; }
        else {
            // ambigu (01/02/2025) -> default Indonesia: DD/MM
            $d = $a; $mo = $b;
        }

        if (checkdate($mo, $d, $y)) {
            return sprintf('%04d-%02d-%02d', $y, $mo, $d);
        }

        // fallback: coba dibalik
        if (checkdate($a, $b, $y)) {
            return sprintf('%04d-%02d-%02d', $y, $a, $b);
        }

        return '';
    }

    // support DD-MM-YYYY atau MM-DD-YYYY
    if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/', $str, $m)) {
        $a = (int)$m[1];
        $b = (int)$m[2];
        $y = (int)$m[3];

        if ($a > 12) { $d = $a; $mo = $b; }
        elseif ($b > 12) { $mo = $a; $d = $b; }
        else { $d = $a; $mo = $b; }

        if (checkdate($mo, $d, $y)) {
            return sprintf('%04d-%02d-%02d', $y, $mo, $d);
        }
        if (checkdate($a, $b, $y)) {
            return sprintf('%04d-%02d-%02d', $y, $a, $b);
        }
        return '';
    }

    // fallback umum
    $ts = strtotime($str);
    return $ts ? date('Y-m-d', $ts) : '';
}


public function cariMutasi($page = 0)
{
    $this->_cek_akses_mutasi('html');

    $page_post = $this->input->post('page');
    $page = ($page_post !== null && $page_post !== '') ? (int)$page_post : (int)$page;
    $offset = ($page > 0) ? $page : 0;

    $dari_raw   = $this->input->post('dari');
    $sampai_raw = $this->input->post('sampai');

    $dari   = $this->_parse_picker_date($dari_raw);
    $sampai = $this->_parse_picker_date($sampai_raw);

    if ($dari === '' || $sampai === '') {
        $dari   = date('Y-m-d', strtotime('monday this week'));
        $sampai = date('Y-m-d');
    }

    if ($dari > $sampai) {
        $tmp = $dari; $dari = $sampai; $sampai = $tmp;
    }

    $conditions = [];
    $conditions['search']['dari']   = $dari;
    $conditions['search']['sampai'] = $sampai;

    $conditions['returnType'] = 'count';
    $totalRec = $this->model_data->getMutasiTimeline($conditions);

    $config['target']      = '#dataMutasi';
    $config['base_url']    = base_url('kas/cariMutasi');
    $config['total_rows']  = $totalRec;
    $config['per_page']    = $this->perPage;
    $config['link_func']   = 'search_Mutasi';
    $this->ajax_pagination->initialize($config);

    unset($conditions['returnType']);
    $conditions['start'] = $offset;
    $conditions['limit'] = $this->perPage;

    $data['result'] = $this->model_data->getMutasiTimeline($conditions);
    $this->load->view('kas/cari-mutasi', $data);
}



public function dashboard_saldo()
{
    // akses sama seperti mutasi (di file ini memang akses-check dipusatkan di _cek_akses_mutasi)
    $this->_cek_akses_mutasi('json');

    // Kas tunai default (sudah ada helpernya)
    $akunTunai = (int)$this->_get_akun_kas_tunai_default();

    $namaTunai = $this->db->select('nama')
        ->get_where('akun', ['id_akun' => $akunTunai])
        ->row('nama');
    if (!$namaTunai) $namaTunai = 'Kas Tunai';

    $items = [];
    $saldoTunai = (int)$this->_saldoAkun($akunTunai);
    $items[] = [
        'type' => 'cash',
        'label' => $namaTunai,
        'saldo' => $saldoTunai,
        'akun'  => $akunTunai,
    ];

    // Bank (rekening_bank) -> join akun agar labelnya konsisten seperti yang biasa tampil
    $banks = $this->db->select('rb.id, rb.id_akun, rb.nama_bank, rb.inisial, a.nama AS nama_akun')
        ->from('rekening_bank rb')
        ->join('akun a', 'a.id_akun = rb.id_akun', 'left')
        ->where('rb.publish', 'Y')
        ->order_by('rb.id', 'ASC')
        ->get()->result_array();

    foreach ($banks as $b) {
        $idAkun = (int)$b['id_akun'];
        if ($idAkun <= 0) continue;

        $label = trim((string)$b['nama_akun']);
        if ($label === '') {
            $inisial = trim((string)$b['inisial']);
            $label = $inisial ? ('Bank ' . $inisial) : (trim((string)$b['nama_bank']) ?: 'Kas Bank');
        }

        $items[] = [
            'type'        => 'bank',
            'label'       => $label,
            'saldo'       => (int)$this->_saldoAkun($idAkun),
            'akun'        => $idAkun,
            'rekening_id' => (int)$b['id'],
        ];
    }

    $total = 0;
    foreach ($items as $it) $total += (int)$it['saldo'];

    return $this->output
        ->set_content_type('application/json')
        ->set_output(json_encode([
            'status' => 200,
            'total'  => $total,
            'items'  => $items,
            'ts'     => date('Y-m-d H:i:s'),
        ]));
}





public function jenis_kas_mutasi()
{
    // sumber mutasi: Kas Tunai (411) + Kas Tunai di Simpan (111) + Bank (110)
    $bank = $this->model_app->view_where('rekening_bank', ['publish' => 'Y'])->result_array();

    $bankLabel = 'Kas Bank';
    if (count($bank) === 1) {
        $bankLabel = 'Bank ' . $bank[0]['inisial'];
    } elseif (count($bank) > 1) {
        $bankLabel = 'Kas Bank (Pilih Rekening)';
    } else {
        $bankLabel = 'Kas Bank (Belum ada rekening)';
    }

    $data = [
        ['id' => 411, 'name' => 'Kas Tunai di Laci'],
        ['id' => 111, 'name' => 'Kas Tunai di Simpan'],
        ['id' => 110, 'name' => $bankLabel],
    ];

    return $this->output
        ->set_content_type('application/json')
        ->set_output(json_encode($data));
}



public function cek_saldo()
{
	$this->_cek_akses_mutasi('json');

	$idkas    = (int)$this->input->post('idkas');
	$rekening = (int)$this->input->post('rekening'); // dipakai kalau idkas=110 (bank)

	// resolve akun jurnal (id_akun) dari pilihan dropdown mutasi
	$src = $this->_resolve_akun_mutasi($idkas, ($idkas === 110 ? $rekening : 0));
	if ((int)$src['akun'] <= 0) {
		$msg = ($idkas === 110) ? 'Rekening bank belum dipilih' : 'Akun sumber tidak ditemukan';
		return $this->output
		->set_content_type('application/json')
		->set_output(json_encode(['status' => 400, 'saldo' => 0, 'msg' => $msg]));
	}

	$saldo = (int)$this->_saldoAkun((int)$src['akun']);

	return $this->output
	->set_content_type('application/json')
	->set_output(json_encode(['status' => 200, 'saldo' => $saldo]));
}





private function _saldo_kas_mutasi($kas_code, $rekening_id = 0)
{
	$kas_code    = (int)$kas_code;
	$rekening_id = (int)$rekening_id;

	$this->db->select('COALESCE(SUM(pemasukan),0) AS pemasukan, COALESCE(SUM(pengeluaran),0) AS pengeluaran', false);
	$this->db->from('kas_masuk');

    // Banyak data lama kadang pakai id_jenis, kadang pakai no_reff
	$this->db->group_start();
	$this->db->where('no_reff', $kas_code);
	$this->db->or_where('id_jenis', $kas_code);
	$this->db->group_end();

	if ($kas_code === 110) {
        // BANK: wajib cocok rekening
		$this->db->where('id_sub_bayar', $rekening_id);
	} else {
        // NON BANK: data lama bisa 0 / NULL / '' → anggap sama
		$this->db->group_start();
		$this->db->where('id_sub_bayar', 0);
		$this->db->or_where('id_sub_bayar IS NULL', null, false);
		$this->db->or_where('id_sub_bayar', '');
		$this->db->group_end();
	}

	$row = $this->db->get()->row_array();
	$pemasukan   = isset($row['pemasukan']) ? (float)$row['pemasukan'] : 0;
	$pengeluaran = isset($row['pengeluaran']) ? (float)$row['pengeluaran'] : 0;

	return $pemasukan - $pengeluaran;
}



public function simpan_mutasi()
{
	$this->_cek_akses_mutasi('json');
	simpan_demo("Simpan");

	$out = ['status' => 400, 'msg' => 'Gagal'];

	$id_user = (int)$this->session->idu;

	$dari_kas      = (int)$this->input->post('dari_kas');
	$rekening_dari = (int)$this->input->post('rekening_dari'); // kalau dari_kas=110
	$tujuan        = (int)$this->input->post('tujuan');
	$rekening      = (int)$this->input->post('rekening');      // kalau tujuan=110

	// Jika Bank -> Bank, rekening sumber & tujuan wajib beda
	if ($dari_kas === 110 && $tujuan === 110) {
		if ($rekening_dari <= 0 || $rekening <= 0) {
			$out['msg'] = 'Rekening sumber/tujuan belum dipilih.';
			return $this->output->set_content_type('application/json')->set_output(json_encode($out));
		}
		if ((int)$rekening_dari === (int)$rekening) {
			$out['msg'] = 'Rekening tujuan harus berbeda dari rekening sumber.';
			return $this->output->set_content_type('application/json')->set_output(json_encode($out));
		}
	}

	$jumlah = (int)$this->_angka($this->input->post('jumlah'));
	$catatan_user = trim((string)$this->input->post('catatan'));

	if ($dari_kas <= 0 || $tujuan <= 0 || $jumlah <= 0) {
		$out['msg'] = 'Data mutasi belum lengkap.';
		return $this->output->set_content_type('application/json')->set_output(json_encode($out));
	}

	$src = $this->_resolve_akun_mutasi($dari_kas, ($dari_kas === 110 ? $rekening_dari : 0));
	$dst = $this->_resolve_akun_mutasi($tujuan,   ($tujuan === 110   ? $rekening      : 0));

	if ((int)$src['akun'] <= 0) {
		$out['msg'] = ($dari_kas === 110) ? 'Rekening sumber belum dipilih' : 'Akun sumber tidak ditemukan';
		return $this->output->set_content_type('application/json')->set_output(json_encode($out));
	}
	if ((int)$dst['akun'] <= 0) {
		$out['msg'] = ($tujuan === 110) ? 'Rekening tujuan belum dipilih' : 'Akun tujuan tidak ditemukan';
		return $this->output->set_content_type('application/json')->set_output(json_encode($out));
	}

	// saldo sumber harus cukup (mengacu jurnal_detail)
	$saldo_sumber = (int)$this->_saldoAkun((int)$src['akun']);
	if ($saldo_sumber < $jumlah) {
		$out['msg'] = 'Saldo sumber tidak mencukupi';
		return $this->output->set_content_type('application/json')->set_output(json_encode($out));
	}

	$now = date('Y-m-d H:i:s');
	$tgl = date('Y-m-d');

	$id_generate = autoNumber('REF-','%05s','id_generate','kas_masuk');
	$no_trans    = $id_generate;

	$catatan = ($catatan_user !== '') ? $catatan_user : '-';
	$catatan_db = 'Mutasi: ' . $catatan;

	// =========================================================
	// [FIX] Upload bukti mutasi (opsional) -> simpan ke jurnal.bukti
	// =========================================================
	$bukti_mutasi_file = '';
	if (!empty($_FILES['bukti_mutasi']['name'])) {
		$upload_dir = FCPATH . 'uploads/lampiran/';
		if (!is_dir($upload_dir)) {
			@mkdir($upload_dir, 0755, true);
		}

		$this->load->library('upload');

		$safe_ref = preg_replace('/[^A-Za-z0-9_\-]/', '_', (string)$no_trans);
		$config = [
			'upload_path'   => $upload_dir,
			'allowed_types' => 'jpg|jpeg|png|webp|pdf',
			'max_size'      => 6144, // 6MB
			'file_name'     => 'mutasi_' . $safe_ref . '_' . time(),
			'overwrite'     => false,
		];

		$this->upload->initialize($config);

		if (!$this->upload->do_upload('bukti_mutasi')) {
			$out['status'] = 400;
			$out['msg']    = trim($this->upload->display_errors('', ''));
			return $this->output->set_content_type('application/json')->set_output(json_encode($out));
		}

		$up = $this->upload->data();
		$finalUpload = bm_finalize_ci_upload_as_webp($up, 80);
		if (!$finalUpload['status']) {
			$out['status'] = 400;
			$out['msg']    = $finalUpload['message'];
			return $this->output->set_content_type('application/json')->set_output(json_encode($out));
		}

		$bukti_mutasi_file = $finalUpload['file_name'];
	}
	// =========================================================

	$this->db->trans_begin();

	try {
		// 1) kas_masuk pengeluaran sumber
		$this->db->insert('kas_masuk', [
			'id_generate'  => $id_generate,
			'id_jenis'     => (int)$src['jenis'],
			'id_parent'    => 0,
			'id_user'      => $id_user,
			'id_bayar'     => 0,
			'id_sub_bayar' => (int)$src['sub'],
			'no_reff'      => (string)$src['jenis'],
			'catatan'      => $catatan_db,
			'pemasukan'    => 0,
			'pengeluaran'  => $jumlah,
			'create_date'  => $now,
		]);

		$parentId = (int)$this->db->insert_id();
		if ($parentId > 0) {
			$this->db->where('id', $parentId)->update('kas_masuk', ['id_parent' => $parentId]);
		}

		// 2) kas_masuk pemasukan tujuan
		$this->db->insert('kas_masuk', [
			'id_generate'  => $id_generate,
			'id_jenis'     => (int)$dst['jenis'],
			'id_parent'    => $parentId,
			'id_user'      => $id_user,
			'id_bayar'     => 0,
			'id_sub_bayar' => (int)$dst['sub'],
			'no_reff'      => (string)$dst['jenis'],
			'catatan'      => $catatan_db,
			'pemasukan'    => $jumlah,
			'pengeluaran'  => 0,
			'create_date'  => $now,
		]);

		// 3) jurnal + jurnal_detail
		if ($this->db->table_exists('jurnal') && $this->db->table_exists('jurnal_detail')) {

			$this->db->insert('jurnal', [
				'no_trans'     => $no_trans,
				'tgl'          => $tgl,
				'keterangan'   => $catatan_db . ' (' . $src['nama'] . ' -> ' . $dst['nama'] . ')',
				'bukti'        => $bukti_mutasi_file, // ✅ [FIX] simpan lampiran
				'id_user'      => $id_user,
				'create_date'  => $now,
				'update_date'  => $now,
			]);

			$id_jurnal = (int)$this->db->insert_id();

			// debit tujuan
			$this->db->insert('jurnal_detail', [
				'id_jurnal'      => $id_jurnal,
				'id_akun'        => (int)$dst['akun'],
				'tipe_kas'       => 1,
				'id_perkiraan'   => 1,
				'nilai'          => $jumlah,
				'catatan_jurnal' => null,
			]);

			// kredit sumber
			$this->db->insert('jurnal_detail', [
				'id_jurnal'      => $id_jurnal,
				'id_akun'        => (int)$src['akun'],
				'tipe_kas'       => 1,
				'id_perkiraan'   => 2,
				'nilai'          => $jumlah,
				'catatan_jurnal' => null,
			]);
		}

		// 4) jurnal_transaksi (kompat modul lama)
		if ($this->db->table_exists('jurnal_transaksi')) {
			$this->db->insert('jurnal_transaksi', [
				'id_user'       => $id_user,
				'no_reff'       => (int)$dst['akun'],
				'reff'          => null,
				'tgl_input'     => $now,
				'tgl_transaksi' => $tgl,
				'jenis_saldo'   => 'debit',
				'saldo'         => $jumlah,
				'keterangan'    => $catatan_db,
			]);

			$this->db->insert('jurnal_transaksi', [
				'id_user'       => $id_user,
				'no_reff'       => (int)$src['akun'],
				'reff'          => null,
				'tgl_input'     => $now,
				'tgl_transaksi' => $tgl,
				'jenis_saldo'   => 'kredit',
				'saldo'         => $jumlah,
				'keterangan'    => $catatan_db,
			]);
		}

		if ($this->db->trans_status() === false) {
			$this->db->trans_rollback();
			$out['status'] = 400;
			$out['msg']    = 'Gagal menyimpan mutasi (DB).';
		} else {
			$this->db->trans_commit();
			$out['status'] = 200;
			$out['msg']    = 'Mutasi berhasil';
		}

	} catch (Throwable $e) {
		$this->db->trans_rollback();
		$out['status'] = 400;
		$out['msg']    = 'Error: ' . $e->getMessage();
	}

	return $this->output->set_content_type('application/json')->set_output(json_encode($out));
}




private function _angka($str){
	return (int)preg_replace('/[^0-9]/', '', (string)$str);
}

private function _saldoAkun($idAkun){
	$idAkun = (int)$idAkun;
	if($idAkun <= 0) return 0;

	$debit = (float)$this->db->select_sum('nilai','t')
	->get_where('jurnal_detail',['id_akun'=>$idAkun,'id_perkiraan'=>1])
	->row()->t;

	$kredit = (float)$this->db->select_sum('nilai','t')
	->get_where('jurnal_detail',['id_akun'=>$idAkun,'id_perkiraan'=>2])
	->row()->t;

	return $debit - $kredit;
}

private function _get_akun_kas_tunai_default()
{
	// fallback paling aman: akun kas tunai di dump Aa = id_akun 1 :contentReference[oaicite:3]{index=3}
	$default = 1;

	if ($this->db->table_exists('set_account_kas')) {
		$row = $this->db
		->like('nm', 'Kas Tunai', 'both')
		->get('set_account_kas')
		->row_array();

		if (!empty($row) && isset($row['id_akun']) && (int)$row['id_akun'] > 0) {
			return (int)$row['id_akun'];
		}
	}
	return $default;
}

private function _get_akun_kas_kecil_default()
{
	// fallback aman (umum di project Aa Kas Tunai di Simpan pakai id_akun 47)
	$default = 47;

	if ($this->db->table_exists('set_account_kas')) {
		$row = $this->db
		->like('nm', 'Kas Tunai di Simpan', 'both')
		->get('set_account_kas')
		->row_array();

		if (!empty($row) && isset($row['id_akun']) && (int)$row['id_akun'] > 0) {
			return (int)$row['id_akun'];
		}
	}
	return $default;
}


/**
 * Resolve akun untuk mutasi kas.
 * Return:
 * - jenis : kode akun untuk kas_masuk (misal 111 tunai, 110 bank, dll)
 * - sub   : id_sub_bayar (khusus bank: id rekening_bank)
 * - nama  : label akun utk keterangan
 * - akun  : id_akun utk jurnal_detail (kalau ada mapping), fallback ke jenis
 */
private function _resolve_akun_mutasi($kas_code, $rekening_id = 0)
{
	$kas_code    = (int)$kas_code;
	$rekening_id = (int)$rekening_id;

	$out = [
		'jenis' => 0,   // kode kas utk kas_masuk (110/411/111)
		'sub'   => 0,   // id_sub_bayar utk kas_masuk (bank: id rekening_bank)
		'nama'  => '',
		'akun'  => 0,   // id_akun utk jurnal_detail (ini yang dipakai hitung saldo)
	];

	// ===== BANK =====
	if ($kas_code === 110) {
		if ($rekening_id <= 0) return $out;

		$rek = $this->db->get_where('rekening_bank', ['id' => $rekening_id])->row_array();
		if (!$rek) return $out;

		$nama = !empty($rek['inisial']) ? $rek['inisial'] : 'BANK';

		$out['jenis'] = 110;
		$out['sub']   = $rekening_id;
		$out['nama']  = $nama;

		// mapping id_akun bank (contoh dump: rekening_bank id=1 => id_akun=51) :contentReference[oaicite:4]{index=4}
		if (isset($rek['id_akun']) && (int)$rek['id_akun'] > 0) {
			$out['akun'] = (int)$rek['id_akun'];
		}

		return $out;
	}

	// ===== NON-BANK (KAS) =====
	$out['jenis'] = $kas_code;
	$out['sub']   = 0;

	// 🔥 PENTING:
	// Dropdown mutasi di project Aa pakai kode 411 utk "Kas Tunai di Laci",
	// tapi saldo realnya ada di jurnal_detail id_akun=1. :contentReference[oaicite:5]{index=5}
	if ($kas_code === 411) {
		$out['akun'] = (int)$this->_get_akun_kas_tunai_default();
		$out['nama'] = 'Kas Tunai di Laci';
		return $out;
	}

	// Kas Tunai di Simpan biasanya kode 111, saldo realnya id_akun=47 (fallback)
	if ($kas_code === 111) {
		$out['akun'] = (int)$this->_get_akun_kas_kecil_default();
		$out['nama'] = 'Kas Tunai di Simpan';
		return $out;
	}

	// kalau suatu saat dropdown mengirim langsung id_akun pembukuan
	$akun = $this->db->get_where('akun', ['id_akun' => $kas_code])->row_array();
	if ($akun) {
		$out['akun'] = (int)$akun['id_akun'];
		$out['nama'] = !empty($akun['nama']) ? $akun['nama'] : 'Kas';
		return $out;
	}

	// fallback terakhir
	$out['akun'] = 0;
	$out['nama'] = 'Kas';
	return $out;
}


private function _saldo_kas_masuk($jenis, $sub = 0)
{
	$jenis = (int)$jenis;
	$sub   = (int)$sub;

	$row = $this->db
	->select('COALESCE(SUM(pemasukan),0) AS masuk, COALESCE(SUM(pengeluaran),0) AS keluar', false)
	->from('kas_masuk')
	->group_start()
	->where('id_jenis', $jenis)
	->or_where('no_reff', (string)$jenis)
	->group_end()
	->where('id_sub_bayar', $sub)
	->get()
	->row_array();

	$masuk  = isset($row['masuk']) ? (float)$row['masuk'] : 0;
	$keluar = isset($row['keluar']) ? (float)$row['keluar'] : 0;

	return $masuk - $keluar;
}

private function _next_no_trans_mutasi()
{
	$prefix = date('ymd');

    // ambil terakhir dari jurnal (kalau kosong fallback ke kas_masuk)
	$last = $this->db->select('no_trans')
	->from('jurnal')
	->like('no_trans', $prefix, 'after')
	->order_by('no_trans', 'DESC')
	->limit(1)
	->get()->row_array();

	if (!$last || empty($last['no_trans'])) {
		return $prefix . '0001';
	}

	$urut = (int)substr($last['no_trans'], 6);
	$urut = $urut + 1;

	return $prefix . str_pad((string)$urut, 4, '0', STR_PAD_LEFT);
}





}	
