PDV modul: uslovno prikazivanje + auto cena_konacna + stanje zaliha sa PDV-om
- PDV pravilo (Moduli.pdv) primenjeno na: magacin, usluge, prodaja_detalji, usluge_forma - magacin: toggle cena bez/sa PDV u zaglavlju kolone, jedna kolona - stanje_zaliha: Cena sa PDV i Vred. sa PDV kolone, tamne kartice za zaglavlje - PromeniStatus: auto-izračunavanje cena_konacna (dijagnostika+radovi+delovi) pri Preuzeto - migrations/088: popravlja postojeće Preuzeto naloge bez cene - dashboard: prihod cifra sakrivena, hover 1s → prikaz - izvestaji: aktivni servisi bez Preuzeto, COALESCE u SQL, 0→— - izvestaji.html: vraćeno — umesto 0 din
This commit is contained in:
@@ -200,6 +200,7 @@ type ServisRepository interface {
|
||||
AzurirajNalazDijagnostike(ctx context.Context, id int64, tekst string) error
|
||||
AzurirajUradjeno(ctx context.Context, id int64, tekst string) error
|
||||
AzurirajCenaDijagnostike(ctx context.Context, id int64, cena float64) error
|
||||
AzurirajCenuKonacnu(ctx context.Context, id int64, cena float64) error
|
||||
OdbijPopravku(ctx context.Context, id int64, cena float64) error
|
||||
AzurirajKomentarKlijenta(ctx context.Context, id int64, tekst string) error
|
||||
SacuvajOdlukuKlijenta(ctx context.Context, id int64, odluka string, odgovor string) error
|
||||
|
||||
@@ -27,7 +27,7 @@ func (r *sqliteIzvestajRepo) BrojArtikala(ctx context.Context) (int, error) {
|
||||
func (r *sqliteIzvestajRepo) BrojAktivnihServisa(ctx context.Context) (int, error) {
|
||||
var n int
|
||||
err := r.db.QueryRowContext(ctx,
|
||||
`SELECT COUNT(*) FROM servisni_nalozi WHERE status != 'Završeno'`).Scan(&n)
|
||||
`SELECT COUNT(*) FROM servisni_nalozi WHERE status NOT IN ('Završeno', 'Preuzeto')`).Scan(&n)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: izvestaj.BrojAktivnihServisa: %w", err)
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func (r *sqliteIzvestajRepo) MesecniPrihodProdaja(ctx context.Context) ([]model.
|
||||
|
||||
func (r *sqliteIzvestajRepo) MesecniPrihodServis(ctx context.Context) ([]model.MesecniIznos, error) {
|
||||
return r.mesecniPrihod(ctx, `
|
||||
SELECT substr(datum_zavrsetka, 1, 7), SUM(cena_konacna)
|
||||
SELECT substr(datum_zavrsetka, 1, 7), SUM(COALESCE(cena_konacna, 0))
|
||||
FROM servisni_nalozi
|
||||
WHERE datum_zavrsetka IS NOT NULL
|
||||
AND status = 'Preuzeto'
|
||||
@@ -269,7 +269,9 @@ func (r *sqliteIzvestajRepo) StanjeZaliha(ctx context.Context) ([]model.StanjeZa
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT a.naziv, COALESCE(a.sifra, ''), COALESCE(k.naziv, ''),
|
||||
a.kolicina, a.kolicina_min, a.nabavna_cena, a.prodajna_cena,
|
||||
a.kolicina * a.nabavna_cena AS vrednost
|
||||
a.cena_sa_pdv,
|
||||
a.kolicina * a.nabavna_cena AS vrednost,
|
||||
a.kolicina * a.cena_sa_pdv AS vrednost_sa_pdv
|
||||
FROM artikli a
|
||||
LEFT JOIN kategorije k ON k.id = a.kategorija_id
|
||||
ORDER BY k.naziv ASC, a.naziv ASC`,
|
||||
@@ -283,7 +285,8 @@ func (r *sqliteIzvestajRepo) StanjeZaliha(ctx context.Context) ([]model.StanjeZa
|
||||
for rows.Next() {
|
||||
var s model.StanjeZalihaRed
|
||||
if err := rows.Scan(&s.Naziv, &s.Sifra, &s.Kategorija,
|
||||
&s.Kolicina, &s.KolicinMin, &s.NabavnaCena, &s.ProdajnaCena, &s.VrednostZalihe); err != nil {
|
||||
&s.Kolicina, &s.KolicinMin, &s.NabavnaCena, &s.ProdajnaCena,
|
||||
&s.CenaSaPdv, &s.VrednostZalihe, &s.VrednostSaPdv); err != nil {
|
||||
return nil, fmt.Errorf("ntech: IzvestajRepo.StanjeZaliha: scan: %w", err)
|
||||
}
|
||||
lista = append(lista, s)
|
||||
|
||||
@@ -339,6 +339,16 @@ func (r *ServisRepo) AzurirajCenaDijagnostike(ctx context.Context, id int64, cen
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ServisRepo) AzurirajCenuKonacnu(ctx context.Context, id int64, cena float64) error {
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
"UPDATE servisni_nalozi SET cena_konacna = ? WHERE id = ?", cena, id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisRepo.AzurirajCenuKonacnu: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AzurirajKomentarKlijenta čuva poruku klijenta uz prihvatanje/odbijanje predloga
|
||||
func (r *ServisRepo) AzurirajKomentarKlijenta(ctx context.Context, id int64, tekst string) error {
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
|
||||
@@ -264,9 +264,10 @@ func (h *Handler) PrometniListMagacina(w http.ResponseWriter, r *http.Request) {
|
||||
// PodaciStanjaZaliha su podaci za izveštaj o stanju zaliha
|
||||
type PodaciStanjaZaliha struct {
|
||||
model.PodaciStranice
|
||||
Zalihe []model.StanjeZalihaRed
|
||||
UkupnaVrednost float64
|
||||
BrojArtikala int
|
||||
Zalihe []model.StanjeZalihaRed
|
||||
UkupnaVrednost float64
|
||||
UkupnaVrednostSaPdv float64
|
||||
BrojArtikala int
|
||||
}
|
||||
|
||||
// StanjeZalihaIzvestaj renderuje izveštaj o trenutnom stanju zaliha
|
||||
@@ -282,8 +283,10 @@ func (h *Handler) StanjeZalihaIzvestaj(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var ukupnaVrednost float64
|
||||
var ukupnaVrednostSaPdv float64
|
||||
for _, z := range zalihe {
|
||||
ukupnaVrednost += z.VrednostZalihe
|
||||
ukupnaVrednostSaPdv += z.VrednostSaPdv
|
||||
}
|
||||
|
||||
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||
@@ -292,10 +295,11 @@ func (h *Handler) StanjeZalihaIzvestaj(w http.ResponseWriter, r *http.Request) {
|
||||
ps.NaslovStranice = "Stanje zaliha"
|
||||
|
||||
h.renderujTemplate(w, "stanje_zaliha", PodaciStanjaZaliha{
|
||||
PodaciStranice: ps,
|
||||
Zalihe: zalihe,
|
||||
UkupnaVrednost: ukupnaVrednost,
|
||||
BrojArtikala: len(zalihe),
|
||||
PodaciStranice: ps,
|
||||
Zalihe: zalihe,
|
||||
UkupnaVrednost: ukupnaVrednost,
|
||||
UkupnaVrednostSaPdv: ukupnaVrednostSaPdv,
|
||||
BrojArtikala: len(zalihe),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1969,8 +1969,23 @@ func (h *Handler) PromeniStatus(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// pri prelasku u Preuzeto — sačuvaj naplatu i fiskalizuj
|
||||
// pri prelasku u Preuzeto — auto-izračunaj cenu_konacnu ako nije uneta, pa sačuvaj naplatu i fiskalizuj
|
||||
if noviStatus == model.StatusPreuzeto {
|
||||
nalog, _ := h.ServisRepo.DohvatiID(r.Context(), id)
|
||||
if nalog != nil && nalog.CenaKonacna == nil {
|
||||
// auto-izračunaj: dijagnostika + radovi + delovi
|
||||
radovi, _ := h.ServisniRadoviRepo.DohvatiZaNalog(r.Context(), id)
|
||||
delovi, _ := h.ServisniDeloviRepo.DohvatiZaNalog(r.Context(), id)
|
||||
ukupno := nalog.CenaDijagnostike
|
||||
for _, rad := range radovi {
|
||||
ukupno += rad.Ukupno()
|
||||
}
|
||||
for _, d := range delovi {
|
||||
ukupno += d.Ukupno()
|
||||
}
|
||||
h.ServisRepo.AzurirajCenuKonacnu(r.Context(), id, ukupno)
|
||||
nalog.CenaKonacna = &ukupno
|
||||
}
|
||||
nacin := strings.TrimSpace(r.FormValue("nacin_placanja"))
|
||||
if nacin == "" {
|
||||
nacin = "Gotovina"
|
||||
|
||||
@@ -81,5 +81,7 @@ type StanjeZalihaRed struct {
|
||||
KolicinMin int
|
||||
NabavnaCena float64
|
||||
ProdajnaCena float64
|
||||
CenaSaPdv float64
|
||||
VrednostZalihe float64 // kolicina × nabavna_cena
|
||||
VrednostSaPdv float64 // kolicina × cena_sa_pdv
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user