feat(magacin): nivelacija — promena cene uz trag (Faza A)

Tabela nivelacije (migr 045) beleži svaku promenu prodajne cene:
artikal, stara→nova cena, razlog, izvor, korisnik, datum. Dva okidača:
posebna akcija „Promeni cenu" (modal, izvor 'rucno') i auto-trag pri
izmeni artikla (izvor 'izmena'). PromeniCenu je transakciono (update
cene + upis zapisa). Pregled /nivelacije sa filterom perioda i razlikom
(+/− i %). Modal otvara svoj nextElementSibling — radi i na mobilnom
uprkos dupliranim id-jevima iz dva rasporeda.
This commit is contained in:
2026-06-14 09:37:49 +02:00
parent c9d4704c3d
commit 0f1f65c7f7
13 changed files with 463 additions and 2 deletions
+37
View File
@@ -0,0 +1,37 @@
package model
import "time"
// Nivelacija je zapis o promeni prodajne cene artikla (revizioni trag).
// Razlika i procenat se izvode iz stare i nove cene (ne čuvaju se u bazi).
type Nivelacija struct {
ID int64
ArtikalID int64
ArtikalNaziv string // iz JOIN-a, radi prikaza; nije kolona u nivelacije
StaraCena float64
NovaCena float64
Razlog string
Izvor string // "rucno" | "izmena" | "kalkulacija"
KorisnikID *int64
KorisnikIme string // iz JOIN-a, radi prikaza
Datum time.Time
DatumUnosa time.Time
}
// Razlika vraća apsolutnu promenu cene (nova stara); negativna znači pojeftinjenje.
func (n Nivelacija) Razlika() float64 {
return n.NovaCena - n.StaraCena
}
// Procenat vraća procentualnu promenu u odnosu na staru cenu (0 ako je stara cena 0).
func (n Nivelacija) Procenat() float64 {
if n.StaraCena == 0 {
return 0
}
return (n.NovaCena - n.StaraCena) / n.StaraCena * 100
}
// Poskupljenje vraća true kada je nova cena veća od stare.
func (n Nivelacija) Poskupljenje() bool {
return n.NovaCena > n.StaraCena
}
+23
View File
@@ -0,0 +1,23 @@
package model
import "testing"
func TestNivelacija(t *testing.T) {
// poskupljenje: 100 → 120 = +20, +20%
n := Nivelacija{StaraCena: 100, NovaCena: 120}
if !blizu(n.Razlika(), 20) || !blizu(n.Procenat(), 20) || !n.Poskupljenje() {
t.Errorf("razlika=%v procenat=%v poskupljenje=%v, očekivano 20/20/true", n.Razlika(), n.Procenat(), n.Poskupljenje())
}
// pojeftinjenje: 200 → 150 = -50, -25%
n2 := Nivelacija{StaraCena: 200, NovaCena: 150}
if !blizu(n2.Razlika(), -50) || !blizu(n2.Procenat(), -25) || n2.Poskupljenje() {
t.Errorf("razlika=%v procenat=%v poskupljenje=%v, očekivano -50/-25/false", n2.Razlika(), n2.Procenat(), n2.Poskupljenje())
}
// stara cena 0 → procenat 0 (bez deljenja nulom)
n3 := Nivelacija{StaraCena: 0, NovaCena: 80}
if !blizu(n3.Procenat(), 0) {
t.Errorf("procenat=%v, očekivano 0 kada je stara cena 0", n3.Procenat())
}
}