Initial commit
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
<div class="container mt-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 class="mb-0">Chart of Account (COA)</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Akun</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableAccounts" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Tipe</th>
|
||||
<th>Posisi</th>
|
||||
<th>Kategori</th>
|
||||
<th width="15%">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalAccount">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Tambah Akun</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<label class="fw-semibold">Kode Akun</label>
|
||||
<input type="text" class="form-control" id="kode_akun">
|
||||
|
||||
<label class="fw-semibold mt-2">Nama Akun</label>
|
||||
<input type="text" class="form-control" id="nama_akun">
|
||||
|
||||
<label class="fw-semibold mt-2">Tipe</label>
|
||||
<select class="form-control" id="tipe">
|
||||
<option value="asset">Asset</option>
|
||||
<option value="liability">Liability</option>
|
||||
<option value="equity">Equity</option>
|
||||
<option value="revenue">Revenue</option>
|
||||
<option value="expense">Expense</option>
|
||||
</select>
|
||||
|
||||
<label class="fw-semibold mt-2">Parent</label>
|
||||
<select class="form-control" id="parent_id">
|
||||
<option value="">-- Tanpa Parent --</option>
|
||||
<?php foreach($parent_accounts as $p): ?>
|
||||
<option value="<?= $p->id ?>">
|
||||
<?= $p->kode_akun ?> - <?= $p->nama_akun ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableAccounts').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: true,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('accounts/get_data'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable:false },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4 },
|
||||
{ data: 5 },
|
||||
{ data: 6, orderable:false }
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="text-center"><div class="spinner-border text-warning"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
// ================= RESET FORM
|
||||
function resetForm(){
|
||||
$('#inputId').val('');
|
||||
$('#kode_akun').val('');
|
||||
$('#nama_akun').val('');
|
||||
$('#tipe').val('asset');
|
||||
$('#parent_id').val('');
|
||||
$('#modalAccount .modal-title').text('Tambah Akun');
|
||||
}
|
||||
|
||||
// ================= OPEN MODAL
|
||||
$('.btn-add').click(function(){
|
||||
resetForm();
|
||||
$('#btnSimpan').data('action','add');
|
||||
$('#modalAccount').modal('show');
|
||||
});
|
||||
|
||||
// ================= SAVE / UPDATE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let data = {
|
||||
id: $('#inputId').val(),
|
||||
kode_akun: $('#kode_akun').val().trim(),
|
||||
nama_akun: $('#nama_akun').val().trim(),
|
||||
tipe: $('#tipe').val(),
|
||||
parent_id: $('#parent_id').val()
|
||||
};
|
||||
|
||||
if(!data.kode_akun || !data.nama_akun){
|
||||
Swal.fire('Warning','Kode & Nama wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('accounts/save'); ?>"
|
||||
: "<?= base_url('accounts/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
$('#modalAccount').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Error', res.message, 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Terjadi kesalahan server','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ================= EDIT
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('accounts/detail/'); ?>" + id, function(res){
|
||||
|
||||
$('#inputId').val(res.id);
|
||||
$('#kode_akun').val(res.kode_akun);
|
||||
$('#nama_akun').val(res.nama_akun);
|
||||
$('#tipe').val(res.tipe);
|
||||
$('#parent_id').val(res.parent_id);
|
||||
|
||||
$('#modalAccount .modal-title').text('Edit Akun');
|
||||
$('#btnSimpan').data('action','edit');
|
||||
|
||||
$('#modalAccount').modal('show');
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// ================= DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title: 'Yakin hapus?',
|
||||
text: 'Data tidak bisa dikembalikan!',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus'
|
||||
}).then((result)=>{
|
||||
if(result.isConfirmed){
|
||||
|
||||
$.get("<?= base_url('accounts/delete/'); ?>" + id, function(res){
|
||||
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Error', res.message, 'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,527 @@
|
||||
<div class="container mt-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>Data Asset</h5>
|
||||
<div class="text-end">
|
||||
<button class="btn btn-add bg-success btn-from-stock mr-2">Dari Gudang</button>
|
||||
<button class="btn btn-add bg-warning btn-add-asset">Tambah Asset</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableAsset" class="table modern-table w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Lokasi Asset</th>
|
||||
<th>Nilai</th>
|
||||
<th>Masa</th>
|
||||
<th>Susut/Bulan</th>
|
||||
<th>Create</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL TAMBAH ASSET -->
|
||||
<div class="modal fade" id="modalAsset">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 id="modalTitleAsset">Tambah Asset</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="id_asset">
|
||||
|
||||
<label class="mt-2">Akun Asset (Debit)</label>
|
||||
<select id="account_asset" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Akun Kas (Kredit)</label>
|
||||
<select id="account_kas" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Lokasi Aset</label>
|
||||
<select id="lokasi_asset" class="form-control"></select>
|
||||
|
||||
<label>Nama Asset</label>
|
||||
<input type="text" id="nama_asset" class="form-control">
|
||||
|
||||
<label class="mt-2">Keterangan</label>
|
||||
<input type="text" id="keterangan" class="form-control">
|
||||
|
||||
<label class="mt-2">Harga Per Unit</label>
|
||||
<input type="text" id="harga" class="form-control format-rupiah">
|
||||
|
||||
<label class="mt-2">Tanggal</label>
|
||||
<input type="date" id="tanggal" class="form-control">
|
||||
|
||||
<hr>
|
||||
|
||||
<label>Masa Manfaat (bulan)</label>
|
||||
<input type="number" id="masa" class="form-control">
|
||||
|
||||
<label>Nilai Residu</label>
|
||||
<input type="text" id="residu" class="form-control format-rupiah">
|
||||
|
||||
<label>Penyusutan / bulan</label>
|
||||
<input type="text" id="susut" class="form-control format-rupiah" readonly>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnSave">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL EDIT ASSET -->
|
||||
<div class="modal fade" id="modalEditAsset">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5>Edit Asset</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="edit_id">
|
||||
|
||||
<label>Nama Asset</label>
|
||||
<input type="text" id="edit_nama" class="form-control">
|
||||
|
||||
<label class="mt-2">Lokasi Aset</label>
|
||||
<select id="edit_lokasi_asset" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Keterangan</label>
|
||||
<input type="text" id="edit_keterangan" class="form-control">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" id="btnUpdate">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DETAIL & HISTORY -->
|
||||
<div class="modal fade" id="modalDetail">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5>Detail & History Asset</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="detailContent"></div>
|
||||
<hr>
|
||||
<h6>History Perubahan:</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm" id="tableHistory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tanggal</th>
|
||||
<th>Tipe</th>
|
||||
<th>Nilai</th>
|
||||
<th>Keterangan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DARI GUDANG -->
|
||||
<div class="modal fade" id="modalAssetStock">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5>Tambah Asset dari Gudang</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="s_item_id">
|
||||
<input type="hidden" id="s_harga">
|
||||
|
||||
<label class="mt-2">Akun Asset (Debit)</label>
|
||||
<select id="s_account_asset" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Lokasi Aset</label>
|
||||
<select id="s_lokasi_asset" class="form-control"></select>
|
||||
|
||||
<label>Pilih Barang</label>
|
||||
<select id="s_item" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Stok Tersedia</label>
|
||||
<input type="text" id="s_stok" class="form-control" readonly>
|
||||
|
||||
<label class="mt-2">Tanggal</label>
|
||||
<input type="date" id="s_tanggal" class="form-control">
|
||||
|
||||
<hr>
|
||||
|
||||
<label>Masa Manfaat (bulan)</label>
|
||||
<input type="number" id="s_masa" class="form-control">
|
||||
|
||||
<label>Nilai Residu</label>
|
||||
<input type="text" id="s_residu" class="form-control format-rupiah">
|
||||
|
||||
<label>Penyusutan / bulan</label>
|
||||
<input type="text" id="s_susut" class="form-control format-rupiah" readonly>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-success" id="btnSaveStock">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DELETE -->
|
||||
<div class="modal fade" id="modalDelete">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5>Hapus Asset</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="delete_id">
|
||||
<label>Pilih Alasan:</label>
|
||||
<select id="delete_alasan" class="form-control">
|
||||
<option value="dijual_untung">Dijual (Untung)</option>
|
||||
<option value="dijual_rugi">Dijual (Rugi)</option>
|
||||
<option value="dihapus">Dihapus</option>
|
||||
</select>
|
||||
<label class="mt-2">Keterangan:</label>
|
||||
<textarea id="delete_keterangan" class="form-control" rows="3" placeholder="Alasan detail penghapusan..."></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button type="button" class="btn btn-danger" id="btnConfirmDelete">Hapus</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DARI STOCK (SAMA) -->
|
||||
<div class="modal fade" id="modalAssetStock">
|
||||
<!-- sama seperti sebelumnya, tidak diubah -->
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
let action = 'add';
|
||||
let table = $('#tableAsset').DataTable({
|
||||
ajax:"<?= base_url('asset/get_data'); ?>"
|
||||
});
|
||||
|
||||
// ================= HELPER =================
|
||||
function formatRupiah(angka){
|
||||
if(!angka) return '';
|
||||
return angka.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||
}
|
||||
|
||||
function setSelectValue(selector, value){
|
||||
setTimeout(()=>{
|
||||
$(selector).val(value).trigger('change');
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// ================= LOAD SELECTS =================
|
||||
function loadKas(selected = null){
|
||||
$.get("<?= base_url('asset/get_accounts_kas'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KAS --</option>';
|
||||
res.forEach(i=>{
|
||||
let sel = (selected && selected == i.id) ? 'selected' : '';
|
||||
opt += `<option value="${i.id}" ${sel}>${i.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_kas').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function loadAsset(selected = null){
|
||||
$.get("<?= base_url('asset/get_accounts_asset'); ?>",res=>{
|
||||
let optAsset='<option value="">-- PILIH AKUN ASET --</option>';
|
||||
res.forEach(i=>{
|
||||
let sel = (selected && selected == i.id) ? 'selected' : '';
|
||||
optAsset += `<option value="${i.id}" ${sel}>${i.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_asset, #s_account_asset').html(optAsset);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function loadLokasiAsset(selected = null){
|
||||
$.get("<?= base_url('asset/get_lokasi_asset'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH LOKASI --</option>';
|
||||
res.forEach(i=>{
|
||||
let sel = (selected && selected == i.id) ? 'selected' : '';
|
||||
opt += `<option value="${i.id}" ${sel}>${i.nama}</option>`;
|
||||
});
|
||||
$('#lokasi_asset, #edit_lokasi_asset, #s_lokasi_asset').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD ITEMS =================
|
||||
function loadItems(){
|
||||
$.get("<?= base_url('asset/get_items'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH BARANG --</option>';
|
||||
res.forEach(i=>{
|
||||
opt += `<option value="${i.id}" data-harga="${i.harga_beli}" data-stok="${i.stok}" data-nama="${i.nama_barang}">
|
||||
${i.kode_detail} - ${i.nama_barang} - ( Stok: ${i.stok})
|
||||
</option>`;
|
||||
});
|
||||
$('#s_item').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= HITUNG PENYUSUTAN MANUAL =================
|
||||
function hitungSusut(){
|
||||
let harga = parseInt($('#harga').val().replace(/\D/g,'')) || 0;
|
||||
let residu = parseInt($('#residu').val().replace(/\D/g,'')) || 0;
|
||||
let masa = parseInt($('#masa').val()) || 1;
|
||||
let susut = (harga - residu) / masa;
|
||||
$('#susut').val(formatRupiah(Math.round(susut)));
|
||||
}
|
||||
|
||||
$('#masa, #residu, #harga').on('keyup change',hitungSusut);
|
||||
|
||||
// ================= HITUNG SUSUT STOCK =================
|
||||
$('#s_masa, #s_residu').on('keyup change',function(){
|
||||
let harga = parseInt($('#s_harga').val()) || 0;
|
||||
let residu = parseInt($('#s_residu').val().replace(/\D/g,'')) || 0;
|
||||
let masa = parseInt($('#s_masa').val()) || 1;
|
||||
let susut = (harga - residu) / masa;
|
||||
$('#s_susut').val(formatRupiah(Math.round(susut)));
|
||||
});
|
||||
|
||||
// ================= TAMBAH ASSET MANUAL =================
|
||||
$('.btn-add-asset').click(function(){
|
||||
action='add';
|
||||
$('#modalTitleAsset').text('Tambah Asset');
|
||||
$('#modalAsset input[type="text"], #modalAsset input[type="date"], #modalAsset input[type="number"], #modalAsset select').val('');
|
||||
$('#id_asset').val('');
|
||||
loadKas(); loadAsset(); loadLokasiAsset();
|
||||
$('#modalAsset').modal('show');
|
||||
});
|
||||
|
||||
// ================= DETAIL & HISTORY =================
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('asset/detail/'); ?>"+id, function(asset){
|
||||
$('#detailContent').html(`
|
||||
<table class="table table-borderless">
|
||||
<tr><td><strong>Kode Asset</strong></td><td>: <strong>${asset.kode_asset || '-'}</strong></td></tr>
|
||||
<tr><td><strong>Nama Asset</strong></td><td>: <strong>${asset.nama_asset}</strong></td></tr>
|
||||
<tr><td><strong>Lokasi</strong></td><td>: <strong>${asset.nama_lokasi || '-'}</strong></td></tr>
|
||||
<tr><td><strong>Harga/Unit</strong></td><td>: <strong>Rp ${formatRupiah(asset.harga_per_unit)}</strong></td></tr>
|
||||
<tr><td><strong>Nilai Buku</strong></td><td>: <strong>Rp ${formatRupiah(asset.nilai_buku)}</strong></td></tr>
|
||||
<tr><td><strong>Masa Manfaat</strong></td><td>: <strong>${asset.masa_manfaat} bulan</strong></td></tr>
|
||||
<tr><td><strong>Sumber</strong></td><td>: <strong>${asset.sumber}</strong></td></tr>
|
||||
<tr><td><strong>Keterangan</strong></td><td>: <strong>${asset.keterangan || '-'}</strong></td></tr>
|
||||
</table>
|
||||
`);
|
||||
|
||||
// Load history
|
||||
$.get("<?= base_url('asset/get_history/'); ?>"+id, function(history){
|
||||
let rows = '';
|
||||
if(history.length === 0){
|
||||
rows = '<tr><td colspan="5" class="text-center">Belum ada history</td></tr>';
|
||||
}else{
|
||||
history.forEach(h=>{
|
||||
let badgeClass = h.tipe=='perolehan' ? 'bg-success' :
|
||||
h.tipe=='penambahan' ? 'bg-info' :
|
||||
h.tipe=='pengurangan' ? 'bg-warning' : 'bg-secondary';
|
||||
rows += `<tr>
|
||||
<td>${h.created_at}</td>
|
||||
<td><span class="badge ${badgeClass}">${h.tipe}</span></td>
|
||||
<td>Rp ${formatRupiah(h.nilai || 0)}</td>
|
||||
<td>${h.keterangan}</td>
|
||||
</tr>`;
|
||||
});
|
||||
}
|
||||
$('#tableHistory tbody').html(rows);
|
||||
},'json');
|
||||
|
||||
$('#modalDetail').modal('show');
|
||||
},'json');
|
||||
});
|
||||
|
||||
// ================= EDIT ASSET =================
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('asset/detail/'); ?>"+id,function(res){
|
||||
$('#edit_id').val(res.id);
|
||||
$('#edit_nama').val(res.nama_asset);
|
||||
$('#edit_keterangan').val(res.keterangan || '');
|
||||
loadLokasiAsset(res.lokasi_asset_id);
|
||||
$('#modalEditAsset').modal('show');
|
||||
},'json');
|
||||
});
|
||||
|
||||
// ================= UPDATE ASSET =================
|
||||
$('#btnUpdate').click(function(){
|
||||
let btn = $(this);
|
||||
let data = {
|
||||
id: $('#edit_id').val(),
|
||||
nama_asset: $('#edit_nama').val(),
|
||||
lokasi_asset: $('#edit_lokasi_asset').val(),
|
||||
keterangan: $('#edit_keterangan').val()
|
||||
};
|
||||
|
||||
if(!data.nama_asset){
|
||||
Swal.fire('Error','Nama asset wajib diisi','error');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post("<?= base_url('asset/update'); ?>", data, function(res){
|
||||
if(res.status){
|
||||
$('#modalEditAsset').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Berhasil','Asset berhasil diupdate','success');
|
||||
}
|
||||
},'json').always(()=>{
|
||||
btn.prop('disabled', false).html('Update');
|
||||
});
|
||||
});
|
||||
|
||||
// ================= DELETE =================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
let id = $(this).data('id');
|
||||
$('#delete_id').val(id);
|
||||
$('#delete_keterangan').val('');
|
||||
$('#modalDelete').modal('show');
|
||||
});
|
||||
|
||||
$('#btnConfirmDelete').click(function(){
|
||||
let btn = $(this);
|
||||
let keterangan = $('#delete_keterangan').val().trim();
|
||||
|
||||
if(!keterangan){
|
||||
Swal.fire('Error','Keterangan wajib diisi','error');
|
||||
return;
|
||||
}
|
||||
|
||||
let data = {
|
||||
id: $('#delete_id').val(),
|
||||
alasan: $('#delete_alasan').val(),
|
||||
keterangan: keterangan
|
||||
};
|
||||
|
||||
btn.prop('disabled', true).html('Menghapus...');
|
||||
|
||||
$.post("<?= base_url('asset/delete'); ?>", data, function(res){
|
||||
if(res.status){
|
||||
$('#modalDelete').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Berhasil','Asset berhasil dihapus','success');
|
||||
}
|
||||
},'json').always(()=>{
|
||||
btn.prop('disabled', false).html('Hapus');
|
||||
});
|
||||
});
|
||||
|
||||
// ================= SAVE ASSET MANUAL =================
|
||||
$('#btnSave').click(function(){
|
||||
let btn = $(this);
|
||||
let data = {
|
||||
id: $('#id_asset').val(),
|
||||
nama_asset: $('#nama_asset').val(),
|
||||
harga: $('#harga').val(),
|
||||
tanggal: $('#tanggal').val(),
|
||||
masa: $('#masa').val(),
|
||||
residu: $('#residu').val(),
|
||||
account_kas: $('#account_kas').val(),
|
||||
account_asset: $('#account_asset').val(),
|
||||
lokasi_asset: $('#lokasi_asset').val(),
|
||||
keterangan: $('#keterangan').val()
|
||||
};
|
||||
|
||||
// Validasi
|
||||
if(!data.nama_asset || !data.harga || !data.tanggal || !data.account_kas || !data.account_asset){
|
||||
Swal.fire('Error','Semua field wajib diisi','error');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
let url = action==='add' ? "<?= base_url('asset/save'); ?>" : "<?= base_url('asset/update'); ?>";
|
||||
|
||||
$.post(url, data, function(res){
|
||||
if(res.status){
|
||||
$('#modalAsset').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire({icon:'success',title:'Berhasil',timer:1500,showConfirmButton:false});
|
||||
}
|
||||
},'json').always(()=>{
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
});
|
||||
|
||||
// ================= FROM STOCK =================
|
||||
$('.btn-from-stock').click(function(){
|
||||
$('#modalAssetStock input[type="text"], #modalAssetStock input[type="date"], #modalAssetStock input[type="number"], #modalAssetStock select').val('');
|
||||
$('#s_item_id, #s_harga').val('');
|
||||
loadItems();
|
||||
loadAsset();
|
||||
loadLokasiAsset();
|
||||
$('#modalAssetStock').modal('show');
|
||||
});
|
||||
|
||||
// ================= PILIH ITEM STOCK =================
|
||||
$(document).on('change','#s_item',function(){
|
||||
let selected = $(this).find(':selected');
|
||||
let harga = selected.data('harga') || 0;
|
||||
let stok = selected.data('stok') || 0;
|
||||
$('#s_item_id').val($(this).val());
|
||||
$('#s_harga').val(harga);
|
||||
$('#s_stok').val(stok);
|
||||
});
|
||||
|
||||
// ================= SAVE FROM STOCK =================
|
||||
$('#btnSaveStock').click(function(){
|
||||
let btn = $(this);
|
||||
let data = {
|
||||
item_id: $('#s_item').val(),
|
||||
s_tanggal: $('#s_tanggal').val(),
|
||||
s_masa: $('#s_masa').val(),
|
||||
s_residu: $('#s_residu').val(),
|
||||
s_lokasi_asset: $('#s_lokasi_asset').val(),
|
||||
account_asset: $('#s_account_asset').val()
|
||||
};
|
||||
|
||||
// Validasi
|
||||
if(!data.item_id || !data.s_tanggal || !data.account_asset || !data.s_lokasi_asset){
|
||||
Swal.fire('Error','Item, tanggal, akun asset, dan lokasi wajib diisi','error');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post("<?= base_url('asset/save_from_stock'); ?>",data,function(res){
|
||||
if(res.status){
|
||||
$('#modalAssetStock').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire({
|
||||
icon:'success',
|
||||
title:'Berhasil!',
|
||||
text:'Asset dari gudang berhasil dibuat',
|
||||
timer:2000,
|
||||
showConfirmButton:false
|
||||
});
|
||||
}else{
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
},'json').always(()=>{
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Login - Accounting</title>
|
||||
<link rel="icon" href="<?= base_url('assets/img/accounting-color.png') ?>" type="image/png">
|
||||
|
||||
<!-- Assets from Theme -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Make sure the path is correct in a real scenario -->
|
||||
<link href="<?= base_url('assets/css/style-custom.css'); ?>" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--orange-main: #ff8c00;
|
||||
--orange-dark: #e67700;
|
||||
--orange-soft: rgba(255, 140, 0, 0.15);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff8f1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
color: var(--orange-dark);
|
||||
font-weight: 700;
|
||||
font-size: 1.8rem;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.login-subtitle {
|
||||
text-align: center;
|
||||
color: #6c757d;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 12px;
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px solid #ced4da;
|
||||
transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: var(--orange-main);
|
||||
box-shadow: 0 0 0 0.25rem var(--orange-soft);
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
width: 100%;
|
||||
padding: 0.8rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
border-radius: 12px;
|
||||
background: var(--orange-main);
|
||||
border: none;
|
||||
color: #fff;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-login:hover {
|
||||
background: var(--orange-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="card modern-card login-card shadow-lg">
|
||||
<div class="card-body">
|
||||
|
||||
<center style="margin-bottom: 20px;">
|
||||
<img src="<?= base_url('assets/img/accounting-color.png'); ?>" width="150px">
|
||||
</center>
|
||||
<hr>
|
||||
<p class="login-subtitle">Silakan login untuk melanjutkan</p>
|
||||
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?= $error; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="<?= base_url('auth/process_login'); ?>" method="post">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label fw-semibold">Username</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0"><i class="bi bi-person"></i></span>
|
||||
<input type="text" class="form-control border-start-0" id="username" name="username" placeholder="Masukkan username Anda" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="password" class="form-label fw-semibold">Password</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0"><i class="bi bi-lock"></i></span>
|
||||
<input type="password" class="form-control border-start-0" id="password" name="password" placeholder="Masukkan password Anda" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-premium btn-login">Login</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts from Theme -->
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<?php if($this->session->flashdata('error')): ?>
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Login Gagal',
|
||||
text: '<?= $this->session->flashdata('error'); ?>',
|
||||
confirmButtonText: 'Coba Lagi'
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
@@ -0,0 +1,339 @@
|
||||
<div class="container mt-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 class="mb-0">Base Jurnal</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Template</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableJurnal" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Status</th>
|
||||
<th width="15%">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalJurnal">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Tambah Base Jurnal</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label>Kode</label>
|
||||
<input type="text" class="form-control" id="kode">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label>Nama</label>
|
||||
<input type="text" class="form-control" id="nama">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="mt-2">Deskripsi</label>
|
||||
<textarea class="form-control" id="deskripsi"></textarea>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- DETAIL -->
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<strong>Detail Akun</strong>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="btnAddRow">
|
||||
+ Tambah Baris
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table class="table table-bordered" id="tableDetail">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Akun</th>
|
||||
<th width="150">Posisi</th>
|
||||
<th width="80">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
// ================= DATATABLE
|
||||
let table = $('#tableJurnal').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: "<?= base_url('basejurnal/get_data'); ?>",
|
||||
type: "POST"
|
||||
}
|
||||
});
|
||||
|
||||
// ================= GLOBAL STATE
|
||||
let accountList = [];
|
||||
let isAccountLoaded = false;
|
||||
|
||||
// ================= LOAD ACCOUNT (PROMISE)
|
||||
function loadAccounts(){
|
||||
return new Promise((resolve, reject) => {
|
||||
if(isAccountLoaded){
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
$.get("<?= base_url('basejurnal/get_list_account'); ?>", function(res){
|
||||
accountList = res;
|
||||
isAccountLoaded = true;
|
||||
resolve();
|
||||
}, 'json').fail(function(){
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ================= RENDER OPTION
|
||||
function renderAccountOption(selected=null){
|
||||
let html = `<option value="">-- Pilih Akun --</option>`;
|
||||
|
||||
accountList.forEach(a=>{
|
||||
html += `<option value="${a.id}" ${selected==a.id?'selected':''}>
|
||||
${a.kode_akun} - ${a.nama_akun}
|
||||
</option>`;
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// ================= ADD ROW
|
||||
function addRow(data=null){
|
||||
let row = `
|
||||
<tr>
|
||||
<td>
|
||||
<select class="form-control account_id">
|
||||
${renderAccountOption(data?.account_id)}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-control posisi">
|
||||
<option value="debit" ${data?.posisi=='debit'?'selected':''}>Debit</option>
|
||||
<option value="kredit" ${data?.posisi=='kredit'?'selected':''}>Kredit</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-danger btn-sm btn-remove">X</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
$('#tableDetail tbody').append(row);
|
||||
}
|
||||
|
||||
// ================= RESET FORM
|
||||
function resetForm(){
|
||||
$('#inputId, #kode, #nama, #deskripsi').val('');
|
||||
$('#tableDetail tbody').html('');
|
||||
}
|
||||
|
||||
// ================= OPEN MODAL ADD
|
||||
$('.btn-add').click(async function(){
|
||||
|
||||
resetForm();
|
||||
|
||||
try {
|
||||
await loadAccounts();
|
||||
addRow();
|
||||
} catch(e){
|
||||
Swal.fire('Error','Gagal load data akun','error');
|
||||
return;
|
||||
}
|
||||
|
||||
$('#btnSimpan').data('action','add');
|
||||
$('#modalJurnal .modal-title').text('Tambah Base Jurnal');
|
||||
$('#modalJurnal').modal('show');
|
||||
});
|
||||
|
||||
// ================= ADD ROW BUTTON
|
||||
$('#btnAddRow').click(async function(){
|
||||
if(!isAccountLoaded){
|
||||
await loadAccounts();
|
||||
}
|
||||
addRow();
|
||||
});
|
||||
|
||||
// ================= REMOVE ROW
|
||||
$(document).on('click','.btn-remove',function(){
|
||||
$(this).closest('tr').remove();
|
||||
});
|
||||
|
||||
// ================= SAVE / UPDATE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let accounts = [];
|
||||
let posisi = [];
|
||||
|
||||
$('#tableDetail tbody tr').each(function(){
|
||||
let acc = $(this).find('.account_id').val();
|
||||
let pos = $(this).find('.posisi').val();
|
||||
|
||||
if(acc){ // skip kosong
|
||||
accounts.push(acc);
|
||||
posisi.push(pos ? pos : 'debit');
|
||||
}
|
||||
});
|
||||
|
||||
let data = {
|
||||
id: $('#inputId').val(),
|
||||
kode: $('#kode').val().trim(),
|
||||
nama: $('#nama').val().trim(),
|
||||
deskripsi: $('#deskripsi').val().trim(),
|
||||
account_id: accounts,
|
||||
posisi: posisi
|
||||
};
|
||||
|
||||
// VALIDASI
|
||||
if(!data.kode || !data.nama){
|
||||
Swal.fire('Warning','Kode & Nama wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if(accounts.length === 0){
|
||||
Swal.fire('Warning','Minimal 1 akun harus dipilih','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('basejurnal/save'); ?>"
|
||||
: "<?= base_url('basejurnal/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
$('#modalJurnal').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Error', res.message, 'error');
|
||||
}
|
||||
},
|
||||
error: function(xhr){
|
||||
console.log(xhr.responseText);
|
||||
Swal.fire('Error','Terjadi kesalahan server','error');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ================= EDIT
|
||||
$(document).on('click','.btn-edit', async function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
resetForm();
|
||||
|
||||
try {
|
||||
await loadAccounts();
|
||||
} catch(e){
|
||||
Swal.fire('Error','Gagal load akun','error');
|
||||
return;
|
||||
}
|
||||
|
||||
$.get("<?= base_url('basejurnal/detail/'); ?>" + id, function(res){
|
||||
|
||||
$('#inputId').val(res.header.id);
|
||||
$('#kode').val(res.header.kode);
|
||||
$('#nama').val(res.header.nama);
|
||||
$('#deskripsi').val(res.header.deskripsi);
|
||||
|
||||
$('#tableDetail tbody').html('');
|
||||
|
||||
if(res.detail.length > 0){
|
||||
res.detail.forEach(d=>{
|
||||
addRow(d);
|
||||
});
|
||||
} else {
|
||||
addRow();
|
||||
}
|
||||
|
||||
$('#btnSimpan').data('action','edit');
|
||||
$('#modalJurnal .modal-title').text('Edit Base Jurnal');
|
||||
$('#modalJurnal').modal('show');
|
||||
|
||||
}, 'json');
|
||||
});
|
||||
|
||||
// ================= DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus data?',
|
||||
text: 'Data tidak bisa dikembalikan!',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus'
|
||||
}).then((result)=>{
|
||||
if(result.isConfirmed){
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('basejurnal/delete/'); ?>" + id,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Error', res.message, 'error');
|
||||
}
|
||||
},
|
||||
error: function(xhr){
|
||||
console.log(xhr.responseText);
|
||||
Swal.fire('Error','Terjadi kesalahan server','error');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,101 @@
|
||||
<div class="container mt-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>Buku Besar</h5>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<label>Akun</label>
|
||||
<select id="account_id" class="form-control select-search"></select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<label>Dari</label>
|
||||
<input type="date" id="start_date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<label>Sampai</label>
|
||||
<input type="date" id="end_date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<button class="btn btn-primary w-100" id="btnFilter">Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableLedger" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tanggal</th>
|
||||
<th>No Ref</th>
|
||||
<th>Keterangan</th>
|
||||
<th>Debit</th>
|
||||
<th>Kredit</th>
|
||||
<th>Saldo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
// LOAD ACCOUNTS
|
||||
$.get("<?= base_url('bukubesar/get_accounts'); ?>", function(res){
|
||||
let opt = '';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_id').html(opt);
|
||||
},'json');
|
||||
|
||||
function loadData(){
|
||||
|
||||
let account_id = $('#account_id').val();
|
||||
let start = $('#start_date').val();
|
||||
let end = $('#end_date').val();
|
||||
|
||||
$.get("<?= base_url('bukubesar/get_data'); ?>", {
|
||||
account_id: account_id,
|
||||
start_date: start,
|
||||
end_date: end
|
||||
}, function(res){
|
||||
|
||||
let html = '';
|
||||
|
||||
res.forEach(r=>{
|
||||
html += `
|
||||
<tr>
|
||||
<td>${r.tanggal}</td>
|
||||
<td>${r.no_ref}</td>
|
||||
<td>${r.keterangan}</td>
|
||||
<td class="text-success">${parseFloat(r.debit).toLocaleString()}</td>
|
||||
<td class="text-danger">${parseFloat(r.kredit).toLocaleString()}</td>
|
||||
<td class="fw-bold">${parseFloat(r.saldo).toLocaleString()}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
$('#tableLedger tbody').html(html);
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
// FILTER
|
||||
$('#btnFilter').click(function(){
|
||||
loadData();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<style>
|
||||
.atm-card {
|
||||
position: relative;
|
||||
margin: auto;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.text-block {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* Dinamis berdasarkan orientasi */
|
||||
<?php if ($orientation == 'landscape'): ?>
|
||||
.atm-card {
|
||||
width: <?= $width ?>px;
|
||||
height: <?= $height ?>px;
|
||||
}
|
||||
.text-block {
|
||||
bottom: 40px;
|
||||
left: 50px;
|
||||
}
|
||||
.text-block h2 { font-size: 48px; margin: 0; }
|
||||
.text-block p { font-size: 30px; margin: 2px 0; }
|
||||
|
||||
<?php else: // portrait ?>
|
||||
.atm-card {
|
||||
width: <?= $width ?>px;
|
||||
height: <?= $height ?>px;
|
||||
}
|
||||
.text-block {
|
||||
bottom: 30px;
|
||||
left: 40px;
|
||||
}
|
||||
.text-block h2 { font-size: 40px; margin: 0; }
|
||||
.text-block p { font-size: 26px; margin: 2px 0; }
|
||||
<?php endif; ?>
|
||||
|
||||
.btn-area {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-print {
|
||||
padding: 10px 25px;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="atm-card" style="background-image: url('<?= $background ?>')">
|
||||
<div class="text-block">
|
||||
<h2><?= $nama ?></h2>
|
||||
<p>NIS: <?= $nis ?></p>
|
||||
<p>Kelas: <?= $kelas ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-area">
|
||||
<button class="btn-print" onclick="window.print()">Print</button>
|
||||
</div>
|
||||
@@ -0,0 +1,165 @@
|
||||
<div class="container mt-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>Data Customers</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Customer</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableCustomers" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama</th>
|
||||
<th>Alamat</th>
|
||||
<th>Telp</th>
|
||||
<th>Email</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalCustomer">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Customer</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<label>Nama</label>
|
||||
<input type="text" id="nama" class="form-control">
|
||||
|
||||
<label class="mt-2">Alamat</label>
|
||||
<textarea id="alamat" class="form-control"></textarea>
|
||||
|
||||
<label class="mt-2">Telp</label>
|
||||
<input type="text" id="telp" class="form-control">
|
||||
|
||||
<label class="mt-2">Email</label>
|
||||
<input type="email" id="email" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CARA MANGGIL TABLE PERTAMA -->
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
|
||||
let table = $('#tableCustomers').DataTable({
|
||||
processing:true,
|
||||
serverSide:true,
|
||||
order:[[1,'asc']],
|
||||
ajax:{
|
||||
url:"<?= base_url('customers/get_data'); ?>",
|
||||
type:"POST"
|
||||
}
|
||||
});
|
||||
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#nama').val('');
|
||||
$('#alamat').val('');
|
||||
$('#telp').val('');
|
||||
$('#email').val('');
|
||||
}
|
||||
|
||||
// ADD
|
||||
$('.btn-add').click(function(){
|
||||
resetForm();
|
||||
action = 'add';
|
||||
$('#modalCustomer').modal('show');
|
||||
});
|
||||
|
||||
// EDIT
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('customers/detail/'); ?>"+id,function(res){
|
||||
$('#id').val(res.id);
|
||||
$('#nama').val(res.nama);
|
||||
$('#alamat').val(res.alamat);
|
||||
$('#telp').val(res.telp);
|
||||
$('#email').val(res.email);
|
||||
|
||||
action = 'edit';
|
||||
$('#modalCustomer').modal('show');
|
||||
},'json');
|
||||
});
|
||||
|
||||
// SAVE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
nama: $('#nama').val(),
|
||||
alamat: $('#alamat').val(),
|
||||
telp: $('#telp').val(),
|
||||
email: $('#email').val()
|
||||
};
|
||||
|
||||
if(!data.nama){
|
||||
Swal.fire('Warning','Nama wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('customers/save'); ?>"
|
||||
: "<?= base_url('customers/update'); ?>";
|
||||
|
||||
$.post(url,data,function(res){
|
||||
|
||||
if(res.status){
|
||||
$('#modalCustomer').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Hapus data?',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(r=>{
|
||||
if(r.isConfirmed){
|
||||
$.get("<?= base_url('customers/delete/'); ?>"+id,function(res){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
},'json');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,102 @@
|
||||
<div class="container mt-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>Activity Log</h5>
|
||||
<button class="btn btn-secondary btn-sm" id="btnReload">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableActivity" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Waktu</th>
|
||||
<th>User</th>
|
||||
<th>Module</th>
|
||||
<th>Action</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Status</th>
|
||||
<th>IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
let table = $('#tableActivity').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: "<?= base_url('dashboard/get_activity_datatable'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
order: [[0, 'desc']],
|
||||
columns: [
|
||||
{ data: 'created_at' },
|
||||
{ data: 'nama' },
|
||||
{ data: 'module' },
|
||||
{ data: 'action' },
|
||||
{ data: 'description' },
|
||||
{ data: 'status' },
|
||||
{ data: 'ip_address' }
|
||||
],
|
||||
|
||||
columnDefs: [
|
||||
|
||||
|
||||
// ================= MODULE =================
|
||||
{
|
||||
targets: 2,
|
||||
render: function (data) {
|
||||
return `<span class="badge bg-light text-dark border">${data ?? '-'}</span>`;
|
||||
}
|
||||
},
|
||||
|
||||
// ================= ACTION =================
|
||||
{
|
||||
targets: 3,
|
||||
render: function (data) {
|
||||
return `<span class="text-muted">${data ?? '-'}</span>`;
|
||||
}
|
||||
},
|
||||
|
||||
// ================= STATUS =================
|
||||
{
|
||||
targets: 5,
|
||||
render: function (data) {
|
||||
|
||||
let cls = "text-muted";
|
||||
|
||||
if (data === "success") cls = "text-success";
|
||||
if (data === "error") cls = "text-danger";
|
||||
if (data === "warning") cls = "text-warning";
|
||||
|
||||
return `<span class="${cls}">${data ?? '-'}</span>`;
|
||||
}
|
||||
},
|
||||
|
||||
// ================= IP =================
|
||||
{
|
||||
targets: 6,
|
||||
render: function (data) {
|
||||
return `<small class="text-muted">${data ?? '-'}</small>`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
$('#btnReload').click(function () {
|
||||
table.ajax.reload(null, false);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,849 @@
|
||||
<?php $role = $this->session->userdata('role'); ?>
|
||||
|
||||
<style>
|
||||
/* ======================================================
|
||||
DASHBOARD CLEAN - Orange Theme (Minimal & Elegant)
|
||||
====================================================== */
|
||||
:root {
|
||||
/* Orange Theme Colors */
|
||||
--orange-primary: #ff8c00;
|
||||
--orange-light: #ffd4a3;
|
||||
--orange-dark: #e67700;
|
||||
--orange-gradient: linear-gradient(135deg, #ff8c00 0%, #ff7b00 50%, #e67700 100%);
|
||||
|
||||
/* Neutral Colors */
|
||||
--white: #ffffff;
|
||||
--light-bg: #f8fafc;
|
||||
--border-light: #e2e8f0;
|
||||
--text-dark: #1e293b;
|
||||
--text-muted: #64748b;
|
||||
|
||||
/* Shadows - Subtle */
|
||||
--shadow-sm: 0 2px 8px rgba(0,0,0,0.06);
|
||||
--shadow-md: 0 8px 24px rgba(0,0,0,0.08);
|
||||
--shadow-lg: 0 16px 40px rgba(0,0,0,0.10);
|
||||
}
|
||||
|
||||
/* Modern Card - Clean & Minimal */
|
||||
.modern-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modern-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: var(--orange-gradient);
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.modern-card:hover {
|
||||
box-shadow: var(--shadow-lg);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.modern-card:hover::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
SUMMARY CARDS - Orange Accents
|
||||
====================================================== */
|
||||
.summary-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.summary-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
color: var(--white);
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 6px 20px rgba(255,140,0,0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Orange-based icon colors - subtle variations */
|
||||
.summary-card:nth-child(1) .summary-icon { background: var(--orange-gradient); }
|
||||
.summary-card:nth-child(2) .summary-icon {
|
||||
background: linear-gradient(135deg, var(--orange-light) 0%, var(--orange-primary) 100%);
|
||||
}
|
||||
.summary-card:nth-child(3) .summary-icon {
|
||||
background: linear-gradient(135deg, #ff9500 0%, var(--orange-primary) 100%);
|
||||
}
|
||||
.summary-card:nth-child(4) .summary-icon {
|
||||
background: linear-gradient(135deg, var(--orange-dark) 0%, #d66a00 100%);
|
||||
}
|
||||
.summary-card:nth-child(5) .summary-icon {
|
||||
background: linear-gradient(135deg, #ffb366 0%, var(--orange-primary) 100%);
|
||||
}
|
||||
.summary-card:nth-child(6) .summary-icon {
|
||||
background: linear-gradient(135deg, #ffcc80 0%, #ffad42 100%);
|
||||
}
|
||||
.summary-card:nth-child(7) .summary-icon {
|
||||
background: linear-gradient(135deg, #ffd180 0%, #ffab40 100%);
|
||||
}
|
||||
|
||||
/* Quick Action Cards */
|
||||
.quick-action .summary-card {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.quick-action .summary-card:hover .summary-icon {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 10px 30px rgba(255,140,0,0.4);
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
AI INSIGHT - Clean Cards
|
||||
====================================================== */
|
||||
.ai-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
max-height: 340px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ai-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.ai-box::-webkit-scrollbar-track {
|
||||
background: #f1f5f9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.ai-box::-webkit-scrollbar-thumb {
|
||||
background: var(--orange-light);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.ai-item {
|
||||
padding: 16px 20px;
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
border-left: 4px solid var(--orange-primary);
|
||||
background: #fef7ee;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid #fee2c7;
|
||||
}
|
||||
|
||||
.ai-item:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.ai-item i {
|
||||
font-size: 16px;
|
||||
margin-top: 1px;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.9;
|
||||
color: var(--orange-primary);
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.ai-success {
|
||||
border-left-color: #10b981;
|
||||
background: #f0fdf4;
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
.ai-success i {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.ai-warning {
|
||||
border-left-color: #f59e0b;
|
||||
background: #fef3c7;
|
||||
border-color: #fed7aa;
|
||||
}
|
||||
|
||||
.ai-warning i {
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.ai-info {
|
||||
border-left-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
border-color: #bfdbfe;
|
||||
}
|
||||
|
||||
.ai-info i {
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
TABLE CLEAN & MODERN
|
||||
====================================================== */
|
||||
.modern-table-dashboard {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
border: none;
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
.modern-table-dashboard thead th {
|
||||
background: linear-gradient(135deg, #fef7ee 0%, #fff8f0 100%);
|
||||
border: none;
|
||||
padding: 18px 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-dark);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.modern-table-dashboard tbody tr {
|
||||
transition: all 0.2s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modern-table-dashboard tbody tr:hover {
|
||||
background: rgba(255,140,0,0.04);
|
||||
}
|
||||
|
||||
.modern-table-dashboard td {
|
||||
padding: 18px 16px;
|
||||
border-color: #f8fafc;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Modern Badges */
|
||||
.badge {
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.3px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
SUBTLE ANIMATIONS
|
||||
====================================================== */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-card,
|
||||
.summary-card {
|
||||
animation: fadeInUp 0.6s ease forwards;
|
||||
}
|
||||
|
||||
.modern-card:nth-child(1) { animation-delay: 0.1s; }
|
||||
.modern-card:nth-child(2) { animation-delay: 0.15s; }
|
||||
.modern-card:nth-child(3) { animation-delay: 0.2s; }
|
||||
.modern-card:nth-child(4) { animation-delay: 0.25s; }
|
||||
|
||||
/* ======================================================
|
||||
RESPONSIVE - Clean Mobile
|
||||
====================================================== */
|
||||
@media (max-width: 768px) {
|
||||
.summary-card {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ai-item {
|
||||
padding: 14px 16px;
|
||||
font-size: 13.5px;
|
||||
}
|
||||
|
||||
.modern-table-dashboard thead th,
|
||||
.modern-table-dashboard td {
|
||||
padding: 14px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.modern-card,
|
||||
.summary-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Button enhancements */
|
||||
.btn-outline-primary {
|
||||
border-color: var(--orange-primary);
|
||||
color: var(--orange-primary);
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background: var(--orange-primary);
|
||||
border-color: var(--orange-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Chart container */
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- ───────────────────────── DASHBOARD CONTENT ───────────────────────── -->
|
||||
<div class="container mt-4 px-3 px-md-4">
|
||||
|
||||
<?php if($role == 'Admin'): ?>
|
||||
<!-- ================= SUMMARY CARDS ================= -->
|
||||
<div class="row g-4 mb-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="summary-card h-100">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
<div class="summary-icon"><i class="bi bi-cash-stack"></i></div>
|
||||
<div class="ms-3 flex-grow-1">
|
||||
<div class="fw-bold fs-4 lh-1 text-dark">Rp <?= number_format($summary['total_revenue']); ?></div>
|
||||
<small class="text-muted fw-medium">Total Pemasukan</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="summary-card h-100">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
<div class="summary-icon"><i class="bi bi-arrow-down-circle"></i></div>
|
||||
<div class="ms-3 flex-grow-1">
|
||||
<div class="fw-bold fs-4 lh-1 text-danger">Rp <?= number_format($summary['total_expense']); ?></div>
|
||||
<small class="text-muted fw-medium">Total Pengeluaran</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="summary-card h-100">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
<div class="summary-icon"><i class="bi bi-graph-up-arrow"></i></div>
|
||||
<div class="ms-3 flex-grow-1">
|
||||
<div class="fw-bold fs-4 lh-1 text-success">Rp <?= number_format($summary['net_profit']); ?></div>
|
||||
<small class="text-muted fw-medium">Keuntungan Bersih</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ================= SECOND ROW ================= -->
|
||||
<div class="row g-4 mb-3">
|
||||
|
||||
<!-- ================= NERACA ================= -->
|
||||
<div class="col-12 col-md-6">
|
||||
<a href="<?= base_url('neraca'); ?>" class="text-decoration-none">
|
||||
<div class="summary-card h-100">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
|
||||
<div class="summary-icon">
|
||||
<i class="bi bi-bar-chart-line-fill"></i>
|
||||
</div>
|
||||
|
||||
<div class="ms-3 flex-grow-1 position-relative">
|
||||
|
||||
<div class="fw-bold fs-4 lh-1 text-primary">
|
||||
Neraca
|
||||
</div>
|
||||
|
||||
<small class="text-muted fw-medium">
|
||||
Laporan posisi keuangan perusahaan
|
||||
</small>
|
||||
|
||||
<div class="position-absolute bottom-0 end-0 p-3">
|
||||
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- ================= LABA RUGI ================= -->
|
||||
<div class="col-12 col-md-6">
|
||||
<a href="<?= base_url('labarugi'); ?>" class="text-decoration-none">
|
||||
<div class="summary-card h-100">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
|
||||
<div class="summary-icon">
|
||||
<i class="bi bi-graph-up-arrow"></i>
|
||||
</div>
|
||||
|
||||
<div class="ms-3 flex-grow-1 position-relative">
|
||||
|
||||
<div class="fw-bold fs-4 lh-1 text-success">
|
||||
Laba Rugi
|
||||
</div>
|
||||
|
||||
<small class="text-muted fw-medium">
|
||||
Analisis pendapatan dan beban usaha
|
||||
</small>
|
||||
|
||||
<div class="position-absolute bottom-0 end-0 p-3">
|
||||
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ================= QUICK ACTIONS ================= -->
|
||||
<div class="row g-4 mb-3 quick-action">
|
||||
|
||||
<!-- ================= INVOICE ================= -->
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<a href="<?= base_url('invoices/draft'); ?>" class="text-decoration-none">
|
||||
<div class="summary-card h-100 text-center p-4 position-relative overflow-hidden">
|
||||
|
||||
<div class="summary-icon mx-auto mb-3 d-inline-block">
|
||||
<i class="bi bi-receipt"></i>
|
||||
</div>
|
||||
|
||||
<h6 class="mb-2 fw-bold text-dark">Invoice</h6>
|
||||
|
||||
<small class="text-muted fw-medium d-block">
|
||||
Kelola penjualan & penagihan pelanggan
|
||||
</small>
|
||||
|
||||
<div class="position-absolute bottom-0 end-0 p-3">
|
||||
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- ================= GUDANG / ITEMS ================= -->
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<a href="<?= base_url('items'); ?>" class="text-decoration-none">
|
||||
<div class="summary-card h-100 text-center p-4 position-relative overflow-hidden">
|
||||
|
||||
<div class="summary-icon mx-auto mb-3 d-inline-block">
|
||||
<i class="bi bi-box-seam"></i>
|
||||
</div>
|
||||
|
||||
<h6 class="mb-2 fw-bold text-dark">Persediaan</h6>
|
||||
|
||||
<small class="text-muted fw-medium d-block">
|
||||
Kelola stok & barang gudang
|
||||
</small>
|
||||
|
||||
<div class="position-absolute bottom-0 end-0 p-3">
|
||||
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- ================= MAIN CONTENT ================= -->
|
||||
<div class="row g-4">
|
||||
<!-- Chart -->
|
||||
<div class="col-xl-8">
|
||||
<div class="modern-card h-100">
|
||||
<div class="p-5">
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
<h4 class="mb-1 fw-bold text-dark">Ringkasan Keuangan</h4>
|
||||
<small class="text-muted">Performa keuangan</small>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<select id="yearFilter" class="form-select form-select-sm">
|
||||
<option value="">Semua Tahun</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<canvas id="financeChart" height="140"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI INSIGHT -->
|
||||
<div class="col-xl-4">
|
||||
<div class="modern-card h-100 shadow-sm border-0 rounded-4">
|
||||
<div class="p-4">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<div class="bg-primary rounded-circle p-3 me-3 shadow-sm">
|
||||
<i class="bi bi-robot text-white fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="mb-0 fw-bold text-dark">AI Insight</h5>
|
||||
<small class="text-muted">Rekomendasi otomatis sistem</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="ai-box d-flex flex-column gap-2">
|
||||
|
||||
<?php if(empty($ai_insight)): ?>
|
||||
|
||||
<div class="text-center text-muted py-4">
|
||||
<i class="bi bi-lightbulb-off" style="font-size:28px;"></i>
|
||||
<div class="mt-2 small">Belum ada insight hari ini</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<?php foreach($ai_insight as $ai): ?>
|
||||
|
||||
<?php
|
||||
// =========================
|
||||
// mapping icon & color
|
||||
// =========================
|
||||
$icon = 'bi-info-circle-fill';
|
||||
$colorClass = 'ai-info';
|
||||
|
||||
if($ai->severity == 'critical'){
|
||||
$icon = 'bi-x-octagon-fill';
|
||||
$colorClass = 'ai-danger';
|
||||
} elseif($ai->severity == 'warning'){
|
||||
$icon = 'bi-exclamation-triangle-fill';
|
||||
$colorClass = 'ai-warning';
|
||||
} elseif($ai->severity == 'info'){
|
||||
$icon = 'bi-info-circle-fill';
|
||||
$colorClass = 'ai-info';
|
||||
} elseif($ai->type == 'stock'){
|
||||
$icon = 'bi-box-seam-fill';
|
||||
$colorClass = 'ai-stock';
|
||||
} elseif($ai->type == 'finance'){
|
||||
$icon = 'bi-cash-coin';
|
||||
$colorClass = 'ai-finance';
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="ai-item <?= $colorClass ?>">
|
||||
|
||||
<div class="d-flex align-items-start gap-2">
|
||||
|
||||
<i class="bi <?= $icon ?> fs-5 mt-1"></i>
|
||||
|
||||
<div class="flex-grow-1">
|
||||
<div class="small text-dark">
|
||||
<?= $ai->message; ?>
|
||||
</div>
|
||||
|
||||
<?php if(!empty($ai->meta)): ?>
|
||||
<div class="text-muted small mt-1">
|
||||
<i class="bi bi-info-circle"></i>
|
||||
detail tambahan tersedia
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ================= ACTIVITY FEED ================= -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="modern-card">
|
||||
<div class="p-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h4 class="mb-1 fw-bold text-dark">Aktivitas Terbaru</h4>
|
||||
<small class="text-muted">Aktivitas terakhir di sistem</small>
|
||||
</div>
|
||||
<a href="<?= base_url('dashboard/log_activity') ?>" class="btn btn-outline-primary btn-sm px-4 rounded-pill">
|
||||
Lihat Semua <i class="bi bi-arrow-right ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table modern-table-dashboard table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="rounded-start">Waktu</th>
|
||||
<th>Modul</th>
|
||||
<th>Keterangan</th>
|
||||
<th>Pengguna</th>
|
||||
<th class="rounded-end">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="activityBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- End Container -->
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
let chartInstance = null;
|
||||
|
||||
// ================= INIT =================
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
loadYearOptions();
|
||||
loadChart(currentYear);
|
||||
|
||||
// set default dropdown setelah load
|
||||
setTimeout(() => {
|
||||
$('#yearFilter').val(currentYear);
|
||||
}, 500);
|
||||
|
||||
// ================= LOAD YEAR =================
|
||||
function loadYearOptions() {
|
||||
$.get("<?= base_url('dashboard/get_years'); ?>", function (res) {
|
||||
|
||||
let html = ``;
|
||||
|
||||
res.forEach(y => {
|
||||
html += `<option value="${y.year}">${y.year}</option>`;
|
||||
});
|
||||
|
||||
$('#yearFilter').html(html);
|
||||
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// ================= LOAD CHART =================
|
||||
function loadChart(year = '') {
|
||||
|
||||
$.get("<?= base_url('dashboard/get_chart'); ?>", { year: year }, function (res) {
|
||||
|
||||
const ctx = document.getElementById('financeChart');
|
||||
if (!ctx) return;
|
||||
|
||||
if (chartInstance) chartInstance.destroy();
|
||||
|
||||
const g1 = ctx.getContext('2d').createLinearGradient(0, 0, 0, 250);
|
||||
g1.addColorStop(0, 'rgba(25, 135, 84, 0.18)');
|
||||
g1.addColorStop(1, 'rgba(25, 135, 84, 0.02)');
|
||||
|
||||
const g2 = ctx.getContext('2d').createLinearGradient(0, 0, 0, 250);
|
||||
g2.addColorStop(0, 'rgba(220, 53, 69, 0.18)');
|
||||
g2.addColorStop(1, 'rgba(220, 53, 69, 0.02)');
|
||||
|
||||
chartInstance = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: res.labels || [],
|
||||
datasets: [
|
||||
{
|
||||
label: 'Revenue',
|
||||
data: res.revenue || [],
|
||||
borderColor: '#198754',
|
||||
backgroundColor: g1,
|
||||
borderWidth: 2,
|
||||
tension: 0.35,
|
||||
fill: true,
|
||||
pointRadius: 2,
|
||||
pointHoverRadius: 5
|
||||
},
|
||||
{
|
||||
label: 'Expense',
|
||||
data: res.expense || [],
|
||||
borderColor: '#dc3545',
|
||||
backgroundColor: g2,
|
||||
borderWidth: 2,
|
||||
tension: 0.35,
|
||||
fill: true,
|
||||
pointRadius: 2,
|
||||
pointHoverRadius: 5
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false
|
||||
},
|
||||
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: 'circle',
|
||||
padding: 18,
|
||||
font: {
|
||||
size: 12,
|
||||
weight: '500'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(33,33,33,0.9)',
|
||||
padding: 10,
|
||||
displayColors: false
|
||||
}
|
||||
},
|
||||
|
||||
scales: {
|
||||
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
color: 'rgba(0,0,0,0.05)'
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// ================= FILTER =================
|
||||
$('#yearFilter').on('change', function () {
|
||||
loadChart($(this).val());
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
loadActivity();
|
||||
});
|
||||
|
||||
function loadActivity() {
|
||||
fetch("<?= base_url('dashboard/get_activity') ?>")
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
let html = "";
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
html = `
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted py-2">
|
||||
Tidak ada aktivitas
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
document.getElementById("activityBody").innerHTML = html;
|
||||
return;
|
||||
}
|
||||
|
||||
data.forEach(item => {
|
||||
|
||||
let time = new Date(item.created_at);
|
||||
let jam = time.getHours().toString().padStart(2,'0') + ":" +
|
||||
time.getMinutes().toString().padStart(2,'0');
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td class="fw-semibold text-primary">${jam}</td>
|
||||
<td>${item.module ?? '-'}</td>
|
||||
<td>${item.description ?? '-'}</td>
|
||||
<td class="fw-medium">${item.nama ?? 'System'}</td>
|
||||
<td>${getStatusBadge(item.status)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
document.getElementById("activityBody").innerHTML = html;
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
|
||||
// ================= STATUS BADGE (SIMPLE CLEAN) =================
|
||||
function getStatusBadge(status) {
|
||||
|
||||
if (!status) status = 'success';
|
||||
|
||||
const map = {
|
||||
success: "success",
|
||||
failed: "danger",
|
||||
pending: "warning"
|
||||
};
|
||||
|
||||
let cls = map[status] || "secondary";
|
||||
|
||||
return `<span class="badge bg-${cls}">${status}</span>`;
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,75 @@
|
||||
<div class="container mt-4">
|
||||
|
||||
<div class="card border-0 shadow-sm rounded-4">
|
||||
|
||||
<div class="card-body p-4">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
|
||||
<h5 class="mb-0">
|
||||
Monitoring Absensi
|
||||
</h5>
|
||||
|
||||
<input type="date"
|
||||
id="filterDate"
|
||||
class="form-control"
|
||||
style="max-width:220px"
|
||||
value="<?= date('Y-m-d') ?>">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table id="tableAttendance"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Shift</th>
|
||||
<th>Checkin</th>
|
||||
<th>Checkout</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableAttendance').DataTable({
|
||||
ajax:{
|
||||
url:`<?= base_url(); ?>attendancemonitoring/get_data`,
|
||||
data:function(d){
|
||||
d.date = $('#filterDate').val();
|
||||
},
|
||||
dataSrc:'data'
|
||||
},
|
||||
columns:[
|
||||
{data:0},
|
||||
{data:1},
|
||||
{data:2},
|
||||
{data:3},
|
||||
{data:4},
|
||||
{data:5},
|
||||
{data:6}
|
||||
]
|
||||
});
|
||||
|
||||
$('#filterDate').change(function(){
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,334 @@
|
||||
<div class="container mt-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 class="mb-0">
|
||||
Master Holiday
|
||||
</h5>
|
||||
|
||||
<button class="btn btn-warning btn-add">
|
||||
Tambah Holiday
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table id="tableHoliday"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Nama Holiday</th>
|
||||
<th>Type</th>
|
||||
<th width="15%">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalHoliday">
|
||||
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
|
||||
<div class="modal-content rounded-4">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
|
||||
<h5 class="modal-title">
|
||||
Tambah Holiday
|
||||
</h5>
|
||||
|
||||
<button class="btn-close btn-close-white"
|
||||
data-bs-dismiss="modal"></button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<label class="fw-semibold">
|
||||
Tanggal Holiday
|
||||
</label>
|
||||
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="holiday_date">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Nama Holiday
|
||||
</label>
|
||||
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="holiday_name">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jenis Holiday
|
||||
</label>
|
||||
|
||||
<select class="form-control"
|
||||
id="is_national">
|
||||
|
||||
<option value="1">
|
||||
Nasional
|
||||
</option>
|
||||
|
||||
<option value="0">
|
||||
Perusahaan
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
||||
<button class="btn btn-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
|
||||
Batal
|
||||
|
||||
</button>
|
||||
|
||||
<button class="btn btn-warning"
|
||||
id="btnSimpan">
|
||||
|
||||
Simpan
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableHoliday').DataTable({
|
||||
processing:true,
|
||||
responsive:true,
|
||||
autoWidth:false,
|
||||
ajax:{
|
||||
url:`<?= base_url(); ?>holidays/get_data`,
|
||||
dataSrc:'data'
|
||||
},
|
||||
order:[],
|
||||
columns:[
|
||||
{data:0, orderable:false},
|
||||
{data:1},
|
||||
{data:2},
|
||||
{data:3},
|
||||
{data:4, orderable:false}
|
||||
],
|
||||
language:{
|
||||
processing:`
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-warning"></div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// RESET
|
||||
// =========================================
|
||||
function resetForm(){
|
||||
|
||||
$('#inputId').val('');
|
||||
$('#holiday_date').val('');
|
||||
$('#holiday_name').val('');
|
||||
$('#is_national').val(1);
|
||||
|
||||
$('#modalHoliday .modal-title')
|
||||
.text('Tambah Holiday');
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// ADD
|
||||
// =========================================
|
||||
$('.btn-add').click(function(){
|
||||
|
||||
resetForm();
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','add');
|
||||
|
||||
$('#modalHoliday').modal('show');
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// SAVE UPDATE
|
||||
// =========================================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let data = {
|
||||
id: $('#inputId').val(),
|
||||
holiday_date: $('#holiday_date').val(),
|
||||
holiday_name: $('#holiday_name').val(),
|
||||
is_national: $('#is_national').val()
|
||||
};
|
||||
|
||||
if(
|
||||
!data.holiday_date ||
|
||||
!data.holiday_name
|
||||
){
|
||||
Swal.fire(
|
||||
'Warning',
|
||||
'Tanggal & Nama Holiday wajib diisi',
|
||||
'warning'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? `<?= base_url(); ?>holidays/save`
|
||||
: `<?= base_url(); ?>holidays/update`;
|
||||
|
||||
$.ajax({
|
||||
url:url,
|
||||
type:'POST',
|
||||
data:data,
|
||||
dataType:'json',
|
||||
success:function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalHoliday').modal('hide');
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
},
|
||||
error:function(){
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
'Terjadi kesalahan server',
|
||||
'error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// EDIT
|
||||
// =========================================
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>holidays/detail/` + id,
|
||||
function(res){
|
||||
|
||||
$('#inputId').val(res.id);
|
||||
$('#holiday_date').val(res.holiday_date);
|
||||
$('#holiday_name').val(res.holiday_name);
|
||||
$('#is_national').val(res.is_national);
|
||||
|
||||
$('#modalHoliday .modal-title')
|
||||
.text('Edit Holiday');
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','edit');
|
||||
|
||||
$('#modalHoliday').modal('show');
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// DELETE
|
||||
// =========================================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Yakin hapus?',
|
||||
text:'Data tidak bisa dikembalikan!',
|
||||
icon:'warning',
|
||||
showCancelButton:true,
|
||||
confirmButtonText:'Ya, hapus'
|
||||
}).then((result)=>{
|
||||
|
||||
if(result.isConfirmed){
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>holidays/delete/` + id,
|
||||
function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,418 @@
|
||||
<div class="container mt-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 class="mb-0">
|
||||
Leave Requests
|
||||
</h5>
|
||||
|
||||
<button class="btn btn-warning btn-add">
|
||||
Tambah Leave
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table id="tableLeave"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
|
||||
<tr>
|
||||
|
||||
<th width="5%">No</th>
|
||||
<th>Finger ID</th>
|
||||
<th>Employee</th>
|
||||
<th>Jenis Leave</th>
|
||||
<th>Tanggal Mulai</th>
|
||||
<th>Tanggal Selesai</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th width="15%">Aksi</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalLeave">
|
||||
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
|
||||
<div class="modal-content rounded-4">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
|
||||
<h5 class="modal-title">
|
||||
Tambah Leave
|
||||
</h5>
|
||||
|
||||
<button class="btn-close btn-close-white"
|
||||
data-bs-dismiss="modal"></button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<label class="fw-semibold">
|
||||
Employee
|
||||
</label>
|
||||
|
||||
<select class="form-control select-search"
|
||||
id="employee_id">
|
||||
|
||||
<option value="">
|
||||
Pilih Employee
|
||||
</option>
|
||||
|
||||
<?php foreach($employees as $e): ?>
|
||||
|
||||
<option value="<?= $e->id ?>">
|
||||
|
||||
<?= $e->fingerprint_user_id ?>
|
||||
-
|
||||
<?= $e->full_name ?>
|
||||
|
||||
</option>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
</select>
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jenis Cuti / Izin
|
||||
</label>
|
||||
|
||||
<select class="form-control"
|
||||
id="leave_type">
|
||||
|
||||
<option value="annual">
|
||||
Cuti Tahunan
|
||||
</option>
|
||||
|
||||
<option value="sick">
|
||||
Sakit
|
||||
</option>
|
||||
|
||||
<option value="permit">
|
||||
Izin
|
||||
</option>
|
||||
|
||||
<option value="maternity">
|
||||
Cuti Melahirkan
|
||||
</option>
|
||||
|
||||
<option value="unpaid">
|
||||
Cuti Tidak Dibayar
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Start Date
|
||||
</label>
|
||||
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="start_date">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
End Date
|
||||
</label>
|
||||
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="end_date">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Approval Status
|
||||
</label>
|
||||
|
||||
<select class="form-control"
|
||||
id="approval_status">
|
||||
|
||||
<option value="pending">
|
||||
Pending
|
||||
</option>
|
||||
|
||||
<option value="approved">
|
||||
Approved
|
||||
</option>
|
||||
|
||||
<option value="rejected">
|
||||
Rejected
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Reason
|
||||
</label>
|
||||
|
||||
<textarea class="form-control"
|
||||
id="reason"
|
||||
rows="4"></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
||||
<button class="btn btn-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
|
||||
Batal
|
||||
|
||||
</button>
|
||||
|
||||
<button class="btn btn-warning"
|
||||
id="btnSimpan">
|
||||
|
||||
Simpan
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableLeave').DataTable({
|
||||
processing:true,
|
||||
responsive:true,
|
||||
autoWidth:false,
|
||||
ajax:{
|
||||
url:`<?= base_url(); ?>leaverequests/get_data`,
|
||||
dataSrc:'data'
|
||||
},
|
||||
order:[]
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// RESET
|
||||
// =====================================
|
||||
function resetForm(){
|
||||
|
||||
$('#inputId').val('');
|
||||
$('#employee_id').val('');
|
||||
$('#leave_type').val('annual');
|
||||
$('#start_date').val('');
|
||||
$('#end_date').val('');
|
||||
$('#approval_status').val('pending');
|
||||
$('#reason').val('');
|
||||
|
||||
$('#modalLeave .modal-title')
|
||||
.text('Tambah Leave');
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// ADD
|
||||
// =====================================
|
||||
$('.btn-add').click(function(){
|
||||
|
||||
resetForm();
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','add');
|
||||
|
||||
$('#modalLeave').modal('show');
|
||||
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// SAVE UPDATE
|
||||
// =====================================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let data = {
|
||||
|
||||
id: $('#inputId').val(),
|
||||
|
||||
employee_id: $('#employee_id').val(),
|
||||
|
||||
leave_type: $('#leave_type').val(),
|
||||
|
||||
start_date: $('#start_date').val(),
|
||||
|
||||
end_date: $('#end_date').val(),
|
||||
|
||||
approval_status: $('#approval_status').val(),
|
||||
|
||||
reason: $('#reason').val()
|
||||
};
|
||||
|
||||
if(
|
||||
!data.employee_id ||
|
||||
!data.start_date ||
|
||||
!data.end_date
|
||||
){
|
||||
|
||||
Swal.fire(
|
||||
'Warning',
|
||||
'Data wajib diisi',
|
||||
'warning'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action == 'add'
|
||||
? `<?= base_url(); ?>leaverequests/save`
|
||||
: `<?= base_url(); ?>leaverequests/update`;
|
||||
|
||||
$.ajax({
|
||||
url:url,
|
||||
type:'POST',
|
||||
data:data,
|
||||
dataType:'json',
|
||||
success:function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalLeave').modal('hide');
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// EDIT
|
||||
// =====================================
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>leaverequests/detail/` + id,
|
||||
function(res){
|
||||
|
||||
$('#inputId').val(res.id);
|
||||
|
||||
$('#employee_id').val(res.employee_id);
|
||||
|
||||
$('#leave_type').val(res.leave_type);
|
||||
|
||||
$('#start_date').val(res.start_date);
|
||||
|
||||
$('#end_date').val(res.end_date);
|
||||
|
||||
$('#approval_status')
|
||||
.val(res.approval_status);
|
||||
|
||||
$('#reason').val(res.reason);
|
||||
|
||||
$('#modalLeave .modal-title')
|
||||
.text('Edit Leave');
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','edit');
|
||||
|
||||
$('#modalLeave').modal('show');
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// DELETE
|
||||
// =====================================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Yakin hapus?',
|
||||
text:'Data tidak bisa dikembalikan',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then((result)=>{
|
||||
|
||||
if(result.isConfirmed){
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>leaverequests/delete/` + id,
|
||||
function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,831 @@
|
||||
<div class="container mt-4">
|
||||
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4">
|
||||
|
||||
<div class="card-body p-4">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
|
||||
<div>
|
||||
<h4 class="mb-1">
|
||||
Payroll Karyawan
|
||||
</h4>
|
||||
|
||||
<small class="text-muted">
|
||||
Generate dan kelola payroll karyawan
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
|
||||
<input
|
||||
type="month"
|
||||
id="filterMonth"
|
||||
class="form-control">
|
||||
|
||||
<button
|
||||
class="btn btn-warning"
|
||||
id="btnGeneratePayroll">
|
||||
|
||||
<i class="fa fa-refresh me-1"></i>
|
||||
Generate Payroll
|
||||
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-dark"
|
||||
id="btnReload">
|
||||
|
||||
<i class="fa fa-search me-1"></i>
|
||||
Filter
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TABLE -->
|
||||
<div class="table-responsive">
|
||||
|
||||
<table
|
||||
id="tablePayroll"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
|
||||
<tr>
|
||||
|
||||
<th width="50">
|
||||
No
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Karyawan
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Gaji Pokok
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Pendapatan
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Potongan
|
||||
</th>
|
||||
|
||||
<th>
|
||||
THP
|
||||
</th>
|
||||
|
||||
<th width="180">
|
||||
Status
|
||||
</th>
|
||||
|
||||
<th width="180">
|
||||
Aksi
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ========================================= -->
|
||||
<!-- MODAL DETAIL PAYROLL -->
|
||||
<!-- ========================================= -->
|
||||
<div class="modal fade" id="modalPayroll">
|
||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||
<div class="modal-content border-0 rounded-4">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="modal-header bg-warning text-white">
|
||||
|
||||
<div>
|
||||
|
||||
<h5 class="modal-title mb-0">
|
||||
Detail Payroll
|
||||
</h5>
|
||||
|
||||
<small id="employeeNameHeader"></small>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal">
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- BODY -->
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="payroll_id">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- LEFT -->
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="card border-0 shadow-sm rounded-4 h-100">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
|
||||
<h5 class="mb-0">
|
||||
Pendapatan
|
||||
</h5>
|
||||
|
||||
<button
|
||||
class="btn btn-sm btn-success"
|
||||
id="btnTambahPendapatan">
|
||||
|
||||
<i class="fa fa-plus"></i>
|
||||
Tambah
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- BASIC SALARY -->
|
||||
<div class="border rounded-4 p-3 mb-3 bg-light">
|
||||
|
||||
<div class="fw-bold">
|
||||
Gaji Pokok
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="text-success fw-bold"
|
||||
id="basicSalaryText">
|
||||
|
||||
Rp 0
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ITEMS -->
|
||||
<div id="earningItems"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- RIGHT -->
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="card border-0 shadow-sm rounded-4 h-100">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
|
||||
<h5 class="mb-0">
|
||||
Potongan
|
||||
</h5>
|
||||
|
||||
<button
|
||||
class="btn btn-sm btn-danger"
|
||||
id="btnTambahPotongan">
|
||||
|
||||
<i class="fa fa-plus"></i>
|
||||
Tambah
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ITEMS -->
|
||||
<div id="deductionItems"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TAKE HOME PAY -->
|
||||
<div class="card border-0 shadow-sm rounded-4 mt-4">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row text-center">
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<small class="text-muted">
|
||||
Total Pendapatan
|
||||
</small>
|
||||
|
||||
<h5
|
||||
class="text-success mt-1"
|
||||
id="totalPendapatan">
|
||||
|
||||
Rp 0
|
||||
|
||||
</h5>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<small class="text-muted">
|
||||
Total Potongan
|
||||
</small>
|
||||
|
||||
<h5
|
||||
class="text-danger mt-1"
|
||||
id="totalPotongan">
|
||||
|
||||
Rp 0
|
||||
|
||||
</h5>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<small class="text-muted">
|
||||
Take Home Pay
|
||||
</small>
|
||||
|
||||
<h3
|
||||
class="mt-1 fw-bold"
|
||||
id="totalTakeHome">
|
||||
|
||||
Rp 0
|
||||
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div class="modal-footer">
|
||||
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
|
||||
Tutup
|
||||
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-warning"
|
||||
id="btnSavePayroll">
|
||||
|
||||
<i class="fa fa-save me-1"></i>
|
||||
Simpan Payroll
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ========================================= -->
|
||||
<!-- TEMPLATE ITEM -->
|
||||
<!-- ========================================= -->
|
||||
<script type="text/template" id="templatePayrollItem">
|
||||
|
||||
<div class="payroll-item border rounded-4 p-3 mb-3">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-5">
|
||||
|
||||
<label class="form-label">
|
||||
Nama Item
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
class="form-control item-name"
|
||||
placeholder="Contoh : Bonus Proyek">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
|
||||
<label class="form-label">
|
||||
Nominal
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
class="form-control item-amount"
|
||||
value="0">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
|
||||
<label class="form-label">
|
||||
Tipe
|
||||
</label>
|
||||
|
||||
<select class="form-control item-type">
|
||||
|
||||
<option value="allowance">
|
||||
Tunjangan
|
||||
</option>
|
||||
|
||||
<option value="bonus">
|
||||
Bonus
|
||||
</option>
|
||||
|
||||
<option value="overtime">
|
||||
Lembur
|
||||
</option>
|
||||
|
||||
<option value="deduction">
|
||||
Potongan
|
||||
</option>
|
||||
|
||||
<option value="bpjs">
|
||||
BPJS
|
||||
</option>
|
||||
|
||||
<option value="tax">
|
||||
Pajak
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-1 d-flex align-items-end">
|
||||
|
||||
<button
|
||||
class="btn btn-danger btn-remove-item w-100">
|
||||
|
||||
<i class="fa fa-trash"></i>
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
// =========================================
|
||||
// DEFAULT MONTH
|
||||
// =========================================
|
||||
let now = new Date();
|
||||
|
||||
let month =
|
||||
now.getFullYear()
|
||||
+ '-'
|
||||
+ String(now.getMonth()+1).padStart(2,'0');
|
||||
|
||||
$('#filterMonth').val(month);
|
||||
|
||||
// =========================================
|
||||
// DATATABLE
|
||||
// =========================================
|
||||
let table = $('#tablePayroll').DataTable({
|
||||
|
||||
processing:true,
|
||||
serverSide:false,
|
||||
|
||||
ajax:{
|
||||
url:"<?= base_url('payroll/get_data'); ?>",
|
||||
type:"POST",
|
||||
data:function(d){
|
||||
d.month = $('#filterMonth').val();
|
||||
}
|
||||
},
|
||||
|
||||
columnDefs:[
|
||||
{
|
||||
targets:[2,3,4,5],
|
||||
className:'text-end'
|
||||
}
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// RELOAD
|
||||
// =========================================
|
||||
$('#btnReload').click(function(){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// GENERATE PAYROLL
|
||||
// =========================================
|
||||
$('#btnGeneratePayroll').click(function(){
|
||||
|
||||
let month = $('#filterMonth').val();
|
||||
|
||||
if(!month){
|
||||
|
||||
Swal.fire(
|
||||
'Warning',
|
||||
'Pilih bulan terlebih dahulu',
|
||||
'warning'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
|
||||
title:'Generate Payroll?',
|
||||
text:'Payroll akan dibuat otomatis',
|
||||
icon:'question',
|
||||
showCancelButton:true,
|
||||
confirmButtonText:'Generate'
|
||||
|
||||
}).then((r)=>{
|
||||
|
||||
if(r.isConfirmed){
|
||||
|
||||
$.post(
|
||||
|
||||
"<?= base_url('payroll/generate_payroll'); ?>",
|
||||
|
||||
{
|
||||
month:month
|
||||
},
|
||||
|
||||
function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'json'
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// OPEN DETAIL
|
||||
// =========================================
|
||||
$(document).on(
|
||||
'click',
|
||||
'.btn-edit',
|
||||
function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$('#payroll_id').val(id);
|
||||
|
||||
$('#earningItems').html('');
|
||||
$('#deductionItems').html('');
|
||||
|
||||
$.get(
|
||||
|
||||
"<?= base_url('payroll/detail/'); ?>"+id,
|
||||
|
||||
function(res){
|
||||
|
||||
$('#employeeNameHeader').html(
|
||||
res.employee.full_name
|
||||
);
|
||||
|
||||
$('#basicSalaryText').html(
|
||||
'Rp ' +
|
||||
parseFloat(
|
||||
res.payroll.basic_salary
|
||||
).toLocaleString('id-ID')
|
||||
);
|
||||
|
||||
// =========================
|
||||
// LOAD ITEMS
|
||||
// =========================
|
||||
$.each(res.items,function(i,item){
|
||||
|
||||
appendItem(
|
||||
item.item_name,
|
||||
item.amount,
|
||||
item.item_type
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
calculateTHP();
|
||||
|
||||
$('#modalPayroll').modal('show');
|
||||
|
||||
},
|
||||
|
||||
'json'
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// =========================================
|
||||
// ADD EARNING
|
||||
// =========================================
|
||||
$('#btnTambahPendapatan').click(function(){
|
||||
|
||||
appendItem(
|
||||
'',
|
||||
0,
|
||||
'allowance'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// ADD DEDUCTION
|
||||
// =========================================
|
||||
$('#btnTambahPotongan').click(function(){
|
||||
|
||||
appendItem(
|
||||
'',
|
||||
0,
|
||||
'deduction'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// APPEND ITEM
|
||||
// =========================================
|
||||
function appendItem(
|
||||
name='',
|
||||
amount=0,
|
||||
type='allowance'
|
||||
){
|
||||
|
||||
let html =
|
||||
$('#templatePayrollItem').html();
|
||||
|
||||
let el = $(html);
|
||||
|
||||
el.find('.item-name').val(name);
|
||||
el.find('.item-amount').val(amount);
|
||||
el.find('.item-type').val(type);
|
||||
|
||||
if(
|
||||
type == 'allowance'
|
||||
||
|
||||
type == 'bonus'
|
||||
||
|
||||
type == 'overtime'
|
||||
){
|
||||
|
||||
$('#earningItems').append(el);
|
||||
|
||||
} else {
|
||||
|
||||
$('#deductionItems').append(el);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// REMOVE ITEM
|
||||
// =========================================
|
||||
$(document).on(
|
||||
'click',
|
||||
'.btn-remove-item',
|
||||
function(){
|
||||
|
||||
$(this)
|
||||
.closest('.payroll-item')
|
||||
.remove();
|
||||
|
||||
calculateTHP();
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// =========================================
|
||||
// CALCULATE
|
||||
// =========================================
|
||||
$(document).on(
|
||||
'keyup change',
|
||||
'.item-amount',
|
||||
function(){
|
||||
|
||||
calculateTHP();
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
function calculateTHP(){
|
||||
|
||||
let basicSalary =
|
||||
parseFloat(
|
||||
$('#basicSalaryText')
|
||||
.text()
|
||||
.replace(/[^0-9]/g,'')
|
||||
) || 0;
|
||||
|
||||
let totalEarning = 0;
|
||||
let totalDeduction = 0;
|
||||
|
||||
$('#earningItems .payroll-item').each(function(){
|
||||
|
||||
totalEarning += parseFloat(
|
||||
$(this)
|
||||
.find('.item-amount')
|
||||
.val()
|
||||
) || 0;
|
||||
|
||||
});
|
||||
|
||||
$('#deductionItems .payroll-item').each(function(){
|
||||
|
||||
totalDeduction += parseFloat(
|
||||
$(this)
|
||||
.find('.item-amount')
|
||||
.val()
|
||||
) || 0;
|
||||
|
||||
});
|
||||
|
||||
let thp =
|
||||
(
|
||||
basicSalary
|
||||
+
|
||||
totalEarning
|
||||
)
|
||||
-
|
||||
totalDeduction;
|
||||
|
||||
$('#totalPendapatan').html(
|
||||
'Rp '+
|
||||
totalEarning.toLocaleString('id-ID')
|
||||
);
|
||||
|
||||
$('#totalPotongan').html(
|
||||
'Rp '+
|
||||
totalDeduction.toLocaleString('id-ID')
|
||||
);
|
||||
|
||||
$('#totalTakeHome').html(
|
||||
'Rp '+
|
||||
thp.toLocaleString('id-ID')
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// SAVE PAYROLL
|
||||
// =========================================
|
||||
$('#btnSavePayroll').click(function(){
|
||||
|
||||
let items = [];
|
||||
|
||||
$('#earningItems .payroll-item').each(function(){
|
||||
|
||||
items.push({
|
||||
|
||||
item_name:
|
||||
$(this)
|
||||
.find('.item-name')
|
||||
.val(),
|
||||
|
||||
amount:
|
||||
$(this)
|
||||
.find('.item-amount')
|
||||
.val(),
|
||||
|
||||
item_type:
|
||||
$(this)
|
||||
.find('.item-type')
|
||||
.val()
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$('#deductionItems .payroll-item').each(function(){
|
||||
|
||||
items.push({
|
||||
|
||||
item_name:
|
||||
$(this)
|
||||
.find('.item-name')
|
||||
.val(),
|
||||
|
||||
amount:
|
||||
$(this)
|
||||
.find('.item-amount')
|
||||
.val(),
|
||||
|
||||
item_type:
|
||||
$(this)
|
||||
.find('.item-type')
|
||||
.val()
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$.post(
|
||||
|
||||
"<?= base_url('payroll/save_items'); ?>",
|
||||
|
||||
{
|
||||
|
||||
payroll_id:
|
||||
$('#payroll_id').val(),
|
||||
|
||||
items:items
|
||||
|
||||
},
|
||||
|
||||
function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalPayroll').modal('hide');
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'json'
|
||||
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,411 @@
|
||||
<div class="container mt-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 class="mb-0">
|
||||
Master Shift
|
||||
</h5>
|
||||
|
||||
<button class="btn btn-warning btn-add">
|
||||
Tambah Shift
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table id="tableShifts"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama Shift</th>
|
||||
<th>Jam Masuk</th>
|
||||
<th>Jam Pulang</th>
|
||||
<th>Toleransi</th>
|
||||
<th>Jam Kerja</th>
|
||||
<th>Type</th>
|
||||
<th width="15%">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalShift">
|
||||
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
|
||||
<div class="modal-content rounded-4">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
|
||||
<h5 class="modal-title">
|
||||
Tambah Shift
|
||||
</h5>
|
||||
|
||||
<button class="btn-close btn-close-white"
|
||||
data-bs-dismiss="modal"></button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<label class="fw-semibold">
|
||||
Kode Shift
|
||||
</label>
|
||||
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="shift_code">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Nama Shift
|
||||
</label>
|
||||
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="shift_name">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jam Masuk
|
||||
</label>
|
||||
|
||||
<input type="time"
|
||||
class="form-control"
|
||||
id="checkin_time">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jam Pulang
|
||||
</label>
|
||||
|
||||
<input type="time"
|
||||
class="form-control"
|
||||
id="checkout_time">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Toleransi Telat
|
||||
</label>
|
||||
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
id="late_tolerance_minutes">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jam Kerja
|
||||
</label>
|
||||
|
||||
<input type="number"
|
||||
step="0.1"
|
||||
class="form-control"
|
||||
id="work_hours">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<label class="fw-semibold mt-2">
|
||||
Jenis Shift
|
||||
</label>
|
||||
|
||||
<select class="form-control"
|
||||
id="is_night_shift">
|
||||
|
||||
<option value="0">
|
||||
Normal Shift
|
||||
</option>
|
||||
|
||||
<option value="1">
|
||||
Night Shift
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
||||
<button class="btn btn-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
|
||||
Batal
|
||||
|
||||
</button>
|
||||
|
||||
<button class="btn btn-warning"
|
||||
id="btnSimpan">
|
||||
|
||||
Simpan
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableShifts').DataTable({
|
||||
processing:true,
|
||||
responsive:true,
|
||||
autoWidth:false,
|
||||
ajax:{
|
||||
url: `<?= base_url(); ?>` + 'shifts/get_data',
|
||||
dataSrc:'data'
|
||||
},
|
||||
order:[],
|
||||
columns:[
|
||||
{data:0, orderable:false},
|
||||
{data:1},
|
||||
{data:2},
|
||||
{data:3},
|
||||
{data:4},
|
||||
{data:5},
|
||||
{data:6},
|
||||
{data:7},
|
||||
{data:8, orderable:false}
|
||||
],
|
||||
language:{
|
||||
processing:`
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-warning"></div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// RESET
|
||||
// =========================================
|
||||
function resetForm(){
|
||||
|
||||
$('#inputId').val('');
|
||||
$('#shift_code').val('');
|
||||
$('#shift_name').val('');
|
||||
$('#checkin_time').val('');
|
||||
$('#checkout_time').val('');
|
||||
$('#late_tolerance_minutes').val(0);
|
||||
$('#work_hours').val(8);
|
||||
$('#is_night_shift').val(0);
|
||||
|
||||
$('#modalShift .modal-title')
|
||||
.text('Tambah Shift');
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// ADD
|
||||
// =========================================
|
||||
$('.btn-add').click(function(){
|
||||
|
||||
resetForm();
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','add');
|
||||
|
||||
$('#modalShift').modal('show');
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// SAVE UPDATE
|
||||
// =========================================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let data = {
|
||||
id: $('#inputId').val(),
|
||||
shift_code: $('#shift_code').val(),
|
||||
shift_name: $('#shift_name').val(),
|
||||
checkin_time: $('#checkin_time').val(),
|
||||
checkout_time: $('#checkout_time').val(),
|
||||
late_tolerance_minutes: $('#late_tolerance_minutes').val(),
|
||||
work_hours: $('#work_hours').val(),
|
||||
is_night_shift: $('#is_night_shift').val()
|
||||
};
|
||||
|
||||
if(
|
||||
!data.shift_code ||
|
||||
!data.shift_name
|
||||
){
|
||||
Swal.fire(
|
||||
'Warning',
|
||||
'Kode & Nama Shift wajib diisi',
|
||||
'warning'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? `<?= base_url(); ?>` + 'shifts/save'
|
||||
: `<?= base_url(); ?>` + 'shifts/update';
|
||||
|
||||
$.ajax({
|
||||
url:url,
|
||||
type:'POST',
|
||||
data:data,
|
||||
dataType:'json',
|
||||
success:function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalShift').modal('hide');
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
},
|
||||
error:function(){
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
'Terjadi kesalahan server',
|
||||
'error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// EDIT
|
||||
// =========================================
|
||||
$(document).on('click','.btn-edit',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>` + 'shifts/detail/' + id,
|
||||
function(res){
|
||||
|
||||
$('#inputId').val(res.id);
|
||||
$('#shift_code').val(res.shift_code);
|
||||
$('#shift_name').val(res.shift_name);
|
||||
$('#checkin_time').val(res.checkin_time);
|
||||
$('#checkout_time').val(res.checkout_time);
|
||||
$('#late_tolerance_minutes').val(res.late_tolerance_minutes);
|
||||
$('#work_hours').val(res.work_hours);
|
||||
$('#is_night_shift').val(res.is_night_shift);
|
||||
|
||||
$('#modalShift .modal-title')
|
||||
.text('Edit Shift');
|
||||
|
||||
$('#btnSimpan')
|
||||
.data('action','edit');
|
||||
|
||||
$('#modalShift').modal('show');
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =========================================
|
||||
// DELETE
|
||||
// =========================================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Yakin hapus?',
|
||||
text:'Data tidak bisa dikembalikan!',
|
||||
icon:'warning',
|
||||
showCancelButton:true,
|
||||
confirmButtonText:'Ya, hapus'
|
||||
}).then((result)=>{
|
||||
|
||||
if(result.isConfirmed){
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>` + 'shifts/delete/' + id,
|
||||
function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire(
|
||||
'Sukses',
|
||||
res.message,
|
||||
'success'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire(
|
||||
'Error',
|
||||
res.message,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
echo "\nERROR: ",
|
||||
$heading,
|
||||
"\n\n",
|
||||
$message,
|
||||
"\n\n";
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
echo "\nDatabase error: ",
|
||||
$heading,
|
||||
"\n\n",
|
||||
$message,
|
||||
"\n\n";
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
|
||||
|
||||
An uncaught Exception was encountered
|
||||
|
||||
Type: <?php echo get_class($exception), "\n"; ?>
|
||||
Message: <?php echo $message, "\n"; ?>
|
||||
Filename: <?php echo $exception->getFile(), "\n"; ?>
|
||||
Line Number: <?php echo $exception->getLine(); ?>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
|
||||
|
||||
Backtrace:
|
||||
<?php foreach ($exception->getTrace() as $error): ?>
|
||||
<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
|
||||
File: <?php echo $error['file'], "\n"; ?>
|
||||
Line: <?php echo $error['line'], "\n"; ?>
|
||||
Function: <?php echo $error['function'], "\n\n"; ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
echo "\nERROR: ",
|
||||
$heading,
|
||||
"\n\n",
|
||||
$message,
|
||||
"\n\n";
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
|
||||
|
||||
A PHP Error was encountered
|
||||
|
||||
Severity: <?php echo $severity, "\n"; ?>
|
||||
Message: <?php echo $message, "\n"; ?>
|
||||
Filename: <?php echo $filepath, "\n"; ?>
|
||||
Line Number: <?php echo $line; ?>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
|
||||
|
||||
Backtrace:
|
||||
<?php foreach (debug_backtrace() as $error): ?>
|
||||
<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
|
||||
File: <?php echo $error['file'], "\n"; ?>
|
||||
Line: <?php echo $error['line'], "\n"; ?>
|
||||
Function: <?php echo $error['function'], "\n\n"; ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= $heading; ?></title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<style>
|
||||
/* ================================
|
||||
🔥 GLOBAL STYLE
|
||||
================================ */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background: linear-gradient(135deg, #ff8c00, #ffb347);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
🔥 CARD
|
||||
================================ */
|
||||
.error-card {
|
||||
background: #fff;
|
||||
padding: 40px 35px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
max-width: 420px;
|
||||
width: 90%;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
|
||||
animation: fadeIn 0.4s ease;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
🔥 TITLE
|
||||
================================ */
|
||||
.error-code {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #ff8c00;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
🔥 BUTTON
|
||||
================================ */
|
||||
.btn-dashboard {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #ff8c00;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.btn-dashboard:hover {
|
||||
background: #e67700;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
🔥 ANIMATION
|
||||
================================ */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="error-card">
|
||||
|
||||
<!-- 🔥 KODE ERROR -->
|
||||
<div class="error-code">
|
||||
<?= strpos($heading, '404') !== false ? '404' : 'Error'; ?>
|
||||
</div>
|
||||
|
||||
<!-- 🔥 TITLE -->
|
||||
<div class="error-title">
|
||||
<?= $heading; ?>
|
||||
</div>
|
||||
|
||||
<!-- 🔥 MESSAGE -->
|
||||
<div class="error-message">
|
||||
<?= strip_tags($message); ?>
|
||||
</div>
|
||||
|
||||
<!-- 🔥 BUTTON -->
|
||||
<a href="<?= base_url('dashboard'); ?>" class="btn-dashboard">
|
||||
Kembali ke Dashboard
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Database Error</title>
|
||||
<style type="text/css">
|
||||
|
||||
::selection { background-color: #E13300; color: white; }
|
||||
::-moz-selection { background-color: #E13300; color: white; }
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
margin: 40px;
|
||||
font: 13px/20px normal Helvetica, Arial, sans-serif;
|
||||
color: #4F5155;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #003399;
|
||||
background-color: transparent;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #444;
|
||||
background-color: transparent;
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
font-size: 19px;
|
||||
font-weight: normal;
|
||||
margin: 0 0 14px 0;
|
||||
padding: 14px 15px 10px 15px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Consolas, Monaco, Courier New, Courier, monospace;
|
||||
font-size: 12px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #D0D0D0;
|
||||
color: #002166;
|
||||
display: block;
|
||||
margin: 14px 0 14px 0;
|
||||
padding: 12px 10px 12px 10px;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin: 10px;
|
||||
border: 1px solid #D0D0D0;
|
||||
box-shadow: 0 0 8px #D0D0D0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 12px 15px 12px 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<h1><?php echo $heading; ?></h1>
|
||||
<?php echo $message; ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?>
|
||||
|
||||
<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
|
||||
|
||||
<h4>An uncaught Exception was encountered</h4>
|
||||
|
||||
<p>Type: <?php echo get_class($exception); ?></p>
|
||||
<p>Message: <?php echo $message; ?></p>
|
||||
<p>Filename: <?php echo $exception->getFile(); ?></p>
|
||||
<p>Line Number: <?php echo $exception->getLine(); ?></p>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
|
||||
|
||||
<p>Backtrace:</p>
|
||||
<?php foreach ($exception->getTrace() as $error): ?>
|
||||
|
||||
<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
|
||||
|
||||
<p style="margin-left:10px">
|
||||
File: <?php echo $error['file']; ?><br />
|
||||
Line: <?php echo $error['line']; ?><br />
|
||||
Function: <?php echo $error['function']; ?>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>403 Forbidden</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background: linear-gradient(135deg, #ff8c00, #ffb347);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error-card {
|
||||
background: #fff;
|
||||
padding: 40px 35px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
max-width: 420px;
|
||||
width: 90%;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
|
||||
animation: fadeIn 0.4s ease;
|
||||
}
|
||||
|
||||
.error-code {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #ff8c00;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.btn-dashboard {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #ff8c00;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.btn-dashboard:hover {
|
||||
background: #e67700;
|
||||
}
|
||||
|
||||
.btn-back {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
padding: 10px 20px;
|
||||
background: #6c757d;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.btn-back:hover {
|
||||
background: #5a6268;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="error-card">
|
||||
|
||||
<!-- 🔥 ICON -->
|
||||
<div style="font-size:50px; margin-bottom:10px;">🔒</div>
|
||||
|
||||
<!-- 🔥 CODE -->
|
||||
<div class="error-code">403</div>
|
||||
|
||||
<!-- 🔥 TITLE -->
|
||||
<div class="error-title">Akses Ditolak</div>
|
||||
|
||||
<!-- 🔥 MESSAGE -->
|
||||
<div class="error-message">
|
||||
Anda tidak memiliki izin untuk mengakses halaman ini.<br>
|
||||
Silakan hubungi administrator jika ini adalah kesalahan.
|
||||
</div>
|
||||
|
||||
<a href="javascript:history.back()" class="btn-back">
|
||||
Kembali
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?>
|
||||
|
||||
<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
|
||||
|
||||
<h4>A PHP Error was encountered</h4>
|
||||
|
||||
<p>Severity: <?php echo $severity; ?></p>
|
||||
<p>Message: <?php echo $message; ?></p>
|
||||
<p>Filename: <?php echo $filepath; ?></p>
|
||||
<p>Line Number: <?php echo $line; ?></p>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
|
||||
|
||||
<p>Backtrace:</p>
|
||||
<?php foreach (debug_backtrace() as $error): ?>
|
||||
|
||||
<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
|
||||
|
||||
<p style="margin-left:10px">
|
||||
File: <?php echo $error['file'] ?><br />
|
||||
Line: <?php echo $error['line'] ?><br />
|
||||
Function: <?php echo $error['function'] ?>
|
||||
</p>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th, td { border:1px solid #000; padding:6px; font-size:12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h3>Data Santri</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama</th>
|
||||
<th>NIS</th>
|
||||
<th>Kelas</th>
|
||||
<th>Alamat</th>
|
||||
<th>Nama Wali</th>
|
||||
<th>No WA</th>
|
||||
<th>Email</th>
|
||||
<th>Tahun Masuk</th>
|
||||
<th>Kamar</th>
|
||||
<th>Gedung</th>
|
||||
<th>Jumlah Kumjungan</th>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
$no = 1;
|
||||
foreach ($siswa as $s) { ?>
|
||||
<tr>
|
||||
<td><?= $no ?></td>
|
||||
<td><?= $s->nama ?></td>
|
||||
<td><?= $s->nis ?></td>
|
||||
<td><?= $s->nama_kelas ?></td>
|
||||
<td><?= $s->alamat ?></td>
|
||||
<td><?= $s->nama_wali ?></td>
|
||||
<td><?= $s->nomor_whatsapp ?></td>
|
||||
<td><?= $s->email ?></td>
|
||||
<td><?= $s->tahun_masuk ?></td>
|
||||
<td><?= $s->nama_kamar ?></td>
|
||||
<td><?= $s->nama_gedung_kamar ?></td>
|
||||
<td><?= $s->jumlah_kunjungan ?></td>
|
||||
</tr>
|
||||
<?php $no++; } ?>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,129 @@
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">History Kunjungan</h5>
|
||||
<input type="text" id="dateRangeFilter" class="form-control me-2" placeholder="Pilih rentang waktu..." style="max-width: 200px;">
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableHistory" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama</th>
|
||||
<th>NIS</th>
|
||||
<th>Kelas</th>
|
||||
<th>Kamar</th>
|
||||
<th>Nama Wali</th>
|
||||
<th>Alamat</th>
|
||||
<th>Jam Masuk</th>
|
||||
<th>Petugas Masuk</th>
|
||||
<th>Jam Keluar</th>
|
||||
<th>Petugas Keluar</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
let isInitialLoad = true;
|
||||
$('#dateRangeFilter').val('');
|
||||
|
||||
$('#dateRangeFilter').daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: { cancelLabel: false, format: 'YYYY-MM-DD' },
|
||||
linkedCalendars: false
|
||||
});
|
||||
|
||||
$('#dateRangeFilter').on('apply.daterangepicker', function(ev, picker) {
|
||||
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
$('#dateRangeFilter').on('cancel.daterangepicker', function(ev, picker) {
|
||||
$(this).val('');
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
let table = $('#tableHistory').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"l f>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('history/get_data'); ?>",
|
||||
type: "POST",
|
||||
data: function(d) {
|
||||
if (isInitialLoad) { isInitialLoad = false; return; }
|
||||
|
||||
let dateVal = $('#dateRangeFilter').val();
|
||||
if (dateVal) {
|
||||
let dates = dateVal.split(' - ');
|
||||
if (dates[0]) d.startDate = dates[0];
|
||||
if (dates[1]) d.endDate = dates[1];
|
||||
}
|
||||
// jika dateVal kosong, startDate dan endDate tidak dikirim
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false }, // No
|
||||
{ data: 1 }, // Nama
|
||||
{ data: 2 }, // NIS
|
||||
{ data: 3 }, // Kelas
|
||||
{ data: 4 }, // Kelas
|
||||
{ data: 5 }, // Nama Wali
|
||||
{ data: 6 }, // Alamat
|
||||
{
|
||||
data: 7, // Jam Masuk
|
||||
render: function(data) { return data ? data : ''; }
|
||||
},
|
||||
{
|
||||
data: 8, // Media Masuk
|
||||
orderable: false,
|
||||
render: function(data) { return data ? data : ''; }
|
||||
},
|
||||
{
|
||||
data: 9, // Jam Keluar
|
||||
render: function(data) { return data ? data : ''; }
|
||||
},
|
||||
{
|
||||
data: 10, // Media Keluar
|
||||
orderable: false,
|
||||
render: function(data) { return data ? data : ''; }
|
||||
}
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input').attr('placeholder', 'Cari nama, nis, kelas...').css({
|
||||
'padding': '6px 12px',
|
||||
'border-radius': '6px',
|
||||
'border': '1px solid #ced4da',
|
||||
'font-size': '0.9rem',
|
||||
'box-sizing': 'border-box'
|
||||
});
|
||||
|
||||
table.on('draw', function() {
|
||||
$('#tableHistory tbody tr').each(function() {
|
||||
$(this).find('td').each(function(index) {
|
||||
let header = $('#tableHistory thead th').eq(index).text().trim();
|
||||
$(this).attr('data-label', header + ' : ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,575 @@
|
||||
<div class="container mt-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>
|
||||
<?php if($active_menu == 'invoice_unpaid') echo 'Invoice Berjalan'; ?>
|
||||
<?php if($active_menu == 'invoice_paid') echo 'Riwayat Invoice'; ?>
|
||||
<?php if($active_menu == 'invoice_draft') echo 'Draft Invoice'; ?>
|
||||
</h5>
|
||||
|
||||
<?php if($active_menu == 'invoice_draft') : ?>
|
||||
<button class="btn btn-warning btn-add">Buat Invoice</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table modern-table align-middle w-100" id="tableInvoice">
|
||||
<!-- <table id="tableInvoice" class="table table-bordered"> -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>No Invoice</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Jatuh Tempo</th>
|
||||
<th>Customer</th>
|
||||
<th>Total</th>
|
||||
<th>Terbayar</th>
|
||||
<th>Sisa</th>
|
||||
<th>Status</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalInvoice">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Buat Invoice</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="customer_id">Customer</label>
|
||||
<select id="customer_id" class="form-control mb-2"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="tanggal">Tanggal</label>
|
||||
<input type="date" id="tanggal" class="form-control mb-2">
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="jatuh_tempo">Jatuh Tempo</label>
|
||||
<input type="date" id="jatuh_tempo" class="form-control mb-3">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="modalBayar">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>
|
||||
Bayar Invoice -
|
||||
<span id="customerName"></span>
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="bayar_invoice_id">
|
||||
|
||||
<!-- INFO BOX -->
|
||||
<div class="row mb-3">
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="p-2 border rounded">
|
||||
<small>Total Invoice</small>
|
||||
<h5 id="invoiceTotal">0</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="p-2 border rounded">
|
||||
<small>Total Bayar</small>
|
||||
<h5 id="totalBayar">0</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="p-2 border rounded">
|
||||
<small>Sisa (Balance)</small>
|
||||
<h5 id="balance">0</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<label>Tanggal Bayar</label>
|
||||
<input type="date" id="tanggal_bayar" class="form-control mb-2">
|
||||
|
||||
<table class="table" id="tableBayar">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Debit</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<button class="btn btn-sm btn-primary btn-add-bayar">
|
||||
+ Tambah Pembayaran
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnProsesBayar">
|
||||
Proses Bayar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let url = "";
|
||||
let accountOptions = '';
|
||||
let accountOptionsAssets = '';
|
||||
|
||||
// =========================
|
||||
// URL BY MENU
|
||||
// =========================
|
||||
<?php if($active_menu == 'invoice_unpaid'): ?>
|
||||
url = "<?= base_url('invoices/get_data/unpaid'); ?>";
|
||||
<?php elseif($active_menu == 'invoice_paid'): ?>
|
||||
url = "<?= base_url('invoices/get_data/paid'); ?>";
|
||||
<?php elseif($active_menu == 'invoice_draft'): ?>
|
||||
url = "<?= base_url('invoices/get_data/draft'); ?>";
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
// =========================
|
||||
// LOAD CUSTOMER
|
||||
// =========================
|
||||
$.get("<?= base_url('invoices/get_customers'); ?>", res => {
|
||||
let opt = '<option value="">Pilih Customer</option>';
|
||||
res.forEach(c => opt += `<option value="${c.id}">${c.nama}</option>`);
|
||||
$('#customer_id').html(opt);
|
||||
}, 'json');
|
||||
|
||||
|
||||
// =========================
|
||||
// LOAD ACCOUNT (PENDAPATAN)
|
||||
// =========================
|
||||
$.get("<?= base_url('invoices/get_accounts'); ?>", res => {
|
||||
accountOptions = '<option value="">Pilih Akun</option>';
|
||||
res.forEach(a => {
|
||||
accountOptions += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
|
||||
});
|
||||
}, 'json');
|
||||
|
||||
|
||||
// =========================
|
||||
// LOAD ACCOUNT (ASSET / KAS)
|
||||
// =========================
|
||||
$.get("<?= base_url('invoices/get_accounts_assets'); ?>", res => {
|
||||
accountOptionsAssets = '<option value="">Pilih Akun</option>';
|
||||
res.forEach(a => {
|
||||
accountOptionsAssets += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
|
||||
});
|
||||
}, 'json');
|
||||
|
||||
|
||||
// =========================
|
||||
// DATATABLE
|
||||
// =========================
|
||||
let table = $('#tableInvoice').DataTable({
|
||||
ajax:{
|
||||
url: url,
|
||||
type:"POST"
|
||||
},
|
||||
columnDefs:[
|
||||
{ targets:[3], className:'text-end' }
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// ADD ITEM ROW
|
||||
// =========================
|
||||
$('.btn-add-row').click(function(){
|
||||
|
||||
if(!accountOptions){
|
||||
Swal.fire('Warning','Account belum siap, tunggu sebentar','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
$('#tableDetail tbody').append(`
|
||||
<tr>
|
||||
<td>
|
||||
<select class="form-control account_id">${accountOptions}</select>
|
||||
</td>
|
||||
<td><input type="text" class="form-control nama_item"></td>
|
||||
<td><input type="number" class="form-control qty" value="1"></td>
|
||||
<td><input type="text" class="form-control harga format-rupiah"></td>
|
||||
<td class="subtotal text-end">0</td>
|
||||
<td><button class="btn btn-danger btn-remove">X</button></td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// HITUNG SUBTOTAL
|
||||
// =========================
|
||||
$(document).on('input','.qty,.harga',function(){
|
||||
|
||||
let tr = $(this).closest('tr');
|
||||
let qty = parseFloat(tr.find('.qty').val()) || 0;
|
||||
let harga = parseFloat(tr.find('.harga').val()) || 0;
|
||||
|
||||
let sub = qty * harga;
|
||||
|
||||
tr.find('.subtotal').text(sub.toLocaleString('id-ID'));
|
||||
calcTotal();
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// TOTAL
|
||||
// =========================
|
||||
function calcTotal(){
|
||||
let total = 0;
|
||||
|
||||
$('.subtotal').each(function(){
|
||||
total += parseFloat($(this).text().replace(/\./g,'')) || 0;
|
||||
});
|
||||
|
||||
$('#grandTotal').text(total.toLocaleString('id-ID'));
|
||||
}
|
||||
|
||||
|
||||
// =========================
|
||||
// REMOVE ROW (GLOBAL)
|
||||
// =========================
|
||||
$(document).on('click','.btn-remove',function(){
|
||||
$(this).closest('tr').remove();
|
||||
calcTotal();
|
||||
hitungBayar();
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// OPEN MODAL INVOICE
|
||||
// =========================
|
||||
$('.btn-add').click(function(){
|
||||
$('#modalInvoice').modal('show');
|
||||
$('#tableDetail tbody').html('');
|
||||
$('#grandTotal').text('0');
|
||||
});
|
||||
|
||||
// =========================
|
||||
// SIMPAN INVOICE
|
||||
// =========================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let nama_item=[], qty=[], harga=[], account_id=[];
|
||||
|
||||
$('#tableDetail tbody tr').each(function(){
|
||||
nama_item.push($(this).find('.nama_item').val());
|
||||
qty.push($(this).find('.qty').val());
|
||||
harga.push($(this).find('.harga').val());
|
||||
account_id.push($(this).find('.account_id').val());
|
||||
});
|
||||
|
||||
$.post("<?= base_url('invoices/save'); ?>",{
|
||||
customer_id: $('#customer_id').val(),
|
||||
tanggal: $('#tanggal').val(),
|
||||
jatuh_tempo: $('#jatuh_tempo').val()
|
||||
}, function(res){
|
||||
|
||||
if(res.status){
|
||||
Swal.fire({
|
||||
icon:'success',
|
||||
title:'Berhasil',
|
||||
text:'Invoice berhasil disimpan',
|
||||
timer:1500,
|
||||
showConfirmButton:false
|
||||
}).then(()=>{
|
||||
window.location.href = "<?= base_url('invoices/detail/'); ?>" + res.invoice_id;
|
||||
});
|
||||
}else{
|
||||
Swal.fire('Error', res.message || 'Gagal simpan', 'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
let id = $(this).data('id');
|
||||
window.location.href = "<?= base_url('invoices/detail/'); ?>" + id;
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// OPEN MODAL BAYAR
|
||||
// =========================
|
||||
$(document).on('click','.btn-bayar',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
let total = parseFloat($(this).data('total') - $(this).data('terbayar')) || 0;
|
||||
let customer = $(this).data('customer');
|
||||
|
||||
$('#bayar_invoice_id').val(id);
|
||||
$('#customerName').text(customer);
|
||||
|
||||
$('#invoiceTotal').text(total.toLocaleString('id-ID'));
|
||||
|
||||
$('#tableBayar tbody').html('');
|
||||
$('#totalBayar').text('0');
|
||||
$('#balance').text(total.toLocaleString('id-ID'));
|
||||
|
||||
$('#modalBayar').modal('show');
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// ADD ROW BAYAR
|
||||
// =========================
|
||||
$('.btn-add-bayar').click(function(){
|
||||
|
||||
if(!accountOptionsAssets){
|
||||
Swal.fire('Warning','Account belum siap','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
$('#tableBayar tbody').append(`
|
||||
<tr>
|
||||
<td><select class="form-control account_id">${accountOptionsAssets}</select></td>
|
||||
<td><input type="text" class="form-control debit text-end format-rupiah"></td>
|
||||
<td><button class="btn btn-danger btn-remove">X</button></td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// HITUNG BAYAR
|
||||
// =========================
|
||||
$(document).on('input','.debit',function(){
|
||||
hitungBayar();
|
||||
});
|
||||
|
||||
function hitungBayar(){
|
||||
|
||||
let totalBayar = 0;
|
||||
|
||||
$('#tableBayar .debit').each(function(){
|
||||
totalBayar += parseFloat($(this).val()) || 0;
|
||||
});
|
||||
|
||||
let invoiceTotal = parseFloat($('#invoiceTotal').text().replace(/\./g,'')) || 0;
|
||||
let balance = invoiceTotal - totalBayar;
|
||||
|
||||
$('#totalBayar').text(totalBayar.toLocaleString('id-ID'));
|
||||
$('#balance').text(balance.toLocaleString('id-ID'));
|
||||
|
||||
if(balance < 0){
|
||||
$('#balance').css('color','red');
|
||||
}else if(balance === 0){
|
||||
$('#balance').css('color','green');
|
||||
}else{
|
||||
$('#balance').css('color','orange');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =========================
|
||||
// PROSES BAYAR
|
||||
// =========================
|
||||
$('#btnProsesBayar').click(function(){
|
||||
|
||||
let id = $('#bayar_invoice_id').val();
|
||||
let tanggal_bayar = $('#tanggal_bayar').val();
|
||||
|
||||
if(!tanggal_bayar){
|
||||
Swal.fire('Warning','Tanggal bayar wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let detail = [];
|
||||
let totalBayar = 0;
|
||||
|
||||
$('#tableBayar tbody tr').each(function(){
|
||||
|
||||
let account_id = $(this).find('.account_id').val();
|
||||
let debit = parseFloat($(this).find('.debit').val()) || 0;
|
||||
|
||||
if(account_id && debit > 0){
|
||||
detail.push({ account_id, amount: debit });
|
||||
totalBayar += debit;
|
||||
}
|
||||
});
|
||||
|
||||
if(detail.length === 0){
|
||||
Swal.fire('Warning','Isi minimal 1 pembayaran','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let invoiceTotal = parseFloat($('#invoiceTotal').text().replace(/\./g,'')) || 0;
|
||||
|
||||
if(totalBayar > invoiceTotal){
|
||||
Swal.fire('Error','Pembayaran melebihi total invoice','error');
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title:'Memproses...',
|
||||
allowOutsideClick:false,
|
||||
didOpen:()=>Swal.showLoading()
|
||||
});
|
||||
|
||||
$.post("<?= base_url('invoices/bayar'); ?>", {
|
||||
invoice_id: id,
|
||||
tanggal_bayar,
|
||||
detail
|
||||
}, function(res){
|
||||
|
||||
if(res.status){
|
||||
Swal.fire('Success','Pembayaran sukses','success');
|
||||
$('#modalBayar').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
}else{
|
||||
Swal.fire('Error', res.message || 'Gagal', 'error');
|
||||
}
|
||||
|
||||
}, 'json');
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// POSTING
|
||||
// =========================
|
||||
$(document).on('click','.btn-posting',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Posting Invoice?',
|
||||
text:'Akan masuk ke piutang',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(result=>{
|
||||
|
||||
if(result.isConfirmed){
|
||||
|
||||
Swal.fire({
|
||||
title:'Processing...',
|
||||
allowOutsideClick:false,
|
||||
didOpen:()=>Swal.showLoading()
|
||||
});
|
||||
|
||||
$.post("<?= base_url('invoices/posting'); ?>",{invoice_id:id},function(){
|
||||
Swal.fire('Success','Berhasil diposting','success');
|
||||
table.ajax.reload(null,false);
|
||||
},'json');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
$(document).on('click', '.btn-delete', function () {
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus Invoice?',
|
||||
text: 'Data tidak bisa dikembalikan',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#dc3545',
|
||||
confirmButtonText: 'Ya, Hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
|
||||
if (result.isConfirmed) {
|
||||
|
||||
Swal.fire({
|
||||
title: 'Menghapus...',
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => Swal.showLoading()
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('invoices/delete/'); ?>" + id,
|
||||
type: "GET",
|
||||
dataType: "json"
|
||||
})
|
||||
.done(function (res) {
|
||||
|
||||
if (res.status) {
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: 'Invoice berhasil dihapus'
|
||||
});
|
||||
|
||||
// reload datatable
|
||||
if (typeof table !== 'undefined') {
|
||||
table.ajax.reload(null, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Tidak bisa dihapus'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.fail(function () {
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Terjadi kesalahan koneksi'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,757 @@
|
||||
<div class="container mt-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>Data Barang Dalam Perjalanan</h5>
|
||||
<div class="text-end">
|
||||
<button class="btn btn-warning btn-add btn-add-item mr-2">Tambah Barang</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableItems" class="table modern-table w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Tanggal Beli</th>
|
||||
<th>Kode Barang</th>
|
||||
<th>Nama</th>
|
||||
<th style="max-width: 150px;">Gudang</th>
|
||||
<th>Stok</th>
|
||||
<th>Harga Beli</th>
|
||||
<th>Harga Jual</th>
|
||||
<th>Create at</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalItem">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Item</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<div id="group_tanggal">
|
||||
<label>Tanggal Pembelian</label>
|
||||
<input type="date" id="tanggal_beli" class="form-control">
|
||||
</div>
|
||||
|
||||
<div id="group_kode">
|
||||
<label class="mt-2">Kode Barang</label>
|
||||
<select id="kode_barang" class="form-control select-search"></select>
|
||||
</div>
|
||||
|
||||
<label>Nama Barang</label>
|
||||
<input type="text" id="nama_barang" class="form-control">
|
||||
|
||||
<div id="group_qty">
|
||||
<label class="mt-2">Jumlah Barang</label>
|
||||
<input type="number" id="qty" class="form-control">
|
||||
</div>
|
||||
|
||||
<label class="mt-2">Harga Beli</label>
|
||||
<input type="text" id="harga_beli" class="form-control format-rupiah">
|
||||
|
||||
<label class="mt-2">Harga Jual</label>
|
||||
<input type="text" id="harga_jual" class="form-control format-rupiah">
|
||||
|
||||
<div id="group_warehouse">
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="warehouse_id" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div id="group_account">
|
||||
<label class="mt-2">Akun Kas</label>
|
||||
<select id="account_kas" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL BARANAG KELUAR -->
|
||||
<div class="modal fade" id="modalKeluar">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5>Barang Keluar</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div id="group_account_biaya">
|
||||
<label class="mt-2">Akun Biaya</label>
|
||||
<select id="account_biaya" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Tanggal</label>
|
||||
<input type="date" id="tanggal_keluar" class="form-control">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="warehouse_id_keluar" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div class="d-none" id="group_barang_keluar">
|
||||
<label class="mt-2">Barang</label>
|
||||
<select id="barang_id" class="form-control select-search"></select>
|
||||
</div>
|
||||
|
||||
<div class="d-none" id="group_qty_keluar">
|
||||
<label class="mt-2">Jumlah Barang</label>
|
||||
<input type="number" id="qty_keluar" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-2 d-none" id="group_keterangan">
|
||||
<label for="keterangan" class="form-label">Keterangan</label>
|
||||
<textarea class="form-control" id="keterangan_keluar" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger" id="btnKeluar">Keluarkan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- MODAL DETAIL -->
|
||||
<div class="modal fade" id="modalDetail">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Detail Item</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="detailContent"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="modal fade" id="modalAdjust">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning">
|
||||
<h5>Penyesuaian Stok</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="adjust_item_id">
|
||||
|
||||
<label>Qty Adjustment</label>
|
||||
<input type="number" id="adjust_qty" class="form-control">
|
||||
<small>Gunakan minus (-) jika mengurangi</small>
|
||||
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="adjust_warehouse" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Keterangan</label>
|
||||
<input type="text" id="adjust_ket" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnAdjust">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
let selectedItemId = null;
|
||||
|
||||
// ================= DATATABLE =================
|
||||
let table = $('#tableItems').DataTable({
|
||||
ajax: {
|
||||
url: "<?= base_url('items/get_data'); ?>",
|
||||
data: function (d) {
|
||||
d.s = `draft`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ================= LOAD AKUN KAS =================
|
||||
function loadKas(){
|
||||
$.get("<?= base_url('items/get_accounts'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KAS --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_kas').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD AKUN KAS =================
|
||||
function loadKasOut(){
|
||||
$.get("<?= base_url('items/get_accounts_biaya'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KAS --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_biaya').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD GUDANG =================
|
||||
function loadGudang(){
|
||||
$.get("<?= base_url('warehouses/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH GUDANG --</option>';
|
||||
res.forEach(w=>{
|
||||
opt += `<option value="${w.id}">${w.nama}</option>`;
|
||||
});
|
||||
$('#warehouse_id, #adjust_warehouse').html(opt);
|
||||
},'json');
|
||||
}
|
||||
// ================= LOAD GUDANG =================
|
||||
function loadGudangList(){
|
||||
$.get("<?= base_url('warehouses/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH GUDANG --</option>';
|
||||
res.forEach(w=>{
|
||||
opt += `<option value="${w.id}">${w.nama}</option>`;
|
||||
});
|
||||
$('#warehouse_id_keluar').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function loadKode(){
|
||||
$.get("<?= base_url('kodebarang/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KODE --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.kode_barang} - ${a.nama}</option>`;
|
||||
});
|
||||
$('#kode_barang').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= RESET FORM =================
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#nama_barang').val('');
|
||||
$('#qty').val('');
|
||||
$('#harga_beli').val('');
|
||||
$('#harga_jual').val('');
|
||||
$('#tanggal_beli').val('');
|
||||
}
|
||||
|
||||
// ================= INIT LOAD =================
|
||||
loadGudang();
|
||||
loadKas();
|
||||
loadKode();
|
||||
|
||||
// ================= ADD =================
|
||||
$('.btn-add-item').click(function(){
|
||||
action='add';
|
||||
resetForm();
|
||||
|
||||
$('#qty').closest('div').show();
|
||||
$('#kode_barang').closest('div').show();
|
||||
$('#warehouse_id').closest('div').show();
|
||||
$('#account_kas').closest('div').show();
|
||||
$('#modalItem').modal('show');
|
||||
loadGudang();
|
||||
loadKas();
|
||||
loadKode();
|
||||
});
|
||||
|
||||
// ================= EDIT =================
|
||||
$(document).on('click','.btn-editItem',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
action='edit';
|
||||
|
||||
$.get("<?= base_url('items/detail_simple/'); ?>"+id,function(res){
|
||||
|
||||
$('#id').val(res.id);
|
||||
$('#nama_barang').val(res.nama_barang);
|
||||
$('#harga_beli').val(res.harga_beli);
|
||||
$('#harga_jual').val(res.harga_jual);
|
||||
|
||||
// 🔥 FIX DI SINI
|
||||
$('#group_qty').hide();
|
||||
$('#group_account').hide();
|
||||
$('#group_kode').hide();
|
||||
$('#group_warehouse').hide();
|
||||
$('#group_tanggal').hide();
|
||||
|
||||
$('#modalItem').modal('show');
|
||||
|
||||
},'json');
|
||||
|
||||
|
||||
});
|
||||
|
||||
// ================= SAVE =================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
kode_id: $('#kode_barang').val(),
|
||||
nama_barang: $('#nama_barang').val(),
|
||||
qty: $('#qty').val(),
|
||||
harga_beli: $('#harga_beli').val(),
|
||||
harga_jual: $('#harga_jual').val(),
|
||||
warehouse_id: $('#warehouse_id').val(),
|
||||
account_kas: $('#account_kas').val(),
|
||||
tanggal_beli: $('#tanggal_beli').val(),
|
||||
status: `draft`
|
||||
};
|
||||
|
||||
let url = action==='add'
|
||||
? "<?= base_url('items/save'); ?>"
|
||||
: "<?= base_url('items/update'); ?>";
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post(url, data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalItem').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil disimpan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Terjadi kesalahan'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// ================= START URUSAN KELUAR ===============
|
||||
// =====================================================
|
||||
|
||||
// ================= RESET FORM KELUAR =================
|
||||
function resetFormKeluar(){
|
||||
$('#tanggal_keluar').val('');
|
||||
$('#qty_keluar').val('');
|
||||
$('#keterangan_keluar').val('');
|
||||
}
|
||||
|
||||
loadKasOut();
|
||||
loadGudangList();
|
||||
// ================= BARANG KELUAR ================= account_biaya warehouse_id barang_id
|
||||
$('.btn-out').click(function(){
|
||||
// action='add';
|
||||
resetFormKeluar();
|
||||
|
||||
$('#warehouse_id').closest('div').show();
|
||||
$('#account_biaya').closest('div').show();
|
||||
$('#modalKeluar').modal('show');
|
||||
|
||||
loadGudangList();
|
||||
loadKasOut();
|
||||
});
|
||||
|
||||
$('#warehouse_id_keluar').on('change', function(){
|
||||
let warehouse_id = $(this).val();
|
||||
|
||||
// $('#wrap_item_select').addClass('d-none');
|
||||
$('#barang_id').html('<option value="">Loading...</option>');
|
||||
|
||||
loadItems(warehouse_id);
|
||||
});
|
||||
|
||||
// ================= ITEMS =================
|
||||
function loadItems(warehouse_id){
|
||||
return $.get("<?= base_url('items/get_items_by_wh_id/'); ?>" + warehouse_id, function(res){
|
||||
if(res && res.length){
|
||||
let opt = '<option value="">-- PILIH BARANG --</option>';
|
||||
res.forEach(i=>{
|
||||
opt += `<option value="${i.id}">
|
||||
${i.kode_detail} - ${i.nama_barang} (Stok: ${i.stok})
|
||||
</option>`;
|
||||
});
|
||||
$('#barang_id').html(opt);
|
||||
$('#group_barang_keluar').removeClass('d-none');
|
||||
$('#group_qty_keluar').removeClass('d-none');
|
||||
$('#group_keterangan').removeClass('d-none');
|
||||
} else {
|
||||
$('#barang_id').html(opt);
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// ================= SAVE =================
|
||||
$('#btnKeluar').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
account_biaya: $('#account_biaya').val(),
|
||||
tanggal_keluar: $('#tanggal_keluar').val(),
|
||||
warehouse_id_keluar: $('#warehouse_id_keluar').val(),
|
||||
barang_id: $('#barang_id').val(),
|
||||
qty_keluar: $('#qty_keluar').val(),
|
||||
keterangan_keluar: $('#keterangan_keluar').val()
|
||||
};
|
||||
|
||||
let url = "<?= base_url('items/keluarkan'); ?>";
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post(url, data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalItem').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil disimpan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Terjadi kesalahan'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Keluarkan');
|
||||
});
|
||||
|
||||
});
|
||||
// =====================================================
|
||||
// ================= END URUSAN KELUAR ===============
|
||||
// =====================================================
|
||||
|
||||
// ================= DELETE =================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
let btn = $(this);
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus data?',
|
||||
text: "Data tidak bisa dikembalikan!",
|
||||
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("<?= base_url('items/delete/'); ?>"+id,function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil dihapus',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Gagal menghapus data'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Hapus');
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// ================= POSTING =================
|
||||
$(document).on('click','.btn-updatePosting',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
let btn = $(this);
|
||||
|
||||
if(btn.data('loading')) return;
|
||||
|
||||
Swal.fire({
|
||||
title: 'Konfirmasi Penerimaan Barang',
|
||||
text: 'Pastikan barang sudah diterima dan sesuai pesanan. Stok akan otomatis ditambahkan ke gudang.',
|
||||
icon: 'info',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#28a745',
|
||||
cancelButtonColor: '#6c757d',
|
||||
confirmButtonText: 'Ya, Terima Barang',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
|
||||
if(result.isConfirmed){
|
||||
|
||||
btn.data('loading', true)
|
||||
.prop('disabled', true)
|
||||
.html('Memposting...');
|
||||
|
||||
$.post("<?= base_url('items/posting'); ?>", {
|
||||
id: id
|
||||
// tambahkan CSRF kalau perlu
|
||||
}, function(res){
|
||||
|
||||
if(res && res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil diposting',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res?.message || 'Gagal memposting data'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(xhr){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: xhr.responseJSON?.message || 'Server error ('+xhr.status+')'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false)
|
||||
.html('Posting')
|
||||
.data('loading', false);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ================= DETAIL =================
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('items/detail/'); ?>"+id,function(res){
|
||||
|
||||
let html = `
|
||||
<b>Nama :</b> ${res.item.nama_barang}<br>
|
||||
<b>Harga Beli :</b> ${formatRupiah(res.item.harga_beli)}<br>
|
||||
<b>Harga Jual :</b> ${formatRupiah(res.item.harga_jual)}
|
||||
<hr>
|
||||
<h6>Riwayat Stok</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<tr>
|
||||
<th>Tanggal</th>
|
||||
<th>Gudang</th>
|
||||
<th>Qty</th>
|
||||
<th>Tipe</th>
|
||||
<th>Keterangan</th>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
res.logs.forEach(l=>{
|
||||
html += `
|
||||
<tr>
|
||||
<td>${l.created_at ?? '-'}</td>
|
||||
<td>${l.gudang ?? '-'}</td>
|
||||
<td>${l.qty}</td>
|
||||
<td>${l.tipe}</td>
|
||||
<td>${l.keterangan ?? ''}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
html += `</table>`;
|
||||
|
||||
$('#detailContent').html(html);
|
||||
$('#modalDetail').modal('show');
|
||||
|
||||
},'json');
|
||||
|
||||
});
|
||||
|
||||
// ================= OPEN ADJUST =================
|
||||
$(document).on('click','.btn-adjust',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
if(!id){
|
||||
alert('Pilih item dari tabel (gunakan tombol Adjust di baris)');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedItemId = id;
|
||||
$('#adjust_item_id').val(id);
|
||||
$('#adjust_qty').val('');
|
||||
$('#adjust_ket').val('');
|
||||
|
||||
$('#modalAdjust').modal('show');
|
||||
});
|
||||
|
||||
// ================= SAVE ADJUST =================
|
||||
$('#btnAdjust').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
item_id: $('#adjust_item_id').val(),
|
||||
qty: $('#adjust_qty').val(),
|
||||
warehouse_id: $('#adjust_warehouse').val(),
|
||||
keterangan: $('#adjust_ket').val()
|
||||
};
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post("<?= base_url('items/adjust'); ?>", data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalAdjust').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Stok berhasil disesuaikan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Gagal melakukan penyesuaian'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,685 @@
|
||||
<div class="container mt-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>Data Barang</h5>
|
||||
<div class="text-end">
|
||||
<button class="btn btn-add bg-danger btn-out mr-2">Pengeluaran</button>
|
||||
<button class="btn btn-warning btn-add btn-add-item mr-2">Tambah Barang</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableItems" class="table modern-table w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Tanggal Beli</th>
|
||||
<th>Kode Barang</th>
|
||||
<th>Nama</th>
|
||||
<th style="max-width: 150px;">Gudang</th>
|
||||
<th>Stok</th>
|
||||
<th>Harga Beli</th>
|
||||
<th>Harga Jual</th>
|
||||
<th>Create at</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalItem">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Item</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<div id="group_tanggal">
|
||||
<label>Tanggal Pembelian</label>
|
||||
<input type="date" id="tanggal_beli" class="form-control">
|
||||
</div>
|
||||
|
||||
<div id="group_kode">
|
||||
<label class="mt-2">Kode Barang</label>
|
||||
<select id="kode_barang" class="form-control select-search"></select>
|
||||
</div>
|
||||
|
||||
<label>Nama Barang</label>
|
||||
<input type="text" id="nama_barang" class="form-control">
|
||||
|
||||
<div id="group_qty">
|
||||
<label class="mt-2">Jumlah Barang</label>
|
||||
<input type="number" id="qty" class="form-control">
|
||||
</div>
|
||||
|
||||
<label class="mt-2">Harga Beli</label>
|
||||
<input type="text" id="harga_beli" class="form-control format-rupiah">
|
||||
|
||||
<label class="mt-2">Harga Jual</label>
|
||||
<input type="text" id="harga_jual" class="form-control format-rupiah">
|
||||
|
||||
<div id="group_warehouse">
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="warehouse_id" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div id="group_account">
|
||||
<label class="mt-2">Akun Kas</label>
|
||||
<select id="account_kas" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL BARANAG KELUAR -->
|
||||
<div class="modal fade" id="modalKeluar">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5>Barang Keluar</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div id="group_account_biaya">
|
||||
<label class="mt-2">Akun Biaya</label>
|
||||
<select id="account_biaya" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Tanggal</label>
|
||||
<input type="date" id="tanggal_keluar" class="form-control">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="warehouse_id_keluar" class="form-control"></select>
|
||||
</div>
|
||||
|
||||
<div class="d-none" id="group_barang_keluar">
|
||||
<label class="mt-2">Barang</label>
|
||||
<select id="barang_id" class="form-control select-search"></select>
|
||||
</div>
|
||||
|
||||
<div class="d-none" id="group_qty_keluar">
|
||||
<label class="mt-2">Jumlah Barang</label>
|
||||
<input type="number" id="qty_keluar" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-2 d-none" id="group_keterangan">
|
||||
<label for="keterangan" class="form-label">Keterangan</label>
|
||||
<textarea class="form-control" id="keterangan_keluar" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger" id="btnKeluar">Keluarkan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- MODAL DETAIL -->
|
||||
<div class="modal fade" id="modalDetail">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Detail Item</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="detailContent"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="modal fade" id="modalAdjust">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning">
|
||||
<h5>Penyesuaian Stok</h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="adjust_item_id">
|
||||
|
||||
<label>Qty Adjustment</label>
|
||||
<input type="number" id="adjust_qty" class="form-control">
|
||||
<small>Gunakan minus (-) jika mengurangi</small>
|
||||
|
||||
<label class="mt-2">Gudang</label>
|
||||
<select id="adjust_warehouse" class="form-control"></select>
|
||||
|
||||
<label class="mt-2">Keterangan</label>
|
||||
<input type="text" id="adjust_ket" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnAdjust">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
let selectedItemId = null;
|
||||
|
||||
// ================= DATATABLE =================
|
||||
let table = $('#tableItems').DataTable({
|
||||
ajax: {
|
||||
url: "<?= base_url('items/get_data'); ?>",
|
||||
data: function (d) {
|
||||
d.s = `active`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ================= LOAD AKUN KAS =================
|
||||
function loadKas(){
|
||||
$.get("<?= base_url('items/get_accounts'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KAS --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_kas').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD AKUN KAS =================
|
||||
function loadKasOut(){
|
||||
$.get("<?= base_url('items/get_accounts_biaya'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KAS --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_biaya').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD GUDANG =================
|
||||
function loadGudang(){
|
||||
$.get("<?= base_url('warehouses/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH GUDANG --</option>';
|
||||
res.forEach(w=>{
|
||||
opt += `<option value="${w.id}">${w.nama}</option>`;
|
||||
});
|
||||
$('#warehouse_id, #adjust_warehouse').html(opt);
|
||||
},'json');
|
||||
}
|
||||
// ================= LOAD GUDANG =================
|
||||
function loadGudangList(){
|
||||
$.get("<?= base_url('warehouses/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH GUDANG --</option>';
|
||||
res.forEach(w=>{
|
||||
opt += `<option value="${w.id}">${w.nama}</option>`;
|
||||
});
|
||||
$('#warehouse_id_keluar').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function loadKode(){
|
||||
$.get("<?= base_url('kodebarang/list'); ?>",res=>{
|
||||
let opt='<option value="">-- PILIH KODE --</option>';
|
||||
res.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.kode_barang} - ${a.nama}</option>`;
|
||||
});
|
||||
$('#kode_barang').html(opt);
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= RESET FORM =================
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#nama_barang').val('');
|
||||
$('#qty').val('');
|
||||
$('#harga_beli').val('');
|
||||
$('#harga_jual').val('');
|
||||
$('#tanggal_beli').val('');
|
||||
}
|
||||
|
||||
// ================= INIT LOAD =================
|
||||
loadGudang();
|
||||
loadKas();
|
||||
loadKode();
|
||||
|
||||
// ================= ADD =================
|
||||
$('.btn-add-item').click(function(){
|
||||
action='add';
|
||||
resetForm();
|
||||
|
||||
$('#qty').closest('div').show();
|
||||
$('#kode_barang').closest('div').show();
|
||||
$('#warehouse_id').closest('div').show();
|
||||
$('#account_kas').closest('div').show();
|
||||
$('#modalItem').modal('show');
|
||||
loadGudang();
|
||||
loadKas();
|
||||
loadKode();
|
||||
});
|
||||
|
||||
// ================= EDIT =================
|
||||
$(document).on('click','.btn-editItem',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
action='edit';
|
||||
|
||||
$.get("<?= base_url('items/detail_simple/'); ?>"+id,function(res){
|
||||
|
||||
$('#id').val(res.id);
|
||||
$('#nama_barang').val(res.nama_barang);
|
||||
$('#harga_beli').val(res.harga_beli);
|
||||
$('#harga_jual').val(res.harga_jual);
|
||||
|
||||
// 🔥 FIX DI SINI
|
||||
$('#group_qty').hide();
|
||||
$('#group_account').hide();
|
||||
$('#group_kode').hide();
|
||||
$('#group_warehouse').hide();
|
||||
$('#group_tanggal').hide();
|
||||
|
||||
$('#modalItem').modal('show');
|
||||
|
||||
},'json');
|
||||
|
||||
|
||||
});
|
||||
|
||||
// ================= SAVE =================
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
kode_id: $('#kode_barang').val(),
|
||||
nama_barang: $('#nama_barang').val(),
|
||||
qty: $('#qty').val(),
|
||||
harga_beli: $('#harga_beli').val(),
|
||||
harga_jual: $('#harga_jual').val(),
|
||||
warehouse_id: $('#warehouse_id').val(),
|
||||
account_kas: $('#account_kas').val(),
|
||||
tanggal_beli: $('#tanggal_beli').val(),
|
||||
status: `active`
|
||||
};
|
||||
|
||||
let url = action==='add'
|
||||
? "<?= base_url('items/save'); ?>"
|
||||
: "<?= base_url('items/update'); ?>";
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post(url, data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalItem').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil disimpan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Terjadi kesalahan'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// ================= START URUSAN KELUAR ===============
|
||||
// =====================================================
|
||||
|
||||
// ================= RESET FORM KELUAR =================
|
||||
function resetFormKeluar(){
|
||||
$('#tanggal_keluar').val('');
|
||||
$('#qty_keluar').val('');
|
||||
$('#keterangan_keluar').val('');
|
||||
}
|
||||
|
||||
loadKasOut();
|
||||
loadGudangList();
|
||||
// ================= BARANG KELUAR ================= account_biaya warehouse_id barang_id
|
||||
$('.btn-out').click(function(){
|
||||
// action='add';
|
||||
resetFormKeluar();
|
||||
|
||||
$('#warehouse_id').closest('div').show();
|
||||
$('#account_biaya').closest('div').show();
|
||||
$('#modalKeluar').modal('show');
|
||||
|
||||
loadGudangList();
|
||||
loadKasOut();
|
||||
});
|
||||
|
||||
$('#warehouse_id_keluar').on('change', function(){
|
||||
let warehouse_id = $(this).val();
|
||||
|
||||
// $('#wrap_item_select').addClass('d-none');
|
||||
$('#barang_id').html('<option value="">Loading...</option>');
|
||||
|
||||
loadItems(warehouse_id);
|
||||
});
|
||||
|
||||
// ================= ITEMS =================
|
||||
function loadItems(warehouse_id){
|
||||
return $.get("<?= base_url('items/get_items_by_wh_id/'); ?>" + warehouse_id, function(res){
|
||||
if(res && res.length){
|
||||
let opt = '<option value="">-- PILIH BARANG --</option>';
|
||||
res.forEach(i=>{
|
||||
opt += `<option value="${i.id}">
|
||||
${i.kode_detail} - ${i.nama_barang} (Stok: ${i.stok})
|
||||
</option>`;
|
||||
});
|
||||
$('#barang_id').html(opt);
|
||||
$('#group_barang_keluar').removeClass('d-none');
|
||||
$('#group_qty_keluar').removeClass('d-none');
|
||||
$('#group_keterangan').removeClass('d-none');
|
||||
} else {
|
||||
$('#barang_id').html(opt);
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// ================= SAVE =================
|
||||
$('#btnKeluar').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
account_biaya: $('#account_biaya').val(),
|
||||
tanggal_keluar: $('#tanggal_keluar').val(),
|
||||
warehouse_id_keluar: $('#warehouse_id_keluar').val(),
|
||||
barang_id: $('#barang_id').val(),
|
||||
qty_keluar: $('#qty_keluar').val(),
|
||||
keterangan_keluar: $('#keterangan_keluar').val()
|
||||
};
|
||||
|
||||
let url = "<?= base_url('items/keluarkan'); ?>";
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post(url, data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalItem').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil disimpan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Terjadi kesalahan'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Keluarkan');
|
||||
});
|
||||
|
||||
});
|
||||
// =====================================================
|
||||
// ================= END URUSAN KELUAR ===============
|
||||
// =====================================================
|
||||
|
||||
// ================= DELETE =================
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
let btn = $(this);
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus data?',
|
||||
text: "Data tidak bisa dikembalikan!",
|
||||
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("<?= base_url('items/delete/'); ?>"+id,function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Data berhasil dihapus',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Gagal menghapus data'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Hapus');
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ================= DETAIL =================
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('items/detail/'); ?>"+id,function(res){
|
||||
|
||||
let html = `
|
||||
<b>Nama :</b> ${res.item.nama_barang}<br>
|
||||
<b>Harga Beli :</b> ${formatRupiah(res.item.harga_beli)}<br>
|
||||
<b>Harga Jual :</b> ${formatRupiah(res.item.harga_jual)}
|
||||
<hr>
|
||||
<h6>Riwayat Stok</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<tr>
|
||||
<th>Tanggal</th>
|
||||
<th>Gudang</th>
|
||||
<th>Qty</th>
|
||||
<th>Tipe</th>
|
||||
<th>Keterangan</th>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
res.logs.forEach(l=>{
|
||||
html += `
|
||||
<tr>
|
||||
<td>${l.created_at ?? '-'}</td>
|
||||
<td>${l.gudang ?? '-'}</td>
|
||||
<td>${l.qty}</td>
|
||||
<td>${l.tipe}</td>
|
||||
<td>${l.keterangan ?? ''}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
html += `</table>`;
|
||||
|
||||
$('#detailContent').html(html);
|
||||
$('#modalDetail').modal('show');
|
||||
|
||||
},'json');
|
||||
|
||||
});
|
||||
|
||||
// ================= OPEN ADJUST =================
|
||||
$(document).on('click','.btn-adjust',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
if(!id){
|
||||
alert('Pilih item dari tabel (gunakan tombol Adjust di baris)');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedItemId = id;
|
||||
$('#adjust_item_id').val(id);
|
||||
$('#adjust_qty').val('');
|
||||
$('#adjust_ket').val('');
|
||||
|
||||
$('#modalAdjust').modal('show');
|
||||
});
|
||||
|
||||
// ================= SAVE ADJUST =================
|
||||
$('#btnAdjust').click(function(){
|
||||
|
||||
let btn = $(this);
|
||||
|
||||
let data = {
|
||||
item_id: $('#adjust_item_id').val(),
|
||||
qty: $('#adjust_qty').val(),
|
||||
warehouse_id: $('#adjust_warehouse').val(),
|
||||
keterangan: $('#adjust_ket').val()
|
||||
};
|
||||
|
||||
// 🔥 loading state
|
||||
btn.prop('disabled', true).html('Menyimpan...');
|
||||
|
||||
$.post("<?= base_url('items/adjust'); ?>", data, function(res){
|
||||
|
||||
if(res.status){
|
||||
|
||||
$('#modalAdjust').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: res.message || 'Stok berhasil disesuaikan',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: res.message || 'Gagal melakukan penyesuaian'
|
||||
});
|
||||
}
|
||||
|
||||
},'json')
|
||||
.fail(function(){
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Koneksi ke server gagal'
|
||||
});
|
||||
|
||||
})
|
||||
.always(function(){
|
||||
btn.prop('disabled', false).html('Simpan');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,510 @@
|
||||
<div class="container mt-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>Jurnal Umum</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Jurnal</button>
|
||||
</div>
|
||||
|
||||
<!--<form id="filterForm" class="row mb-3">-->
|
||||
|
||||
<!-- <div class="col-md-4">-->
|
||||
<!-- <label>Dari Tanggal</label>-->
|
||||
<!-- <input type="date" id="tanggal_dari" class="form-control">-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="col-md-4">-->
|
||||
<!-- <label>Sampai Tanggal</label>-->
|
||||
<!-- <input type="date" id="tanggal_sampai" class="form-control">-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="col-md-4 d-flex align-items-end">-->
|
||||
<!-- <button type="submit" class="btn btn-warning w-100">-->
|
||||
<!-- Tampilkan-->
|
||||
<!-- </button>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!--</form>-->
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableJurnal" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Tanggal</th>
|
||||
<th>No Ref</th>
|
||||
<th>Keterangan</th>
|
||||
<th class="text-end">Debit</th>
|
||||
<th class="text-end">Kredit</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="4" class="text-end">TOTAL</td>
|
||||
<td class="text-end" id="totalDebitTable">0</td>
|
||||
<td class="text-end" id="totalKreditTable">0</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL INPUT -->
|
||||
<div class="modal fade" id="modalJurnal">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Tambah Jurnal</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- MODE -->
|
||||
<div class="mb-3">
|
||||
<div class="btn-group w-100">
|
||||
<button class="btn btn-warning active" id="modeAuto">Otomatis</button>
|
||||
<button class="btn btn-outline-secondary" id="modeManual">Manual</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TEMPLATE -->
|
||||
<div id="autoSection" class="mb-3">
|
||||
<label>Template Jurnal</label>
|
||||
<select id="base_jurnal_id" class="form-control select-search">
|
||||
<option value="">-- Pilih Template --</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- FORM -->
|
||||
<input type="date" id="tanggal" class="form-control mb-2">
|
||||
<textarea id="keterangan" class="form-control mb-3" placeholder="Keterangan"></textarea>
|
||||
|
||||
<!-- TABLE -->
|
||||
<table class="table" id="tableDetail">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Akun</th>
|
||||
<th>Debit</th>
|
||||
<th>Kredit</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td class="text-end">TOTAL</td>
|
||||
<td id="formTotalDebit">0</td>
|
||||
<td id="formTotalKredit">0</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<button class="btn btn-warning btn-add-row">Tambah Baris</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DETAIL -->
|
||||
<div class="modal fade" id="modalDetail">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Detail Jurnal</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Tanggal:</strong> <span id="d_tanggal"></span><br>
|
||||
<strong>No Ref:</strong> <span id="d_noref"></span><br>
|
||||
<strong>Keterangan:</strong> <span id="d_keterangan"></span><br>
|
||||
<strong>Dibuat oleh:</strong> <span id="d_createdby"></span>
|
||||
</div>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Akun</th>
|
||||
<th>Debit</th>
|
||||
<th>Kredit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="detailBody"></tbody>
|
||||
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Total</th>
|
||||
<th id="totalDebitDetail">0</th>
|
||||
<th id="totalKreditDetail">0</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#tableJurnal tbody tr:hover {
|
||||
background-color: #fff3cd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
let accounts = [];
|
||||
let mode = 'auto';
|
||||
|
||||
// ================= LOAD ACCOUNTS
|
||||
function loadAccounts(){
|
||||
return $.get("<?= base_url('jurnal/get_accounts'); ?>", function(res){
|
||||
accounts = res;
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD BASE JURNAL
|
||||
function loadBaseJurnal(){
|
||||
return $.get("<?= base_url('jurnal/get_base_jurnal'); ?>", function(res){
|
||||
|
||||
let opt = '<option value="">-- Pilih Template --</option>';
|
||||
res.forEach(b=>{
|
||||
opt += `<option value="${b.id}">${b.kode} - ${b.nama}</option>`;
|
||||
});
|
||||
|
||||
$('#base_jurnal_id').html(opt);
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
function accountOptions(){
|
||||
let opt = '<option value="">Pilih Akun</option>';
|
||||
accounts.forEach(a=>{
|
||||
opt += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
|
||||
});
|
||||
return opt;
|
||||
}
|
||||
|
||||
// ================= ADD ROW
|
||||
function addRow(data=null){
|
||||
|
||||
let isAuto = (mode === 'auto');
|
||||
|
||||
let debitVal = data?.debit || '';
|
||||
let kreditVal = data?.kredit || '';
|
||||
|
||||
let hideDebit = isAuto && data?.posisi === 'kredit';
|
||||
let hideKredit = isAuto && data?.posisi === 'debit';
|
||||
|
||||
let row = `
|
||||
<tr>
|
||||
<td>
|
||||
<select class="form-control account_id" ${isAuto ? 'disabled' : ''}>
|
||||
${accountOptions()}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="text" class="form-control debit format-rupiah"
|
||||
value="${debitVal}"
|
||||
${hideDebit ? 'style="display:none"' : ''}
|
||||
>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="text" class="form-control kredit format-rupiah"
|
||||
value="${kreditVal}"
|
||||
${hideKredit ? 'style="display:none"' : ''}
|
||||
>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
${isAuto ? '' : '<button class="btn btn-danger btn-remove">X</button>'}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
$('#tableDetail tbody').append(row);
|
||||
|
||||
if(data){
|
||||
$('#tableDetail tbody tr:last .account_id').val(data.account_id);
|
||||
}
|
||||
}
|
||||
|
||||
// ================= LOAD TEMPLATE DETAIL
|
||||
function loadTemplateDetail(id){
|
||||
|
||||
if(!id) return;
|
||||
|
||||
$.get("<?= base_url('jurnal/get_base_jurnal_detail/'); ?>" + id, function(res){
|
||||
|
||||
$('#tableDetail tbody').html('');
|
||||
|
||||
res.forEach(r=>{
|
||||
addRow({
|
||||
account_id: r.account_id,
|
||||
posisi: r.posisi, // penting!
|
||||
debit: r.posisi === 'debit' ? 0 : '',
|
||||
kredit: r.posisi === 'kredit' ? 0 : ''
|
||||
});
|
||||
});
|
||||
|
||||
hitungTotalForm();
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
$('#modeAuto').click(function(){
|
||||
|
||||
mode = 'auto';
|
||||
|
||||
$(this).addClass('btn-warning active').removeClass('btn-outline-warning');
|
||||
$('#modeManual').removeClass('btn-warning active').addClass('btn-outline-secondary');
|
||||
|
||||
$('#autoSection').show();
|
||||
|
||||
// ✅ RESET TOTAL FORM
|
||||
$('#tableDetail tbody').html('');
|
||||
$('#base_jurnal_id').val('');
|
||||
|
||||
// reset total juga
|
||||
$('#formTotalDebit').text('0');
|
||||
$('#formTotalKredit').text('0');
|
||||
|
||||
// sembunyikan tombol tambah
|
||||
$('.btn-add-row').hide();
|
||||
});
|
||||
|
||||
$('#modeManual').click(function(){
|
||||
mode = 'manual';
|
||||
|
||||
$(this).addClass('btn-warning active').removeClass('btn-outline-secondary');
|
||||
$('#modeAuto').removeClass('btn-warning active').addClass('btn-outline-warning');
|
||||
|
||||
$('#autoSection').hide();
|
||||
$('#tableDetail tbody').html('');
|
||||
|
||||
$('.btn-add-row').show(); // ⬅️ tampilkan lagi
|
||||
|
||||
addRow();
|
||||
});
|
||||
|
||||
// ================= PILIH TEMPLATE
|
||||
$('#base_jurnal_id').change(function(){
|
||||
loadTemplateDetail($(this).val());
|
||||
});
|
||||
|
||||
// ================= ADD ROW BUTTON
|
||||
$('.btn-add-row').click(function(){
|
||||
|
||||
if(mode === 'manual'){
|
||||
addRow();
|
||||
}else{
|
||||
Swal.fire('Info','Mode otomatis pakai template','info');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ================= REMOVE ROW
|
||||
$(document).on('click','.btn-remove',function(){
|
||||
$(this).closest('tr').remove();
|
||||
hitungTotalForm();
|
||||
});
|
||||
|
||||
// ================= HITUNG TOTAL
|
||||
function hitungTotalForm(){
|
||||
let td=0, tk=0;
|
||||
|
||||
$('#tableDetail tbody tr').each(function(){
|
||||
td += parseFloat($(this).find('.debit').val()) || 0;
|
||||
tk += parseFloat($(this).find('.kredit').val()) || 0;
|
||||
});
|
||||
|
||||
$('#formTotalDebit').text(td.toLocaleString('id-ID'));
|
||||
$('#formTotalKredit').text(tk.toLocaleString('id-ID'));
|
||||
}
|
||||
|
||||
$(document).on('keyup change','.debit, .kredit',hitungTotalForm);
|
||||
|
||||
// ================= OPEN MODAL
|
||||
$('.btn-add').click(async function(){
|
||||
|
||||
await loadAccounts();
|
||||
await loadBaseJurnal();
|
||||
|
||||
$('#modalJurnal').modal('show');
|
||||
|
||||
$('#tableDetail tbody').html('');
|
||||
$('#base_jurnal_id').val('');
|
||||
|
||||
// reset total juga
|
||||
$('#formTotalDebit').text('0');
|
||||
$('#formTotalKredit').text('0');
|
||||
|
||||
$('#modeAuto').click(); // default
|
||||
});
|
||||
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let account_id = [];
|
||||
let debit = [];
|
||||
let kredit = [];
|
||||
|
||||
let totalDebit = 0;
|
||||
let totalKredit = 0;
|
||||
|
||||
$('#tableDetail tbody tr').each(function(){
|
||||
|
||||
let d = parseFloat($(this).find('.debit').val()) || 0;
|
||||
let k = parseFloat($(this).find('.kredit').val()) || 0;
|
||||
|
||||
account_id.push($(this).find('.account_id').val());
|
||||
debit.push(d);
|
||||
kredit.push(k);
|
||||
|
||||
totalDebit += d;
|
||||
totalKredit += k;
|
||||
});
|
||||
|
||||
// ✅ VALIDASI DI SINI
|
||||
if(totalDebit !== totalKredit){
|
||||
Swal.fire('Warning','Total Debit dan Kredit harus sama!','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
// lanjut simpan
|
||||
$.post("<?= base_url('jurnal/save'); ?>", {
|
||||
tanggal: $('#tanggal').val(),
|
||||
keterangan: $('#keterangan').val(),
|
||||
account_id: account_id,
|
||||
debit: debit,
|
||||
kredit: kredit
|
||||
}, function(res){
|
||||
|
||||
if(res.status){
|
||||
$('#modalJurnal').modal('hide');
|
||||
$('#tableJurnal').DataTable().ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// DATATABLE
|
||||
let table = $('#tableJurnal').DataTable({
|
||||
processing:true,
|
||||
serverSide:true,
|
||||
pageLength:10, // default 10
|
||||
lengthMenu:[ [10,25,50,100], [10,25,50,100] ],
|
||||
order:[[1,'desc']],
|
||||
ajax:{
|
||||
url:"<?= base_url('jurnal/get_data'); ?>",
|
||||
type:"POST"
|
||||
},
|
||||
columnDefs:[
|
||||
{ targets:[4,5], className:'text-end' }
|
||||
],
|
||||
drawCallback:function(){
|
||||
|
||||
let api = this.api();
|
||||
let td = 0, tk = 0;
|
||||
|
||||
api.rows().every(function(){
|
||||
let d = this.data();
|
||||
|
||||
td += parseFloat(d[4].replace(/\./g,'')) || 0;
|
||||
tk += parseFloat(d[5].replace(/\./g,'')) || 0;
|
||||
});
|
||||
|
||||
$('#totalDebitTable').text(td.toLocaleString('id-ID'));
|
||||
$('#totalKreditTable').text(tk.toLocaleString('id-ID'));
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Hapus?',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(r=>{
|
||||
if(r.isConfirmed){
|
||||
$.get("<?= base_url('jurnal/delete/'); ?>"+id,function(){
|
||||
table.ajax.reload(null,false);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// DETAIL
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('jurnal/detail/'); ?>" + id, function(res){
|
||||
|
||||
$('#d_tanggal').text(res.header.tanggal);
|
||||
$('#d_noref').text(res.header.no_ref);
|
||||
$('#d_keterangan').text(res.header.keterangan);
|
||||
$('#d_createdby').text(res.user.nama);
|
||||
|
||||
let html = '';
|
||||
let totalDebit = 0;
|
||||
let totalKredit = 0;
|
||||
|
||||
res.detail.forEach(row => {
|
||||
|
||||
totalDebit += parseFloat(row.debit);
|
||||
totalKredit += parseFloat(row.kredit);
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${row.kode_akun} - ${row.nama_akun}</td>
|
||||
<td>${parseFloat(row.debit).toLocaleString('id-ID')}</td>
|
||||
<td>${parseFloat(row.kredit).toLocaleString('id-ID')}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
$('#detailBody').html(html);
|
||||
$('#totalDebitDetail').text(totalDebit.toLocaleString('id-ID'));
|
||||
$('#totalKreditDetail').text(totalKredit.toLocaleString('id-ID'));
|
||||
|
||||
$('#modalDetail').modal('show');
|
||||
|
||||
},'json');
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,241 @@
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">Data Kamar</h5>
|
||||
<div>
|
||||
<?php if(check_permission('kamar', 'can_create')): ?>
|
||||
<button class="btn btn-success btn-add" style="margin-right: 5px;">
|
||||
<i class="bi bi-plus-circle me-1"></i> Tambah Kamar
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableKamar" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Kamar</th>
|
||||
<th>Gedung</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL TAMBAH / EDIT KAMAR -->
|
||||
<div class="modal fade" id="modalKamar">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
<div class="modal-header bg-success text-white rounded-top-4">
|
||||
<h5 class="modal-title">Tambah Kamar</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="inputId">
|
||||
<label class="fw-semibold mt-2">Nama Kamar</label>
|
||||
<input type="text" class="form-control" id="inputNama" placeholder="Masukkan nama kamar">
|
||||
|
||||
<label class="fw-semibold mt-2">Gedung</label>
|
||||
<input type="text" class="form-control" id="inputGedung" placeholder="Masukkan nama gedung">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-success" id="btnSimpanKamar">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DETAIL KAMAR -->
|
||||
<div class="modal fade" id="modalDetailKamar">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4 shadow">
|
||||
<div class="modal-header bg-primary text-white rounded-top-4">
|
||||
<h5 class="modal-title">Detail Kamar</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="p-3 border rounded-3 bg-light">
|
||||
<span class="text-success fw-bold">Nama Kamar:</span>
|
||||
<div id="detailNamaKamar" class="fw-semibold"></div>
|
||||
</div>
|
||||
<div class="p-3 border rounded-3 bg-light">
|
||||
<span class="text-success fw-bold">Gedung:</span>
|
||||
<div id="detailGedung"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-bs-dismiss="modal">Tutup</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
let table = $('#tableKamar').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"l f>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('kamar/get_data'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3, orderable: false } // Kolom Aksi
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input').attr('placeholder', 'Search...').css({
|
||||
'min-width': '300px',
|
||||
'padding': '6px 12px',
|
||||
'border-radius': '6px',
|
||||
'border': '1px solid #ced4da',
|
||||
'font-size': '0.9rem',
|
||||
'box-sizing': 'border-box'
|
||||
});
|
||||
|
||||
table.on('draw', function () {
|
||||
$('#tableKamar tbody tr').each(function() {
|
||||
$(this).find('td').each(function(index) {
|
||||
let header = $('#tableKamar thead th').eq(index).text().trim();
|
||||
$(this).attr('data-label', header + ' : ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// OPEN MODAL TAMBAH
|
||||
$(document).on('click', '.btn-add', function(){
|
||||
$('#inputId, #inputNama, #inputGedung').val('');
|
||||
$('#modalKamar .modal-title').text('Tambah Kamar');
|
||||
$('#btnSimpanKamar').text('Simpan').data('action','add').removeData('id');
|
||||
$('#modalKamar').modal('show');
|
||||
});
|
||||
|
||||
// SAVE / UPDATE KAMAR
|
||||
$('#btnSimpanKamar').click(function(){
|
||||
let action = $(this).data('action');
|
||||
let id = $('#inputId').val() || '';
|
||||
let formData = {
|
||||
id: id,
|
||||
nama: $('#inputNama').val(),
|
||||
gedung: $('#inputGedung').val()
|
||||
};
|
||||
|
||||
let url = action === 'add' ? "<?= base_url('kamar/save'); ?>" : "<?= base_url('kamar/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
$('#modalKamar').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message || 'Berhasil!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error', 'Terjadi kesalahan server.', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// DETAIL KAMAR
|
||||
$(document).on('click', '.btn-detail', function(){
|
||||
let id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: "<?= base_url('kamar/detail'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
$('#detailNamaKamar').text(res.nama);
|
||||
$('#detailGedung').text(res.gedung);
|
||||
$('#modalDetailKamar').modal('show');
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Gagal memuat detail.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// EDIT KAMAR
|
||||
$(document).on('click', '.btn-edit', function(){
|
||||
let id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: "<?= base_url('kamar/detail'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
$('#inputId').val(res.id);
|
||||
$('#inputNama').val(res.nama);
|
||||
$('#inputGedung').val(res.gedung);
|
||||
|
||||
$('#modalKamar .modal-title').text('Edit Kamar');
|
||||
$('#btnSimpanKamar').text('Update').data('action','edit');
|
||||
$('#modalKamar').modal('show');
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Gagal memuat data edit.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// DELETE KAMAR
|
||||
$(document).on('click', '.btn-delete', function(){
|
||||
let id = $(this).data('id');
|
||||
Swal.fire({
|
||||
title: 'Yakin ingin hapus?',
|
||||
text: "Data tidak dapat dikembalikan!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
$.ajax({
|
||||
url: "<?= base_url('kamar/delete'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Terhapus!', res.message || 'Berhasil dihapus!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal menghapus!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Terjadi kesalahan saat menghapus.','error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,253 @@
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">Data Kelas</h5>
|
||||
<div>
|
||||
<?php if(check_permission('kelas', 'can_create')): ?>
|
||||
<button class="btn btn-success btn-add" style="margin-right: 5px;">
|
||||
<i class="bi bi-plus-circle me-1"></i> Tambah Kelas
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableKelas" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Kelas</th>
|
||||
<th>Gedung</th>
|
||||
<th>Wali Kelas</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL TAMBAH / EDIT KELAS -->
|
||||
<div class="modal fade" id="modalKelas">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
<div class="modal-header bg-success text-white rounded-top-4">
|
||||
<h5 class="modal-title">Tambah Kelas</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="inputId">
|
||||
<label class="fw-semibold mt-2">Nama Kelas</label>
|
||||
<input type="text" class="form-control" id="inputNama" placeholder="Masukkan nama kelas">
|
||||
|
||||
<label class="fw-semibold mt-2">Gedung</label>
|
||||
<input type="text" class="form-control" id="inputGedung" placeholder="Masukkan nama gedung">
|
||||
|
||||
<label class="fw-semibold mt-2">Nama Wali Kelas</label>
|
||||
<input type="text" class="form-control" id="inputWaliKelas" placeholder="Masukkan nama wali kelas">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-success" id="btnSimpanKelas">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL DETAIL KELAS -->
|
||||
<div class="modal fade" id="modalDetailKelas">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4 shadow">
|
||||
<div class="modal-header bg-primary text-white rounded-top-4">
|
||||
<h5 class="modal-title">Detail Kelas</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="p-3 border rounded-3 bg-light">
|
||||
<span class="text-success fw-bold">Nama Kelas:</span>
|
||||
<div id="detailNamaKelas" class="fw-semibold"></div>
|
||||
</div>
|
||||
<div class="p-3 border rounded-3 bg-light">
|
||||
<span class="text-success fw-bold">Gedung:</span>
|
||||
<div id="detailGedung"></div>
|
||||
</div>
|
||||
<div class="p-3 border rounded-3 bg-light">
|
||||
<span class="text-success fw-bold">Nama Wali Kelas:</span>
|
||||
<div id="detailWaliKelas"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-bs-dismiss="modal">Tutup</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
let table = $('#tableKelas').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"l f>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('kelas/get_data'); ?>", // Sesuaikan dengan controller Kelas
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4, orderable: false } // Kolom Aksi
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input').attr('placeholder', 'Search...').css({
|
||||
'min-width': '300px',
|
||||
'padding': '6px 12px',
|
||||
'border-radius': '6px',
|
||||
'border': '1px solid #ced4da',
|
||||
'font-size': '0.9rem',
|
||||
'box-sizing': 'border-box'
|
||||
});
|
||||
|
||||
table.on('draw', function () {
|
||||
$('#tableKelas tbody tr').each(function() {
|
||||
$(this).find('td').each(function(index) {
|
||||
let header = $('#tableKelas thead th').eq(index).text().trim();
|
||||
$(this).attr('data-label', header + ' : ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// OPEN MODAL TAMBAH
|
||||
$(document).on('click', '.btn-add', function(){
|
||||
$('#inputId, #inputNama, #inputGedung, #inputWaliKelas').val('');
|
||||
$('#modalKelas .modal-title').text('Tambah Kelas');
|
||||
$('#btnSimpanKelas').text('Simpan').data('action','add').removeData('id');
|
||||
$('#modalKelas').modal('show');
|
||||
});
|
||||
|
||||
// SAVE / UPDATE KELAS
|
||||
$('#btnSimpanKelas').click(function(){
|
||||
let action = $(this).data('action');
|
||||
let id = $('#inputId').val() || ''; // Ambil dari hidden input
|
||||
let formData = {
|
||||
id: id,
|
||||
nama: $('#inputNama').val(),
|
||||
gedung: $('#inputGedung').val(),
|
||||
nama_wali_kelas: $('#inputWaliKelas').val()
|
||||
};
|
||||
|
||||
let url = action === 'add' ? "<?= base_url('kelas/save'); ?>" : "<?= base_url('kelas/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
$('#modalKelas').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message || 'Berhasil!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error', 'Terjadi kesalahan server.', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// DETAIL KELAS
|
||||
$(document).on('click', '.btn-detail', function(){
|
||||
let id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: "<?= base_url('kelas/detail'); ?>/" + id, // Sesuaikan dengan controller Kelas
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
$('#detailNamaKelas').text(res.nama);
|
||||
$('#detailGedung').text(res.gedung);
|
||||
$('#detailWaliKelas').text(res.nama_wali_kelas);
|
||||
$('#modalDetailKelas').modal('show');
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Gagal memuat detail.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// EDIT KELAS
|
||||
$(document).on('click', '.btn-edit', function(){
|
||||
let id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: "<?= base_url('kelas/detail'); ?>/" + id, // Sesuaikan dengan controller Kelas
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
$('#inputId').val(res.id); // Set ID ke hidden input
|
||||
$('#inputNama').val(res.nama);
|
||||
$('#inputGedung').val(res.gedung);
|
||||
$('#inputWaliKelas').val(res.nama_wali_kelas);
|
||||
|
||||
$('#modalKelas .modal-title').text('Edit Kelas');
|
||||
$('#btnSimpanKelas').text('Update').data('action','edit'); // ID sudah ada di hidden input
|
||||
$('#modalKelas').modal('show');
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Gagal memuat data edit.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// DELETE KELAS
|
||||
$(document).on('click', '.btn-delete', function(){
|
||||
let id = $(this).data('id');
|
||||
Swal.fire({
|
||||
title: 'Yakin ingin hapus?',
|
||||
text: "Data tidak dapat dikembalikan!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
$.ajax({
|
||||
url: "<?= base_url('kelas/delete'); ?>/" + id, // Sesuaikan dengan controller Kelas
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Terhapus!', res.message || 'Berhasil dihapus!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal menghapus!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Terjadi kesalahan saat menghapus.','error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,168 @@
|
||||
<!--Lokasi nya : /views/employees/employees.php-->
|
||||
<div class="container mt-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>Kode Barang</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableWarehouse" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Limit Stok</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalKodebarang">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Kode Barang</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<label>Kode Barang</label>
|
||||
<input type="text" id="kode" class="form-control">
|
||||
|
||||
<label>Nama Barang</label>
|
||||
<input type="text" id="nama" class="form-control">
|
||||
|
||||
<label>Limit Stok</label>
|
||||
<input type="number" id="limit_stock" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
|
||||
let table = $('#tableWarehouse').DataTable({
|
||||
ajax:{
|
||||
url:"<?= base_url('kodebarang/get_data'); ?>",
|
||||
type:"POST"
|
||||
}
|
||||
});
|
||||
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#kode').val('');
|
||||
$('#nama').val('');
|
||||
$('#limit_stock').val('');
|
||||
}
|
||||
|
||||
// ADD
|
||||
$('.btn-add').click(function(){
|
||||
resetForm();
|
||||
action = 'add';
|
||||
$('#modalKodebarang').modal('show');
|
||||
});
|
||||
|
||||
// EDIT
|
||||
$(document).on('click','.btn-editkode',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('kodebarang/detail/'); ?>"+id,function(res){
|
||||
|
||||
$('#id').val(res.id);
|
||||
$('#kode').val(res.kode_barang);
|
||||
$('#nama').val(res.nama);
|
||||
$('#limit_stock').val(res.limit_stock);
|
||||
|
||||
action = 'edit';
|
||||
$('#modalKodebarang').modal('show');
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// SAVE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
kode: $('#kode').val(),
|
||||
nama: $('#nama').val(),
|
||||
limit_stock: $('#limit_stock').val()
|
||||
};
|
||||
|
||||
if(!data.kode || !data.nama || !data.limit_stock){
|
||||
Swal.fire('Warning','Nama gudang wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('kodebarang/save'); ?>"
|
||||
: "<?= base_url('kodebarang/update'); ?>";
|
||||
|
||||
$.post(url,data,function(res){
|
||||
|
||||
if(res.status){
|
||||
$('#modalKodebarang').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Hapus gudang?',
|
||||
text:'Pastikan tidak dipakai item',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(r=>{
|
||||
if(r.isConfirmed){
|
||||
|
||||
$.get("<?= base_url('kodebarang/delete/'); ?>"+id,function(res){
|
||||
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,172 @@
|
||||
<div class="container mt-4">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
|
||||
<h4 class="mb-4 fw-bold text-center">Laporan Laba Rugi</h4>
|
||||
|
||||
<form id="filterForm" class="row g-2">
|
||||
|
||||
<div class="col-md-4">
|
||||
<label>Dari Tanggal</label>
|
||||
<input type="date" id="tanggal_dari" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label>Sampai Tanggal</label>
|
||||
<input type="date" id="tanggal_sampai" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-warning w-100">
|
||||
Tampilkan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<div id="content" class="mt-3"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
function loadData(dari = '', sampai = ''){
|
||||
|
||||
$.get("<?= base_url('labarugi/get_data'); ?>", {
|
||||
tanggal_dari: dari,
|
||||
tanggal_sampai: sampai
|
||||
}, function(res){
|
||||
|
||||
let html = '<div class="row">';
|
||||
|
||||
// ================= PENDAPATAN
|
||||
html += `
|
||||
<div class="col-md-6">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="text-success mb-3">Pendapatan</h5>
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kode</th>
|
||||
<th>Akun</th>
|
||||
<th class="text-end">Jumlah</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
res.data.forEach(r=>{
|
||||
if(r.tipe=='revenue'){
|
||||
let saldo = (parseFloat(r.kredit) - parseFloat(r.debit)) || 0;
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${r.kode_akun}</td>
|
||||
<td>${r.nama_akun}</td>
|
||||
<td class="text-end">${saldo.toLocaleString()}</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="fw-bold border-top">
|
||||
<td></td>
|
||||
<td>Total Pendapatan</td>
|
||||
<td class="text-end text-success">${Number(res.revenue).toLocaleString()}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// ================= BEBAN
|
||||
html += `
|
||||
<div class="col-md-6">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="text-danger mb-3">Beban</h5>
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kode</th>
|
||||
<th>Akun</th>
|
||||
<th class="text-end">Jumlah</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
res.data.forEach(r=>{
|
||||
if(r.tipe=='expense'){
|
||||
let saldo = (parseFloat(r.debit) - parseFloat(r.kredit)) || 0;
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${r.kode_akun}</td>
|
||||
<td>${r.nama_akun}</td>
|
||||
<td class="text-end">${saldo.toLocaleString()}</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="fw-bold border-top">
|
||||
<td></td>
|
||||
<td>Total Beban</td>
|
||||
<td class="text-end text-danger">${Number(res.expense).toLocaleString()}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
html += '</div>';
|
||||
|
||||
// ================= LABA
|
||||
html += `
|
||||
<div class="mt-4">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="mb-2">Laba Bersih</h5>
|
||||
<h3 class="${res.laba >= 0 ? 'text-success' : 'text-danger'} fw-bold">
|
||||
${Number(res.laba).toLocaleString()}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$('#content').html(html);
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
// LOAD AWAL
|
||||
loadData();
|
||||
|
||||
// FILTER
|
||||
$('#filterForm').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
let dari = $('#tanggal_dari').val();
|
||||
let sampai = $('#tanggal_sampai').val();
|
||||
|
||||
loadData(dari, sampai);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,151 @@
|
||||
<div class="container mt-4">
|
||||
|
||||
<!-- ================= FILTER PERIODE -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
|
||||
<h4 class="mb-4 fw-bold text-center">NERACA</h4><hr>
|
||||
|
||||
<form id="filterForm" class="row g-2">
|
||||
|
||||
<div class="col-md-4">
|
||||
<label>Dari Tanggal</label>
|
||||
<input type="date" name="tanggal_dari" id="tanggal_dari" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label>Sampai Tanggal</label>
|
||||
<input type="date" name="tanggal_sampai" id="tanggal_sampai" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-warning w-100">
|
||||
Tampilkan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- ACTIVA -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h5>ACTIVA</h5>
|
||||
|
||||
<table class="table">
|
||||
<tbody id="activaBody"></tbody>
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td>Total Activa</td>
|
||||
<td id="totalActiva"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PASIVA -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h5>PASIVA</h5>
|
||||
|
||||
<table class="table">
|
||||
<tbody id="pasivaBody"></tbody>
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td>Total Pasiva</td>
|
||||
<td id="totalPasiva"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
function loadData(tanggal_dari = '', tanggal_sampai = ''){
|
||||
|
||||
$.get("<?= base_url('neraca/get_data'); ?>", {
|
||||
tanggal_dari: tanggal_dari,
|
||||
tanggal_sampai: tanggal_sampai
|
||||
}, function(res){
|
||||
|
||||
let act = '', pas = '';
|
||||
|
||||
// ================= ACTIVA
|
||||
res.activa.forEach(a=>{
|
||||
act += `<tr>
|
||||
<td>${a.kode} - ${a.nama}</td>
|
||||
<td class="text-end">${Number(a.saldo).toLocaleString()}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
// ================= PASIVA
|
||||
res.pasiva.forEach(p=>{
|
||||
pas += `<tr>
|
||||
<td>${p.kode} - ${p.nama}</td>
|
||||
<td class="text-end">${Number(p.saldo).toLocaleString()}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
$('#activaBody').html(act);
|
||||
$('#pasivaBody').html(pas);
|
||||
|
||||
$('#totalActiva').text(Number(res.total_activa).toLocaleString());
|
||||
$('#totalPasiva').text(Number(res.total_pasiva).toLocaleString());
|
||||
|
||||
// reset warna dulu
|
||||
$('#totalActiva, #totalPasiva')
|
||||
.removeClass('text-danger text-success');
|
||||
|
||||
// ================= VALIDASI BALANCE
|
||||
if(Math.round(res.total_activa) !== Math.round(res.total_pasiva)){
|
||||
|
||||
$('#totalActiva').addClass('text-danger');
|
||||
$('#totalPasiva').addClass('text-danger');
|
||||
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Neraca Tidak Balance!',
|
||||
text: 'Selisih: ' + Number(res.selisih).toLocaleString()
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
$('#totalActiva').addClass('text-success');
|
||||
$('#totalPasiva').addClass('text-success');
|
||||
}
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
// ================= LOAD AWAL
|
||||
loadData();
|
||||
|
||||
// ================= SUBMIT FILTER
|
||||
$('#filterForm').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
let dari = $('#tanggal_dari').val();
|
||||
let sampai = $('#tanggal_sampai').val();
|
||||
|
||||
loadData(dari, sampai);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,66 @@
|
||||
<div class="container mt-4">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0 fw-bold">Neraca Saldo</h4>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped table-hover align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 120px;">Kode</th>
|
||||
<th>Akun</th>
|
||||
<th class="text-end">Debit</th>
|
||||
<th class="text-end">Kredit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tb"></tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr class="fw-bold">
|
||||
<th colspan="2" class="text-end">Total</th>
|
||||
<th class="text-end text-primary" id="td"></th>
|
||||
<th class="text-end text-danger" id="tk"></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
$.get("<?= base_url('neracasaldo/get_data'); ?>", function(res){
|
||||
|
||||
let html = '';
|
||||
let td = 0, tk = 0;
|
||||
|
||||
res.forEach(r=>{
|
||||
|
||||
let debit = parseFloat(r.saldo_debit) || 0;
|
||||
let kredit = parseFloat(r.saldo_kredit) || 0;
|
||||
|
||||
td += debit;
|
||||
tk += kredit;
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td class="fw-semibold text-muted">${r.kode_akun}</td>
|
||||
<td>${r.nama_akun}</td>
|
||||
<td class="text-end">${debit.toLocaleString()}</td>
|
||||
<td class="text-end">${kredit.toLocaleString()}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
$('#tb').html(html);
|
||||
$('#td').text(td.toLocaleString());
|
||||
$('#tk').text(tk.toLocaleString());
|
||||
|
||||
}, 'json');
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,153 @@
|
||||
<div class="container mt-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>Data Lokasi Aset</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableWarehouse" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Lokasi</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalWarehouse">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Lokasi Aset</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<label>Nama Lokasi Aset</label>
|
||||
<input type="text" id="nama" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
|
||||
let table = $('#tableWarehouse').DataTable({
|
||||
ajax:{
|
||||
url:"<?= base_url('lokasiasset/get_data'); ?>",
|
||||
type:"POST"
|
||||
}
|
||||
});
|
||||
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#nama').val('');
|
||||
}
|
||||
|
||||
// ADD
|
||||
$('.btn-add').click(function(){
|
||||
resetForm();
|
||||
action = 'add';
|
||||
$('#modalWarehouse').modal('show');
|
||||
});
|
||||
|
||||
// EDIT
|
||||
$(document).on('click','.btn-editgudang',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('lokasiasset/detail/'); ?>"+id,function(res){
|
||||
|
||||
$('#id').val(res.id);
|
||||
$('#nama').val(res.nama);
|
||||
|
||||
action = 'edit';
|
||||
$('#modalWarehouse').modal('show');
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// SAVE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
nama: $('#nama').val()
|
||||
};
|
||||
|
||||
if(!data.nama){
|
||||
Swal.fire('Warning','Nama gudang wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('lokasiasset/save'); ?>"
|
||||
: "<?= base_url('lokasiasset/update'); ?>";
|
||||
|
||||
$.post(url,data,function(res){
|
||||
|
||||
if(res.status){
|
||||
$('#modalWarehouse').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Hapus gudang?',
|
||||
text:'Pastikan tidak dipakai item',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(r=>{
|
||||
if(r.isConfirmed){
|
||||
|
||||
$.get("<?= base_url('lokasiasset/delete/'); ?>"+id,function(res){
|
||||
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,261 @@
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
|
||||
// =====================================================
|
||||
// 🔥 FORMAT NUMBER
|
||||
// contoh:
|
||||
// 1000 => 1,000
|
||||
// 1000.5 => 1,000.5
|
||||
// 1000.55 => 1,000.55
|
||||
// =====================================================
|
||||
|
||||
function formatNumber(value){
|
||||
|
||||
if(value === null || value === undefined){
|
||||
return '';
|
||||
}
|
||||
|
||||
value = value.toString();
|
||||
|
||||
// hanya angka dan titik
|
||||
value = value.replace(/[^0-9.]/g, '');
|
||||
|
||||
// hanya boleh 1 titik
|
||||
let parts = value.split('.');
|
||||
|
||||
let integerPart = parts[0] || '';
|
||||
let decimalPart = parts[1] || '';
|
||||
|
||||
// format ribuan pakai koma
|
||||
integerPart = integerPart.replace(/,/g, '');
|
||||
integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
|
||||
// max 2 digit decimal
|
||||
decimalPart = decimalPart.substring(0,2);
|
||||
|
||||
// kalau ada desimal
|
||||
if(parts.length > 1 || value.endsWith('.')){
|
||||
return integerPart + '.' + decimalPart;
|
||||
}
|
||||
|
||||
return integerPart;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 🔥 CLEAN NUMBER
|
||||
// hasil:
|
||||
// 1,000.25 => 1000.25
|
||||
// =====================================================
|
||||
|
||||
function cleanNumber(value){
|
||||
|
||||
if(!value) return '';
|
||||
|
||||
return value.toString().replace(/,/g, '');
|
||||
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 🔥 AUTO FORMAT INPUT
|
||||
// =====================================================
|
||||
|
||||
$(document).on('input', '.format-rupiah', function(){
|
||||
|
||||
let cursorPos = this.selectionStart;
|
||||
|
||||
let beforeLength = $(this).val().length;
|
||||
|
||||
let formatted = formatNumber($(this).val());
|
||||
|
||||
$(this).val(formatted);
|
||||
|
||||
let afterLength = formatted.length;
|
||||
|
||||
cursorPos = cursorPos + (afterLength - beforeLength);
|
||||
|
||||
this.setSelectionRange(cursorPos, cursorPos);
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// 🔥 FORMAT SAAT BLUR
|
||||
// =====================================================
|
||||
|
||||
$(document).on('blur', '.format-rupiah', function(){
|
||||
|
||||
$(this).val(
|
||||
formatNumber($(this).val())
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// 🔥 AUTO CLEAN SAAT SUBMIT
|
||||
// =====================================================
|
||||
|
||||
$(document).on('submit', 'form', function(){
|
||||
|
||||
$(this).find('.format-rupiah').each(function(){
|
||||
|
||||
$(this).val(
|
||||
cleanNumber($(this).val())
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// 🔥 AUTO FORMAT VALUE AWAL
|
||||
// =====================================================
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
$('.format-rupiah').each(function(){
|
||||
|
||||
let val = $(this).val();
|
||||
|
||||
if(val !== ''){
|
||||
|
||||
$(this).val(
|
||||
formatNumber(val)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// =====================================================
|
||||
// 🔥 OVERRIDE jQuery .val()
|
||||
// =====================================================
|
||||
|
||||
(function($){
|
||||
|
||||
const originalVal = $.fn.val;
|
||||
|
||||
$.fn.val = function(value){
|
||||
|
||||
// setter
|
||||
if(typeof value !== 'undefined'){
|
||||
|
||||
if(this.hasClass('format-rupiah')){
|
||||
|
||||
return originalVal.call(
|
||||
this,
|
||||
formatNumber(value)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return originalVal.apply(this, arguments);
|
||||
}
|
||||
|
||||
// getter
|
||||
if(this.hasClass('format-rupiah')){
|
||||
|
||||
return cleanNumber(
|
||||
originalVal.call(this)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return originalVal.call(this);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
function formatRupiah(num){
|
||||
return 'Rp ' + new Intl.NumberFormat('id-ID').format(num || 0);
|
||||
}
|
||||
|
||||
function formatTglIndo(dateString){
|
||||
|
||||
if(!dateString) return '-';
|
||||
|
||||
let date = new Date(dateString);
|
||||
|
||||
const bulan = [
|
||||
"Januari","Februari","Maret","April","Mei","Juni",
|
||||
"Juli","Agustus","September","Oktober","November","Desember"
|
||||
];
|
||||
|
||||
let tgl = date.getDate();
|
||||
let bln = bulan[date.getMonth()];
|
||||
let thn = date.getFullYear();
|
||||
|
||||
return `${tgl} ${bln} ${thn}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
function initSelectSearch(scope = document){
|
||||
|
||||
if (typeof $.fn.select2 === 'undefined') {
|
||||
console.error('Select2 belum ke-load!');
|
||||
return;
|
||||
}
|
||||
|
||||
$(scope).find('select.select-search').each(function(){
|
||||
|
||||
let $this = $(this);
|
||||
|
||||
if ($this.hasClass("select2-hidden-accessible")) return;
|
||||
|
||||
let parent = $this.closest('.modal');
|
||||
parent = parent.length ? parent : $(document.body);
|
||||
|
||||
$this.select2({
|
||||
width: '100%',
|
||||
placeholder: $this.attr('placeholder') || '-- Pilih --',
|
||||
allowClear: true,
|
||||
dropdownParent: parent
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ INIT AWAL
|
||||
initSelectSearch();
|
||||
|
||||
// $(window).on('load', function(){
|
||||
// setTimeout(() => {
|
||||
// initSelectSearch();
|
||||
// }, 100);
|
||||
// });
|
||||
|
||||
// ✅ AUTO INIT untuk dynamic content (modal, ajax, dll)
|
||||
const observer = new MutationObserver(function(mutations){
|
||||
|
||||
mutations.forEach(function(mutation){
|
||||
|
||||
mutation.addedNodes.forEach(function(node){
|
||||
|
||||
if (node.nodeType === 1){ // element
|
||||
initSelectSearch(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,394 @@
|
||||
<?php $role = $this->session->userdata('role'); ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Accounting</title>
|
||||
<link rel="icon" href="<?= base_url('assets/img/accounting-color.png') ?>" type="image/png">
|
||||
|
||||
<!-- Bootstrap 5 -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Bootstrap Icons -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
|
||||
|
||||
<!-- Google Font -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="<?= base_url('assets/css/style-custom.css'); ?>" rel="stylesheet">
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.4.1/css/responsive.bootstrap5.min.css">
|
||||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/responsive/2.4.1/js/dataTables.responsive.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script>
|
||||
|
||||
|
||||
<!-- Daterange Picker -->
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
|
||||
|
||||
<!-- Select2 STABLE -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ───────────────────────── NAVBAR ───────────────────────── -->
|
||||
<nav class="navbar navbar-expand-lg fixed-top">
|
||||
<div class="container">
|
||||
|
||||
<!-- Mobile menu button -->
|
||||
<button class="btn text-white d-lg-none me-2" data-bs-toggle="offcanvas" data-bs-target="#mobileMenu">
|
||||
<i class="bi bi-list fs-3"></i>
|
||||
</button>
|
||||
|
||||
<img src="<?= base_url('assets/img/accounting-white.png'); ?>" width="50px">
|
||||
|
||||
<div class="collapse navbar-collapse d-none d-lg-flex">
|
||||
<ul class="navbar-nav ms-4">
|
||||
|
||||
<!-- DASHBOARD -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= ($active_menu == 'dashboard') ? 'active' : ''?>" href="<?= base_url(); ?>">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= ($active_menu == 'jurnal') ? 'active' : ''?>" href="<?= base_url('jurnal'); ?>">
|
||||
<i class="bi bi-journal-plus"></i> Jurnal Umum
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php if($role == 'Admin'): ?>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= ($active_menu == 'buku_besar') ? 'active' : ''?>" href="<?= base_url('bukubesar'); ?>">
|
||||
<i class="bi bi-book"></i> Buku Besar
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['laba_rugi','neraca','neraca_saldo']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-graph-up"></i> Laporan
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'neraca_saldo') ? 'active' : '' ?>" href="<?= base_url('neracasaldo'); ?>">
|
||||
<i class="bi bi-clipboard-data me-2"></i> Neraca Saldo</a>
|
||||
</li>
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'laba_rugi') ? 'active' : '' ?>" href="<?= base_url('labarugi'); ?>">
|
||||
<i class="bi bi-graph-up-arrow me-2"></i> Laba Rugi</a>
|
||||
</li>
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'neraca') ? 'active' : '' ?>" href="<?= base_url('neraca'); ?>">
|
||||
<i class="bi bi-bar-chart-line me-2"></i> Neraca</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['accounts','basejurnal']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-list-nested"></i> Daftar Akun
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<?php if($role == 'Admin'): ?>
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'accounts') ? 'active' : '' ?>"
|
||||
href="<?= base_url('accounts'); ?>">
|
||||
<i class="bi bi-list-nested"></i> Base Akun
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'basejurnal') ? 'active' : '' ?>"
|
||||
href="<?= base_url('basejurnal'); ?>">
|
||||
<i class="bi bi-arrow-left-right"></i> Base Jurnal
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!--<li class="nav-item">-->
|
||||
<!-- <a class="nav-link <?= ($active_menu == 'asset') ? 'active' : ''?>" href="<?= base_url('asset'); ?>">-->
|
||||
<!-- <i class="bi bi-book"></i> Asset-->
|
||||
<!-- </a>-->
|
||||
<!--</li>-->
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['asset','lokasiasset']) ? 'active' : '' ?>"
|
||||
href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-archive"></i> Asset
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<!-- Daftar Asset -->
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'asset') ? 'active' : '' ?>"
|
||||
href="<?= base_url('asset'); ?>">
|
||||
<i class="bi bi-archive me-2"></i> Daftar Asset
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- Lokasi Asset -->
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'lokasiasset') ? 'active' : '' ?>"
|
||||
href="<?= base_url('lokasiasset'); ?>">
|
||||
<i class="bi bi-geo-alt me-2"></i> Lokasi Asset
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['warehouses','items', 'kode_barang', 'draft_items']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-box-seam"></i> Gudang
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'warehouses') ? 'active' : '' ?>"
|
||||
href="<?= base_url('warehouses'); ?>">
|
||||
<i class="bi bi-building me-2"></i> Daftar Gudang
|
||||
</a>
|
||||
</li><hr class="dropdown-divider">
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'draft_items') ? 'active' : '' ?>"
|
||||
href="<?= base_url('items/draft_items'); ?>">
|
||||
<i class="bi bi-truck me-2"></i> Daftar Pending
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'items') ? 'active' : '' ?>"
|
||||
href="<?= base_url('items'); ?>">
|
||||
<i class="bi bi-box me-2"></i> Daftar Barang
|
||||
</a>
|
||||
</li><hr class="dropdown-divider">
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'kode_barang') ? 'active' : '' ?>"
|
||||
href="<?= base_url('kodebarang'); ?>">
|
||||
<i class="bi bi-code me-2"></i> Daftar Kode Barang
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['customers','invoice_unpaid','invoice_paid','payments','invoice_draft']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-receipt"></i> Invoice
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- Customers -->
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'customers') ? 'active' : '' ?>" href="<?= base_url('customers'); ?>">
|
||||
<i class="bi bi-people me-2"></i> Customers
|
||||
</a>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<!-- Draft -->
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'invoice_draft') ? 'active' : '' ?>" href="<?= base_url('invoices/draft'); ?>">
|
||||
<i class="bi bi-pencil-square me-2"></i> Draft Invoice
|
||||
</a>
|
||||
</li>
|
||||
<!-- Riwayat Invoice -->
|
||||
<li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'invoice_paid') ? 'active' : '' ?>" href="<?= base_url('invoices/paid'); ?>">
|
||||
<i class="bi bi-check-circle me-2"></i> Riwayat Invoice
|
||||
</a>
|
||||
</li>
|
||||
<!-- Pembayaran -->
|
||||
<!-- <li>
|
||||
<a class="dropdown-item <?= ($active_menu == 'payments') ? 'active' : '' ?>" href="<?= base_url('payments'); ?>">
|
||||
<i class="bi bi-cash-stack me-2"></i> Pembayaran
|
||||
</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['employees','shift','holidays','attendance_monitoring','leave_requests','generate_schedule']) ? 'active' : '' ?>"
|
||||
href="#"
|
||||
data-bs-toggle="dropdown">
|
||||
|
||||
<i class="bi bi-people-fill me-1"></i>
|
||||
Kepegawaian
|
||||
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu shadow border-0 rounded-4 p-2">
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'employees') ? 'active' : '' ?>"
|
||||
href="<?= base_url('employees'); ?>">
|
||||
|
||||
<i class="bi bi-person-vcard-fill me-2"></i>
|
||||
Data Karyawan
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'generate_schedule') ? 'active' : '' ?>"
|
||||
href="<?= base_url('generateschedule'); ?>">
|
||||
|
||||
<i class="bi bi-calendar3-week-fill me-2"></i>
|
||||
Jadwal Kerja
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'attendance_monitoring') ? 'active' : '' ?>"
|
||||
href="<?= base_url('attendancemonitoring'); ?>">
|
||||
|
||||
<i class="bi bi-fingerprint me-2"></i>
|
||||
Monitoring Absensi
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<hr class="dropdown-divider">
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'shift') ? 'active' : '' ?>"
|
||||
href="<?= base_url('shifts'); ?>">
|
||||
|
||||
<i class="bi bi-alarm-fill me-2"></i>
|
||||
Data Shift
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'holidays') ? 'active' : '' ?>"
|
||||
href="<?= base_url('holidays'); ?>">
|
||||
|
||||
<i class="bi bi-calendar2-heart-fill me-2"></i>
|
||||
Hari Libur
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'leave_requests') ? 'active' : '' ?>"
|
||||
href="<?= base_url('leaverequests'); ?>">
|
||||
|
||||
<i class="bi bi-calendar-check-fill me-2"></i>
|
||||
Cuti & Izin
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<hr class="dropdown-divider">
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'payroll') ? 'active' : '' ?>"
|
||||
href="<?= base_url('payroll'); ?>">
|
||||
|
||||
<i class="bi bi-cash-stack me-2"></i>
|
||||
Penggajihan
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<?php if($role == 'Admin'): ?>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['umum','users']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-gear"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'umum') ? 'active' : '' ?>" href="<?= base_url('umum'); ?>">
|
||||
<i class="bi bi-sliders me-2"></i> Umum</a>
|
||||
</li>
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'users') ? 'active' : '' ?>" href="<?= base_url('users'); ?>">
|
||||
<i class="bi bi-person-gear me-2"></i> Users</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="btn btn-premium dropdown-toggle" href="#" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle me-1"></i> <?= $this->session->username; ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item <?= ($active_menu == 'profile') ? 'active' : '' ?>" href="<?= base_url('profile'); ?>">
|
||||
<i class="bi bi-person me-2"></i> Profile</a></li>
|
||||
<li><a class="dropdown-item" href="<?= base_url('auth/logout'); ?>">
|
||||
<i class="bi bi-box-arrow-right me-2"></i> Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div style="height: 70px;"></div>
|
||||
|
||||
|
||||
<!-- ───────────────────────── SIDEBAR MOBILE ───────────────────────── -->
|
||||
<div class="offcanvas offcanvas-start" tabindex="-1" id="mobileMenu">
|
||||
<div class="offcanvas-header">
|
||||
<span class="brand-mobile">🌿 Sekolah Islami</span>
|
||||
<button class="btn-close" data-bs-dismiss="offcanvas"></button>
|
||||
</div>
|
||||
|
||||
<div class="offcanvas-body">
|
||||
<ul class="nav flex-column">
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= ($active_menu == 'dashboard') ? 'active' : ''?>" href="<?= base_url(); ?>">
|
||||
<span class="menu-wrap"><i class="bi bi-speedometer2"></i> Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="sidebar-divider"></div>
|
||||
|
||||
<a href="<?= base_url('logout'); ?>" class="btn btn-logout">
|
||||
<i class="bi bi-box-arrow-right me-2"></i> Logout
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,109 @@
|
||||
<style>
|
||||
/* Style to truncate long text in table cells */
|
||||
.truncate-text {
|
||||
max-width: 300px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">Riwayat Pesan</h5>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tablePesan" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Waktu</th>
|
||||
<th>Tipe</th>
|
||||
<th>Penerima</th>
|
||||
<th>Pesan</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for full message -->
|
||||
<div class="modal fade" id="pesanModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Isi Pesan Lengkap</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" style="white-space: pre-wrap; word-wrap: break-word;">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
let table = $('#tablePesan').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"l f>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('pesan/get_data'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4 },
|
||||
{ data: 5 }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 4, // Target the 'Pesan' column
|
||||
createdCell: function (td, cellData, rowData, row, col) {
|
||||
$(td).attr('title', 'Klik untuk lihat lengkap');
|
||||
}
|
||||
}
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input').attr('placeholder', 'Cari pesan, nomor, email...').css({
|
||||
'min-width': '300px',
|
||||
'padding': '6px 12px',
|
||||
'border-radius': '6px',
|
||||
'border': '1px solid #ced4da',
|
||||
'font-size': '0.9rem',
|
||||
'box-sizing': 'border-box'
|
||||
});
|
||||
|
||||
// Handle click on truncated text to show full message in modal
|
||||
$('#tablePesan tbody').on('click', 'td .truncate-text', function () {
|
||||
var fullText = $(this).text();
|
||||
$('#pesanModal .modal-body').text(fullText);
|
||||
var pesanModal = new bootstrap.Modal(document.getElementById('pesanModal'));
|
||||
pesanModal.show();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,207 @@
|
||||
<div class="container mt-4">
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-4 text-center">
|
||||
<h5 id="judulscan">Silahkan Scan QR <?= ucfirst($scan_type); ?></h5>
|
||||
<div id="reader" style="max-width: 50%; margin: 0 auto;"></div>
|
||||
<div id="result" class="mt-4">Hasil scan akan muncul di sini</div>
|
||||
<button class="btn btn-success btn-add mt-3" id="backBtn" style="display:none;">Ulangi Scan</button>
|
||||
<a href="<?= base_url(); ?>" class="btn btn-success btn-add mt-3">Kembali</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Modern Detail Card Style */
|
||||
.detail-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
max-width: 450px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.detail-card img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid #fb6340;
|
||||
}
|
||||
.detail-card h2 {
|
||||
margin-top: 15px;
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
color: #555;
|
||||
}
|
||||
.detail-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.detail-label {
|
||||
font-weight: 600;
|
||||
color: #fb6340;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let scanner;
|
||||
const resultDiv = document.getElementById("result");
|
||||
const backBtn = document.getElementById("backBtn");
|
||||
const judul = document.getElementById("judulscan");
|
||||
|
||||
function startScanner() {
|
||||
scanner = new Html5Qrcode("reader");
|
||||
|
||||
Html5Qrcode.getCameras().then(cameras => {
|
||||
if (cameras && cameras.length) {
|
||||
let cameraId = cameras[0].id;
|
||||
const backCamera = cameras.find(cam =>
|
||||
cam.label.toLowerCase().includes("back")
|
||||
);
|
||||
if (backCamera) cameraId = backCamera.id;
|
||||
|
||||
scanner.start(
|
||||
cameraId,
|
||||
{ fps: 10, qrbox: { width: 250, height: 250 } },
|
||||
qrCodeMessage => {
|
||||
|
||||
// Stop scanner
|
||||
scanner.stop().then(() => {
|
||||
scanner.clear();
|
||||
|
||||
// Kirim data ke server
|
||||
fetch('<?= site_url("cameraqrscan/get_data"); ?>', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
qr_code: qrCodeMessage,
|
||||
scan_type: '<?= $scan_type ?>'
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
// Jika sukses (status true)
|
||||
if (data.status) {
|
||||
|
||||
// Jika ada peringatan 5 menit
|
||||
if (data.message && data.message.includes("5 menit")) {
|
||||
showDetail(data.data, true, data.message);
|
||||
}
|
||||
// Sukses normal
|
||||
else {
|
||||
showDetail(data.data, false, "");
|
||||
}
|
||||
|
||||
} else {
|
||||
// Jika error lain
|
||||
resultDiv.innerHTML = `
|
||||
<p class="text-danger">${data.message}</p>
|
||||
`;
|
||||
backBtn.style.display = "inline-block";
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
errorMessage => {
|
||||
console.warn(errorMessage);
|
||||
}
|
||||
).catch(err => {
|
||||
console.error("Start scanner error:", err);
|
||||
alert("Gagal membuka kamera: " + err);
|
||||
});
|
||||
|
||||
} else {
|
||||
alert("Tidak ada kamera terdeteksi");
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error("Camera error:", err);
|
||||
alert("Tidak bisa mengakses kamera: " + err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===========================================
|
||||
// TAMPIL DETAIL DATA + WARNING JIKA PERLU
|
||||
// ===========================================
|
||||
function showDetail(data, isWarning = false, warningText = "") {
|
||||
|
||||
const foto = data.foto
|
||||
? `<?= base_url('uploads/siswa/') ?>` + data.foto
|
||||
: 'https://storage.manjapro.net/file/users/avatar/default.jpg';
|
||||
|
||||
let warningHtml = "";
|
||||
if (isWarning) {
|
||||
warningHtml = `
|
||||
<div class="alert alert-warning mt-3">
|
||||
⚠️ ${warningText}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
let html = `
|
||||
${warningHtml}
|
||||
|
||||
<h2>Scan <?= ucfirst($scan_type) ?> Berhasil</h2>
|
||||
|
||||
<div class="detail-card text-center">
|
||||
<img src="${foto}" alt="Foto Siswa">
|
||||
|
||||
<h2>${data.nama}</h2>
|
||||
|
||||
<div class="detail-row mt-3">
|
||||
<div class="detail-label">Kelas</div>
|
||||
<div>${data.nama_kelas}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-row mt-3">
|
||||
<div class="detail-label">Kamar</div>
|
||||
<div>${data.nama_kamar} (${data.nama_gedung_kamar})</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Alamat</div>
|
||||
<div>${data.alamat}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Nama Orang Tua</div>
|
||||
<div>${data.nama_wali}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Waktu</div>
|
||||
<div>${data.created_at}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
resultDiv.innerHTML = html;
|
||||
|
||||
backBtn.style.display = "inline-block";
|
||||
judul.style.display = "none";
|
||||
}
|
||||
|
||||
|
||||
// ===========================================
|
||||
// TOMBOL ULANGI SCAN
|
||||
// ===========================================
|
||||
backBtn.addEventListener("click", () => {
|
||||
resultDiv.innerText = "Hasil scan akan muncul di sini";
|
||||
backBtn.style.display = "none";
|
||||
judul.style.display = "block";
|
||||
startScanner();
|
||||
});
|
||||
|
||||
|
||||
// ===========================================
|
||||
// MULAI SCANNER SAAT PAGE LOAD
|
||||
// ===========================================
|
||||
window.onload = startScanner;
|
||||
</script>
|
||||
@@ -0,0 +1,444 @@
|
||||
<?php if(check_permission('setting', 'can_view')): ?>
|
||||
<div class="container mt-4">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="mb-0">Pengaturan</h5>
|
||||
</div>
|
||||
|
||||
<div class="row lign-items-stretch">
|
||||
|
||||
<!-- ================== 1. PENGATURAN UMUM ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h6 class="mb-0">Umum</h6>
|
||||
<hr>
|
||||
|
||||
<form action="<?= base_url('setting/save_umum') ?>" method="POST">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nama Lembaga</label>
|
||||
<input type="text" name="nama_lembaga" class="form-control" value="<?= $config->nama_lembaga ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Pimpinan Lembaga</label>
|
||||
<input type="text" name="pimpinan_lembaga" class="form-control" value="<?= $config->pimpinan_lembaga ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success btn-add rounded-3">
|
||||
Simpan
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================== 2. SETTING CARD ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h6 class="mb-0">Setting Card</h6>
|
||||
<hr>
|
||||
<div class="items-card-center">
|
||||
|
||||
<img id="defaultBg" src="<?= base_url($config->card_background) ?>" hidden>
|
||||
<div id="cardPreview"></div>
|
||||
|
||||
<small class="text-muted d-block mt-2 mb-4">Preview akan berubah otomatis</small>
|
||||
</div>
|
||||
|
||||
<form action="<?= base_url('setting/save_card') ?>" method="POST" enctype="multipart/form-data">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Upload Background Kartu (Ukuran 300 x 480 pixel)</label>
|
||||
<input type="file" name="card_background" id="bgInput" class="form-control" accept="image/*">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success btn-add rounded-3">
|
||||
Simpan Background
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================== 3. SETTING WHATSAPP ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h6 class="mb-0">Setting Whatsapp</h6>
|
||||
<hr>
|
||||
|
||||
<form action="<?= base_url('setting/save_whatsapp') ?>" method="POST">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Mode WhatsApp</label>
|
||||
<select class="form-select" id="waMode" name="wa_mode">
|
||||
<option value="">-- Pilih --</option>
|
||||
<option value="official" <?= ($config->wa_mode == 'official' ) ? 'selected' : '' ?>>Official API</option>
|
||||
<option value="unofficial" <?= ($config->wa_mode == 'unofficial' ) ? 'selected' : '' ?>>Unofficial Gateway</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- OFFICIAL -->
|
||||
<div id="officialForm" style="display:none;">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Phone Number</label>
|
||||
<input type="text" name="wa_phone" class="form-control" value="<?= $config->wa_phone; ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Phone Number ID</label>
|
||||
<input type="text" name="wa_phone_id" class="form-control" value="<?= $config->wa_phone_id; ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">WABA ID</label>
|
||||
<input type="text" name="wa_waba_id" class="form-control" value="<?= $config->wa_waba_id; ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Access Token</label>
|
||||
<input type="text" name="wa_access_token" class="form-control" value="<?= $config->wa_access_token; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UNOFFICIAL -->
|
||||
<div id="unofficialForm" style="display:none;">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Endpoint URL</label>
|
||||
<input type="text" name="wa_endpoint" class="form-control" value="<?= $config->wa_endpoint; ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">API Key</label>
|
||||
<input type="text" name="wa_api_key" class="form-control" value="<?= $config->wa_api_key; ?>">
|
||||
</div>
|
||||
<center>
|
||||
<img id="waStatusImage" src="" style="width:220px; margin-top:15px;"><br>
|
||||
<button type="button" id="scanWhatsappQR" class="btn btn-success btn-add rounded-3 mb-4">
|
||||
Cek Tautan Whatsapp Gateway
|
||||
</button>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success btn-add rounded-3">
|
||||
Simpan
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================== 4. TEMPLATE PESAN ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h6 class="mb-0">Setting Template Pesan</h6>
|
||||
<hr>
|
||||
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th>Nama</th>
|
||||
<th>Pesan</th>
|
||||
<th width="10%">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($template_pesan as $i => $row): ?>
|
||||
<tr>
|
||||
<td><?= $i+1 ?></td>
|
||||
<td><?= $row->nama_template ?></td>
|
||||
<td><?= $row->isi_template ?></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#editModal<?= $row->id ?>">
|
||||
Edit
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Modal Edit -->
|
||||
<div class="modal fade" id="editModal<?= $row->id ?>">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
<div class="modal-header">
|
||||
<h6 class="modal-title">Edit Pesan</h6>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<form action="<?= base_url('setting/update_template_pesan') ?>" method="POST">
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" name="id" value="<?= $row->id ?>">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nama</label>
|
||||
<input type="text" name="nama_template" class="form-control" value="<?= $row->nama_template ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Pesan</label>
|
||||
<textarea name="isi_template" class="form-control" rows="12"><?= $row->isi_template ?></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-primary">Simpan</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- JS untuk dynamic show/hide -->
|
||||
<script>
|
||||
function showWaMode(mode) {
|
||||
document.getElementById("officialForm").style.display = (mode === "official") ? "block" : "none";
|
||||
document.getElementById("unofficialForm").style.display = (mode === "unofficial") ? "block" : "none";
|
||||
}
|
||||
|
||||
// Saat dropdown berubah
|
||||
document.getElementById("waMode").addEventListener("change", function() {
|
||||
showWaMode(this.value);
|
||||
});
|
||||
|
||||
// Saat halaman pertama kali load → pakai value dari dropdown (sudah diset PHP)
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
let initial = document.getElementById("waMode").value;
|
||||
showWaMode(initial);
|
||||
});
|
||||
|
||||
|
||||
// =====================================================
|
||||
// 1. LOAD BACKGROUND DEFAULT SAAT PAGE AWAL TERBUKA
|
||||
// =====================================================
|
||||
window.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
let defaultBgElement = document.getElementById("defaultBg");
|
||||
let preview = document.getElementById("cardPreview");
|
||||
|
||||
if (!defaultBgElement) {
|
||||
console.error("defaultBg tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
if (!preview) {
|
||||
console.error("cardPreview tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
let defaultBg = defaultBgElement.src;
|
||||
if (defaultBg && defaultBg !== "") {
|
||||
validateAndLoadCard(defaultBg);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// =====================================================
|
||||
// 2. EVENT: USER UPLOAD GAMBAR BACKGROUND BARU
|
||||
// =====================================================
|
||||
document.getElementById("bgInput").addEventListener("change", function (e) {
|
||||
let file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (evt) {
|
||||
validateAndLoadCard(evt.target.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
|
||||
// =====================================================
|
||||
// 3. VALIDASI RASIO GAMBAR (PORTRAIT / LANDSCAPE)
|
||||
// =====================================================
|
||||
function validateAndLoadCard(imgSrc) {
|
||||
let img = new Image();
|
||||
|
||||
img.onload = function () {
|
||||
let width = img.width;
|
||||
let height = img.height;
|
||||
|
||||
let ratio = width / height;
|
||||
console.log("Rasio gambar:", ratio);
|
||||
|
||||
let isPortrait = ratio < 0.9; // 2:3 atau sejenis
|
||||
let isLandscape = ratio > 1.2; // 3:2 atau sejenis
|
||||
|
||||
if (!isPortrait && !isLandscape) {
|
||||
alert("⚠️ Gambar tidak sesuai rasio ID Card!\nGunakan potret (2:3) atau landscape (3:2).");
|
||||
return;
|
||||
}
|
||||
|
||||
loadCardPreviewFromImage(imgSrc, isPortrait);
|
||||
};
|
||||
|
||||
img.onerror = function () {
|
||||
console.error("Gambar tidak bisa diload:", imgSrc);
|
||||
};
|
||||
|
||||
img.src = imgSrc;
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// 4. LOAD PREVIEW + GANTI TEMPLATE
|
||||
// =====================================================
|
||||
function loadCardPreviewFromImage(imgSrc, isPortrait) {
|
||||
let preview = document.getElementById("cardPreview");
|
||||
if (!preview) {
|
||||
console.error("Element #cardPreview tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set background image
|
||||
preview.style.backgroundImage = `url('${imgSrc}')`;
|
||||
|
||||
// Reset semua class
|
||||
preview.className = "";
|
||||
|
||||
// Tambahkan class sesuai orientasi
|
||||
if (isPortrait) {
|
||||
preview.classList.add("id-card-potret");
|
||||
preview.innerHTML = portraitTemplate();
|
||||
} else {
|
||||
preview.classList.add("id-card-lemscape");
|
||||
preview.innerHTML = landscapeTemplate();
|
||||
}
|
||||
|
||||
console.log("Template loaded:", isPortrait ? "Potret" : "Landscape");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function portraitTemplate() {
|
||||
return `
|
||||
<div class="card-inner">
|
||||
|
||||
<div class="card-logo">
|
||||
<img src="assets/img/logo.png">
|
||||
</div>
|
||||
|
||||
<div class="card-title">Kartu Tanda Wali Santri</div>
|
||||
|
||||
<div class="photo-wrapper">
|
||||
<img src="assets/img/foto.jpg">
|
||||
</div>
|
||||
|
||||
<div class="card-info">
|
||||
<div class="nama">Nama Santri</div>
|
||||
<div class="nis">NIS: 00000000</div>
|
||||
<div class="kelas">Tahun Masuk: -</div>
|
||||
<div class="alamat">Alamat lengkap tampil di sini...</div>
|
||||
</div>
|
||||
|
||||
<div class="qr-wrapper">
|
||||
<img src="assets/img/qr.png" width="100%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function landscapeTemplate() {
|
||||
return `
|
||||
<div class="card-inner">
|
||||
|
||||
<div class="card-logo">
|
||||
<img src="assets/img/logo.png">
|
||||
</div>
|
||||
|
||||
<div class="card-title">Kartu Tanda Wali Santri</div>
|
||||
|
||||
<div class="landscape-content">
|
||||
|
||||
<div class="photo-wrapper">
|
||||
<img src="assets/img/foto.jpg">
|
||||
</div>
|
||||
|
||||
<div class="card-info">
|
||||
<div class="nama">Nama Santri</div>
|
||||
<div class="nis">NIS: 00000000</div>
|
||||
<div class="kelas">Tahun Masuk: -</div>
|
||||
<div class="alamat">Alamat lengkap tampil di sini...</div>
|
||||
</div>
|
||||
|
||||
<div class="qr-wrapper">
|
||||
<img src="assets/img/qr.png" width="100%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------
|
||||
// Perintah untuk cek status whatsapp
|
||||
// -----------------------------
|
||||
|
||||
document.getElementById("scanWhatsappQR").addEventListener("click", function () {
|
||||
let counter = 0;
|
||||
let imgTag = document.getElementById("waStatusImage");
|
||||
|
||||
function checkStatusLoop() {
|
||||
fetch(`<?= base_url('setting/cek_whatsapp_status') ?>`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
console.log("Status:", data.status);
|
||||
|
||||
imgTag.src = data.img; // tampilkan gambar ke <img>
|
||||
|
||||
if (data.status === "CONNECTED") {
|
||||
console.log("Whatsapp sudah terhubung, stop loop");
|
||||
return; // STOP AUTOMATIS
|
||||
}
|
||||
|
||||
counter++;
|
||||
if (counter < 50) {
|
||||
setTimeout(checkStatusLoop, 2000);
|
||||
} else {
|
||||
console.log("Loop selesai 50x");
|
||||
}
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
checkStatusLoop();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<?php endif; ?>
|
||||
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
if(check_permission('siswa', 'can_view')):
|
||||
|
||||
$fotoSiswa = ($siswa->foto) ? base_url('uploads/siswa/'.$siswa->foto) : base_url('uploads/siswa/foto.jpg') ;
|
||||
|
||||
?>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
|
||||
<div class="container mt-4">
|
||||
<?php if(check_permission('siswa', 'can_update')): ?>
|
||||
<div class="text-end mb-3">
|
||||
<button class="btn btn-success btn-eximport d-none d-lg-inline" id="downloadPdfBtn">
|
||||
<i class="bi bi-file-earmark-pdf-fill me-1"></i> Export PDF Halaman Ini
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div id="containerDownload">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0 fw-bold">Detail Santri</h4>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-stretch">
|
||||
|
||||
<!-- ================== DETAIL SANTRI ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h5 class="fw-semibold">Informasi Santri</h5>
|
||||
<hr>
|
||||
|
||||
<center>
|
||||
<img class="foto-santri rounded-4 shadow-sm mb-3"
|
||||
src="<?= $fotoSiswa; ?>"
|
||||
style="width:160px;height:200px;object-fit:cover;">
|
||||
</center>
|
||||
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<th width="200">Nama</th>
|
||||
<td>: <?= $siswa->nama; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>NIS</th>
|
||||
<td>: <?= $siswa->nis; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Kelas</th>
|
||||
<td>: <?= $siswa->nama_kelas; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Kamar</th>
|
||||
<td>: <?= $siswa->nama_kamar . ' ('.$siswa->nama_gedung_kamar.')'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Tahun Masuk</th>
|
||||
<td>: <?= $siswa->tahun_masuk; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Alamat</th>
|
||||
<td>: <?= $siswa->alamat; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Nama Wali Santri</th>
|
||||
<td>: <?= $siswa->nama_wali; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>No Whatsapp Wali Santri</th>
|
||||
<td>: <?= $siswa->nomor_whatsapp; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email Wali Santri</th>
|
||||
<td>: <?= $siswa->email; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Jumlah Kunjungan</th>
|
||||
<td>: <?= $siswa->jumlah_kunjungan; ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================== KARTU WALI SANTRI ================== -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card shadow-sm border-0 rounded-4 h-100">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h5 class="fw-semibold">Kartu Tanda Wali Santri</h5>
|
||||
<hr>
|
||||
|
||||
<div class="items-card-center">
|
||||
<img id="defaultBg" src="<?= base_url($setting->card_background) ?>" hidden>
|
||||
<div id="cardPreview"></div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<?php if(check_permission('siswa', 'can_update')): ?>
|
||||
<button class="btn btn-success btn-add rounded-3 mt-4" onclick="printCardPDF()">
|
||||
<i class="bi bi-printer me-1"></i> Print ID Card
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card modern-card shadow-sm border-0 rounded-4 mt-3 mb-4">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-1">Riwayat Kunjungan</h5>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableHistory" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama</th>
|
||||
<th>NIS</th>
|
||||
<th>Kelas</th>
|
||||
<th>Kamar</th>
|
||||
<th>Nama Wali</th>
|
||||
<th>Alamat</th>
|
||||
<th>Jam Masuk</th>
|
||||
<th>Petugas Masuk</th>
|
||||
<th>Jam Keluar</th>
|
||||
<th>Petugas Keluar</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
let isInitialLoad = true;
|
||||
$('#dateRangeFilter').val('');
|
||||
|
||||
$('#dateRangeFilter').daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: { cancelLabel: false, format: 'YYYY-MM-DD' },
|
||||
linkedCalendars: false
|
||||
});
|
||||
|
||||
$('#dateRangeFilter').on('apply.daterangepicker', function(ev, picker) {
|
||||
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
$('#dateRangeFilter').on('cancel.daterangepicker', function(ev, picker) {
|
||||
$(this).val('');
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
let table = $('#tableHistory').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"l f>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('siswa/get_kunjungan'); ?>",
|
||||
type: "POST",
|
||||
data: function(d) {
|
||||
|
||||
// Tambahkan id_siswa dari PHP
|
||||
d.id_siswa = `<?= $siswa->id; ?>`;
|
||||
|
||||
// Tambahkan filter tanggal
|
||||
var picker = $('#dateRangeFilter').data('daterangepicker');
|
||||
if (picker && picker.startDate && picker.startDate.isValid()) {
|
||||
d.startDate = picker.startDate.format('YYYY-MM-DD');
|
||||
}
|
||||
if (picker && picker.endDate && picker.endDate.isValid()) {
|
||||
d.endDate = picker.endDate.format('YYYY-MM-DD');
|
||||
}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false }, // No
|
||||
{ data: 1 }, // Nama
|
||||
{ data: 2 }, // NIS
|
||||
{ data: 3 }, // Kelas
|
||||
{ data: 4 }, // Kamar
|
||||
{ data: 5 }, // Nama Wali
|
||||
{ data: 6 }, // Alamat
|
||||
{
|
||||
data: 7, // Jam Masuk
|
||||
render: function(data) {
|
||||
return data ? data : '';
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 8, // Media Masuk
|
||||
orderable: false,
|
||||
render: function(data) {
|
||||
return data ? data : '';
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 9, // Jam Keluar
|
||||
render: function(data) {
|
||||
return data ? data : '';
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 10, // Media Keluar
|
||||
orderable: false,
|
||||
render: function(data) {
|
||||
return data ? data : '';
|
||||
}
|
||||
}
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input').attr('placeholder', 'Cari nama, nis, kelas...').css({
|
||||
'padding': '6px 12px',
|
||||
'border-radius': '6px',
|
||||
'border': '1px solid #ced4da',
|
||||
'font-size': '0.9rem',
|
||||
'box-sizing': 'border-box'
|
||||
});
|
||||
|
||||
table.on('draw', function() {
|
||||
$('#tableHistory tbody tr').each(function() {
|
||||
$(this).find('td').each(function(index) {
|
||||
let header = $('#tableHistory thead th').eq(index).text().trim();
|
||||
$(this).attr('data-label', header + ' : ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
/* ============================================================
|
||||
1. DETEKSI ORIENTASI BACKGROUND & LOAD TEMPLATE OTOMATIS
|
||||
============================================================ */
|
||||
window.addEventListener("DOMContentLoaded", function () {
|
||||
let bg = document.getElementById("defaultBg");
|
||||
|
||||
if (!bg) {
|
||||
console.error("defaultBg tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Tunggu gambar background selesai diload
|
||||
bg.onload = function () {
|
||||
let isPortrait = bg.naturalHeight > bg.naturalWidth;
|
||||
|
||||
console.log("Background orientation:",
|
||||
isPortrait ? "POTRAIT" : "LANDSCAPE"
|
||||
);
|
||||
|
||||
loadCardPreviewFromImage(bg.src, isPortrait);
|
||||
};
|
||||
|
||||
// Jika gambar sudah cached & tidak trigger onload
|
||||
if (bg.complete) {
|
||||
bg.onload();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* ============================================================
|
||||
2. LOAD TEMPLATE CARD
|
||||
============================================================ */
|
||||
function loadCardPreviewFromImage(imgSrc, isPortrait) {
|
||||
let preview = document.getElementById("cardPreview");
|
||||
if (!preview) return;
|
||||
|
||||
preview.style.backgroundImage = "url('" + imgSrc + "')";
|
||||
preview.className = "";
|
||||
|
||||
if (isPortrait) {
|
||||
preview.classList.add("id-card-potret");
|
||||
preview.innerHTML = portraitTemplate();
|
||||
} else {
|
||||
preview.classList.add("id-card-lemscape");
|
||||
preview.innerHTML = landscapeTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
3. TEMPLATE POTRAIT
|
||||
============================================================ */
|
||||
function portraitTemplate() {
|
||||
return `
|
||||
<div class="card-inner">
|
||||
|
||||
<div class="card-logo">
|
||||
<img src="<?= base_url('assets/img/logo.png'); ?>">
|
||||
</div>
|
||||
|
||||
<div class="card-title">Kartu Tanda Wali Santri</div>
|
||||
|
||||
<div class="photo-wrapper">
|
||||
<img src="<?= $fotoSiswa; ?>">
|
||||
</div>
|
||||
|
||||
<div class="card-info">
|
||||
<div class="nama"><?= $siswa->nama; ?></div>
|
||||
<div class="nis">NIS: <?= $siswa->nis; ?></div>
|
||||
<div class="kelas">Tahun Masuk: <?= $siswa->tahun_masuk; ?></div>
|
||||
<div class="alamat"><?= $siswa->alamat; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="qr-wrapper">
|
||||
<img src="<?= base_url('qr/show/' . urlencode($siswa->qr_id)) ?>" width="100%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
4. TEMPLATE LANDSCAPE
|
||||
============================================================ */
|
||||
function landscapeTemplate() {
|
||||
return `
|
||||
<div class="card-inner">
|
||||
|
||||
<div class="card-logo">
|
||||
<img src="<?= base_url('assets/img/logo.png'); ?>">
|
||||
</div>
|
||||
|
||||
<div class="card-title">Kartu Tanda Wali Santri</div>
|
||||
|
||||
<div class="landscape-content">
|
||||
|
||||
<div class="photo-wrapper">
|
||||
<img src="<?= $fotoSiswa; ?>">
|
||||
</div>
|
||||
|
||||
<div class="card-info">
|
||||
<div class="nama"><?= $siswa->nama; ?></div>
|
||||
<div class="nis">NIS: <?= $siswa->nis; ?></div>
|
||||
<div class="kelas">Tahun Masuk: <?= $siswa->tahun_masuk; ?></div>
|
||||
<div class="alamat"><?= $siswa->alamat; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="qr-wrapper">
|
||||
<img src="<?= base_url('qr/show/' . urlencode($siswa->qr_id)) ?>" width="100%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
5. PRINT CARD DALAM MODE PDF
|
||||
============================================================ */
|
||||
function printCardPDF() {
|
||||
let card = document.getElementById("cardPreview");
|
||||
if (!card) {
|
||||
alert("Card Preview tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ambil semua CSS di halaman
|
||||
let styles = "";
|
||||
document.querySelectorAll("style, link[rel='stylesheet']").forEach((el) => {
|
||||
styles += el.outerHTML;
|
||||
});
|
||||
|
||||
// Buka jendela print
|
||||
let w = window.open("", "_blank");
|
||||
|
||||
w.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>Cetak Kartu Santri</title>
|
||||
${styles} <!-- COPY semua CSS -->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
zoom: 69%;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
/* Pastikan background ikut ke print */
|
||||
@media print {
|
||||
#cardPreview {
|
||||
-webkit-print-color-adjust: exact !important;
|
||||
print-color-adjust: exact !important;
|
||||
}
|
||||
* {
|
||||
-webkit-print-color-adjust: exact !important;
|
||||
print-color-adjust: exact !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${card.outerHTML}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
w.document.close();
|
||||
|
||||
// Tunggu elemen selesai render
|
||||
setTimeout(() => {
|
||||
w.print();
|
||||
// w.close(); // Kalau mau ditutup otomatis
|
||||
}, 500);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
document.getElementById('downloadPdfBtn').addEventListener('click', function() {
|
||||
// Ambil seluruh container
|
||||
const container = document.getElementById('containerDownload');
|
||||
if (!container) {
|
||||
alert("Container tidak ditemukan!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Opsi PDF
|
||||
const opt = {
|
||||
margin: 0.5, // Margin dalam inch
|
||||
filename: 'Detail_Santri_<?= $siswa->nama ?>.pdf',
|
||||
image: { type: 'jpeg', quality: 0.98 },
|
||||
html2canvas: { scale: 2, logging: true, letterRendering: true, useCORS: true },
|
||||
jsPDF: { unit: 'in', format: 'a4', orientation: 'landscape' }
|
||||
};
|
||||
|
||||
// Generate PDF
|
||||
html2pdf().set(opt).from(container).save();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,601 @@
|
||||
<style>
|
||||
.modern-tabs .nav-link {
|
||||
border: none;
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.modern-tabs .nav-link.active {
|
||||
background: #0d6efd;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.import-dropzone {
|
||||
border: 2px dashed #c7d6ff;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
transition: .3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.import-dropzone.dragover {
|
||||
background: #eef5ff;
|
||||
border-color: #0d6efd;
|
||||
}
|
||||
|
||||
.export-card {
|
||||
border: 1px solid #eaeaea;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">Data Santri</h5>
|
||||
|
||||
<div>
|
||||
<?php if(check_permission('siswa', 'can_create')): ?>
|
||||
<button class="btn btn-success btn-add" style="margin-right: 5px;">
|
||||
<i class="bi bi-plus-circle me-1"></i> Tambah
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(check_permission('siswa', 'can_export')): ?>
|
||||
<button class="btn btn-success btn-eximport d-none d-lg-inline" style="margin-right: 5px;" data-bs-toggle="modal" data-bs-target="#modalImport">
|
||||
<i class="bi bi-upload me-1"></i> Import
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(check_permission('siswa', 'can_import')): ?>
|
||||
<button class="btn btn-success btn-eximport d-none d-lg-inline" data-bs-toggle="modal" data-bs-target="#modalExport">
|
||||
<i class="bi bi-download me-1"></i> Export
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableSiswa" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Foto</th>
|
||||
<th>Nama</th>
|
||||
<th>NIS</th>
|
||||
<th>Kelas</th>
|
||||
<th>Kamar</th>
|
||||
<th>Alamat</th>
|
||||
<th>Nama Wali</th>
|
||||
<th>Nomor Whatsapp</th>
|
||||
<th>Jumlah Kunjungan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL TAMBAH / EDIT -->
|
||||
<div class="modal fade" id="modalTambah">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
<div class="modal-header bg-success text-white rounded-top-4">
|
||||
<h5 class="modal-title">Tambah Santri</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-foto-santri">
|
||||
<div class="foto-santri" id="previewFoto"></div>
|
||||
<input type="file" class="form-control d-none" id="imageSantri">
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">Nama</label>
|
||||
<input type="text" class="form-control" id="inputNama">
|
||||
|
||||
<label class="fw-semibold mt-2">NIS</label>
|
||||
<input type="text" class="form-control" id="inputNIS">
|
||||
|
||||
<label class="fw-semibold mt-2">Kelas</label>
|
||||
<select class="form-control" id="inputKelas">
|
||||
<option value="">-- Pilih Kelas --</option>
|
||||
</select>
|
||||
|
||||
<label class="fw-semibold mt-2">Kamar</label>
|
||||
<select class="form-control" id="inputKamar">
|
||||
<option value="">-- Pilih Kamar --</option>
|
||||
</select>
|
||||
|
||||
<label class="fw-semibold mt-2">Nama Wali Santri</label>
|
||||
<input type="text" class="form-control" id="inputWali">
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
|
||||
<label class="fw-semibold mt-2">Nomor Whatsapp</label>
|
||||
<input type="text" class="form-control" id="inputWhatsapp">
|
||||
|
||||
<label class="fw-semibold mt-2">Email Wali Santri</label>
|
||||
<input type="text" class="form-control" id="inputEmail">
|
||||
|
||||
<label class="fw-semibold mt-2">Alamat</label>
|
||||
<textarea class="form-control" id="inputAlamat" rows="4"></textarea>
|
||||
|
||||
<label class="fw-semibold mt-2">Tahun Masuk</label>
|
||||
<select class="form-control" id="inputTahun">
|
||||
<option value="">-- Pilih Tahun --</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-success" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal Import -->
|
||||
<div class="modal fade" id="modalImport" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content shadow-lg rounded-4 border-0">
|
||||
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">
|
||||
<i class="bi bi-upload me-2"></i> Import Data Siswa
|
||||
</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="import-dropzone text-center" id="dropzone">
|
||||
<i class="bi bi-cloud-arrow-up fs-1 mb-2 text-primary"></i>
|
||||
<h6 class="fw-bold">Tarik File ke Sini</h6>
|
||||
<p class="small text-muted mb-2">Atau klik untuk memilih file Excel (.xlsx)</p>
|
||||
|
||||
<input type="file" id="fileImport" accept=".xlsx" hidden>
|
||||
<button class="btn btn-outline-primary btn-sm mt-2" id="btnSelectFile">
|
||||
Pilih File
|
||||
</button>
|
||||
|
||||
<div id="fileName" class="mt-3 fw-semibold text-success"></div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-success w-100 mt-3" id="btnUpload">
|
||||
<i class="bi bi-check-circle me-2"></i> Upload & Proses
|
||||
</button>
|
||||
|
||||
<hr>
|
||||
<a href="<?= base_url('import/template'); ?>" class="btn btn-secondary w-100">
|
||||
<i class="bi bi-file-earmark-spreadsheet me-1"></i> Download Template Excel
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Export -->
|
||||
<div class="modal fade" id="modalExport" tabindex="-1">
|
||||
<div class="modal-dialog modal-md modal-dialog-centered">
|
||||
<div class="modal-content shadow-lg rounded-4 border-0">
|
||||
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">
|
||||
<i class="bi bi-download me-2"></i> Export Data Siswa
|
||||
</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="export-card p-3 rounded-3">
|
||||
<h6 class="fw-bold mb-3"><i class="bi bi-file-earmark-arrow-down me-1"></i> Pilih Format</h6>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<a href="<?= base_url('export/siswa_excel'); ?>" class="btn btn-primary flex-fill">
|
||||
<i class="bi bi-file-earmark-excel me-1"></i> Excel
|
||||
</a>
|
||||
|
||||
<a href="<?= base_url('export/siswa_pdf'); ?>" class="btn btn-danger flex-fill">
|
||||
<i class="bi bi-file-earmark-pdf me-1"></i> PDF
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
// ========================================================
|
||||
// INIT DATATABLE
|
||||
// ========================================================
|
||||
let table = $('#tableSiswa').DataTable({
|
||||
dom: '<"dataTables_top d-flex justify-content-between mb-3"lf>rtip',
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: false,
|
||||
autoWidth: false,
|
||||
order: [],
|
||||
ajax: {
|
||||
url: "<?= base_url('siswa/get_data'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0, orderable: false },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4 },
|
||||
{ data: 5 },
|
||||
{ data: 6 },
|
||||
{ data: 7 },
|
||||
{ data: 8 },
|
||||
{ data: 9 },
|
||||
{ data: 10, orderable: false }
|
||||
],
|
||||
language: {
|
||||
processing: `<div class="d-flex justify-content-center"><div class="spinner-border text-success"></div></div>`
|
||||
}
|
||||
});
|
||||
|
||||
$('.dataTables_filter input')
|
||||
.attr('placeholder','Search...')
|
||||
.css({
|
||||
'min-width':'300px',
|
||||
'padding':'6px 12px',
|
||||
'border-radius':'6px',
|
||||
'border':'1px solid #ced4da',
|
||||
'font-size':'0.9rem'
|
||||
});
|
||||
|
||||
table.on('draw', function () {
|
||||
$('#tableSiswa tbody tr').each(function() {
|
||||
$(this).find('td').each(function(index) {
|
||||
let header = $('#tableSiswa thead th').eq(index).text().trim();
|
||||
$(this).attr('data-label', header + ' : ');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// MODAL ADD
|
||||
// ========================================================
|
||||
$(document).on('click', '.btn-add', function(){
|
||||
resetModal();
|
||||
|
||||
$('#modalTambah .modal-title').text('Tambah Santri');
|
||||
$('#btnSimpan').text('Simpan').data('action','add').removeData('id');
|
||||
|
||||
loadKelasList();
|
||||
loadKamarList();
|
||||
loadListTahun();
|
||||
|
||||
$('#modalTambah').modal('show');
|
||||
|
||||
// default foto
|
||||
$('#previewFoto').css('background-image', `url('uploads/siswa/foto.jpg')`);
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// MODAL EDIT
|
||||
// ========================================================
|
||||
$(document).on('click', '.btn-edit', function(){
|
||||
resetModal();
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('siswa/detailEdit'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
|
||||
$('#inputNama').val(res.nama);
|
||||
$('#inputNIS').val(res.nis);
|
||||
$('#inputAlamat').val(res.alamat);
|
||||
$('#inputWali').val(res.nama_wali);
|
||||
$('#inputWhatsapp').val(res.nomor_whatsapp);
|
||||
$('#inputEmail').val(res.email);
|
||||
|
||||
loadKelasList(res.id_kelas);
|
||||
loadKamarList(res.id_kamar);
|
||||
loadListTahun(res.tahun_masuk);
|
||||
|
||||
if(res.foto){
|
||||
$('#previewFoto').css('background-image', `url('uploads/siswa/${res.foto}')`);
|
||||
} else {
|
||||
$('#previewFoto').css('background-image', `url('uploads/siswa/foto.jpg')`);
|
||||
}
|
||||
|
||||
$('#modalTambah .modal-title').text('Edit Santri');
|
||||
$('#btnSimpan').text('Update').data('action','edit').data('id', res.id);
|
||||
|
||||
$('#modalTambah').modal('show');
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Gagal memuat data edit.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// DELETE
|
||||
// ========================================================
|
||||
$(document).on('click', '.btn-delete', function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title: 'Yakin ingin hapus?',
|
||||
text: "Data tidak dapat dikembalikan!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result)=>{
|
||||
if(result.isConfirmed){
|
||||
$.ajax({
|
||||
url: "<?= base_url('siswa/delete'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Terhapus!', res.message || 'Berhasil dihapus!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal menghapus!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Terjadi kesalahan server.','error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// FOTO PREVIEW + COMPRESS (SEND COMPRESSED)
|
||||
// ========================================================
|
||||
const fotoDiv = document.getElementById("previewFoto");
|
||||
const fileInput = document.getElementById("imageSantri");
|
||||
|
||||
fotoDiv.addEventListener("click", () => fileInput.click());
|
||||
|
||||
fileInput.addEventListener("change", function(e){
|
||||
const file = e.target.files[0];
|
||||
if(!file || !file.type.startsWith("image/")) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(evt){
|
||||
const img = new Image();
|
||||
|
||||
img.onload = function(){
|
||||
const canvas = document.createElement("canvas");
|
||||
let {width, height} = img;
|
||||
const maxDim = 800;
|
||||
|
||||
if(width > maxDim || height > maxDim){
|
||||
if(width > height){
|
||||
height = Math.round(height * maxDim / width);
|
||||
width = maxDim;
|
||||
} else {
|
||||
width = Math.round(width * maxDim / height);
|
||||
height = maxDim;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
|
||||
let quality = 0.7;
|
||||
let compressed = canvas.toDataURL("image/jpeg", quality);
|
||||
|
||||
while(compressed.length/1024 > 250 && quality > 0.1){
|
||||
quality -= 0.05;
|
||||
compressed = canvas.toDataURL("image/jpeg", quality);
|
||||
}
|
||||
|
||||
fotoDiv.style.backgroundImage = `url('${compressed}')`;
|
||||
|
||||
// simpan hasil kompres ke element
|
||||
$('#previewFoto').data('compressed', compressed);
|
||||
};
|
||||
|
||||
img.src = evt.target.result;
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// SAVE / UPDATE
|
||||
// ========================================================
|
||||
$('#btnSimpan').click(function(){
|
||||
let action = $(this).data('action');
|
||||
let id = $(this).data('id') || '';
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('nama', $('#inputNama').val());
|
||||
formData.append('nis', $('#inputNIS').val());
|
||||
formData.append('id_kelas', $('#inputKelas').val());
|
||||
formData.append('alamat', $('#inputAlamat').val());
|
||||
formData.append('nama_wali', $('#inputWali').val());
|
||||
formData.append('nomor_whatsapp', $('#inputWhatsapp').val());
|
||||
formData.append('email', $('#inputEmail').val());
|
||||
formData.append('tahun_masuk', $('#inputTahun').val());
|
||||
formData.append('id_kamar', $('#inputKamar').val());
|
||||
|
||||
// Ambil hasil kompres
|
||||
const compressedImage = $('#previewFoto').data('compressed');
|
||||
|
||||
if(compressedImage){
|
||||
formData.append('foto', compressedImage);
|
||||
}
|
||||
|
||||
let url = action === 'add' ? "<?= base_url('siswa/save'); ?>"
|
||||
: "<?= base_url('siswa/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status){
|
||||
$('#modalTambah').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses', res.message || 'Berhasil!', 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message || 'Gagal!', 'error');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
Swal.fire('Error','Terjadi kesalahan server.','error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ========================================================
|
||||
// FUNCTIONS
|
||||
// ========================================================
|
||||
function resetModal(){
|
||||
$('#imageSantri').val('');
|
||||
$('#inputNama,#inputNIS,#inputAlamat,#inputWali,#inputWhatsapp,#inputEmail').val('');
|
||||
$('#inputKelas,#inputKamar,#inputTahun').val('');
|
||||
$('#previewFoto').css('background-image', `url('uploads/siswa/foto.jpg')`);
|
||||
$('#previewFoto').removeData('compressed');
|
||||
}
|
||||
|
||||
function loadKelasList(selectedId=''){
|
||||
$.ajax({
|
||||
url: "<?= base_url('kelas/get_list'); ?>",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
const select = $('#inputKelas');
|
||||
select.empty().append('<option value="">-- Pilih Kelas --</option>');
|
||||
res.forEach(k=>{
|
||||
select.append(`<option value="${k.id}" ${k.id==selectedId?'selected':''}>${k.nama}</option>`);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadKamarList(selectedId=''){
|
||||
$.ajax({
|
||||
url: "<?= base_url('kamar/get_list'); ?>",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
const select = $('#inputKamar');
|
||||
select.empty().append('<option value="">-- Pilih Kamar --</option>');
|
||||
res.forEach(k=>{
|
||||
select.append(`<option value="${k.id}" ${k.id==selectedId?'selected':''}>${k.nama} (${k.gedung})</option>`);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadListTahun(selected=''){
|
||||
const select = $('#inputTahun');
|
||||
select.empty().append('<option value="">-- Pilih Tahun --</option>');
|
||||
for(let tahun=2015; tahun<=2030; tahun++){
|
||||
select.append(`<option value="${tahun}" ${tahun==selected?'selected':''}>${tahun}</option>`);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$("#btnSelectFile").click(function () {
|
||||
$("#fileImport").click();
|
||||
});
|
||||
|
||||
$("#fileImport").on("change", function () {
|
||||
$("#fileName").text(this.files[0].name);
|
||||
});
|
||||
|
||||
let dropzone = document.getElementById("dropzone");
|
||||
|
||||
dropzone.addEventListener("click", () => $("#fileImport").click());
|
||||
dropzone.addEventListener("dragover", (e) => {
|
||||
e.preventDefault(); dropzone.classList.add("dragover");
|
||||
});
|
||||
dropzone.addEventListener("dragleave", () => dropzone.classList.remove("dragover"));
|
||||
dropzone.addEventListener("drop", (e) => {
|
||||
e.preventDefault(); dropzone.classList.remove("dragover");
|
||||
|
||||
let file = e.dataTransfer.files[0];
|
||||
$("#fileImport")[0].files = e.dataTransfer.files;
|
||||
$("#fileName").text(file.name);
|
||||
});
|
||||
|
||||
$("#btnUpload").click(function () {
|
||||
let file = $("#fileImport")[0].files[0];
|
||||
|
||||
if (!file) {
|
||||
Swal.fire("Oops!", "Silakan pilih file terlebih dahulu!", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
Swal.fire({ title: "Mengupload...", didOpen: () => Swal.showLoading() });
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('import/siswa'); ?>",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: function () {
|
||||
Swal.fire("Berhasil!", "Data berhasil di-import.", "success");
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire("Error!", "Gagal upload file.", "error");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,291 @@
|
||||
<div class="container mt-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 align-items-center mb-3">
|
||||
<h5 class="mb-0">Manajemen Pengguna</h5>
|
||||
|
||||
<button class="btn btn-warning btn-add">
|
||||
<i class="bi bi-plus-circle me-1"></i> Tambah Pengguna
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableUsers" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Username</th>
|
||||
<th>Nama</th>
|
||||
<th>Role</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalUser">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4">
|
||||
|
||||
<div class="modal-header bg-warning text-white rounded-top-4">
|
||||
<h5 class="modal-title">Tambah Pengguna</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="inputId">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="fw-semibold">Username</label>
|
||||
<input type="text" class="form-control" id="inputUsername">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="fw-semibold">Nama</label>
|
||||
<input type="text" class="form-control" id="inputNama">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="fw-semibold">Role</label>
|
||||
<select class="form-control" id="inputRole">
|
||||
<option value="">-- Pilih Role --</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="password-group">
|
||||
<div class="mb-3">
|
||||
<label class="fw-semibold">Password</label>
|
||||
<input type="password" class="form-control" id="inputPassword">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
let modal = new bootstrap.Modal(document.getElementById('modalUser'));
|
||||
|
||||
// ======================
|
||||
// DATATABLE
|
||||
// ======================
|
||||
let table = $('#tableUsers').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
responsive: true,
|
||||
ajax: {
|
||||
url: "<?= base_url('users/get_data'); ?>",
|
||||
type: "POST"
|
||||
},
|
||||
columns: [
|
||||
{ data: 0 },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4, orderable: false }
|
||||
]
|
||||
});
|
||||
|
||||
// ======================
|
||||
// OPEN ADD MODAL
|
||||
// ======================
|
||||
$('.btn-add').on('click', function () {
|
||||
|
||||
resetModal();
|
||||
|
||||
$('#modalUser .modal-title').text('Tambah Pengguna');
|
||||
$('#btnSimpan').data('action', 'add');
|
||||
|
||||
$('.password-group').show();
|
||||
|
||||
modal.show();
|
||||
});
|
||||
|
||||
// ======================
|
||||
// SAVE
|
||||
// ======================
|
||||
$('#btnSimpan').on('click', function () {
|
||||
|
||||
let action = $(this).data('action');
|
||||
|
||||
let formData = {
|
||||
id: $('#inputId').val(),
|
||||
username: $('#inputUsername').val(),
|
||||
nama: $('#inputNama').val(),
|
||||
role_id: $('#inputRole').val(),
|
||||
password: $('#inputPassword').val()
|
||||
};
|
||||
|
||||
let url = (action === 'add')
|
||||
? "<?= base_url('users/store'); ?>"
|
||||
: "<?= base_url('users/update'); ?>";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
|
||||
if (res.status) {
|
||||
modal.hide();
|
||||
table.ajax.reload(null, false);
|
||||
Swal.fire('Sukses', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message, 'error');
|
||||
}
|
||||
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire('Error', 'Server bermasalah', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ======================
|
||||
// EDIT
|
||||
// ======================
|
||||
$('#tableUsers').on('click', '.btn-edit', function () {
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('users/edit'); ?>/" + id,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
|
||||
if (res.status) {
|
||||
|
||||
resetModal();
|
||||
|
||||
$('#modalUser .modal-title').text('Edit Pengguna');
|
||||
$('#btnSimpan').data('action', 'edit');
|
||||
|
||||
$('#inputId').val(res.data.id);
|
||||
$('#inputUsername').val(res.data.username);
|
||||
$('#inputNama').val(res.data.nama);
|
||||
|
||||
loadRole(res.data.role_id);
|
||||
|
||||
$('.password-group').hide();
|
||||
$('#inputPassword').val('');
|
||||
|
||||
modal.show();
|
||||
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message, 'error');
|
||||
}
|
||||
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire('Error', 'Gagal load data edit', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ======================
|
||||
// DELETE
|
||||
// ======================
|
||||
$('#tableUsers').on('click', '.btn-delete', function () {
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus user?',
|
||||
text: "Data tidak bisa dikembalikan!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, hapus!'
|
||||
}).then((result) => {
|
||||
|
||||
if (result.isConfirmed) {
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('users/delete'); ?>/" + id,
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
|
||||
if (res.status) {
|
||||
table.ajax.reload(null, false);
|
||||
Swal.fire('Terhapus', res.message, 'success');
|
||||
} else {
|
||||
Swal.fire('Gagal', res.message, 'error');
|
||||
}
|
||||
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire('Error', 'Server error', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ======================
|
||||
// LOAD ROLE (FIXED)
|
||||
// ======================
|
||||
function loadRole(selected = '') {
|
||||
|
||||
$.ajax({
|
||||
url: "<?= base_url('users/get_role'); ?>",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
|
||||
let select = $('#inputRole');
|
||||
select.empty();
|
||||
select.append('<option value="">-- Pilih Role --</option>');
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
res.forEach(r => {
|
||||
let selectedAttr = (r.id == selected) ? 'selected' : '';
|
||||
select.append(`<option value="${r.id}" ${selectedAttr}>${r.nama_role}</option>`);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire('Error', 'Gagal load role', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// ======================
|
||||
// RESET MODAL
|
||||
// ======================
|
||||
function resetModal() {
|
||||
$('#inputId').val('');
|
||||
$('#inputUsername').val('');
|
||||
$('#inputNama').val('');
|
||||
$('#inputPassword').val('');
|
||||
$('#inputRole').val('');
|
||||
|
||||
loadRole();
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,153 @@
|
||||
<div class="container mt-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>Data Gudang</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Gudang</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableWarehouse" class="table modern-table align-middle w-100">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Gudang</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modalWarehouse">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5 class="modal-title">Gudang</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<label>Nama Gudang</label>
|
||||
<input type="text" id="nama" class="form-control">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||
<button class="btn btn-warning" id="btnSimpan">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let action = 'add';
|
||||
|
||||
let table = $('#tableWarehouse').DataTable({
|
||||
ajax:{
|
||||
url:"<?= base_url('warehouses/get_data'); ?>",
|
||||
type:"POST"
|
||||
}
|
||||
});
|
||||
|
||||
function resetForm(){
|
||||
$('#id').val('');
|
||||
$('#nama').val('');
|
||||
}
|
||||
|
||||
// ADD
|
||||
$('.btn-add').click(function(){
|
||||
resetForm();
|
||||
action = 'add';
|
||||
$('#modalWarehouse').modal('show');
|
||||
});
|
||||
|
||||
// EDIT
|
||||
$(document).on('click','.btn-editgudang',function(){
|
||||
let id = $(this).data('id');
|
||||
|
||||
$.get("<?= base_url('warehouses/detail/'); ?>"+id,function(res){
|
||||
|
||||
$('#id').val(res.id);
|
||||
$('#nama').val(res.nama);
|
||||
|
||||
action = 'edit';
|
||||
$('#modalWarehouse').modal('show');
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// SAVE
|
||||
$('#btnSimpan').click(function(){
|
||||
|
||||
let data = {
|
||||
id: $('#id').val(),
|
||||
nama: $('#nama').val()
|
||||
};
|
||||
|
||||
if(!data.nama){
|
||||
Swal.fire('Warning','Nama gudang wajib diisi','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let url = action === 'add'
|
||||
? "<?= base_url('warehouses/save'); ?>"
|
||||
: "<?= base_url('warehouses/update'); ?>";
|
||||
|
||||
$.post(url,data,function(res){
|
||||
|
||||
if(res.status){
|
||||
$('#modalWarehouse').modal('hide');
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
Swal.fire({
|
||||
title:'Hapus gudang?',
|
||||
text:'Pastikan tidak dipakai item',
|
||||
icon:'warning',
|
||||
showCancelButton:true
|
||||
}).then(r=>{
|
||||
if(r.isConfirmed){
|
||||
|
||||
$.get("<?= base_url('warehouses/delete/'); ?>"+id,function(res){
|
||||
|
||||
if(res.status){
|
||||
table.ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
Swal.fire('Error',res.message,'error');
|
||||
}
|
||||
|
||||
},'json');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
?><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Welcome to CodeIgniter</title>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
::selection { background-color: #E13300; color: white; }
|
||||
::-moz-selection { background-color: #E13300; color: white; }
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
margin: 40px;
|
||||
font: 13px/20px normal Helvetica, Arial, sans-serif;
|
||||
color: #4F5155;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #003399;
|
||||
background-color: transparent;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #97310e;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #444;
|
||||
background-color: transparent;
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
font-size: 19px;
|
||||
font-weight: normal;
|
||||
margin: 0 0 14px 0;
|
||||
padding: 14px 15px 10px 15px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Consolas, Monaco, Courier New, Courier, monospace;
|
||||
font-size: 12px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #D0D0D0;
|
||||
color: #002166;
|
||||
display: block;
|
||||
margin: 14px 0 14px 0;
|
||||
padding: 12px 10px 12px 10px;
|
||||
}
|
||||
|
||||
#body {
|
||||
margin: 0 15px 0 15px;
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 10px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
p.footer {
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
border-top: 1px solid #D0D0D0;
|
||||
line-height: 32px;
|
||||
padding: 0 10px 0 10px;
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin: 10px;
|
||||
border: 1px solid #D0D0D0;
|
||||
box-shadow: 0 0 8px #D0D0D0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
<h1>Welcome to CodeIgniter!</h1>
|
||||
|
||||
<div id="body">
|
||||
<p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
|
||||
|
||||
<p>If you would like to edit this page you'll find it located at:</p>
|
||||
<code>application/views/welcome_message.php</code>
|
||||
|
||||
<p>The corresponding controller for this page is found at:</p>
|
||||
<code>application/controllers/Welcome.php</code>
|
||||
|
||||
<p>If you are exploring CodeIgniter for the very first time, you should start by reading the <a href="userguide3/">User Guide</a>.</p>
|
||||
</div>
|
||||
|
||||
<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user