// vat-page.jsx — Облік ПДВ: реєстр податкових накладних, зобов'язання vs кредит, // незакриті позиції, ПДВ до сплати. Ручний ввід + гачок під інтеграцію (Вчасно/ДПС). function VatStatusTag({ status }) { const s = window.VAT_INV_STATUS[status]; if (!s) return null; return {s.label}; } function VatAddBar({ periodId, onAdd, onClose }) { const [kind, setKind] = React.useState("in"); const [f, setF] = React.useState({ date: periodId + "-", number: "", party: "", edrpou: "", base: "" }); const set = (k, v) => setF(prev => ({ ...prev, [k]: v })); const statusOpts = kind === "out" ? [["registered", "Зареєстрована"], ["pending", "Очікує реєстрації"], ["overdue", "Прострочена"]] : [["credit", "У кредит"], ["awaiting", "Очікує постачальника"], ["no_vat", "Без ПДВ (ЄП)"], ["blocked", "Заблокована"]]; const [status, setStatus] = React.useState(statusOpts[0][0]); React.useEffect(() => { setStatus(statusOpts[0][0]); }, [kind]); const base = parseFloat(String(f.base).replace(/\s/g, "").replace(",", ".")); const valid = f.number.trim() && f.party.trim() && !isNaN(base) && base > 0; const submit = () => { if (!valid) return; onAdd({ id: "x-" + Date.now(), period: periodId, kind, date: f.date && f.date.length > 7 ? f.date : periodId + "-15", number: f.number.trim(), party: f.party.trim(), edrpou: f.edrpou.trim(), base: Math.round(base), status, basis: "Ручний ввід", obj: null, }); onClose(); }; return (
ПДВ 20%: {!isNaN(base) && base > 0 ? window.formatMoney(window.vatOf(Math.round(base))) : "—"} ₴
); } function VatPage({ role }) { const periods = window.VAT_PERIODS; const [periodId, setPeriodId] = React.useState(periods[0].id); const [filter, setFilter] = React.useState("all"); // all | out | in const [extra, setExtra] = React.useState([]); const [adding, setAdding] = React.useState(false); const period = periods.find(p => p.id === periodId) || periods[0]; const extraForPeriod = extra.filter(r => r.period === periodId); const sum = window.vatSummary(periodId, extraForPeriod); let rows = sum.rows; if (filter !== "all") rows = rows.filter(r => r.kind === filter); rows = [...rows].sort((a, b) => (a.date < b.date ? -1 : 1)); const m = window.formatMoney; const isPaid = period.status === "paid"; // незакриті позиції const alerts = []; if (sum.cntUnreg > 0) alerts.push({ tone: "late", icon: "alert", title: `${sum.cntUnreg} вихідних ПН не зареєстровано в ЄРПН`, sub: `Зобов'язання на ${m(sum.outputUnreg)} ₴ ПДВ. Ризик штрафу і блокування податкового кредиту в покупця — зареєструвати в межах строку.` }); if (sum.cntStuck > 0) alerts.push({ tone: "amber", icon: "clock", title: `${sum.cntStuck} вхідних ПН очікують реєстрації постачальником`, sub: `Кредит ${m(sum.inputStuck)} ₴ поки недоступний. Після реєстрації ПДВ до сплати зменшиться на цю суму.` }); if (!isPaid) alerts.push({ tone: sum.payable > 0 ? "amber" : "live", icon: "coins", title: `ПДВ до сплати за ${period.label}: ${m(sum.payable)} ₴`, sub: `Граничний строк сплати — ${window.formatDate(period.payDue)}. Декларацію ще не подано.` }); return (

ПДВ

ТОВ · загальна система · платник ПДВ 20% {period.label} {isPaid ? Сплачено {window.formatDate(period.paidAt)} : Період відкритий}
{/* Підсумок */}
Податкове зобов'язання
{m(sum.output)}
вихідний ПДВ за період
Податковий кредит
{m(sum.input)}
вхідний ПДВ {sum.inputStuck > 0 ? `· ще ${m(sum.inputStuck)} ₴ завис` : "(зареєстровані)"}
ПДВ до сплати
0 ? "var(--ink)" : "var(--c-green-deep)" }}>{m(sum.payable)}
зобов'язання − кредит
Незакрите
0 ? "var(--late)" : "var(--c-green-deep)" }}>{sum.cntUnreg + sum.cntStuck}
{(sum.cntUnreg + sum.cntStuck) > 0 ? "накладних потребують дії" : "усі накладні в порядку"}
{/* Незакриті позиції */} {alerts.length > 0 && (

Незакриті позиції

{alerts.map((a, i) => (
{a.title}
{a.sub}
))}
)} {/* Тулбар реєстру */}
{[["all", "Усі"], ["out", "Вихідні"], ["in", "Вхідні"]].map(([id, l]) => ( ))}
{periods.map(p => ( ))}
{!isPaid && }
{adding && setExtra(prev => [...prev, r])} onClose={() => setAdding(false)} />} {/* Реєстр податкових накладних */} {rows.map(r => { const vat = window.vatOf(r.base); return ( ); })}
Тип Дата № ПН Контрагент Підстава База ПДВ 20% Сума з ПДВ Статус
{r.kind === "out" ? "Вих" : "Вх"} {window.formatDate(r.date)} {r.number}
{r.party}
{r.edrpou}
{r.basis} {m(r.base)} {r.status === "no_vat" ? "—" : m(vat)} {m(r.base + (r.status === "no_vat" ? 0 : vat))}
Усього {filter === "all" ? "" : filter === "out" ? "вихідних" : "вхідних"} · {rows.length} ПН {m(rows.reduce((s, r) => s + r.base, 0))} {m(rows.reduce((s, r) => s + (r.status === "no_vat" ? 0 : window.vatOf(r.base)), 0))}
Як це працює. Зобов'язання виникає за датою першої події (відвантаження/оплата), незалежно від реєстрації ПН. У кредит потрапляють лише зареєстровані вхідні накладні — від постачальників без ПДВ (єдиний податок) кредиту немає. ПДВ до сплати = зобов'язання − кредит. Реєстр можна вести вручну вже зараз; підтягування з Вчасно / кабінету ДПС — на бекенді. Ці суми живлять рядок ПДВ у звіті P&L.
); } window.VatPage = VatPage;