Update account Invoice
update invoice agar tidak langsung di akui sebagai pendapatan dan di akui nya saat invoice di bayar
This commit is contained in:
@@ -3,6 +3,18 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
|||||||
|
|
||||||
class Invoices extends CI_Controller {
|
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()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@@ -405,297 +417,6 @@ class Invoices extends CI_Controller {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// DELETE
|
||||||
// =========================
|
// =========================
|
||||||
@@ -818,13 +539,6 @@ class Invoices extends CI_Controller {
|
|||||||
echo json_encode($data);
|
echo json_encode($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================
|
|
||||||
// 🔥 CONFIG AKUN
|
|
||||||
// =========================
|
|
||||||
private $akun_persediaan = 21;
|
|
||||||
private $akun_hpp = 63;
|
|
||||||
private $akun_piutang = 19;
|
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// ADD ITEM - FIXED RESPONSE
|
// ADD ITEM - FIXED RESPONSE
|
||||||
// =========================
|
// =========================
|
||||||
@@ -909,7 +623,8 @@ class Invoices extends CI_Controller {
|
|||||||
'warehouse_id' => $warehouse_id,
|
'warehouse_id' => $warehouse_id,
|
||||||
'keterangan' => $this->input->post('keterangan'),
|
'keterangan' => $this->input->post('keterangan'),
|
||||||
'subtotal_asli' => $harga_asli,
|
'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);
|
$this->db->insert('invoice_details', $insert_data);
|
||||||
@@ -921,6 +636,7 @@ class Invoices extends CI_Controller {
|
|||||||
if($this->input->post('account_id') != 70) {
|
if($this->input->post('account_id') != 70) {
|
||||||
$this->generate_jurnal_item($detail_id, $ket_cicilan_jr);
|
$this->generate_jurnal_item($detail_id, $ket_cicilan_jr);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->update_total($invoice_id);
|
$this->update_total($invoice_id);
|
||||||
|
|
||||||
// ambil customer dari invoice
|
// ambil customer dari invoice
|
||||||
@@ -995,12 +711,15 @@ class Invoices extends CI_Controller {
|
|||||||
$nama_item = $this->input->post('nama_item');
|
$nama_item = $this->input->post('nama_item');
|
||||||
$tanggal = $this->input->post('tanggal');
|
$tanggal = $this->input->post('tanggal');
|
||||||
|
|
||||||
|
$total_hpp = 0;
|
||||||
|
|
||||||
if($item_id){
|
if($item_id){
|
||||||
$item = $this->db->get_where('items', ['id'=>$item_id])->row();
|
$item = $this->db->get_where('items', ['id'=>$item_id])->row();
|
||||||
if($item){
|
if($item){
|
||||||
$nama_item = $item->nama_barang;
|
$nama_item = $item->nama_barang;
|
||||||
$stok = $this->get_stok($item_id);
|
$stok = $this->get_stok($item_id);
|
||||||
$qty = (float)$this->input->post('qty');
|
$qty = (float)$this->input->post('qty');
|
||||||
|
$total_hpp = $this->input->post('qty') * $item->harga_beli;
|
||||||
if($stok < $qty){
|
if($stok < $qty){
|
||||||
echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup']);
|
echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup']);
|
||||||
return;
|
return;
|
||||||
@@ -1021,7 +740,8 @@ class Invoices extends CI_Controller {
|
|||||||
'harga' => $harga,
|
'harga' => $harga,
|
||||||
'subtotal' => $qty * $harga,
|
'subtotal' => $qty * $harga,
|
||||||
'warehouse_id' => $this->input->post('warehouse_id'),
|
'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);
|
$this->db->where('id', $id)->update('invoice_details', $update_data);
|
||||||
@@ -1112,60 +832,6 @@ class Invoices extends CI_Controller {
|
|||||||
echo json_encode($cicilan_raw);
|
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)
|
private function generate_jurnal_item($id, $ket_cicilan_jr = null)
|
||||||
{
|
{
|
||||||
// $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
|
// $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', [
|
$this->db->insert('journal_details', [
|
||||||
'journal_id' => $jid,
|
'journal_id' => $jid,
|
||||||
'account_id' => $d->account_id,
|
'account_id' => $this->pendapatan_dimuka,
|
||||||
'debit' => 0,
|
'debit' => 0,
|
||||||
'kredit' => $nilai_jurnal
|
'kredit' => $nilai_jurnal
|
||||||
]);
|
]);
|
||||||
@@ -1271,7 +937,7 @@ class Invoices extends CI_Controller {
|
|||||||
// HPP (debit)
|
// HPP (debit)
|
||||||
$this->db->insert('journal_details', [
|
$this->db->insert('journal_details', [
|
||||||
'journal_id' => $jid,
|
'journal_id' => $jid,
|
||||||
'account_id' => $this->akun_hpp,
|
'account_id' => $this->persediaan_dijual,
|
||||||
'debit' => $total_hpp,
|
'debit' => $total_hpp,
|
||||||
'kredit' => 0
|
'kredit' => 0
|
||||||
]);
|
]);
|
||||||
@@ -1689,4 +1355,495 @@ class Invoices extends CI_Controller {
|
|||||||
'status' => $this->db->trans_status()
|
'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'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user