From ff59c3edcfa3e802c57c4c4a0cbef9d7bd6625ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Sat, 27 Jun 2026 02:06:18 +0200 Subject: [PATCH] =?UTF-8?q?PDV=20pravilo=20na=20=C5=A1tampanim=20dokumenti?= =?UTF-8?q?ma=20+=20fiksni=20layout=20+=20QR=20popravka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PDV uslovi (Moduli.pdv) na: predračun, otpremnica, garantni list, prodaja_stampa - Modal za preuzimanje: jedna cena (sa/bez PDV), ne duplo - Javna status stranica: PDV uslovi za cene, predlog, checkbox-ove - Svi print templejti: viewport=device-width+min-width, bez responsive - JavniToken generisan za postojeće naloge bez tokena (QR popravka) - UkupnoSaPdv() metode na ServisniRad i ServisniDeoSaArtiklom - UkupnoBezPdv() na StavkaProdaje --- internal/db/sqlite/servisni_delovi.go | 5 +- internal/db/sqlite/servisni_radovi.go | 5 +- internal/handler/prodaja.go | 10 + internal/handler/servis.go | 313 +++++++++++------- internal/model/prodaja.go | 5 + internal/model/servis.go | 14 + web/templates/stranice/prodaja_stampa.html | 16 +- web/templates/stranice/servis_detalji.html | 48 ++- .../stranice/servis_garantni_list.html | 20 +- web/templates/stranice/servis_nalepnica.html | 2 +- web/templates/stranice/servis_otpremnica.html | 28 +- web/templates/stranice/servis_predracun.html | 26 +- .../stranice/servis_radni_nalog.html | 4 +- web/templates/stranice/servis_revers.html | 4 +- .../stranice/servis_status_javni.html | 18 +- 15 files changed, 335 insertions(+), 183 deletions(-) diff --git a/internal/db/sqlite/servisni_delovi.go b/internal/db/sqlite/servisni_delovi.go index a5d2270..bdbdc07 100644 --- a/internal/db/sqlite/servisni_delovi.go +++ b/internal/db/sqlite/servisni_delovi.go @@ -24,7 +24,7 @@ func NoviServisniDeloviRepo(db *sql.DB) *ServisniDeloviRepo { func (r *ServisniDeloviRepo) DohvatiZaNalog(ctx context.Context, nalogID int64) ([]model.ServisniDeoSaArtiklom, error) { redovi, err := r.db.QueryContext(ctx, ` SELECT sd.id, sd.nalog_id, sd.artikal_id, sd.kolicina, sd.cena_komada, sd.datum, - sd.predlozeno, a.naziv, a.sifra + sd.predlozeno, a.naziv, a.sifra, a.pdv_stopa FROM servisni_delovi sd JOIN artikli a ON a.id = sd.artikal_id WHERE sd.nalog_id = ? @@ -39,11 +39,12 @@ func (r *ServisniDeloviRepo) DohvatiZaNalog(ctx context.Context, nalogID int64) var d model.ServisniDeoSaArtiklom err := redovi.Scan( &d.ID, &d.NalogID, &d.ArtikalID, &d.Kolicina, &d.CenaKomada, &d.Datum, - &d.Predlozeno, &d.ArtikalNaziv, &d.ArtikalSifra, + &d.Predlozeno, &d.ArtikalNaziv, &d.ArtikalSifra, &d.PdvStopa, ) if err != nil { return nil, fmt.Errorf("ntech: ServisniDeloviRepo.DohvatiZaNalog: scan: %w", err) } + d.CenaSaPdv = d.CenaKomada * (1 + d.PdvStopa/100) rezultat = append(rezultat, d) } diff --git a/internal/db/sqlite/servisni_radovi.go b/internal/db/sqlite/servisni_radovi.go index b1d92df..02a0d14 100644 --- a/internal/db/sqlite/servisni_radovi.go +++ b/internal/db/sqlite/servisni_radovi.go @@ -22,7 +22,7 @@ func NoviServisniRadoviRepo(baza *sql.DB) *ServisniRadoviRepo { func (r *ServisniRadoviRepo) DohvatiZaNalog(ctx context.Context, nalogID int64) ([]model.ServisniRad, error) { redovi, err := r.db.QueryContext(ctx, ` SELECT sr.id, sr.nalog_id, COALESCE(sr.usluga_id, 0), sr.naziv, sr.kolicina, sr.cena_komada, sr.datum, sr.predlozeno, - COALESCE(u.sifra, '') + COALESCE(u.sifra, ''), COALESCE(u.pdv_stopa, 20.0) FROM servis_radovi sr LEFT JOIN usluge u ON u.id = sr.usluga_id WHERE sr.nalog_id = ? ORDER BY sr.id`, nalogID) @@ -34,9 +34,10 @@ func (r *ServisniRadoviRepo) DohvatiZaNalog(ctx context.Context, nalogID int64) var radovi []model.ServisniRad for redovi.Next() { var rad model.ServisniRad - if err := redovi.Scan(&rad.ID, &rad.NalogID, &rad.UslugaID, &rad.Naziv, &rad.Kolicina, &rad.CenaKomada, &rad.Datum, &rad.Predlozeno, &rad.Sifra); err != nil { + if err := redovi.Scan(&rad.ID, &rad.NalogID, &rad.UslugaID, &rad.Naziv, &rad.Kolicina, &rad.CenaKomada, &rad.Datum, &rad.Predlozeno, &rad.Sifra, &rad.PdvStopa); err != nil { return nil, fmt.Errorf("ntech: ServisniRadoviRepo.DohvatiZaNalog: %w", err) } + rad.CenaSaPdv = rad.CenaKomada * (1 + rad.PdvStopa/100) radovi = append(radovi, rad) } return radovi, redovi.Err() diff --git a/internal/handler/prodaja.go b/internal/handler/prodaja.go index 9fbe0fe..9897d07 100644 --- a/internal/handler/prodaja.go +++ b/internal/handler/prodaja.go @@ -53,6 +53,8 @@ type PodaciStampeProdaje struct { Nalog model.ProdajniNalog Stavke []model.StavkaProdajeSaArtiklom KlijentNaziv string + Moduli map[string]bool + UkupnoBezPdv float64 NazivFirme string Podnazlov string Adresa string @@ -370,10 +372,18 @@ func (h *Handler) StampaProdaje(w http.ResponseWriter, r *http.Request) { } } + moduli := config.SviModuli(podesavanja) + var ukupnoBezPdv float64 + for _, s := range stavke { + ukupnoBezPdv += s.CenaBezPdv * float64(s.Kolicina) + } + podaci := PodaciStampeProdaje{ Nalog: *nalog, Stavke: stavke, KlijentNaziv: klijentNaziv, + Moduli: moduli, + UkupnoBezPdv: ukupnoBezPdv, NazivFirme: podesavanja["naziv_firme"], Podnazlov: podesavanja["podnazlov"], Adresa: podesavanja["adresa"], diff --git a/internal/handler/servis.go b/internal/handler/servis.go index 66479f7..0af7a52 100644 --- a/internal/handler/servis.go +++ b/internal/handler/servis.go @@ -70,9 +70,13 @@ type PodaciDetaljiNaloga struct { Sacuvano bool UkupnoDelovi float64 UkupnoRadovi float64 + UkupnoDeloviSaPdv float64 + UkupnoRadoviSaPdv float64 UkupnoSve float64 + UkupnoSveSaPdv float64 Avans float64 PreostaloSve float64 + PreostaloSveSaPdv float64 ZakljucanStatus bool // onemogući promenu statusa dok ima potraživanih delova CenaDijagnostikePredlog string // podrazumevana cena dijagnostike iz podešavanja (za prefill input-a) KorisceneUsluge map[int64]bool // ID-evi usluga već dodatih na nalog — izostavljaju se iz dropdown-a @@ -645,13 +649,16 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) { } var ukupnoDelovi, ukupnoRadovi float64 + var ukupnoDeloviSaPdv, ukupnoRadoviSaPdv float64 for _, d := range delovi { ukupnoDelovi += d.Ukupno() + ukupnoDeloviSaPdv += d.CenaSaPdv * float64(d.Kolicina) } // skup već dodatih usluga — izostavljaju se iz dropdown-a da se ista usluga ne doda dvaput korisceneUsluge := make(map[int64]bool, len(radovi)) for _, rad := range radovi { ukupnoRadovi += rad.Ukupno() + ukupnoRadoviSaPdv += rad.CenaSaPdv * rad.Kolicina if rad.UslugaID != 0 { korisceneUsluge[rad.UslugaID] = true } @@ -665,6 +672,14 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) { } else { ukupnoSve = ukupnoRadovi + ukupnoDelovi } + // ukupno sa PDV-om —suma CenaSaPdv za radove i delove + var ukupnoSveSaPdv float64 + for _, rad := range radovi { + ukupnoSveSaPdv += rad.CenaSaPdv * rad.Kolicina + } + for _, d := range delovi { + ukupnoSveSaPdv += d.CenaSaPdv * float64(d.Kolicina) + } avans := 0.0 if nalog.Avans != nil { avans = *nalog.Avans @@ -673,6 +688,10 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) { if preostaloSve < 0 { preostaloSve = 0 } + preostaloSveSaPdv := ukupnoSveSaPdv - avans + if preostaloSveSaPdv < 0 { + preostaloSveSaPdv = 0 + } zakljucanStatus := false for _, d := range delovi { @@ -704,9 +723,13 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) { Sacuvano: r.URL.Query().Get("sacuvano") == "1", UkupnoDelovi: ukupnoDelovi, UkupnoRadovi: ukupnoRadovi, + UkupnoDeloviSaPdv: ukupnoDeloviSaPdv, + UkupnoRadoviSaPdv: ukupnoRadoviSaPdv, UkupnoSve: ukupnoSve, + UkupnoSveSaPdv: ukupnoSveSaPdv, Avans: avans, PreostaloSve: preostaloSve, + PreostaloSveSaPdv: preostaloSveSaPdv, ZakljucanStatus: zakljucanStatus, CenaDijagnostikePredlog: podesavanja["servis_cena_dijagnostike"], KorisceneUsluge: korisceneUsluge, @@ -1371,24 +1394,29 @@ func (h *Handler) StampaRadnogNaloga(w http.ResponseWriter, r *http.Request) { // PodaciOtpremnice su podaci za otpremnicu pri preuzimanju uređaja type PodaciOtpremnice struct { - Nalog model.ServisniNalog - Radovi []model.ServisniRad - ServisniDelovi []model.ServisniDeoSaArtiklom - UkupnoDelovi float64 - PreostaloSve float64 - ImaAvans bool - QRKod string - Klijent *model.Klijent - KlijentNaziv string - TehnicarNaziv string - NazivFirme string - LogoPutanja string - Podnazlov string - Adresa string - Telefon string - PIB string - MaticniBroj string - Barkod string // base64 PNG Code128 barkoda broja naloga + Nalog model.ServisniNalog + Radovi []model.ServisniRad + ServisniDelovi []model.ServisniDeoSaArtiklom + UkupnoDelovi float64 + UkupnoDeloviSaPdv float64 + UkupnoSve float64 + UkupnoSveSaPdv float64 + PreostaloSve float64 + PreostaloSveSaPdv float64 + ImaAvans bool + QRKod string + Klijent *model.Klijent + KlijentNaziv string + TehnicarNaziv string + Moduli map[string]bool + NazivFirme string + LogoPutanja string + Podnazlov string + Adresa string + Telefon string + PIB string + MaticniBroj string + Barkod string // base64 PNG Code128 barkoda broja naloga } // StampaOtpremnice renderuje otpremnicu pri preuzimanju uređaja od strane klijenta @@ -1446,14 +1474,17 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) { } var ukupnoDelovi float64 + var ukupnoDeloviSaPdv float64 for _, d := range delovi { ukupnoDelovi += d.Ukupno() + ukupnoDeloviSaPdv += d.CenaSaPdv * float64(d.Kolicina) } - var preostaloSve float64 + var ukupnoSve, ukupnoSveSaPdv, preostaloSve, preostaloSveSaPdv float64 var imaAvans bool if nalog.PopravkaOdbijena { // klijent odbio popravku — naplaćuje se samo dijagnostika - ukupnoSve := nalog.CenaDijagnostike + ukupnoSve = nalog.CenaDijagnostike + ukupnoSveSaPdv = nalog.CenaDijagnostike avans := 0.0 if nalog.Avans != nil && *nalog.Avans > 0 { avans = *nalog.Avans @@ -1463,8 +1494,10 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) { if preostaloSve < 0 { preostaloSve = 0 } + preostaloSveSaPdv = preostaloSve } else if nalog.CenaKonacna != nil { - ukupnoSve := *nalog.CenaKonacna + ukupnoDelovi + ukupnoSve = *nalog.CenaKonacna + ukupnoDelovi + ukupnoSveSaPdv = *nalog.CenaKonacna + ukupnoDeloviSaPdv avans := 0.0 if nalog.Avans != nil && *nalog.Avans > 0 { avans = *nalog.Avans @@ -1474,8 +1507,14 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) { if preostaloSve < 0 { preostaloSve = 0 } + preostaloSveSaPdv = ukupnoSveSaPdv - avans + if preostaloSveSaPdv < 0 { + preostaloSveSaPdv = 0 + } } + moduli := config.SviModuli(podesavanja) + nalogURL := qrNalogURL(r, nalog.JavniToken, podesavanja["qr_bazni_url"]) var qrKodOtpr string if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil { @@ -1495,24 +1534,29 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) { } h.renderujStandalone(w, "servis_otpremnica", PodaciOtpremnice{ - Nalog: *nalog, - Radovi: radovi, - ServisniDelovi: delovi, - UkupnoDelovi: ukupnoDelovi, - PreostaloSve: preostaloSve, - ImaAvans: imaAvans, - QRKod: qrKodOtpr, - Klijent: klijent, - KlijentNaziv: klijentNaziv, - TehnicarNaziv: tehnicarNaziv, - NazivFirme: podesavanja["naziv_firme"], - LogoPutanja: logoZaDokument(podesavanja), - Podnazlov: podesavanja["podnazlov"], - Adresa: podesavanja["adresa"], - Telefon: podesavanja["telefon"], - PIB: podesavanja["pib"], - MaticniBroj: podesavanja["maticni_broj"], - Barkod: barkodNaloga(nalog.BrojNaloga), + Nalog: *nalog, + Radovi: radovi, + ServisniDelovi: delovi, + UkupnoDelovi: ukupnoDelovi, + UkupnoDeloviSaPdv: ukupnoDeloviSaPdv, + UkupnoSve: ukupnoSve, + UkupnoSveSaPdv: ukupnoSveSaPdv, + PreostaloSve: preostaloSve, + PreostaloSveSaPdv: preostaloSveSaPdv, + ImaAvans: imaAvans, + QRKod: qrKodOtpr, + Klijent: klijent, + KlijentNaziv: klijentNaziv, + TehnicarNaziv: tehnicarNaziv, + Moduli: moduli, + NazivFirme: podesavanja["naziv_firme"], + LogoPutanja: logoZaDokument(podesavanja), + Podnazlov: podesavanja["podnazlov"], + Adresa: podesavanja["adresa"], + Telefon: podesavanja["telefon"], + PIB: podesavanja["pib"], + MaticniBroj: podesavanja["maticni_broj"], + Barkod: barkodNaloga(nalog.BrojNaloga), }) } @@ -1527,6 +1571,7 @@ type PodaciGarantnog struct { KlijentNaziv string TehnicarNaziv string Uslovi string + Moduli map[string]bool NazivFirme string LogoPutanja string Podnazlov string @@ -1612,6 +1657,7 @@ func (h *Handler) StampaGarantnog(w http.ResponseWriter, r *http.Request) { KlijentNaziv: klijentNaziv, TehnicarNaziv: tehnicarNaziv, Uslovi: vrednostIliDefault(podesavanja, "servis_uslovi", podrazumevaniUsloviServisa), + Moduli: config.SviModuli(podesavanja), NazivFirme: podesavanja["naziv_firme"], LogoPutanja: logoZaDokument(podesavanja), Podnazlov: podesavanja["podnazlov"], @@ -1717,27 +1763,31 @@ func (h *Handler) StampaReversa(w http.ResponseWriter, r *http.Request) { // PodaciPredracuna su podaci za predračun — procenu cene za tražene radove i delove, // koju klijent odobrava pre popravke. Gradi se iz stavki radova i delova na nalogu. type PodaciPredracuna struct { - Nalog model.ServisniNalog - Radovi []model.ServisniRad - UkupnoRad float64 - ServisniDelovi []model.ServisniDeoSaArtiklom - UkupnoDelovi float64 - UkupnoSve float64 - DatumIzdavanja time.Time - VaziDo time.Time - Klauzula string - QRKod string - Klijent *model.Klijent - KlijentNaziv string - TehnicarNaziv string - NazivFirme string - LogoPutanja string - Podnazlov string - Adresa string - Telefon string - PIB string - MaticniBroj string - Barkod string // base64 PNG Code128 barkoda broja naloga + Nalog model.ServisniNalog + Radovi []model.ServisniRad + UkupnoRad float64 + UkupnoRadSaPdv float64 + ServisniDelovi []model.ServisniDeoSaArtiklom + UkupnoDelovi float64 + UkupnoDeloviSaPdv float64 + UkupnoSve float64 + UkupnoSveSaPdv float64 + DatumIzdavanja time.Time + VaziDo time.Time + Klauzula string + QRKod string + Klijent *model.Klijent + KlijentNaziv string + TehnicarNaziv string + Moduli map[string]bool + NazivFirme string + LogoPutanja string + Podnazlov string + Adresa string + Telefon string + PIB string + MaticniBroj string + Barkod string // base64 PNG Code128 barkoda broja naloga } // StampaPredracuna renderuje predračun (procenu cene) na osnovu traženih radova i delova @@ -1791,14 +1841,22 @@ func (h *Handler) StampaPredracuna(w http.ResponseWriter, r *http.Request) { } var ukupnoRad float64 + var ukupnoRadSaPdv float64 for _, rd := range radovi { ukupnoRad += rd.Ukupno() + ukupnoRadSaPdv += rd.CenaSaPdv * rd.Kolicina } var ukupnoDelovi float64 + var ukupnoDeloviSaPdv float64 for _, d := range delovi { ukupnoDelovi += d.Ukupno() + ukupnoDeloviSaPdv += d.CenaSaPdv * float64(d.Kolicina) } + ukupnoSve := ukupnoRad + ukupnoDelovi + ukupnoSveSaPdv := ukupnoRadSaPdv + ukupnoDeloviSaPdv + moduli := config.SviModuli(podesavanja) + // rok važenja iz podešavanja (default 7 dana) rok := 7 if v, err := strconv.Atoi(podesavanja["predracun_rok_dana"]); err == nil && v > 0 { @@ -1814,27 +1872,31 @@ func (h *Handler) StampaPredracuna(w http.ResponseWriter, r *http.Request) { } h.renderujStandalone(w, "servis_predracun", PodaciPredracuna{ - Nalog: *nalog, - Radovi: radovi, - UkupnoRad: ukupnoRad, - ServisniDelovi: delovi, - UkupnoDelovi: ukupnoDelovi, - UkupnoSve: ukupnoRad + ukupnoDelovi, - DatumIzdavanja: datumIzdavanja, - VaziDo: vaziDo, - Klauzula: vrednostIliDefault(podesavanja, "servis_klauzula_predracuna", podrazumevanaKlauzulaPredracuna), - QRKod: qrKod, - Klijent: klijent, - KlijentNaziv: klijentNaziv, - TehnicarNaziv: tehnicarNaziv, - NazivFirme: podesavanja["naziv_firme"], - LogoPutanja: logoZaDokument(podesavanja), - Podnazlov: podesavanja["podnazlov"], - Adresa: podesavanja["adresa"], - Telefon: podesavanja["telefon"], - PIB: podesavanja["pib"], - MaticniBroj: podesavanja["maticni_broj"], - Barkod: barkodNaloga(nalog.BrojNaloga), + Nalog: *nalog, + Radovi: radovi, + UkupnoRad: ukupnoRad, + UkupnoRadSaPdv: ukupnoRadSaPdv, + ServisniDelovi: delovi, + UkupnoDelovi: ukupnoDelovi, + UkupnoDeloviSaPdv: ukupnoDeloviSaPdv, + UkupnoSve: ukupnoSve, + UkupnoSveSaPdv: ukupnoSveSaPdv, + DatumIzdavanja: datumIzdavanja, + VaziDo: vaziDo, + Klauzula: vrednostIliDefault(podesavanja, "servis_klauzula_predracuna", podrazumevanaKlauzulaPredracuna), + QRKod: qrKod, + Klijent: klijent, + KlijentNaziv: klijentNaziv, + TehnicarNaziv: tehnicarNaziv, + Moduli: moduli, + NazivFirme: podesavanja["naziv_firme"], + LogoPutanja: logoZaDokument(podesavanja), + Podnazlov: podesavanja["podnazlov"], + Adresa: podesavanja["adresa"], + Telefon: podesavanja["telefon"], + PIB: podesavanja["pib"], + MaticniBroj: podesavanja["maticni_broj"], + Barkod: barkodNaloga(nalog.BrojNaloga), }) } @@ -2533,24 +2595,28 @@ func (h *Handler) OdbijPopravku(w http.ResponseWriter, r *http.Request) { // PodaciJavnogStatusa su podaci za javnu status stranicu servisnog naloga type PodaciJavnogStatusa struct { - Nalog model.ServisniNalog - NazivFirme string - LogoPutanja string - Podnazlov string - Adresa string - Telefon string - PIB string - MaticniBroj string - Radovi []model.ServisniRad // ugrađeni/odobreni - ServisniDelovi []model.ServisniDeoSaArtiklom // ugrađeni/odobreni - UkupnoSve float64 // zbir ugrađenih (radovi + delovi) - PredlozeniRadovi []model.ServisniRad - PredlozeniDelovi []model.ServisniDeoSaArtiklom - UkupnoPredlog float64 // zbir predloženih (radovi + delovi) - ImaPredlog bool - UkupnoSaPredlogom float64 // ukupno ugrađeno + predloženo - Odgovoreno bool // klijent već odgovorio (nema predloga, nije „Primljeno") - SviStatusi []string + Nalog model.ServisniNalog + NazivFirme string + LogoPutanja string + Podnazlov string + Adresa string + Telefon string + PIB string + MaticniBroj string + Radovi []model.ServisniRad // ugrađeni/odobreni + ServisniDelovi []model.ServisniDeoSaArtiklom // ugrađeni/odobreni + UkupnoSve float64 // zbir ugrađenih (radovi + delovi) + UkupnoSveSaPdv float64 + PredlozeniRadovi []model.ServisniRad + PredlozeniDelovi []model.ServisniDeoSaArtiklom + UkupnoPredlog float64 // zbir predloženih (radovi + delovi) + UkupnoPredlogSaPdv float64 + ImaPredlog bool + UkupnoSaPredlogom float64 // ukupno ugrađeno + predloženo + UkupnoSaPredlogomSaPdv float64 + Odgovoreno bool // klijent vec odgovorio (nema predloga, nije "Primljeno") + Moduli map[string]bool + SviStatusi []string } // ServisJavniStatus prikazuje javnu status stranicu — dostupna bez prijave putem QR koda @@ -2578,14 +2644,16 @@ func (h *Handler) ServisJavniStatus(w http.ResponseWriter, r *http.Request) { // razdvajamo ugrađene/odobrene od predloženih (čekaju odluku klijenta) var ugrRadovi, predRadovi []model.ServisniRad - var ukupnoSve, ukupnoPredlog float64 + var ukupnoSve, ukupnoSveSaPdv, ukupnoPredlog, ukupnoPredlogSaPdv float64 for _, rd := range radovi { if rd.Predlozeno { predRadovi = append(predRadovi, rd) ukupnoPredlog += rd.Ukupno() + ukupnoPredlogSaPdv += rd.UkupnoSaPdv() } else { ugrRadovi = append(ugrRadovi, rd) ukupnoSve += rd.Ukupno() + ukupnoSveSaPdv += rd.UkupnoSaPdv() } } var ugrDelovi, predDelovi []model.ServisniDeoSaArtiklom @@ -2593,13 +2661,16 @@ func (h *Handler) ServisJavniStatus(w http.ResponseWriter, r *http.Request) { if d.Predlozeno { predDelovi = append(predDelovi, d) ukupnoPredlog += d.Ukupno() + ukupnoPredlogSaPdv += d.UkupnoSaPdv() } else { ugrDelovi = append(ugrDelovi, d) ukupnoSve += d.Ukupno() + ukupnoSveSaPdv += d.UkupnoSaPdv() } } podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) + moduli := config.SviModuli(podesavanja) // kad je klijent odbio popravku, ne prikazujemo radove i delove if nalog.PopravkaOdbijena { @@ -2608,28 +2679,34 @@ func (h *Handler) ServisJavniStatus(w http.ResponseWriter, r *http.Request) { predRadovi = nil predDelovi = nil ukupnoSve = 0 + ukupnoSveSaPdv = 0 ukupnoPredlog = 0 + ukupnoPredlogSaPdv = 0 } h.renderujStandalone(w, "servis_status_javni", PodaciJavnogStatusa{ - Nalog: *nalog, - NazivFirme: podesavanja["naziv_firme"], - LogoPutanja: logoZaDokument(podesavanja), - Podnazlov: podesavanja["podnazlov"], - Adresa: podesavanja["adresa"], - Telefon: podesavanja["telefon"], - PIB: podesavanja["pib"], - MaticniBroj: podesavanja["maticni_broj"], - Radovi: ugrRadovi, - ServisniDelovi: ugrDelovi, - UkupnoSve: ukupnoSve, - PredlozeniRadovi: predRadovi, - PredlozeniDelovi: predDelovi, - UkupnoPredlog: ukupnoPredlog, - ImaPredlog: len(predRadovi) > 0 || len(predDelovi) > 0, - UkupnoSaPredlogom: ukupnoSve + ukupnoPredlog, - Odgovoreno: nalog.OdlukaKlijenta != "" || (!(len(predRadovi) > 0 || len(predDelovi) > 0) && nalog.Status != model.StatusPrimljeno), - SviStatusi: model.SviStatusi, + Nalog: *nalog, + NazivFirme: podesavanja["naziv_firme"], + LogoPutanja: logoZaDokument(podesavanja), + Podnazlov: podesavanja["podnazlov"], + Adresa: podesavanja["adresa"], + Telefon: podesavanja["telefon"], + PIB: podesavanja["pib"], + MaticniBroj: podesavanja["maticni_broj"], + Radovi: ugrRadovi, + ServisniDelovi: ugrDelovi, + UkupnoSve: ukupnoSve, + UkupnoSveSaPdv: ukupnoSveSaPdv, + PredlozeniRadovi: predRadovi, + PredlozeniDelovi: predDelovi, + UkupnoPredlog: ukupnoPredlog, + UkupnoPredlogSaPdv: ukupnoPredlogSaPdv, + ImaPredlog: len(predRadovi) > 0 || len(predDelovi) > 0, + UkupnoSaPredlogom: ukupnoSve + ukupnoPredlog, + UkupnoSaPredlogomSaPdv: ukupnoSveSaPdv + ukupnoPredlogSaPdv, + Odgovoreno: nalog.OdlukaKlijenta != "" || (!(len(predRadovi) > 0 || len(predDelovi) > 0) && nalog.Status != model.StatusPrimljeno), + Moduli: moduli, + SviStatusi: model.SviStatusi, }) } diff --git a/internal/model/prodaja.go b/internal/model/prodaja.go index e59b0dc..8b26cd9 100644 --- a/internal/model/prodaja.go +++ b/internal/model/prodaja.go @@ -28,6 +28,11 @@ type StavkaProdaje struct { CenaBezPdv float64 } +// UkupnoBezPdv vraća ukupno bez PDV-a za stavku (CenaBezPdv × količina) +func (s StavkaProdaje) UkupnoBezPdv() float64 { + return s.CenaBezPdv * float64(s.Kolicina) +} + // ProdajniNalogSaDetaljem je nalog sa nazivom klijenta — za prikaz u listi type ProdajniNalogSaDetaljem struct { ProdajniNalog diff --git a/internal/model/servis.go b/internal/model/servis.go index 0405e23..299eccb 100644 --- a/internal/model/servis.go +++ b/internal/model/servis.go @@ -78,11 +78,18 @@ func (d ServisniDeo) Ukupno() float64 { return float64(d.Kolicina) * d.CenaKomada } +// UkupnoSaPdv vraća ukupnu vrednost dela sa PDV-om (kolicina × cena_sa_pdv) +func (d ServisniDeoSaArtiklom) UkupnoSaPdv() float64 { + return float64(d.Kolicina) * d.CenaSaPdv +} + // ServisniDeoSaArtiklom je servisni deo sa nazivom artikla — za prikaz type ServisniDeoSaArtiklom struct { ServisniDeo ArtikalNaziv string ArtikalSifra string + PdvStopa float64 + CenaSaPdv float64 Potrazivano int // komada koji nedostaju (iz servisni_potrazivani_delovi), 0 ako nema } @@ -110,6 +117,8 @@ type ServisniRad struct { Sifra string Kolicina float64 CenaKomada float64 + PdvStopa float64 + CenaSaPdv float64 // CenaKomada * (1 + PdvStopa/100) Datum string Predlozeno bool // true = serviser predložio posle dijagnostike; čeka odobrenje klijenta } @@ -119,6 +128,11 @@ func (r ServisniRad) Ukupno() float64 { return r.Kolicina * r.CenaKomada } +// UkupnoSaPdv vraća ukupnu vrednost rada sa PDV-om (kolicina × cena_sa_pdv) +func (r ServisniRad) UkupnoSaPdv() float64 { + return r.Kolicina * r.CenaSaPdv +} + // ServisniNalogSaKlijentom proširuje ServisniNalog sa nazivom klijenta za prikaz u listi type ServisniNalogSaKlijentom struct { ServisniNalog diff --git a/web/templates/stranice/prodaja_stampa.html b/web/templates/stranice/prodaja_stampa.html index ebd0321..f4806c6 100644 --- a/web/templates/stranice/prodaja_stampa.html +++ b/web/templates/stranice/prodaja_stampa.html @@ -2,11 +2,11 @@ - + Priznanica {{.Nalog.BrojNaloga}} @@ -73,8 +73,8 @@ Artikal Kol. - Cena/kom - Ukupno + Cena/kom{{if index .Moduli "pdv"}} sa PDV{{end}} + Ukupno{{if index .Moduli "pdv"}} sa PDV{{end}} @@ -82,15 +82,15 @@ {{.ArtikalNaziv}} {{.Kolicina}} {{.JedinicaMere}} - {{dinari .CenaPoKomadu}} din - {{dinari .Ukupno}} din + {{if index $.Moduli "pdv"}}{{dinari .CenaPoKomadu}}{{else}}{{dinari .CenaBezPdv}}{{end}} din + {{if index $.Moduli "pdv"}}{{dinari .Ukupno}}{{else}}{{dinari .UkupnoBezPdv}}{{end}} din {{end}} Ukupno za naplatu: - {{dinari .Nalog.Ukupno}} din + {{if index .Moduli "pdv"}}{{dinari .Nalog.Ukupno}}{{else}}{{dinari .UkupnoBezPdv}}{{end}} din diff --git a/web/templates/stranice/servis_detalji.html b/web/templates/stranice/servis_detalji.html index ca9caf7..a006c5b 100644 --- a/web/templates/stranice/servis_detalji.html +++ b/web/templates/stranice/servis_detalji.html @@ -102,10 +102,17 @@
+ {{if index .Moduli "pdv"}} +
+ Ukupno sa PDV-om + {{dinari .UkupnoSveSaPdv}} din +
+ {{else}}
Ukupno {{dinari .UkupnoSve}} din
+ {{end}} {{if gt .Avans 0.0}}
Avans (uplaćeno) @@ -116,7 +123,7 @@ {{end}}
Za naplatu - {{dinari .PreostaloSve}} din + {{if index .Moduli "pdv"}}{{dinari .PreostaloSveSaPdv}}{{else}}{{dinari .PreostaloSve}}{{end}} din
@@ -129,7 +136,7 @@
- +
{{.Naziv}}{{if gt .Kolicina 1.0}} × {{printf "%.0f" .Kolicina}}{{end}} - {{dinari .Ukupno}} din + {{if index $.Moduli "pdv"}}{{dinari .UkupnoSaPdv}}{{else}}{{dinari .Ukupno}}{{end}} din {{end}} {{end}} @@ -300,18 +300,18 @@ {{range .PredlozeniDelovi}} {{end}} {{end}}
Predlog ukupno - {{dinari .UkupnoPredlog}} din + {{if index .Moduli "pdv"}}{{dinari .UkupnoPredlogSaPdv}}{{else}}{{dinari .UkupnoPredlog}}{{end}} din