diff --git a/internal/db/sqlite/prodaja.go b/internal/db/sqlite/prodaja.go index e9f09bf..71b8d86 100644 --- a/internal/db/sqlite/prodaja.go +++ b/internal/db/sqlite/prodaja.go @@ -210,20 +210,21 @@ func (r *ProdajaRepo) Kreiraj(ctx context.Context, n *model.ProdajniNalog, stavk } } - // CenaPoKomadu je neto (bez PDV); PDV se dodaje naviše - cenaBezPdv := s.CenaBezPdv - pdvIznos := s.PdvIznos - if cenaBezPdv == 0 { - cenaBezPdv = s.CenaPoKomadu - pdvIznos = cenaBezPdv * s.PdvStopa / 100 - } - // popust umanjuje cenu po komadu pre računanja ukupnog i PDV-a cenaPoslePopusta := s.CenaPoKomadu if s.PopustProcenat > 0 { cenaPoslePopusta = cenaPoslePopusta * (1 - s.PopustProcenat/100) } ukupnoStavke := float64(s.Kolicina) * cenaPoslePopusta + + // CenaPoKomadu je neto (bez PDV); PDV se dodaje naviše. + // cena_bez_pdv/pdv_iznos moraju biti diskontovani da ostanu konzistentni sa ukupno. + cenaBezPdv := s.CenaBezPdv + pdvIznos := s.PdvIznos + if cenaBezPdv == 0 { + cenaBezPdv = cenaPoslePopusta + pdvIznos = cenaBezPdv * s.PdvStopa / 100 + } _, err = tx.ExecContext(ctx, ` INSERT INTO stavke_prodaje (nalog_id, artikal_id, kolicina, cena_po_komadu, popust_procenat, ukupno, pdv_stopa, pdv_iznos, cena_bez_pdv) diff --git a/internal/db/sqlite/prodaja_kreiraj_test.go b/internal/db/sqlite/prodaja_kreiraj_test.go index 5b65ec5..cc36e04 100644 --- a/internal/db/sqlite/prodaja_kreiraj_test.go +++ b/internal/db/sqlite/prodaja_kreiraj_test.go @@ -81,7 +81,7 @@ func TestProdajaKreiraj_NedovoljnoStanja(t *testing.T) { } // TestProdajaKreiraj_PdvAutoKalkulacija: kada CenaBezPdv=0 a PdvStopa>0, -// cena_bez_pdv i pdv_iznos se automatski računaju iz bruto cene. +// cena_bez_pdv i pdv_iznos se automatski računaju iz neto cene (CenaPoKomadu je neto). func TestProdajaKreiraj_PdvAutoKalkulacija(t *testing.T) { ctx := context.Background() baza := testDB(t) @@ -92,11 +92,11 @@ func TestProdajaKreiraj_PdvAutoKalkulacija(t *testing.T) { Naziv: "Tastatura", Tip: model.TipProizvod, Kolicina: 10, }) - // bruto cena 1200, PDV 20% → neto = 1200/1.2 = 1000, pdv_iznos = 200 + // neto cena 1000, PDV 20% → pdv_iznos = 200 _, err := prodRepo.Kreiraj(ctx, &model.ProdajniNalog{ - BrojNaloga: "PR-PDV-001", Ukupno: 1200, NacinPlacanja: "gotovina", Datum: time.Now(), + BrojNaloga: "PR-PDV-001", Ukupno: 1000, NacinPlacanja: "gotovina", Datum: time.Now(), }, []model.StavkaProdaje{ - {ArtikalID: artID, Kolicina: 1, CenaPoKomadu: 1200, PdvStopa: 20}, + {ArtikalID: artID, Kolicina: 1, CenaPoKomadu: 1000, PdvStopa: 20}, // CenaBezPdv=0 namerno — treba da se auto-izračuna }, nil) if err != nil { diff --git a/internal/fiskal/mapiranje.go b/internal/fiskal/mapiranje.go index 5c7564a..0a4f92d 100644 --- a/internal/fiskal/mapiranje.go +++ b/internal/fiskal/mapiranje.go @@ -62,13 +62,14 @@ func NapraviZahtev( if s.PdvStopa > 0 { stopa = s.PdvStopa } - // CenaPoKomadu je neto cena — konvertujemo u bruto; popust umanjuje neto cenu pre PDV-a + // CenaBezPdv iz baze je već diskontovana (popust primenjen pri kreiranju naloga); + // popust se ponovo primenjuje samo u fallback grani kad CenaBezPdv nije popunjena. netoCena := s.CenaBezPdv if netoCena == 0 { netoCena = s.CenaPoKomadu - } - if s.PopustProcenat > 0 { - netoCena = math.Round(netoCena*(1-s.PopustProcenat/100)*100) / 100 + if s.PopustProcenat > 0 { + netoCena = math.Round(netoCena*(1-s.PopustProcenat/100)*100) / 100 + } } brutoCena := BrutoCena(netoCena, stopa) brutoTotal := math.Round(brutoCena*float64(s.Kolicina)*100) / 100 diff --git a/internal/model/pdv_evidencija.go b/internal/model/pdv_evidencija.go index d96153c..bb2018f 100644 --- a/internal/model/pdv_evidencija.go +++ b/internal/model/pdv_evidencija.go @@ -120,7 +120,11 @@ func KirIzProdaje(nalog ProdajniNalog, stavke []StavkaProdaje, kupacNaziv, kupac IzvorID: &id, } for _, s := range stavke { - k.DodajNeto(float64(s.Kolicina)*s.CenaPoKomadu, s.PdvStopa) + cenaPoslePopusta := s.CenaPoKomadu + if s.PopustProcenat > 0 { + cenaPoslePopusta = cenaPoslePopusta * (1 - s.PopustProcenat/100) + } + k.DodajNeto(float64(s.Kolicina)*cenaPoslePopusta, s.PdvStopa) } return k } diff --git a/internal/model/pdv_evidencija_test.go b/internal/model/pdv_evidencija_test.go index 5287feb..864dcc8 100644 --- a/internal/model/pdv_evidencija_test.go +++ b/internal/model/pdv_evidencija_test.go @@ -11,9 +11,9 @@ func blizu(a, b float64) bool { return math.Abs(a-b) < 0.01 } func TestKirIzProdaje(t *testing.T) { nalog := ProdajniNalog{ID: 5, BrojNaloga: "P-1", Datum: time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC)} stavke := []StavkaProdaje{ - // 20%: 2 × 120 = 240 (osnovica 200, PDV 40) + // 20%: CenaPoKomadu je NETO → osnovica 2×120=240, PDV 240×20%=48 {Kolicina: 2, CenaPoKomadu: 120, PdvStopa: 20}, - // 10%: 1 × 110 = 110 (osnovica 100, PDV 10) + // 10%: osnovica 1×110=110, PDV 110×10%=11 {Kolicina: 1, CenaPoKomadu: 110, PdvStopa: 10}, // 0%: 1 × 50 = 50 (oslobođeno, bez PDV) {Kolicina: 1, CenaPoKomadu: 50, PdvStopa: 0}, @@ -27,17 +27,17 @@ func TestKirIzProdaje(t *testing.T) { if k.BrojDokumenta != "P-1" || k.KupacNaziv != "Kupac doo" || k.KupacPib != "123456789" { t.Errorf("zaglavlje ne odgovara: %+v", k) } - if !blizu(k.OsnovicaOpsta, 200) || !blizu(k.PdvOpsta, 40) { - t.Errorf("opšta: osnovica=%v pdv=%v, očekivano 200/40", k.OsnovicaOpsta, k.PdvOpsta) + if !blizu(k.OsnovicaOpsta, 240) || !blizu(k.PdvOpsta, 48) { + t.Errorf("opšta: osnovica=%v pdv=%v, očekivano 240/48", k.OsnovicaOpsta, k.PdvOpsta) } - if !blizu(k.OsnovicaPosebna, 100) || !blizu(k.PdvPosebna, 10) { - t.Errorf("posebna: osnovica=%v pdv=%v, očekivano 100/10", k.OsnovicaPosebna, k.PdvPosebna) + if !blizu(k.OsnovicaPosebna, 110) || !blizu(k.PdvPosebna, 11) { + t.Errorf("posebna: osnovica=%v pdv=%v, očekivano 110/11", k.OsnovicaPosebna, k.PdvPosebna) } if !blizu(k.OslobodenSaPravom, 50) { t.Errorf("oslobođeno=%v, očekivano 50", k.OslobodenSaPravom) } - if !blizu(k.Ukupno, 400) { - t.Errorf("ukupno=%v, očekivano 400 (240+110+50)", k.Ukupno) + if !blizu(k.Ukupno, 459) { + t.Errorf("ukupno=%v, očekivano 459 (288+121+50 bruto)", k.Ukupno) } }