Sidebar: +ERP +CRM +Dokumenti, godišnjaci import (18 PDFs), filter helpers

- pgz nav now includes /erp/full, /crm/v2, /admin/users, /dokumenti
- 4 dokumenti endpoints: list, godišnjaci/list, godišnjak/{godina} PDF, detail
- 18 godišnjaka u pgz_sport.dokumenti (2006-2024) with savez_id=333
- PGŽ filter helpers (window._pgz_filter_priority, togglePGZFilter)
- navItemClick handler for nav items with href
This commit is contained in:
2026-05-05 13:08:11 +02:00
parent 9fb512932a
commit 1d02c0897d
970 changed files with 268354 additions and 434 deletions
+943
View File
@@ -0,0 +1,943 @@
<!DOCTYPE html>
<!--
erp_full.html — FULL ERP (SAP-Lite) za PGŽ Sport
Author: Damir Radulić <dradulic@outlook.com> / damir@rinet.one
Version: 1.0.0
Date: 2026-05-05
Description: Sub-tabs Dnevnik | Glavna knjiga | Partneri | Računi | PDV | Plaće | Proračun | Izvještaji
-->
<html lang="hr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>PGŽ SPORT — ERP (SAP-Lite)</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
<style>
:root{
--pgz-blue:#003087; --pgz-blue2:#004CC4; --pgz-gold:#F4C430;
--bg0:#08090e; --bg1:#0d1021; --bg2:#111628; --bg3:#161d35; --bg4:#1c2542;
--rim:#1e2a50; --rim2:#283560;
--t0:#fff; --t1:#e2e6f0; --t2:#8a95b4; --t4:#4e5a7a;
--green:#00e88f; --red:#ff2d55; --amber:#f59e0b; --cyan:#00c8e8;
--font:'Inter',sans-serif; --mono:'JetBrains Mono',monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{font-family:var(--font);background:var(--bg0);color:var(--t1);font-size:13px;overflow-x:hidden}
button,input,select,textarea{font-family:inherit;font-size:inherit;outline:none}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:var(--bg1)}
::-webkit-scrollbar-thumb{background:var(--rim2);border-radius:4px}
.main{padding:0 0 0 0;flex:1;min-width:0}
.tb{background:var(--bg1);border-bottom:1px solid var(--rim);padding:12px 22px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:5}
.tb-t{font-size:15px;font-weight:700;color:var(--t0)}
.tb-s{font-size:11px;color:var(--t2)}
.content{padding:18px 22px}
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--rim);margin-bottom:14px;flex-wrap:wrap}
.tab{padding:9px 16px;cursor:pointer;color:var(--t2);font-weight:600;font-size:12px;border-bottom:2px solid transparent;transition:all .15s;background:none;border-left:0;border-right:0;border-top:0}
.tab:hover{color:var(--t1)}
.tab.active{color:var(--pgz-gold);border-bottom-color:var(--pgz-gold)}
.panel{display:none}
.panel.active{display:block}
.card{background:var(--bg2);border:1px solid var(--rim);border-radius:8px;padding:14px;margin-bottom:14px}
.card-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--rim)}
.card-t{font-weight:700;color:var(--t0);font-size:13px}
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}
.toolbar input,.toolbar select{background:var(--bg2);border:1px solid var(--rim);border-radius:5px;padding:7px 10px;color:var(--t1);font-size:12px}
.toolbar input:focus,.toolbar select:focus{border-color:var(--pgz-blue2)}
.toolbar label{font-size:11px;color:var(--t2);display:flex;align-items:center;gap:6px}
.btn{background:var(--pgz-blue2);border:0;color:#fff;padding:7px 14px;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;transition:background .15s}
.btn:hover{background:var(--pgz-blue)}
.btn.gold{background:var(--pgz-gold);color:var(--bg0)}
.btn.gold:hover{background:#e0b220}
.btn.green{background:var(--green);color:var(--bg0)}
.btn.red{background:var(--red);color:#fff}
.btn.sec{background:var(--bg3);color:var(--t1);border:1px solid var(--rim)}
table{width:100%;border-collapse:collapse;font-size:12px}
table th{background:var(--bg3);color:var(--t2);text-transform:uppercase;font-size:10px;letter-spacing:.5px;padding:8px 10px;text-align:left;border-bottom:1px solid var(--rim);font-weight:700}
table td{padding:7px 10px;border-bottom:1px solid var(--rim);color:var(--t1)}
table tbody tr{cursor:pointer;transition:background .15s}
table tbody tr:hover{background:var(--bg3)}
.num{font-family:var(--mono);text-align:right}
.tbl-wrap{overflow-x:auto;max-height:600px;overflow-y:auto;border:1px solid var(--rim);border-radius:6px}
.modal-bg{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:100;align-items:flex-start;justify-content:center;padding-top:40px}
.modal-bg.show{display:flex}
.modal{background:var(--bg1);border:1px solid var(--rim);border-radius:8px;padding:18px;width:min(720px,94vw);max-height:90vh;overflow-y:auto}
.modal h3{font-size:14px;font-weight:700;color:var(--pgz-gold);margin-bottom:14px;padding-bottom:8px;border-bottom:1px solid var(--rim)}
.form-row{display:grid;grid-template-columns:140px 1fr;gap:8px;margin-bottom:8px;align-items:center}
.form-row label{font-size:11px;color:var(--t2)}
.form-row input,.form-row select,.form-row textarea{width:100%;background:var(--bg2);border:1px solid var(--rim);border-radius:4px;padding:6px 9px;color:var(--t1);font-size:12px}
.form-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:14px;padding-top:10px;border-top:1px solid var(--rim)}
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:14px}
.kpi{background:linear-gradient(135deg,var(--bg2) 0%,var(--bg1) 100%);border:1px solid var(--rim);border-radius:8px;padding:12px 14px;position:relative}
.kpi::before{content:"";position:absolute;top:0;left:0;width:3px;height:100%;background:var(--pgz-gold)}
.kpi.g::before{background:var(--green)}
.kpi.r::before{background:var(--red)}
.kpi-l{font-size:10.5px;color:var(--t2);text-transform:uppercase;letter-spacing:1px;font-weight:600}
.kpi-v{font-size:22px;font-weight:800;color:var(--t0);margin-top:4px;font-family:var(--mono)}
.badge{display:inline-block;padding:2px 7px;border-radius:3px;font-size:10px;font-weight:600;text-transform:uppercase}
.badge.nacrt{background:var(--bg4);color:var(--t1)}
.badge.knjizen{background:var(--green);color:var(--bg0)}
.badge.placen{background:var(--pgz-gold);color:var(--bg0)}
.badge.otkazan{background:var(--red);color:#fff}
.dnev-line-row{display:grid;grid-template-columns:140px 1fr 100px 100px 1fr 30px;gap:6px;margin-bottom:6px;align-items:center}
.dnev-line-row input,.dnev-line-row select{background:var(--bg2);border:1px solid var(--rim);border-radius:4px;padding:5px 8px;color:var(--t1);font-size:12px;width:100%}
.dnev-balans{padding:8px;background:var(--bg3);border-radius:4px;margin-top:8px;font-family:var(--mono);font-size:11px}
.dnev-balans.ok{color:var(--green)}
.dnev-balans.bad{color:var(--red)}
</style>
<link rel="stylesheet" href="/static/shared/sidebar.css">
<script src="/static/shared/sidebar.js" defer data-active="erp_full"></script>
</head>
<body>
<main class="main">
<div class="tb">
<div>
<div class="tb-t">ERP — SAP-Lite</div>
<div class="tb-s">Dvostavno knjigovodstvo · HR-RRIF kontni plan · FINA e-Račun</div>
</div>
<div class="tb-s"><span style="color:var(--green)"></span> /api/v2/erp/*</div>
</div>
<div class="content">
<div class="tabs">
<button class="tab active" data-panel="dnevnik">📓 Dnevnik</button>
<button class="tab" data-panel="glavna">📊 Glavna knjiga</button>
<button class="tab" data-panel="partneri">🤝 Partneri</button>
<button class="tab" data-panel="racuni">🧾 Računi</button>
<button class="tab" data-panel="pdv">% PDV</button>
<button class="tab" data-panel="place">💼 Plaće</button>
<button class="tab" data-panel="proracun">€ Proračun</button>
<button class="tab" data-panel="izvjestaji">📈 Izvještaji</button>
<button class="tab" data-panel="kontni">📚 Kontni plan</button>
</div>
<!-- ============ DNEVNIK ============ -->
<section class="panel active" id="panel-dnevnik">
<div class="card">
<div class="card-h">
<div class="card-t">Dnevnik knjiženja</div>
<button class="btn gold" onclick="openDnevnikModal()">+ Novi zapis</button>
</div>
<div class="toolbar">
<label>Godina <input type="number" id="dnev-godina" value="2026" style="width:90px"></label>
<label>Tip <select id="dnev-tip"><option value="">— svi —</option><option value="rucno">Ručno</option><option value="racun_u">Račun ulazni</option><option value="racun_i">Račun izlazni</option><option value="placa">Plaća</option><option value="storno">Storno</option></select></label>
<button class="btn" onclick="loadDnevnik()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="dnev-tbl"><thead><tr><th>#</th><th>Datum</th><th>Opis</th><th>Tip</th><th class="num">Stavki</th><th class="num">Ukupno</th><th>Akcije</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ GLAVNA KNJIGA ============ -->
<section class="panel" id="panel-glavna">
<div class="card">
<div class="card-h">
<div class="card-t">Glavna knjiga (saldo po kontu)</div>
<button class="btn sec" onclick="exportXlsx('glavna-knjiga', 2026)">⬇ XLSX</button>
</div>
<div class="toolbar">
<label>Klasa <select id="gk-klasa"><option value="">— sve —</option><option>0</option><option>1</option><option>2</option><option>3</option><option>4</option><option>7</option><option>9</option></select></label>
<button class="btn" onclick="loadGlavnaKnjiga()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="gk-tbl"><thead><tr><th>Šifra</th><th>Naziv</th><th>Klasa</th><th>Vrsta</th><th class="num">Duguje</th><th class="num">Potražuje</th><th class="num">Saldo</th><th class="num">Stavki</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ PARTNERI ============ -->
<section class="panel" id="panel-partneri">
<div class="card">
<div class="card-h">
<div class="card-t">Partneri (kupci/dobavljači)</div>
<button class="btn gold" onclick="openPartnerModal()">+ Novi partner</button>
</div>
<div class="toolbar">
<input id="part-q" placeholder="Pretraži (naziv/OIB)…">
<label>Vrsta <select id="part-vrsta"><option value="">— sve —</option><option value="kupac">Kupac</option><option value="dobavljac">Dobavljač</option><option value="oba">Oba</option></select></label>
<button class="btn" onclick="loadPartneri()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="part-tbl"><thead><tr><th>#</th><th>OIB</th><th>Naziv</th><th>Vrsta</th><th>Grad</th><th>IBAN</th><th class="num">Saldo</th><th>Akcije</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ RAČUNI ============ -->
<section class="panel" id="panel-racuni">
<div class="card">
<div class="card-h">
<div class="card-t">Računi</div>
<div style="display:flex;gap:6px">
<button class="btn gold" onclick="openRacunModal('ulazni')">+ Ulazni</button>
<button class="btn green" onclick="openRacunModal('izlazni')">+ Izlazni</button>
<label class="btn sec" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
📥 Import e-Račun XML
<input type="file" id="eracun-file" accept=".xml,application/xml" style="display:none" onchange="importERacun()">
</label>
</div>
</div>
<div class="toolbar">
<label>Tip <select id="rac-tip"><option value="ulazni">Ulazni</option><option value="izlazni">Izlazni</option></select></label>
<label>Status <select id="rac-status"><option value="">— svi —</option><option value="nacrt">Nacrt</option><option value="knjizen">Knjižen</option><option value="placen">Plaćen</option><option value="otkazan">Otkazan</option></select></label>
<label>Godina <input type="number" id="rac-godina" value="2026" style="width:90px"></label>
<button class="btn" onclick="loadRacuni()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="rac-tbl"><thead><tr><th>#</th><th>Broj</th><th>Datum</th><th>Partner</th><th>OIB</th><th class="num">Neto</th><th class="num">PDV</th><th class="num">Brutto</th><th>Status</th><th>Akcije</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ PDV ============ -->
<section class="panel" id="panel-pdv">
<div class="card">
<div class="card-h">
<div class="card-t">PDV — Knjige + Obrazac</div>
<div style="display:flex;gap:6px">
<button class="btn sec" onclick="exportXlsx('pdv-u', document.getElementById('pdv-godina').value, document.getElementById('pdv-mjesec').value)">⬇ U XLSX</button>
<button class="btn sec" onclick="exportXlsx('pdv-i', document.getElementById('pdv-godina').value, document.getElementById('pdv-mjesec').value)">⬇ I XLSX</button>
</div>
</div>
<div class="toolbar">
<label>Godina <input type="number" id="pdv-godina" value="2026" style="width:90px"></label>
<label>Mjesec <input type="number" id="pdv-mjesec" min="1" max="12" placeholder="1-12" style="width:80px"></label>
<button class="btn" onclick="loadPdv()">Osvježi</button>
</div>
<div id="pdv-summary" class="kpi-grid"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<div>
<h4 style="font-size:12px;color:var(--t2);margin-bottom:8px">KNJIGA U-RA (ulazni)</h4>
<div class="tbl-wrap"><table id="pdv-u-tbl"><thead><tr><th>Broj</th><th>Datum</th><th>Partner</th><th>OIB</th><th class="num">Neto</th><th class="num">PDV</th></tr></thead><tbody></tbody></table></div>
</div>
<div>
<h4 style="font-size:12px;color:var(--t2);margin-bottom:8px">KNJIGA I-RA (izlazni)</h4>
<div class="tbl-wrap"><table id="pdv-i-tbl"><thead><tr><th>Broj</th><th>Datum</th><th>Partner</th><th>OIB</th><th class="num">Neto</th><th class="num">PDV</th></tr></thead><tbody></tbody></table></div>
</div>
</div>
</div>
</section>
<!-- ============ PLAĆE ============ -->
<section class="panel" id="panel-place">
<div class="card">
<div class="card-h">
<div class="card-t">Zaposlenici i obračun plaća</div>
<div style="display:flex;gap:6px">
<button class="btn gold" onclick="openZapModal()">+ Zaposlenik</button>
<button class="btn green" onclick="openPlacaModal()">€ Obračun plaće</button>
</div>
</div>
<h4 style="font-size:12px;color:var(--t2);margin:8px 0">Zaposlenici</h4>
<div class="tbl-wrap" style="margin-bottom:14px">
<table id="zap-tbl"><thead><tr><th>#</th><th>OIB</th><th>Ime</th><th>Prezime</th><th>Klub</th><th>Mjesto</th><th class="num">Bruto</th><th>Aktivan</th></tr></thead><tbody></tbody></table>
</div>
<h4 style="font-size:12px;color:var(--t2);margin:8px 0">Obračuni plaća</h4>
<div class="toolbar">
<label>Godina <input type="number" id="pl-godina" value="2026" style="width:90px"></label>
<label>Mjesec <input type="number" id="pl-mjesec" placeholder="1-12" style="width:80px"></label>
<button class="btn" onclick="loadPlace()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="pl-tbl"><thead><tr><th>#</th><th>Zaposlenik</th><th>God/Mj</th><th class="num">Bruto</th><th class="num">Doprinosi iz</th><th class="num">Dohodnina</th><th class="num">Neto</th><th class="num">Doprinosi na</th><th class="num">Trošak</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ PRORAČUN ============ -->
<section class="panel" id="panel-proracun">
<div class="card">
<div class="card-h"><div class="card-t">Proračun PGŽ Sport (po godinama)</div></div>
<div class="tbl-wrap">
<table id="pr-tbl"><thead><tr><th>Godina</th><th class="num">Proračun PGŽ</th><th class="num">Rebalans 1</th><th class="num">Rebalans 2</th><th class="num">Ukupno PGŽ</th><th class="num">Ministarstvo</th><th class="num">Ukupno</th><th>Napomena</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
<!-- ============ IZVJEŠTAJI ============ -->
<section class="panel" id="panel-izvjestaji">
<div class="card">
<div class="card-h">
<div class="card-t">Izvještaji (Bilanca · PnL · Cashflow)</div>
</div>
<div class="toolbar">
<label>Tip <select id="iz-tip"><option value="bilanca">Bilanca</option><option value="pnl">PnL (Račun dobiti/gubitka)</option><option value="cashflow">Cashflow</option></select></label>
<label>Godina <input type="number" id="iz-godina" value="2026" style="width:90px"></label>
<button class="btn" onclick="loadIzvjestaj()">Generiraj</button>
<button class="btn sec" onclick="exportXlsx(document.getElementById('iz-tip').value, document.getElementById('iz-godina').value)">⬇ XLSX</button>
<button class="btn sec" onclick="exportPdf(document.getElementById('iz-tip').value, document.getElementById('iz-godina').value)">⬇ PDF</button>
</div>
<div id="iz-out"></div>
</div>
</section>
<!-- ============ KONTNI PLAN ============ -->
<section class="panel" id="panel-kontni">
<div class="card">
<div class="card-h">
<div class="card-t">Kontni plan (HR-RRIF)</div>
<button class="btn gold" onclick="openKontoModal()">+ Novi konto</button>
</div>
<div class="toolbar">
<input id="kp-q" placeholder="Šifra ili naziv…">
<label>Klasa <select id="kp-klasa"><option value="">— sve —</option><option>0</option><option>1</option><option>2</option><option>3</option><option>4</option><option>7</option><option>9</option></select></label>
<label>Vrsta <select id="kp-vrsta"><option value="">— sve —</option><option value="aktiva">Aktiva</option><option value="pasiva">Pasiva</option><option value="prihod">Prihod</option><option value="rashod">Rashod</option><option value="kapital">Kapital</option></select></label>
<button class="btn" onclick="loadKontniPlan()">Osvježi</button>
</div>
<div class="tbl-wrap">
<table id="kp-tbl"><thead><tr><th>Šifra</th><th>Naziv</th><th>Klasa</th><th>Vrsta</th><th>Aktivan</th><th>Akcije</th></tr></thead><tbody></tbody></table>
</div>
</div>
</section>
</div>
</main>
<!-- ===== MODALS ===== -->
<div class="modal-bg" id="m-konto" onclick="if(event.target===this)closeModal('m-konto')">
<div class="modal">
<h3>Novi / izmjena konta</h3>
<div class="form-row"><label>Šifra</label><input id="k-sifra"></div>
<div class="form-row"><label>Naziv</label><input id="k-naziv"></div>
<div class="form-row"><label>Klasa</label><input type="number" id="k-klasa" min="0" max="9"></div>
<div class="form-row"><label>Vrsta</label><select id="k-vrsta"><option value="aktiva">Aktiva</option><option value="pasiva">Pasiva</option><option value="prihod">Prihod</option><option value="rashod">Rashod</option><option value="kapital">Kapital</option><option value="izvanbilanca">Izvanbilanca</option></select></div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-konto')">Odustani</button>
<button class="btn gold" onclick="saveKonto()">Spremi</button>
</div>
</div>
</div>
<div class="modal-bg" id="m-partner" onclick="if(event.target===this)closeModal('m-partner')">
<div class="modal">
<h3>Novi / izmjena partnera</h3>
<div class="form-row"><label>Naziv</label><input id="p-naziv"></div>
<div class="form-row"><label>OIB</label><input id="p-oib" maxlength="11"></div>
<div class="form-row"><label>Vrsta</label><select id="p-vrsta"><option value="oba">Oba</option><option value="kupac">Kupac</option><option value="dobavljac">Dobavljač</option></select></div>
<div class="form-row"><label>IBAN</label><input id="p-iban"></div>
<div class="form-row"><label>Adresa</label><input id="p-adresa"></div>
<div class="form-row"><label>Grad</label><input id="p-grad"></div>
<div class="form-row"><label>Email</label><input id="p-email"></div>
<div class="form-row"><label>Telefon</label><input id="p-telefon"></div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-partner')">Odustani</button>
<button class="btn gold" onclick="savePartner()">Spremi</button>
</div>
</div>
</div>
<div class="modal-bg" id="m-dnev" onclick="if(event.target===this)closeModal('m-dnev')">
<div class="modal" style="width:min(960px,96vw)">
<h3>Novi zapis u dnevniku</h3>
<div class="form-row"><label>Datum</label><input type="date" id="d-datum"></div>
<div class="form-row"><label>Opis</label><input id="d-opis"></div>
<div class="form-row"><label>Tip dokumenta</label><select id="d-tip"><option value="rucno">Ručno</option><option value="racun_u">Račun ulazni</option><option value="racun_i">Račun izlazni</option><option value="placa">Plaća</option></select></div>
<h4 style="font-size:11px;color:var(--t2);margin:14px 0 6px">STAVKE (D=duguje, P=potražuje, samo jedno > 0)</h4>
<div id="d-lines"></div>
<button class="btn sec" onclick="addDnevLine()" style="margin-top:8px">+ Dodaj stavku</button>
<div id="d-balans" class="dnev-balans">Duguje: 0,00 · Potražuje: 0,00</div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-dnev')">Odustani</button>
<button class="btn gold" onclick="saveDnev()">Spremi zapis</button>
</div>
</div>
</div>
<div class="modal-bg" id="m-rac" onclick="if(event.target===this)closeModal('m-rac')">
<div class="modal" style="width:min(900px,96vw)">
<h3 id="m-rac-title">Novi račun</h3>
<div class="form-row"><label>Broj</label><input id="r-broj"></div>
<div class="form-row"><label>Partner</label><select id="r-partner"></select></div>
<div class="form-row"><label>Datum izdavanja</label><input type="date" id="r-datum"></div>
<div class="form-row"><label>Dospijeće</label><input type="date" id="r-dospjece"></div>
<div class="form-row"><label>Status</label><select id="r-status"><option value="nacrt">Nacrt</option><option value="knjizen">Knjižen (auto-knjiženje)</option></select></div>
<h4 style="font-size:11px;color:var(--t2);margin:14px 0 6px">STAVKE</h4>
<div id="r-lines"></div>
<button class="btn sec" onclick="addRacLine()" style="margin-top:8px">+ Dodaj stavku</button>
<div id="r-summary" class="dnev-balans">Neto: 0,00 · PDV: 0,00 · Brutto: 0,00</div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-rac')">Odustani</button>
<button class="btn gold" onclick="saveRac()">Spremi račun</button>
</div>
</div>
</div>
<div class="modal-bg" id="m-zap" onclick="if(event.target===this)closeModal('m-zap')">
<div class="modal">
<h3>Novi zaposlenik</h3>
<div class="form-row"><label>Ime</label><input id="z-ime"></div>
<div class="form-row"><label>Prezime</label><input id="z-prezime"></div>
<div class="form-row"><label>OIB</label><input id="z-oib" maxlength="11"></div>
<div class="form-row"><label>Klub ID</label><input type="number" id="z-klub"></div>
<div class="form-row"><label>Radno mjesto</label><input id="z-mjesto"></div>
<div class="form-row"><label>Plata bruto</label><input type="number" step="0.01" id="z-bruto"></div>
<div class="form-row"><label>IBAN</label><input id="z-iban"></div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-zap')">Odustani</button>
<button class="btn gold" onclick="saveZap()">Spremi</button>
</div>
</div>
</div>
<div class="modal-bg" id="m-pl" onclick="if(event.target===this)closeModal('m-pl')">
<div class="modal">
<h3>Obračun plaće (HR 2026)</h3>
<div class="form-row"><label>Zaposlenik</label><select id="pl-zap"></select></div>
<div class="form-row"><label>Godina</label><input type="number" id="pl-god" value="2026"></div>
<div class="form-row"><label>Mjesec</label><input type="number" id="pl-mj" min="1" max="12"></div>
<div class="form-row"><label>Bruto (€)</label><input type="number" step="0.01" id="pl-bruto" placeholder="prazno = iz zaposlenika"></div>
<div class="form-row"><label>Osobni odbitak</label><input type="number" step="0.01" id="pl-odb" value="600"></div>
<div class="form-row"><label>Prirez %</label><input type="number" step="0.1" id="pl-prirez" value="0"></div>
<div class="form-row"><label>Datum isplate</label><input type="date" id="pl-isplata"></div>
<div class="form-row"><label>Knjiži u dnevnik</label><input type="checkbox" id="pl-knjizi"></div>
<div class="form-actions">
<button class="btn sec" onclick="closeModal('m-pl')">Odustani</button>
<button class="btn gold" onclick="savePlaca()">Obračunaj</button>
</div>
</div>
</div>
<script>
const API = '/api/v2/erp';
const AUTH = () => ({ 'Authorization': 'Bearer ' + (localStorage.getItem('jwt') || localStorage.getItem('access_token') || 'admin-pgz-2026') });
const fmt = n => (Number(n||0)).toLocaleString('hr-HR',{minimumFractionDigits:2,maximumFractionDigits:2});
async function api(path, opts={}) {
const r = await fetch(API + path, { headers: { 'Content-Type':'application/json', ...AUTH() }, ...opts });
if (!r.ok) {
let detail = await r.text();
throw new Error(`${r.status}: ${detail}`);
}
return r.json();
}
// Tab switching
document.querySelectorAll('.tab').forEach(t => t.addEventListener('click', () => {
document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));
document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));
t.classList.add('active');
const panel = t.dataset.panel;
document.getElementById('panel-' + panel).classList.add('active');
loaders[panel] && loaders[panel]();
}));
function closeModal(id){ document.getElementById(id).classList.remove('show'); }
function openModal(id){ document.getElementById(id).classList.add('show'); }
// ===== KONTNI PLAN =====
async function loadKontniPlan(){
const q = document.getElementById('kp-q').value;
const klasa = document.getElementById('kp-klasa').value;
const vrsta = document.getElementById('kp-vrsta').value;
const params = new URLSearchParams();
if (q) params.set('q', q);
if (klasa) params.set('klasa', klasa);
if (vrsta) params.set('vrsta', vrsta);
const d = await api('/kontni-plan?' + params.toString());
const tbody = document.querySelector('#kp-tbl tbody');
tbody.innerHTML = d.rows.map(r=>`<tr>
<td><b>${r.sifra}</b></td><td>${r.naziv}</td><td>${r.klasa}</td><td>${r.vrsta}</td>
<td>${r.aktivan?'✓':'✗'}</td>
<td><button class="btn sec" onclick="event.stopPropagation();editKonto(${r.id})">✎</button></td>
</tr>`).join('');
}
function openKontoModal(){
['k-sifra','k-naziv','k-klasa'].forEach(i=>document.getElementById(i).value='');
document.getElementById('m-konto').dataset.id='';
openModal('m-konto');
}
async function editKonto(id){
const d = await api('/kontni-plan?'); // we don't have a single GET, so fetch & filter
const r = d.rows.find(x=>x.id===id);
if(!r) return;
document.getElementById('k-sifra').value=r.sifra;
document.getElementById('k-naziv').value=r.naziv;
document.getElementById('k-klasa').value=r.klasa;
document.getElementById('k-vrsta').value=r.vrsta;
document.getElementById('m-konto').dataset.id=id;
openModal('m-konto');
}
async function saveKonto(){
const body = {
sifra: document.getElementById('k-sifra').value.trim(),
naziv: document.getElementById('k-naziv').value.trim(),
klasa: parseInt(document.getElementById('k-klasa').value),
vrsta: document.getElementById('k-vrsta').value,
aktivan: true
};
const id = document.getElementById('m-konto').dataset.id;
try {
if(id) await api('/kontni-plan/'+id, { method:'PUT', body: JSON.stringify(body) });
else await api('/kontni-plan', { method:'POST', body: JSON.stringify(body) });
closeModal('m-konto'); loadKontniPlan();
} catch(e){ alert(e.message); }
}
// ===== PARTNERI =====
async function loadPartneri(){
const q = document.getElementById('part-q').value;
const v = document.getElementById('part-vrsta').value;
const p = new URLSearchParams();
if(q)p.set('q',q); if(v)p.set('vrsta',v);
const d = await api('/partneri?'+p.toString());
const tbody = document.querySelector('#part-tbl tbody');
tbody.innerHTML = d.rows.map(r=>`<tr onclick="loadPartnerSaldo(${r.id})">
<td>${r.id}</td><td>${r.oib||'—'}</td><td><b>${r.naziv}</b></td>
<td>${r.vrsta}</td><td>${r.grad||''}</td><td>${r.iban||''}</td>
<td class="num" id="ps-${r.id}">…</td>
<td><button class="btn sec" onclick="event.stopPropagation();editPartner(${r.id})">✎</button></td>
</tr>`).join('');
d.rows.forEach(r => {
api('/partneri/'+r.id+'/saldo').then(x => {
const el = document.getElementById('ps-'+r.id);
if(el) el.textContent = fmt(x.info?.saldo || 0);
}).catch(()=>{});
});
}
function openPartnerModal(){
['p-naziv','p-oib','p-iban','p-adresa','p-grad','p-email','p-telefon'].forEach(i=>document.getElementById(i).value='');
document.getElementById('m-partner').dataset.id='';
openModal('m-partner');
}
async function editPartner(id){
const d = await api('/partneri?');
const r = d.rows.find(x=>x.id===id);
if(!r) return;
document.getElementById('p-naziv').value=r.naziv||'';
document.getElementById('p-oib').value=r.oib||'';
document.getElementById('p-vrsta').value=r.vrsta;
document.getElementById('p-iban').value=r.iban||'';
document.getElementById('p-adresa').value=r.adresa||'';
document.getElementById('p-grad').value=r.grad||'';
document.getElementById('p-email').value=r.email||'';
document.getElementById('p-telefon').value=r.telefon||'';
document.getElementById('m-partner').dataset.id=id;
openModal('m-partner');
}
async function savePartner(){
const body = {
naziv: document.getElementById('p-naziv').value.trim(),
oib: document.getElementById('p-oib').value.trim() || null,
vrsta: document.getElementById('p-vrsta').value,
iban: document.getElementById('p-iban').value.trim() || null,
adresa: document.getElementById('p-adresa').value || null,
grad: document.getElementById('p-grad').value || null,
email: document.getElementById('p-email').value || null,
telefon: document.getElementById('p-telefon').value || null,
};
const id = document.getElementById('m-partner').dataset.id;
try {
if(id) await api('/partneri/'+id, { method:'PUT', body: JSON.stringify(body) });
else await api('/partneri', { method:'POST', body: JSON.stringify(body) });
closeModal('m-partner'); loadPartneri();
} catch(e){ alert(e.message); }
}
async function loadPartnerSaldo(id){
const d = await api('/partneri/'+id+'/saldo');
alert(`Partner saldo: ${fmt(d.info?.saldo||0)} EUR\nDuguje: ${fmt(d.info?.uk_duguje||0)}\nPotražuje: ${fmt(d.info?.uk_potrazuje||0)}\nBroj stavki: ${d.stavke.length}`);
}
// ===== DNEVNIK =====
async function loadDnevnik(){
const g = document.getElementById('dnev-godina').value;
const t = document.getElementById('dnev-tip').value;
const p = new URLSearchParams();
if(g) p.set('godina', g);
if(t) p.set('dokument_tip', t);
const d = await api('/dnevnik?'+p.toString());
const tbody = document.querySelector('#dnev-tbl tbody');
tbody.innerHTML = d.rows.map(r=>`<tr onclick="dnevDetail(${r.id})">
<td>${r.redni_broj||r.id}</td><td>${r.datum}</td><td>${r.opis||''}</td>
<td>${r.dokument_tip||''}</td><td class="num">${r.broj_stavki}</td>
<td class="num">${fmt(r.uk_duguje)}</td>
<td><button class="btn sec" onclick="event.stopPropagation();dnevStorno(${r.id})">↺ Storno</button></td>
</tr>`).join('');
}
async function dnevDetail(id){
const d = await api('/dnevnik/'+id);
let html = `<b>${d.head.opis||''}</b> · ${d.head.datum} · #${d.head.id}\n\nSTAVKE:\n`;
d.stavke.forEach(s => html += `${s.konto_sifra} ${s.konto_naziv}: D=${fmt(s.duguje)} P=${fmt(s.potrazuje)}\n`);
alert(html);
}
async function dnevStorno(id){
if(!confirm('Sigurno storno za zapis #'+id+'?')) return;
try {
await api('/dnevnik/'+id+'/storno', { method:'POST' });
loadDnevnik();
} catch(e){ alert(e.message); }
}
let kontoCache = [];
async function loadKontoCache(){
if(kontoCache.length) return kontoCache;
const d = await api('/kontni-plan?aktivan=true');
kontoCache = d.rows;
return kontoCache;
}
async function openDnevnikModal(){
await loadKontoCache();
document.getElementById('d-datum').value = new Date().toISOString().slice(0,10);
document.getElementById('d-opis').value = '';
document.getElementById('d-tip').value = 'rucno';
document.getElementById('d-lines').innerHTML = '';
addDnevLine(); addDnevLine();
updateDnevBalans();
openModal('m-dnev');
}
function addDnevLine(){
const opts = kontoCache.map(k=>`<option value="${k.id}">${k.sifra}${k.naziv}</option>`).join('');
const div = document.createElement('div');
div.className = 'dnev-line-row';
div.innerHTML = `
<select class="d-konto">${opts}</select>
<input class="d-opis" placeholder="opis stavke">
<input type="number" step="0.01" class="d-duguje" placeholder="Duguje" oninput="updateDnevBalans()">
<input type="number" step="0.01" class="d-potrazuje" placeholder="Potražuje" oninput="updateDnevBalans()">
<input type="number" class="d-partner" placeholder="Partner ID (opc)">
<button class="btn red" onclick="this.parentElement.remove();updateDnevBalans()">×</button>`;
document.getElementById('d-lines').appendChild(div);
}
function updateDnevBalans(){
const rows = document.querySelectorAll('#d-lines .dnev-line-row');
let d=0,p=0;
rows.forEach(r => {
d += parseFloat(r.querySelector('.d-duguje').value)||0;
p += parseFloat(r.querySelector('.d-potrazuje').value)||0;
});
const el = document.getElementById('d-balans');
el.textContent = `Duguje: ${fmt(d)} · Potražuje: ${fmt(p)} · Razlika: ${fmt(d-p)}`;
el.className = 'dnev-balans ' + (d===p && d>0 ? 'ok' : 'bad');
}
async function saveDnev(){
const stavke = Array.from(document.querySelectorAll('#d-lines .dnev-line-row')).map(r => ({
konto_id: parseInt(r.querySelector('.d-konto').value),
opis: r.querySelector('.d-opis').value,
duguje: parseFloat(r.querySelector('.d-duguje').value)||0,
potrazuje: parseFloat(r.querySelector('.d-potrazuje').value)||0,
partner_id: parseInt(r.querySelector('.d-partner').value)||null
}));
const body = {
datum: document.getElementById('d-datum').value,
opis: document.getElementById('d-opis').value,
dokument_tip: document.getElementById('d-tip').value,
stavke
};
try {
await api('/dnevnik', { method:'POST', body: JSON.stringify(body) });
closeModal('m-dnev'); loadDnevnik();
} catch(e){ alert(e.message); }
}
// ===== GLAVNA KNJIGA =====
async function loadGlavnaKnjiga(){
const k = document.getElementById('gk-klasa').value;
const p = new URLSearchParams();
if(k) p.set('klasa', k);
const d = await api('/glavna-knjiga?'+p.toString());
const tbody = document.querySelector('#gk-tbl tbody');
tbody.innerHTML = d.rows.map(r=>`<tr>
<td><b>${r.sifra}</b></td><td>${r.naziv}</td><td>${r.klasa}</td><td>${r.vrsta}</td>
<td class="num">${fmt(r.sum_duguje)}</td>
<td class="num">${fmt(r.sum_potrazuje)}</td>
<td class="num"><b>${fmt(r.saldo)}</b></td>
<td class="num">${r.broj_stavki}</td>
</tr>`).join('');
}
// ===== RAČUNI =====
let partnerCache = [];
async function loadPartnerCache(){
if(partnerCache.length) return partnerCache;
const d = await api('/partneri?');
partnerCache = d.rows;
return partnerCache;
}
async function loadRacuni(){
const tip = document.getElementById('rac-tip').value;
const status = document.getElementById('rac-status').value;
const godina = document.getElementById('rac-godina').value;
const p = new URLSearchParams();
if(status) p.set('status', status);
if(godina) p.set('godina', godina);
const d = await api('/racuni/'+tip+'?'+p.toString());
const tbody = document.querySelector('#rac-tbl tbody');
tbody.innerHTML = d.rows.map(r=>`<tr onclick="racDetail('${tip}',${r.id})">
<td>${r.id}</td><td>${r.broj||''}</td><td>${r.datum_izdavanja}</td>
<td>${r.partner_naziv||''}</td><td>${r.partner_oib||''}</td>
<td class="num">${fmt(r.iznos_neto)}</td>
<td class="num">${fmt(r.iznos_pdv)}</td>
<td class="num"><b>${fmt(r.iznos_brutto)}</b></td>
<td><span class="badge ${r.status}">${r.status}</span></td>
<td>${r.status==='nacrt'?`<button class="btn green" onclick="event.stopPropagation();knjizi('${tip}',${r.id})">Knjiži</button>`:''}</td>
</tr>`).join('');
}
async function knjizi(tip, id){
if(!confirm('Knjižiti račun #'+id+' u dnevnik?')) return;
try{ await api('/racuni/'+tip+'/'+id+'/knjizi', {method:'POST'}); loadRacuni(); }
catch(e){ alert(e.message); }
}
async function racDetail(tip, id){
const d = await api('/racuni/'+tip+'/'+id);
let html = `Račun ${d.head.broj||''} · ${d.head.partner_naziv}\nNeto: ${fmt(d.head.iznos_neto)} · PDV: ${fmt(d.head.iznos_pdv)} · Brutto: ${fmt(d.head.iznos_brutto)}\n\nSTAVKE:\n`;
d.stavke.forEach(s => html += `${s.naziv} ${s.kolicina}×${fmt(s.cijena_jed)} = ${fmt(s.iznos_brutto)}\n`);
alert(html);
}
async function openRacunModal(tip){
await loadPartnerCache();
document.getElementById('m-rac').dataset.tip = tip;
document.getElementById('m-rac-title').textContent = 'Novi ' + tip + ' račun';
document.getElementById('r-broj').value='';
document.getElementById('r-datum').value = new Date().toISOString().slice(0,10);
document.getElementById('r-dospjece').value = '';
document.getElementById('r-status').value = 'nacrt';
document.getElementById('r-partner').innerHTML = partnerCache.map(p=>`<option value="${p.id}">${p.naziv}${p.oib?' · '+p.oib:''}</option>`).join('');
document.getElementById('r-lines').innerHTML='';
addRacLine();
updateRacSummary();
openModal('m-rac');
}
function addRacLine(){
const div = document.createElement('div');
div.className = 'dnev-line-row';
div.style.gridTemplateColumns = '1fr 60px 80px 80px 60px 30px';
div.innerHTML = `
<input class="r-naziv" placeholder="Naziv stavke">
<input type="number" step="0.01" class="r-kol" value="1" oninput="updateRacSummary()">
<input type="number" step="0.01" class="r-cij" placeholder="Cijena" oninput="updateRacSummary()">
<input type="number" step="0.01" class="r-pop" value="0" placeholder="Popust %" oninput="updateRacSummary()">
<input type="number" step="0.01" class="r-pdv" value="25" placeholder="PDV %" oninput="updateRacSummary()">
<button class="btn red" onclick="this.parentElement.remove();updateRacSummary()">×</button>`;
document.getElementById('r-lines').appendChild(div);
}
function updateRacSummary(){
const rows = document.querySelectorAll('#r-lines .dnev-line-row');
let neto=0, pdv=0;
rows.forEach(r => {
const k = parseFloat(r.querySelector('.r-kol').value)||0;
const c = parseFloat(r.querySelector('.r-cij').value)||0;
const pop = parseFloat(r.querySelector('.r-pop').value)||0;
const ppdv = parseFloat(r.querySelector('.r-pdv').value)||0;
const n = k*c*(1-pop/100);
neto += n;
pdv += n*ppdv/100;
});
document.getElementById('r-summary').textContent = `Neto: ${fmt(neto)} · PDV: ${fmt(pdv)} · Brutto: ${fmt(neto+pdv)}`;
}
async function saveRac(){
const tip = document.getElementById('m-rac').dataset.tip;
const stavke = Array.from(document.querySelectorAll('#r-lines .dnev-line-row')).map(r => ({
naziv: r.querySelector('.r-naziv').value,
kolicina: parseFloat(r.querySelector('.r-kol').value)||1,
cijena_jed: parseFloat(r.querySelector('.r-cij').value)||0,
popust_pct: parseFloat(r.querySelector('.r-pop').value)||0,
pdv_pct: parseFloat(r.querySelector('.r-pdv').value)||25,
}));
const body = {
broj: document.getElementById('r-broj').value || null,
partner_id: parseInt(document.getElementById('r-partner').value),
datum_izdavanja: document.getElementById('r-datum').value,
datum_dospjeca: document.getElementById('r-dospjece').value || null,
status: document.getElementById('r-status').value,
stavke
};
try {
await api('/racuni/'+tip, { method:'POST', body: JSON.stringify(body) });
closeModal('m-rac');
loadRacuni();
} catch(e){ alert(e.message); }
}
async function importERacun(){
const f = document.getElementById('eracun-file').files[0];
if(!f) return;
const fd = new FormData();
fd.append('file', f);
const r = await fetch(API+'/racuni/eracun-import', { method:'POST', headers: AUTH(), body: fd });
const d = await r.json();
alert(r.ok ? `e-Račun importiran:\nBroj: ${d.broj}\nNeto: ${fmt(d.neto)} PDV: ${fmt(d.pdv)} Brutto: ${fmt(d.brutto)}` : 'Greška: '+JSON.stringify(d));
document.getElementById('eracun-file').value='';
loadRacuni();
}
// ===== PDV =====
async function loadPdv(){
const g = document.getElementById('pdv-godina').value;
const m = document.getElementById('pdv-mjesec').value;
const params = new URLSearchParams({ godina:g });
if(m) params.set('mjesec', m);
const [u,i,o] = await Promise.all([
api('/pdv/knjiga-u?'+params.toString()),
api('/pdv/knjiga-i?'+params.toString()),
api('/pdv/obrazac?'+params.toString())
]);
document.querySelector('#pdv-u-tbl tbody').innerHTML = u.rows.map(r=>`<tr><td>${r.broj||''}</td><td>${r.datum_izdavanja}</td><td>${r.partner_naziv||''}</td><td>${r.partner_oib||''}</td><td class="num">${fmt(r.iznos_neto)}</td><td class="num">${fmt(r.iznos_pdv)}</td></tr>`).join('');
document.querySelector('#pdv-i-tbl tbody').innerHTML = i.rows.map(r=>`<tr><td>${r.broj||''}</td><td>${r.datum_izdavanja}</td><td>${r.partner_naziv||''}</td><td>${r.partner_oib||''}</td><td class="num">${fmt(r.iznos_neto)}</td><td class="num">${fmt(r.iznos_pdv)}</td></tr>`).join('');
document.getElementById('pdv-summary').innerHTML = `
<div class="kpi"><div class="kpi-l">Pretporez (U)</div><div class="kpi-v">${fmt(o.ulazni.pdv)} €</div></div>
<div class="kpi"><div class="kpi-l">PDV obveza (I)</div><div class="kpi-v">${fmt(o.izlazni.pdv)} €</div></div>
<div class="kpi ${o.obveza_za_uplatu>0?'r':'g'}"><div class="kpi-l">Obveza za uplatu</div><div class="kpi-v">${fmt(o.obveza_za_uplatu)} €</div></div>
<div class="kpi g"><div class="kpi-l">Pretporez za povrat</div><div class="kpi-v">${fmt(o.pretporez_za_povrat)} €</div></div>`;
}
// ===== ZAPOSLENICI + PLAĆE =====
async function loadZap(){
const d = await api('/zaposlenici');
document.querySelector('#zap-tbl tbody').innerHTML = d.rows.map(r=>`<tr>
<td>${r.id}</td><td>${r.oib||'—'}</td><td>${r.ime}</td><td>${r.prezime}</td>
<td>${r.klub_naziv||'—'}</td><td>${r.radno_mjesto||''}</td>
<td class="num">${fmt(r.plata_bruto)}</td><td>${r.aktivan?'✓':'✗'}</td>
</tr>`).join('');
}
async function loadPlace(){
const g = document.getElementById('pl-godina').value;
const m = document.getElementById('pl-mjesec').value;
const p = new URLSearchParams();
if(g)p.set('godina',g); if(m)p.set('mjesec',m);
const d = await api('/place/obracun?'+p.toString());
document.querySelector('#pl-tbl tbody').innerHTML = d.rows.map(r=>`<tr>
<td>${r.id}</td><td>${r.ime} ${r.prezime}</td><td>${r.godina}/${String(r.mjesec).padStart(2,'0')}</td>
<td class="num">${fmt(r.bruto)}</td>
<td class="num">${fmt(r.doprinosi_iz_plate)}</td>
<td class="num">${fmt(r.dohodnina)}</td>
<td class="num"><b>${fmt(r.neto)}</b></td>
<td class="num">${fmt(r.doprinosi_na_plate)}</td>
<td class="num">${fmt(r.ukupni_trosak)}</td>
</tr>`).join('');
}
function openZapModal(){
['z-ime','z-prezime','z-oib','z-klub','z-mjesto','z-bruto','z-iban'].forEach(i=>document.getElementById(i).value='');
openModal('m-zap');
}
async function saveZap(){
const body = {
ime: document.getElementById('z-ime').value,
prezime: document.getElementById('z-prezime').value,
oib: document.getElementById('z-oib').value || null,
klub_id: parseInt(document.getElementById('z-klub').value)||null,
radno_mjesto: document.getElementById('z-mjesto').value || null,
plata_bruto: parseFloat(document.getElementById('z-bruto').value)||0,
iban: document.getElementById('z-iban').value || null,
aktivan: true
};
try { await api('/zaposlenici', { method:'POST', body: JSON.stringify(body) }); closeModal('m-zap'); loadZap(); }
catch(e){ alert(e.message); }
}
async function openPlacaModal(){
const d = await api('/zaposlenici');
document.getElementById('pl-zap').innerHTML = d.rows.map(r=>`<option value="${r.id}">${r.ime} ${r.prezime}</option>`).join('');
openModal('m-pl');
}
async function savePlaca(){
const body = {
zaposlenik_id: parseInt(document.getElementById('pl-zap').value),
godina: parseInt(document.getElementById('pl-god').value),
mjesec: parseInt(document.getElementById('pl-mj').value),
bruto: parseFloat(document.getElementById('pl-bruto').value) || null,
osobni_odbitak: parseFloat(document.getElementById('pl-odb').value)||600,
prirez_pct: parseFloat(document.getElementById('pl-prirez').value)||0,
datum_isplate: document.getElementById('pl-isplata').value || null,
knjizi: document.getElementById('pl-knjizi').checked
};
try {
const r = await api('/place/obracun', { method:'POST', body: JSON.stringify(body) });
alert(`Bruto: ${fmt(r.calc.bruto)}\nDoprinosi iz: ${fmt(r.calc.doprinosi_iz_plate)}\nDohodnina: ${fmt(r.calc.dohodnina)}\nNeto: ${fmt(r.calc.neto)}\nUkupni trošak: ${fmt(r.calc.ukupni_trosak)}`);
closeModal('m-pl'); loadPlace();
} catch(e){ alert(e.message); }
}
// ===== PRORAČUN =====
async function loadProracun(){
const d = await api('/proracun');
document.querySelector('#pr-tbl tbody').innerHTML = d.rows.map(r=>`<tr>
<td><b>${r.godina}</b></td><td class="num">${fmt(r.proracun_pgz)}</td>
<td class="num">${fmt(r.rebalans1)}</td><td class="num">${fmt(r.rebalans2)}</td>
<td class="num"><b>${fmt(r.ukupno_pgz)}</b></td><td class="num">${fmt(r.ministarstvo)}</td>
<td class="num"><b>${fmt(r.ukupno)}</b></td><td>${r.napomena||''}</td>
</tr>`).join('');
}
// ===== IZVJEŠTAJI =====
async function loadIzvjestaj(){
const tip = document.getElementById('iz-tip').value;
const g = document.getElementById('iz-godina').value;
const d = await api('/izvjestaji/'+tip+'?godina='+g);
const out = document.getElementById('iz-out');
if(tip==='bilanca'){
out.innerHTML = `
<div class="kpi-grid">
<div class="kpi g"><div class="kpi-l">Ukupno aktiva</div><div class="kpi-v">${fmt(d.ukupno_aktiva)} €</div></div>
<div class="kpi"><div class="kpi-l">Ukupno pasiva</div><div class="kpi-v">${fmt(d.ukupno_pasiva)} €</div></div>
<div class="kpi ${d.balans_ok?'g':'r'}"><div class="kpi-l">Balans</div><div class="kpi-v">${d.balans_ok?'✓ OK':'✗ neusklađen'}</div></div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<div><h4 style="font-size:12px;color:var(--t2);margin-bottom:6px">AKTIVA</h4>
<div class="tbl-wrap"><table><thead><tr><th>Šifra</th><th>Naziv</th><th class="num">Saldo</th></tr></thead>
<tbody>${d.aktiva.map(r=>`<tr><td>${r.sifra}</td><td>${r.naziv}</td><td class="num">${fmt(r.saldo)}</td></tr>`).join('')}</tbody></table></div></div>
<div><h4 style="font-size:12px;color:var(--t2);margin-bottom:6px">PASIVA</h4>
<div class="tbl-wrap"><table><thead><tr><th>Šifra</th><th>Naziv</th><th class="num">Saldo</th></tr></thead>
<tbody>${d.pasiva.map(r=>`<tr><td>${r.sifra}</td><td>${r.naziv}</td><td class="num">${fmt(r.saldo)}</td></tr>`).join('')}</tbody></table></div></div>
</div>`;
} else if(tip==='pnl'){
out.innerHTML = `
<div class="kpi-grid">
<div class="kpi g"><div class="kpi-l">Prihodi</div><div class="kpi-v">${fmt(d.ukupno_prihodi)} €</div></div>
<div class="kpi r"><div class="kpi-l">Rashodi</div><div class="kpi-v">${fmt(d.ukupno_rashodi)} €</div></div>
<div class="kpi ${d.rezultat>=0?'g':'r'}"><div class="kpi-l">Rezultat (${d.tip_rezultata})</div><div class="kpi-v">${fmt(d.rezultat)} €</div></div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<div><h4 style="font-size:12px;color:var(--t2);margin-bottom:6px">PRIHODI</h4>
<div class="tbl-wrap"><table><thead><tr><th>Šifra</th><th>Naziv</th><th class="num">Iznos</th></tr></thead>
<tbody>${d.prihodi.map(r=>`<tr><td>${r.sifra}</td><td>${r.naziv}</td><td class="num">${fmt(r.iznos)}</td></tr>`).join('')}</tbody></table></div></div>
<div><h4 style="font-size:12px;color:var(--t2);margin-bottom:6px">RASHODI</h4>
<div class="tbl-wrap"><table><thead><tr><th>Šifra</th><th>Naziv</th><th class="num">Iznos</th></tr></thead>
<tbody>${d.rashodi.map(r=>`<tr><td>${r.sifra}</td><td>${r.naziv}</td><td class="num">${fmt(r.iznos)}</td></tr>`).join('')}</tbody></table></div></div>
</div>`;
} else {
out.innerHTML = `
<div class="tbl-wrap"><table><thead><tr><th>Mjesec</th><th class="num">Uplate</th><th class="num">Isplate</th><th class="num">Net</th></tr></thead>
<tbody>${d.po_mjesecu.map(r=>`<tr><td>${r.mjesec}</td><td class="num">${fmt(r.uplate)}</td><td class="num">${fmt(r.isplate)}</td><td class="num"><b>${fmt(Number(r.uplate)-Number(r.isplate))}</b></td></tr>`).join('')}</tbody></table></div>`;
}
}
function exportXlsx(report, godina, mjesec){
let url = API+'/export/xlsx/'+report+'?godina='+godina;
if(mjesec) url += '&mjesec='+mjesec;
window.open(url, '_blank');
}
function exportPdf(report, godina){
window.open(API+'/export/pdf/'+report+'?godina='+godina, '_blank');
}
// Lazy loaders per panel
const loaders = {
dnevnik: loadDnevnik,
glavna: loadGlavnaKnjiga,
partneri: loadPartneri,
racuni: loadRacuni,
pdv: loadPdv,
place: () => { loadZap(); loadPlace(); },
proracun: loadProracun,
izvjestaji: loadIzvjestaj,
kontni: loadKontniPlan
};
// Initial
document.addEventListener('DOMContentLoaded', () => {
loadKontoCache();
loadPartnerCache();
loadDnevnik();
});
</script>
</body>
</html>