Update besar apk finance
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<div class="container-fluid py-3"><h4>HR & Payroll Control</h4><p class="text-muted">Lock absensi → Draft → Review HR → Approval → Final → Jurnal → Pembayaran.</p><?php foreach(array('success','error')as$f)if($this->session->flashdata($f)):?><div class="alert alert-<?=$f==='success'?'success':'danger'?>"><?=html_escape($this->session->flashdata($f))?></div><?php endif?><div class="row g-3"><div class="col-lg-4"><div class="card h-100"><div class="card-header">1. Lock Absensi Bulanan</div><div class="card-body"><form method="post" action="<?=base_url('hrpayroll/lock_attendance')?>"><input class="form-control mb-2" type="month" name="period" value="<?=date('Y-m')?>" required><input class="form-control mb-2" name="notes" required placeholder="Catatan validasi absensi"><button class="btn btn-warning">Validasi & Lock</button></form></div></div></div><div class="col-lg-4"><div class="card h-100"><div class="card-header">2. Hitung Draft Payroll</div><div class="card-body"><form method="post" action="<?=base_url('hrpayroll/calculate')?>"><input class="form-control mb-2" type="month" name="month" value="<?=date('Y-m')?>" required><p class="small">Menggunakan snapshot absensi terkunci dan formula komponen aktif.</p><button class="btn btn-primary">Generate/Hitung Ulang Draft</button></form></div></div></div><div class="col-lg-4"><div class="card h-100"><div class="card-header">Formula Configurable</div><div class="card-body"><small>Variabel: basic_salary, work_days, present_days, unpaid_days, overtime_hours, overtime_rate, daily_rate.</small><form class="mt-2" method="post" action="<?=base_url('hrpayroll/component')?>"><div class="d-flex gap-1"><input class="form-control" name="code" placeholder="Kode" required><input class="form-control" name="name" placeholder="Nama" required></div><div class="d-flex gap-1 my-1"><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><select class="form-select" name="category"><option>allowance</option><option>overtime</option><option>unpaid_leave</option><option>loan</option><option>bpjs</option><option>tax</option><option>thr</option><option>bonus</option><option>other</option></select></div><input class="form-control mb-1" name="formula_expression" placeholder="Contoh: overtime_hours * overtime_rate"><input class="form-control mb-1" type="number" name="fixed_amount" placeholder="Atau nominal tetap"><label class="me-2"><input type="checkbox" name="taxable" value="1"> Taxable</label><label><input type="checkbox" name="prorated" value="1"> Prorata</label><br><button class="btn btn-sm btn-outline-primary mt-2">Simpan Komponen</button></form></div></div></div></div>
|
||||
<div class="card mt-3"><div class="card-header">Payroll Register</div><div class="table-responsive"><table class="table mb-0"><tr><th>Periode</th><th>Karyawan</th><th>Bruto</th><th>Potongan</th><th>Neto</th><th>Status</th><th>Workflow</th></tr><?php foreach($periods as$p):?><tr><td><?=html_escape($p->period_name)?></td><td><?=$p->employee_count?></td><td class="text-end"><?=number_format($p->gross,0,',','.')?></td><td class="text-end"><?=number_format($p->deductions,0,',','.')?></td><td class="text-end"><?=number_format($p->net,0,',','.')?></td><td><span class="badge bg-secondary"><?=$p->workflow_status?></span></td><td><div class="d-flex gap-1"><?php if($p->workflow_status==='draft'):?><form method="post" action="<?=base_url('hrpayroll/workflow/'.$p->id.'/review')?>"><button class="btn btn-sm btn-info">Review HR</button></form><?php elseif($p->workflow_status==='reviewed'):?><form method="post" action="<?=base_url('hrpayroll/workflow/'.$p->id.'/approve')?>"><button class="btn btn-sm btn-warning">Approve</button></form><?php elseif($p->workflow_status==='approved'):?><form method="post" action="<?=base_url('hrpayroll/workflow/'.$p->id.'/finalize')?>"><button class="btn btn-sm btn-danger">Final & Lock</button></form><?php elseif($p->workflow_status==='final'):?><form class="d-flex" method="post" action="<?=base_url('hrpayroll/post/'.$p->id)?>"><input class="form-control form-control-sm" type="date" name="date" value="<?=$p->end_date?>"><button class="btn btn-sm btn-success">Post Jurnal</button></form><?php elseif($p->workflow_status==='posted'):?><form class="d-flex" method="post" action="<?=base_url('hrpayroll/pay/'.$p->id)?>"><input class="form-control form-control-sm" type="date" name="date" value="<?=date('Y-m-d')?>"><select class="form-select form-select-sm" name="cash_account_id"><?php foreach($cash_accounts as$c):?><option value="<?=$c->id?>"><?=html_escape($c->name)?></option><?php endforeach?></select><button class="btn btn-sm btn-primary">Bayar</button></form><?php endif?></div></td></tr><?php endforeach?></table></div></div>
|
||||
<div class="card mt-3"><div class="card-header">Komponen Aktif</div><div class="table-responsive"><table class="table table-sm"><tr><th>Kode</th><th>Nama</th><th>Jenis</th><th>Kategori</th><th>Formula/Nominal</th><th>Pajak</th></tr><?php foreach($components as$c):?><tr><td><?=$c->code?></td><td><?=html_escape($c->name)?></td><td><?=$c->component_type?></td><td><?=$c->category?></td><td><?=html_escape($c->formula_expression?:number_format($c->fixed_amount,0,',','.'))?></td><td><?=$c->taxable?'Ya':'Tidak'?></td></tr><?php endforeach?></table></div></div></div>
|
||||
@@ -0,0 +1,37 @@
|
||||
<div class="container-fluid py-3">
|
||||
<div class="mb-3"><h4 class="mb-1">Master Departemen & Posisi</h4><p class="text-muted mb-0">Satu sumber data untuk karyawan, Purchase Request, payroll, jadwal, dan modul lainnya.</p></div>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6"><div class="card h-100"><div class="card-header"><b>Departemen</b></div><div class="card-body">
|
||||
<form id="departmentForm" class="row g-2 mb-3"><input type="hidden" name="<?=$this->security->get_csrf_token_name()?>" value="<?=$this->security->get_csrf_hash()?>"><input type="hidden" name="id"><div class="col-md-3"><input class="form-control" name="code" placeholder="Kode" required></div><div class="col-md-4"><input class="form-control" name="name" placeholder="Nama departemen" required></div><div class="col-md-5"><input class="form-control" name="description" placeholder="Keterangan"></div><div class="col-8"><label><input type="checkbox" name="is_active" value="1" checked> Aktif</label></div><div class="col-4 text-end"><button type="button" class="btn btn-light btn-reset">Reset</button> <button class="btn btn-primary">Simpan</button></div></form>
|
||||
<div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>Kode</th><th>Departemen</th><th>Status</th><th></th></tr></thead><tbody id="departmentRows"></tbody></table></div>
|
||||
</div></div></div>
|
||||
<div class="col-lg-6"><div class="card h-100"><div class="card-header"><b>Posisi / Jabatan</b></div><div class="card-body">
|
||||
<form id="positionForm" class="row g-2 mb-3"><input type="hidden" name="<?=$this->security->get_csrf_token_name()?>" value="<?=$this->security->get_csrf_hash()?>"><input type="hidden" name="id"><div class="col-md-3"><input class="form-control" name="code" placeholder="Kode" required></div><div class="col-md-4"><input class="form-control" name="name" placeholder="Nama posisi" required></div><div class="col-md-5"><select class="form-select" name="department_id" id="positionDepartment"><option value="">Semua departemen</option></select></div><div class="col-12"><input class="form-control" name="description" placeholder="Keterangan/tanggung jawab"></div><div class="col-8"><label><input type="checkbox" name="is_active" value="1" checked> Aktif</label></div><div class="col-4 text-end"><button type="button" class="btn btn-light btn-reset">Reset</button> <button class="btn btn-primary">Simpan</button></div></form>
|
||||
<div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>Kode</th><th>Posisi</th><th>Departemen</th><th>Status</th><th></th></tr></thead><tbody id="positionRows"></tbody></table></div>
|
||||
</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
const base='<?=base_url('organizationmaster/')?>';
|
||||
const departmentForm=document.getElementById('departmentForm'),positionForm=document.getElementById('positionForm');
|
||||
const departmentRows=document.getElementById('departmentRows'),positionRows=document.getElementById('positionRows'),positionDepartment=document.getElementById('positionDepartment');
|
||||
const esc=v=>$('<div>').text(v??'').html();
|
||||
let state={departments:[],positions:[]};
|
||||
async function load(){
|
||||
try{
|
||||
const response=await fetch(base+'data',{headers:{Accept:'application/json','X-Requested-With':'XMLHttpRequest'}}),json=await response.json();
|
||||
if(!response.ok||!json.status)throw new Error(json.message||'Gagal mengambil master organisasi.');
|
||||
state={departments:Array.isArray(json.departments)?json.departments:[],positions:Array.isArray(json.positions)?json.positions:[]};
|
||||
departmentRows.innerHTML=state.departments.map(x=>`<tr><td>${esc(x.code)}</td><td>${esc(x.department_name)}<small class="d-block text-muted">${esc(x.description||'')}</small></td><td>${x.is_active==1?'Aktif':'Nonaktif'}</td><td class="text-end"><button class="btn btn-sm btn-outline-primary edit-dep" data-id="${x.id}">Edit</button> <button class="btn btn-sm btn-outline-danger del-dep" data-id="${x.id}">Hapus</button></td></tr>`).join('')||'<tr><td colspan="4" class="text-center text-muted">Belum ada departemen.</td></tr>';
|
||||
positionRows.innerHTML=state.positions.map(x=>`<tr><td>${esc(x.code)}</td><td>${esc(x.position_name)}</td><td>${esc(x.department_name||'Semua')}</td><td>${x.is_active==1?'Aktif':'Nonaktif'}</td><td class="text-end"><button class="btn btn-sm btn-outline-primary edit-pos" data-id="${x.id}">Edit</button> <button class="btn btn-sm btn-outline-danger del-pos" data-id="${x.id}">Hapus</button></td></tr>`).join('')||'<tr><td colspan="5" class="text-center text-muted">Belum ada posisi.</td></tr>';
|
||||
positionDepartment.innerHTML='<option value="">Semua departemen</option>'+state.departments.filter(x=>x.is_active==1).map(x=>`<option value="${x.id}">${esc(x.code+' - '+x.department_name)}</option>`).join('');
|
||||
}catch(error){departmentRows.innerHTML=positionRows.innerHTML=`<tr><td colspan="5" class="text-danger">${esc(error.message)}</td></tr>`;}
|
||||
}
|
||||
async function save(form,path){const button=form.querySelector('button[type="submit"]');button.disabled=true;try{const response=await fetch(base+path,{method:'POST',body:new FormData(form),headers:{Accept:'application/json','X-Requested-With':'XMLHttpRequest'}}),json=await response.json();if(!response.ok||!json.status)throw new Error(json.message||'Gagal menyimpan');form.reset();form.elements.id.value='';form.elements.is_active.checked=true;await load();}catch(error){alert(error.message)}finally{button.disabled=false}}
|
||||
departmentForm.addEventListener('submit',event=>{event.preventDefault();save(departmentForm,'save_department')});
|
||||
positionForm.addEventListener('submit',event=>{event.preventDefault();save(positionForm,'save_position')});
|
||||
$(document).on('click','.btn-reset',function(){const form=this.closest('form');form.reset();form.elements.id.value='';form.elements.is_active.checked=true}).on('click','.edit-dep',function(){const x=state.departments.find(v=>v.id==this.dataset.id),f=departmentForm;if(!x)return;f.elements.id.value=x.id;f.elements.code.value=x.code;f.elements.name.value=x.department_name;f.elements.description.value=x.description||'';f.elements.is_active.checked=x.is_active==1}).on('click','.edit-pos',function(){const x=state.positions.find(v=>v.id==this.dataset.id),f=positionForm;if(!x)return;f.elements.id.value=x.id;f.elements.code.value=x.code;f.elements.name.value=x.position_name;f.elements.department_id.value=x.department_id||'';f.elements.description.value=x.description||'';f.elements.is_active.checked=x.is_active==1}).on('click','.del-dep,.del-pos',async function(){if(!confirm('Hapus data ini? Data yang sudah digunakan akan dinonaktifkan.'))return;const path=this.classList.contains('del-dep')?'delete_department/':'delete_position/',response=await fetch(base+path+this.dataset.id,{method:'POST',body:new FormData(departmentForm),headers:{Accept:'application/json','X-Requested-With':'XMLHttpRequest'}}),json=await response.json();alert(json.message);load()});
|
||||
load();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Slip Gaji</title><style>body{font:14px Arial;max-width:760px;margin:30px auto}table{width:100%;border-collapse:collapse}td,th{padding:8px;border-bottom:1px solid #ddd}.r{text-align:right}@media print{button{display:none}}</style></head><body><button onclick="print()">Cetak</button><h2>SLIP GAJI</h2><p><b><?=html_escape($payroll->full_name)?></b> — <?=html_escape($payroll->employee_code)?><br>Periode <?=html_escape($payroll->period_name)?></p><table><tr><th>Komponen</th><th>Jenis</th><th class="r">Nilai</th></tr><?php foreach($lines as$l):?><tr><td><?=html_escape($l->component_name)?></td><td><?=$l->component_type?></td><td class="r"><?=number_format($l->amount,0,',','.')?></td></tr><?php endforeach?><tr><th colspan="2">Gaji Neto</th><th class="r"><?=number_format($payroll->total_salary,0,',','.')?></th></tr></table><small>Dokumen rahasia. Status payroll: <?=$payroll->workflow_status?></small></body></html>
|
||||
Reference in New Issue
Block a user