update koneksi DB

This commit is contained in:
Wian Drs
2026-09-11 18:06:17 +07:00
parent 4ef15c22ae
commit ff870b7667
30 changed files with 390 additions and 115 deletions
+27 -1
View File
@@ -1 +1,27 @@
<div class="container-fluid py-3"><h4>Multi-company & Mata Uang</h4><div class="row g-3"><div class="col-lg-6"><div class="card"><div class="card-header">Perusahaan</div><div class="card-body"><form method="post" action="<?=base_url('companies/save')?>"><div class="row g-2"><div class="col-4"><input class="form-control" name="code" placeholder="Kode"></div><div class="col-8"><input class="form-control" name="name" placeholder="Nama"></div><div class="col-8"><input class="form-control" name="legal_name" placeholder="Nama legal"></div><div class="col-4"><select class="form-select" name="base_currency"><?php foreach($currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-8"><input class="form-control" name="tax_number" placeholder="NPWP"></div><div class="col-4"><button class="btn btn-primary">Tambah</button></div></div></form><hr><?php foreach($companies as$c):?><a class="btn btn-outline-dark m-1" href="<?=base_url('companies/switch_company/'.$c->id)?>"><?=html_escape($c->company_code.' · '.$c->name)?></a><?php endforeach?></div></div></div><div class="col-lg-6"><div class="card"><div class="card-header">Kurs Harian</div><div class="card-body"><form method="post" action="<?=base_url('companies/rate')?>"><div class="row g-2"><div class="col-4"><input class="form-control" type="date" name="date" value="<?=date('Y-m-d')?>"></div><div class="col-2"><select class="form-select" name="from_currency"><?php foreach($currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-2"><select class="form-select" name="to_currency"><?php foreach($currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-4"><input class="form-control" type="number" step=".00000001" name="rate" placeholder="Kurs"></div><div class="col-8"><input class="form-control" name="source" placeholder="Sumber kurs"></div><div class="col-4"><button class="btn btn-success">Simpan Kurs</button></div></div></form></div></div></div></div><div class="card mt-3"><div class="table-responsive"><table class="table table-sm"><tr><th>Tanggal</th><th>Perusahaan</th><th>Mata uang</th><th>Kurs</th><th>Sumber</th></tr><?php foreach($rates as$r):?><tr><td><?=$r->rate_date?></td><td><?=html_escape($r->company_name)?></td><td><?=$r->from_currency?>/<?=$r->to_currency?></td><td><?=number_format($r->rate,8,',','.')?></td><td><?=html_escape($r->source?:'-')?></td></tr><?php endforeach?></table></div></div></div>
<?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>
<?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?>
<nav class="company-settings-nav nav nav-pills" role="tablist"><button class="nav-link active" data-bs-toggle="pill" data-bs-target="#companyIdentity" type="button"><i class="bi bi-building"></i> Identitas Perusahaan</button><button class="nav-link" data-bs-toggle="pill" data-bs-target="#companyBanks" type="button"><i class="bi bi-bank"></i> Rekening Invoice</button><button class="nav-link" data-bs-toggle="pill" data-bs-target="#companyCurrencies" type="button"><i class="bi bi-currency-exchange"></i> Currency & Kurs</button><button class="nav-link" data-bs-toggle="pill" data-bs-target="#companyList" type="button"><i class="bi bi-buildings"></i> Multi-company</button></nav>
<div class="tab-content">
<div class="tab-pane fade show active" id="companyIdentity"><div class="settings-card"><div class="settings-card-head"><div><h5>Identitas pada Dokumen</h5><p>Informasi ini digunakan pada header PDF Invoice dan dokumen perusahaan.</p></div></div><form method="post" enctype="multipart/form-data" action="<?=base_url('companies/update')?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><div class="identity-grid"><div class="logo-field"><div class="company-logo-preview"><?php if(!empty($active_company->logo_path)&&is_file(FCPATH.$active_company->logo_path)):?><img src="<?=base_url($active_company->logo_path)?>" alt="Logo"><?php else:?><i class="bi bi-image"></i><span>Belum ada logo</span><?php endif?></div><label class="form-label">Logo Perusahaan</label><input class="form-control" type="file" name="logo" accept=".jpg,.jpeg,.png,.webp"><small>Maksimal 2 MB. Gunakan logo rasio mendekati persegi.</small></div><div><div class="row g-3"><div class="col-md-6"><label class="form-label">Nama Perusahaan</label><input class="form-control" name="name" value="<?=html_escape($active_company->name)?>" required></div><div class="col-md-6"><label class="form-label">Nama Legal</label><input class="form-control" name="legal_name" value="<?=html_escape($active_company->legal_name)?>"></div><div class="col-md-4"><label class="form-label">Telepon</label><input class="form-control" name="phone" value="<?=html_escape($active_company->phone??'')?>"></div><div class="col-md-4"><label class="form-label">Email</label><input class="form-control" type="email" name="email" value="<?=html_escape($active_company->email??'')?>"></div><div class="col-md-4"><label class="form-label">Mata Uang Dasar</label><select class="form-select" name="base_currency" required><?php foreach($active_currencies as$c):?><option value="<?=$c->code?>" <?=$active_company->base_currency===$c->code?'selected':''?>><?=html_escape($c->code.' - '.$c->name)?></option><?php endforeach?></select></div><div class="col-md-6"><label class="form-label">NPWP</label><input class="form-control" name="tax_number" value="<?=html_escape($active_company->tax_number)?>"></div><div class="col-12"><label class="form-label">Alamat Perusahaan</label><textarea class="form-control" name="address" rows="3"><?=html_escape($active_company->address)?></textarea></div></div><div class="text-end mt-3"><button class="btn btn-primary"><i class="bi bi-save"></i> Simpan Company Setting</button></div></div></div></form></div></div>
<div class="tab-pane fade" id="companyBanks"><div class="settings-split"><div class="settings-card"><div class="settings-card-head"><div><h5>Tambah / Edit Rekening</h5><p>Rekening aktif otomatis ditampilkan pada PDF Invoice.</p></div></div><form id="bankAccountForm" method="post" action="<?=base_url('companies/save_bank')?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><input type="hidden" name="id" value=""><div class="mb-3"><label class="form-label">Nama Bank / Dompet</label><input class="form-control" name="bank_name" placeholder="Contoh: Bank BRI" required></div><div class="mb-3"><label class="form-label">Nomor Rekening</label><input class="form-control" name="account_number" required></div><div class="mb-3"><label class="form-label">Atas Nama</label><input class="form-control" name="account_holder" required></div><div class="row g-3"><div class="col-7"><label class="form-label">Mata Uang</label><select class="form-select" name="currency"><?php foreach($active_currencies as$c):?><option value="<?=$c->code?>"><?=$c->code?></option><?php endforeach?></select></div><div class="col-5 d-flex align-items-end"><label class="form-check mb-2"><input class="form-check-input" type="checkbox" name="is_primary" value="1"><span class="form-check-label">Rekening utama</span></label></div></div><div class="d-flex gap-2 mt-3"><button class="btn btn-primary"><i class="bi bi-save"></i> Simpan Rekening</button><button class="btn btn-light d-none" id="cancelBankEdit" type="button">Batal Edit</button></div></form></div><div class="settings-card"><div class="settings-card-head"><div><h5>Daftar Rekening Perusahaan</h5><p>Rekening nonaktif disimpan dalam histori, tetapi tidak tampil di PDF.</p></div></div><div class="table-responsive"><table class="table align-middle"><thead><tr><th>Bank / Rekening</th><th>Mata Uang</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php foreach($bank_accounts as$b):?><tr><td><b><?=html_escape($b->bank_name)?></b><small><?=html_escape($b->account_number.' · a.n. '.$b->account_holder)?></small></td><td><?=html_escape($b->currency)?></td><td><span class="badge <?=$b->is_active?'text-bg-success':'text-bg-secondary'?>"><?=$b->is_active?'Aktif':'Nonaktif'?></span><?=$b->is_primary?'<span class="badge text-bg-primary ms-1">Utama</span>':''?></td><td><div class="d-flex gap-1"><button class="btn btn-sm btn-outline-primary edit-bank" type="button" data-row='<?=html_escape(json_encode($b,JSON_HEX_APOS|JSON_HEX_QUOT))?>'>Edit</button><form method="post" action="<?=base_url('companies/toggle_bank/'.$b->id)?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><button class="btn btn-sm btn-outline-secondary"><?=$b->is_active?'Nonaktifkan':'Aktifkan'?></button></form></div></td></tr><?php endforeach?><?php if(!$bank_accounts):?><tr><td colspan="4" class="text-center text-muted py-4">Belum ada rekening perusahaan.</td></tr><?php endif?></tbody></table></div></div></div></div>
<div class="tab-pane fade" id="companyCurrencies"><div class="settings-split"><div class="settings-card"><div class="settings-card-head"><div><h5>Master Mata Uang</h5><p>Atur kode, simbol, desimal, dan status mata uang.</p></div></div><form id="currencyForm" method="post" action="<?=base_url('companies/save_currency')?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><div class="row g-3"><div class="col-4"><label class="form-label">Kode</label><input class="form-control text-uppercase" name="code" maxlength="3" required></div><div class="col-8"><label class="form-label">Nama</label><input class="form-control" name="name" required></div><div class="col-6"><label class="form-label">Simbol</label><input class="form-control" name="symbol"></div><div class="col-6"><label class="form-label">Jumlah Desimal</label><input class="form-control" type="number" min="0" max="6" name="decimal_places" value="2"></div><div class="col-12"><label class="form-check"><input class="form-check-input" type="checkbox" name="is_active" value="1" checked><span class="form-check-label">Mata uang aktif</span></label></div></div><div class="d-flex gap-2 mt-3"><button class="btn btn-primary">Simpan Mata Uang</button><button class="btn btn-light d-none" id="cancelCurrencyEdit" type="button">Batal Edit</button></div></form><hr><div class="currency-list"><?php foreach($currencies as$c):?><button class="currency-row edit-currency" type="button" data-row='<?=html_escape(json_encode($c,JSON_HEX_APOS|JSON_HEX_QUOT))?>'><span><b><?=$c->code?></b> <?=html_escape($c->name)?></span><span><?=html_escape($c->symbol?:'-')?> · <?=$c->decimal_places?> desimal · <?=$c->is_active?'Aktif':'Nonaktif'?></span></button><?php endforeach?></div></div><div class="settings-card"><div class="settings-card-head"><div><h5>Kurs Harian</h5><p>Simpan kurs untuk transaksi multi-currency perusahaan aktif.</p></div></div><form method="post" action="<?=base_url('companies/rate')?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><div class="row g-3"><div class="col-md-5"><label class="form-label">Tanggal</label><input class="form-control" type="date" name="date" value="<?=date('Y-m-d')?>" required></div><div class="col-md-3"><label class="form-label">Dari</label><select class="form-select" name="from_currency"><?php foreach($active_currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-md-4"><label class="form-label">Ke</label><select class="form-select" name="to_currency"><?php foreach($active_currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-md-6"><label class="form-label">Nilai Kurs</label><input class="form-control" type="number" min="0" step=".00000001" name="rate" required></div><div class="col-md-6"><label class="form-label">Sumber</label><input class="form-control" name="source"></div></div><button class="btn btn-success mt-3">Simpan Kurs</button></form><div class="table-responsive mt-4"><table class="table table-sm"><thead><tr><th>Tanggal</th><th>Mata Uang</th><th>Kurs</th><th>Sumber</th></tr></thead><tbody><?php foreach($rates as$r):?><tr><td><?=$r->rate_date?></td><td><?=$r->from_currency?> / <?=$r->to_currency?></td><td><?=number_format($r->rate,8,',','.')?></td><td><?=html_escape($r->source?:'-')?></td></tr><?php endforeach?></tbody></table></div></div></div></div>
<div class="tab-pane fade" id="companyList"><div class="settings-split"><div class="settings-card"><div class="settings-card-head"><div><h5>Perusahaan yang Dapat Diakses</h5><p>Pilih untuk mengganti konteks data aktif.</p></div></div><div class="company-switch-list"><?php foreach($companies as$c):?><a class="company-switch <?=$c->id==$active_company->id?'active':''?>" href="<?=base_url('companies/switch_company/'.$c->id)?>"><span><b><?=html_escape($c->name)?></b><small><?=html_escape($c->company_code.' · '.$c->base_currency)?></small></span><i class="bi bi-chevron-right"></i></a><?php endforeach?></div></div><div class="settings-card"><div class="settings-card-head"><div><h5>Tambah Perusahaan</h5><p>Membuat tenant perusahaan baru tanpa mengubah perusahaan aktif.</p></div></div><form method="post" action="<?=base_url('companies/save')?>"><input type="hidden" name="<?=$csrfName?>" value="<?=$csrfHash?>"><div class="row g-3"><div class="col-4"><label class="form-label">Kode</label><input class="form-control" name="code" required></div><div class="col-8"><label class="form-label">Nama</label><input class="form-control" name="name" required></div><div class="col-8"><label class="form-label">Nama Legal</label><input class="form-control" name="legal_name"></div><div class="col-4"><label class="form-label">Mata Uang</label><select class="form-select" name="base_currency"><?php foreach($active_currencies as$c):?><option><?=$c->code?></option><?php endforeach?></select></div><div class="col-6"><label class="form-label">Telepon</label><input class="form-control" name="phone"></div><div class="col-6"><label class="form-label">Email</label><input class="form-control" type="email" name="email"></div><div class="col-12"><label class="form-label">NPWP</label><input class="form-control" name="tax_number"></div><div class="col-12"><label class="form-label">Alamat</label><textarea class="form-control" name="address" rows="2"></textarea></div></div><button class="btn btn-primary mt-3">Tambah Perusahaan</button></form></div></div></div>
</div>
</section>
<script>
(function($){
function resetBank(){var f=document.getElementById('bankAccountForm');f.reset();f.elements.id.value='';$('#cancelBankEdit').addClass('d-none');}
$('.edit-bank').on('click',function(){var r=$(this).data('row'),f=document.getElementById('bankAccountForm');f.elements.id.value=r.id;f.elements.bank_name.value=r.bank_name;f.elements.account_number.value=r.account_number;f.elements.account_holder.value=r.account_holder;f.elements.currency.value=r.currency;f.elements.is_primary.checked=Number(r.is_primary)===1;$('#cancelBankEdit').removeClass('d-none');f.scrollIntoView({behavior:'smooth',block:'center'});});$('#cancelBankEdit').on('click',resetBank);
function resetCurrency(){var f=document.getElementById('currencyForm');f.reset();f.elements.code.readOnly=false;$('#cancelCurrencyEdit').addClass('d-none');}
$('.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>
+1 -1
View File
@@ -14,7 +14,7 @@ function invLabel($value){$labels=array('draft'=>'Draft','submitted'=>'Menunggu
<section class="invoice-workspace invoice-editor-page p-0">
<header class="invoice-hero">
<div><span><?=$creating?'INVOICE BARU':'KELOLA INVOICE'?></span><h5><?=$creating?'Buat Invoice':html_escape($invoice->no_invoice)?></h5><p><?=$creating?'Tentukan customer dan aturan penagihan. Item dapat ditambahkan setelah Draft tersimpan.':'Item dapat ditambahkan bertahap dan langsung tersimpan pada Draft invoice.'?></p></div>
<div class="hero-actions"><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-arrow-left"></i> Daftar Invoice</a><?php if($invoice&&$p['export']):?><button class="btn btn-outline-danger open-invoice-pdf" data-url="<?=base_url('invoices/pdf/'.$invoice->id)?>"><i class="bi bi-file-pdf"></i> PDF</button><?php endif?></div>
<div class="hero-actions"><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-arrow-left"></i> Daftar Invoice</a><?php if($invoice&&$p['export']):?><button class="btn btn-outline-danger open-invoice-pdf" data-id="<?=$invoice->id?>" data-url="<?=base_url('invoices/pdf/'.$invoice->id)?>"><i class="bi bi-file-pdf"></i> PDF</button><?php endif?></div>
</header>
<?php if($invoice):?><div class="invoice-progress"><span class="done"><i class="bi bi-check-lg"></i> Header Draft</span><span class="<?=$invoice->delivery_status==='delivered'?'done':''?>"><i class="bi bi-truck"></i> <?=$invoice->inventory_line_count?'Pengiriman':'Tanpa Surat Jalan'?></span><span class="<?=in_array($invoice->workflow_status,array('submitted','approved','posted'),true)?'done':''?>"><i class="bi bi-send"></i> Diajukan</span><span class="<?=$invoice->workflow_status==='posted'?'done':''?>"><i class="bi bi-patch-check"></i> Approved & Posted</span></div><?php endif?>
+51 -14
View File
@@ -1,23 +1,60 @@
<?php
$company=$pdf_company;$groups=array();
$company=$pdf_company;
$previous_invoices=isset($previous_invoices)?$previous_invoices:array();
$pdf_bank_accounts=isset($pdf_bank_accounts)?$pdf_bank_accounts:array();
$currencyCode=isset($pdf_currency->code)?$pdf_currency->code:($company->base_currency??'IDR');
$currencySymbol=isset($pdf_currency->symbol)&&trim((string)$pdf_currency->symbol)!==''?$pdf_currency->symbol:$currencyCode;
$groups=array();
$barcodesByLine=array();
foreach($barcodes as$b)$barcodesByLine[(int)$b->invoice_detail_id][]=$b;
foreach($lines as$l){
$detail=trim((string)($l->keterangan?:$l->specification));
$key=$l->service_date.'|'.$l->items_id.'|'.$l->harga.'|'.$l->tax_rate.'|'.$detail;
$label=trim(($l->item_code?$l->item_code.' - ':'').$l->nama_item);
if(!isset($groups[$key]))$groups[$key]=array('date'=>$l->service_date,'item'=>$label,'detail'=>$detail,'qty'=>0,'unit'=>$l->unit,'price'=>$l->harga,'discount'=>0,'tax'=>0,'total'=>0);
$groups[$key]['qty']+=(float)$l->qty;$groups[$key]['discount']+=(float)$l->discount_amount;$groups[$key]['tax']+=(float)$l->tax_amount;$groups[$key]['total']+=(float)$l->subtotal;
$code=trim((string)($l->item_code??''));
$name=trim((string)$l->nama_item);
$key=$l->service_date.'|'.$l->line_type.'|'.$code.'|'.$name.'|'.$l->unit;
$label=trim(($code!==''?$code.' - ':'').$name);
if(!isset($groups[$key]))$groups[$key]=array('date'=>$l->service_date,'item'=>$label,'qty'=>0,'unit'=>$l->unit,'gross'=>0,'discount'=>0,'tax'=>0,'total'=>0);
$groups[$key]['qty']+=(float)$l->qty;
$groups[$key]['gross']+=(float)$l->harga*(float)$l->qty;
$groups[$key]['discount']+=(float)$l->discount_amount;
$groups[$key]['tax']+=(float)$l->tax_amount;
$groups[$key]['total']+=(float)$l->subtotal;
}
function ipMoney($v){return number_format((float)$v,2,',','.');}
function ipQty($v){return floor($v)==$v?number_format($v,0,',','.'):number_format($v,4,',','.');}
function ipQty($v){return floor((float)$v)==(float)$v?number_format((float)$v,0,',','.'):rtrim(rtrim(number_format((float)$v,4,',','.'),'0'),',');}
$statusKey=$invoice->workflow_status==='posted'?$invoice->status:$invoice->workflow_status;
$statusLabels=array('draft'=>'DRAFT','submitted'=>'MENUNGGU PERSETUJUAN','approved'=>'DISETUJUI','posted'=>'POSTED','unpaid'=>'BELUM LUNAS','partial'=>'DIBAYAR SEBAGIAN','paid'=>'LUNAS','cancelled'=>'DIBATALKAN','reversed'=>'DIBALIK');
$statusLabel=$statusLabels[$statusKey]??strtoupper(str_replace('_',' ',$statusKey));
$previousTotal=0;foreach($previous_invoices as$old)$previousTotal+=(float)$old->sisa_piutang;$customerOutstanding=$previousTotal+(float)$invoice->sisa_piutang;
?>
<!doctype html><html><head><meta charset="utf-8"><style>
@page{margin:28px 34px}body{font-family:DejaVu Sans,sans-serif;font-size:10px;color:#20242c}h1{font-size:20px;margin:0}.muted{color:#667085}.head{width:100%;margin-bottom:18px}.head td{vertical-align:top}.right{text-align:right}table.grid{width:100%;border-collapse:collapse}table.grid th{background:#eef2f6;text-align:left;font-size:8px;letter-spacing:.04em}table.grid th,table.grid td{border:1px solid #d8dee8;padding:7px}.num{text-align:right}.summary{margin:14px 0 0 auto;width:44%}.summary td{padding:4px}.page{page-break-before:always}.sign{margin-top:40px;width:100%;text-align:center}.sign td{width:33%;height:80px;vertical-align:top}.repeat{display:table-header-group}
<!doctype html>
<html><head><meta charset="utf-8"><style>
@page{margin:27px 32px}body{font-family:DejaVu Sans,sans-serif;font-size:9.5px;color:#20242c;line-height:1.42}h1{font-size:21px;margin:0}h2{font-size:15px;margin:0 0 4px}.muted{color:#667085}.head{width:100%;margin-bottom:16px}.head td{vertical-align:top}.brand{width:64%}.logo{float:left;width:62px;height:62px;object-fit:contain;margin-right:11px}.company-name{font-size:15px;font-weight:bold;margin:0 0 3px}.right{text-align:right}.invoice-number{font-size:11px;margin:2px 0 6px}.status{display:inline-block;padding:4px 9px;border-radius:11px;font-size:8px;font-weight:bold;color:#fff;background:#475467}.status-paid{background:#15803d}.status-partial{background:#d97706}.status-unpaid,.status-submitted{background:#dc2626}.status-draft{background:#64748b}.status-approved,.status-posted{background:#2563eb}.status-cancelled,.status-reversed{background:#475467}.info{width:100%;margin:8px 0 14px;border-collapse:collapse}.info td{width:50%;vertical-align:top;padding:10px;border:1px solid #d8dee8}.info-label{font-size:8px;color:#667085;text-transform:uppercase;letter-spacing:.06em;margin-bottom:3px}table.grid{width:100%;border-collapse:collapse}table.grid th{background:#eef2f6;text-align:left;font-size:7.5px;letter-spacing:.04em}table.grid th,table.grid td{border:1px solid #d8dee8;padding:6px}.num{text-align:right}.summary{margin:12px 0 0 auto;width:46%;border-collapse:collapse}.summary td{padding:3px 5px}.summary .grand td{padding-top:6px;border-top:1px solid #98a2b3;font-size:11px}.section-title{font-size:11px;font-weight:bold;margin-bottom:6px}.outstanding{margin-top:16px;padding-top:10px;border-top:1px solid #d8dee8}.outstanding-total{text-align:right;font-weight:bold;margin-top:6px}.bank-box{margin-top:14px;padding:9px 11px;border:1px solid #d8dee8;background:#f8fafc}.bank-row{margin-top:3px}.page{page-break-before:always}.sign{margin-top:35px;width:100%;text-align:center}.sign td{width:33%;height:78px;vertical-align:top}.repeat{display:table-header-group}.detail-note{max-width:175px}.empty{text-align:center;color:#667085;padding:15px!important}
</style></head><body>
<table class="head"><tr><td><h1><?=html_escape($company->name??'Perusahaan')?></h1><div class="muted"><?=html_escape($company->address??'')?></div></td><td class="right"><h1>INVOICE</h1><b><?=html_escape($invoice->no_invoice)?></b><br><?=html_escape($invoice->tanggal)?></td></tr></table>
<table width="100%"><tr><td><b>Kepada</b><br><?=html_escape($invoice->customer_name)?><br><?=nl2br(html_escape($invoice->customer_address?:'-'))?></td><td class="right"><b>Periode</b><br><?=html_escape(($invoice->period_start?:$invoice->tanggal).' s.d. '.($invoice->period_end?:$invoice->tanggal))?><br><b>Jatuh tempo:</b> <?=html_escape($invoice->jatuh_tempo)?><br><b>Pengakuan:</b> <?=$invoice->recognition_policy==='accrual'?'Akrual':'Setelah pembayaran'?></td></tr></table><br>
<table class="grid"><thead><tr><th>TANGGAL</th><th>BARANG / JASA & KETERANGAN</th><th>QTY</th><th class="num">HARGA</th><th class="num">DISKON</th><th class="num">PAJAK</th><th class="num">SUBTOTAL</th></tr></thead><tbody><?php foreach($groups as$g):?><tr><td><?=html_escape($g['date'])?></td><td><b><?=html_escape($g['item'])?></b><br><span class="muted"><?=html_escape($g['detail']?:'-')?></span></td><td><?=ipQty($g['qty']).' '.html_escape($g['unit'])?></td><td class="num"><?=ipMoney($g['price'])?></td><td class="num"><?=ipMoney($g['discount'])?></td><td class="num"><?=ipMoney($g['tax'])?></td><td class="num"><b><?=ipMoney($g['total'])?></b></td></tr><?php endforeach?></tbody></table>
<table class="summary"><tr><td>Subtotal bersih</td><td class="num"><?=ipMoney($invoice->subtotal_before_tax)?></td></tr><tr><td>Diskon</td><td class="num"><?=ipMoney($invoice->discount_total)?></td></tr><tr><td>Pajak</td><td class="num"><?=ipMoney($invoice->tax_total)?></td></tr><tr><td><b>Total</b></td><td class="num"><b>Rp <?=ipMoney($invoice->total)?></b></td></tr><tr><td>Sudah dibayar</td><td class="num"><?=ipMoney($invoice->total_bayar)?></td></tr><tr><td><b>Sisa piutang</b></td><td class="num"><b><?=ipMoney($invoice->sisa_piutang)?></b></td></tr></table>
<table class="head"><tr><td class="brand">
<?php if(!empty($pdf_logo_data)):?><img class="logo" src="<?=$pdf_logo_data?>"><?php endif?>
<div class="company-name"><?=html_escape($company->name??'Perusahaan')?></div>
<div><?=nl2br(html_escape($company->address??'-'))?></div>
<div>Telp: <?=html_escape($company->phone??'-')?></div>
</td><td class="right"><h1>INVOICE</h1><div class="invoice-number"><b><?=html_escape($invoice->no_invoice)?></b><br><?=html_escape($invoice->tanggal)?></div><span class="status status-<?=html_escape($statusKey)?>"><?=html_escape($statusLabel)?></span></td></tr></table>
<table class="info"><tr><td><div class="info-label">Ditagihkan kepada</div><b><?=html_escape($invoice->customer_name)?></b><br><?=nl2br(html_escape($invoice->customer_address?:'-'))?></td><td><div class="info-label">Informasi Invoice</div><b>Tanggal Invoice:</b> <?=html_escape($invoice->tanggal)?><br><b>Tanggal Jatuh Tempo:</b> <?=html_escape($invoice->jatuh_tempo)?><br><b>Mata Uang:</b> <?=html_escape($currencyCode)?></td></tr></table>
<table class="grid"><thead><tr><th>TANGGAL</th><th>BARANG / JASA / TABUNGAN</th><th>QTY</th><th class="num">HARGA</th><th class="num">DISKON</th><th class="num">PAJAK</th><th class="num">SUBTOTAL</th></tr></thead><tbody>
<?php foreach($groups as$g):$average=$g['qty']!=0?$g['gross']/$g['qty']:0;?><tr><td><?=html_escape($g['date'])?></td><td><b><?=html_escape($g['item'])?></b></td><td><?=ipQty($g['qty']).' '.html_escape($g['unit'])?></td><td class="num"><?=ipMoney($average)?></td><td class="num"><?=ipMoney($g['discount'])?></td><td class="num"><?=ipMoney($g['tax'])?></td><td class="num"><b><?=ipMoney($g['total'])?></b></td></tr><?php endforeach?>
<?php if(!$groups):?><tr><td colspan="7" class="empty">Belum ada item pada invoice ini.</td></tr><?php endif?>
</tbody></table>
<table class="summary"><tr><td>Subtotal bersih</td><td class="num"><?=ipMoney($invoice->subtotal_before_tax)?></td></tr><tr><td>Diskon</td><td class="num"><?=ipMoney($invoice->discount_total)?></td></tr><tr><td>Pajak</td><td class="num"><?=ipMoney($invoice->tax_total)?></td></tr><tr class="grand"><td><b>Total Invoice</b></td><td class="num"><b><?=html_escape($currencySymbol)?> <?=ipMoney($invoice->total)?></b></td></tr><tr><td>Sudah dibayar</td><td class="num"><?=ipMoney($invoice->total_bayar)?></td></tr><tr><td><b>Sisa tagihan</b></td><td class="num"><b><?=ipMoney($invoice->sisa_piutang)?></b></td></tr></table>
<?php if($previous_invoices):?><div class="outstanding"><div class="section-title">Daftar Tagihan Sebelumnya yang Belum Lunas</div><table class="grid"><thead><tr><th>INVOICE</th><th>TANGGAL</th><th>JATUH TEMPO</th><th class="num">TOTAL</th><th class="num">TERBAYAR</th><th class="num">SISA TAGIHAN</th></tr></thead><tbody><?php foreach($previous_invoices as$old):?><tr><td><b><?=html_escape($old->no_invoice)?></b></td><td><?=html_escape($old->tanggal)?></td><td><?=html_escape($old->jatuh_tempo)?></td><td class="num"><?=ipMoney($old->total)?></td><td class="num"><?=ipMoney($old->total_bayar)?></td><td class="num"><b><?=ipMoney($old->sisa_piutang)?></b></td></tr><?php endforeach?></tbody></table><div class="outstanding-total">Total sisa tagihan <?=html_escape($invoice->customer_name)?>, termasuk invoice ini: <?=html_escape($currencySymbol)?> <?=ipMoney($customerOutstanding)?></div></div><?php endif?>
<?php if($pdf_bank_accounts):?><div class="bank-box"><b>Rekening Pembayaran Perusahaan</b><?php foreach($pdf_bank_accounts as$bank):?><div class="bank-row"><?=html_escape($bank->bank_name)?> · <?=html_escape($bank->account_number)?> · a.n. <?=html_escape($bank->account_holder)?> (<?=html_escape($bank->currency)?>)<?=$bank->is_primary?' · Utama':''?></div><?php endforeach?></div><?php endif?>
<p><b>Surat Jalan:</b> <?=html_escape(implode(', ',array_map(function($d){return$d->delivery_no;},$deliveries))?:'-')?><br><b>Catatan:</b> <?=html_escape($invoice->keterangan?:'-')?></p>
<table class="sign"><tr><td>Dibuat oleh<br><br><br><b><?=html_escape($invoice->creator_name?:'-')?></b></td><td>Disetujui<br><br><br><b><?=html_escape($invoice->approver_name?:'-')?></b></td><td>Diterima Customer</td></tr></table>
<div class="page"><h2>Lampiran Detail Barcode / Serial Number</h2><p class="muted">Lampiran invoice <?=html_escape($invoice->no_invoice)?> · <?=count($barcodes)?> baris barcode</p><table class="grid"><thead class="repeat"><tr><th>TANGGAL</th><th>SURAT JALAN</th><th>BARANG</th><th>BARCODE / SERIAL</th><th>QTY</th><th>GUDANG</th><th>STATUS</th></tr></thead><tbody><?php foreach($barcodes as$b):?><tr><td><?=html_escape($b->service_date)?></td><td><?=html_escape($b->delivery_no?:'-')?></td><td><?=html_escape(trim(($b->item_code?$b->item_code.' - ':'').$b->nama_barang))?></td><td><b><?=html_escape($b->barcode)?></b><br><?=html_escape($b->serial_number?:'-')?></td><td><?=ipQty($b->qty)?></td><td><?=html_escape($b->warehouse_name?:'-')?></td><td><?=in_array($invoice->workflow_status,array('posted','approved'),true)?'Terkirim':'Dialokasikan'?></td></tr><?php endforeach?><?php if(!$barcodes):?><tr><td colspan="7" style="text-align:center">Invoice ini tidak berisi barang gudang sehingga tidak memiliki detail barcode atau Surat Jalan.</td></tr><?php endif?></tbody></table></div>
<div class="page"><h2>Lampiran Detail</h2><p class="muted">Rincian seluruh item Invoice <?=html_escape($invoice->no_invoice)?>.</p><table class="grid"><thead class="repeat"><tr><th>TANGGAL</th><th>SURAT JALAN</th><th>BARANG / JASA / TABUNGAN</th><th>BARCODE / SERIAL</th><th>QTY</th><th>KETERANGAN</th></tr></thead><tbody>
<?php foreach($lines as$l):$lineBars=$barcodesByLine[(int)$l->id]??array();$label=trim((!empty($l->item_code)?$l->item_code.' - ':'').$l->nama_item);$note=trim((string)($l->keterangan?:$l->specification));if($lineBars):foreach($lineBars as$b):?><tr><td><?=html_escape($l->service_date)?></td><td><?=html_escape($b->delivery_no?:'-')?></td><td><b><?=html_escape($label)?></b></td><td><b><?=html_escape($b->barcode)?></b><br><?=html_escape($b->serial_number?:'-')?></td><td><?=ipQty($b->qty).' '.html_escape($l->unit)?></td><td class="detail-note"><?=nl2br(html_escape($note?:'-'))?></td></tr><?php endforeach;else:?><tr><td><?=html_escape($l->service_date)?></td><td>-</td><td><b><?=html_escape($label)?></b></td><td>-</td><td><?=ipQty($l->qty).' '.html_escape($l->unit)?></td><td class="detail-note"><?=nl2br(html_escape($note?:'-'))?></td></tr><?php endif;endforeach?>
<?php if(!$lines):?><tr><td colspan="6" class="empty">Belum ada detail item pada invoice ini.</td></tr><?php endif?>
</tbody></table></div>
</body></html>