Zalihe: storno nabavke umesto brisanja + ponderisana prosečna nabavna cena
This commit is contained in:
+1
-1
@@ -350,7 +350,7 @@ func main() {
|
||||
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "nabavka.pregled")).Get("/nabavke/nova", h.NovaNabavka)
|
||||
r.With(doz("nabavka.dodaj")).Post("/nabavke/nova", h.SacuvajNabavku)
|
||||
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "nabavka.pregled")).Get("/nabavke/{id}", h.DetaljiNabavke)
|
||||
r.With(doz("nabavka.obrisi")).Post("/nabavke/obrisi/{id}", h.ObrisiNabavku)
|
||||
r.With(doz("nabavka.storno")).Post("/nabavke/storno/{id}", h.StornoNabavke)
|
||||
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "dobavljac.pregled")).Get("/dobavljaci", h.Dobavljaci)
|
||||
r.Get("/dobavljaci/novi", h.NoviDobavljac)
|
||||
r.With(doz("dobavljac.dodaj")).Post("/dobavljaci/novi", h.SacuvajDobavljaca)
|
||||
|
||||
@@ -22,7 +22,8 @@ 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.metod_raspodele, n.datum,
|
||||
n.id, n.dobavljac_id, n.napomena, n.ukupno, n.metod_raspodele,
|
||||
n.stornirano, n.razlog_storniranja, n.datum,
|
||||
COALESCE(d.naziv, '') AS dobavljac_naziv
|
||||
FROM nabavke n
|
||||
LEFT JOIN dobavljaci d ON n.dobavljac_id = d.id
|
||||
@@ -36,10 +37,11 @@ func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, err
|
||||
for redovi.Next() {
|
||||
var n model.NabavkaSaDetaljem
|
||||
var dobavljacID sql.NullInt64
|
||||
var napomena, metod sql.NullString
|
||||
var napomena, metod, razlogStorniranja sql.NullString
|
||||
|
||||
err := redovi.Scan(
|
||||
&n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod, &n.Datum,
|
||||
&n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod,
|
||||
&n.Stornirano, &razlogStorniranja, &n.Datum,
|
||||
&n.DobavljacNaziv,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -51,6 +53,7 @@ func (r *NabavkaRepo) Lista(ctx context.Context) ([]model.NabavkaSaDetaljem, err
|
||||
}
|
||||
n.Napomena = napomena.String
|
||||
n.MetodRaspodele = metod.String
|
||||
n.RazlogStorniranja = razlogStorniranja.String
|
||||
|
||||
rezultat = append(rezultat, n)
|
||||
}
|
||||
@@ -62,12 +65,14 @@ 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, metod sql.NullString
|
||||
var napomena, metod, razlogStorniranja sql.NullString
|
||||
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT id, dobavljac_id, napomena, ukupno, metod_raspodele, datum
|
||||
SELECT id, dobavljac_id, napomena, ukupno, metod_raspodele,
|
||||
stornirano, razlog_storniranja, datum
|
||||
FROM nabavke WHERE id = ?`, id).Scan(
|
||||
&n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod, &n.Datum,
|
||||
&n.ID, &dobavljacID, &napomena, &n.Ukupno, &metod,
|
||||
&n.Stornirano, &razlogStorniranja, &n.Datum,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: NabavkaRepo.DohvatiID: %w", err)
|
||||
@@ -78,6 +83,7 @@ func (r *NabavkaRepo) DohvatiID(ctx context.Context, id int64) (*model.Nabavka,
|
||||
}
|
||||
n.Napomena = napomena.String
|
||||
n.MetodRaspodele = metod.String
|
||||
n.RazlogStorniranja = razlogStorniranja.String
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
@@ -194,17 +200,26 @@ func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []mo
|
||||
}
|
||||
|
||||
var stanjePre int
|
||||
var staraNabavnaCena float64
|
||||
err = tx.QueryRowContext(ctx,
|
||||
"SELECT kolicina FROM artikli WHERE id = ?", s.ArtikalID,
|
||||
).Scan(&stanjePre)
|
||||
"SELECT kolicina, nabavna_cena FROM artikli WHERE id = ?", s.ArtikalID,
|
||||
).Scan(&stanjePre, &staraNabavnaCena)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: dohvati stanje: %w", err)
|
||||
}
|
||||
|
||||
// ponderisana prosečna nabavna cena (MRS 2)
|
||||
stanjePosle := stanjePre + s.Kolicina
|
||||
var novaProsecna float64
|
||||
if stanjePosle > 0 {
|
||||
novaProsecna = (float64(stanjePre)*staraNabavnaCena + float64(s.Kolicina)*s.CenaPoKomadu) / float64(stanjePosle)
|
||||
} else {
|
||||
novaProsecna = s.CenaPoKomadu
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?",
|
||||
stanjePosle, s.ArtikalID,
|
||||
"UPDATE artikli SET kolicina = ?, nabavna_cena = ? WHERE id = ?",
|
||||
stanjePosle, novaProsecna, s.ArtikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: NabavkaRepo.Kreiraj: update kolicina: %w", err)
|
||||
@@ -223,19 +238,31 @@ func (r *NabavkaRepo) Kreiraj(ctx context.Context, n *model.Nabavka, stavke []mo
|
||||
return nabavkaID, nil
|
||||
}
|
||||
|
||||
// Obrisi briše nabavku po ID-u, vraća količine artikala na stanje i beleži korekciju u magacinski trag.
|
||||
func (r *NabavkaRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) error {
|
||||
// Storno označava nabavku kao storniranu, vraća količine artikala na stanje i beleži
|
||||
// korekciju u magacinski trag. Nabavna cena se NE računa unazad — ostaje kakva jeste.
|
||||
func (r *NabavkaRepo) Storno(ctx context.Context, id int64, razlog string, korisnikID *int64) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: begin: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: begin: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// učitaj stavke pre brisanja (CASCADE ih briše zajedno sa nabavkom)
|
||||
// provera da li je već stornirano
|
||||
var stornirano bool
|
||||
if err := tx.QueryRowContext(ctx,
|
||||
"SELECT stornirano FROM nabavke WHERE id = ?", id,
|
||||
).Scan(&stornirano); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: provera: %w", err)
|
||||
}
|
||||
if stornirano {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: nabavka je već stornirana")
|
||||
}
|
||||
|
||||
// učitaj stavke
|
||||
redovi, err := tx.QueryContext(ctx,
|
||||
"SELECT artikal_id, kolicina FROM stavke_nabavke WHERE nabavka_id = ?", id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: dohvati stavke: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: dohvati stavke: %w", err)
|
||||
}
|
||||
type stavka struct {
|
||||
artikalID int64
|
||||
@@ -246,7 +273,7 @@ func (r *NabavkaRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) e
|
||||
var s stavka
|
||||
if err := redovi.Scan(&s.artikalID, &s.kolicina); err != nil {
|
||||
redovi.Close()
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: scan stavka: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: scan stavka: %w", err)
|
||||
}
|
||||
stavke = append(stavke, s)
|
||||
}
|
||||
@@ -258,7 +285,7 @@ func (r *NabavkaRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) e
|
||||
if err := tx.QueryRowContext(ctx,
|
||||
"SELECT kolicina FROM artikli WHERE id = ?", s.artikalID,
|
||||
).Scan(&stanjePre); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: dohvati stanje: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: dohvati stanje: %w", err)
|
||||
}
|
||||
stanjePosle := stanjePre - s.kolicina
|
||||
if stanjePosle < 0 {
|
||||
@@ -267,20 +294,23 @@ func (r *NabavkaRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) e
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?", stanjePosle, s.artikalID,
|
||||
); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: update stanje: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: update stanje: %w", err)
|
||||
}
|
||||
if err := zabeleziMagacinPromenu(ctx, tx, s.artikalID, model.PromenaKorekcija,
|
||||
-s.kolicina, stanjePre, stanjePosle, id, korisnikID, "brisanje nabavke"); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: magacin: %w", err)
|
||||
-s.kolicina, stanjePre, stanjePosle, id, korisnikID, "storno nabavke: "+razlog); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: magacin: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, "DELETE FROM nabavke WHERE id = ?", id); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: delete: %w", err)
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
"UPDATE nabavke SET stornirano = 1, razlog_storniranja = ? WHERE id = ?",
|
||||
nullString(razlog), id,
|
||||
); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: update nabavka: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Obrisi: commit: %w", err)
|
||||
return fmt.Errorf("ntech: NabavkaRepo.Storno: commit: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+22
-19
@@ -43,6 +43,7 @@ type PodaciDetaljiNabavke struct {
|
||||
Troskovi []model.NabavkaTrosak
|
||||
UkupanTrosak float64
|
||||
DobavljacNaziv string
|
||||
Sacuvano bool
|
||||
}
|
||||
|
||||
// artikalUJSON pretvara listu artikala u template.JS vrednost bezbednu za umetanje u <script> tag
|
||||
@@ -208,20 +209,14 @@ func (h *Handler) SacuvajNabavku(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// kalkulacija: ažuriraj nabavnu i prodajnu cenu artikla iz forme + nivelacioni trag.
|
||||
// kalkulacija: ažuriraj prodajnu cenu artikla iz forme + nivelacioni trag.
|
||||
// nabavna cena je već ponderisana prosečna (postavlja je Kreiraj) — ne preglašava se.
|
||||
// prodajna[] je paralelni niz uz stavke (isti redosled kao artikal_id[]).
|
||||
prodajne := r.Form["prodajna[]"]
|
||||
var korisnikID *int64
|
||||
if k != nil {
|
||||
korisnikID = &k.ID
|
||||
}
|
||||
// kalkulativna nabavna cena po stavci (fakturna + raspodeljeni zavisni trošak) —
|
||||
// računa se na serveru; bez troškova je jednaka čistoj ceni po komadu.
|
||||
var ukupanTrosak float64
|
||||
for _, t := range troskovi {
|
||||
ukupanTrosak += t.Iznos
|
||||
}
|
||||
kalkNabavna := model.RasporediTroskove(stavke, ukupanTrosak, nabavka.MetodRaspodele)
|
||||
for i, s := range stavke {
|
||||
if i >= len(prodajne) {
|
||||
break
|
||||
@@ -230,12 +225,13 @@ func (h *Handler) SacuvajNabavku(w http.ResponseWriter, r *http.Request) {
|
||||
if e != nil || prodajna <= 0 {
|
||||
continue // prazno/nula ne sme da pregazi postojeću cenu
|
||||
}
|
||||
// stara prodajna cena — za nivelacioni zapis
|
||||
var staraProdajna float64
|
||||
// stara prodajna i tekuća (ponderisana) nabavna — nabavnu zadržavamo
|
||||
var staraProdajna, nabavna float64
|
||||
if a, e := h.Artikli.DohvatiID(r.Context(), s.ArtikalID); e == nil {
|
||||
staraProdajna = a.ProdajnaCena
|
||||
nabavna = a.NabavnaCena
|
||||
}
|
||||
if e := h.Artikli.AzurirajCene(r.Context(), s.ArtikalID, kalkNabavna[i], prodajna); e != nil {
|
||||
if e := h.Artikli.AzurirajCene(r.Context(), s.ArtikalID, nabavna, prodajna); e != nil {
|
||||
slog.Error("kalkulacija: ažuriranje cena nije uspelo", "artikal_id", s.ArtikalID, "error", e)
|
||||
continue
|
||||
}
|
||||
@@ -333,14 +329,15 @@ func (h *Handler) DetaljiNabavke(w http.ResponseWriter, r *http.Request) {
|
||||
Troskovi: troskovi,
|
||||
UkupanTrosak: ukupanTrosak,
|
||||
DobavljacNaziv: dobavljacNaziv,
|
||||
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
||||
}
|
||||
|
||||
h.renderujTemplate(w, "nabavka_detalji", podaci)
|
||||
}
|
||||
|
||||
// ObrisiNabavku prima POST zahtev i briše nabavku po ID-u
|
||||
func (h *Handler) ObrisiNabavku(w http.ResponseWriter, r *http.Request) {
|
||||
k, ok := h.zahtevajDozvolu(w, r, "nabavka.obrisi")
|
||||
// StornoNabavke prima POST zahtev i stornira nabavku po ID-u (umesto fizičkog brisanja)
|
||||
func (h *Handler) StornoNabavke(w http.ResponseWriter, r *http.Request) {
|
||||
k, ok := h.zahtevajDozvolu(w, r, "nabavka.storno")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -349,17 +346,23 @@ func (h *Handler) ObrisiNabavku(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Neispravan ID nabavke", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.NabavkeRepo.Obrisi(r.Context(), id, &k.ID); err != nil {
|
||||
http.Error(w, "Greška pri brisanju nabavke", http.StatusInternalServerError)
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// ukloni vezani auto-KPR zapis (ako ga je ova nabavka kreirala)
|
||||
razlog := strings.TrimSpace(r.FormValue("razlog"))
|
||||
|
||||
if err := h.NabavkeRepo.Storno(r.Context(), id, razlog, &k.ID); err != nil {
|
||||
slog.Error("greška pri storniranju nabavke", "error", err)
|
||||
http.Redirect(w, r, "/nabavke/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
// stornirana nabavka ne ulazi u PDV — ukloni vezani auto-KPR zapis
|
||||
if err := h.PdvKprRepo.ObrisiPoIzvoru(r.Context(), "nabavka", id); err != nil {
|
||||
slog.Error("brisanje vezanog KPR zapisa nije uspelo", "nabavka_id", id, "error", err)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/nabavke?obrisan=1", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/nabavke/"+strconv.FormatInt(id, 10)+"?sacuvano=1", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// parseFormuNabavke čita zaglavlje, stavke i zavisne troškove iz HTTP forme
|
||||
|
||||
@@ -15,6 +15,7 @@ var sveAkcije = []string{
|
||||
"nabavka.pregled",
|
||||
"nabavka.dodaj",
|
||||
"nabavka.obrisi",
|
||||
"nabavka.storno",
|
||||
"dobavljac.pregled",
|
||||
"dobavljac.dodaj",
|
||||
"dobavljac.izmeni",
|
||||
@@ -66,7 +67,7 @@ func ImaDozvolu(uloga, akcija string) bool {
|
||||
case "kategorija.pregled", "kategorija.dodaj", "kategorija.izmeni", "kategorija.obrisi":
|
||||
return true
|
||||
// nabavka
|
||||
case "nabavka.pregled", "nabavka.dodaj", "nabavka.obrisi":
|
||||
case "nabavka.pregled", "nabavka.dodaj", "nabavka.obrisi", "nabavka.storno":
|
||||
return true
|
||||
// dobavljač
|
||||
case "dobavljac.pregled", "dobavljac.dodaj",
|
||||
|
||||
@@ -7,12 +7,14 @@ import (
|
||||
|
||||
// Nabavka predstavlja zaglavlje jedne nabavke
|
||||
type Nabavka struct {
|
||||
ID int64
|
||||
DobavljacID *int64
|
||||
Napomena string
|
||||
Ukupno float64
|
||||
MetodRaspodele string // "vrednost" ili "kolicina"; prazno = nema zavisnih troškova
|
||||
Datum time.Time
|
||||
ID int64
|
||||
DobavljacID *int64
|
||||
Napomena string
|
||||
Ukupno float64
|
||||
MetodRaspodele string // "vrednost" ili "kolicina"; prazno = nema zavisnih troškova
|
||||
Stornirano bool
|
||||
RazlogStorniranja string
|
||||
Datum time.Time
|
||||
}
|
||||
|
||||
// NabavkaTrosak je jedna stavka zavisnih troškova nabavke (npr. prevoz, carina)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Nabavke — storniranje umesto fizičkog brisanja (računovodstveni tretman ulaznih dokumenata)
|
||||
ALTER TABLE nabavke ADD COLUMN stornirano INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE nabavke ADD COLUMN razlog_storniranja TEXT;
|
||||
@@ -14,6 +14,10 @@
|
||||
{{define "sadrzaj"}}
|
||||
<div class="kolona" style="gap:16px;">
|
||||
|
||||
{{if .Sacuvano}}
|
||||
<div class="poruka-uspeh poruka-animacija">Nabavka je uspešno sačuvana.</div>
|
||||
{{end}}
|
||||
|
||||
<!-- nazad dugme -->
|
||||
<a href="/nabavke" class="nazad-link" hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
@@ -23,7 +27,14 @@
|
||||
<!-- zaglavlje nabavke -->
|
||||
<div class="kartica detalji-kartica animiraj">
|
||||
<div style="margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
|
||||
<span style="font-size:16px;font-weight:500;color:var(--tekst-glavni);">Detalji nabavke</span>
|
||||
<span style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
|
||||
<span style="font-size:16px;font-weight:500;color:var(--tekst-glavni);">Detalji nabavke</span>
|
||||
{{if .Nabavka.Stornirano}}
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:20px;font-size:12px;font-weight:500;background:rgba(220,38,38,0.12);color:#dc2626;">
|
||||
Stornirano
|
||||
</span>
|
||||
{{end}}
|
||||
</span>
|
||||
<span class="pomocni-tekst">{{.Nabavka.Datum.Format "02.01.2006. u 15:04"}}</span>
|
||||
</div>
|
||||
|
||||
@@ -46,6 +57,12 @@
|
||||
{{dinari .Nabavka.Ukupno}} din
|
||||
</div>
|
||||
</div>
|
||||
{{if .Nabavka.RazlogStorniranja}}
|
||||
<div style="grid-column:1/-1;">
|
||||
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Razlog storniranja</div>
|
||||
<div style="font-size:13px;color:#dc2626;">{{.Nabavka.RazlogStorniranja}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -146,23 +163,27 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- zona za brisanje -->
|
||||
<!-- zona za storniranje -->
|
||||
{{if and (index .Dozvole "nabavka.storno") (not .Nabavka.Stornirano)}}
|
||||
<div class="kartica detalji-kartica animiraj" style="border-color:#dc262633;">
|
||||
<div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;">
|
||||
<div style="flex:1;min-width:200px;">
|
||||
<div style="font-size:14px;font-weight:500;color:#dc2626;margin-bottom:4px;">Brisanje nabavke</div>
|
||||
<div style="font-size:14px;font-weight:500;color:#f97316;margin-bottom:4px;">Storniranje nabavke</div>
|
||||
<div class="pomocni-tekst">
|
||||
Brisanje je trajno i ne vraća količine artikala u magacin.
|
||||
Storno vraća količine artikala na stanje u magacinu. Nabavka ostaje u evidenciji sa oznakom stornirana. Nabavna cena se ne menja.
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/nabavke/obrisi/{{.Nabavka.ID}}">
|
||||
<button type="submit" class="btn-opasno"
|
||||
data-potvrda="Da li ste sigurni da želite da obrišete ovu nabavku? Brisanje ne vraća količine artikala u magacin.">
|
||||
Obriši nabavku
|
||||
<form method="POST" action="/nabavke/storno/{{.Nabavka.ID}}" style="display:flex;flex-direction:column;gap:8px;align-items:flex-end;">
|
||||
<input type="hidden" name="csrf_token" value="{{.CsrfToken}}">
|
||||
<input type="text" name="razlog" placeholder="Razlog storniranja (opciono)" style="width:240px;">
|
||||
<button type="submit" class="btn-upozorenje"
|
||||
data-potvrda="Stornirati ovu nabavku? Količine artikala biće vraćene na stanje.">
|
||||
Storniraj nabavku
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
{{.Datum.Format "02.01.2006."}}
|
||||
</td>
|
||||
<td style="padding:12px 16px;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
||||
{{if .DobavljacNaziv}}{{.DobavljacNaziv}}{{else}}—{{end}}
|
||||
<span style="display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||||
{{if .DobavljacNaziv}}{{.DobavljacNaziv}}{{else}}—{{end}}
|
||||
{{if .Stornirano}}<span style="padding:2px 8px;border-radius:20px;font-size:11px;font-weight:500;background:rgba(220,38,38,0.12);color:#dc2626;">Stornirano</span>{{end}}
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:12px 16px;font-size:13px;color:var(--tekst-sporedni);">
|
||||
{{if .Napomena}}{{.Napomena}}{{else}}—{{end}}
|
||||
@@ -50,14 +53,6 @@
|
||||
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/nabavke/{{.ID}}" class="btn-primarno-malo">
|
||||
Detalji
|
||||
</a>
|
||||
{{if index $.Dozvole "nabavka.obrisi"}}
|
||||
<form method="POST" action="/nabavke/obrisi/{{.ID}}" style="display:inline;">
|
||||
<button type="submit" class="btn-obrisi-malo"
|
||||
data-potvrda="Da li ste sigurni? Brisanje nabavke ne vraća količine artikala u magacin.">
|
||||
Obriši
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -79,8 +74,9 @@
|
||||
<div class="kartica nabavka-kartica animiraj">
|
||||
<div class="red-izmedju" style="align-items:flex-start;gap:12px;margin-bottom:10px;">
|
||||
<div>
|
||||
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">
|
||||
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||||
{{if .DobavljacNaziv}}{{.DobavljacNaziv}}{{else}}Bez dobavljača{{end}}
|
||||
{{if .Stornirano}}<span style="padding:2px 8px;border-radius:20px;font-size:11px;font-weight:500;background:rgba(220,38,38,0.12);color:#dc2626;">Stornirano</span>{{end}}
|
||||
</div>
|
||||
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:2px;">
|
||||
{{.Datum.Format "02.01.2006."}}
|
||||
@@ -97,14 +93,6 @@
|
||||
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/nabavke/{{.ID}}" class="btn-primarno-malo" style="flex:1;justify-content:center;">
|
||||
Detalji
|
||||
</a>
|
||||
{{if index $.Dozvole "nabavka.obrisi"}}
|
||||
<form method="POST" action="/nabavke/obrisi/{{.ID}}" style="flex:1;">
|
||||
<button type="submit" class="btn-obrisi-malo" style="width:100%;justify-content:center;"
|
||||
data-potvrda="Da li ste sigurni? Brisanje nabavke ne vraća količine artikala u magacin.">
|
||||
Obriši
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
|
||||
Reference in New Issue
Block a user