- migracija 102: indeksi na FK kolonama (stavke_prodaje, servisni_delovi,
servisni_potrazivani_delovi, magacinske_promene, stavke_nabavke, pdv_kir,
pdv_kpr) — potvrđeno kreiranje i idempotentnost
- BrojKriticnihZaliha/KriticneZalihe filtriraju samo proizvode i aktivne
artikle, usklađeno sa ArtikalRepo.Lista(SamoKriticni)
- url.QueryEscape na query string u magacin.go/klijent.go (paginacija)
- TestFiskalizacije/BeStatus vraćaju generičku poruku, detalj u slog
- SetFlash loguje grešku umesto tihog ignorisanja
- os.WriteFile/os.MkdirAll u main.go proveravaju grešku
- dummyHash generisanje panikuje na startu ako bcrypt ikad zakaže
(umesto tihog sloma anti-enumeracije)
- PrihvatiPredlozene proverava redovi.Err()
- /healthz endpoint (DB ping)
- hx-boost na "Osveži" linkovima (blokirane_ip, fiskal_pazar)
- MaxBytesReader (4KB) na javne /status/{token}/* POST rute
- komentar u auth.go zašto postoje dva flash mehanizma (namerno, ne spojeno)
Provereno: jePrivatnaAdresa ne radi DNS lookup (nema net.LookupIP u repou),
pa DNS-rebinding nalaz iz pregleda nije primenljiv na trenutni kod.
109 lines
6.5 KiB
HTML
109 lines
6.5 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "naslov"}}Dnevni fiskalni presek — NTech{{end}}
|
|
|
|
{{define "sadrzaj"}}
|
|
<div class="stranica-stack" style="width:100%;max-width:720px;">
|
|
|
|
<div class="kartica animiraj" style="margin-bottom:16px;">
|
|
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Dnevni fiskalni presek</span>
|
|
</div>
|
|
|
|
{{if .Greska}}
|
|
<div class="fisk-status greska" style="margin-bottom:16px;">✗ {{.Greska}}</div>
|
|
{{end}}
|
|
|
|
{{if .Presek}}
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:16px;">
|
|
Kumulativni promet od poslednjeg (opcionog) reseta brojača: <strong>{{.Presek.StartOfPeriod}}</strong> do sada.
|
|
Za tačan izveštaj za određeni dan/period koristi „Preuzmi izveštaj za period" ispod.
|
|
</div>
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px;">
|
|
<div style="padding:14px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:10px;">
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);">Broj računa</div>
|
|
<div style="font-size:22px;font-weight:700;color:var(--tekst-glavni);">{{.Presek.InvoiceCount}}</div>
|
|
</div>
|
|
<div style="padding:14px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:10px;">
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);">Ukupan promet</div>
|
|
<div style="font-size:22px;font-weight:700;color:var(--tekst-glavni);">{{dinari .Presek.Total}} din</div>
|
|
</div>
|
|
<div style="padding:14px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:10px;">
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);">Gotovina</div>
|
|
<div style="font-size:18px;font-weight:600;color:var(--tekst-glavni);">{{dinari .Presek.TotalCash}} din</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{if .Presek.TotalByPaymentType}}
|
|
<div style="margin-bottom:16px;">
|
|
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);margin-bottom:8px;">Po vrsti plaćanja</div>
|
|
{{range .Presek.TotalByPaymentType}}
|
|
<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:0.5px solid var(--ivica);font-size:13px;">
|
|
<span style="color:var(--tekst-sporedni);">{{.PaymentType}}</span>
|
|
<span style="color:var(--tekst-glavni);">{{dinari .Amount}} din</span>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Presek.TotalByTax}}
|
|
<div style="margin-bottom:16px;">
|
|
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);margin-bottom:8px;">Po poreskim stopama</div>
|
|
{{range .Presek.TotalByTax}}
|
|
<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:0.5px solid var(--ivica);font-size:13px;">
|
|
<span style="color:var(--tekst-sporedni);">{{.Label}} ({{.Rate}}%)</span>
|
|
<span style="color:var(--tekst-glavni);">{{dinari .Amount}} din</span>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Presek.TotalByCashier}}
|
|
<div style="margin-bottom:16px;">
|
|
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);margin-bottom:8px;">Po kasiru</div>
|
|
{{range .Presek.TotalByCashier}}
|
|
<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:0.5px solid var(--ivica);font-size:13px;">
|
|
<span style="color:var(--tekst-sporedni);">{{.Name}}</span>
|
|
<span style="color:var(--tekst-glavni);">{{dinari .Amount}} din</span>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{if .FiskalPodesen}}
|
|
<div style="padding-top:12px;border-top:0.5px solid var(--ivica);">
|
|
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);margin-bottom:8px;">Preuzmi izveštaj za period</div>
|
|
<form method="POST" action="/fiskal/pazar/izvestaj" data-full-reload style="display:flex;gap:10px;flex-wrap:wrap;align-items:end;margin-bottom:16px;">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div>
|
|
<label style="display:block;font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Od datuma</label>
|
|
<input type="date" name="od_datuma" value="{{.Danas}}" class="polje-forme" style="font-size:13px;padding:7px 10px;">
|
|
</div>
|
|
<div>
|
|
<label style="display:block;font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Do datuma</label>
|
|
<input type="date" name="do_datuma" value="{{.Danas}}" class="polje-forme" style="font-size:13px;padding:7px 10px;">
|
|
</div>
|
|
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;">Preuzmi izveštaj</button>
|
|
</form>
|
|
|
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
|
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/fiskal/pazar" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;">Osveži</a>
|
|
|
|
{{if index .Dozvole "fiskal.zakljucenje"}}
|
|
<form method="POST" action="/fiskal/pazar/zakljuci" style="display:inline;" data-full-reload
|
|
onsubmit="return confirm('Resetovati brojače na ekranu? Ovo NIJE zakonska obaveza — izveštaj po periodu radi nezavisno od ovoga. Samo svodi prikaz Promet od poslednjeg preseka na nulu.')">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;color:var(--tekst-sporedni);">Resetuj brojače (opciono)</button>
|
|
</form>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
</div>
|
|
{{end}}
|