Files
accounting_dev/application/views/invoices/detail.php
T
2026-07-24 00:01:55 +07:00

1213 lines
42 KiB
PHP

<div class="container mt-4 mb-4">
<div class="card modern-card shadow-sm border-0 rounded-4">
<div class="card-body p-4">
<div class="d-flex justify-content-between mb-3">
<h5>Detail Invoice</h5>
<div>
<a href="<?= base_url('invoices/')?>" class="btn btn-secondary" id="btn-back">Kembali</a>
<button class="btn btn-danger btn-pdf" id="generate_pdf">Generate PDF</button>
<button class="btn btn-warning btn-cicilan" id="get_cicilan">Ambil Cicilan</button>
</div>
</div>
<div id="customerInfo"></div>
<div class="table-responsive">
<table class="table modern-table align-middle w-100" id="tableDetail">
<thead class="table-light">
<tr>
<th>To Account</th>
<th>No</th>
<th>Tanggal</th>
<th>Item</th>
<th>Qty</th>
<th>Harga</th>
<th>Subtotal</th>
<th>Keterangan</th>
<th>Aksi</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="d-flex justify-content-between mt-3">
<div id="btn-add-items"></div>
<div class="mb-2 mr-4">
<table class="table table-borderless table-sm mb-0 w-auto" style="zoom: 110%;">
<!-- <tr>
<td class="pe-3 text-muted">Total Tagihan</td>
<td class="pe-2">:</td>
<td><strong id="grandTotal">0</strong></td>
</tr> -->
<tbody id="grandTotal"></tbody>
<tbody id="othergrandTotal"></tbody>
</table>
</div>
</div>
</div>
</div>
<div id="riwayatPembayaran"></div>
</div>
<!--MODAL GET CICILAN-->
<div class="modal fade" id="modalCicilan" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<!-- HEADER -->
<div class="modal-header bg-warning text-white">
<h5 class="modal-title">List Cicilan</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- BODY -->
<div class="modal-body">
<div id="cicilanContainer">
<div class="text-center text-muted">
Memuat data...
</div>
</div>
</div>
<!-- FOOTER -->
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">
Tutup
</button>
<button class="btn btn-primary" id="save_cicilan">
Pilih Cicilan
</button>
</div>
</div>
</div>
</div>
<!-- MODAL (TIDAK DIUBAH STYLE) -->
<div class="modal fade" id="modalItem">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header bg-warning text-white">
<h5 class="modal-title" id="modalTitle">Item Invoice</h5>
<button class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="item_id">
<div class="mb-2">
<label for="account_id" class="form-label">Tujuan Neraca (Account)</label>
<select id="account_id" class="form-control">
<option value="">Loading...</option>
</select>
</div>
<div class="mb-2" id="wrap_nama_item">
<label for="nama_item" class="form-label">Nama Item</label>
<input type="text" id="nama_item" class="form-control" placeholder="Nama Item">
</div>
<div class="mb-2 d-none" id="wrap_warehouse">
<label for="warehouse_id" class="form-label">Gudang</label>
<select id="warehouse_id" class="form-control"></select>
</div>
<div class="mb-2 d-none" id="wrap_item_select">
<label for="item_select" class="form-label">Item dari Gudang</label>
<select id="item_select" class="form-control select-search"></select>
</div>
<div class="mb-2 d-none" id="wrap_barcode_select">
<label for="barcode_select" class="form-label">Barcode / QR ID</label>
<select id="barcode_select" class="form-control select-search"></select>
</div>
<div id="stokSisaQty"></div>
<div class="mb-2" id="wrap_qty_item">
<label for="qty" class="form-label">Qty</label>
<input type="number" id="qty" class="form-control" min="0">
</div>
<div class="mb-2">
<label for="harga" class="form-label">Harga</label>
<input type="text" id="harga" class="form-control format-rupiah" min="0">
</div>
<!-- CICILAN -->
<div class="mb-3 mt-3" id="is_cicilan_group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="is_cicilan">
<label class="form-check-label fw-semibold" for="is_cicilan">
Pembayaran Cicilan
</label>
</div>
</div>
<div id="wrap_cicilan" class="border rounded-3 p-3 bg-light d-none">
<div class="mb-2">
<label class="form-label">Tenor (Jumlah Cicilan)</label>
<input type="number" id="tenor" class="form-control" min="1" placeholder="Contoh: 3">
</div>
<div class="small text-muted">
Sistem akan otomatis membagi total harga menjadi beberapa cicilan.
</div>
</div>
<div class="mb-2">
<label for="tanggal_input" class="form-label">Tanggal</label>
<input type="date" id="tanggal_input" class="form-control">
</div>
<div class="mb-2">
<label for="keterangan" class="form-label">Keterangan</label>
<textarea class="form-control" id="keterangan" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button class="btn btn-warning" id="btnSimpanItem">Simpan</button>
</div>
</div></div></div>
<script>
$(function(){
let invoice_id = "<?= $invoice_id ?>";
let action = "add";
let edit_id = null;
let isEditing = false;
let editData = null;
let modal = new bootstrap.Modal(document.getElementById('modalItem'));
// ================= FORMAT =================
function formatNumber(num){
return new Intl.NumberFormat('id-ID').format(num || 0);
}
// ================= FORMAT TANGGAL (BARU) =================
function formatTglIndo(tgl){
if(!tgl) return '-';
let date = new Date(tgl);
let day = String(date.getDate()).padStart(2, '0');
let month = String(date.getMonth() + 1).padStart(2, '0');
let year = date.getFullYear();
return `${day}/${month}/${year}`;
}
// ================= VALIDASI FORM =================
function validateForm(){
let errors = [];
if(!$('#tanggal_input').val()) errors.push('Tanggal wajib diisi');
if(!$('#account_id').val()) errors.push('Account wajib dipilih');
if(!$('#nama_item').val() && !$('#item_select').val()) errors.push('Nama item wajib diisi');
if(!$('#qty').val() || $('#qty').val() <= 0) errors.push('Qty harus lebih dari 0');
if(!$('#harga').val() || $('#harga').val() <= 0) errors.push('Harga harus lebih dari 0');
if($('#is_cicilan').is(':checked')){
let tenor = parseInt($('#tenor').val());
if(!tenor || tenor <= 0){
errors.push('Tenor cicilan wajib diisi');
}
}
if(errors.length > 0){
Swal.fire('Error', errors.join('<br>'), 'error');
return false;
}
return true;
}
// ================= RESET UI =================
function resetForm(){
// $('#form_scan_barang').addClass('d-none');
$('#wrap_warehouse').addClass('d-none');
$('#wrap_item_select').addClass('d-none');
$('#wrap_nama_item').removeClass('d-none');
$('#wrap_qty_item').removeClass('d-none');
$('#wrap_barcode_select').addClass('d-none');
$('#warehouse_id').html('<option value="">Pilih Gudang</option>');
$('#item_select').html('<option value="">Pilih Item</option>');
$('#nama_item').val('').show();
$('#tanggal_input').val('');
$('#qty').val('');
$('#harga').val('');
$('#keterangan').val('');
$('#barcode_select').val('');
$('#is_cicilan').prop('checked', false);
$('#wrap_cicilan').addClass('d-none');
$('#tenor').val('');
$('#stokSisaQty').html('');
setMode('manual');
}
// ================= COA =================
$.get("<?= base_url('invoices/get_accounts'); ?>", function(res){
let opt = '<option value="">Pilih Akun</option>';
if(res && res.length){
res.forEach(a=>{
opt += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
});
}
$("#account_id").html(opt);
},'json').fail(function(){
$("#account_id").html('<option value="">Error loading accounts</option>');
});
// ================= ACCOUNT CHANGE =================
$('#account_id').on('change', function(){
let account_id = $(this).val();
if(!isEditing){
resetForm();
}
if(!account_id) return;
$.get("<?= base_url('invoices/check_items_by_account/'); ?>" + account_id, function(res){
if(res.has_item){
// $('#form_scan_barang').removeClass('d-none');
$('#wrap_warehouse').removeClass('d-none');
$('#wrap_nama_item').addClass('d-none');
$('#wrap_qty_item').addClass('d-none');
loadWarehouse();
setMode('warehouse');
} else {
$('#wrap_nama_item').removeClass('d-none');
$('#wrap_qty_item').removeClass('d-none');
setMode('manual');
}
}, 'json').fail(function(){
Swal.fire('Error', 'Gagal memuat data account', 'error');
});
});
// ================= WAREHOUSE =================
function loadWarehouse(){
return $.get("<?= base_url('invoices/gudang_list'); ?>", function(res){
let opt = '<option value="">Pilih Gudang</option>';
if(res && res.length){
res.forEach(w=>{
opt += `<option value="${w.id}">${w.nama}</option>`;
});
}
$('#warehouse_id').html(opt);
}, 'json');
}
$('#warehouse_id').on('change', function(){
let warehouse_id = $(this).val();
let account_id = $('#account_id').val();
$('#wrap_item_select').addClass('d-none');
$('#item_select').html('<option value="">Loading...</option>');
if(!warehouse_id){
$('#wrap_nama_item').removeClass('d-none');
$('#wrap_qty_item').removeClass('d-none');
setMode('manual');
return;
}
loadItems(account_id, warehouse_id);
});
// ================= ITEMS =================
function loadItems(account_id, warehouse_id){
return $.get("<?= base_url('invoices/get_items_by_wh_account/'); ?>" + warehouse_id + "/" + account_id, function(res){
if(res && res.length){
let opt = '<option value="">Pilih Item</option>';
res.forEach(i=>{
opt += `<option value="${i.id}"
data-harga="${i.harga_jual}"
data-stok="${i.stok}"
data-nama="${i.nama_barang}">
${i.kode_detail} - ${i.nama_barang} (Stok: ${i.stok})
</option>`;
});
$('#item_select').html(opt);
$('#wrap_item_select').removeClass('d-none');
$('#wrap_nama_item').addClass('d-none');
$('#wrap_qty_item').addClass('d-none');
setMode('item');
} else {
$('#wrap_item_select').addClass('d-none');
$('#wrap_nama_item').removeClass('d-none');
$('#wrap_qty_item').removeClass('d-none');
setMode('manual');
}
}, 'json');
}
$('#item_select').on('change', function(){
let item_id = $(this).val();
$('#wrap_barcode_select').addClass('d-none');
$('#barcode_select').html('<option value="">Loading...</option>');
if(!item_id){
$('#wrap_barcode_select').removeClass('d-none');
setMode('manual');
return;
}
// loadItemBarcodes(item_id);
loadItemBarcodes(
item_id,
isEditing ? editData.barcode_id : null
);
});
$('#barcode_select').on('change', function(){
let barcode_id = $(this).val();
let selected = $(this).find(':selected');
let qty_sisa = parseFloat(selected.data('qty_sisa')) || 0;
// console.log("QTY : " + qty_sisa);
if (qty_sisa > 1 ) {
$('#stokSisaQty').html('<h6 class="text-success ml-4">Stok : ' + qty_sisa + '</h6><hr>');
$('#qty').val('');
$('#wrap_qty_item').removeClass('d-none');
}
});
// $(document).on('keyup','#qty',function(){
// hitungTotal();
// });
// function hitungTotal(){
// let qty_sisa = 1000;
// $('#stokSisaQty').html('<h6 class="text-success ml-4">Stok : ' + qty_sisa + '</h6><hr>');
// }
// ================= LOAD BARCODE ITEMS =================
// function loadItemBarcodes(item_id){
// return $.get("<?= base_url('items/get_list_barcode_id/'); ?>" + item_id, function(res){
// if(res && res.length){
// let opt = '<option value="">Pilih Item</option>';
// res.forEach(i=>{
// opt += `<option value="${i.barcode_id}">
// ${i.nama_barang} - ${i.barcode} - ${i.serial_number}
// </option>`;
// });
// $('#barcode_select').html(opt);
// $('#wrap_barcode_select').removeClass('d-none');
// // set QTY jadi 1
// let qty = Number($('#qty').val());
// $('#qty').val(qty + 1);
// setMode('item');
// } else {
// $('#wrap_barcode_select').addClass('d-none');
// // $('#wrap_barcode_select').removeClass('d-none');
// setMode('manual');
// }
// }, 'json');
// }
function loadItemBarcodes(item_id, selectedBarcode = null){
return $.get("<?= base_url('items/get_list_barcode_id/'); ?>" + item_id, function(res){
if(res && res.length){
let opt = '<option value="">Pilih Barcode</option>';
res.forEach(i=>{
opt += `
<option value="${i.barcode_id}" data-qty_sisa="${i.qty_sisa}">
${i.nama_barang} - ${i.barcode} - ${i.serial_number}
</option>
`;
});
$('#barcode_select').html(opt);
if(selectedBarcode){
$('#barcode_select').val(selectedBarcode);
}
$('#wrap_barcode_select').removeClass('d-none');
if(!isEditing){
$('#qty').val(1);
}
setMode('item');
}else{
$('#wrap_barcode_select').addClass('d-none');
setMode('manual');
}
},'json');
}
// ================= AUTO HARGA =================
$('#item_select').on('change', function(){
let selected = $(this).find(':selected');
let harga = parseFloat(selected.data('harga')) || 0;
$('#harga').val(harga);
});
// ================= STOK CHECK =================
$('#qty').on('input', function(){
let qty = parseFloat($(this).val()) || 0;
let selected = $('#barcode_select option:selected');
let stok = selected.length ? parseFloat(selected.data('qty_sisa')) || 0 : 0;
if(stok > 0 && qty > stok){
Swal.fire('Warning','Stok tidak cukup! Max: ' + stok,'warning');
$(this).val(stok);
}
});
let invoiceData = null;
// ================= LOAD INVOICE =================
function loadInvoice(){
$.get("<?= base_url('invoices/get_invoice/'); ?>"+invoice_id,function(data){
if(!data) return;
invoiceData = data;
let backUrl = "<?= base_url('invoices') ?>";
if(data.status === 'draft'){
backUrl = "<?= base_url('invoices/draft') ?>";
$("#btn-add-items").html(`<button class="btn btn-warning btn-add">Tambah Item</button>`);
} else if(data.status === 'unpaid'){
backUrl = "<?= base_url('invoices/draft') ?>";
loadRiwayatPembayaran();
} else if(data.status === 'partial'){
backUrl = "<?= base_url('invoices/draft') ?>";
loadRiwayatPembayaran();
} else if(data.status === 'paid'){
backUrl = "<?= base_url('invoices/paid') ?>";
loadRiwayatPembayaran();
}
$('#btn-back').attr('href', backUrl);
$("#customerInfo").html(`
<hr>
<div class="px-2">
<h3 class="mt-2 fw-bold text-end">
<span class="${getStatusClass(data.status)}">
${(data.status || '').toUpperCase()}
</span>
</h3>
<div class="row">
<!-- CUSTOMER INFO -->
<div class="col-md-9">
<div class="p-2">
<div class="font-weight-bold mb-1" style="font-size:16px;">
${data.nama || '-'}
</div>
<div class="text-muted small" style="font-size:13px;">
<div>${data.telp || '-'}</div>
<div>${data.alamat || '-'}</div>
</div>
</div>
</div>
<!-- INVOICE INFO -->
<div class="col-md-3 text-end">
<div class="p-2">
<table class="w-100" style="font-size:13px; line-height:1.6;">
<tr>
<td class="text-muted">Tanggal :</td>
<td class="text-right font-weight-bold text-dark">
${formatTglIndo(data.tanggal)}
</td>
</tr>
<tr>
<td class="text-muted">Due Date :</td>
<td class="text-right font-weight-bold text-dark">
${formatTglIndo(data.jatuh_tempo)}
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
`);
renderTotal(data.total);
},'json');
}
function getStatusClass(status){
const classes = {
'draft': 'text-secondary',
'unpaid': 'text-warning',
'paid': 'text-success',
'partial': 'text-primary'
};
return classes[status] || 'text-dark';
}
// ================= TABLE =================
function loadInvoiceItems(){
$.get("<?= base_url('invoices/get_items/'); ?>" + invoice_id, function(data){
let html = '';
let total = 0;
let no = 1;
if(!data || data.length === 0){
$("#tableDetail tbody").html(`
<tr>
<td colspan="9" class="text-center py-4 text-muted">Tidak ada data item</td>
</tr>
`);
$("#grandTotal").text('0');
return;
}
data.forEach(v => {
let subtotal = parseFloat(v.subtotal) || 0;
total += subtotal;
let btnAction = '';
if(v.status == 'draft'){
btnAction = `
<button class="btn btn-sm btn-danger btn-delete" data-id="${v.id}">
Hapus
</button>
`;
}
html += `
<tr>
<td>
<small class="text-secondary">${v.kode_akun || ''} - ${v.nama_akun || ''}</small>
<br><small class="text-warning"><small>Created at : </small>${v.created_at || ''}</small>
</td>
<td>${no++}</td>
<td>${formatTglIndo(v.tanggal)}</td>
<td>${v.nama_item || '-'}<br><small class="text-secondary"><small></small><i>${v.barcode || ''}</i></small></td>
<td>${v.qty || 0}</td>
<td>${formatNumber(v.harga)}</td>
<td>${formatNumber(subtotal)}</td>
<td style="max-width: 150px">${v.keterangan || '-'}</td>
<td>${btnAction}</td>
</tr>
`;
});
$("#tableDetail tbody").html(html);
renderTotal(total);
},'json').fail(function(){
$("#tableDetail tbody").html('<tr><td colspan="9" class="text-center text-danger">Error loading items</td></tr>');
});
}
function renderTotal(subtotal){
let tunggakan = invoiceData ? (invoiceData.tunggakan || 0) : 0;
$("#grandTotal").html(`
<tr>
<td class="pe-3 text-muted text-end">Subtotal</td>
<td class="pe-2">:</td>
<td><strong class="text-success">${formatNumber(subtotal)}</strong></td>
</tr>
<tr>
<td class="pe-3 text-muted text-end">Akumulasi Tunggakan Invoice Bulan Lalu</td>
<td class="pe-2">:</td>
<td><strong class="text-danger">${formatNumber(tunggakan)}</strong></td>
</tr>
<tr>
<td class="pe-3 text-muted text-end">Total Tagihan</td>
<td class="pe-2">:</td>
<td><strong class="text-dark">${formatNumber((parseFloat(subtotal) || 0) + (parseFloat(tunggakan) || 0))}</strong></td>
</tr>
`);
}
// ================= ADD BUTTON =================
$(document).on('click', '.btn-add', function () {
action = "add";
edit_id = null;
isEditing = false;
editData = null;
$('#modalTitle').text('Tambah Item');
$('#account_id').val('');
resetForm();
modal.show();
});
// ================= SAVE =================
// ================= SAVE - FIXED SESUAI STYLE ANDA =================
$('#btnSimpanItem').on('click', function(){
if(!validateForm()) return;
let url = (action === 'add')
? "<?= base_url('invoices/add_item'); ?>"
: "<?= base_url('invoices/update_item'); ?>";
let selected = $('#item_select option:selected');
let nama_item = $('#nama_item').val().trim();
let item_id = selected.val() || '';
if(selected.length && selected.val()){
nama_item = selected.data('nama') || nama_item;
}
let warehouse_id = $('#warehouse_id').val() || '';
let data = {
invoice_id: invoice_id,
tanggal: $('#tanggal_input').val(), // ✅ FIXED
account_id: $('#account_id').val(),
warehouse_id: warehouse_id || null,
nama_item: nama_item,
item_id: item_id || null,
qty: parseFloat($('#qty').val()) || 0,
harga: parseFloat($('#harga').val()) || 0,
keterangan: $('#keterangan').val().trim(),
barcode_id: $('#barcode_select').val() || 0,
is_cicilan: $('#is_cicilan').is(':checked') ? 1 : 0,
tenor: parseInt($('#tenor').val()) || 0,
};
if(action === 'edit'){
data.id = edit_id;
}
let btn = $(this);
btn.prop('disabled', true).html('Menyimpan...');
$.post({
url: url,
data: data,
dataType: 'json' // ✅ FIXED
})
.done(function(res){
if(res.status === true || res.status === 1){
modal.hide();
loadInvoice();
loadInvoiceItems();
Swal.fire('Success', res.message || 'Data berhasil disimpan!', 'success');
} else {
Swal.fire('Error', res.message || 'Gagal menyimpan data', 'error');
}
})
.fail(function(){
Swal.fire('Error', 'Terjadi kesalahan koneksi', 'error');
})
.always(function(){
btn.prop('disabled', false).html('Simpan');
});
});
// ================= DELETE =================
$(document).on('click','.btn-delete', function(){
let id = $(this).data('id');
let btn = $(this);
Swal.fire({
title:'Hapus?',
text: "Data akan dihapus permanen!",
icon:'warning',
showCancelButton:true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if(result.isConfirmed){
btn.prop('disabled', true).html('Menghapus...');
$.get({
url: "<?= base_url('invoices/delete_item/'); ?>" + id + "/" + `<?= $no_invoice ?>`,
dataType: 'json' // ✅ FIXED
})
.done(function(res){
if(res.status === true || res.status === 1){
loadInvoice();
loadInvoiceItems();
Swal.fire('Success', res.message || 'Item berhasil dihapus', 'success');
} else {
Swal.fire('Error', res.message || 'Gagal menghapus', 'error');
}
})
.fail(function(){
Swal.fire('Error', 'Terjadi kesalahan koneksi', 'error');
})
.always(function(){
btn.prop('disabled', false).html('Hapus');
});
}
});
});
// ================= MODE =================
function setMode(type){
let $label = $('#item_mode_label')
.removeClass('alert-secondary alert-info alert-success alert-warning');
switch(type){
case 'manual':
$label.addClass('alert-secondary').text('Mode: Manual Input');
break;
case 'warehouse':
$label.addClass('alert-info').text('Mode: Pilih Gudang');
break;
case 'item':
$label.addClass('alert-success').text('Mode: Item dari Gudang');
break;
}
}
// ================= MODAL EVENTS =================
$('#modalItem').on('hidden.bs.modal', function(){
if(!isEditing){
resetForm();
}
action = "add";
edit_id = null;
isEditing = false;
editData = null;
});
// =========================
// SAVE CICILAN (POST)
// =========================
$(document).on('click', '#save_cicilan', function(){
let selected = [];
$('#modalCicilan input[type=radio]:checked').each(function(){
selected.push($(this).val());
});
if (selected.length === 0) {
Swal.fire('Warning', 'Pilih minimal 1 cicilan!', 'warning');
return;
}
Swal.fire({
title: 'Konfirmasi',
text: 'Simpan cicilan yang dipilih?',
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Ya, Simpan',
cancelButtonText: 'Batal'
}).then((result) => {
if (!result.isConfirmed) return;
$.ajax({
url: "<?= base_url('invoices/save_cicilan'); ?>",
type: "POST",
data: {
cicilan_id: selected,
customer_id: "<?= $customer_id ?>",
invoice_id: "<?= $invoice_id ?>"
},
dataType: "json",
beforeSend: function(){
$('#save_cicilan').prop('disabled', true).text('Menyimpan...');
Swal.fire({
title: 'Menyimpan...',
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
}
});
},
success: function(res){
if (res.status) {
Swal.fire('Berhasil', 'Cicilan berhasil disimpan', 'success');
$('#modalCicilan').modal('hide');
loadInvoice();
loadInvoiceItems();
} else {
Swal.fire('Gagal', res.message || 'Gagal menyimpan', 'error');
}
},
error: function(){
Swal.fire('Error', 'Terjadi kesalahan server', 'error');
},
complete: function(){
$('#save_cicilan').prop('disabled', false).text('Pilih Cicilan');
}
});
});
});
// ================= INIT =================
loadInvoice();
loadInvoiceItems();
// Prevent double submit
$(document).on('submit', 'form', function(e){
e.preventDefault();
});
// ================= GENERATE PDF =================
$('#generate_pdf').on('click', function(){
let btn = $(this);
btn.prop('disabled', true).html('Generating...');
$.ajax({
url: "<?= base_url('generateinvoice/generate/'.$invoice_id); ?>",
type: "GET",
xhrFields: {
responseType: 'blob' // 🔥 penting untuk PDF
},
success: function(response){
let blob = new Blob([response], { type: 'application/pdf' });
let url = window.URL.createObjectURL(blob);
// buka di tab baru
window.open(url, '_blank');
},
error: function(){
Swal.fire('Error', 'Gagal generate PDF', 'error');
},
complete: function(){
btn.prop('disabled', false).html('Generate PDF');
}
});
});
function loadRiwayatPembayaran(){
$.ajax({
url: "<?= base_url('invoices/get_payment/'); ?>" + invoice_id,
type: "GET",
dataType: "json",
success: function(res){
let totalBayar = res.invoice?.total_bayar || 0;
let sisa = res.invoice?.sisa_piutang || 0;
let html = `
<div class="card modern-card shadow-sm border-0 rounded-4 mt-4">
<div class="card-body p-4">
<!-- HEADER -->
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0 fw-semibold">Riwayat Pembayaran</h5>
<span class="badge bg-light text-dark">
${res.data.length} transaksi
</span>
</div>
`;
if(res.data.length === 0){
html += `
<div class="text-center text-muted py-4">
<i class="bi bi-receipt" style="font-size: 26px;"></i>
<div class="mt-2">Belum ada pembayaran</div>
</div>
`;
} else {
html += `<div class="position-relative ps-3">`;
res.data.forEach(function(row, i){
html += `
<div class="mb-3 position-relative">
<!-- DOT -->
<div style="
position:absolute;
left:-8px;
top:6px;
width:10px;
height:10px;
background:#198754;
border-radius:50%;
"></div>
<div class="p-3 border rounded-3 bg-white shadow-sm d-flex justify-content-between align-items-center">
<!-- LEFT -->
<div>
<div class="fw-semibold">
${row.tanggal}
</div>
<small class="text-muted">
${row.created_at}
</small>
</div>
<!-- RIGHT -->
<div class="text-end">
<div class="fw-bold text-success fs-6">
+ ${row.jumlah}
</div>
</div>
</div>
</div>
`;
});
html += `</div>`;
}
// ================= SUMMARY =================
html += `
<hr class="my-4">
<div class="d-flex flex-column gap-2">
<div class="p-3 rounded-3 bg-light d-flex justify-content-between align-items-center">
<span class="text-muted">Total Pembayaran</span>
<span class="fw-bold text-success fs-5">
Rp ${formatNumber(totalBayar)}
</span>
</div>
<div class="p-3 rounded-3 d-flex justify-content-between align-items-center"
style="background: ${sisa > 0 ? '#fff5f5' : '#f0fff4'};">
<span class="text-muted">Sisa Tagihan</span>
<span class="fw-bold ${sisa > 0 ? 'text-danger' : 'text-success'} fs-5">
Rp ${formatNumber(sisa)}
</span>
</div>
</div>
`;
html += `
</div>
</div>
`;
$('#riwayatPembayaran').html(html);
},
error:function(){
$('#riwayatPembayaran').html(`
<div class="text-danger text-center mt-3">
Gagal load data
</div>
`);
}
});
}
});
// ================= CICILAN TOGGLE =================
$('#is_cicilan').on('change', function(){
if(this.checked){
$('#wrap_cicilan').removeClass('d-none');
} else {
$('#wrap_cicilan').addClass('d-none');
$('#tenor').val('');
}
});
// =========================
// GET CICILAN
// =========================
$(document).on('click', '#get_cicilan', function() {
let url = "<?= base_url('invoices/get_cicilan/'.$customer_id); ?>";
$('#cicilanContainer').html('<div class="text-center">Loading...</div>');
$.get(url, function(res){
let data;
try {
data = typeof res === 'object' ? res : JSON.parse(res);
} catch (e) {
Swal.fire('Error', 'Format response salah', 'error');
return;
}
if (!data || data.length === 0) {
Swal.fire('Info', 'Tidak ada cicilan tersedia', 'info');
return;
}
let grouped = {};
data.forEach(item => {
if (!grouped[item.invoice_detail_id]) {
grouped[item.invoice_detail_id] = [];
}
grouped[item.invoice_detail_id].push(item);
});
let html = '';
Object.keys(grouped).forEach((key) => {
let items = grouped[key];
let total = items.reduce((sum, i) => {
return sum + (parseFloat(i.nominal) - parseFloat(i.paid_amount));
}, 0);
html += `
<div class="mb-4">
<div class="bg-light p-2 fw-bold d-flex justify-content-between">
<span>Nama Barang : ${items[0].nama_barang}</span>
<span class="text-primary">
Total: Rp ${total.toLocaleString()}
</span>
</div>
<div class="table-responsive">
<table class="table table-bordered table-sm mb-0">
<thead class="table-warning text-center">
<tr>
<th width="40">Pilih</th>
<th>Angsuran</th>
<th>Jatuh Tempo</th>
<th>Nominal</th>
<th>Dibayar</th>
<th>Sisa</th>
<th>Status</th>
</tr>
</thead>
<tbody>
`;
items.forEach((item) => {
let nominal = parseFloat(item.nominal);
let paid = parseFloat(item.paid_amount);
let sisa = nominal - paid;
html += `
<tr class="cicilan-row" data-id="${item.id}" data-group="${key}">
<td class="text-center">
<input
type="radio"
name="cicilan_group_${key}"
value="${item.id}"
id="radio_${item.id}"
>
</td>
<td class="text-center">
${item.angsuran_ke} / ${item.total_angsuran}
</td>
<td>${item.jatuh_tempo}</td>
<td class="text-end">
Rp ${nominal.toLocaleString()}
</td>
<td class="text-end">
Rp ${paid.toLocaleString()}
</td>
<td class="text-end text-success">
Rp ${sisa.toLocaleString()}
</td>
<td class="text-center">
<span class="badge bg-${item.status === 'unpaid' ? 'danger' : 'warning'}">
${item.status}
</span>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
</div>
`;
});
$('#cicilanContainer').html(html);
$('#modalCicilan').modal('show');
}).fail(function(){
Swal.fire('Error', 'Gagal ambil data', 'error');
});
});
// =========================
// CLICK ROW (PILIH RADIO + HIGHLIGHT)
// =========================
$(document).on('click', '.cicilan-row', function(){
let id = $(this).data('id');
let group = $(this).data('group');
$(`input[name="cicilan_group_${group}"]`).prop('checked', false);
$(`#radio_${id}`).prop('checked', true);
$(`tr[data-group="${group}"]`).removeClass('table-secondary');
$(this).addClass('table-secondary');
});
</script>