Knjigovodstvo i fiskalizacija: dashboard upozorenje za praznine, KPO dozvole, pojednostavljen storno, ispravke verifikacije i kasira
- Dashboard kartica prikazuje naloge bez KIR/KPO/fiskalnog upisa i sumnjive duplikate (double-submit), sa zaštitom od automatskog dupliranja prihoda pri bulk dopuni - Registrovane nedostajuće KPO dozvole (kpo.pregled/dodaj/obrisi) — modul je bio potpuno nedostupan - Uklonjen suvišan/nefunkcionalan 'Ukloni nalog' (duplirao Storno bez stvarne razlike); Storno u listi prodaje sad vodi direktno na formu - Kasir na fiskalnom računu koristi ime prijavljenog korisnika umesto fiksnog podešavanja - Fiskalni računi za nalog uvek prikazuju najnoviji zapis (original vs. refund posle storna) - Verifikaciona stranica (/v/) jasno označena kao lokalna test simulacija, ne prava provera kod PURS-a; dodat prikaz kusura - Mock brojač fiskalnih računa (kartica emulator) sad preživljava restart servera
This commit is contained in:
+20
-12
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
appdb "ntech/internal/db"
|
||||
"ntech/internal/db/sqlite"
|
||||
"ntech/internal/middleware"
|
||||
"ntech/internal/model"
|
||||
@@ -161,24 +160,28 @@ func (h *Handler) KpoBackfill(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
var kreirano, preskoceno int
|
||||
var kreirano, preskoceno, sumnjivo int
|
||||
|
||||
// prodajni nalozi
|
||||
nalozi, err := h.ProdajaRepo.Lista(ctx, appdb.ProdajaFilter{})
|
||||
nalozi, prodajaPostoji, prodajaKandidati, err := h.kpoKandidatiProdaje(ctx)
|
||||
if err != nil {
|
||||
http.Error(w, "Greška pri učitavanju prodaje", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
prodajaDuplikati := sumnjiviDuplikati(prodajaKandidati)
|
||||
for _, nd := range nalozi {
|
||||
if nd.Stornirano {
|
||||
preskoceno++
|
||||
continue
|
||||
}
|
||||
postoji, _ := h.KpoRepo.PostojiZaIzvor(ctx, "prodaja", nd.ID)
|
||||
if postoji {
|
||||
if prodajaPostoji[nd.ID] {
|
||||
preskoceno++
|
||||
continue
|
||||
}
|
||||
if prodajaDuplikati[nd.ID] {
|
||||
sumnjivo++
|
||||
continue
|
||||
}
|
||||
z := model.KpoZapis{
|
||||
DatumPrometa: nd.Datum,
|
||||
BrojDokumenta: nd.BrojNaloga,
|
||||
@@ -196,18 +199,19 @@ func (h *Handler) KpoBackfill(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// naplaćeni servisni nalozi
|
||||
servisNalozi, err := h.ServisRepo.Lista(ctx, "", "")
|
||||
naplaceni, servisPostoji, servisKandidati, nenaplaceniBroj, err := h.kpoKandidatiServisa(ctx)
|
||||
if err != nil {
|
||||
slog.Error("kpo backfill: greška pri učitavanju servisa", "error", err)
|
||||
} else {
|
||||
for _, sn := range servisNalozi {
|
||||
if sn.Status != model.StatusPreuzeto || sn.Naplaceno == 0 {
|
||||
preskoceno += nenaplaceniBroj
|
||||
servisDuplikati := sumnjiviDuplikati(servisKandidati)
|
||||
for _, sn := range naplaceni {
|
||||
if servisPostoji[sn.ID] {
|
||||
preskoceno++
|
||||
continue
|
||||
}
|
||||
postoji, _ := h.KpoRepo.PostojiZaIzvor(ctx, "servis", sn.ID)
|
||||
if postoji {
|
||||
preskoceno++
|
||||
if servisDuplikati[sn.ID] {
|
||||
sumnjivo++
|
||||
continue
|
||||
}
|
||||
datum := sn.DatumPrijema
|
||||
@@ -231,6 +235,10 @@ func (h *Handler) KpoBackfill(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
middleware.SetFlash(w, r, h.DB, "uspeh", fmt.Sprintf("Backfill završen: %d novih KPO unosa, %d preskočeno.", kreirano, preskoceno))
|
||||
poruka := fmt.Sprintf("Backfill završen: %d novih KPO unosa, %d preskočeno.", kreirano, preskoceno)
|
||||
if sumnjivo > 0 {
|
||||
poruka += fmt.Sprintf(" %d sumnjivih duplikata NIJE upisano — proveri ručno.", sumnjivo)
|
||||
}
|
||||
middleware.SetFlash(w, r, h.DB, "uspeh", poruka)
|
||||
http.Redirect(w, r, "/kpo", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user