hr dan payroll
This commit is contained in:
@@ -15,12 +15,12 @@
|
||||
|
||||
<div class="col-md-2">
|
||||
<label>Dari</label>
|
||||
<input type="date" id="start_date" class="form-control">
|
||||
<input type="date" id="start_date" class="form-control" value="<?=date('Y-m-01')?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label>Sampai</label>
|
||||
<input type="date" id="end_date" class="form-control">
|
||||
<input type="date" id="end_date" class="form-control" value="<?=date('Y-m-d')?>">
|
||||
</div>
|
||||
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3" id="ledgerSummary">
|
||||
<div class="col-6 col-lg-3"><div class="card card-body"><small class="text-muted">Saldo Awal</small><strong data-summary="saldo_awal">0</strong></div></div>
|
||||
<div class="col-6 col-lg-3"><div class="card card-body"><small class="text-muted">Total Debit</small><strong data-summary="total_debit">0</strong></div></div>
|
||||
<div class="col-6 col-lg-3"><div class="card card-body"><small class="text-muted">Total Kredit</small><strong data-summary="total_kredit">0</strong></div></div>
|
||||
<div class="col-6 col-lg-3"><div class="card card-body"><small class="text-muted">Saldo Akhir</small><strong data-summary="saldo_akhir">0</strong></div></div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="tableLedger" class="table modern-table align-middle w-100">
|
||||
<thead>
|
||||
@@ -62,6 +69,7 @@ $(function(){
|
||||
opt += `<option value="${a.id}">${a.kode_akun} - ${a.nama_akun}</option>`;
|
||||
});
|
||||
$('#account_id').html(opt);
|
||||
if(res.length) loadData();
|
||||
},'json');
|
||||
|
||||
function loadData(){
|
||||
@@ -78,7 +86,7 @@ $(function(){
|
||||
|
||||
let html = '';
|
||||
|
||||
res.forEach(r=>{
|
||||
(res.data || []).forEach(r=>{
|
||||
html += `
|
||||
<tr>
|
||||
<td>${r.tanggal}</td>
|
||||
@@ -92,8 +100,13 @@ $(function(){
|
||||
});
|
||||
|
||||
$('#tableLedger tbody').html(html);
|
||||
Object.keys(res.summary || {}).forEach(function(key){
|
||||
$('[data-summary="'+key+'"]').text(Number(res.summary[key] || 0).toLocaleString('id-ID'));
|
||||
});
|
||||
|
||||
},'json');
|
||||
},'json').fail(function(xhr){
|
||||
Swal.fire('Error', xhr.responseJSON?.message || 'Data Buku Besar gagal dimuat.', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +131,7 @@ $(function(){
|
||||
+ String(now.getDate()).padStart(2, '0');
|
||||
|
||||
const account_id = $('#account_id').val();
|
||||
const start_date = $('#start_date').val() || '0000-00-00';
|
||||
const start_date = $('#start_date').val() || '1900-01-01';
|
||||
const end_date = $('#end_date').val() || today;
|
||||
|
||||
let btn = $(this);
|
||||
@@ -153,4 +166,4 @@ $(function(){
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php $csrfName=$this->security->get_csrf_token_name();$csrfHash=$this->security->get_csrf_hash(); ?>
|
||||
<link rel="stylesheet" href="<?=base_url('assets/css/company-settings.css').'?v='.filemtime(FCPATH.'assets/css/company-settings.css')?>">
|
||||
<section class="company-settings-workspace">
|
||||
<header class="company-settings-hero"><div><span>ADMINISTRASI PERUSAHAAN</span><h3>Company Setting</h3><p>Kelola identitas dokumen, rekening pembayaran, perusahaan, dan mata uang dari satu tempat.</p></div><div class="active-company-chip"><small>Perusahaan aktif</small><b><?=html_escape($active_company->company_code.' - '.$active_company->name)?></b></div></header>
|
||||
<header class="company-settings-hero"><div><span>ADMINISTRASI PERUSAHAAN</span><h3 class="text-light">Company Setting</h3><p>Kelola identitas dokumen, rekening pembayaran, perusahaan, dan mata uang dari satu tempat.</p></div><div class="active-company-chip"><small>Perusahaan aktif</small><b><?=html_escape($active_company->company_code.' - '.$active_company->name)?></b></div></header>
|
||||
<?php if($this->session->flashdata('success')):?><div class="alert alert-success"><?=html_escape($this->session->flashdata('success'))?></div><?php endif?>
|
||||
<?php if($this->session->flashdata('error')):?><div class="alert alert-danger"><?=html_escape($this->session->flashdata('error'))?></div><?php endif?>
|
||||
|
||||
@@ -25,3 +25,26 @@
|
||||
$('.edit-currency').on('click',function(){var r=$(this).data('row'),f=document.getElementById('currencyForm');f.elements.code.value=r.code;f.elements.code.readOnly=true;f.elements.name.value=r.name;f.elements.symbol.value=r.symbol||'';f.elements.decimal_places.value=r.decimal_places;f.elements.is_active.checked=Number(r.is_active)===1;$('#cancelCurrencyEdit').removeClass('d-none');f.scrollIntoView({behavior:'smooth',block:'center'});});$('#cancelCurrencyEdit').on('click',resetCurrency);
|
||||
})(jQuery);
|
||||
</script>
|
||||
<script>
|
||||
(function($){
|
||||
var form=document.getElementById('bankAccountForm');if(!form)return;
|
||||
$('[data-bs-target="#companyBanks"]').html('<i class="bi bi-bank"></i> Akun Bank Perusahaan');
|
||||
var glAccounts=<?=json_encode(array_map(function($a){return array('id'=>$a->id,'text'=>$a->kode_akun.' - '.$a->nama_akun);},$bank_gl_accounts),JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)?>;
|
||||
var coaOptions='<option value="">Pilih akun COA</option>'+glAccounts.map(function(a){return '<option value="'+a.id+'">'+$('<div>').text(a.text).html()+'</option>';}).join('');
|
||||
$(form).find('.row.g-3').first().before(
|
||||
'<div class="mb-3"><label class="form-label">Jenis Produk / Jasa Bank</label><input class="form-control" name="product_name" placeholder="Contoh: BritAma Bisnis atau Deposito Berjangka" required></div>'+
|
||||
'<div class="row g-3 mb-3"><div class="col-md-6"><label class="form-label">Jenis Rekening</label><select class="form-select" name="account_type" required><option value="savings">Tabungan</option><option value="deposit">Deposito</option></select></div><div class="col-md-6"><label class="form-label">Bunga Bank (%)</label><input class="form-control" type="number" min="0" step="0.0001" name="interest_rate" value="0"></div><div class="col-md-6"><label class="form-label">Tanggal Pembukaan</label><input class="form-control" type="date" name="opened_at" required></div><div class="col-md-6 maturity-field d-none"><label class="form-label">Tanggal Jatuh Tempo</label><input class="form-control" type="date" name="maturity_date"></div><div class="col-12"><label class="form-label">Akun COA Terhubung</label><select class="form-select select-search" name="gl_account_id" required>'+coaOptions+'</select><small class="text-muted">Gunakan akun Aktiva kas/bank yang menampung transaksi rekening ini.</small></div></div>'
|
||||
);
|
||||
function accountTypeChanged(){var deposit=form.elements.account_type.value==='deposit';$(form).find('.maturity-field').toggleClass('d-none',!deposit);form.elements.maturity_date.required=deposit;if(!deposit)form.elements.maturity_date.value='';}
|
||||
$(form.elements.account_type).on('change',accountTypeChanged);accountTypeChanged();
|
||||
$('#cancelBankEdit').on('click',function(){$(form.elements.gl_account_id).val('').trigger('change');accountTypeChanged();});
|
||||
$('.edit-bank').on('click',function(){var r=$(this).data('row');form.elements.product_name.value=r.product_name||'';form.elements.account_type.value=r.account_type||'savings';form.elements.interest_rate.value=r.interest_rate||0;form.elements.opened_at.value=r.opened_at||'';form.elements.maturity_date.value=r.maturity_date||'';form.elements.gl_account_id.value=r.gl_account_id||'';$(form.elements.gl_account_id).trigger('change');accountTypeChanged();});
|
||||
|
||||
var table=$('#companyBanks table').first(),head=table.find('thead tr');head.html('<th>Bank / Rekening</th><th>Produk</th><th>Mata Uang</th><th>Akun COA</th><th>Status</th><th>Aksi</th>');
|
||||
table.find('tbody tr').each(function(){var tr=$(this),button=tr.find('.edit-bank');if(!button.length){tr.children('td').attr('colspan',6);return;}var r=button.data('row'),cells=tr.children('td'),product=$('<td>').html('<b>'+(r.account_type==='deposit'?'Deposito':'Tabungan')+'</b><small>'+$('<div>').text(r.product_name||'-').html()+' · buka '+(r.opened_at||'-')+(r.maturity_date?' · jatuh tempo '+r.maturity_date:'')+(Number(r.interest_rate)>0?' · bunga '+Number(r.interest_rate).toLocaleString('id-ID')+'%':'')+'</small>'),coa=$('<td>').html(r.kode_akun?'<b>'+$('<div>').text(r.kode_akun).html()+'</b><small>'+$('<div>').text(r.nama_akun||'').html()+'</small>':'<span class="text-warning">Belum terhubung</span>');cells.eq(0).after(product);cells.eq(1).after(coa);tr.data('bankRow',r);});
|
||||
var filters=$('<div class="row g-2 mb-3 bank-report-filter"><div class="col-md-3"><input class="form-control" id="bankFilterName" placeholder="Cari nama bank"></div><div class="col-md-2"><select class="form-select" id="bankFilterType"><option value="">Semua jenis</option><option value="savings">Tabungan</option><option value="deposit">Deposito</option></select></div><div class="col-md-2"><select class="form-select" id="bankFilterStatus"><option value="">Semua status</option><option value="1">Aktif</option><option value="0">Nonaktif</option></select></div><div class="col-md-2"><input type="date" class="form-control" id="bankFilterFrom" title="Jatuh tempo dari"></div><div class="col-md-2"><input type="date" class="form-control" id="bankFilterTo" title="Jatuh tempo sampai"></div><div class="col-md-1"><a class="btn btn-success w-100" id="bankExport" href="<?=base_url('companies/bank_export')?>" title="Export CSV"><i class="bi bi-file-earmark-spreadsheet"></i></a></div></div>');table.before(filters);
|
||||
function filterBanks(){var name=$('#bankFilterName').val().toLowerCase(),type=$('#bankFilterType').val(),status=$('#bankFilterStatus').val(),from=$('#bankFilterFrom').val(),to=$('#bankFilterTo').val();table.find('tbody tr').each(function(){var tr=$(this),r=tr.data('bankRow');if(!r)return;var match=(!name||String(r.bank_name||'').toLowerCase().includes(name))&&(!type||r.account_type===type)&&(status===''||String(Number(r.is_active))===status)&&(!from||(r.maturity_date&&r.maturity_date>=from))&&(!to||(r.maturity_date&&r.maturity_date<=to));tr.toggle(match);});$('#bankExport').attr('href','<?=base_url('companies/bank_export')?>?'+$.param({bank:$('#bankFilterName').val(),type:type,status:status,maturity_from:from,maturity_to:to}));}
|
||||
$('.bank-report-filter').on('input change','input,select',filterBanks);
|
||||
if(location.hash==='#companyBanks'){var trigger=document.querySelector('[data-bs-target="#companyBanks"]');if(trigger)bootstrap.Tab.getOrCreateInstance(trigger).show();}
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
@@ -30,9 +30,19 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
let table = $('#tableActivity').DataTable({
|
||||
$(function () {
|
||||
|
||||
if (!$.fn || typeof $.fn.DataTable !== 'function') {
|
||||
$('#tableActivity tbody').remove();
|
||||
$('#tableActivity').append(
|
||||
'<tbody><tr><td colspan="7" class="text-center text-danger py-4">' +
|
||||
'Komponen tabel gagal dimuat. Silakan muat ulang halaman.' +
|
||||
'</td></tr></tbody>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let table = $('#tableActivity').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
@@ -99,4 +109,4 @@ $(function () {
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -8,6 +8,7 @@ $statusLabels=array('draft'=>'Draft','reviewed'=>'Sudah Direview','approved'=>'D
|
||||
?>
|
||||
<?php foreach(array('success','error')as$flash):if($this->session->flashdata($flash)):?><div data-app-toast data-icon="<?=$flash==='success'?'success':'error'?>" data-message="<?=html_escape($this->session->flashdata($flash))?>"></div><?php endif;endforeach?>
|
||||
<?php if(!$can_manage_all_salary):?><div class="alert alert-warning"><i class="bi bi-lock-fill me-1"></i> Tampilan ini tidak memuat nilai maupun total gaji terbatas. Akses tersebut memerlukan permission <b>Manage All Gaji</b>.</div><?php endif?>
|
||||
<?php if(!$can_manage_allowances&&in_array($payroll_section,array('salaries','settings','adjustments'),true)):?><div class="alert alert-info"><i class="bi bi-shield-lock-fill me-1"></i> Akses pengelolaan dibatasi pada <b>Gaji Pokok dan Potongan</b>. Tunjangan, bonus, lembur, THR, dan pendapatan tambahan memerlukan permission <b>Kelola Tunjangan & Bonus</b>.</div><?php endif?>
|
||||
|
||||
<?php if($payroll_section==='periods'):?>
|
||||
<div class="hr-workflow-strip" aria-label="Tahapan payroll"><span><b>1</b>Buat Periode</span><span><b>2</b>Lock Kehadiran</span><span><b>3</b>Hitung Draft</span><span><b>4</b>Review HR</span><span><b>5</b>Approve & Final</span><span><b>6</b>Posting Jurnal</span><span><b>7</b>Pembayaran</span></div>
|
||||
@@ -32,23 +33,31 @@ $statusLabels=array('draft'=>'Draft','reviewed'=>'Sudah Direview','approved'=>'D
|
||||
<ul class="nav nav-pills payroll-setting-tabs mb-3" role="tablist"><li class="nav-item"><button class="nav-link active" data-bs-toggle="pill" data-bs-target="#componentsTab">Master Komponen</button></li><li class="nav-item"><button class="nav-link" data-bs-toggle="pill" data-bs-target="#positionsTab">Template Posisi</button></li><li class="nav-item"><button class="nav-link" data-bs-toggle="pill" data-bs-target="#attendanceRulesTab">Aturan Kehadiran</button></li><li class="nav-item"><button class="nav-link" data-bs-toggle="pill" data-bs-target="#generalTab">Pengaturan Umum</button></li></ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="componentsTab"><section class="card hr-panel"><div class="card-header bg-white"><b>Master Komponen</b><small class="d-block text-muted">Komponen tidak otomatis berlaku untuk semua karyawan.</small></div><?php if($permissions['update']):?><div class="card-body border-bottom"><form method="post" action="<?=base_url('hrpayroll/component')?>" class="row g-2"><?=$csrf?><div class="col-md-2"><label class="form-label">Kode</label><input class="form-control" name="code" required></div><div class="col-md-3"><label class="form-label">Nama</label><input class="form-control" name="name" required></div><div class="col-md-2"><label class="form-label">Jenis</label><select class="form-select" name="component_type"><option value="earning">Pendapatan</option><option value="deduction">Potongan</option><option value="employer_cost">Beban perusahaan</option></select></div><div class="col-md-2"><label class="form-label">Kategori</label><select class="form-select" name="category"><option value="basic">Gaji Pokok</option><option value="allowance">Tunjangan</option><option value="overtime">Lembur</option><option value="unpaid_leave">Cuti tak dibayar</option><option value="loan">Pinjaman</option><option value="bpjs">BPJS</option><option value="tax">Pajak</option><option value="thr">THR</option><option value="bonus">Bonus</option><option value="other">Lainnya</option></select></div><div class="col-md-3"><label class="form-label">Metode</label><select class="form-select" name="calculation_method"><?php foreach($methodLabels as$key=>$label):?><option value="<?=$key?>"><?=html_escape($label)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nilai Default</label><input type="number" min="0" step="0.01" class="form-control" name="default_value" value="0"></div><div class="col-md-3"><label class="form-label">Formula</label><input class="form-control" name="formula_expression" placeholder="present_days * 25000"></div><div class="col-md-2"><label class="form-label">Akun Beban</label><select class="form-select searchable" name="expense_account_id"><option value="">Mapping umum</option><?php foreach($accounts as$a):?><option value="<?=$a->id?>"><?=html_escape($a->kode_akun.' - '.$a->nama_akun)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Akun Kewajiban</label><select class="form-select searchable" name="liability_account_id"><option value="">Mapping umum</option><?php foreach($accounts as$a):?><option value="<?=$a->id?>"><?=html_escape($a->kode_akun.' - '.$a->nama_akun)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>"></div><div class="col-md-1 d-flex align-items-end"><label class="form-check mb-2"><input class="form-check-input" type="checkbox" name="is_active" value="1" checked> Aktif</label></div><div class="col-md-2 d-flex align-items-end justify-content-end"><button class="btn btn-primary">Simpan Komponen</button></div></form></div><?php endif?><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Kode</th><th>Komponen</th><th>Jenis</th><th>Metode</th><th class="text-end">Default</th><th>Mapping</th><th>Status</th></tr></thead><tbody><?php foreach($components as$c):?><tr><td><b><?=html_escape($c->code)?></b></td><td><?=html_escape($c->name)?></td><td><?=html_escape($c->component_type)?></td><td><?=html_escape($methodLabels[$c->calculation_method]??$c->calculation_method)?></td><td class="text-end">Rp <?=number_format($c->default_value??$c->fixed_amount,2,',','.')?></td><td><?=html_escape(($c->expense_account_id?:'mapping umum').' / '.($c->liability_account_id?:'mapping umum'))?></td><td><span class="badge <?=$c->is_active?'bg-success':'bg-secondary'?>"><?=$c->is_active?'Aktif':'Nonaktif'?></span></td></tr><?php endforeach?></tbody></table></div></section></div>
|
||||
<div class="tab-pane fade" id="positionsTab"><section class="card hr-panel"><div class="card-header bg-white"><b>Template Posisi</b><small class="d-block text-muted">Override karyawan tetap memiliki prioritas di atas template posisi.</small></div><?php if($permissions['update']):?><div class="card-body border-bottom"><form method="post" action="<?=base_url('hrpayroll/save_position_line')?>" class="row g-2"><?=$csrf?><div class="col-md-3"><label class="form-label">Posisi</label><select class="form-select searchable" name="position_id" required><option value="">Pilih posisi</option><?php foreach($positions as$p):?><option value="<?=$p->id?>"><?=html_escape($p->position_name)?></option><?php endforeach?></select></div><div class="col-md-3"><label class="form-label">Komponen</label><select class="form-select searchable" name="component_id" required><option value="">Pilih komponen</option><?php foreach($components as$c):?><option value="<?=$c->id?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Metode</label><select class="form-select" name="calculation_method"><?php foreach($methodLabels as$key=>$label):?><option value="<?=$key?>"><?=html_escape($label)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nilai/Tarif</label><input type="number" min="0" step="0.01" class="form-control" name="amount_override" value="0"></div><div class="col-md-2"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>" required></div><div class="col-md-10"><input class="form-control" name="notes" placeholder="Keterangan template, opsional"></div><div class="col-md-2"><button class="btn btn-primary w-100">Tambah Template</button></div></form></div><?php endif?><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Posisi</th><th>Komponen</th><th>Metode</th><th class="text-end">Nilai</th><th>Efektif</th><th>Status</th></tr></thead><tbody><?php if(!$position_assignments):?><tr><td colspan="6" class="text-center text-muted py-4">Belum ada template posisi.</td></tr><?php endif;foreach($position_assignments as$x):?><tr><td><?=html_escape($x->position_name)?></td><td><?=html_escape($x->component_code.' - '.$x->component_name)?></td><td><?=html_escape($methodLabels[$x->calculation_method]??$x->calculation_method)?></td><td class="text-end">Rp <?=number_format($x->amount_override,2,',','.')?></td><td><?=html_escape($x->effective_from)?><?=!empty($x->effective_to)?' s.d. '.html_escape($x->effective_to):''?></td><td><span class="badge <?=$x->is_active?'bg-success':'bg-secondary'?>"><?=$x->is_active?'Aktif':'Nonaktif'?></span></td></tr><?php endforeach?></tbody></table></div></section></div>
|
||||
<div class="tab-pane fade" id="positionsTab"><section class="card hr-panel"><div class="card-header bg-white"><b>Template Posisi</b><small class="d-block text-muted">Override karyawan tetap memiliki prioritas di atas template posisi.</small></div><?php if($permissions['update']):?><div class="card-body border-bottom"><form method="post" action="<?=base_url('hrpayroll/save_position_line')?>" class="row g-2"><?=$csrf?><div class="col-md-3"><label class="form-label">Posisi</label><select class="form-select searchable" name="position_id" required><option value="">Pilih posisi</option><?php foreach($positions as$p):?><option value="<?=$p->id?>"><?=html_escape($p->position_name)?></option><?php endforeach?></select></div><div class="col-md-3"><label class="form-label">Komponen</label><select class="form-select searchable" name="component_id" required><option value="">Pilih komponen</option><?php foreach($manageable_components as$c):?><option value="<?=$c->id?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Metode</label><select class="form-select" name="calculation_method"><?php foreach($methodLabels as$key=>$label):?><option value="<?=$key?>"><?=html_escape($label)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nilai/Tarif</label><input type="number" min="0" step="0.01" class="form-control" name="amount_override" value="0"></div><div class="col-md-2"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>" required></div><div class="col-md-10"><input class="form-control" name="notes" placeholder="Keterangan template, opsional"></div><div class="col-md-2"><button class="btn btn-primary w-100">Tambah Template</button></div></form></div><?php endif?><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Posisi</th><th>Komponen</th><th>Metode</th><th class="text-end">Nilai</th><th>Efektif</th><th>Status</th></tr></thead><tbody><?php if(!$position_assignments):?><tr><td colspan="6" class="text-center text-muted py-4">Belum ada template posisi.</td></tr><?php endif;foreach($position_assignments as$x):?><tr><td><?=html_escape($x->position_name)?></td><td><?=html_escape($x->component_code.' - '.$x->component_name)?></td><td><?=html_escape($methodLabels[$x->calculation_method]??$x->calculation_method)?></td><td class="text-end">Rp <?=number_format($x->amount_override,2,',','.')?></td><td><?=html_escape($x->effective_from)?><?=!empty($x->effective_to)?' s.d. '.html_escape($x->effective_to):''?></td><td><span class="badge <?=$x->is_active?'bg-success':'bg-secondary'?>"><?=$x->is_active?'Aktif':'Nonaktif'?></span></td></tr><?php endforeach?></tbody></table></div></section></div>
|
||||
<div class="tab-pane fade" id="attendanceRulesTab"><section class="card hr-panel"><div class="card-header bg-white"><b>Aturan Kehadiran</b><small class="d-block text-muted">Terlambat secara default tidak dipotong. Cuti tahunan, sakit, izin, dan hari libur tidak dianggap alpa.</small></div><?php if($permissions['update']):?><div class="card-body border-bottom"><form method="post" action="<?=base_url('hrpayroll/save_attendance_rule')?>" class="row g-2"><?=$csrf?><div class="col-md-3"><label class="form-label">Nama Aturan</label><input class="form-control" name="rule_name" required></div><div class="col-md-2"><label class="form-label">Kondisi</label><select class="form-select" name="condition_type"><option value="alpha">Alpa</option><option value="late">Terlambat</option><option value="early_leave">Pulang cepat</option><option value="unpaid">Cuti tidak dibayar</option><option value="missing_checkin">Tidak check-in</option><option value="missing_checkout">Tidak check-out</option></select></div><div class="col-md-2"><label class="form-label">Metode Potongan</label><select class="form-select" name="calculation_method"><option value="none">Tidak dipotong</option><option value="fixed">Nominal tetap</option><option value="per_minute">Per menit</option><option value="per_hour">Per jam</option><option value="per_day">Per hari</option><option value="percentage_daily">Persentase tarif harian</option><option value="formula">Formula</option></select></div><div class="col-md-2"><label class="form-label">Komponen Potongan</label><select class="form-select searchable" name="component_id"><option value="">Tidak ada</option><?php foreach($components as$c):if($c->component_type!=='deduction')continue;?><option value="<?=$c->id?>"><?=html_escape($c->name)?></option><?php endforeach?></select></div><div class="col-md-1"><label class="form-label">Toleransi</label><input type="number" min="0" class="form-control" name="tolerance_minutes" value="0"></div><div class="col-md-2"><label class="form-label">Tarif</label><input type="number" min="0" step="0.01" class="form-control" name="rate_value" value="0"></div><div class="col-md-2"><label class="form-label">Maksimum</label><input type="number" min="0" step="0.01" class="form-control" name="maximum_amount"></div><div class="col-md-3"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>" required></div><div class="col-md-4"><label class="form-label">Formula / Keterangan</label><input class="form-control" name="formula_expression" placeholder="condition_quantity * rule_rate"></div><div class="col-md-1 d-flex align-items-end"><label class="form-check mb-2"><input class="form-check-input" type="checkbox" name="is_active" value="1" checked> Aktif</label></div><div class="col-md-2 d-flex align-items-end"><button class="btn btn-primary w-100">Simpan Versi</button></div></form></div><?php endif?><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Aturan</th><th>Kondisi</th><th>Metode</th><th>Toleransi</th><th class="text-end">Tarif</th><th>Komponen</th><th>Efektif</th></tr></thead><tbody><?php foreach($attendance_rules as$r):?><tr><td><?=html_escape($r->rule_name)?></td><td><?=html_escape($r->condition_type)?></td><td><?=html_escape($r->calculation_method)?></td><td><?=number_format($r->tolerance_minutes)?> menit</td><td class="text-end"><?=number_format($r->rate_value,2,',','.')?></td><td><?=html_escape($r->component_name?:'Tidak memotong')?></td><td><?=html_escape($r->effective_from)?></td></tr><?php endforeach?></tbody></table></div></section></div>
|
||||
<div class="tab-pane fade" id="generalTab"><section class="card hr-panel"><div class="card-header bg-white"><b>Pengaturan Umum Payroll</b><small class="d-block text-muted">Berlaku untuk perusahaan aktif dan tidak mengubah histori payroll lama.</small></div><div class="card-body"><div class="row g-3 mb-4"><div class="col-md-4"><div class="payroll-info-box"><b>Sumber Kehadiran</b><span>Rentang tanggal pada periode payroll</span></div></div><div class="col-md-4"><div class="payroll-info-box"><b>Prioritas Komponen</b><span>Override karyawan → template posisi → nilai default</span></div></div><div class="col-md-4"><div class="payroll-info-box"><b>Pengamanan</b><span>Snapshot, separation of duties, idempotency jurnal</span></div></div></div><?php if($permissions['update']):?><form method="post" action="<?=base_url('hrpayroll/save_settings')?>" class="row g-3"><?=$csrf?><div class="col-md-4"><label class="form-label">Pemisahan Tugas</label><label class="form-check form-switch"><input class="form-check-input" type="checkbox" name="separation_of_duties" value="1" <?=!$payroll_settings||$payroll_settings->separation_of_duties?'checked':''?>> Reviewer, approver, dan finalizer harus berbeda</label></div><div class="col-md-3"><label class="form-label">Tanggal Bayar Default</label><input type="number" min="1" max="31" class="form-control" name="default_payment_day" value="<?=html_escape($payroll_settings->default_payment_day??'')?>" placeholder="1–31"></div><div class="col-md-5"><label class="form-label">Catatan Export Bank</label><div class="input-group"><input class="form-control" name="bank_export_note" value="<?=html_escape($payroll_settings->bank_export_note??'')?>" placeholder="Instruksi internal sebelum upload"><button class="btn btn-primary">Simpan</button></div></div></form><?php endif?><p class="text-muted small mt-3 mb-0">Akun jurnal utama dikelola melalui System Account Mapping. Akun khusus dapat dipilih pada masing-masing komponen.</p></div></section></div>
|
||||
</div>
|
||||
|
||||
<?php else:?>
|
||||
<?php if($permissions['create']):?><section class="card hr-panel mb-3"><div class="card-header bg-white"><b>Tambah Penyesuaian Satu Periode</b><small class="d-block text-muted">Tidak membuat jurnal saat disimpan dan tidak berulang ke periode berikutnya.</small></div><div class="card-body"><form method="post" action="<?=base_url('hrpayroll/save_adjustment')?>" class="row g-2"><?=$csrf?><div class="col-md-3"><label class="form-label">Periode Draft</label><select class="form-select searchable" name="payroll_period_id" required><option value="">Pilih periode</option><?php foreach($periods as$p):if($p->workflow_status!=='draft')continue;?><option value="<?=$p->id?>"><?=html_escape($p->period_name)?></option><?php endforeach?></select></div><div class="col-md-3"><label class="form-label">Karyawan</label><select class="form-select searchable" name="employee_id" required><option value="">Pilih karyawan</option><?php foreach($employees as$e):?><option value="<?=$e->id?>"><?=html_escape($e->employee_code.' - '.$e->full_name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Jenis</label><select class="form-select" name="adjustment_type"><option value="earning">Pendapatan</option><option value="deduction">Potongan</option></select></div><div class="col-md-2"><label class="form-label">Komponen</label><select class="form-select searchable" name="component_id" required><option value="">Pilih komponen</option><?php foreach($components as$c):if($c->component_type==='employer_cost')continue;?><option value="<?=$c->id?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nominal</label><input type="number" min="0.01" step="0.01" class="form-control" name="amount" required></div><div class="col-md-10"><label class="form-label">Keterangan</label><input class="form-control" name="notes" placeholder="Alasan bonus, rapel, koreksi, atau potongan" required></div><div class="col-md-2 d-flex align-items-end"><button class="btn btn-primary w-100">Simpan</button></div></form></div></section><?php endif?>
|
||||
<section class="card hr-panel"><div class="card-header bg-white"><b>Daftar Penyesuaian</b></div><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Periode</th><th>Karyawan</th><th>Komponen</th><th>Jenis</th><th class="text-end">Nominal</th><th>Keterangan</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php if(!$adjustments):?><tr><td colspan="8" class="text-center text-muted py-5">Belum ada penyesuaian periode.</td></tr><?php endif;foreach($adjustments as$a):?><tr><td><?=html_escape($a->period_name)?></td><td><b><?=html_escape($a->full_name)?></b><small class="d-block text-muted"><?=html_escape($a->employee_code)?></small></td><td><?=html_escape($a->component_name)?></td><td><span class="badge <?=$a->adjustment_type==='earning'?'bg-success':'bg-warning text-dark'?>"><?=html_escape($a->adjustment_type==='earning'?'Pendapatan':'Potongan')?></span></td><td class="text-end">Rp <?=number_format($a->amount,2,',','.')?></td><td><?=html_escape($a->notes)?></td><td><?=html_escape($statusLabels[$a->workflow_status]??$a->workflow_status)?></td><td><?php if($permissions['update']&&$a->workflow_status==='draft'):?><form method="post" action="<?=base_url('hrpayroll/deactivate_adjustment/'.$a->id)?>" class="js-confirm"><?=$csrf?><button class="btn btn-sm btn-outline-danger">Nonaktifkan</button></form><?php else:?>-<?php endif?></td></tr><?php endforeach?></tbody></table></div></section>
|
||||
<?php if($permissions['create']):?><section class="card hr-panel mb-3"><div class="card-header bg-white"><b>Tambah Penyesuaian Satu Periode</b><small class="d-block text-muted">Tidak membuat jurnal saat disimpan dan tidak berulang ke periode berikutnya.</small></div><div class="card-body"><form method="post" action="<?=base_url('hrpayroll/save_adjustment')?>" class="row g-2"><?=$csrf?><div class="col-md-3"><label class="form-label">Periode Draft</label><select class="form-select searchable" name="payroll_period_id" required><option value="">Pilih periode</option><?php foreach($periods as$p):if($p->workflow_status!=='draft')continue;?><option value="<?=$p->id?>"><?=html_escape($p->period_name)?></option><?php endforeach?></select></div><div class="col-md-3"><label class="form-label">Karyawan</label><select class="form-select searchable" name="employee_id" required><option value="">Pilih karyawan</option><?php foreach($employees as$e):?><option value="<?=$e->id?>"><?=html_escape($e->employee_code.' - '.$e->full_name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Jenis</label><select class="form-select" name="adjustment_type"><?php if($can_manage_allowances):?><option value="earning">Pendapatan / Bonus</option><?php endif?><option value="deduction">Potongan</option></select></div><div class="col-md-2"><label class="form-label">Komponen</label><select class="form-select searchable" name="component_id" required><option value="">Pilih komponen</option><?php foreach($adjustment_components as$c):?><option value="<?=$c->id?>" data-type="<?=html_escape($c->component_type)?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nominal</label><input type="number" min="0.01" step="0.01" class="form-control" name="amount" required></div><div class="col-md-10"><label class="form-label">Keterangan</label><input class="form-control" name="notes" placeholder="Alasan bonus, rapel, koreksi, atau potongan" required></div><div class="col-md-2 d-flex align-items-end"><button class="btn btn-primary w-100">Simpan</button></div></form></div></section><?php endif?>
|
||||
<section class="card hr-panel"><div class="card-header bg-white"><b>Daftar Penyesuaian</b></div><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Periode</th><th>Karyawan</th><th>Komponen</th><th>Jenis</th><th class="text-end">Nominal</th><th>Keterangan</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php if(!$adjustments):?><tr><td colspan="8" class="text-center text-muted py-5">Belum ada penyesuaian periode.</td></tr><?php endif;foreach($adjustments as$a):?><tr><td><?=html_escape($a->period_name)?></td><td><b><?=html_escape($a->full_name)?></b><small class="d-block text-muted"><?=html_escape($a->employee_code)?></small></td><td><?=html_escape($a->component_name)?></td><td><span class="badge <?=$a->adjustment_type==='earning'?'bg-success':'bg-warning text-dark'?>"><?=html_escape($a->adjustment_type==='earning'?'Pendapatan':'Potongan')?></span></td><td class="text-end">Rp <?=number_format($a->amount,2,',','.')?></td><td><?=html_escape($a->notes)?></td><td><?=html_escape($statusLabels[$a->workflow_status]??$a->workflow_status)?></td><td><?php if($permissions['update']&&!empty($a->can_manage)&&$a->workflow_status==='draft'):?><form method="post" action="<?=base_url('hrpayroll/deactivate_adjustment/'.$a->id)?>" class="js-confirm"><?=$csrf?><button class="btn btn-sm btn-outline-danger">Nonaktifkan</button></form><?php else:?>-<?php endif?></td></tr><?php endforeach?></tbody></table></div></section>
|
||||
<?php endif?>
|
||||
|
||||
<div class="modal fade" id="payrollDetailModal" tabindex="-1"><div class="modal-dialog modal-xl modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><div><small class="text-muted">RINCIAN PERIODE</small><h5 class="modal-title" id="payrollDetailTitle">Payroll</h5></div><button class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="table-responsive"><table class="table align-middle"><thead><tr><th>Karyawan</th><th class="text-end">Hadir</th><th class="text-end">Alpa</th><th class="text-end">Lembur</th><th class="text-end">Bruto</th><th class="text-end">Potongan</th><th class="text-end">Neto</th><th>Slip</th></tr></thead><tbody id="payrollDetailRows"></tbody></table></div></div></div></div></div>
|
||||
<div class="modal fade" id="salaryModal" tabindex="-1" data-bs-backdrop="static"><div class="modal-dialog modal-xl modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><div><small class="text-muted">STRUKTUR GAJI EFEKTIF</small><h5 class="modal-title" id="salaryModalTitle">Karyawan</h5><small id="salaryModalMeta" class="text-muted"></small></div><button class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="table-responsive mb-4"><table class="table align-middle"><thead><tr><th>Komponen</th><th>Jenis</th><th>Metode</th><th class="text-end">Nilai/Tarif</th><th>Efektif</th><th>Status</th><th>Aksi</th></tr></thead><tbody id="salaryLineRows"></tbody></table></div><?php if($permissions['update']):?><form id="salaryLineForm" data-ajax="true" class="row g-2"><?=$csrf?><input type="hidden" name="employee_id" id="salaryEmployeeId"><div class="col-md-3"><label class="form-label">Komponen</label><select class="form-select" name="component_id" required><option value="">Pilih komponen</option><?php foreach($components as$c):?><option value="<?=$c->id?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Metode</label><select class="form-select" name="calculation_method"><?php foreach($methodLabels as$key=>$label):?><option value="<?=$key?>"><?=html_escape($label)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nilai/Tarif</label><input type="number" min="0" step="0.01" class="form-control" name="amount_override" value="0" required></div><div class="col-md-2"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>" required></div><div class="col-md-2"><label class="form-label">Selesai (opsional)</label><input type="date" class="form-control" name="effective_to"></div><div class="col-md-1 d-flex align-items-end"><button class="btn btn-primary w-100">Tambah</button></div><div class="col-md-6"><input class="form-control" name="formula_expression" placeholder="Formula bila metode Formula"></div><div class="col-md-6"><input class="form-control" name="notes" placeholder="Keterangan perubahan"></div></form><?php endif?></div></div></div></div>
|
||||
<div class="modal fade" id="salaryModal" tabindex="-1" data-bs-backdrop="static"><div class="modal-dialog modal-xl modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><div><small class="text-muted">STRUKTUR GAJI EFEKTIF</small><h5 class="modal-title" id="salaryModalTitle">Karyawan</h5><small id="salaryModalMeta" class="text-muted"></small></div><button class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="table-responsive mb-4"><table class="table align-middle"><thead><tr><th>Komponen</th><th>Jenis</th><th>Metode</th><th class="text-end">Nilai/Tarif</th><th>Efektif</th><th>Status</th><th>Aksi</th></tr></thead><tbody id="salaryLineRows"></tbody></table></div><?php if($permissions['update']):?><form id="salaryLineForm" data-ajax="true" class="row g-2"><?=$csrf?><input type="hidden" name="employee_id" id="salaryEmployeeId"><div class="col-md-3"><label class="form-label">Komponen</label><select class="form-select" name="component_id" required><option value="">Pilih komponen</option><?php foreach($manageable_components as$c):?><option value="<?=$c->id?>"><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Metode</label><select class="form-select" name="calculation_method"><?php foreach($methodLabels as$key=>$label):?><option value="<?=$key?>"><?=html_escape($label)?></option><?php endforeach?></select></div><div class="col-md-2"><label class="form-label">Nilai/Tarif</label><input type="number" min="0" step="0.01" class="form-control" name="amount_override" value="0" required></div><div class="col-md-2"><label class="form-label">Mulai Berlaku</label><input type="date" class="form-control" name="effective_from" value="<?=date('Y-m-d')?>" required></div><div class="col-md-2"><label class="form-label">Selesai (opsional)</label><input type="date" class="form-control" name="effective_to"></div><div class="col-md-1 d-flex align-items-end"><button type="submit" class="btn btn-primary w-100">Tambah</button></div><div class="col-md-6"><input class="form-control" name="formula_expression" placeholder="Formula bila metode Formula"></div><div class="col-md-6"><input class="form-control" name="notes" placeholder="Keterangan perubahan"></div></form><?php endif?></div></div></div></div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
const esc=v=>$('<div>').text(v??'').html(),money=v=>'Rp '+Number(v||0).toLocaleString('id-ID',{minimumFractionDigits:2,maximumFractionDigits:2});
|
||||
$('.searchable').select2({width:'100%'});
|
||||
<?php if(!$can_manage_allowances):?>
|
||||
$('#componentsTab select[name="component_type"] option').filter(function(){return this.value!=='deduction'}).remove();
|
||||
$('#componentsTab select[name="category"] option').filter(function(){return !['unpaid_leave','loan','bpjs','tax','other'].includes(this.value)}).remove();
|
||||
$('#generalTab form').remove();
|
||||
<?php endif?>
|
||||
const adjustmentForm=$('form[action$="hrpayroll/save_adjustment"]');
|
||||
adjustmentForm.find('select[name="component_id"]').on('change',function(){const type=$(this).find(':selected').data('type');if(type)adjustmentForm.find('select[name="adjustment_type"]').val(type).trigger('change.select2')});
|
||||
$(document).ajaxSuccess(function(_event,_xhr,settings,response){if(!String(settings.url||'').includes('hrpayroll/salary_detail/'))return;const lines=response?.data?.lines||response?.lines||[];$('#salaryLineRows tr').each(function(index){if(lines[index]&&!lines[index].can_manage)$(this).find('.deactivate-salary').remove()})});
|
||||
if($('#salaryTable').length){const table=$('#salaryTable').DataTable({pageLength:25,order:[[0,'asc']],language:{search:'Cari:',lengthMenu:'Tampilkan _MENU_ data',info:'_START_–_END_ dari _TOTAL_',paginate:{previous:'Sebelumnya',next:'Berikutnya'}}});$('#salaryDepartmentFilter').on('change',function(){table.column(1).search(this.value).draw()});$('#salaryPositionFilter').on('change',function(){table.column(2).search(this.value).draw()});$('#salaryStatusFilter').on('change',function(){table.column(3).search(this.value).draw()})}
|
||||
const detailModal=bootstrap.Modal.getOrCreateInstance('#payrollDetailModal');$('.payroll-detail').on('click',function(){$.getJSON('<?=base_url('hrpayroll/period_detail/')?>'+this.dataset.id).done(r=>{if(!r.status)return AppAlert.toast(r.message,'error');$('#payrollDetailTitle').text(r.period.period_name);$('#payrollDetailRows').html((r.rows||[]).map(x=>`<tr><td><b>${esc(x.full_name)}</b><small class="d-block text-muted">${esc(x.employee_code)}${x.salary_restricted==1?' · Gaji terbatas':''}</small></td><td class="text-end">${x.total_present}</td><td class="text-end">${x.total_alpha}</td><td class="text-end">${x.total_overtime_hours}</td><td class="text-end">${money(x.gross_salary)}</td><td class="text-end">${money(x.total_deductions)}</td><td class="text-end fw-bold">${money(x.total_salary)}</td><td>${['final','posted','paid'].includes(r.period.workflow_status)?`<a class="btn btn-sm btn-outline-primary" target="_blank" href="<?=base_url('hrpayroll/slip/')?>${x.id}">Slip</a>`:'-'}</td></tr>`).join('')||'<tr><td colspan="8" class="text-center text-muted">Belum ada rincian.</td></tr>');detailModal.show()}).fail(x=>AppAlert.toast(x.responseJSON?.message||'Rincian gagal dimuat.','error'))});
|
||||
const salaryModal=bootstrap.Modal.getOrCreateInstance('#salaryModal');let currentEmployee=0;function loadSalary(id){currentEmployee=id;$('#salaryLineRows').html('<tr><td colspan="7" class="text-center py-4"><span class="spinner-border spinner-border-sm"></span> Memuat…</td></tr>');salaryModal.show();$.getJSON('<?=base_url('hrpayroll/salary_detail/')?>'+id).done(r=>{if(!r.status){salaryModal.hide();return AppAlert.toast(r.message,'error')}$('#salaryEmployeeId').val(id);$('#salaryModalTitle').text(r.data?.employee?.full_name||r.employee?.full_name||'Karyawan');const employee=r.data?.employee||r.employee,lines=r.data?.lines||r.lines||[];$('#salaryModalMeta').text((employee?.employee_code||'')+' · '+(employee?.department_name||'-')+' · '+(employee?.position_name||'-'));$('#salaryLineRows').html(lines.map(x=>`<tr><td><b>${esc(x.component_code)}</b><small class="d-block text-muted">${esc(x.component_name)}</small></td><td>${esc(x.component_type)}</td><td>${esc(x.calculation_method)}</td><td class="text-end">${money(x.amount_override)}</td><td>${esc(x.effective_from)}${x.effective_to?' s.d. '+esc(x.effective_to):''}</td><td><span class="badge ${x.is_active==1?'bg-success':'bg-secondary'}">${x.is_active==1?'Aktif':'Selesai'}</span></td><td>${x.is_active==1?`<button class="btn btn-sm btn-outline-danger deactivate-salary" data-id="${x.id}">Nonaktifkan</button>`:'-'}</td></tr>`).join('')||'<tr><td colspan="7" class="text-center text-muted py-4">Belum ada komponen gaji.</td></tr>')}).fail(x=>{salaryModal.hide();AppAlert.toast(x.responseJSON?.message||'Struktur gaji gagal dimuat.','error')})}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
)as$m):?><div class="col-6 col-xl-2"><div class="metric-card"><span class="metric-icon text-<?=$m[3]?>"><i class="bi <?=$m[2]?>"></i></span><strong><?=$m[1]?></strong><small><?=$m[0]?></small></div></div><?php endforeach?>
|
||||
</div>
|
||||
<div class="row g-3 mt-1">
|
||||
<div class="col-xl-7"><section class="inventory-card h-100"><div class="inventory-card-head"><div><h5>Pekerjaan Gudang</h5><p>Barang yang sudah diterima tetapi belum siap digunakan atau dijual.</p></div><a href="<?=base_url('items/draft_items')?>" class="btn btn-sm btn-outline-primary">Buka Barang Pending</a></div>
|
||||
<div class="col-xl-6"><section class="inventory-card h-100"><div class="inventory-card-head"><div><h5>Pekerjaan Gudang</h5><p>Barang yang sudah diterima tetapi belum siap digunakan atau dijual.</p></div><a href="<?=base_url('items/draft_items')?>" class="btn btn-sm btn-outline-primary">Buka Barang Pending</a></div>
|
||||
<?php if(!$action_items):?><div class="inventory-empty"><i class="bi bi-check-circle"></i><strong>Tidak ada barang pending</strong><span>Semua penerimaan sudah ditangani.</span></div><?php else:?><div class="inventory-list"><?php foreach($action_items as$i):?><a href="<?=base_url('items/draft_items?focus='.$i->id)?>"><span class="item-avatar"><i class="bi bi-box"></i></span><span class="flex-grow-1"><strong><?=html_escape($i->kode_detail.' - '.$i->nama_barang)?></strong><small><?=number_format($i->ready_barcodes,0,',','.')?> siap dari <?=number_format($i->pending_barcodes,0,',','.')?> barcode pending</small></span><i class="bi bi-chevron-right"></i></a><?php endforeach?></div><?php endif?>
|
||||
</section></div>
|
||||
<div class="col-xl-5"><section class="inventory-card h-100" id="scanner"><div class="inventory-card-head"><div><h5>Scan Barcode / Serial</h5><p>Lihat posisi, status, saldo, dan riwayat unit.</p></div></div><div class="p-3"><div class="input-group input-group-lg"><span class="input-group-text"><i class="bi bi-upc-scan"></i></span><input id="scanCode" class="form-control" placeholder="Scan atau ketik kode"><button id="scanButton" class="btn btn-primary">Periksa</button></div><div id="scanResult" class="scan-result mt-3"><div class="inventory-empty py-4"><i class="bi bi-qr-code-scan"></i><span>Hasil scan tampil di sini.</span></div></div></div></section></div>
|
||||
<div class="col-xl-6"><section class="inventory-card h-100" id="scanner"><div class="inventory-card-head"><div><h5>Scan Barcode / Serial</h5><p>Lihat posisi, status, saldo, dan riwayat unit.</p></div></div><div class="p-3"><div class="input-group input-group-lg"><span class="input-group-text"><i class="bi bi-upc-scan"></i></span><input id="scanCode" class="form-control" placeholder="Scan atau ketik kode"><button id="scanButton" class="btn btn-primary">Periksa</button></div><div id="scanResult" class="scan-result mt-3"><div class="inventory-empty py-4"><i class="bi bi-qr-code-scan"></i><span>Hasil scan tampil di sini.</span></div></div></div></section></div>
|
||||
</div>
|
||||
<section class="inventory-card mt-3"><div class="inventory-card-head"><div><h5>Dokumen Mutasi Terbaru</h5><p>Jejak dokumen stok dari seluruh gudang.</p></div><a href="<?=base_url('inventoryprofessional/operations')?>" class="btn btn-sm btn-outline-primary">Lihat Semua</a></div><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Dokumen</th><th>Jenis</th><th>Tanggal</th><th>Lokasi</th><th>Status</th><th>Pembuat</th></tr></thead><tbody><?php foreach($documents as$d):?><tr><td><a href="<?=base_url('inventoryprofessional/operations?focus='.$d->id)?>" class="fw-semibold"><?=html_escape($d->document_no)?></a></td><td><?=html_escape(ucwords(str_replace('_',' ',$d->document_type)))?></td><td><?=date('d/m/Y',strtotime($d->document_date))?></td><td><?=html_escape(($d->from_warehouse?:'-').' → '.($d->to_warehouse?:'-'))?></td><td><span class="status-chip status-<?=$d->status?>"><?=html_escape(strtoupper($d->status))?></span></td><td><?=html_escape($d->creator_name?:'-')?></td></tr><?php endforeach?></tbody></table></div></section>
|
||||
<script>
|
||||
|
||||
@@ -8,7 +8,7 @@ $(function(){
|
||||
const csrf=()=>({[APP_CSRF.name]:APP_CSRF.value}),esc=v=>$('<div>').text(v==null?'-':v).html(),money=v=>'Rp '+Number(v||0).toLocaleString('id-ID',{minimumFractionDigits:2,maximumFractionDigits:2});
|
||||
const table=$('#tableItems').DataTable({responsive:true,processing:true,serverSide:true,searchDelay:350,ajax:{url:'<?=base_url('items/get_data')?>',data:d=>{d.s='draft';d.server=1}},pageLength:25,language:{search:'Cari:',processing:'Memuat data...',lengthMenu:'Tampilkan _MENU_',info:'_START_–_END_ dari _TOTAL_',paginate:{previous:'Sebelumnya',next:'Berikutnya'}},initComplete:function(){let f=new URLSearchParams(location.search).get('focus');if(f)setTimeout(()=>$('.btn-detail[data-id="'+f+'"]').first().click(),300)}});
|
||||
$(document).on('blur','.pending-sale-price',function(){let n=String(this.value).replace(/\./g,'').replace(',','.');if(Number(n)>0)this.value=Number(n).toLocaleString('id-ID',{minimumFractionDigits:2,maximumFractionDigits:2})});
|
||||
$(document).on('click','.btn-updatePosting',function(){let id=$(this).data('id'),input=$('.pending-sale-price[data-id="'+id+'"]'),sale=Number(String(input.val()).replace(/\./g,'').replace(',','.')),buy=Number(input.data('buy')||0);if(!sale)return AppAlert.toast('Harga jual satuan wajib diisi.','warning');if(sale<buy)return AppAlert.toast('Harga jual tidak boleh lebih rendah dari harga beli.','error');let b=$(this);AppAlert.confirm({title:'Posting barang siap digunakan?',text:'Hanya barcode yang serialnya sudah lengkap yang akan diaktifkan.',confirmButtonText:'Posting Barang'}).then(r=>{if(!r.isConfirmed)return;b.prop('disabled',true);$.post('<?=base_url('items/posting')?>',Object.assign({id:id,harga_jual:sale},csrf())).done(x=>{if(!x.status)return AppAlert.toast(x.message,'error');table.ajax.reload(null,false);AppAlert.toast(x.message,'success')}).fail(()=>AppAlert.toast('Posting barang gagal.','error')).always(()=>b.prop('disabled',false))})});
|
||||
$(document).on('click','.btn-updatePosting',function(){let id=$(this).data('id'),input=$('.pending-sale-price[data-id="'+id+'"]'),sale=Number(String(input.val()).replace(/\./g,'').replace(',','.')),buy=Number(input.data('buy')||0);if(!sale)return AppAlert.toast('Harga jual satuan wajib diisi.','warning');if(sale<buy)return AppAlert.toast('Harga jual tidak boleh lebih rendah dari harga beli.','error');let b=$(this);AppAlert.confirm({title:'Posting barang siap digunakan?',text:'Hanya barcode yang serialnya sudah lengkap yang akan diaktifkan.',confirmButtonText:'Posting Barang'}).then(r=>{if(!r.isConfirmed)return;b.prop('disabled',true);$.ajax({url:'<?=base_url('items/posting')?>',type:'POST',data:Object.assign({id:id,harga_jual:sale},csrf()),dataType:'json'}).done(x=>{let message=x&&x.message?String(x.message):'Respons posting barang tidak valid.';if(!x||!x.status)return AppAlert.toast(message,'error');table.ajax.reload(null,false);AppAlert.toast(message,'success')}).fail(xhr=>{let message=xhr.responseJSON&&xhr.responseJSON.message?xhr.responseJSON.message:'Posting barang gagal.';AppAlert.toast(String(message),'error')}).always(()=>b.prop('disabled',false))})});
|
||||
$(document).on('click','.btn-detail',function(){let id=$(this).data('id');$('#pendingDetailBody').html('<div class="inventory-loading"><span class="spinner-border spinner-border-sm"></span> Memuat detail…</div>');bootstrap.Modal.getOrCreateInstance('#pendingDetailModal').show();$.get('<?=base_url('items/detail')?>/'+id).done(r=>{let rows=(r.logs||[]).map(x=>'<tr><td>'+esc(x.created_at)+'</td><td>'+esc(x.gudang)+'</td><td>'+esc(x.tipe)+'</td><td class="text-end">'+Number(x.qty||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</td><td>'+esc(x.keterangan)+'</td></tr>').join('');$('#pendingDetailBody').html('<div class="document-meta"><span>Kode<strong>'+esc(r.item.kode_detail)+'</strong></span><span>Barang<strong>'+esc(r.item.nama_barang)+'</strong></span><span>Harga Beli<strong>'+money(r.item.harga_beli)+'</strong></span><span>Harga Jual<strong>'+money(r.item.harga_jual)+'</strong></span><span>Stok Diterima<strong>'+Number(r.item.stok||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</strong></span><span>Status<strong><span class="status-chip status-submitted">PENDING</span></strong></span></div><div class="table-responsive mt-3"><table class="table inventory-table"><thead><tr><th>Tanggal</th><th>Gudang</th><th>Arah</th><th class="text-end">Qty</th><th>Keterangan</th></tr></thead><tbody>'+rows+'</tbody></table></div><button type="button" class="btn btn-sm btn-outline-danger stock-pdf" data-id="'+id+'"><i class="bi bi-file-earmark-pdf"></i> PDF Audit</button>')})});
|
||||
$(document).on('click','.stock-pdf',function(){$('#barcodePrintModal .modal-title').text('PDF Kartu Stok');$('#barcodePrintModal iframe').attr('src','<?=base_url('items/stock_log_pdf')?>/'+$(this).data('id'));bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()});
|
||||
$(document).on('click','.btn-print',function(){let id=$(this).data('id');AppAlert.prompt({title:'Preview Barcode',html:'<label class="form-label d-block text-start">Jumlah kolom</label><select id="printColumn" class="form-select mb-3"><option value="2">2</option><option value="3" selected>3</option><option value="4">4</option></select><label class="form-label d-block text-start">Salinan</label><input id="printCopies" type="number" min="1" max="20" value="1" class="form-control">',preConfirm:()=>({column:$('#printColumn').val(),duplicat:$('#printCopies').val()}),confirmButtonText:'Preview'}).then(r=>{if(!r.isConfirmed)return;$('#barcodePrintModal .modal-title').text('Preview Barcode');$('#barcodePrintModal iframe').attr('src','<?=base_url('items/print_barcode')?>/'+id+'?column='+r.value.column+'&duplicat='+r.value.duplicat+'&status=all');bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()})});
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
<h5>Jurnal Umum</h5>
|
||||
<button class="btn btn-warning btn-add">Tambah Jurnal</button>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-6 col-md-4 col-lg-3">
|
||||
<label for="journalStatusFilter" class="form-label">Status</label>
|
||||
<select id="journalStatusFilter" class="form-select">
|
||||
<option value="">Semua Status</option>
|
||||
<option value="draft">Draft</option>
|
||||
<option value="submitted">Diajukan</option>
|
||||
<option value="approved">Disetujui</option>
|
||||
<option value="posted">Terposting</option>
|
||||
<option value="rejected">Ditolak</option>
|
||||
<option value="reversed">Reversal</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<form id="filterForm" class="row mb-3">-->
|
||||
|
||||
@@ -63,7 +78,7 @@
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Tambah Jurnal</h5>
|
||||
<h5 id="journalModalTitle">Tambah Jurnal</h5>
|
||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
@@ -140,7 +155,8 @@
|
||||
<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><br>
|
||||
<strong>Status:</strong> <span id="d_status"></span>
|
||||
<strong>Status:</strong> <span id="d_status"></span>
|
||||
<div id="d_rejection" class="alert alert-danger mt-3 d-none"></div>
|
||||
</div>
|
||||
|
||||
<table class="table table-bordered">
|
||||
@@ -183,6 +199,7 @@ $(function(){
|
||||
|
||||
let accounts = [];
|
||||
let mode = 'manual';
|
||||
let editJournalId = 0;
|
||||
|
||||
// ================= LOAD ACCOUNTS
|
||||
function loadAccounts(){
|
||||
@@ -374,6 +391,27 @@ $('.btn-add').click(async function(){
|
||||
$('#formTotalKredit').text('0');
|
||||
|
||||
$('#modeManual').click(); // default jurnal manual dengan dua akun
|
||||
editJournalId = 0;
|
||||
$('#journalModalTitle').text('Tambah Jurnal');
|
||||
$('#btnSimpan').text('Simpan');
|
||||
});
|
||||
|
||||
$(document).on('click','.btn-edit-rejected',async function(){
|
||||
const id=$(this).data('id');
|
||||
await loadAccounts();
|
||||
await loadBaseJurnal();
|
||||
$('#modeManual').click();
|
||||
$.get("<?= base_url('jurnal/detail/'); ?>"+id,function(res){
|
||||
editJournalId=id;
|
||||
$('#journalModalTitle').text('Koreksi Jurnal Ditolak');
|
||||
$('#btnSimpan').text('Simpan Koreksi');
|
||||
$('#tanggal').val(res.header.tanggal);
|
||||
$('#keterangan').val(res.header.keterangan);
|
||||
$('#tableDetail tbody').empty();
|
||||
(res.detail||[]).forEach(function(row){addRow({account_id:row.account_id,debit:Number(row.debit)>0?row.debit:'',kredit:Number(row.kredit)>0?row.kredit:''});});
|
||||
hitungTotalForm();
|
||||
$('#modalJurnal').modal('show');
|
||||
},'json').fail(function(xhr){Swal.fire('Error',xhr.responseJSON?.message||'Jurnal tidak dapat dimuat.','error');});
|
||||
});
|
||||
|
||||
$('#btnSimpan').click(function(){
|
||||
@@ -426,7 +464,10 @@ $('#btnSimpan').click(function(){
|
||||
return;
|
||||
}
|
||||
// lanjut simpan
|
||||
$.post("<?= base_url('jurnal/save'); ?>", {
|
||||
const saveUrl=editJournalId
|
||||
? "<?= base_url('jurnal/update_rejected/'); ?>"+editJournalId
|
||||
: "<?= base_url('jurnal/save'); ?>";
|
||||
$.post(saveUrl, {
|
||||
tanggal: $('#tanggal').val(),
|
||||
keterangan: $('#keterangan').val(),
|
||||
account_id: account_id,
|
||||
@@ -436,6 +477,7 @@ $('#btnSimpan').click(function(){
|
||||
|
||||
if(res.status){
|
||||
$('#modalJurnal').modal('hide');
|
||||
editJournalId=0;
|
||||
$('#tableJurnal').DataTable().ajax.reload(null,false);
|
||||
Swal.fire('Sukses',res.message,'success');
|
||||
} else {
|
||||
@@ -454,7 +496,10 @@ let table = $('#tableJurnal').DataTable({
|
||||
order:[[1,'desc']],
|
||||
ajax:{
|
||||
url:"<?= base_url('jurnal/get_data'); ?>",
|
||||
type:"POST"
|
||||
type:"POST",
|
||||
data:function(d){
|
||||
d.status = $('#journalStatusFilter').val();
|
||||
}
|
||||
},
|
||||
columnDefs:[
|
||||
{ targets:[4,5], className:'text-end' }
|
||||
@@ -476,6 +521,10 @@ let table = $('#tableJurnal').DataTable({
|
||||
}
|
||||
});
|
||||
|
||||
$('#journalStatusFilter').on('change', function(){
|
||||
table.ajax.reload(null, true);
|
||||
});
|
||||
|
||||
// DELETE
|
||||
$(document).on('click','.btn-delete',function(){
|
||||
let id = $(this).data('id');
|
||||
@@ -520,10 +569,7 @@ let table = $('#tableJurnal').DataTable({
|
||||
});
|
||||
|
||||
// DETAIL
|
||||
$(document).on('click','.btn-detail',function(){
|
||||
|
||||
let id = $(this).data('id');
|
||||
|
||||
function openJournalDetail(id){
|
||||
$.get("<?= base_url('jurnal/detail/'); ?>" + id, function(res){
|
||||
|
||||
$('#d_tanggal').text(res.header.tanggal);
|
||||
@@ -531,6 +577,7 @@ $(document).on('click','.btn-detail',function(){
|
||||
$('#d_keterangan').text(res.header.keterangan);
|
||||
$('#d_createdby').text(res.user ? res.user.nama : '-');
|
||||
$('#d_status').text(String(res.header.status || '').toUpperCase());
|
||||
if(res.header.rejection_reason){$('#d_rejection').removeClass('d-none').html('<strong>Alasan penolakan sebelumnya</strong><br>'+String(res.header.rejection_reason).replace(/[&<>'"]/g,function(c){return{'&':'&','<':'<','>':'>',"'":''','"':'"'}[c];}));}else{$('#d_rejection').addClass('d-none').empty();}
|
||||
let history=(res.history||[]).map(h=>`${h.from_status||'-'} → ${h.to_status} oleh ${h.changed_by_name||'-'} (${h.changed_at})${h.notes?' — '+h.notes:''}`).join('<br>');
|
||||
$('#statusHistory').html(history || 'Belum ada perubahan status.');
|
||||
|
||||
@@ -558,9 +605,11 @@ $(document).on('click','.btn-detail',function(){
|
||||
|
||||
$('#modalDetail').modal('show');
|
||||
|
||||
},'json');
|
||||
},'json').fail(function(xhr){Swal.fire('Error',xhr.responseJSON?.message||'Detail jurnal tidak dapat dimuat.','error');});
|
||||
}
|
||||
|
||||
});
|
||||
$(document).on('click','.btn-detail',function(){openJournalDetail($(this).data('id'));});
|
||||
$(function(){const focus=Number(new URLSearchParams(window.location.search).get('focus')||0);if(focus>0)openJournalDetail(focus);});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -10,6 +10,7 @@ $CI->config->load('ui_assets',true);
|
||||
$uiAssets=$CI->config->item('ui_assets');
|
||||
$dataPages=isset($uiAssets['ui_data_pages'])?$uiAssets['ui_data_pages']:array();
|
||||
$selectPages=isset($uiAssets['ui_select_pages'])?$uiAssets['ui_select_pages']:array();
|
||||
$loadDataTables=!empty($use_datatables)||in_array($active_menu,$dataPages,true);
|
||||
$userName=$this->session->userdata('nama')?:$this->session->userdata('username')?:'Pengguna';
|
||||
$userRole=$this->session->userdata('role')?:'User';
|
||||
$userPhoto=$this->session->userdata('profile_photo');
|
||||
@@ -19,11 +20,11 @@ $userPhoto=$this->session->userdata('profile_photo');
|
||||
<title><?=html_escape($page_title)?> · Accounting</title>
|
||||
<link rel="manifest" href="<?=base_url('manifest.webmanifest')?>"><link rel="icon" href="<?=base_url('assets/img/pwa-192.png')?>"><link rel="apple-touch-icon" href="<?=base_url('assets/img/pwa-192.png')?>">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" onerror="this.onerror=null;this.href='<?=base_url('assets/vendor/bootstrap.min.css')?>'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
||||
<?php if(in_array($active_menu,$dataPages,true)):?><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.8/css/dataTables.bootstrap5.min.css"><?php endif?>
|
||||
<?php if($loadDataTables):?><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.8/css/dataTables.bootstrap5.min.css"><?php endif?>
|
||||
<?php if(in_array($active_menu,$selectPages,true)):?><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css"><?php endif?>
|
||||
<link rel="stylesheet" href="<?=base_url('assets/css/style-custom.css').'?v='.filemtime(FCPATH.'assets/css/style-custom.css')?>"><link rel="stylesheet" href="<?=base_url('assets/css/app-final.css').'?v='.filemtime(FCPATH.'assets/css/app-final.css')?>"><?php if($active_menu==='profile'):?><link rel="stylesheet" href="<?=base_url('assets/css/profile.css').'?v='.filemtime(FCPATH.'assets/css/profile.css')?>"><?php endif?><?php if($active_menu==='leave_requests'):?><link rel="stylesheet" href="<?=base_url('assets/css/leave-requests.css').'?v='.filemtime(FCPATH.'assets/css/leave-requests.css')?>"><?php endif?><?php if(in_array($active_menu,array('organization_master','employees','generate_schedule','attendance_monitoring','attendance_monthly','shift','holidays','leave_requests','hr_payroll'),true)):?><link rel="stylesheet" href="<?=base_url('assets/css/hr-payroll.css').'?v='.filemtime(FCPATH.'assets/css/hr-payroll.css')?>"><?php endif?>
|
||||
<script src="<?=base_url('assets/vendor/jquery.min.js')?>"></script>
|
||||
<?php if(in_array($active_menu,$dataPages,true)):?><script src="https://cdn.jsdelivr.net/npm/datatables.net@1.13.8/js/jquery.dataTables.min.js"></script><script src="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.8/js/dataTables.bootstrap5.min.js"></script><script src="https://cdn.jsdelivr.net/npm/datatables.net-responsive@2.5.0/js/dataTables.responsive.min.js"></script><?php endif?>
|
||||
<?php if($loadDataTables):?><script src="https://cdn.jsdelivr.net/npm/datatables.net@1.13.8/js/jquery.dataTables.min.js"></script><script src="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.8/js/dataTables.bootstrap5.min.js"></script><script src="https://cdn.jsdelivr.net/npm/datatables.net-responsive@2.5.0/js/dataTables.responsive.min.js"></script><?php endif?>
|
||||
<?php if(in_array($active_menu,$selectPages,true)):?><script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script><?php endif?>
|
||||
</head><body class="app-v2" data-page="<?=html_escape($active_menu)?>">
|
||||
<a class="visually-hidden-focusable skip-link" href="#mainContent">Lewati ke konten</a>
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
$inventory_title='Log Peralatan Teknisi';
|
||||
$inventory_subtitle='Telusuri barang yang dibawa, dipasang pada customer, atau dikembalikan oleh teknisi.';
|
||||
$perm=$equipment_permissions??array();
|
||||
$active_panel='history';
|
||||
$active_panel=$active_panel??'history';
|
||||
$initialFilters=$initial_filters??array();
|
||||
$initialStatus=(string)($initialFilters['status']??'');
|
||||
$initialCondition=(string)($initialFilters['condition']??'');
|
||||
$this->load->view('inventory_professional/_module_nav',get_defined_vars());
|
||||
?>
|
||||
<link rel="stylesheet" href="<?=base_url('assets/css/technician-equipment.css')?>?v=<?=filemtime(FCPATH.'assets/css/technician-equipment.css')?>">
|
||||
<div class="tech-shell">
|
||||
<?php $this->load->view('peralatan_teknisi/_module_nav',get_defined_vars()); ?>
|
||||
<section class="inventory-card">
|
||||
<div class="inventory-card-head"><div><h5>Filter Riwayat Peralatan</h5><p>Tanggal mencakup tanggal dibawa, dipasang, atau dikembalikan.</p></div><a href="<?=base_url('teknisi')?>" class="btn btn-outline-secondary"><i class="bi bi-arrow-left me-1"></i>Kembali</a></div>
|
||||
@@ -14,14 +18,15 @@ $this->load->view('inventory_professional/_module_nav',get_defined_vars());
|
||||
<div class="col-sm-6 col-xl-2"><label class="form-label">Sampai Tanggal</label><input type="date" class="form-control" name="date_to"></div>
|
||||
<div class="col-md-6 col-xl-2"><label class="form-label">Customer</label><select class="form-select select-search" name="customer_id"><option value="">Semua customer</option><?php foreach($customers as$customer):?><option value="<?=$customer->id?>"><?=html_escape($customer->nama)?></option><?php endforeach?></select></div>
|
||||
<div class="col-md-6 col-xl-2"><label class="form-label">Karyawan / Teknisi</label><select class="form-select select-search" name="user_id"><option value="">Semua teknisi</option><?php foreach($teknisi_list as$employee):?><option value="<?=$employee->id?>"><?=html_escape($employee->employee_code.' - '.$employee->full_name)?></option><?php endforeach?></select></div>
|
||||
<div class="col-md-4 col-xl-2"><label class="form-label">Status</label><select class="form-select" name="status"><option value="">Semua</option><option value="carried">Dibawa</option><option value="installed">Dipasang</option><option value="removed">Dilepas</option><option value="returned">Dikembalikan</option></select></div>
|
||||
<div class="col-md-4 col-xl-2"><label class="form-label">Kondisi</label><select class="form-select" name="condition"><option value="">Semua</option><option value="good">Baik</option><option value="inspection_required">Perlu Diperiksa</option><option value="repair_required">Perlu Perbaikan</option><option value="under_repair">Dalam Perbaikan</option><option value="damaged">Rusak</option><option value="lost">Hilang</option><option value="scrapped">Dihapuskan</option></select></div>
|
||||
<div class="col-md-4 col-xl-2"><label class="form-label">Status</label><select class="form-select" name="status"><option value="">Semua</option><option value="carried" <?=$initialStatus==='carried'?'selected':''?>>Dibawa</option><option value="installed" <?=$initialStatus==='installed'?'selected':''?>>Dipasang</option><option value="removed" <?=$initialStatus==='removed'?'selected':''?>>Dilepas</option><option value="returned" <?=$initialStatus==='returned'?'selected':''?>>Dikembalikan</option></select></div>
|
||||
<div class="col-md-4 col-xl-2"><label class="form-label">Kondisi</label><select class="form-select" name="condition"><option value="">Semua</option><option value="good" <?=$initialCondition==='good'?'selected':''?>>Baik</option><option value="inspection_required" <?=$initialCondition==='inspection_required'?'selected':''?>>Perlu Diperiksa</option><option value="repair_required" <?=$initialCondition==='repair_required'?'selected':''?>>Perlu Perbaikan</option><option value="under_repair" <?=$initialCondition==='under_repair'?'selected':''?>>Dalam Perbaikan</option><option value="damaged" <?=$initialCondition==='damaged'?'selected':''?>>Rusak</option><option value="lost" <?=$initialCondition==='lost'?'selected':''?>>Hilang</option><option value="scrapped" <?=$initialCondition==='scrapped'?'selected':''?>>Dihapuskan</option></select></div>
|
||||
<div class="col-md-4 col-xl-2"><label class="form-label">Kepemilikan</label><select class="form-select" name="ownership"><option value="">Semua</option><option value="company">Perusahaan</option><option value="customer">Customer</option><option value="transferred_non_inventory">Non-Persediaan Diserahkan</option><option value="unknown">Belum Diketahui</option></select></div>
|
||||
<div class="col-md-8 col-xl-4"><label class="form-label">Barang / Barcode / Serial</label><input class="form-control" name="query" placeholder="Cari identitas barang"></div>
|
||||
<div class="col-md-4 col-xl-2 d-flex gap-2"><button type="submit" class="btn btn-primary flex-grow-1"><i class="bi bi-funnel me-1"></i>Tampilkan</button><?php if($can_export):?><button type="button" id="technicianLogPdf" class="btn btn-outline-danger" title="Export PDF"><i class="bi bi-file-earmark-pdf"></i></button><?php endif?></div>
|
||||
</form>
|
||||
<div class="table-responsive"><table class="table align-middle mb-0 w-100" id="tblLogBarang"><thead><tr><th>No</th><th>Dokumen</th><th>Teknisi</th><th>Barang</th><th>Barcode / SN</th><th>Pemilik</th><th>Qty</th><th>Customer</th><th>Posisi</th><th>Status</th><th>Kondisi</th><th>Keterangan</th><th>Aksi</th></tr></thead><tbody></tbody></table></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="modal fade" id="technicianLogDetailModal" data-bs-backdrop="static" tabindex="-1"><div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Detail Dokumen Peralatan</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"></div><div class="modal-footer"><button class="btn btn-light" data-bs-dismiss="modal">Tutup</button></div></div></div></div>
|
||||
<?php if($can_export):?><div class="modal fade" id="technicianLogPdfModal" tabindex="-1"><div class="modal-dialog modal-xl modal-dialog-centered"><div class="modal-content" style="height:min(90vh,900px)"><div class="modal-header"><h5 class="modal-title">PDF Log Peralatan Teknisi</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body p-0"><iframe title="PDF Log Peralatan Teknisi" style="width:100%;height:100%;border:0"></iframe></div></div></div></div><?php endif?>
|
||||
<script>
|
||||
|
||||
@@ -10,8 +10,8 @@ function tech_qty($value){$n=(float)$value;return abs($n-round($n))<.0001?number
|
||||
|
||||
<?php if($panel==='overview'):?>
|
||||
<div class="tech-summary">
|
||||
<?php foreach(array('carried'=>array('Dibawa Teknisi','bi-person-bag'),'installed'=>array('Terpasang','bi-house-check'),'inspection'=>array('Menunggu Periksa','bi-clipboard-pulse'),'repair'=>array('Dalam Perbaikan','bi-wrench-adjustable'),'damaged'=>array('Rusak','bi-exclamation-octagon'),'lost'=>array('Hilang','bi-question-diamond')) as$key=>$meta):?>
|
||||
<div class="tech-stat"><small><i class="bi <?=$meta[1]?>"></i> <?=$meta[0]?></small><strong data-summary="<?=$key?>"><?=tech_qty($dash['summary'][$key]??0)?></strong></div>
|
||||
<?php foreach(array('carried'=>array('Dibawa Teknisi','bi-person-bag','status','carried'),'installed'=>array('Terpasang','bi-house-check','status','installed'),'inspection'=>array('Menunggu Periksa','bi-clipboard-pulse','condition','inspection_required'),'repair'=>array('Dalam Perbaikan','bi-wrench-adjustable','condition','under_repair'),'damaged'=>array('Rusak','bi-exclamation-octagon','condition','damaged'),'lost'=>array('Hilang','bi-question-diamond','condition','lost')) as$key=>$meta):?>
|
||||
<a class="tech-stat tech-stat-<?=$key?>" href="<?=base_url('teknisi/log_barang').'?'.http_build_query(array($meta[2]=>$meta[3]))?>" title="Lihat riwayat <?=html_escape(strtolower($meta[0]))?>"><small><i class="bi <?=$meta[1]?>"></i> <?=$meta[0]?></small><strong data-summary="<?=$key?>"><?=tech_qty($dash['summary'][$key]??0)?></strong><span class="tech-stat-link"><i class="bi bi-arrow-right"></i></span></a>
|
||||
<?php endforeach?>
|
||||
</div>
|
||||
<section class="tech-card" id="scanner">
|
||||
|
||||
@@ -33,9 +33,22 @@ $accountCode=function($value){return preg_replace('/(?:[\.,]0+)$/','',(string)$v
|
||||
<div class="col-lg-6"><div class="card h-100"><div class="card-header bg-danger text-white"><b>BEBAN</b></div><div class="card-body p-0"><table class="table mb-0"><tbody><?php foreach($expenses as$r):?><tr><td><?=html_escape($accountCode($r['kode_akun']).' · '.$r['nama_akun'])?></td><td class="text-end"><?=$money($r['amount'])?></td></tr><?php endforeach?></tbody><tfoot><tr class="table-danger"><th>TOTAL BEBAN</th><th class="text-end">Rp <?=$money($totalExpense)?></th></tr></tfoot></table></div></div></div>
|
||||
</div>
|
||||
<div class="card mt-3"><div class="card-body d-flex justify-content-between align-items-center"><h5 class="mb-0"><?=$netProfit>=0?'LABA BERSIH':'RUGI BERSIH'?></h5><h4 class="mb-0 <?=$netProfit>=0?'text-success':'text-danger'?>">Rp <?=$money(abs($netProfit))?></h4></div></div>
|
||||
<?php elseif($report==='cash_flow'): ?>
|
||||
<div class="row g-2 mb-3">
|
||||
<?php foreach(array('opening_balance'=>'Saldo Awal Kas','operating'=>'Aktivitas Operasi','investing'=>'Aktivitas Investasi','financing'=>'Aktivitas Pendanaan','increase_decrease'=>'Kenaikan / Penurunan Kas','closing_balance'=>'Saldo Akhir Kas')as$key=>$label):?>
|
||||
<div class="col-md-4 col-xl-2"><div class="card h-100"><div class="card-body"><small class="text-muted"><?=$label?></small><strong class="d-block mt-1 <?=((float)($report_summary[$key]??0))<0?'text-danger':''?>">Rp <?=$money($report_summary[$key]??0)?></strong></div></div></div>
|
||||
<?php endforeach?>
|
||||
</div>
|
||||
<div class="card"><div class="card-header"><b>Detail Transaksi Pembentuk Arus Kas</b><small class="d-block text-muted">Saldo berjalan mencakup seluruh akun kas/bank yang dipilih.</small></div><div class="table-responsive"><table class="table table-sm align-middle mb-0"><thead><tr><th>Tanggal</th><th>Referensi</th><th>Keterangan</th><th>Akun</th><th>Aktivitas</th><th class="text-end">Kas Masuk</th><th class="text-end">Kas Keluar</th><th class="text-end">Saldo</th></tr></thead><tbody><?php foreach($rows as$r):?><tr><td><?=html_escape($r['tanggal'])?></td><td><a href="<?=base_url('jurnal?focus='.$r['journal_id'])?>"><?=html_escape($r['no_ref']?:'#'.$r['journal_id'])?></a></td><td><?=html_escape($r['keterangan'])?></td><td><?=html_escape($r['akun'])?></td><td><?=html_escape($r['aktivitas'])?></td><td class="text-end text-success"><?=$money($r['kas_masuk'])?></td><td class="text-end text-danger"><?=$money($r['kas_keluar'])?></td><td class="text-end fw-semibold"><?=$money($r['saldo_berjalan'])?></td></tr><?php endforeach?><?php if(!$rows):?><tr><td colspan="8" class="text-center text-muted py-4">Tidak ada transaksi kas pada periode ini.</td></tr><?php endif?></tbody><tfoot><tr><th colspan="5">Total Mutasi</th><th class="text-end"><?=$money($report_summary['cash_in']??0)?></th><th class="text-end"><?=$money($report_summary['cash_out']??0)?></th><th class="text-end"><?=$money($report_summary['closing_balance']??0)?></th></tr></tfoot></table></div></div>
|
||||
<?php elseif($report==='general_ledger'): ?>
|
||||
<div class="card mb-3"><div class="card-header"><b>Ringkasan Saldo per Akun</b><small class="d-block text-muted">Saldo awal berasal dari seluruh jurnal sebelum periode, bukan dari pagination tampilan.</small></div><div class="table-responsive"><table class="table table-sm mb-0"><thead><tr><th>Akun</th><th class="text-end">Saldo Awal</th><th class="text-end">Total Debit</th><th class="text-end">Total Kredit</th><th class="text-end">Saldo Akhir</th></tr></thead><tbody><?php foreach($report_summary as$r):?><tr><td><?=html_escape($accountCode($r['kode_akun']).' - '.$r['nama_akun'])?></td><td class="text-end"><?=$money($r['saldo_awal'])?></td><td class="text-end"><?=$money($r['total_debit'])?></td><td class="text-end"><?=$money($r['total_kredit'])?></td><td class="text-end fw-bold"><?=$money($r['saldo_akhir'])?></td></tr><?php endforeach?><?php if(!$report_summary):?><tr><td colspan="5" class="text-center text-muted py-4">Tidak ada saldo atau mutasi akun.</td></tr><?php endif?></tbody></table></div></div>
|
||||
<div class="card"><div class="card-header"><b>Rincian Buku Besar</b></div><div class="table-responsive"><table class="table table-sm align-middle mb-0"><thead><tr><th>Akun</th><th>Tanggal</th><th>Referensi</th><th>Keterangan</th><th class="text-end">Debit</th><th class="text-end">Kredit</th><th class="text-end">Saldo Berjalan</th></tr></thead><tbody><?php foreach($rows as$r):?><tr><td><?=html_escape($accountCode($r['kode_akun']).' - '.$r['nama_akun'])?></td><td><?=html_escape($r['tanggal'])?></td><td><a href="<?=base_url('jurnal?focus='.$r['journal_id'])?>"><?=html_escape($r['no_ref'])?></a></td><td><?=html_escape($r['keterangan'])?></td><td class="text-end"><?=$money($r['debit'])?></td><td class="text-end"><?=$money($r['kredit'])?></td><td class="text-end fw-semibold"><?=$money($r['saldo_berjalan'])?></td></tr><?php endforeach?><?php if(!$rows):?><tr><td colspan="7" class="text-center text-muted py-4">Tidak ada transaksi pada periode ini.</td></tr><?php endif?></tbody></table></div></div>
|
||||
<?php elseif($report==='receivable_reconciliation'): ?>
|
||||
<div class="row g-2 mb-3"><div class="col-md-4"><div class="card h-100"><div class="card-body"><small class="text-muted">Subledger Invoice</small><strong class="d-block">Rp <?=$money($report_summary['subledger']??0)?></strong></div></div></div><div class="col-md-4"><div class="card h-100"><div class="card-body"><small class="text-muted">Saldo Buku Besar Piutang</small><strong class="d-block">Rp <?=$money($report_summary['general_ledger']??0)?></strong></div></div></div><div class="col-md-4"><div class="card h-100 border-<?=$report_summary['balanced']?'success':'warning'?>"><div class="card-body"><small class="text-muted">Selisih Belum Terpetakan</small><strong class="d-block <?=$report_summary['balanced']?'text-success':'text-warning'?>">Rp <?=$money($report_summary['difference']??0)?></strong></div></div></div></div>
|
||||
<div class="card"><div class="card-header"><b>Piutang per Invoice sampai <?=html_escape($filters['to'])?></b><small class="d-block text-muted">Pembayaran, credit note, dan write-off ditelusuri sampai tanggal laporan. Selisih data lama tetap ditampilkan untuk kebutuhan koreksi.</small></div><div class="table-responsive"><table class="table table-sm align-middle mb-0"><thead><tr><th>Customer</th><th>Invoice</th><th>Tanggal</th><th>Jatuh Tempo</th><th class="text-end">Nilai Piutang</th><th class="text-end">Pembayaran</th><th class="text-end">Credit Note</th><th class="text-end">Write-off</th><th class="text-end">Sisa</th><th>Status</th><th>Referensi</th></tr></thead><tbody><?php foreach($rows as$r):?><tr class="<?=!empty($r['reconciliation_adjustment'])?'table-warning':''?>"><td><?=html_escape($r['customer'])?></td><td><?php if(!empty($r['record_id'])):?><a href="<?=base_url('invoices/detail/'.$r['record_id'])?>"><?=html_escape($r['no_invoice'])?></a><?php else:?><?=html_escape($r['no_invoice'])?><?php endif?></td><td><?=html_escape($r['invoice_date']?:'-')?></td><td><?=html_escape($r['due_date']?:'-')?></td><td class="text-end"><?=$money($r['receivable_amount'])?></td><td class="text-end"><?=$money($r['payments'])?></td><td class="text-end"><?=$money($r['credit_notes'])?></td><td class="text-end"><?=$money($r['writeoffs'])?></td><td class="text-end fw-bold"><?=$money($r['remaining_receivable'])?></td><td><?=html_escape($r['status'])?></td><td><?=html_escape($r['transaction_references']?:'-')?></td></tr><?php endforeach?></tbody><tfoot><tr><th colspan="8">Total setelah rekonsiliasi</th><th class="text-end">Rp <?=$money($report_summary['general_ledger']??0)?></th><th colspan="2"></th></tr></tfoot></table></div></div>
|
||||
<?php else: ?>
|
||||
<?php $visibleColumns=$rows?array_values(array_filter(array_keys($rows[0]),function($key){return$key!=='record_id';})):array();$documentTypes=array('return_no'=>'purchase_return','refund_no'=>'supplier_refund','debit_note_no'=>'supplier_debit_note'); ?>
|
||||
<div class="card"><div class="table-responsive"><table class="table table-sm mb-0"><thead><?php if($rows):?><tr><?php foreach($visibleColumns as$h):?><th><?=html_escape(ucwords(str_replace('_',' ',$h)))?></th><?php endforeach?></tr><?php endif?></thead><tbody><?php foreach($rows as$r):?><tr><?php foreach($visibleColumns as$k):$v=$r[$k];?><td class="<?=is_numeric($v)&&!preg_match('/(^id$|_id$|kode_akun$)/',$k)?'text-end':''?>"><?php if($k==='journal_id'&&$v):?><a href="<?=base_url('jurnal/detail/'.$v)?>">#<?=$v?></a><?php elseif(isset($documentTypes[$k])&&!empty($r['record_id'])):?><a href="<?=base_url('purchases/returns?action=history&focus_type='.$documentTypes[$k].'&focus='.$r['record_id'])?>"><?=html_escape($v)?></a><?php elseif($k==='kode_akun'):?><?=html_escape($accountCode($v))?><?php elseif(is_numeric($v)&&!preg_match('/(^id$|_id$|kode_akun$)/',$k)):?><?=$money($v)?><?php else:?><?=html_escape($v===null?'-':$v)?><?php endif?></td><?php endforeach?></tr><?php endforeach?></tbody></table></div></div>
|
||||
<div class="card"><div class="table-responsive"><table class="table table-sm mb-0"><thead><?php if($rows):?><tr><?php foreach($visibleColumns as$h):?><th><?=html_escape(ucwords(str_replace('_',' ',$h)))?></th><?php endforeach?></tr><?php endif?></thead><tbody><?php foreach($rows as$r):?><tr><?php foreach($visibleColumns as$k):$v=$r[$k];?><td class="<?=is_numeric($v)&&!preg_match('/(^id$|_id$|kode_akun$)/',$k)?'text-end':''?>"><?php if($k==='journal_id'&&$v):?><a href="<?=base_url('jurnal?focus='.$v)?>">#<?=$v?></a><?php elseif(isset($documentTypes[$k])&&!empty($r['record_id'])):?><a href="<?=base_url('purchases/returns?action=history&focus_type='.$documentTypes[$k].'&focus='.$r['record_id'])?>"><?=html_escape($v)?></a><?php elseif($k==='kode_akun'):?><?=html_escape($accountCode($v))?><?php elseif(is_numeric($v)&&!preg_match('/(^id$|_id$|kode_akun$)/',$k)):?><?=$money($v)?><?php else:?><?=html_escape($v===null?'-':$v)?><?php endif?></td><?php endforeach?></tr><?php endforeach?></tbody></table></div></div>
|
||||
<?php endif; ?>
|
||||
<div class="mt-3"><b>Subledger:</b> <a href="<?=base_url('receivables')?>">Aging Piutang</a> · <a href="<?=base_url('payables')?>">Aging Hutang</a> · <a href="<?=base_url('inventoryprofessional')?>">Persediaan</a> · <a href="<?=base_url('fixedassets')?>">Aset</a> · <a href="<?=base_url('hrpayroll')?>">Payroll</a> · <a href="<?=base_url('purchases/returns')?>">Retur & Refund</a></div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<?php foreach($roles as$r):?><button type="button" class="list-group-item list-group-item-action role-item" data-id="<?=$r->id?>"><div class="d-flex justify-content-between"><b><?=html_escape($r->nama_role)?></b><span><?php if($r->is_super_admin):?><span class="badge bg-danger">Master Admin</span><?php elseif($r->is_system):?><span class="badge bg-secondary">Bawaan</span><?php else:?><span class="badge bg-info text-dark">Custom</span><?php endif?></span></div><small class="text-muted"><?=html_escape($r->description?:'Belum ada uraian tanggung jawab')?></small></button><?php endforeach?>
|
||||
</div></div></div>
|
||||
<div class="col-lg-8"><div class="card"><div class="card-header" id="formTitle">Pilih role untuk melihat permission</div><div class="card-body"><form id="roleForm"><input type="hidden" name="id" id="roleId"><div class="row g-2 mb-3"><div class="col-md-4"><label class="form-label">Nama Role</label><input class="form-control" name="name" id="roleName" required></div><div class="col-md-6"><label class="form-label">Tanggung Jawab Role</label><input class="form-control" name="description" id="roleDescription" required placeholder="Jelaskan pekerjaan yang ditangani"></div><div class="col-md-2 d-flex align-items-end"><label class="form-check mb-2"><input class="form-check-input" type="checkbox" name="is_active" id="roleActive" value="1"> Aktif</label></div></div>
|
||||
<div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>Modul</th><?php foreach($actions as$label):?><th class="text-center"><?=$label?></th><?php endforeach?></tr></thead><tbody><?php foreach($features as$key=>$label):?><tr><td><b><?=$label?></b><?php if($key==='payroll'):?><div class="form-check mt-2"><input class="form-check-input permission-box" type="checkbox" name="permissions[payroll][]" value="can_manage_all_salary" id="manageAllSalary" data-feature="payroll" data-action="can_manage_all_salary"><label class="form-check-label small text-danger" for="manageAllSalary">Manage All Gaji (termasuk gaji terbatas)</label></div><?php endif?></td><?php foreach($actions as$action=>$actionLabel):?><td class="text-center"><input class="form-check-input permission-box" type="checkbox" name="permissions[<?=$key?>][]" value="<?=$action?>" data-feature="<?=$key?>" data-action="<?=$action?>"></td><?php endforeach?></tr><?php endforeach?></tbody></table></div>
|
||||
<div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>Modul</th><?php foreach($actions as$label):?><th class="text-center"><?=$label?></th><?php endforeach?></tr></thead><tbody><?php foreach($features as$key=>$label):?><tr><td><b><?=$label?></b><?php if($key==='payroll'):?><div class="form-check mt-2"><input class="form-check-input permission-box" type="checkbox" name="permissions[payroll][]" value="can_manage_all_salary" id="manageAllSalary" data-feature="payroll" data-action="can_manage_all_salary"><label class="form-check-label small text-danger" for="manageAllSalary">Manage All Gaji (termasuk gaji terbatas)</label></div><div class="form-check mt-2"><input class="form-check-input permission-box" type="checkbox" name="permissions[payroll][]" value="can_manage_allowances" id="managePayrollAllowances" data-feature="payroll" data-action="can_manage_allowances"><label class="form-check-label small text-warning-emphasis" for="managePayrollAllowances">Kelola Tunjangan & Bonus</label><small class="d-block text-muted">Tanpa izin ini, user hanya dapat mengatur Gaji Pokok dan Potongan.</small></div><?php endif?></td><?php foreach($actions as$action=>$actionLabel):?><td class="text-center"><input class="form-check-input permission-box" type="checkbox" name="permissions[<?=$key?>][]" value="<?=$action?>" data-feature="<?=$key?>" data-action="<?=$action?>"></td><?php endforeach?></tr><?php endforeach?></tbody></table></div>
|
||||
<div class="d-flex justify-content-between mt-3"><button type="button" class="btn btn-outline-danger" id="deleteRole" hidden>Hapus Role Custom</button><button class="btn btn-success ms-auto" id="saveRole">Simpan Permission</button></div>
|
||||
</form></div></div></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user