Usluge: zaseban modul (cenovnik usluga)
Usluga je zaseban entitet, ne artikal: svoja tabela usluge (naziv, šifra, jedinica mere, cena, PDV, opis), repo, handleri i forma. Auto-šifra USL-001…999, jedinica mere (usluga/sat/kom). Bez nabavne/prodajne cene, dobavljača, lagera i marže. /usluge lista + CRUD; stari tip-filter handler uklonjen iz magacina.
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"ntech/internal/db"
|
||||
"ntech/internal/db/sqlite"
|
||||
"ntech/internal/model"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// PodaciUsluga su podaci za listu usluga
|
||||
type PodaciUsluga struct {
|
||||
model.PodaciStranice
|
||||
Usluge []model.Usluga
|
||||
Pretraga string
|
||||
Sacuvano bool
|
||||
Obrisan bool
|
||||
}
|
||||
|
||||
// PodaciFormeUsluge su podaci za formu nove/izmenjene usluge
|
||||
type PodaciFormeUsluge struct {
|
||||
model.PodaciStranice
|
||||
Usluga model.Usluga
|
||||
Kategorije []string // postojeće kategorije za predlog (datalist)
|
||||
Greska string
|
||||
Izmena bool
|
||||
}
|
||||
|
||||
// Usluge renderuje listu usluga (cenovnik usluga)
|
||||
func (h *Handler) Usluge(w http.ResponseWriter, r *http.Request) {
|
||||
podesavanja, err := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||
if err != nil {
|
||||
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
pretraga := r.URL.Query().Get("pretraga")
|
||||
usluge, err := h.UslugeRepo.Lista(r.Context(), db.UslugaFilter{Pretraga: pretraga})
|
||||
if err != nil {
|
||||
http.Error(w, "Greška pri učitavanju usluga", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
ps := h.popuniPodaciStranice(r, podesavanja)
|
||||
ps.Stranica = "usluge"
|
||||
ps.NaslovStranice = "Usluge"
|
||||
h.renderujTemplate(w, "usluge", PodaciUsluga{
|
||||
PodaciStranice: ps,
|
||||
Usluge: usluge,
|
||||
Pretraga: pretraga,
|
||||
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
||||
Obrisan: r.URL.Query().Get("obrisan") == "1",
|
||||
})
|
||||
}
|
||||
|
||||
// NovaUsluga prikazuje praznu formu sa predloženom auto-šifrom (USL-NNN)
|
||||
func (h *Handler) NovaUsluga(w http.ResponseWriter, r *http.Request) {
|
||||
sifra, err := h.UslugeRepo.SledecaSifra(r.Context())
|
||||
if err != nil {
|
||||
sifra = "USL-001"
|
||||
}
|
||||
h.renderujFormuUsluge(w, r, model.Usluga{Sifra: sifra, PdvStopa: 20, JedinicaMere: "usluga"}, false, "")
|
||||
}
|
||||
|
||||
// IzmeniUslugu prikazuje formu sa postojećom uslugom
|
||||
func (h *Handler) IzmeniUslugu(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, "Neispravan ID usluge", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
usluga, err := h.UslugeRepo.DohvatiID(r.Context(), id)
|
||||
if err != nil {
|
||||
http.Error(w, "Usluga nije pronađena", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
h.renderujFormuUsluge(w, r, *usluga, true, "")
|
||||
}
|
||||
|
||||
// SacuvajUslugu prima POST i kreira novu uslugu
|
||||
func (h *Handler) SacuvajUslugu(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.zahtevajDozvolu(w, r, "artikal.dodaj"); !ok {
|
||||
return
|
||||
}
|
||||
usluga, greska := parseFormuUsluge(r)
|
||||
if greska != "" {
|
||||
h.renderujFormuUsluge(w, r, usluga, false, greska)
|
||||
return
|
||||
}
|
||||
if _, err := h.UslugeRepo.Kreiraj(r.Context(), &usluga); err != nil {
|
||||
h.renderujFormuUsluge(w, r, usluga, false, "Greška pri čuvanju usluge. Pokušajte ponovo.")
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/usluge?sacuvano=1", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// SacuvajIzmenuUsluge prima POST i ažurira postojeću uslugu
|
||||
func (h *Handler) SacuvajIzmenuUsluge(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.zahtevajDozvolu(w, r, "artikal.izmeni"); !ok {
|
||||
return
|
||||
}
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, "Neispravan ID usluge", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
usluga, greska := parseFormuUsluge(r)
|
||||
usluga.ID = id
|
||||
if greska != "" {
|
||||
h.renderujFormuUsluge(w, r, usluga, true, greska)
|
||||
return
|
||||
}
|
||||
if err := h.UslugeRepo.Izmeni(r.Context(), &usluga); err != nil {
|
||||
h.renderujFormuUsluge(w, r, usluga, true, "Greška pri čuvanju usluge. Pokušajte ponovo.")
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/usluge?sacuvano=1", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// ObrisiUslugu briše uslugu po ID-u
|
||||
func (h *Handler) ObrisiUslugu(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.zahtevajDozvolu(w, r, "artikal.obrisi"); !ok {
|
||||
return
|
||||
}
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, "Neispravan ID usluge", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := h.UslugeRepo.Obrisi(r.Context(), id); err != nil {
|
||||
http.Error(w, "Greška pri brisanju usluge", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/usluge?obrisan=1", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// parseFormuUsluge čita i validira polja forme usluge. Vraća model i poruku o grešci.
|
||||
func parseFormuUsluge(r *http.Request) (model.Usluga, string) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return model.Usluga{}, "Greška pri čitanju forme."
|
||||
}
|
||||
naziv := strings.TrimSpace(r.FormValue("naziv"))
|
||||
if naziv == "" {
|
||||
return model.Usluga{Kategorija: strings.TrimSpace(r.FormValue("kategorija"))}, "Naziv usluge je obavezan."
|
||||
}
|
||||
|
||||
cena, err := strconv.ParseFloat(strings.TrimSpace(r.FormValue("cena")), 64)
|
||||
if err != nil || cena < 0 {
|
||||
cena = 0
|
||||
}
|
||||
pdv, err := strconv.ParseFloat(strings.TrimSpace(r.FormValue("pdv_stopa")), 64)
|
||||
if err != nil || pdv < 0 {
|
||||
pdv = 20
|
||||
}
|
||||
|
||||
jm := strings.TrimSpace(r.FormValue("jedinica_mere"))
|
||||
if jm == "" {
|
||||
jm = "usluga"
|
||||
}
|
||||
|
||||
return model.Usluga{
|
||||
Sifra: strings.TrimSpace(r.FormValue("sifra")),
|
||||
Naziv: naziv,
|
||||
Kategorija: strings.TrimSpace(r.FormValue("kategorija")),
|
||||
JedinicaMere: jm,
|
||||
Cena: cena,
|
||||
PdvStopa: pdv,
|
||||
Opis: strings.TrimSpace(r.FormValue("opis")),
|
||||
}, ""
|
||||
}
|
||||
|
||||
// renderujFormuUsluge prikazuje formu usluge (zajedničko za novu i izmenu)
|
||||
func (h *Handler) renderujFormuUsluge(w http.ResponseWriter, r *http.Request, usluga model.Usluga, izmena bool, greska string) {
|
||||
podesavanja, err := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||
if err != nil {
|
||||
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
kategorije, _ := h.UslugeRepo.Kategorije(r.Context())
|
||||
|
||||
ps := h.popuniPodaciStranice(r, podesavanja)
|
||||
ps.Stranica = "usluge"
|
||||
if izmena {
|
||||
ps.NaslovStranice = "Izmena usluge"
|
||||
} else {
|
||||
ps.NaslovStranice = "Nova usluga"
|
||||
}
|
||||
h.renderujTemplate(w, "usluge_forma", PodaciFormeUsluge{
|
||||
PodaciStranice: ps,
|
||||
Usluga: usluga,
|
||||
Kategorije: kategorije,
|
||||
Greska: greska,
|
||||
Izmena: izmena,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user