From 77320d203003ce8947ca023ff97999ad5df3cbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Wed, 1 Jul 2026 11:54:35 +0200 Subject: [PATCH] =?UTF-8?q?PDV=20KIR:=20za=C5=A1tita=20od=20duplog=20upisa?= =?UTF-8?q?=20dnevnog=20pazara=20maloprodaje?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SacuvajDnevniPazarKir je upisivao ručni zbirni KIR zapis za dati dan bez provere da li već postoji — za razliku od auto-KIR-a iz pojedinačnih faktura (koji ima PostojiZaIzvor zaštitu), ovde ništa nije sprečavalo duplo klikanje/ponovni unos istog dana, što bi duplo precenilo PDV osnov u zvaničnoj evidenciji. Broj dokumenta (FISK-YYYYMMDD) je već deterministički po danu, pa se koristi kao prirodni ključ za proveru. Forma sad prikazuje upozorenje i sakriva dugme za upis ako je dan već zaveden. --- internal/db/repository.go | 3 ++ internal/db/sqlite/pdv_evidencija.go | 12 +++++++ internal/handler/pdv_kir.go | 35 ++++++++++++++++--- .../stranice/pdv_kir_dnevni_pazar.html | 11 +++++- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/internal/db/repository.go b/internal/db/repository.go index 519682c..23ef318 100644 --- a/internal/db/repository.go +++ b/internal/db/repository.go @@ -70,6 +70,9 @@ type PdvKirRepository interface { ObrisiPoIzvoru(ctx context.Context, izvor string, izvorID int64) error // PostojiZaIzvor vraća true ako postoji bar jedan zapis za dati izvor i izvorID PostojiZaIzvor(ctx context.Context, izvor string, izvorID int64) (bool, error) + // PostojiPoBrojuDokumenta vraća true ako postoji zapis sa datim brojem dokumenta + // (npr. zaštita od duplog unosa dnevnog pazara "FISK-YYYYMMDD") + PostojiPoBrojuDokumenta(ctx context.Context, brojDokumenta string) (bool, error) } // PdvKprRepository definiše operacije nad knjigom primljenih računa (KPR) diff --git a/internal/db/sqlite/pdv_evidencija.go b/internal/db/sqlite/pdv_evidencija.go index 61652b5..1851c61 100644 --- a/internal/db/sqlite/pdv_evidencija.go +++ b/internal/db/sqlite/pdv_evidencija.go @@ -148,6 +148,18 @@ func (r *PdvKirRepo) PostojiZaIzvor(ctx context.Context, izvor string, izvorID i return n > 0, nil } +// PostojiPoBrojuDokumenta vraća true ako postoji KIR zapis sa datim brojem dokumenta +func (r *PdvKirRepo) PostojiPoBrojuDokumenta(ctx context.Context, brojDokumenta string) (bool, error) { + var n int + err := r.db.QueryRowContext(ctx, + "SELECT COUNT(*) FROM pdv_kir WHERE broj_dokumenta = ?", brojDokumenta, + ).Scan(&n) + if err != nil { + return false, fmt.Errorf("ntech: PdvKirRepo.PostojiPoBrojuDokumenta: %w", err) + } + return n > 0, nil +} + // izvorIliRucno vraća izvor ili podrazumevano „rucno" (izvor kolona je NOT NULL) func izvorIliRucno(izvor string) string { if izvor == "" { diff --git a/internal/handler/pdv_kir.go b/internal/handler/pdv_kir.go index 7a5b718..5c0b91e 100644 --- a/internal/handler/pdv_kir.go +++ b/internal/handler/pdv_kir.go @@ -251,9 +251,10 @@ func (h *Handler) KirBackfillProdaje(w http.ResponseWriter, r *http.Request) { // PodaciDnevniPazar su podaci za formu zbirnog KIR unosa (maloprodaja) type PodaciDnevniPazar struct { model.PodaciStranice - Datum string - Promet model.DnevniPrometKir - Ukupno float64 + Datum string + Promet model.DnevniPrometKir + Ukupno float64 + VecUpisano bool // true: za ovaj datum već postoji zbirni KIR zapis } // DnevniPazarKir prikazuje formu za potvrdu zbirnog KIR unosa za izabrani datum. @@ -281,6 +282,11 @@ func (h *Handler) DnevniPazarKir(w http.ResponseWriter, r *http.Request) { ukupno := math.Round((promet.OsnovicaOpsta+promet.PdvOpsta+promet.OsnovicaPosebna+promet.PdvPosebna)*100) / 100 + var vecUpisano bool + if brojDok, e := brojDokumentaDnevniPazar(datum); e == nil { + vecUpisano, _ = h.PdvKirRepo.PostojiPoBrojuDokumenta(r.Context(), brojDok) + } + ps := h.popuniPodaciStranice(r, podesavanja) ps.Stranica = "pdv-kir" ps.NaslovStranice = "Dnevni pazar — KIR unos" @@ -289,9 +295,20 @@ func (h *Handler) DnevniPazarKir(w http.ResponseWriter, r *http.Request) { Datum: datum, Promet: promet, Ukupno: ukupno, + VecUpisano: vecUpisano, }) } +// brojDokumentaDnevniPazar gradi deterministički broj dokumenta za zbirni KIR unos +// dnevnog pazara ("FISK-YYYYMMDD") — koristi se i za upis i za proveru duplikata. +func brojDokumentaDnevniPazar(datum string) (string, error) { + d, err := time.Parse("2006-01-02", datum) + if err != nil { + return "", err + } + return fmt.Sprintf("FISK-%s", d.Format("20060102")), nil +} + // SacuvajDnevniPazarKir prima POST i upisuje zbirni KIR zapis za dnevni pazar. func (h *Handler) SacuvajDnevniPazarKir(w http.ResponseWriter, r *http.Request) { if _, ok := h.zahtevajDozvolu(w, r, "pdv.dodaj"); !ok { @@ -302,17 +319,25 @@ func (h *Handler) SacuvajDnevniPazarKir(w http.ResponseWriter, r *http.Request) return } - datum, e1 := time.Parse("2006-01-02", strings.TrimSpace(r.FormValue("datum"))) + datumStr := strings.TrimSpace(r.FormValue("datum")) + datum, e1 := time.Parse("2006-01-02", datumStr) if e1 != nil { middleware.SetFlash(w, r, h.DB, "greska", "Datum je obavezan.") http.Redirect(w, r, "/pdv/kir/dnevni-pazar", http.StatusSeeOther) return } + brojDokumenta := fmt.Sprintf("FISK-%s", datum.Format("20060102")) + if postoji, _ := h.PdvKirRepo.PostojiPoBrojuDokumenta(r.Context(), brojDokumenta); postoji { + middleware.SetFlash(w, r, h.DB, "greska", fmt.Sprintf("Dnevni pazar za %s je već upisan u KIR.", datum.Format("02.01.2006."))) + http.Redirect(w, r, "/pdv/kir/dnevni-pazar?datum="+datumStr, http.StatusSeeOther) + return + } + z := model.PdvKir{ DatumPrometa: datum, DatumKnjizenja: datum, - BrojDokumenta: fmt.Sprintf("FISK-%s", datum.Format("20060102")), + BrojDokumenta: brojDokumenta, KupacNaziv: "Promet fizičkim licima", OsnovicaOpsta: parsiraIznos(r.FormValue("osnovica_opsta")), PdvOpsta: parsiraIznos(r.FormValue("pdv_opsta")), diff --git a/web/templates/stranice/pdv_kir_dnevni_pazar.html b/web/templates/stranice/pdv_kir_dnevni_pazar.html index 34c89b7..d4d3d46 100644 --- a/web/templates/stranice/pdv_kir_dnevni_pazar.html +++ b/web/templates/stranice/pdv_kir_dnevni_pazar.html @@ -78,7 +78,16 @@ - {{if gt .Promet.BrojNaloga 0}} + {{if .VecUpisano}} +
+
+
⚠ Već upisano
+
Dnevni pazar za {{.Datum}} je već upisan u KIR. Ponovni upis bi duplirao promet za ovaj dan.
+
+
+ {{end}} + + {{if and (gt .Promet.BrojNaloga 0) (not .VecUpisano)}}