From 30db396ee667de84aaeb4f7afd914f6df7016684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Sun, 14 Jun 2026 16:12:03 +0200 Subject: [PATCH] =?UTF-8?q?feat(kalkulacija):=20Faza=20C=20=E2=80=94=20mar?= =?UTF-8?q?=C5=BEa=20po=20kategoriji/artiklu=20+=20zavisni=20tro=C5=A1kovi?= =?UTF-8?q?=20(backend)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Celina 1 (kompletna) — marža po kategoriji/artiklu: - migracija 046: nullable marza na artikli i kategorije - model Marza *float64 (Artikal, Kategorija) + KategorijaMarza u ArtikalSaKategorijom - repo: čitanje/pisanje marže; nove DohvatiID/Izmeni za kategoriju - dozvola kategorija.izmeni; handler IzmeniKategoriju + ruta - UI: polje marže u formi artikla i kategorije; modal izmene kategorije - nabavka: fallback predlog marže artikal → kategorija → globalna (izaberiArtikal) Celina 2 (backend) — zavisni troškovi nabavke: - migracija 047: tabela nabavka_troskovi + kolona metod_raspodele na nabavke - model NabavkaTrosak, MetodRaspodele; čista funkcija RasporediTroskove + test - repo: Kreiraj upisuje troškove i metod; DohvatiTroskove - handler: parsiranje troškova/metoda; kalkulativna nabavna cena na serveru UI forme troškova i prikaz u detaljima nabavke slede. --- cmd/ntech/main.go | 1 + internal/db/repository.go | 5 +- internal/db/sqlite/artikal.go | 33 ++++++--- internal/db/sqlite/kategorija.go | 44 ++++++++++-- internal/db/sqlite/nabavka.go | 61 ++++++++++++++--- internal/handler/kategorija.go | 52 +++++++++++++++ internal/handler/magacin_forma.go | 9 +++ internal/handler/nabavka.go | 71 +++++++++++++++----- internal/middleware/dozvole.go | 3 +- internal/model/artikal.go | 3 + internal/model/nabavka.go | 62 +++++++++++++++-- internal/model/nabavka_test.go | 74 +++++++++++++++++++++ migrations/046_marza_artikal_kategorija.sql | 6 ++ migrations/047_nabavka_zavisni_troskovi.sql | 17 +++++ web/static/js/ntech.js | 10 +++ web/templates/stranice/kategorije.html | 37 +++++++++++ web/templates/stranice/magacin_forma.html | 7 ++ web/templates/stranice/nabavka_forma.html | 4 +- 18 files changed, 448 insertions(+), 51 deletions(-) create mode 100644 internal/model/nabavka_test.go create mode 100644 migrations/046_marza_artikal_kategorija.sql create mode 100644 migrations/047_nabavka_zavisni_troskovi.sql diff --git a/cmd/ntech/main.go b/cmd/ntech/main.go index 5bd17e3..65e6d2d 100644 --- a/cmd/ntech/main.go +++ b/cmd/ntech/main.go @@ -282,6 +282,7 @@ func main() { r.With(doz("artikal.izmeni")).Get("/nivelacije", h.Nivelacije) r.Get("/magacin/kategorije", h.Kategorije) r.With(doz("kategorija.dodaj")).Post("/magacin/kategorije/dodaj", h.DodajKategoriju) + r.With(doz("kategorija.izmeni")).Post("/magacin/kategorije/izmeni/{id}", h.IzmeniKategoriju) r.With(doz("kategorija.obrisi")).Get("/magacin/kategorije/obrisi/{id}", h.ObrisiKategoriju) r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "nabavka.pregled")).Get("/nabavke", h.Nabavke) r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "nabavka.pregled")).Get("/nabavke/nova", h.NovaNabavka) diff --git a/internal/db/repository.go b/internal/db/repository.go index 520d5e1..aba096c 100644 --- a/internal/db/repository.go +++ b/internal/db/repository.go @@ -22,7 +22,9 @@ type ArtikalRepository interface { // KategorijaRepository definiše operacije nad kategorijama type KategorijaRepository interface { Lista(ctx context.Context) ([]model.Kategorija, error) + DohvatiID(ctx context.Context, id int64) (*model.Kategorija, error) Kreiraj(ctx context.Context, k *model.Kategorija) (int64, error) + Izmeni(ctx context.Context, k *model.Kategorija) error } // PdvStopaRepository definiše operacije nad šifarnikom PDV stopa @@ -79,7 +81,8 @@ type NabavkaRepository interface { Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, error) DohvatiID(ctx context.Context, id int64) (*model.Nabavka, error) DohvatiStavke(ctx context.Context, nabavkaID int64) ([]model.StavkaSaArtiklom, error) - Kreiraj(ctx context.Context, n *model.Nabavka, stavke []model.StavkaNabavke) (int64, error) + DohvatiTroskove(ctx context.Context, nabavkaID int64) ([]model.NabavkaTrosak, error) + Kreiraj(ctx context.Context, n *model.Nabavka, stavke []model.StavkaNabavke, troskovi []model.NabavkaTrosak) (int64, error) Obrisi(ctx context.Context, id int64) error } diff --git a/internal/db/sqlite/artikal.go b/internal/db/sqlite/artikal.go index d1e0289..6ed7f68 100644 --- a/internal/db/sqlite/artikal.go +++ b/internal/db/sqlite/artikal.go @@ -25,8 +25,8 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod SELECT a.id, a.kategorija_id, a.naziv, a.opis, a.kolicina, a.kolicina_min, a.lokacija, - a.nabavna_cena, a.prodajna_cena, a.pdv_stopa, a.napomena, a.datum_unosa, - COALESCE(k.naziv, '') as kategorija_naziv + a.nabavna_cena, a.prodajna_cena, a.pdv_stopa, a.marza, a.napomena, a.datum_unosa, + COALESCE(k.naziv, '') as kategorija_naziv, k.marza as kategorija_marza FROM artikli a LEFT JOIN kategorije k ON a.kategorija_id = k.id WHERE 1=1` @@ -59,12 +59,13 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod for redovi.Next() { var a model.ArtikalSaKategorijom var kategorijaID sql.NullInt64 + var marza, katMarza sql.NullFloat64 err := redovi.Scan( &a.ID, &kategorijaID, &a.Naziv, &a.Opis, &a.Kolicina, &a.KolicinMin, &a.Lokacija, - &a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &a.Napomena, &a.DatumUnosa, - &a.KategorijaNaziv, + &a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &marza, &a.Napomena, &a.DatumUnosa, + &a.KategorijaNaziv, &katMarza, ) if err != nil { return nil, fmt.Errorf("ntech: ArtikalRepo.Lista: scan: %w", err) @@ -73,6 +74,12 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod if kategorijaID.Valid { a.KategorijaID = &kategorijaID.Int64 } + if marza.Valid { + a.Marza = &marza.Float64 + } + if katMarza.Valid { + a.KategorijaMarza = &katMarza.Float64 + } a.KriticnaZaliha = a.Kolicina <= a.KolicinMin @@ -86,14 +93,15 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod func (r *ArtikalRepo) DohvatiID(ctx context.Context, id int64) (*model.Artikal, error) { var a model.Artikal var kategorijaID sql.NullInt64 + var marza sql.NullFloat64 err := r.db.QueryRowContext(ctx, ` SELECT id, kategorija_id, naziv, opis, kolicina, kolicina_min, - lokacija, nabavna_cena, prodajna_cena, pdv_stopa, napomena, datum_unosa + lokacija, nabavna_cena, prodajna_cena, pdv_stopa, marza, napomena, datum_unosa FROM artikli WHERE id = ?`, id).Scan( &a.ID, &kategorijaID, &a.Naziv, &a.Opis, &a.Kolicina, &a.KolicinMin, &a.Lokacija, - &a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &a.Napomena, &a.DatumUnosa, + &a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &marza, &a.Napomena, &a.DatumUnosa, ) if err != nil { return nil, fmt.Errorf("ntech: ArtikalRepo.DohvatiID: %w", err) @@ -102,6 +110,9 @@ func (r *ArtikalRepo) DohvatiID(ctx context.Context, id int64) (*model.Artikal, if kategorijaID.Valid { a.KategorijaID = &kategorijaID.Int64 } + if marza.Valid { + a.Marza = &marza.Float64 + } return &a, nil } @@ -111,10 +122,10 @@ func (r *ArtikalRepo) Kreiraj(ctx context.Context, a *model.Artikal) (int64, err rezultat, err := r.db.ExecContext(ctx, ` INSERT INTO artikli (kategorija_id, naziv, opis, kolicina, kolicina_min, lokacija, - nabavna_cena, prodajna_cena, pdv_stopa, napomena) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + nabavna_cena, prodajna_cena, pdv_stopa, marza, napomena) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, a.KategorijaID, a.Naziv, a.Opis, a.Kolicina, a.KolicinMin, - a.Lokacija, a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Napomena, + a.Lokacija, a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Marza, a.Napomena, ) if err != nil { return 0, fmt.Errorf("ntech: ArtikalRepo.Kreiraj: %w", err) @@ -134,11 +145,11 @@ func (r *ArtikalRepo) Izmeni(ctx context.Context, a *model.Artikal) error { UPDATE artikli SET kategorija_id = ?, naziv = ?, opis = ?, kolicina = ?, kolicina_min = ?, lokacija = ?, - nabavna_cena = ?, prodajna_cena = ?, pdv_stopa = ?, napomena = ? + nabavna_cena = ?, prodajna_cena = ?, pdv_stopa = ?, marza = ?, napomena = ? WHERE id = ?`, a.KategorijaID, a.Naziv, a.Opis, a.Kolicina, a.KolicinMin, a.Lokacija, - a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Napomena, a.ID, + a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Marza, a.Napomena, a.ID, ) if err != nil { return fmt.Errorf("ntech: ArtikalRepo.Izmeni: %w", err) diff --git a/internal/db/sqlite/kategorija.go b/internal/db/sqlite/kategorija.go index 3a83ce6..928169c 100644 --- a/internal/db/sqlite/kategorija.go +++ b/internal/db/sqlite/kategorija.go @@ -20,7 +20,7 @@ func NovaKategorijaRepo(db *sql.DB) *KategorijaRepo { // Lista vraća sve kategorije func (r *KategorijaRepo) Lista(ctx context.Context) ([]model.Kategorija, error) { - redovi, err := r.db.QueryContext(ctx, "SELECT id, naziv, opis FROM kategorije ORDER BY naziv ASC") + redovi, err := r.db.QueryContext(ctx, "SELECT id, naziv, opis, marza FROM kategorije ORDER BY naziv ASC") if err != nil { return nil, fmt.Errorf("ntech: KategorijaRepo.Lista: %w", err) } @@ -30,12 +30,16 @@ func (r *KategorijaRepo) Lista(ctx context.Context) ([]model.Kategorija, error) for redovi.Next() { var k model.Kategorija var opis sql.NullString - if err := redovi.Scan(&k.ID, &k.Naziv, &opis); err != nil { + var marza sql.NullFloat64 + if err := redovi.Scan(&k.ID, &k.Naziv, &opis, &marza); err != nil { return nil, fmt.Errorf("ntech: KategorijaRepo.Lista: scan: %w", err) } if opis.Valid { k.Opis = opis.String } + if marza.Valid { + k.Marza = &marza.Float64 + } rezultat = append(rezultat, k) } @@ -45,8 +49,8 @@ func (r *KategorijaRepo) Lista(ctx context.Context) ([]model.Kategorija, error) // Kreiraj dodaje novu kategoriju func (r *KategorijaRepo) Kreiraj(ctx context.Context, k *model.Kategorija) (int64, error) { rezultat, err := r.db.ExecContext(ctx, - "INSERT INTO kategorije (naziv, opis) VALUES (?, ?)", - k.Naziv, k.Opis, + "INSERT INTO kategorije (naziv, opis, marza) VALUES (?, ?, ?)", + k.Naziv, k.Opis, k.Marza, ) if err != nil { return 0, fmt.Errorf("ntech: KategorijaRepo.Kreiraj: %w", err) @@ -59,3 +63,35 @@ func (r *KategorijaRepo) Kreiraj(ctx context.Context, k *model.Kategorija) (int6 return id, nil } + +// DohvatiID vraća jednu kategoriju po ID-u +func (r *KategorijaRepo) DohvatiID(ctx context.Context, id int64) (*model.Kategorija, error) { + var k model.Kategorija + var opis sql.NullString + var marza sql.NullFloat64 + err := r.db.QueryRowContext(ctx, + "SELECT id, naziv, opis, marza FROM kategorije WHERE id = ?", id). + Scan(&k.ID, &k.Naziv, &opis, &marza) + if err != nil { + return nil, fmt.Errorf("ntech: KategorijaRepo.DohvatiID: %w", err) + } + if opis.Valid { + k.Opis = opis.String + } + if marza.Valid { + k.Marza = &marza.Float64 + } + return &k, nil +} + +// Izmeni ažurira naziv, opis i maržu postojeće kategorije +func (r *KategorijaRepo) Izmeni(ctx context.Context, k *model.Kategorija) error { + _, err := r.db.ExecContext(ctx, + "UPDATE kategorije SET naziv = ?, opis = ?, marza = ? WHERE id = ?", + k.Naziv, k.Opis, k.Marza, k.ID, + ) + if err != nil { + return fmt.Errorf("ntech: KategorijaRepo.Izmeni: %w", err) + } + return nil +} diff --git a/internal/db/sqlite/nabavka.go b/internal/db/sqlite/nabavka.go index 2e3b735..8d68649 100644 --- a/internal/db/sqlite/nabavka.go +++ b/internal/db/sqlite/nabavka.go @@ -22,7 +22,7 @@ func NoviNabavkaRepo(db *sql.DB) *NabavkaRepo { func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, error) { redovi, err := r.db.QueryContext(ctx, ` SELECT - n.id, n.dobavljac_id, n.napomena, n.ukupno, n.datum, + n.id, n.dobavljac_id, n.napomena, n.ukupno, n.metod_raspodele, n.datum, COALESCE(d.naziv, '') AS dobavljac_naziv FROM nabavke n LEFT JOIN dobavljaci d ON n.dobavljac_id = d.id @@ -36,10 +36,10 @@ func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, err for redovi.Next() { var n model.NabavkaSaDetaljem var dobavljacID sql.NullInt64 - var napomena sql.NullString + var napomena, metod sql.NullString err := redovi.Scan( - &n.ID, &dobavljacID, &napomena, &n.Ukupno, &n.Datum, + &n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod, &n.Datum, &n.DobavljacNaziv, ) if err != nil { @@ -50,6 +50,7 @@ func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, err n.DobavljacID = &dobavljacID.Int64 } n.Napomena = napomena.String + n.MetodRaspodele = metod.String rezultat = append(rezultat, n) } @@ -61,12 +62,12 @@ func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, err func (r *NabavkaRepo) DohvatiID(ctx context.Context, id int64) (*model.Nabavka, error) { var n model.Nabavka var dobavljacID sql.NullInt64 - var napomena sql.NullString + var napomena, metod sql.NullString err := r.db.QueryRowContext(ctx, ` - SELECT id, dobavljac_id, napomena, ukupno, datum + SELECT id, dobavljac_id, napomena, ukupno, metod_raspodele, datum FROM nabavke WHERE id = ?`, id).Scan( - &n.ID, &dobavljacID, &napomena, &n.Ukupno, &n.Datum, + &n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod, &n.Datum, ) if err != nil { return nil, fmt.Errorf("ntech: NabavkaRepo.DohvatiID: %w", err) @@ -76,6 +77,7 @@ func (r *NabavkaRepo) DohvatiID(ctx context.Context, id int64) (*model.Nabavka, n.DobavljacID = &dobavljacID.Int64 } n.Napomena = napomena.String + n.MetodRaspodele = metod.String return &n, nil } @@ -113,8 +115,33 @@ func (r *NabavkaRepo) DohvatiStavke(ctx context.Context, nabavkaID int64) ([]mod return rezultat, nil } -// Kreiraj upisuje novu nabavku sa svim stavkama u jednoj transakciji i ažurira stanje magacina -func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []model.StavkaNabavke) (int64, error) { +// DohvatiTroskove vraća sve zavisne troškove jedne nabavke +func (r *NabavkaRepo) DohvatiTroskove(ctx context.Context, nabavkaID int64) ([]model.NabavkaTrosak, error) { + redovi, err := r.db.QueryContext(ctx, ` + SELECT id, nabavka_id, naziv, iznos + FROM nabavka_troskovi + WHERE nabavka_id = ? + ORDER BY id ASC`, nabavkaID) + if err != nil { + return nil, fmt.Errorf("ntech: NabavkaRepo.DohvatiTroskove: %w", err) + } + defer redovi.Close() + + var rezultat []model.NabavkaTrosak + for redovi.Next() { + var t model.NabavkaTrosak + if err := redovi.Scan(&t.ID, &t.NabavkaID, &t.Naziv, &t.Iznos); err != nil { + return nil, fmt.Errorf("ntech: NabavkaRepo.DohvatiTroskove: scan: %w", err) + } + rezultat = append(rezultat, t) + } + + return rezultat, nil +} + +// Kreiraj upisuje novu nabavku sa svim stavkama i zavisnim troškovima u jednoj +// transakciji i ažurira stanje magacina +func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []model.StavkaNabavke, troskovi []model.NabavkaTrosak) (int64, error) { tx, err := r.db.BeginTx(ctx, nil) if err != nil { return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: begin: %w", err) @@ -130,9 +157,9 @@ func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []mo // upisujemo zaglavlje nabavke rezultat, err := tx.ExecContext(ctx, ` - INSERT INTO nabavke (dobavljac_id, napomena, ukupno) - VALUES (?, ?, ?)`, - nullInt64(n.DobavljacID), nullString(n.Napomena), ukupno, + INSERT INTO nabavke (dobavljac_id, napomena, ukupno, metod_raspodele) + VALUES (?, ?, ?, ?)`, + nullInt64(n.DobavljacID), nullString(n.Napomena), ukupno, nullString(n.MetodRaspodele), ) if err != nil { return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: insert nabavka: %w", err) @@ -143,6 +170,18 @@ func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []mo return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: last insert id: %w", err) } + // upisujemo zavisne troškove (ako ih ima) + for _, t := range troskovi { + _, err := tx.ExecContext(ctx, ` + INSERT INTO nabavka_troskovi (nabavka_id, naziv, iznos) + VALUES (?, ?, ?)`, + nabavkaID, t.Naziv, t.Iznos, + ) + if err != nil { + return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: insert trošak: %w", err) + } + } + // upisujemo svaku stavku i ažuriramo stanje artikla u magacinu for _, s := range stavke { _, err := tx.ExecContext(ctx, ` diff --git a/internal/handler/kategorija.go b/internal/handler/kategorija.go index 81630ca..4e1a1ab 100644 --- a/internal/handler/kategorija.go +++ b/internal/handler/kategorija.go @@ -3,6 +3,7 @@ package handler import ( "net/http" "strconv" + "strings" "ntech/internal/db/sqlite" "ntech/internal/model" @@ -64,6 +65,7 @@ func (h *Handler) DodajKategoriju(w http.ResponseWriter, r *http.Request) { k := &model.Kategorija{ Naziv: naziv, Opis: r.FormValue("opis"), + Marza: parsirajMarzu(r.FormValue("marza")), } if _, err := h.KategorijeRepo.Kreiraj(r.Context(), k); err != nil { @@ -74,6 +76,56 @@ func (h *Handler) DodajKategoriju(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/magacin/kategorije?sacuvano=1", http.StatusSeeOther) } +// IzmeniKategoriju prima POST i ažurira naziv, opis i maržu postojeće kategorije +func (h *Handler) IzmeniKategoriju(w http.ResponseWriter, r *http.Request) { + if _, ok := h.zahtevajDozvolu(w, r, "kategorija.izmeni"); !ok { + return + } + if err := r.ParseForm(); err != nil { + http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest) + return + } + + id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) + if err != nil { + http.Error(w, "Neispravan ID kategorije", http.StatusBadRequest) + return + } + + naziv := r.FormValue("naziv") + if naziv == "" { + http.Redirect(w, r, "/magacin/kategorije", http.StatusSeeOther) + return + } + + k := &model.Kategorija{ + ID: id, + Naziv: naziv, + Opis: r.FormValue("opis"), + Marza: parsirajMarzu(r.FormValue("marza")), + } + + if err := h.KategorijeRepo.Izmeni(r.Context(), k); err != nil { + http.Error(w, "Greška pri čuvanju izmene kategorije", http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/magacin/kategorije?sacuvano=1", http.StatusSeeOther) +} + +// parsirajMarzu pretvara tekst iz forme u *float64; prazno/neispravno → nil (NULL u bazi) +func parsirajMarzu(s string) *float64 { + s = strings.TrimSpace(s) + if s == "" { + return nil + } + v, err := strconv.ParseFloat(s, 64) + if err != nil || v < 0 { + return nil + } + return &v +} + // ObrisiKategoriju briše kategoriju po ID-u func (h *Handler) ObrisiKategoriju(w http.ResponseWriter, r *http.Request) { if _, ok := h.zahtevajDozvolu(w, r, "kategorija.obrisi"); !ok { diff --git a/internal/handler/magacin_forma.go b/internal/handler/magacin_forma.go index 1910c9f..67ef383 100644 --- a/internal/handler/magacin_forma.go +++ b/internal/handler/magacin_forma.go @@ -249,6 +249,15 @@ func parseFormuArtikla(r *http.Request) (model.Artikal, string) { artikal.ProdajnaCena = v } + // marža (%) je opciona; prazno polje ostaje NULL (artikal nasleđuje maržu kategorije/globalnu) + if m := r.FormValue("marza"); m != "" { + v, err := strconv.ParseFloat(m, 64) + if err != nil || v < 0 { + return artikal, "Marža mora biti pozitivan broj." + } + artikal.Marza = &v + } + if katID := r.FormValue("kategorija_id"); katID != "" { id, err := strconv.ParseInt(katID, 10, 64) if err == nil { diff --git a/internal/handler/nabavka.go b/internal/handler/nabavka.go index a6cdd84..ad5e367 100644 --- a/internal/handler/nabavka.go +++ b/internal/handler/nabavka.go @@ -45,13 +45,18 @@ type PodaciDetaljiNabavke struct { // artikalUJSON pretvara listu artikala u template.JS vrednost bezbednu za umetanje u