From edba23ae5031b8cb6f7aa9015ad98b4e82c55f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Fri, 3 Jul 2026 02:22:13 +0200 Subject: [PATCH] Storno kroz modal + ispravka about:blank u fiskalnom tabu Prodaje MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Servis i Prodaja: storniranje naloga sad ide kroz modal — dugme 'Storniraj nalog' prvo traži potvrdu, tek onda otvara modal sa poljem za PIB/JMBG (kad je potrebno za refund); dugme 'Potvrdi storno' ostaje zaključano dok se polje ne popuni. Posle uspešnog storna modal se gasi i sadržaj stranice se osvežava (data-refresh=#sadrzaj). - Dnevni pazar (Fiskalni presek): link u sidebaru i sve tri rute (FiskalniPazar, ZakljuciFiskalniDan, FiskalniIzvestaj) sad proveravaju modul fiskalizacije, ne samo RBAC dozvolu i tehničku dostupnost PFR-a. - Prodaja: čekboks 'Prikaži fiskalni račun' se više ne nudi kad firma ne fiskalizuje, a pripremiFiskalniTab() više ne otvara prazan tab u tom slučaju — do sad je ostajao trajno na about:blank jer odredišna stranica nikad nije imala fiskalni račun da ga popuni. Dodata i odbrana za slučaj kad fiskalizacija jeste uključena ali PFR nije dostupan (zatvara osiroteli tab umesto about:blank). Detalji u docs/Greške.md (van git-a). --- internal/handler/fiskal_pazar.go | 17 +++++ web/static/js/ntech.js | 4 + web/templates/komponente/sidebar.html | 2 +- web/templates/stranice/prodaja_detalji.html | 74 +++++++++++++++--- web/templates/stranice/prodaja_forma.html | 1 + web/templates/stranice/servis_detalji.html | 84 +++++++++++++++++---- 6 files changed, 157 insertions(+), 25 deletions(-) diff --git a/internal/handler/fiskal_pazar.go b/internal/handler/fiskal_pazar.go index 94db409..28e0bc9 100644 --- a/internal/handler/fiskal_pazar.go +++ b/internal/handler/fiskal_pazar.go @@ -9,6 +9,7 @@ import ( "time" "unicode" + "ntech/internal/config" ntechsqlite "ntech/internal/db/sqlite" "ntech/internal/fiskal" "ntech/internal/middleware" @@ -56,6 +57,12 @@ func (h *Handler) FiskalniPazar(w http.ResponseWriter, r *http.Request) { podaci := PodaciFiskalniPazar{PodaciStranice: ps, Danas: time.Now().Format("2006-01-02")} + if !h.modulUkljucen(r.Context(), config.ModulFiskalizacija) { + podaci.Greska = "Fiskalizacija nije uključena u profilu firme — Podešavanja → Opšte → Pravni i poreski status." + h.renderujTemplate(w, "fiskal_pazar", podaci) + return + } + klijent := h.fiskalKlijent() if klijent == nil { podaci.Greska = "Fiskalizacija nije podešena — unesi URL PFR servera u Podešavanja → Fiskalizacija." @@ -82,6 +89,11 @@ func (h *Handler) ZakljuciFiskalniDan(w http.ResponseWriter, r *http.Request) { if _, ok := h.zahtevajDozvolu(w, r, "fiskal.zakljucenje"); !ok { return } + if !h.modulUkljucen(r.Context(), config.ModulFiskalizacija) { + middleware.SetFlash(w, r, h.DB, "greska", "Fiskalizacija nije uključena u profilu firme.") + http.Redirect(w, r, "/fiskal/pazar", http.StatusSeeOther) + return + } klijent := h.fiskalKlijent() if klijent == nil { middleware.SetFlash(w, r, h.DB, "greska", "Fiskalizacija nije podešena.") @@ -110,6 +122,11 @@ func (h *Handler) FiskalniIzvestaj(w http.ResponseWriter, r *http.Request) { http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest) return } + if !h.modulUkljucen(r.Context(), config.ModulFiskalizacija) { + middleware.SetFlash(w, r, h.DB, "greska", "Fiskalizacija nije uključena u profilu firme.") + http.Redirect(w, r, "/fiskal/pazar", http.StatusSeeOther) + return + } klijent := h.fiskalKlijent() if klijent == nil { middleware.SetFlash(w, r, h.DB, "greska", "Fiskalizacija nije podešena.") diff --git a/web/static/js/ntech.js b/web/static/js/ntech.js index dc39160..3349eaa 100644 --- a/web/static/js/ntech.js +++ b/web/static/js/ntech.js @@ -226,6 +226,10 @@ document.addEventListener('alpine:init', () => { this.artikliOpcije = window._ntechArtikli || [] this.klijenti = window._ntechKlijenti || [] this.pdvObveznik = window._ntechPdvObveznik === true + // ako firma ne fiskalizuje, ne otvaramo ni prazan tab u pripremiFiskalniTab() — + // stranica detalja nikad neće imati FiskalniRacun da ga popuni, pa bi ostao + // trajno na about:blank (v. docs/Greške.md) + this.prikaziRacun = window._ntechFiskalizacija === true this.isMobile = window.matchMedia('(max-width: 768px)').matches window.matchMedia('(max-width: 768px)').addEventListener('change', e => { this.isMobile = e.matches diff --git a/web/templates/komponente/sidebar.html b/web/templates/komponente/sidebar.html index 8ca2c60..efd77c1 100644 --- a/web/templates/komponente/sidebar.html +++ b/web/templates/komponente/sidebar.html @@ -100,7 +100,7 @@ {{/* Knjigovodstvo — grupa: KIR/KPR/Obračun (modul „pdv") + Nivelacije (dozvola izmene cena) */}} {{$pdvVid := and (index .Moduli "pdv") (index .Dozvole "pdv.pregled")}} {{$kpoVid := and (index .Moduli "kpo") (index .Dozvole "kpo.pregled")}} - {{$pazarVid := index .Dozvole "fiskal.pazar"}} + {{$pazarVid := and (index .Moduli "fiskalizacija") (index .Dozvole "fiskal.pazar")}} {{$knjVid := or $pdvVid $kpoVid $pazarVid (index .Dozvole "artikal.izmeni")}} {{if $knjVid}} {{$knjAktivan := or (eq .Stranica "nivelacije") (eq .Stranica "kpo") (eq .Stranica "pdv-kir") (eq .Stranica "pdv-kpr") (eq .Stranica "pdv-obracun") (eq .Stranica "fiskal-pazar")}} diff --git a/web/templates/stranice/prodaja_detalji.html b/web/templates/stranice/prodaja_detalji.html index a109122..15e2fe9 100644 --- a/web/templates/stranice/prodaja_detalji.html +++ b/web/templates/stranice/prodaja_detalji.html @@ -252,18 +252,58 @@ Storno vraća sve artikle na stanje u magacinu. Nalog ostaje u evidenciji sa oznakom storniran. -
- - - {{if .PotrebnaIdentKupca}} - - {{end}} - -
+ + +
+

Storniranje naloga {{.Nalog.BrojNaloga}}

+ +
+
+
+ +
+ + +
+ {{if .PotrebnaIdentKupca}} +
+ + +
+ {{end}} + +
+
+
+ {{end}} {{if .FiskalniRacun}} @@ -296,6 +336,18 @@ } })(); + {{else}} + {{end}} {{if .FiskalGreska}} diff --git a/web/templates/stranice/prodaja_forma.html b/web/templates/stranice/prodaja_forma.html index aab5647..cf13464 100644 --- a/web/templates/stranice/prodaja_forma.html +++ b/web/templates/stranice/prodaja_forma.html @@ -21,6 +21,7 @@ var _ntechArtikli = {{.ArtikliJSON}}; var _ntechKlijenti = {{.KlijentiJSON}}; var _ntechPdvObveznik = {{if index .Moduli "pdv"}}true{{else}}false{{end}}; + var _ntechFiskalizacija = {{if index .Moduli "fiskalizacija"}}true{{else}}false{{end}};
diff --git a/web/templates/stranice/servis_detalji.html b/web/templates/stranice/servis_detalji.html index b9f1bc8..21c9e8a 100644 --- a/web/templates/stranice/servis_detalji.html +++ b/web/templates/stranice/servis_detalji.html @@ -214,13 +214,27 @@ f.addEventListener('submit', function(){ var cb = f.querySelector('#prikazi-racun'); if (!cb || !cb.checked) return; + // otvori prazan imenovani tab SINHRONO unutar submit-a (očuvan user + // gesture) — isti obrazac kao pripremiFiskalniTab u Prodaji (ntech.js). + // Naplata ovde ide preko AJAX-a (data-refresh), pa se popunjava tek + // kad MutationObserver javi da je swap gotov — a to je već van user + // gesture-a, pa direktan window.open() u tom trenutku brauzer tretira + // kao blokiran popup i otvara about:blank (v. docs/Greške.md). + var tab = window.open('', 'ntech-fiskalni-tab'); var sadrzaj = document.getElementById('sadrzaj'); - if (!sadrzaj) return; + if (!sadrzaj) { + if (tab) tab.close(); + return; + } var observer = new MutationObserver(function(){ observer.disconnect(); // jedan prozor — server u istu stranicu ubacuje i povraćaj viška // avansa (ako postoji), da brauzer ne blokira drugi popup - window.open('/servis/{{.Nalog.ID}}/fiskalni-racun', '_blank'); + if (tab && !tab.closed) { + tab.location.href = '/servis/{{.Nalog.ID}}/fiskalni-racun'; + } else { + window.open('/servis/{{.Nalog.ID}}/fiskalni-racun', '_blank'); + } }); observer.observe(sadrzaj.parentElement, {childList: true}); }); @@ -1124,19 +1138,63 @@ Storno vraća ugrađene delove na stanje u magacinu. Nalog ostaje u evidenciji sa oznakom storniran.
-
- - - {{if .PotrebnaIdentKupca}} - - {{end}} - -
+ + +
+

Storniranje naloga {{.Nalog.BrojNaloga}}

+ +
+
+
+ +
+ + +
+ {{if .PotrebnaIdentKupca}} +
+ + +
+ {{end}} + +
+
+
+ {{end}}