/* Účtovníček — Daňová evidencia (SZČO): pohľadávky, príjmy, výpočet dane. * Rozloženie stĺpcov kopíruje zošit Mirky (Pohľadávky RRRR / Príjmy RRRR). */ function useTaxYear(route) { const years = uctStore.tax.years(); const fromRoute = +((route || '').split(':')[1] || 0); const [year, setYear] = React.useState(() => fromRoute || (years.includes(new Date().getFullYear()) ? new Date().getFullYear() : (years[0] || new Date().getFullYear()))); return [year, setYear, years.length ? years : [year]]; } function YearPicker({ year, setYear, years }) { const list = years.includes(year) ? years : [year, ...years]; return ( ); } function PaidBadge({ s }) { const m = { A: ['paidA', 'A · uhradená'], 'Č': ['paidC', 'Č · čiastočne'], N: ['paidN', 'N · neuhradená'] }[s]; if (!m) return {s}; return {m[1]}; } /* --- Pohľadávky --- */ function PageTaxReceivables({ go, route }) { const [year, setYear, years] = useTaxYear(route); const [rows, setRows] = React.useState(null); const [edit, setEdit] = React.useState(null); const [err, setErr] = React.useState(null); const [setToast, Toast] = useToast(); const load = () => uctStore.tax.receivables(year).then(setRows).catch(e => setErr(e.message)); React.useEffect(() => { setRows(null); load(); }, [year]); const sum = (k) => (rows || []).filter(r => r.status !== 'storno').reduce((a, r) => a + (k(r) || 0), 0); return (

Pohľadávky {year}

vystavené faktúry a rozdelenie príjmu podľa druhu · stav úhrady z Príjmov
setErr(null)} />
{!rows ? : ( {rows.map((r, i) => ( setEdit(r)}> ))} {rows.length === 0 && } {rows.length > 0 && ( )}
P.č.Číslo dokladuOdberateľDátumQ Autorský zákon (§ 6 ods. 2 písm. a)Živnosť§ 8 ostatné§ 7a DPH POZDNa účet podn.Uhradené
VystaveniaDodaniaSplatnosti HodnotaLF %LF €Na účet HodnotaHodnotaHodnotaHodnotaHodnota
{i + 1} {r.number}{r.unclassified && r.status !== 'storno' && ?} {r.partnerName} {fmt.date(r.issueDate)}{fmt.date(r.deliveryDate)}{fmt.date(r.dueDate)} {r.quarter} {fmt.num(r.tax.autorsky)}{fmt.num(r.tax.lfPct * 100, 0)} %{fmt.num(r.lfEur)}{fmt.num(r.autorskyNet)} {fmt.num(r.tax.zivnost)} {fmt.num(r.tax.ostatne)} {r.tax.par7a ? fmt.num(r.tax.par7a) : '—'} {fmt.num(r.pozd)} {fmt.num(r.naUcet)} {r.paidStatus === 'Č' &&
{fmt.num(r.paidSum)} z {fmt.num(r.naUcet)}
}

V roku {year} nie sú pohľadávky

Vystav faktúru alebo načítaj dáta v Nastaveniach.
spolu {rows.length} {fmt.num(sum(r => r.tax.autorsky))}{fmt.num(sum(r => r.lfEur))}{fmt.num(sum(r => r.autorskyNet))} {fmt.num(sum(r => r.tax.zivnost))}{fmt.num(sum(r => r.tax.ostatne))}{fmt.num(sum(r => r.tax.par7a))} {fmt.num(sum(r => r.pozd))}{fmt.num(sum(r => r.naUcet))}
)}
{edit && setEdit(null)} go={go} onSaved={() => { setEdit(null); load(); setToast('Rozdelenie uložené.'); }} />} {Toast}
); } function TaxClassDrawer({ rec, onClose, onSaved, go }) { const [t, setT] = React.useState(() => ({ ...rec.tax })); const [err, setErr] = React.useState(null); const set = (k, v) => setT(prev => ({ ...prev, [k]: v })); const pozd = Math.round(((t.autorsky || 0) + (t.zivnost || 0) + (t.ostatne || 0)) * 100) / 100; const diff = Math.round((rec.total - pozd) * 100) / 100; const save = async () => { setErr(null); try { await uctStore.tax.setClass(rec.invoiceId, t); onSaved(); } catch (e) { setErr(e.message); } }; return ( {rec.number}} sub={<>{rec.partnerName} · {fmt.eur(rec.total)} · } onClose={onClose} footer={<> }> setErr(null)} />

Rozdeľ sumu faktúry podľa druhu príjmu. Súčet (POZD) má sedieť so sumou faktúry.

