/* Účtovníček — Účtovný denník, Hlavná kniha, Saldokonto (čítané zo servera) */ const thisYear = () => new Date().getFullYear(); const yearsAvailable = () => { const ys = new Set([thisYear()]); uctStore.invoices.all().forEach(i => ys.add(+String(i.issueDate).slice(0, 4))); uctStore.documents.list().forEach(d => ys.add(+String(d.date).slice(0, 4))); return [...ys].filter(Boolean).sort((a, b) => b - a); }; const MONTHS = ['január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december']; /* Otvorenie dokladu z denníka: faktúra alebo doklad podľa druhu. */ function openDoc(go, e) { if (e.docType === 'invoice') go((e.docKind === 'purchase' ? 'purchase' : 'invoices') + ':open:' + e.docId); else go(e.docKind + ':open:' + e.docId); } function PageJournal({ go, route }) { const [, action, routeArg] = (route || '').split(':'); const [year, setYear] = React.useState(() => thisYear()); const [month, setMonth] = React.useState(''); const [account, setAccount] = React.useState(action === 'account' ? routeArg : ''); const [q, setQ] = React.useState(''); const [rows, setRows] = React.useState(null); const [err, setErr] = React.useState(null); React.useEffect(() => { if (action === 'account') { setAccount(routeArg); setYear(0); } }, [route]); React.useEffect(() => { let alive = true; setRows(null); const f = { year: year || undefined, period: month ? `${year}-${month}` : undefined, account: account || undefined, q: q || undefined }; uctStore.journal.list(f).then(r => { if (alive) setRows(r); }).catch(e => { if (alive) { setErr(e.message); setRows([]); } }); return () => { alive = false; }; }, [year, month, account, q]); const sum = (f) => (rows || []).reduce((a, e) => a + (f(e) || 0), 0); const years = yearsAvailable(); return (

Účtovný denník

Každý zápis vznikol z dokladu - klikni naň a otvorí sa faktúra, výpis alebo doklad
setAccount(e.target.value.replace(/\D/g, ''))} /> setQ(e.target.value)} /> {(account || q || month) && }
{err && setErr(null)} />}
{rows === null ? : ( {rows.map(e => ( openDoc(go, e)}> ))} {rows.length === 0 && } {rows.length > 0 && }
DátumDokladÚčetTextPartnerVSMDDAL
{fmt.date(e.date)} {e.binder}{e.docNumber} {e.account} {e.text} {e.partnerName} {e.vs} {e.md ? fmt.num(e.md) : ''} {e.dal ? fmt.num(e.dal) : ''}

Žiadne zápisy

Zápisy vznikajú z faktúr, bankových výpisov, pokladne a interných dokladov.
{rows.length} {plural(rows.length, 'zápis', 'zápisy', 'zápisov')}{fmt.num(sum(e => e.md))}{fmt.num(sum(e => e.dal))}
)}
); } function PageLedger({ go, route }) { const [year, setYear] = React.useState(() => thisYear()); const [from, setFrom] = React.useState(() => `${thisYear()}-01-01`); const [to, setTo] = React.useState(() => `${thisYear()}-12-31`); const [level, setLevel] = React.useState('analytika'); const [rows, setRows] = React.useState(null); const [err, setErr] = React.useState(null); const setYearRange = (y) => { setYear(y); if (y) { setFrom(`${y}-01-01`); setTo(`${y}-12-31`); } else { setFrom(''); setTo(''); } }; React.useEffect(() => { let alive = true; setRows(null); uctStore.journal.ledger(from, to).then(r => { if (alive) setRows(r); }).catch(e => { if (alive) { setErr(e.message); setRows([]); } }); return () => { alive = false; }; }, [from, to]); let shown = rows || []; if (level === 'syntetika' && rows) { const agg = {}; rows.forEach(r => { const k = r.account.slice(0, 3); const a = agg[k] || (agg[k] = { account: k, name: uctStore.accounts.name(k + '001') || r.name, opening: 0, md: 0, dal: 0, closing: 0 }); a.opening += r.opening; a.md += r.md; a.dal += r.dal; a.closing += r.closing; }); shown = Object.values(agg).sort((a, b) => a.account.localeCompare(b.account)); } const sum = (f) => shown.reduce((a, r) => a + (f(r) || 0), 0); const groups = {}; shown.forEach(r => { (groups[r.account[0]] = groups[r.account[0]] || []).push(r); }); const bal = (v) => v === 0 ? '' : fmt.num(v); return (

Hlavná kniha

Počiatočný stav, obraty za obdobie a konečný stav každého účtu
{ setYear(0); setFrom(e.target.value); }} /> { setYear(0); setTo(e.target.value); }} />
{err && setErr(null)} />}
{rows === null ? : ( {Object.keys(groups).sort().map(cls => ( {groups[cls].map(r => ( go('journal:account:' + r.account)}> ))} ))} {shown.length === 0 && } {shown.length > 0 && }
ÚčetNázovPočiatočný stavMDDALKonečný stav
Trieda {cls} · {ACCOUNT_CLASSES[cls] || ''}
{r.account} {r.name || účet nie je v osnove} {bal(r.opening)} {bal(r.md)} {bal(r.dal)} {fmt.num(r.closing)}

Zatiaľ žiadne pohyby

Hlavná kniha sa naplní z denníka.
Spolu {shown.length} účtov{fmt.num(sum(r => r.opening))}{fmt.num(sum(r => r.md))}{fmt.num(sum(r => r.dal))}{fmt.num(sum(r => r.closing))}
)}
Súčet konečných stavov všetkých účtov má byť 0 (MD = DAL). Kladné číslo = zostatok na strane MD, záporné = na strane DAL.
); } function PageSaldo({ go }) { const [rows, setRows] = React.useState(null); const [err, setErr] = React.useState(null); const [tab, setTab] = React.useState('311'); React.useEffect(() => { let alive = true; uctStore.journal.saldo().then(r => { if (alive) setRows(r); }).catch(e => { if (alive) { setErr(e.message); setRows([]); } }); return () => { alive = false; }; }, []); const all = rows || []; const shown = all.filter(r => tab === 'all' || r.account.startsWith(tab)); const sum = (f) => shown.reduce((a, r) => a + (f(r) || 0), 0); const counts = { '311': all.filter(r => r.account.startsWith('311')).length, '321': all.filter(r => r.account.startsWith('321')).length, all: all.length }; return (

Saldokonto

Otvorené položky podľa partnera a variabilného symbolu - čo kto komu ešte dlhuje
{[['311', 'Odberatelia (311)'], ['321', 'Dodávatelia (321)'], ['all', 'Všetky saldokontné účty']].map(([k, l]) => ( ))}
{err && setErr(null)} />}
{rows === null ? : ( {shown.map((r, i) => ( go('journal:account:' + r.account)} title="Zobraziť pohyby účtu v denníku"> ))} {shown.length === 0 && } {shown.length > 0 && }
PartnerVSÚčetDokladDátumMDDALSaldo
{r.partnerName || bez partnera} {r.vs} {r.account} {r.docNumber} {fmt.date(r.date)} {fmt.num(r.md)} {fmt.num(r.dal)} {fmt.num(r.saldo)}

Všetko vyrovnané

Žiadne otvorené položky.
{shown.length} {plural(shown.length, 'položka', 'položky', 'položiek')}{fmt.num(sum(r => r.md))}{fmt.num(sum(r => r.dal))}{fmt.num(sum(r => r.saldo))}
)}
Kladné saldo na 311 = odberateľ ešte nezaplatil. Záporné saldo na 321 = my ešte dlhujeme dodávateľovi. Dvojica s opačnými znamienkami na dvoch účtoch (napr. 321001 a 321002) znamená, že faktúra a platba boli zaúčtované na rôzne analytiky - tak to je aj v Profit365.
); }