Popis: štampa u novom tabu — standalone A4 stranica sa zaglavljem i sumarima
This commit is contained in:
@@ -400,6 +400,7 @@ func main() {
|
|||||||
r.Get("/izvestaji/stanje-zaliha", h.StanjeZalihaIzvestaj)
|
r.Get("/izvestaji/stanje-zaliha", h.StanjeZalihaIzvestaj)
|
||||||
r.Get("/izvestaji/popis", h.Popis)
|
r.Get("/izvestaji/popis", h.Popis)
|
||||||
r.With(doz("artikal.izmeni")).Post("/izvestaji/popis", h.SacuvajPopis)
|
r.With(doz("artikal.izmeni")).Post("/izvestaji/popis", h.SacuvajPopis)
|
||||||
|
r.Get("/izvestaji/popis/stampa", h.PopisStampa)
|
||||||
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "prodaja.pregled")).Get("/prodaja", h.Prodaja)
|
r.With(ntechmw.RequireDozvola(h.DozvoleRepo.ImaDozvolu, "prodaja.pregled")).Get("/prodaja", h.Prodaja)
|
||||||
r.Get("/prodaja/nova", h.NovaProdaja)
|
r.Get("/prodaja/nova", h.NovaProdaja)
|
||||||
r.With(doz("prodaja.dodaj")).Post("/prodaja/nova", h.SacuvajProdaju)
|
r.With(doz("prodaja.dodaj")).Post("/prodaja/nova", h.SacuvajProdaju)
|
||||||
|
|||||||
@@ -452,3 +452,149 @@ func (h *Handler) SacuvajPopis(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
http.Redirect(w, r, "/izvestaji/popis?sacuvano=1", http.StatusSeeOther)
|
http.Redirect(w, r, "/izvestaji/popis?sacuvano=1", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PodaciPopisStampa su podaci za štampu popisa (standalone template)
|
||||||
|
type PodaciPopisStampa struct {
|
||||||
|
NazivFirme string
|
||||||
|
KorisnikIme string
|
||||||
|
TipPopisaNaziv string
|
||||||
|
DatumPopisa string
|
||||||
|
Redovi []PopisStampaRed
|
||||||
|
UkupnoKnjiznoKol int
|
||||||
|
UkupnoKnjiznoVredStr string
|
||||||
|
UkupnoStvarnoKol int
|
||||||
|
UkupnoRazlikaKolStr string
|
||||||
|
UkupnoRazlikaVredStr string
|
||||||
|
ManjakKol int
|
||||||
|
ManjakVredStr string
|
||||||
|
VisakKol int
|
||||||
|
VisakVredStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopisStampaRed je jedan red u štampi popisa
|
||||||
|
type PopisStampaRed struct {
|
||||||
|
Naziv string
|
||||||
|
Sifra string
|
||||||
|
KategorijaNaziv string
|
||||||
|
JedinicaMere string
|
||||||
|
NabavnaCenaStr string
|
||||||
|
Kolicina int
|
||||||
|
KnjiznaVrednostStr string
|
||||||
|
StvarnaKolicina int
|
||||||
|
Razlika int
|
||||||
|
RazlikaStr string
|
||||||
|
RazlikaVrednost float64
|
||||||
|
RazlikaVrednostStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopisStampa prikazuje standalone stranicu za štampu popisa
|
||||||
|
func (h *Handler) PopisStampa(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if _, ok := h.zahtevajDozvolu(w, r, "artikal.izmeni"); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
artikli, err := h.Artikli.Lista(r.Context(), appdbPkg.ArtikalFilter{Tip: model.TipProizvod})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Greška pri učitavanju artikala", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||||
|
tip := "godišnji"
|
||||||
|
|
||||||
|
var redovi []PopisStampaRed
|
||||||
|
var ukKnjKol, ukStvKol, ukRazKol, manjakKol, visakKol int
|
||||||
|
var ukKnjVred, ukRazVred, manjakVred, visakVred float64
|
||||||
|
|
||||||
|
for _, a := range artikli {
|
||||||
|
knjKol := a.Kolicina
|
||||||
|
cena := a.NabavnaCena
|
||||||
|
knjVred := cena * float64(knjKol)
|
||||||
|
stvKol := knjKol
|
||||||
|
razlika := stvKol - knjKol
|
||||||
|
razlikaVred := cena * float64(razlika)
|
||||||
|
|
||||||
|
ukKnjKol += knjKol
|
||||||
|
ukKnjVred += knjVred
|
||||||
|
ukStvKol += stvKol
|
||||||
|
ukRazKol += razlika
|
||||||
|
ukRazVred += razlikaVred
|
||||||
|
|
||||||
|
if razlika < 0 {
|
||||||
|
manjakKol += -razlika
|
||||||
|
manjakVred += -razlikaVred
|
||||||
|
} else if razlika > 0 {
|
||||||
|
visakKol += razlika
|
||||||
|
visakVred += razlikaVred
|
||||||
|
}
|
||||||
|
|
||||||
|
jm := a.JedinicaMere
|
||||||
|
if jm == "" {
|
||||||
|
jm = "kom"
|
||||||
|
}
|
||||||
|
|
||||||
|
razlikaStr := "—"
|
||||||
|
if razlika > 0 {
|
||||||
|
razlikaStr = fmt.Sprintf("+%d", razlika)
|
||||||
|
} else if razlika < 0 {
|
||||||
|
razlikaStr = fmt.Sprintf("%d", razlika)
|
||||||
|
}
|
||||||
|
|
||||||
|
razlikaVredStr := "—"
|
||||||
|
if razlikaVred != 0 {
|
||||||
|
predznak := ""
|
||||||
|
if razlikaVred > 0 {
|
||||||
|
predznak = "+"
|
||||||
|
}
|
||||||
|
razlikaVredStr = predznak + formatirajDinare(razlikaVred, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
redovi = append(redovi, PopisStampaRed{
|
||||||
|
Naziv: a.Naziv,
|
||||||
|
Sifra: a.Sifra,
|
||||||
|
KategorijaNaziv: a.KategorijaNaziv,
|
||||||
|
JedinicaMere: jm,
|
||||||
|
NabavnaCenaStr: formatirajDinare(cena, 0),
|
||||||
|
Kolicina: knjKol,
|
||||||
|
KnjiznaVrednostStr: formatirajDinare(knjVred, 2),
|
||||||
|
StvarnaKolicina: stvKol,
|
||||||
|
Razlika: razlika,
|
||||||
|
RazlikaStr: razlikaStr,
|
||||||
|
RazlikaVrednost: razlikaVred,
|
||||||
|
RazlikaVrednostStr: razlikaVredStr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ukRazKolStr := "—"
|
||||||
|
if ukRazKol > 0 {
|
||||||
|
ukRazKolStr = fmt.Sprintf("+%d", ukRazKol)
|
||||||
|
} else if ukRazKol < 0 {
|
||||||
|
ukRazKolStr = fmt.Sprintf("%d", ukRazKol)
|
||||||
|
}
|
||||||
|
|
||||||
|
ukRazVredStr := "—"
|
||||||
|
if ukRazVred != 0 {
|
||||||
|
predznak := ""
|
||||||
|
if ukRazVred > 0 {
|
||||||
|
predznak = "+"
|
||||||
|
}
|
||||||
|
ukRazVredStr = predznak + formatirajDinare(ukRazVred, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.renderujStandalone(w, "popis_stampa", PodaciPopisStampa{
|
||||||
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
|
KorisnikIme: middleware.KorisnikIzKonteksta(r.Context()).KorisnickoIme,
|
||||||
|
TipPopisaNaziv: tipPopisaNaziv(tip),
|
||||||
|
DatumPopisa: time.Now().Format("02.01.2006."),
|
||||||
|
Redovi: redovi,
|
||||||
|
UkupnoKnjiznoKol: ukKnjKol,
|
||||||
|
UkupnoKnjiznoVredStr: formatirajDinare(ukKnjVred, 2),
|
||||||
|
UkupnoStvarnoKol: ukStvKol,
|
||||||
|
UkupnoRazlikaKolStr: ukRazKolStr,
|
||||||
|
UkupnoRazlikaVredStr: ukRazVredStr,
|
||||||
|
ManjakKol: manjakKol,
|
||||||
|
ManjakVredStr: formatirajDinare(manjakVred, 2),
|
||||||
|
VisakKol: visakKol,
|
||||||
|
VisakVredStr: formatirajDinare(visakVred, 2),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ var saSidebar = []string{
|
|||||||
|
|
||||||
// standalone su šabloni bez base layouta
|
// standalone su šabloni bez base layouta
|
||||||
var standaloneIme = []string{
|
var standaloneIme = []string{
|
||||||
"prijava", "setup", "totp_provera", "prodaja_stampa", "servis_radni_nalog", "servis_otpremnica", "servis_revers", "servis_predracun", "servis_nalepnica", "servis_status_javni", "servis_garantni_list", "fiskal_verifikacija",
|
"prijava", "setup", "totp_provera", "prodaja_stampa", "servis_radni_nalog", "servis_otpremnica", "servis_revers", "servis_predracun", "servis_nalepnica", "servis_status_javni", "servis_garantni_list", "fiskal_verifikacija", "popis_stampa",
|
||||||
}
|
}
|
||||||
|
|
||||||
// sablonskeFunkcije su pomoćne funkcije dostupne u svim šablonima.
|
// sablonskeFunkcije su pomoćne funkcije dostupne u svim šablonima.
|
||||||
|
|||||||
@@ -230,7 +230,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
||||||
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/izvestaji" class="btn-sekundarno" style="white-space:nowrap;">← Izveštaji</a>
|
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/izvestaji" class="btn-sekundarno" style="white-space:nowrap;">← Izveštaji</a>
|
||||||
<button type="button" onclick="window.print()" class="btn-sekundarno" style="white-space:nowrap;">🖨 Štampaj</button>
|
<button type="button" onclick="window.open('/izvestaji/popis/stampa','_blank')" class="btn-sekundarno" style="white-space:nowrap;">🖨 Štampaj</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="sr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Popis — {{.NazivFirme}}</title>
|
||||||
|
<style>
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #111;
|
||||||
|
background: #fff;
|
||||||
|
min-width: 780px;
|
||||||
|
}
|
||||||
|
.strana { max-width: 780px; margin: 0 auto; padding: 24px 32px; }
|
||||||
|
|
||||||
|
.zaglavlje { margin-bottom: 16px; }
|
||||||
|
.firma-naziv { font-size: 18px; font-weight: 700; }
|
||||||
|
.dokument-naslov { font-size: 14px; font-weight: 600; margin-top: 4px; }
|
||||||
|
.dokument-meta { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.6; }
|
||||||
|
|
||||||
|
.tabela { width: 100%; border-collapse: collapse; margin-top: 12px; }
|
||||||
|
.tabela th {
|
||||||
|
font-size: 9px; font-weight: 600; text-transform: uppercase;
|
||||||
|
letter-spacing: 0.3px; color: #555; padding: 5px 6px;
|
||||||
|
border-bottom: 1.5px solid #888; border-top: 1px solid #ccc;
|
||||||
|
text-align: center; background: #f7f7f7;
|
||||||
|
}
|
||||||
|
.tabela th:first-child { text-align: left; }
|
||||||
|
.tabela td {
|
||||||
|
padding: 4px 6px; border-bottom: 0.5px solid #ddd;
|
||||||
|
font-size: 10px; text-align: right;
|
||||||
|
}
|
||||||
|
.tabela td:first-child { text-align: left; font-weight: 500; }
|
||||||
|
.tabela td.slabo { color: #777; font-size: 9px; font-family: monospace; }
|
||||||
|
.tabela td.manjak { color: #b91c1c; }
|
||||||
|
.tabela td.visak { color: #15803d; }
|
||||||
|
|
||||||
|
tfoot td {
|
||||||
|
font-weight: 700; font-size: 10px;
|
||||||
|
border-top: 1.5px solid #888; border-bottom: 1.5px solid #888;
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sumarno { margin-top: 16px; padding-top: 10px; border-top: 1px solid #ccc; }
|
||||||
|
.sumarno-stavke { display: flex; gap: 32px; font-size: 11px; flex-wrap: wrap; }
|
||||||
|
.sumarno-stavka { display: flex; flex-direction: column; gap: 1px; }
|
||||||
|
.sumarno-labela { color: #777; font-size: 9px; }
|
||||||
|
.sumarno-manjak { color: #b91c1c; }
|
||||||
|
.sumarno-visak { color: #15803d; }
|
||||||
|
|
||||||
|
.potpis { margin-top: 28px; display: flex; gap: 60px; }
|
||||||
|
.potpis-stavka { flex: 1; }
|
||||||
|
.potpis-linija { border-top: 1px solid #888; margin-top: 28px; padding-top: 3px; font-size: 10px; color: #777; }
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body { font-size: 11px; }
|
||||||
|
.strana { padding: 20px 28px; max-width: 780px; }
|
||||||
|
@page { size: A4 landscape; margin: 8mm 10mm; }
|
||||||
|
.tabela tr { break-inside: avoid; }
|
||||||
|
.tabela thead { display: table-header-group; }
|
||||||
|
.dugme-stampa { display: none !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.dugme-stampa {
|
||||||
|
position: fixed; bottom: 24px; right: 24px;
|
||||||
|
background: #111; color: #fff; border: none;
|
||||||
|
padding: 10px 20px; border-radius: 8px;
|
||||||
|
font-size: 13px; font-weight: 500; cursor: pointer;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
.dugme-stampa:hover { background: #333; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="strana">
|
||||||
|
|
||||||
|
<div class="zaglavlje">
|
||||||
|
<div class="firma-naziv">{{.NazivFirme}}</div>
|
||||||
|
<div class="dokument-naslov">Popis magacina</div>
|
||||||
|
<div class="dokument-meta">
|
||||||
|
{{.TipPopisaNaziv}} | Datum: {{.DatumPopisa}} | Sačinio: {{.KorisnikIme}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="tabela">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Artikal</th>
|
||||||
|
<th>Šifra</th>
|
||||||
|
<th>Kategorija</th>
|
||||||
|
<th>JM</th>
|
||||||
|
<th>Nab. cena</th>
|
||||||
|
<th>Knj. kol.</th>
|
||||||
|
<th>Knj. vrednost</th>
|
||||||
|
<th>Stvarno kol.</th>
|
||||||
|
<th>Razlika kol.</th>
|
||||||
|
<th>Razlika vred.</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .Redovi}}
|
||||||
|
<tr>
|
||||||
|
<td>{{.Naziv}}</td>
|
||||||
|
<td class="slabo">{{if .Sifra}}{{.Sifra}}{{else}}—{{end}}</td>
|
||||||
|
<td class="slabo">{{if .KategorijaNaziv}}{{.KategorijaNaziv}}{{else}}—{{end}}</td>
|
||||||
|
<td>{{if .JedinicaMere}}{{.JedinicaMere}}{{else}}kom{{end}}</td>
|
||||||
|
<td>{{.NabavnaCenaStr}}</td>
|
||||||
|
<td>{{.Kolicina}}</td>
|
||||||
|
<td>{{.KnjiznaVrednostStr}}</td>
|
||||||
|
<td>{{.StvarnaKolicina}}</td>
|
||||||
|
<td class="{{if gt .Razlika 0}}visak{{else if lt .Razlika 0}}manjak{{end}}">{{.RazlikaStr}}</td>
|
||||||
|
<td class="{{if gt .RazlikaVrednost 0.0}}visak{{else if lt .RazlikaVrednost 0.0}}manjak{{end}}">{{.RazlikaVrednostStr}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" style="text-align:right;">UKUPNO:</td>
|
||||||
|
<td>{{.UkupnoKnjiznoKol}}</td>
|
||||||
|
<td>{{.UkupnoKnjiznoVredStr}}</td>
|
||||||
|
<td>{{.UkupnoStvarnoKol}}</td>
|
||||||
|
<td>{{.UkupnoRazlikaKolStr}}</td>
|
||||||
|
<td>{{.UkupnoRazlikaVredStr}}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="sumarno">
|
||||||
|
<div class="sumarno-stavke">
|
||||||
|
<div class="sumarno-stavka">
|
||||||
|
<span class="sumarno-labela">Manjkovi (kom)</span>
|
||||||
|
<span class="sumarno-manjak">{{.ManjakKol}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sumarno-stavka">
|
||||||
|
<span class="sumarno-labela">Manjkovi (vrednost)</span>
|
||||||
|
<span class="sumarno-manjak">{{.ManjakVredStr}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sumarno-stavka">
|
||||||
|
<span class="sumarno-labela">Viškovi (kom)</span>
|
||||||
|
<span class="sumarno-visak">{{.VisakKol}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sumarno-stavka">
|
||||||
|
<span class="sumarno-labela">Viškovi (vrednost)</span>
|
||||||
|
<span class="sumarno-visak">{{.VisakVredStr}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="potpis">
|
||||||
|
<div class="potpis-stavka">
|
||||||
|
<div class="potpis-linija">Potpis lica koje je izvršilo popis</div>
|
||||||
|
</div>
|
||||||
|
<div class="potpis-stavka">
|
||||||
|
<div class="potpis-linija">Potpis odgovornog lica</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="dugme-stampa" onclick="window.print()">Štampaj</button>
|
||||||
|
<script>window.onload = function() { setTimeout(function() { window.print(); }, 300); }</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user