set('autorsky', v)} /> set('lfPct', v / 100)} />
set('zivnost', v)} /> set('ostatne', v)} />
set('par7a', v)} />
POZD (rozdelené){fmt.eur(pozd)}
Suma faktúry{fmt.eur(rec.total)}
Rozdiel{fmt.eur(diff)}
); } /* --- Príjmy --- */ function PageTaxIncomes({ go, route }) { const [year, setYear, years] = useTaxYear(route); const [rows, setRows] = React.useState(null); const [edit, setEdit] = React.useState(null); // {} = nový const [err, setErr] = React.useState(null); const [setToast, Toast] = useToast(); const [askConfirm, ConfirmUI] = useConfirm(); const load = () => uctStore.tax.incomes(year).then(setRows).catch(e => setErr(e.message)); React.useEffect(() => { setRows(null); load(); }, [year]); const sum = (k) => (rows || []).reduce((a, r) => a + (r[k] || 0), 0); const remove = async (r) => { if (!await askConfirm({ title: 'Vymazať príjem?', message: `${fmt.date(r.date)} · ${r.partnerName || r.invoiceNumber} · ${fmt.eur(r.naUcet)}`, confirmLabel: 'Vymazať', danger: true })) return; try { await uctStore.tax.removeIncome(r.id); load(); setToast('Príjem vymazaný.'); } catch (e) { setErr(e.message); } }; let running = 0; return (

Príjmy {year}

úhrady podľa dátumu prijatia peňazí · POZD ovplyvňuje základ dane, PNZD nie
setErr(null)} />
{!rows ? : ( {rows.map((r, i) => { running = Math.round((running + r.pozd) * 100) / 100; return ( setEdit(r)}> ); })} {rows.length === 0 && } {rows.length > 0 && ( )}
P.č.ÚčetDokladPohľadávkaOdberateľDátum úhrady Autorský zákonŽivnosť§ 8§ 7aPNZDPOZDNa účet
HodnotaLF %LF €Na účetHodnotaHodnotaHodnotaHodnotaHodnotaMedzisúčetHodnota
{i + 1}{r.account}{r.doc} {r.invoiceNumber || —}{r.partnerName}{fmt.date(r.date)} {fmt.num(r.autorsky)}{fmt.num(r.lfPct * 100, 0)} %{fmt.num(r.lfEur)}{fmt.num(r.autorskyNet)} {fmt.num(r.zivnost)}{fmt.num(r.ostatne)}{r.par7a ? fmt.num(r.par7a) : '—'} {r.pnzd ? fmt.num(r.pnzd) : '—'} {fmt.num(r.pozd)}{fmt.num(running)} {fmt.num(r.naUcet)}

V roku {year} nie sú príjmy

Zapíš úhradu tlačidlom Nový príjem.
spolu {rows.length} {fmt.num(sum('autorsky'))}{fmt.num(sum('lfEur'))}{fmt.num(sum('autorskyNet'))} {fmt.num(sum('zivnost'))}{fmt.num(sum('ostatne'))}{fmt.num(sum('par7a'))}{fmt.num(sum('pnzd'))} {fmt.num(sum('pozd'))}{fmt.num(sum('naUcet'))}
)}
{edit && setEdit(null)} onSaved={() => { setEdit(null); load(); setToast('Príjem uložený.'); }} />} {ConfirmUI} {Toast}
); } function TaxIncomeDrawer({ income, year, onClose, onSaved }) { const isNew = !income; const [r, setR] = React.useState(() => isNew ? uctStore.tax.blankIncome(year) : { ...income }); const [err, setErr] = React.useState(null); const [recs, setRecs] = React.useState([]); React.useEffect(() => { uctStore.tax.receivables(0).then(list => setRecs(list.filter(x => x.status !== 'storno' && (x.paidStatus !== 'A' || x.number === r.invoiceNumber)))).catch(() => {}); }, []); const set = (k, v) => setR(prev => ({ ...prev, [k]: v })); const pickInvoice = (number) => { const rec = recs.find(x => x.number === number); if (!rec) { setR(prev => ({ ...prev, invoiceNumber: '', invoiceId: '' })); return; } const rest = Math.max(0, Math.round((rec.naUcet - rec.paidSum) * 100) / 100); const full = rec.paidSum <= 0; setR(prev => ({ ...prev, invoiceNumber: rec.number, invoiceId: rec.invoiceId, partnerName: rec.partnerName, autorsky: full ? rec.tax.autorsky : rest, lfPct: rec.tax.lfPct, zivnost: full ? rec.tax.zivnost : 0, ostatne: full ? rec.tax.ostatne : 0, par7a: full ? rec.tax.par7a : 0 })); }; const pozd = Math.round(((r.autorsky || 0) + (r.zivnost || 0) + (r.ostatne || 0)) * 100) / 100; const naUcet = Math.round((pozd - (r.autorsky || 0) * (r.lfPct || 0) + (r.pnzd || 0)) * 100) / 100; const save = async () => { setErr(null); try { isNew ? await uctStore.tax.createIncome(r) : await uctStore.tax.updateIncome(r); onSaved(); } catch (e) { setErr(e.message); } }; return ( }> setErr(null)} />
set('date', e.target.value)} /> set('account', e.target.value)} placeholder="BANKA - FIO" /> set('doc', e.target.value)} placeholder={r.date ? r.date.slice(5, 7) + '/' + r.date.slice(0, 4) : ''} />
set('partnerName', e.target.value)} />
set('autorsky', v)} /> set('lfPct', v / 100)} /> set('zivnost', v)} />
set('ostatne', v)} /> set('par7a', v)} /> set('pnzd', v)} />
set('note', e.target.value)} />
POZD (do základu dane){fmt.eur(pozd)}
Na účet (po LF, s PNZD){fmt.eur(naUcet)}
); } /* --- Výpočet dane --- */ function PageTaxCalc({ go, route }) { const [year, setYear, years] = useTaxYear(route); const [sum, setSum] = React.useState(null); const [ty, setTy] = React.useState(null); const [err, setErr] = React.useState(null); const [setToast, Toast] = useToast(); const [showConst, setShowConst] = React.useState(false); const load = () => Promise.all([uctStore.tax.summary(year), uctStore.tax.year(year)]).then(([s, t]) => { setSum(s); setTy(t); }).catch(e => setErr(e.message)); React.useEffect(() => { setSum(null); load(); }, [year]); const setT = (k, v) => setTy(prev => ({ ...prev, [k]: v })); const setP = (k, v) => setTy(prev => ({ ...prev, priznanie: { ...(prev.priznanie || {}), [k]: v } })); const save = async () => { setErr(null); try { await uctStore.tax.saveYear(ty); await load(); setToast(`Rok ${year} uložený.`); } catch (e) { setErr(e.message); } }; if (!sum || !ty) return

Výpočet dane {year}

; const P = ty.priznanie || {}; const limitNow = ty.dphLimitNow || 0, limitYear = ty.dphLimitYear || 0; const maxBar = Math.max(limitNow || limitYear || 1, ...sum.months.map(m => m.sum12)); const rowCalc = (label, calc, key, big) => (
{label}
{fmt.num(calc)}
{key ? setP(key, v)} /> : —}
); return (

Výpočet dane {year}

z príjmov podľa dátumu úhrady · paušálne výdavky {Math.round(ty.pausalPct * 100)} %{ty.pausalMax ? ` (max ${fmt.num(ty.pausalMax, 0)})` : ''} · {sum.flatRate ? '15 % (príjmy do limitu)' : 'pásma'}
setErr(null)} />
= limitYear ? 'down' : 'up'} />

