PDV: profil firme blokira nemoguće kombinacije, stope iz šifarnika umesto hardkoda

- Podešavanja: nemoguća kombinacija (samo evidencija + PDV/fiskalizacija=da)
  se sad odbija i na serveru, ne samo u brauzeru (validirajProfilFirme).
- Servis: fiskalni račun/refund više ne iskazuje PDV kad firma nije PDV
  obveznik (stavkeFiskalnogServisa nulira stopu, isto kao Prodaja).
- Avans: uklonjena hardkodovana konstanta 20% PDV — stopa se sad uzima iz
  šifarnika (Podešavanja → Kalkulacija i PDV) ili je 0 kad firma nije
  obveznik.
- fiskal.NapraviZahtev: uklonjen fallback koji je prepisivao namerno
  postavljenu 0% stopu nazad na 20% (poništavao je zaštitu Prodaje za
  ne-PDV firme).
- Forme (usluge, artikli) i validacija PDV stope u prodaji sad koriste
  šifarnik umesto literala 20 / 0,10,20.

Detaljna pravna analiza i status svake stavke u docs/Greške.md (van git-a).
This commit is contained in:
2026-07-03 01:50:57 +02:00
parent 85a2ee1b64
commit 524c6de6ba
11 changed files with 174 additions and 57 deletions
+27
View File
@@ -285,6 +285,20 @@ func validirajMaticniBroj(broj string) string {
return ""
}
// validirajProfilFirme proverava da li je kombinacija pravnog/poreskog statusa
// pravno moguća — vidi docs/Greške.md §1. „Samo evidencija” gasi ceo zakonski
// sloj, pa dok je firma u tom režimu ne postoji osnov da bude PDV obveznik
// niti da izdaje fiskalne račune.
func validirajProfilFirme(rezim, pdvObveznik, fiskalizacija string) string {
if rezim != "samo_evidencija" {
return ""
}
if pdvObveznik == "da" || fiskalizacija == "da" {
return "Režim „Samo evidencija” ne dozvoljava PDV obveznika ni izdavanje fiskalnih računa — prebacite firmu na režim „Pun” ako stvarno posluje."
}
return ""
}
// SacuvajPodesavanja prima POST i čuva podešavanja u bazu
func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
if _, ok := h.zahtevajDozvolu(w, r, "podesavanja.izmeni"); !ok {
@@ -320,6 +334,19 @@ func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
return
}
if _, jeFirmaSekcija := r.Form["_sekcija_firma"]; jeFirmaSekcija {
greska := validirajProfilFirme(r.FormValue("firma_rezim"), r.FormValue("firma_pdv_obveznik"), r.FormValue("firma_fiskalizacija"))
if greska != "" {
middleware.SetFlash(w, r, h.DB, "greska", greska)
sledeci := "/podesavanja"
if r.FormValue("_next") == "/admin/podesavanja/opste" {
sledeci = "/admin/podesavanja/opste"
}
http.Redirect(w, r, sledeci, http.StatusSeeOther)
return
}
}
polja := map[string]string{
"naziv_firme": r.FormValue("naziv_firme"),
"podnazlov": r.FormValue("podnazlov"),