diff --git a/application/controllers/Invoices.php b/application/controllers/Invoices.php index 4a462f3..46c0f0c 100644 --- a/application/controllers/Invoices.php +++ b/application/controllers/Invoices.php @@ -3,6 +3,18 @@ defined('BASEPATH') OR exit('No direct script access allowed'); class Invoices extends CI_Controller { + + // ========================= + // 🔥 CONFIG AKUN + // ========================= + private $akun_persediaan = 21; + private $akun_hpp = 63; + private $akun_piutang = 19; + private $pendapatan_dimuka = 78; // Pendapatan Diterima Dimuka + private $persediaan_dijual = 80; // Persediaan Dalam Penjualan + private $pendapatan_barang = 62; + + public function __construct() { parent::__construct(); @@ -404,297 +416,6 @@ class Invoices extends CI_Controller { 'no_invoice' => $no_invoice ]); } - - public function bayar() - { - $this->output->set_content_type('application/json'); - - $invoice_id = $this->input->post('invoice_id'); - $tanggal_bayar = $this->input->post('tanggal_bayar'); - $detail = $this->input->post('detail'); - - if(!$invoice_id || empty($detail)){ - echo json_encode(['status'=>false,'message'=>'Data tidak valid']); - return; - } - - $invoice = $this->db->get_where('invoices',['id'=>$invoice_id])->row(); - if(!$invoice){ - echo json_encode(['status'=>false,'message'=>'Invoice tidak ditemukan']); - return; - } - - $customer = $this->db->get_where('customers',['id'=>$invoice->customer_id])->row(); - if(!$customer){ - echo json_encode(['status'=>false,'message'=>'Customer tidak ditemukan']); - return; - } - - // ========================= - // HITUNG TOTAL BAYAR - // ========================= - $total_bayar_input = 0; - foreach ($detail as $d) { - $total_bayar_input += (float)$d['amount']; - } - - if($total_bayar_input <= 0){ - echo json_encode(['status'=>false,'message'=>'Total bayar harus > 0']); - return; - } - - // ========================= - // DATA INVOICE - // ========================= - $paid_before = (float)$invoice->total_bayar; - $total_invoice = (float)$invoice->total; - - $new_total_bayar = $paid_before + $total_bayar_input; - $sisa_setelah = $total_invoice - $new_total_bayar; - - if($new_total_bayar > $total_invoice){ - echo json_encode([ - 'status'=>false, - 'message'=>'Pembayaran melebihi total invoice' - ]); - return; - } - - // ========================= - // AKUN - // ========================= - $akun_tabungan = 70; - $akun_barang = 62; - $akun_piutang = 19; - - // ========================= - // HITUNG TOTAL CICILAN - // ========================= - - $cicilan = $this->db->query(" - SELECT ii.* - FROM invoice_installments ii - JOIN ( - SELECT invoice_detail_id, MIN(angsuran_ke) as angsuran_ke - FROM invoice_installments - WHERE customer_id = ? - AND status != 'paid' - GROUP BY invoice_detail_id - ) x - ON x.invoice_detail_id = ii.invoice_detail_id - AND x.angsuran_ke = ii.angsuran_ke - ", [$customer->id])->result(); - - $total_cicilan = 0; - - foreach($cicilan as $c){ - $total_cicilan += ($c->nominal - $c->paid_amount); - } - - // ========================= - // TOTAL PER KATEGORI - // ========================= - $total_tabungan = (float) $this->db - ->select('SUM(subtotal) as total') - ->where('invoice_id', $invoice_id) - ->where('account_id', $akun_tabungan) - ->get('invoice_details')->row()->total ?? 0; - - $total_barang = (float) $this->db - ->select('SUM(subtotal) as total') - ->where('invoice_id', $invoice_id) - ->where('account_id', $akun_barang) - ->get('invoice_details')->row()->total ?? 0; - - $total_other = (float) $this->db - ->select('SUM(subtotal) as total') - ->where('invoice_id', $invoice_id) - ->where_not_in('account_id', [$akun_tabungan, $akun_barang]) - ->get('invoice_details')->row()->total ?? 0; - - // ========================= - // SISA PER KATEGORI - // ========================= - $sisa_other = max(0, $total_other - $paid_before); - $sisa_tabungan = max(0, $total_tabungan - max(0, $paid_before - $total_other)); - $sisa_barang = max(0, $total_barang - max(0, $paid_before - $total_other - $total_tabungan)); - - // ========================= - // ALOKASI - // ========================= - $sisa_bayar = $total_bayar_input; - - // ========================= - // 1. CICILAN (PER ITEM) - // ========================= - $bayar_cicilan = min($sisa_bayar, $total_cicilan); - $sisa_bayar -= $bayar_cicilan; - - // ========================= - // 2. OTHER - // ========================= - $bayar_other = min($sisa_bayar, $sisa_other); - $sisa_bayar -= $bayar_other; - - // ========================= - // 3. TABUNGAN - // ========================= - $bayar_tabungan = min($sisa_bayar, $sisa_tabungan); - $sisa_bayar -= $bayar_tabungan; - - // ========================= - // 4. BARANG - // ========================= - $bayar_barang = min($sisa_bayar, $sisa_barang); - $sisa_bayar -= $bayar_barang; - - // ========================= - // TRANSACTION - // ========================= - $this->db->trans_start(); - - // UPDATE invoice_installments jika perlu di update - if($bayar_cicilan > 0){ - - $sisa = $bayar_cicilan; // ✅ FIX - - foreach($cicilan as $c){ - - if($sisa <= 0) break; - - $kurang = $c->nominal - $c->paid_amount; - $bayar = min($sisa, $kurang); - - $sisa -= $bayar; - - $new_paid = $c->paid_amount + $bayar; - $status = ($new_paid >= $c->nominal) ? 'paid' : 'partial'; - - $this->db->where('id',$c->id)->update('invoice_installments',[ - 'paid_amount' => $new_paid, - 'status' => $status - ]); - } - } - - $no_ref = 'PAY-' . date('YmdHis'); - - $this->db->insert('journals', [ - 'tanggal' => $tanggal_bayar, - 'no_ref' => $no_ref, - 'keterangan'=> 'Diterima Pembayaran Invoice '.$invoice->no_invoice.' ('.$customer->nama.')', - 'ref_type' => 'invoice_payment', - 'ref_id' => $invoice_id, - 'created_by'=> $this->session->userdata('user_id') - ]); - - $journal_id = $this->db->insert_id(); - - // DEBIT - $total_debit = 0; - foreach ($detail as $d) { - if(empty($d['account_id']) || $d['amount'] <= 0) continue; - - $this->db->insert('journal_details', [ - 'journal_id' => $journal_id, - 'account_id' => $d['account_id'], - 'debit' => $d['amount'], - 'kredit' => 0 - ]); - - $total_debit += $d['amount']; - } - - // ========================= - // KREDIT - // ========================= - $total_kredit = 0; - - $kredit_piutang = $bayar_cicilan + $bayar_other + $bayar_barang; - - if($kredit_piutang > 0){ - $this->db->insert('journal_details', [ - 'journal_id'=>$journal_id, - 'account_id'=>$akun_piutang, - 'debit'=>0, - 'kredit'=>$kredit_piutang - ]); - $total_kredit += $kredit_piutang; - } - - if($bayar_tabungan > 0){ - $this->db->insert('journal_details', [ - 'journal_id'=>$journal_id, - 'account_id'=>$akun_tabungan, - 'debit'=>0, - 'kredit'=>$bayar_tabungan - ]); - $total_kredit += $bayar_tabungan; - } - - // VALIDASI - if(round($total_debit,2) !== round($total_kredit,2)){ - $this->db->trans_rollback(); - echo json_encode([ - 'status'=>false, - 'message'=>'Jurnal tidak balance' - ]); - return; - } - - // PAYMENT - $this->db->insert('payments', [ - 'invoice_id'=>$invoice_id, - 'tanggal'=>$tanggal_bayar, - 'jumlah'=>$total_bayar_input, - 'metode'=>'manual', - 'journal_id'=>$journal_id - ]); - - // STATUS - if($new_total_bayar >= $total_invoice){ - $status = 'paid'; - $sisa_setelah = 0; - }elseif($new_total_bayar > 0){ - $status = 'partial'; - }else{ - $status = 'unpaid'; - } - - $this->db->where('id',$invoice_id)->update('invoices',[ - 'total_bayar'=>$new_total_bayar, - 'sisa_piutang'=>$sisa_setelah, - 'status'=>$status, - 'updated_at'=>date('Y-m-d H:i:s'), - 'updated_by'=>$this->session->userdata('user_id') - ]); - - $this->db->trans_complete(); - - // ========================= - // RESPONSE - // ========================= - if (!$this->db->trans_status()) { - echo json_encode([ - 'status' => false, - 'message' => 'Gagal menyelesaikan pembayaran' - ]); - return; - } - - log_activity( - 'invoice', - 'create', - 'Melakukan pembayaran invoice ' . $invoice->no_invoice . ' untuk customer a.n ' . $customer->nama, - 'success' - ); - - echo json_encode([ - 'status'=>true, - 'message'=>'Pembayaran berhasil', - 'sisa'=>$sisa_setelah - ]); - } // ========================= // DELETE @@ -817,13 +538,6 @@ class Invoices extends CI_Controller { echo json_encode($data); } - - // ========================= - // 🔥 CONFIG AKUN - // ========================= - private $akun_persediaan = 21; - private $akun_hpp = 63; - private $akun_piutang = 19; // ========================= // ADD ITEM - FIXED RESPONSE @@ -909,7 +623,8 @@ class Invoices extends CI_Controller { 'warehouse_id' => $warehouse_id, 'keterangan' => $this->input->post('keterangan'), 'subtotal_asli' => $harga_asli, - 'is_cicilan' => $is_cicilan ? 1 : 0 + 'is_cicilan' => $is_cicilan ? 1 : 0, + 'total_hpp_barang' => $total_hpp ]; $this->db->insert('invoice_details', $insert_data); @@ -921,6 +636,7 @@ class Invoices extends CI_Controller { if($this->input->post('account_id') != 70) { $this->generate_jurnal_item($detail_id, $ket_cicilan_jr); } + $this->update_total($invoice_id); // ambil customer dari invoice @@ -994,6 +710,8 @@ class Invoices extends CI_Controller { $item_id = $this->input->post('item_id'); $nama_item = $this->input->post('nama_item'); $tanggal = $this->input->post('tanggal'); + + $total_hpp = 0; if($item_id){ $item = $this->db->get_where('items', ['id'=>$item_id])->row(); @@ -1001,6 +719,7 @@ class Invoices extends CI_Controller { $nama_item = $item->nama_barang; $stok = $this->get_stok($item_id); $qty = (float)$this->input->post('qty'); + $total_hpp = $this->input->post('qty') * $item->harga_beli; if($stok < $qty){ echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup']); return; @@ -1021,7 +740,8 @@ class Invoices extends CI_Controller { 'harga' => $harga, 'subtotal' => $qty * $harga, 'warehouse_id' => $this->input->post('warehouse_id'), - 'keterangan' => $this->input->post('keterangan') + 'keterangan' => $this->input->post('keterangan'), + 'total_hpp_barang' => $total_hpp ]; $this->db->where('id', $id)->update('invoice_details', $update_data); @@ -1112,60 +832,6 @@ class Invoices extends CI_Controller { echo json_encode($cicilan_raw); } - // public function save_cicilan() - // { - // $cicilan_ids = $this->input->post('cicilan_id'); - - // if (empty($cicilan_ids)) { - // echo json_encode([ - // 'status' => false, - // 'message' => 'Tidak ada data dipilih' - // ]); - // return; - // } - - // $this->db->trans_start(); - - // foreach ($cicilan_ids as $id) { - - // // ambil data cicilan - // $cicilan = $this->db->get_where('invoice_installments', [ - // 'id' => $id - // ])->row(); - - // if (!$cicilan) continue; - - // $sisa = $cicilan->nominal - $cicilan->paid_amount; - - // // insert ke invoice_details - // $this->db->insert('invoice_details', [ - // 'invoice_id' => $cicilan->invoice_id, - // 'customer_id' => $cicilan->customer_id, - // 'item_id' => $cicilan->item_id, - // 'qty' => 1, - // 'price' => $sisa, - // 'total' => $sisa, - // 'source_cicilan_id'=> $cicilan->id, // penting buat tracking - // 'created_at' => date('Y-m-d H:i:s') - // ]); - - // // update status cicilan jadi billed - // $this->db->update('invoice_installments', [ - // 'is_billed' => 1 - // ], ['id' => $id]); - // } - - // $this->db->trans_complete(); - - // echo json_encode([ - // 'status' => $this->db->trans_status() - // ]); - // } - // ========================= - // HAPUS HELPER LAMA - TIDAK DIPAKAI LAGI - // ========================= - // Hapus fungsi commit() & rollback() karena sudah inline - private function generate_jurnal_item($id, $ket_cicilan_jr = null) { // $d = $this->db->get_where('invoice_details', ['id'=>$id])->row(); @@ -1254,11 +920,11 @@ class Invoices extends CI_Controller { ]); // ========================= - // 🔥 PENDAPATAN (KREDIT) + // 🔥 PENDAPATAN (KREDIT) Pendapatan Diterima Dimuka // ========================= $this->db->insert('journal_details', [ 'journal_id' => $jid, - 'account_id' => $d->account_id, + 'account_id' => $this->pendapatan_dimuka, 'debit' => 0, 'kredit' => $nilai_jurnal ]); @@ -1271,7 +937,7 @@ class Invoices extends CI_Controller { // HPP (debit) $this->db->insert('journal_details', [ 'journal_id' => $jid, - 'account_id' => $this->akun_hpp, + 'account_id' => $this->persediaan_dijual, 'debit' => $total_hpp, 'kredit' => 0 ]); @@ -1689,4 +1355,495 @@ class Invoices extends CI_Controller { 'status' => $this->db->trans_status() ]); } + +public function bayar() +{ + $this->output->set_content_type('application/json'); + + $invoice_id = $this->input->post('invoice_id'); + $tanggal_bayar = $this->input->post('tanggal_bayar'); + $detail = $this->input->post('detail'); + + if (!$invoice_id || empty($detail)) { + echo json_encode(['status' => false, 'message' => 'Data tidak valid']); + return; + } + + $invoice = $this->db->get_where('invoices', ['id' => $invoice_id])->row(); + if (!$invoice) { + echo json_encode(['status' => false, 'message' => 'Invoice tidak ditemukan']); + return; + } + + $customer = $this->db->get_where('customers', ['id' => $invoice->customer_id])->row(); + if (!$customer) { + echo json_encode(['status' => false, 'message' => 'Customer tidak ditemukan']); + return; + } + + // ========================= + // HITUNG TOTAL BAYAR + // ========================= + $total_bayar_input = 0; + foreach ($detail as $d) { + $total_bayar_input += (float)$d['amount']; + } + + if ($total_bayar_input <= 0) { + echo json_encode(['status' => false, 'message' => 'Total bayar harus > 0']); + return; + } + + // ========================= + // DATA INVOICE + // ========================= + $paid_before = (float)$invoice->total_bayar; + $total_invoice = (float)$invoice->total; + $new_total_bayar = $paid_before + $total_bayar_input; + $sisa_setelah = $total_invoice - $new_total_bayar; + + if ($new_total_bayar > $total_invoice) { + echo json_encode([ + 'status' => false, + 'message' => 'Pembayaran melebihi total invoice' + ]); + return; + } + + // ========================= + // KONFIGURASI AKUN + // ========================= + $akun_tabungan = 70; + $akun_barang = 62; + $akun_piutang = 19; + $akun_pendapatan_ditahan = 78; + $akun_hpp = isset($this->akun_hpp) ? $this->akun_hpp : 81; + $persediaan_dijual = isset($this->persediaan_dijual) ? $this->persediaan_dijual : 50; + + // ========================= + // HITUNG CICILAN + // ========================= + $cicilan = $this->db->query(" + SELECT ii.* + FROM invoice_installments ii + JOIN ( + SELECT invoice_detail_id, MIN(angsuran_ke) as angsuran_ke + FROM invoice_installments + WHERE customer_id = ? + AND status != 'paid' + GROUP BY invoice_detail_id + ) x + ON x.invoice_detail_id = ii.invoice_detail_id + AND x.angsuran_ke = ii.angsuran_ke + ", [$customer->id])->result(); + + $total_cicilan = 0; + foreach ($cicilan as $c) { + $total_cicilan += ($c->nominal - $c->paid_amount); + } + + // ========================= + // TOTAL PER KATEGORI + // ========================= + $total_tabungan = (float)$this->db + ->select('SUM(subtotal) as total') + ->where('invoice_id', $invoice_id) + ->where('account_id', $akun_tabungan) + ->get('invoice_details')->row()->total ?? 0; + + $total_barang = (float)$this->db + ->select('SUM(subtotal) as total') + ->where('invoice_id', $invoice_id) + ->where('account_id', $akun_barang) + ->get('invoice_details')->row()->total ?? 0; + + $total_other = (float)$this->db + ->select('SUM(subtotal) as total') + ->where('invoice_id', $invoice_id) + ->where_not_in('account_id', [$akun_tabungan, $akun_barang]) + ->get('invoice_details')->row()->total ?? 0; + + // ========================= + // SISA PER KATEGORI + // ========================= + $sisa_other = max(0, $total_other - $paid_before); + $sisa_tabungan = max(0, $total_tabungan - max(0, $paid_before - $total_other)); + $sisa_barang = max(0, $total_barang - max(0, $paid_before - $total_other - $total_tabungan)); + + // ========================= + // ALOKASI PEMBAYARAN + // ========================= + $sisa_bayar = $total_bayar_input; + + $bayar_cicilan = min($sisa_bayar, $total_cicilan); + $sisa_bayar -= $bayar_cicilan; + + $bayar_other = min($sisa_bayar, $sisa_other); + $sisa_bayar -= $bayar_other; + + $bayar_tabungan = min($sisa_bayar, $sisa_tabungan); + $sisa_bayar -= $bayar_tabungan; + + $bayar_barang = min($sisa_bayar, $sisa_barang); + $sisa_bayar -= $bayar_barang; + + // ========================= + // AMBIL INVOICE DETAIL + // ========================= + $inv_detail_items = $this->db + ->select(' + invoice_details.id, + invoice_details.account_id, + invoice_details.subtotal, + invoice_details.recognized_amount, + invoice_details.total_hpp_barang, + invoice_details.recognized_hpp, + accounts.priority + ') + ->from('invoice_details') + ->join('accounts', 'accounts.id = invoice_details.account_id', 'left') + ->where('invoice_details.invoice_id', $invoice_id) + ->where('invoice_details.account_id !=', $akun_tabungan) + ->order_by('accounts.priority', 'ASC') + ->order_by('invoice_details.id', 'ASC') + ->get() + ->result(); + + // ========================= + // DEBIT PENDAPATAN DITAHAN + // ========================= + // Tidak termasuk tabungan! + $debit_pendapatan_ditahan = $bayar_cicilan + $bayar_other + $bayar_barang; + + // ========================= + // MULAI TRANSAKSI + // ========================= + $this->db->trans_start(); + + // UPDATE cicilan + if ($bayar_cicilan > 0) { + $sisa = $bayar_cicilan; + foreach ($cicilan as $c) { + if ($sisa <= 0) break; + $kurang = $c->nominal - $c->paid_amount; + $bayar = min($sisa, $kurang); + $sisa -= $bayar; + $new_paid = $c->paid_amount + $bayar; + $status = ($new_paid >= $c->nominal) ? 'paid' : 'partial'; + + $this->db->where('id', $c->id)->update('invoice_installments', [ + 'paid_amount' => $new_paid, + 'status' => $status + ]); + } + } + + $no_ref = 'PAY-' . date('YmdHis'); + + $this->db->insert('journals', [ + 'tanggal' => $tanggal_bayar, + 'no_ref' => $no_ref, + 'keterangan'=> 'Pembayaran Invoice ' . $invoice->no_invoice . ' (' . $customer->nama . ')', + 'ref_type' => 'invoice_payment', + 'ref_id' => $invoice_id, + 'created_by'=> $this->session->userdata('user_id') + ]); + + $journal_id = $this->db->insert_id(); + + // ========================= + // DEBIT SIDE + // ========================= + $total_debit = 0; + $jurnal_debit = []; + + // 1. Kas/Bank (dari detail) + foreach ($detail as $d) { + if (empty($d['account_id']) || $d['amount'] <= 0) continue; + + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $d['account_id'], + 'debit' => $d['amount'], + 'kredit' => 0 + ]); + + $total_debit += (float)$d['amount']; + $jurnal_debit[] = [ + 'account_id' => $d['account_id'], + 'debit' => (float)$d['amount'], + 'jenis' => 'kas' + ]; + } + + // ========================= + // KREDIT SIDE + // ========================= + $total_kredit = 0; + $jurnal_kredit = []; + + // 1. Piutang (KREDIT) + $kredit_piutang = $total_bayar_input - $bayar_tabungan; + if ($kredit_piutang > 0) { + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $akun_piutang, + 'debit' => 0, + 'kredit' => $kredit_piutang + ]); + $total_kredit += $kredit_piutang; + $jurnal_kredit[] = [ + 'account_id' => $akun_piutang, + 'kredit' => $kredit_piutang, + 'jenis' => 'piutang' + ]; + } + + // 2. Tabungan (KREDIT) + if ($bayar_tabungan > 0) { + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $akun_tabungan, + 'debit' => 0, + 'kredit' => $bayar_tabungan + ]); + $total_kredit += $bayar_tabungan; + $jurnal_kredit[] = [ + 'account_id' => $akun_tabungan, + 'kredit' => $bayar_tabungan, + 'jenis' => 'tabungan' + ]; + } + + // ========================= + // PENGAKUAN PENDAPATAN & HPP + // ========================= + $sisa_pengakuan = $bayar_cicilan + $bayar_other + $bayar_barang; + $account_recognition = []; + $total_hpp = 0; + + foreach ($inv_detail_items as $i) { + if ($sisa_pengakuan <= 0) break; + + $belum_diakui = (float)$i->subtotal - (float)$i->recognized_amount; + if ($belum_diakui <= 0) continue; + + $nominal = min($sisa_pengakuan, $belum_diakui); + + if (!isset($account_recognition[$i->account_id])) { + $account_recognition[$i->account_id] = 0; + } + $account_recognition[$i->account_id] += $nominal; + + // Update recognized amount + $this->db->query(" + UPDATE invoice_details + SET recognized_amount = recognized_amount + ? + WHERE id = ? + ", [$nominal, $i->id]); + + if ($i->account_id == $akun_barang ) { + + $persentase = $nominal / (float)$i->subtotal; + $hpp_item = (float)$i->total_hpp_barang * $persentase; + $hpp_item = round($hpp_item, 2); + + $sisa_hpp = max(0, (float)$i->total_hpp_barang - (float)$i->recognized_hpp); + $hpp_item = min($hpp_item, $sisa_hpp); + + if ($hpp_item > 0) { + // Cara 1: Pakai update() method + $this->db->where('id', $i->id); + $this->db->update('invoice_details', [ + 'recognized_hpp' => $i->recognized_hpp + $hpp_item + ]); + + $total_hpp += $hpp_item; + } + } + + $sisa_pengakuan -= $nominal; + } + + // ========================= + // ALOKASI SISA KE AKUN LAIN + // ========================= + $total_diaku = array_sum($account_recognition); + $sisa_yg_harus_diaku = $bayar_cicilan + $bayar_other + $bayar_barang; + $selisih_alokasi = $sisa_yg_harus_diaku - $total_diaku; + + if ($selisih_alokasi > 0) { + $akun_other_list = $this->db + ->select('account_id, SUM(subtotal) as total') + ->from('invoice_details') + ->where('invoice_id', $invoice_id) + ->where_not_in('account_id', [$akun_tabungan, $akun_barang]) + ->group_by('account_id') + ->get() + ->result(); + + foreach ($akun_other_list as $ao) { + if ($selisih_alokasi <= 0) break; + + $belum_diaku_akun = (float)$ao->total; + $alokasi = min($selisih_alokasi, $belum_diaku_akun); + + if (!isset($account_recognition[$ao->account_id])) { + $account_recognition[$ao->account_id] = 0; + } + $account_recognition[$ao->account_id] += $alokasi; + + $selisih_alokasi -= $alokasi; + } + } + + // ========================= + // Insert DEBIT pendapatan + // ========================= + if ($debit_pendapatan_ditahan > 0) { + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $akun_pendapatan_ditahan, + 'debit' => $debit_pendapatan_ditahan, + 'kredit' => 0 + ]); + + $total_debit += $debit_pendapatan_ditahan; + $jurnal_debit[] = [ + 'account_id' => $akun_pendapatan_ditahan, + 'debit' => $debit_pendapatan_ditahan, + 'jenis' => 'pendapatan_ditahan' + ]; + } + + // ========================= + // Insert KREDIT pendapatan + // ========================= + foreach ($account_recognition as $account_id => $nominal) { + if ($nominal <= 0) continue; + + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $account_id, + 'debit' => 0, + 'kredit' => $nominal + ]); + + $total_kredit += $nominal; + $jurnal_kredit[] = [ + 'account_id' => $account_id, + 'kredit' => $nominal, + 'jenis' => 'pendapatan' + ]; + } + + // ========================= + // JURNAL HPP + // ========================= + if ($total_hpp > 0) { + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $akun_hpp, + 'debit' => $total_hpp, + 'kredit' => 0 + ]); + $total_debit += $total_hpp; + + $jurnal_debit[] = [ + 'account_id' => $akun_hpp, + 'debit' => $total_hpp, + 'jenis' => 'hpp_barang' + ]; + + $this->db->insert('journal_details', [ + 'journal_id' => $journal_id, + 'account_id' => $persediaan_dijual, + 'debit' => 0, + 'kredit' => $total_hpp + ]); + $total_kredit += $total_hpp; + + + $jurnal_kredit[] = [ + 'account_id' => $persediaan_dijual, + 'kredit' => $total_hpp, + 'jenis' => 'persediaan_dijual' + ]; + } + + // ========================= + // VALIDASI JURNAL + // ========================= + if (round($total_debit, 2) !== round($total_kredit, 2)) { + $this->db->trans_rollback(); + + echo json_encode([ + 'status' => false, + 'message' => 'Jurnal tidak balance!' + ]); + return; + } + + // ========================= + // INSERT PAYMENTS + // ========================= + $this->db->insert('payments', [ + 'invoice_id' => $invoice_id, + 'tanggal' => $tanggal_bayar, + 'jumlah' => $total_bayar_input, + 'metode' => 'manual', + 'journal_id'=> $journal_id + ]); + + // ========================= + // UPDATE STATUS INVOICE + // ========================= + if ($new_total_bayar >= $total_invoice) { + $status = 'paid'; + $sisa_setelah = 0; + } elseif ($new_total_bayar > 0) { + $status = 'partial'; + } else { + $status = 'unpaid'; + } + + $this->db->where('id', $invoice_id)->update('invoices', [ + 'total_bayar' => $new_total_bayar, + 'sisa_piutang' => $sisa_setelah, + 'status' => $status, + 'updated_at' => date('Y-m-d H:i:s'), + 'updated_by' => $this->session->userdata('user_id') + ]); + + // ========================= + // SELESAIKAN TRANSAKSI + // ========================= + $this->db->trans_complete(); + + // ========================= + // RESPONSE + // ========================= + if (!$this->db->trans_status()) { + echo json_encode([ + 'status' => false, + 'message' => 'Gagal menyelesaikan pembayaran' + ]); + return; + } + + // Logging + log_activity( + 'invoice', + 'create', + 'Pembayaran invoice ' . $invoice->no_invoice . ' - ' . $customer->nama, + 'success' + ); + + echo json_encode([ + 'status' => true, + 'message' => 'Pembayaran berhasil' + ]); +} + + } \ No newline at end of file