Sprečeno dupliranje prodaje/servisa, alat za usklađivanje šifri artikla, ispravke osvežavanja stranica, zaštita od duplikata kategorije/artikla/usluge/troška

- Prodaja i servis: broj naloga se generiše unutar transakcije upisa umesto unapred u handleru, čime se otklanja duplo kreiranje naloga pri dvostrukom slanju forme
- Servis izmena: uklonjen sudar generičkog i sopstvenog auto-snimanja forme (dva paralelna POST-a)
- Magacin: novi alat 'Uskladi šifre sa kategorijama' za masovnu ispravku šifri artikala posle uvođenja šifarnika po kategoriji
- Ispravljeno da forme na 9 stranica (kategorije, admin korisnici/dozvole, profil, podešavanja) posle akcije osveže prikaz umesto da ostanu zastarele do F5
- Kategorija, artikal, usluga i trošak: sprečeno dupliranje naziva/šifre/koda (UNIQUE indeksi + razumljive poruke grešaka)
This commit is contained in:
2026-07-07 03:50:31 +02:00
parent 1ff572dd77
commit bc60288a0d
28 changed files with 682 additions and 110 deletions
+37 -33
View File
@@ -192,28 +192,30 @@
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Moj avatar</span>
</div>
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px;">
<div style="width:64px;height:64px;border-radius:10px;overflow:hidden;border:0.5px solid var(--ivica);flex-shrink:0;background:var(--pozadina);display:flex;align-items:center;justify-content:center;">
{{if .AvatarPutanja}}
<img src="{{.AvatarPutanja}}" alt="Moj avatar" style="width:100%;height:100%;object-fit:cover;">
{{else}}
<span style="font-size:22px;font-weight:600;color:var(--tekst-sporedni);">{{if .KorisnikIme}}{{slice .KorisnikIme 0 2}}{{else}}NT{{end}}</span>
{{end}}
<div id="avatar-blok">
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px;">
<div style="width:64px;height:64px;border-radius:10px;overflow:hidden;border:0.5px solid var(--ivica);flex-shrink:0;background:var(--pozadina);display:flex;align-items:center;justify-content:center;">
{{if .AvatarPutanja}}
<img src="{{.AvatarPutanja}}" alt="Moj avatar" style="width:100%;height:100%;object-fit:cover;">
{{else}}
<span style="font-size:22px;font-weight:600;color:var(--tekst-sporedni);">{{if .KorisnikIme}}{{slice .KorisnikIme 0 2}}{{else}}NT{{end}}</span>
{{end}}
</div>
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.5;">
Slika se prikazuje kao dugme u gornjoj traci.<br>
Dozvoljeni formati: JPG, PNG, WebP. Maksimum 2 MB.
</div>
</div>
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.5;">
Slika se prikazuje kao dugme u gornjoj traci.<br>
Dozvoljeni formati: JPG, PNG, WebP. Maksimum 2 MB.
</div>
</div>
{{if .AvatarPutanja}}
<form method="POST" action="/profil/avatar/ukloni" style="display:inline;margin-bottom:12px;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit" style="background:none;border:0.5px solid #dc2626;color:#dc2626;padding:6px 14px;border-radius:8px;font-size:13px;cursor:pointer;margin-bottom:12px;">
Ukloni avatar
</button>
</form>
{{end}}
{{if .AvatarPutanja}}
<form method="POST" action="/profil/avatar/ukloni" data-refresh="#avatar-blok" style="display:inline;margin-bottom:12px;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit" style="background:none;border:0.5px solid #dc2626;color:#dc2626;padding:6px 14px;border-radius:8px;font-size:13px;cursor:pointer;margin-bottom:12px;">
Ukloni avatar
</button>
</form>
{{end}}
</div>
<form method="POST" action="/profil/avatar" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
@@ -240,20 +242,22 @@
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Moja pozadinska slika</span>
</div>
{{if .LokalnaPozadina}}
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
<img src="{{.LokalnaPozadina}}" alt="Trenutna lična pozadina"
style="width:120px;height:70px;object-fit:cover;border-radius:6px;border:0.5px solid var(--ivica);flex-shrink:0;">
<form method="POST" action="/profil/pozadina/ukloni">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit"
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;font-size:13px;"
data-potvrda="Ukloniti ličnu pozadinsku sliku?">
Ukloni
</button>
</form>
<div id="pozadina-blok">
{{if .LokalnaPozadina}}
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
<img src="{{.LokalnaPozadina}}" alt="Trenutna lična pozadina"
style="width:120px;height:70px;object-fit:cover;border-radius:6px;border:0.5px solid var(--ivica);flex-shrink:0;">
<form method="POST" action="/profil/pozadina/ukloni" data-refresh="#pozadina-blok">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit"
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;font-size:13px;"
data-potvrda="Ukloniti ličnu pozadinsku sliku?">
Ukloni
</button>
</form>
</div>
{{end}}
</div>
{{end}}
<form method="POST" action="/profil/pozadina" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">