Servis: upozorenje i retry fiskalizacije kad ESIR nije dostupan pri preuzimanju

This commit is contained in:
2026-06-30 22:47:26 +02:00
parent 80d7dd69f1
commit c971b5d075
3 changed files with 75 additions and 0 deletions
+1
View File
@@ -389,6 +389,7 @@ func main() {
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "servis.pregled")).Get("/servis/{id}/nalepnica", h.StampaNalepnice)
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "servis.pregled")).Get("/servis/{id}/garantni-list", h.StampaGarantnog)
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "servis.pregled")).Get("/servis/{id}/eskalacioni-list", h.StampaEskalacionogLista)
r.With(doz("servis.izmeni")).Post("/servis/{id}/fiskalizuj", h.RetryFiskalizacija)
r.With(doz("servis.izmeni")).Post("/servis/{id}/status", h.PromeniStatus)
r.With(doz("servis.izmeni")).Post("/servis/{id}/garancija", h.AzurirajGaranciju)
r.With(doz("servis.izmeni")).Post("/servis/{id}/garancija-dana", h.AzurirajGarancijaDana)
+57
View File
@@ -83,6 +83,7 @@ type PodaciDetaljiNaloga struct {
SviStatusi []string
FiskalniRacun *model.FiskalniRacun // nil ako nije fiskalizovano
RokPodizanja *time.Time // DatumZavrsetka + 30 dana; nil dok nije završeno
FiskalGreska bool // true: fiskalizacija aktivna, status Preuzeto, ali nema fiskalnog računa
}
// Servis renderuje listu servisnih naloga sa opcionom pretragom i filterom statusa
@@ -744,6 +745,12 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) {
} else if err != nil {
slog.Error("greška pri učitavanju fiskalnog računa za servis", "servis_id", id, "error", err)
}
// fiskalna greška: modul aktivan, nalog preuzet, ali nema fiskalnog računa
if h.modulUkljucen(r.Context(), config.ModulFiskalizacija) &&
nalog.Status == model.StatusPreuzeto &&
podaci.FiskalniRacun == nil {
podaci.FiskalGreska = true
}
h.renderujTemplate(w, "servis_detalji", podaci)
}
@@ -2362,6 +2369,56 @@ func (h *Handler) fiskalizujServis(ctx context.Context, servisID int64, klijent
slog.Error("greška pri čuvanju fiskalnog računa za servis", "servis_id", servisID, "error", err)
}
}
// RetryFiskalizacija pokušava ponovo da izda fiskalni račun za nalog čija je
// prethodna fiskalizacija pala. Bezbedno za ponovni poziv — proverava da račun
// još uvek ne postoji pre slanja zahteva ka ESIR/PFR.
func (h *Handler) RetryFiskalizacija(w http.ResponseWriter, r *http.Request) {
if _, ok := h.zahtevajDozvolu(w, r, "servis.izmeni"); !ok {
return
}
id, err := parseID(chi.URLParam(r, "id"))
if err != nil {
http.Error(w, "Neispravan ID naloga", http.StatusBadRequest)
return
}
// provjeri da fiskal još nije izdat (zaštita od duplikata)
if fr, _ := h.FiskalRepo.DohvatiPoServisu(r.Context(), id); fr != nil {
middleware.SetFlash(w, r, h.DB, "uspeh", "Fiskalni račun već postoji.")
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
return
}
nalog, err := h.ServisRepo.DohvatiID(r.Context(), id)
if err != nil || nalog.Status != model.StatusPreuzeto {
http.Error(w, "Nalog nije u statusu Preuzeto", http.StatusBadRequest)
return
}
if nalog.Naplaceno <= 0 {
middleware.SetFlash(w, r, h.DB, "greska", "Iznos naplate je 0 — fiskalizacija nije moguća.")
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
return
}
klijent := h.fiskalKlijent()
if klijent == nil {
middleware.SetFlash(w, r, h.DB, "greska", "Fiskalni servis nije dostupan. Proverite vezu sa ESIR/PFR.")
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
return
}
h.fiskalizujServis(r.Context(), id, klijent, nalog.NacinPlacanja, nalog.Naplaceno)
// provjeri da li je uspelo
if fr, _ := h.FiskalRepo.DohvatiPoServisu(r.Context(), id); fr != nil {
middleware.SetFlash(w, r, h.DB, "uspeh", "Fiskalni račun izdat.")
} else {
middleware.SetFlash(w, r, h.DB, "greska", "Fiskalizacija nije uspela. Proverite vezu sa ESIR/PFR i pokušajte ponovo.")
}
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
}
func (h *Handler) StampaFiskalnog(w http.ResponseWriter, r *http.Request) {
id, err := parseID(chi.URLParam(r, "id"))
if err != nil {
@@ -1000,6 +1000,23 @@
</div>
{{end}}
{{if .FiskalGreska}}
<div class="kartica detalji-kartica animiraj" style="border:1.5px solid #f59e0b;background:color-mix(in srgb,#fef3c7 60%,var(--pozadina));">
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
<div style="flex:1;">
<div style="font-size:14px;font-weight:600;color:#92400e;margin-bottom:4px;">⚠ Fiskalni račun nije izdat</div>
<div style="font-size:13px;color:#78350f;">Veza sa ESIR/PFR serverom nije bila dostupna pri preuzimanju. Status naloga je promenjen, ali fiskalni račun nije poslat.</div>
</div>
{{if index .Dozvole "servis.izmeni"}}
<form method="POST" action="/servis/{{.Nalog.ID}}/fiskalizuj">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit" class="btn-primarno" style="background:#d97706;border-color:#d97706;white-space:nowrap;">Pokušaj ponovo</button>
</form>
{{end}}
</div>
</div>
{{end}}
<!-- zona za brisanje -->
{{/* Brisanje je moguće samo dok je „Primljeno" (greška pri unosu); čim uđe u proceduru naplaćuje se dijagnostika */}}
{{if eq .Nalog.Status "Primljeno"}}