Výpočet

ľavý stĺpec počíta appka, pravý je to, čo bolo v podanom priznaní (zapíš ručne)
Položka
Výpočet
D. priznanie
{rowCalc('Príjmy spolu (POZD)', sum.pozd, 'prijmy')} {rowCalc('z toho autorský zákon', sum.autorsky)} {rowCalc('z toho živnosť', sum.zivnost)} {rowCalc('z toho § 8 ostatné', sum.ostatne)} {rowCalc('Paušálne výdavky', sum.pausal, 'pausal')}
Zaplatené poistné SP + ZP
setT('poistne', v)} />
setP('poistne', v)} />
{rowCalc('Príjem po výdavkoch a poistnom', sum.prijemAZ, 'prijemAZ')}
Príjem pre daň vyberanú zrážkou
setT('zrazkova', v)} />
setP('zrazkova', v)} />
{rowCalc('Základ dane', sum.zd, 'zd', true)} {rowCalc('Nezdaniteľná časť', sum.nczd, 'nczd')} {rowCalc('Zdaniteľný základ', sum.taxable)} {rowCalc('Daň', sum.dan, 'dan', true)}
Zaplatené preddavky
setT('preddavky', v)} />
setP('preddavky', v)} />
{rowCalc('Daň na úhradu', sum.naUhradu, 'naUhradu', true)}
{showConst && (
setT('zm', v)} /> setT('nczdBase', v)} /> setT('nczdLimit', v)} /> setT('nczdK', v)} /> setT('pausalPct', v / 100)} /> setT('pausalMax', v)} /> setT('flat15Limit', v)} /> setT('rate15', v)} /> setT('dphLimitYear', v)} /> setT('dphLimitNow', v)} />
Pásma nad limit 15 %: {(ty.brackets || []).map((b, i) => {Math.round(b.rate * 100)} % {b.upTo ? `do ${fmt.num(b.upTo)}` : 'nad'})} {ty.isDefault ? '(predvolené pre tento rok, po uložení ostanú tvoje)' : '(uložené)'}
setT('note', e.target.value)} />
)}

Obrat za posledných 12 mesiacov

klzavý súčet príjmov POZD ku koncu každého mesiaca, naprieč rokmi
{sum.months.map(m =>
= limitNow ? 'over' : (limitYear && m.sum12 >= limitYear ? 'warn' : '')}`} style={{height: Math.max(2, Math.round(80 * m.sum12 / maxBar)) + 'px'}}>
{+m.month.slice(5)}
)}
{sum.months.map(m => )}
MesiacPOZDPNZD12 mesiacov
{m.month}{fmt.num(m.pozd)}{m.pnzd ? fmt.num(m.pnzd) : '—'}= limitYear ? {color:'var(--danger)', fontWeight:600} : undefined}>{fmt.num(m.sum12)}

Pohľadávky {year}

{sum.receivables} {plural(sum.receivables, 'faktúra', 'faktúry', 'faktúr')} · neuhradené {fmt.eur(sum.unpaid)}
{Toast}
); }