Servis: logo na dokumentima, jedinstveno 3-kolonsko zaglavlje, podesiva QR adresa, javni status

- Logo na dokumentima ako je ukljucen prikaz loga; helper logoZaDokument
- Jedinstveno zaglavlje (revers/predracun/otpremnica/radni nalog): firma | klijent | barkod+broj+datumi+QR; dodati MB i barkod
- Revers: QR u sekciju Uredjaj desno, bez JMBG, Primio bez imena servisera
- Podesavanja Opste: auto-snimanje sve 3 sekcije (marker _sekcija_firma za checkbox loga)
- Podesiva adresa za QR (qr_bazni_url) za pristup sa telefona / Caddy HTTPS
- Javni status: token se gasi po preuzimanju; predvidjeni datum zavrsetka, garancija i napomena iz baze; nova kartica Radovi i delovi sa procenom
This commit is contained in:
2026-06-23 14:38:26 +02:00
parent 29cab6e29b
commit 941d60fc4b
9 changed files with 335 additions and 291 deletions
+22 -4
View File
@@ -67,6 +67,7 @@ type PodaciPodesavanja struct {
PredvidjenRokDana string PredvidjenRokDana string
ServisUslovi string ServisUslovi string
ServisKlauzulaPredracuna string ServisKlauzulaPredracuna string
QrBazniUrl string
LoginPozadina string LoginPozadina string
LoginPozadinaOpacity string LoginPozadinaOpacity string
LoginPozadinaBlurPozadine string LoginPozadinaBlurPozadine string
@@ -280,10 +281,17 @@ func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
return return
} }
// checkbox-i: šalju vrednost samo kada su čekirani, pa ih uvek eksplicitno čitamo // checkbox „topbar_logo_slika" živi u Firma sekciji. Pošto se sekcije auto-snimaju
topbarLogoSlika := "0" // odvojeno, čitamo ga SAMO kad je poslata Firma sekcija (marker `_sekcija_firma`),
if r.FormValue("topbar_logo_slika") == "1" { // inače ostaje "" pa ga petlja ispod preskoči i ne dira postojeću vrednost.
topbarLogoSlika = "1" // (Checkbox koji nije čekiran se ne šalje, pa bi inače snimanje druge sekcije
// ugasilo logo u topbaru.)
topbarLogoSlika := ""
if _, jeFirmaSekcija := r.Form["_sekcija_firma"]; jeFirmaSekcija {
topbarLogoSlika = "0"
if r.FormValue("topbar_logo_slika") == "1" {
topbarLogoSlika = "1"
}
} }
// matični broj — 8 cifara; prazno je dozvoljeno (polje nije obavezno) // matični broj — 8 cifara; prazno je dozvoljeno (polje nije obavezno)
@@ -441,6 +449,15 @@ func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
} }
} }
// bazna adresa za QR kod (npr. http://192.168.1.25:3000); prazno → koristi se host iz zahteva
if _, ima := r.Form["qr_bazni_url"]; ima {
bazni := strings.TrimSpace(r.FormValue("qr_bazni_url"))
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "qr_bazni_url", bazni); err != nil {
http.Error(w, "Greška pri čuvanju podešavanja", http.StatusInternalServerError)
return
}
}
http.Redirect(w, r, sledeci+"?sacuvano=1", http.StatusSeeOther) http.Redirect(w, r, sledeci+"?sacuvano=1", http.StatusSeeOther)
} }
@@ -818,6 +835,7 @@ func (h *Handler) napuniPodaciPodesavanja(r *http.Request, naslov string) (Podac
PredvidjenRokDana: vrednostIliDefault(podesavanja, "predvidjen_rok_dana", "15"), PredvidjenRokDana: vrednostIliDefault(podesavanja, "predvidjen_rok_dana", "15"),
ServisUslovi: vrednostIliDefault(podesavanja, "servis_uslovi", podrazumevaniUsloviServisa), ServisUslovi: vrednostIliDefault(podesavanja, "servis_uslovi", podrazumevaniUsloviServisa),
ServisKlauzulaPredracuna: vrednostIliDefault(podesavanja, "servis_klauzula_predracuna", podrazumevanaKlauzulaPredracuna), ServisKlauzulaPredracuna: vrednostIliDefault(podesavanja, "servis_klauzula_predracuna", podrazumevanaKlauzulaPredracuna),
QrBazniUrl: podesavanja["qr_bazni_url"],
}, nil }, nil
} }
+83 -16
View File
@@ -1106,6 +1106,15 @@ func (h *Handler) renderujFormuNaloga(w http.ResponseWriter, podaci PodaciFormeN
} }
// PodaciRadnogNaloga su podaci za interni radni list servisera (bez cena) // PodaciRadnogNaloga su podaci za interni radni list servisera (bez cena)
// logoZaDokument vraća putanju loga za štampu na dokumentima — samo ako je u
// Podešavanja → Opšte uključeno „Prikaži logo" (topbar_logo_slika). Inače prazno.
func logoZaDokument(podesavanja map[string]string) string {
if podesavanja["topbar_logo_slika"] == "1" {
return podesavanja["logo_putanja"]
}
return ""
}
type PodaciRadnogNaloga struct { type PodaciRadnogNaloga struct {
Nalog model.ServisniNalog Nalog model.ServisniNalog
ServisniDelovi []model.ServisniDeoSaArtiklom ServisniDelovi []model.ServisniDeoSaArtiklom
@@ -1113,6 +1122,7 @@ type PodaciRadnogNaloga struct {
KlijentTelefon string KlijentTelefon string
TehnicarNaziv string TehnicarNaziv string
NazivFirme string NazivFirme string
LogoPutanja string
Barkod string // base64 PNG Code128 barkoda broja naloga (za skener) Barkod string // base64 PNG Code128 barkoda broja naloga (za skener)
} }
@@ -1171,6 +1181,7 @@ func (h *Handler) StampaRadnogNaloga(w http.ResponseWriter, r *http.Request) {
KlijentTelefon: klijentTelefon, KlijentTelefon: klijentTelefon,
TehnicarNaziv: tehnicarNaziv, TehnicarNaziv: tehnicarNaziv,
NazivFirme: podesavanja["naziv_firme"], NazivFirme: podesavanja["naziv_firme"],
LogoPutanja: logoZaDokument(podesavanja),
Barkod: barkodNaloga(nalog.BrojNaloga), Barkod: barkodNaloga(nalog.BrojNaloga),
}) })
} }
@@ -1187,10 +1198,13 @@ type PodaciOtpremnice struct {
KlijentNaziv string KlijentNaziv string
TehnicarNaziv string TehnicarNaziv string
NazivFirme string NazivFirme string
LogoPutanja string
Podnazlov string Podnazlov string
Adresa string Adresa string
Telefon string Telefon string
PIB string PIB string
MaticniBroj string
Barkod string // base64 PNG Code128 barkoda broja naloga
} }
// StampaOtpremnice renderuje otpremnicu pri preuzimanju uređaja od strane klijenta // StampaOtpremnice renderuje otpremnicu pri preuzimanju uređaja od strane klijenta
@@ -1260,7 +1274,7 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) {
} }
} }
nalogURL := qrNalogURL(r, nalog.JavniToken) nalogURL := qrNalogURL(r, nalog.JavniToken, podesavanja["qr_bazni_url"])
var qrKodOtpr string var qrKodOtpr string
if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil { if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil {
qrKodOtpr = base64.StdEncoding.EncodeToString(png) qrKodOtpr = base64.StdEncoding.EncodeToString(png)
@@ -1277,10 +1291,13 @@ func (h *Handler) StampaOtpremnice(w http.ResponseWriter, r *http.Request) {
KlijentNaziv: klijentNaziv, KlijentNaziv: klijentNaziv,
TehnicarNaziv: tehnicarNaziv, TehnicarNaziv: tehnicarNaziv,
NazivFirme: podesavanja["naziv_firme"], NazivFirme: podesavanja["naziv_firme"],
LogoPutanja: logoZaDokument(podesavanja),
Podnazlov: podesavanja["podnazlov"], Podnazlov: podesavanja["podnazlov"],
Adresa: podesavanja["adresa"], Adresa: podesavanja["adresa"],
Telefon: podesavanja["telefon"], Telefon: podesavanja["telefon"],
PIB: podesavanja["pib"], PIB: podesavanja["pib"],
MaticniBroj: podesavanja["maticni_broj"],
Barkod: barkodNaloga(nalog.BrojNaloga),
}) })
} }
@@ -1296,10 +1313,13 @@ type PodaciReversa struct {
QRKod string // base64 QR ka javnoj status strani naloga QRKod string // base64 QR ka javnoj status strani naloga
Uslovi string // uslovi servisa iz podešavanja (servis_uslovi) Uslovi string // uslovi servisa iz podešavanja (servis_uslovi)
NazivFirme string NazivFirme string
LogoPutanja string
Podnazlov string Podnazlov string
Adresa string Adresa string
Telefon string Telefon string
PIB string PIB string
MaticniBroj string
Barkod string // base64 PNG Code128 barkoda broja naloga
} }
// StampaReversa renderuje revers (potvrdu o prijemu uređaja na servis) // StampaReversa renderuje revers (potvrdu o prijemu uređaja na servis)
@@ -1346,7 +1366,7 @@ func (h *Handler) StampaReversa(w http.ResponseWriter, r *http.Request) {
} }
} }
nalogURL := qrNalogURL(r, nalog.JavniToken) nalogURL := qrNalogURL(r, nalog.JavniToken, podesavanja["qr_bazni_url"])
var qrKod string var qrKod string
if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil { if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil {
qrKod = base64.StdEncoding.EncodeToString(png) qrKod = base64.StdEncoding.EncodeToString(png)
@@ -1362,10 +1382,13 @@ func (h *Handler) StampaReversa(w http.ResponseWriter, r *http.Request) {
QRKod: qrKod, QRKod: qrKod,
Uslovi: vrednostIliDefault(podesavanja, "servis_uslovi", podrazumevaniUsloviServisa), Uslovi: vrednostIliDefault(podesavanja, "servis_uslovi", podrazumevaniUsloviServisa),
NazivFirme: podesavanja["naziv_firme"], NazivFirme: podesavanja["naziv_firme"],
LogoPutanja: logoZaDokument(podesavanja),
Podnazlov: podesavanja["podnazlov"], Podnazlov: podesavanja["podnazlov"],
Adresa: podesavanja["adresa"], Adresa: podesavanja["adresa"],
Telefon: podesavanja["telefon"], Telefon: podesavanja["telefon"],
PIB: podesavanja["pib"], PIB: podesavanja["pib"],
MaticniBroj: podesavanja["maticni_broj"],
Barkod: barkodNaloga(nalog.BrojNaloga),
}) })
} }
@@ -1386,10 +1409,13 @@ type PodaciPredracuna struct {
KlijentNaziv string KlijentNaziv string
TehnicarNaziv string TehnicarNaziv string
NazivFirme string NazivFirme string
LogoPutanja string
Podnazlov string Podnazlov string
Adresa string Adresa string
Telefon string Telefon string
PIB 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 // StampaPredracuna renderuje predračun (procenu cene) na osnovu traženih radova i delova
@@ -1459,7 +1485,7 @@ func (h *Handler) StampaPredracuna(w http.ResponseWriter, r *http.Request) {
datumIzdavanja := time.Now() datumIzdavanja := time.Now()
vaziDo := datumIzdavanja.AddDate(0, 0, rok) vaziDo := datumIzdavanja.AddDate(0, 0, rok)
nalogURL := qrNalogURL(r, nalog.JavniToken) nalogURL := qrNalogURL(r, nalog.JavniToken, podesavanja["qr_bazni_url"])
var qrKod string var qrKod string
if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil { if png, err := qrcode.Encode(nalogURL, qrcode.Medium, 160); err == nil {
qrKod = base64.StdEncoding.EncodeToString(png) qrKod = base64.StdEncoding.EncodeToString(png)
@@ -1480,10 +1506,13 @@ func (h *Handler) StampaPredracuna(w http.ResponseWriter, r *http.Request) {
KlijentNaziv: klijentNaziv, KlijentNaziv: klijentNaziv,
TehnicarNaziv: tehnicarNaziv, TehnicarNaziv: tehnicarNaziv,
NazivFirme: podesavanja["naziv_firme"], NazivFirme: podesavanja["naziv_firme"],
LogoPutanja: logoZaDokument(podesavanja),
Podnazlov: podesavanja["podnazlov"], Podnazlov: podesavanja["podnazlov"],
Adresa: podesavanja["adresa"], Adresa: podesavanja["adresa"],
Telefon: podesavanja["telefon"], Telefon: podesavanja["telefon"],
PIB: podesavanja["pib"], PIB: podesavanja["pib"],
MaticniBroj: podesavanja["maticni_broj"],
Barkod: barkodNaloga(nalog.BrojNaloga),
}) })
} }
@@ -1779,11 +1808,20 @@ func (h *Handler) SacuvajNapomenuKlijentu(w http.ResponseWriter, r *http.Request
// PodaciJavnogStatusa su podaci za javnu status stranicu servisnog naloga // PodaciJavnogStatusa su podaci za javnu status stranicu servisnog naloga
type PodaciJavnogStatusa struct { type PodaciJavnogStatusa struct {
Nalog model.ServisniNalog Nalog model.ServisniNalog
NazivFirme string NazivFirme string
Telefon string LogoPutanja string
Adresa string Podnazlov string
SviStatusi []string Adresa string
Telefon string
PIB string
MaticniBroj string
Radovi []model.ServisniRad
UkupnoRad float64
ServisniDelovi []model.ServisniDeoSaArtiklom
UkupnoDelovi float64
UkupnoSve float64
SviStatusi []string
} }
// ServisJavniStatus prikazuje javnu status stranicu — dostupna bez prijave putem QR koda // ServisJavniStatus prikazuje javnu status stranicu — dostupna bez prijave putem QR koda
@@ -1800,21 +1838,50 @@ func (h *Handler) ServisJavniStatus(w http.ResponseWriter, r *http.Request) {
return return
} }
// javni link se „gasi" čim klijent preuzme uređaj — posle preuzimanja status više nije dostupan
if nalog.Status == model.StatusPreuzeto {
http.NotFound(w, r)
return
}
radovi, _ := h.ServisniRadoviRepo.DohvatiZaNalog(r.Context(), nalog.ID)
delovi, _ := h.deloviSaPotrazivanima(r.Context(), nalog.ID)
var ukupnoRad, ukupnoDelovi float64
for _, rd := range radovi {
ukupnoRad += rd.Ukupno()
}
for _, d := range delovi {
ukupnoDelovi += d.Ukupno()
}
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
h.renderujStandalone(w, "servis_status_javni", PodaciJavnogStatusa{ h.renderujStandalone(w, "servis_status_javni", PodaciJavnogStatusa{
Nalog: *nalog, Nalog: *nalog,
NazivFirme: podesavanja["naziv_firme"], NazivFirme: podesavanja["naziv_firme"],
Telefon: podesavanja["telefon"], LogoPutanja: logoZaDokument(podesavanja),
Adresa: podesavanja["adresa"], Podnazlov: podesavanja["podnazlov"],
SviStatusi: model.SviStatusi, Adresa: podesavanja["adresa"],
Telefon: podesavanja["telefon"],
PIB: podesavanja["pib"],
MaticniBroj: podesavanja["maticni_broj"],
Radovi: radovi,
UkupnoRad: ukupnoRad,
ServisniDelovi: delovi,
UkupnoDelovi: ukupnoDelovi,
UkupnoSve: ukupnoRad + ukupnoDelovi,
SviStatusi: model.SviStatusi,
}) })
} }
// qrNalogURL konstruiše URL za QR kod vodeći računa o reverse proxy-ju. // qrNalogURL konstruiše URL za QR kod vodeći računa o reverse proxy-ju.
// Ako aplikacija radi iza nginx/Caddy/Traefik koji prekida TLS, r.TLS je nil, // Ako je u podešavanjima zadata fiksna adresa (bazniURL, npr. http://192.168.1.25:3000),
// ali X-Forwarded-Proto header sadrži stvarnu šemu. // koristi se ona — korisno da QR radi sa telefona kad se programu pristupa preko „localhost".
func qrNalogURL(r *http.Request, token string) string { // Inače se host i šema čitaju iz zahteva (X-Forwarded-Proto pokriva nginx/Caddy/Traefik).
func qrNalogURL(r *http.Request, token, bazniURL string) string {
if b := strings.TrimRight(strings.TrimSpace(bazniURL), "/"); b != "" {
return b + "/status/" + token
}
scheme := "http" scheme := "http"
if r.TLS != nil { if r.TLS != nil {
scheme = "https" scheme = "https"
+4 -27
View File
@@ -50,9 +50,10 @@
</div> </div>
<!-- firma: naziv, podnazlov, adresa, telefon, PIB, logo zona --> <!-- firma: naziv, podnazlov, adresa, telefon, PIB, logo zona -->
<form method="POST" action="/podesavanja/sacuvaj"> <form method="POST" action="/podesavanja/sacuvaj" data-autosave>
<input type="hidden" name="_csrf" value="{{.CsrfToken}}"> <input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="_next" value="/admin/podesavanja/opste"> <input type="hidden" name="_next" value="/admin/podesavanja/opste">
<input type="hidden" name="_sekcija_firma" value="1">
<div class="kartica animiraj" style="margin-bottom:16px;"> <div class="kartica animiraj" style="margin-bottom:16px;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);"> <div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
@@ -117,19 +118,11 @@
</div> </div>
</div> </div>
<div style="display:flex;justify-content:flex-end;margin-top:20px;">
<button type="submit"
style="background:var(--sb-akcent);color:#fff;border:none;padding:10px 24px;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:opacity 0.2s;"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
Sačuvaj opšte
</button>
</div>
</div> </div>
</form> </form>
<!-- poslovna jedinica: podaci koje fiskalizacija (SUF) traži uz svaki račun --> <!-- poslovna jedinica: podaci koje fiskalizacija (SUF) traži uz svaki račun -->
<form method="POST" action="/podesavanja/sacuvaj"> <form method="POST" action="/podesavanja/sacuvaj" data-autosave>
<input type="hidden" name="_csrf" value="{{.CsrfToken}}"> <input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="_next" value="/admin/podesavanja/opste"> <input type="hidden" name="_next" value="/admin/podesavanja/opste">
<div class="kartica animiraj" style="margin-bottom:16px;"> <div class="kartica animiraj" style="margin-bottom:16px;">
@@ -169,19 +162,11 @@
</div> </div>
</div> </div>
</div> </div>
<div style="display:flex;justify-content:flex-end;margin-top:20px;">
<button type="submit"
style="background:var(--sb-akcent);color:#fff;border:none;padding:10px 24px;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:opacity 0.2s;"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
Sačuvaj poslovnu jedinicu
</button>
</div>
</div> </div>
</form> </form>
<!-- profil firme: pravni/poreski status (Faza 0) — određuje koji se zakonski moduli pale --> <!-- profil firme: pravni/poreski status (Faza 0) — određuje koji se zakonski moduli pale -->
<form method="POST" action="/podesavanja/sacuvaj"> <form method="POST" action="/podesavanja/sacuvaj" data-autosave>
<input type="hidden" name="_csrf" value="{{.CsrfToken}}"> <input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="_next" value="/admin/podesavanja/opste"> <input type="hidden" name="_next" value="/admin/podesavanja/opste">
<div class="kartica animiraj" style="margin-bottom:16px;"> <div class="kartica animiraj" style="margin-bottom:16px;">
@@ -258,14 +243,6 @@
</div> </div>
</div> </div>
<div style="display:flex;justify-content:flex-end;margin-top:20px;">
<button type="submit"
style="background:var(--sb-akcent);color:#fff;border:none;padding:10px 24px;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:opacity 0.2s;"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
Sačuvaj status
</button>
</div>
</div> </div>
</form> </form>
@@ -89,6 +89,20 @@
Napomena na dnu predračuna (procena cene). Snima se automatski. Napomena na dnu predračuna (procena cene). Snima se automatski.
</div> </div>
</div> </div>
<div style="margin-top:16px;">
<label for="qr_bazni_url" class="polje-labela">
Adresa servera za QR kod
</label>
<input type="text" id="qr_bazni_url" name="qr_bazni_url" value="{{.QrBazniUrl}}"
placeholder="npr. http://192.168.1.25:3000"
style="width:100%;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;">
<div class="pomocni-tekst" style="margin-top:6px;">
Adresa koju otvara QR kod sa dokumenata kad ga klijent skenira telefonom. Ostavi prazno
da se koristi adresa iz pregledača. Za pristup sa telefona na lokalnoj mreži upiši IP
adresu servera (npr. <code>http://192.168.1.25:3000</code>). Snima se automatski.
</div>
</div>
</div> </div>
</form> </form>
+33 -38
View File
@@ -10,14 +10,14 @@
.strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; } .strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; }
/* zaglavlje */ /* zaglavlje: tri okvira (firma · klijent · dokument) */
.zaglavlje { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 2px solid #111; gap: 20px; } .zaglavlje { display: flex; align-items: stretch; margin-bottom: 20px; gap: 12px; }
.firma-naziv { font-size: 20px; font-weight: 700; } .zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.firma-naziv { font-size: 18px; font-weight: 700; }
.firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; } .firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; }
.dok-naslov { text-align: right; }
.dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; } .dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; }
.dok-broj { font-size: 22px; font-weight: 700; font-family: monospace; } .dok-broj { font-size: 18px; font-weight: 700; font-family: monospace; }
.dok-datum { font-size: 12px; color: #555; margin-top: 6px; } .dok-datum { font-size: 12px; color: #555; margin-top: 4px; }
/* strane */ /* strane */
.strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; } .strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
@@ -79,57 +79,52 @@
<!-- zaglavlje --> <!-- zaglavlje -->
<div class="zaglavlje"> <div class="zaglavlje">
<div> <!-- LEVO: firma — logo na vrhu, tekst ispod -->
<div class="zg-okvir">
{{if .LogoPutanja}}
<img src="{{.LogoPutanja}}" alt="Logo" style="max-height:54px;max-width:100%;object-fit:contain;display:block;margin-bottom:8px;">
{{else}}
<div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div> <div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div>
{{end}}
<div class="firma-info"> <div class="firma-info">
{{if .Podnazlov}}{{.Podnazlov}}<br>{{end}} {{if .Podnazlov}}{{.Podnazlov}}<br>{{end}}
{{if .Adresa}}{{.Adresa}}<br>{{end}} {{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}} {{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}}
{{if .PIB}}PIB: {{.PIB}}{{end}} {{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div> </div>
</div> </div>
<div style="display:flex;align-items:flex-start;gap:14px;"> <!-- SREDINA: klijent -->
<div class="dok-naslov"> <div class="zg-okvir">
<div class="dok-tip">Otpremnica</div> <div class="strana-tip">Klijent</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.DatumZavrsetka}}
<div class="dok-datum">Završeno: {{.Nalog.DatumZavrsetka.Format "02.01.2006."}}</div>
{{end}}
</div>
{{if .QRKod}}
<img src="data:image/png;base64,{{.QRKod}}" width="76" height="76"
alt="QR {{.Nalog.BrojNaloga}}"
style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">
{{end}}
</div>
</div>
<!-- isporučilac i primalac -->
<div class="strane-blok">
<div class="strana-kartica">
<div class="strana-tip">Isporučilac</div>
<div class="strana-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}—{{end}}</div>
<div class="strana-info">
{{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}{{telefon .Telefon}}{{end}}
</div>
</div>
<div class="strana-kartica">
<div class="strana-tip">Primalac (klijent)</div>
{{if .KlijentNaziv}} {{if .KlijentNaziv}}
<div class="strana-naziv">{{.KlijentNaziv}}</div> <div class="strana-naziv">{{.KlijentNaziv}}</div>
<div class="strana-info"> <div class="strana-info">
{{if .Klijent}} {{if .Klijent}}
{{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}} {{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}}
{{if .Klijent.Email}}{{.Klijent.Email}}<br>{{end}} {{if .Klijent.Email}}{{.Klijent.Email}}<br>{{end}}
{{if .Klijent.Mesto}}{{.Klijent.Mesto}}{{end}} {{if .Klijent.Mesto}}{{.Klijent.Mesto}}<br>{{end}}
{{if .Klijent.PIB}}PIB: {{.Klijent.PIB}}{{end}}
{{end}} {{end}}
</div> </div>
{{else}} {{else}}
<div class="strana-naziv prazno">— klijent nije naveden —</div> <div class="strana-naziv prazno">— klijent nije naveden —</div>
{{end}} {{end}}
</div> </div>
<!-- DESNO: barkod na vrhu, ispod datumi (levo) + QR (skroz desno) -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;">
<div>
<div class="dok-tip">Otpremnica</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.DatumZavrsetka}}
<div class="dok-datum">Završeno: {{.Nalog.DatumZavrsetka.Format "02.01.2006."}}</div>
{{end}}
</div>
{{if .QRKod}}<img src="data:image/png;base64,{{.QRKod}}" width="64" height="64" alt="QR {{.Nalog.BrojNaloga}}" style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">{{end}}
</div>
</div>
</div> </div>
<!-- uređaj koji se vraća --> <!-- uređaj koji se vraća -->
+38 -36
View File
@@ -10,13 +10,13 @@
.strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; } .strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; }
.zaglavlje { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 2px solid #111; gap: 20px; } .zaglavlje { display: flex; align-items: stretch; margin-bottom: 18px; gap: 12px; }
.firma-naziv { font-size: 20px; font-weight: 700; } .zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; } .firma-naziv { font-size: 18px; font-weight: 700; }
.dok-naslov { text-align: right; } .firma-info { font-size: 11px; color: #555; margin-top: 3px; line-height: 1.5; }
.dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; } .dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; }
.dok-broj { font-size: 22px; font-weight: 700; font-family: monospace; } .dok-broj { font-size: 18px; font-weight: 700; font-family: monospace; }
.dok-datum { font-size: 12px; color: #555; margin-top: 6px; } .dok-datum { font-size: 12px; color: #555; margin-top: 4px; }
.strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; } .strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
.strana-kartica { padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; } .strana-kartica { padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
@@ -53,6 +53,12 @@
.strana { padding: 16px 20px; max-width: 100%; } .strana { padding: 16px 20px; max-width: 100%; }
.dugme-stampa { display: none !important; } .dugme-stampa { display: none !important; }
@page { size: A4; margin: 12mm 14mm; } @page { size: A4; margin: 12mm 14mm; }
/* red tabele se ne sme prelomiti preko granice stranice */
.tabela tr { break-inside: avoid; }
/* zaglavlje tabele se ponavlja na svakoj stranici kad tabela pređe na novu */
.tabela thead { display: table-header-group; }
/* rekapitulacija, klauzula i potpisi ostaju u jednom komadu */
.rekap, .klauzula-blok, .potpisi { break-inside: avoid; }
} }
.dugme-stampa { position: fixed; bottom: 24px; right: 24px; background: #111; color: #fff; border: none; padding: 12px 22px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2); } .dugme-stampa { position: fixed; bottom: 24px; right: 24px; background: #111; color: #fff; border: none; padding: 12px 22px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
.dugme-stampa:hover { background: #333; } .dugme-stampa:hover { background: #333; }
@@ -63,54 +69,50 @@
<!-- zaglavlje --> <!-- zaglavlje -->
<div class="zaglavlje"> <div class="zaglavlje">
<div> <!-- LEVO: firma — logo na vrhu, tekst ispod -->
<div class="zg-okvir">
{{if .LogoPutanja}}
<img src="{{.LogoPutanja}}" alt="Logo" style="max-height:54px;max-width:100%;object-fit:contain;display:block;margin-bottom:8px;">
{{else}}
<div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div> <div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div>
{{end}}
<div class="firma-info"> <div class="firma-info">
{{if .Podnazlov}}{{.Podnazlov}}<br>{{end}} {{if .Podnazlov}}{{.Podnazlov}}<br>{{end}}
{{if .Adresa}}{{.Adresa}}<br>{{end}} {{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}} {{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}}
{{if .PIB}}PIB: {{.PIB}}{{end}} {{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div> </div>
</div> </div>
<div style="display:flex;align-items:flex-start;gap:14px;"> <!-- SREDINA: klijent -->
<div class="dok-naslov"> <div class="zg-okvir">
<div class="dok-tip">Predračun (procena)</div> <div class="strana-tip">Klijent</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.DatumIzdavanja.Format "02.01.2006."}}</div>
<div class="dok-datum">Važi do: {{.VaziDo.Format "02.01.2006."}}</div>
</div>
{{if .QRKod}}
<img src="data:image/png;base64,{{.QRKod}}" width="76" height="76"
alt="QR {{.Nalog.BrojNaloga}}"
style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">
{{end}}
</div>
</div>
<!-- izdao / za -->
<div class="strane-blok">
<div class="strana-kartica">
<div class="strana-tip">Izdao (servis)</div>
<div class="strana-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}—{{end}}</div>
<div class="strana-info">
{{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}{{telefon .Telefon}}{{end}}
</div>
</div>
<div class="strana-kartica">
<div class="strana-tip">Za (klijent)</div>
{{if .KlijentNaziv}} {{if .KlijentNaziv}}
<div class="strana-naziv">{{.KlijentNaziv}}</div> <div class="strana-naziv">{{.KlijentNaziv}}</div>
<div class="strana-info"> <div class="strana-info">
{{if .Klijent}} {{if .Klijent}}
{{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}} {{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}}
{{if .Klijent.Mesto}}{{.Klijent.Mesto}}{{end}} {{if .Klijent.Email}}{{.Klijent.Email}}<br>{{end}}
{{if .Klijent.Mesto}}{{.Klijent.Mesto}}<br>{{end}}
{{if .Klijent.PIB}}PIB: {{.Klijent.PIB}}{{end}}
{{end}} {{end}}
</div> </div>
{{else}} {{else}}
<div class="strana-naziv prazno">— klijent nije naveden —</div> <div class="strana-naziv prazno">— klijent nije naveden —</div>
{{end}} {{end}}
</div> </div>
<!-- DESNO: barkod na vrhu, ispod datumi (levo) + QR (skroz desno) -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;">
<div>
<div class="dok-tip">Predračun (procena)</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.DatumIzdavanja.Format "02.01.2006."}}</div>
<div class="dok-datum">Važi do: {{.VaziDo.Format "02.01.2006."}}</div>
</div>
{{if .QRKod}}<img src="data:image/png;base64,{{.QRKod}}" width="64" height="64" alt="QR {{.Nalog.BrojNaloga}}" style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">{{end}}
</div>
</div>
</div> </div>
<!-- uređaj i traženo --> <!-- uređaj i traženo -->
+26 -42
View File
@@ -11,15 +11,15 @@
.strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; } .strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; }
/* zaglavlje */ /* zaglavlje */
.zaglavlje { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; padding-bottom: 14px; border-bottom: 2px solid #111; gap: 20px; } .zaglavlje { display: flex; align-items: stretch; margin-bottom: 20px; gap: 12px; }
.zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.firma-naziv { font-size: 16px; font-weight: 700; } .firma-naziv { font-size: 16px; font-weight: 700; }
.firma-podnaslov { font-size: 11px; color: #666; text-transform: uppercase; letter-spacing: 1px; margin-top: 2px; } .firma-podnaslov { font-size: 11px; color: #666; text-transform: uppercase; letter-spacing: 1px; margin-top: 2px; }
.nalog-desno { text-align: right; }
.nalog-naslov { font-size: 11px; color: #555; text-transform: uppercase; letter-spacing: 0.6px; margin-bottom: 2px; } .nalog-naslov { font-size: 11px; color: #555; text-transform: uppercase; letter-spacing: 0.6px; margin-bottom: 2px; }
.nalog-broj { font-size: 22px; font-weight: 700; font-family: monospace; } .nalog-broj { font-size: 18px; font-weight: 700; font-family: monospace; }
.status { display: inline-block; margin-top: 6px; padding: 2px 10px; border-radius: 20px; font-size: 11px; font-weight: 600; border: 1.5px solid #111; } .status { display: inline-block; margin-top: 6px; padding: 2px 10px; border-radius: 20px; font-size: 11px; font-weight: 600; border: 1.5px solid #111; }
.barkod { margin-top: 8px; } .barkod { margin-bottom: 10px; }
.barkod img { display: block; height: 11mm; width: 52mm; object-fit: fill; margin-left: auto; } .barkod img { display: block; width: 100%; max-height: 46px; object-fit: contain; }
/* odeljci */ /* odeljci */
.odeljak { margin-bottom: 18px; } .odeljak { margin-bottom: 18px; }
@@ -69,50 +69,34 @@
<!-- zaglavlje --> <!-- zaglavlje -->
<div class="zaglavlje"> <div class="zaglavlje">
<div> <!-- LEVO: firma — logo na vrhu, tekst ispod -->
<div class="zg-okvir">
{{if .LogoPutanja}}
<img src="{{.LogoPutanja}}" alt="Logo" style="max-height:50px;max-width:100%;object-fit:contain;display:block;margin-bottom:8px;">
{{else}}
<div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div> <div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div>
{{end}}
<div class="firma-podnaslov">Radni nalog — interni</div> <div class="firma-podnaslov">Radni nalog — interni</div>
</div> </div>
<div class="nalog-desno"> <!-- SREDINA: klijent -->
<div class="nalog-naslov">Broj naloga</div> <div class="zg-okvir" style="font-size:12px;line-height:1.6;">
<div class="nalog-broj">{{.Nalog.BrojNaloga}}</div> <div class="polje-labela">Klijent</div>
<div><span class="status">{{.Nalog.Status}}</span></div> <div class="polje-vrednost">{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}<span class="prazno"></span>{{end}}</div>
{{if .KlijentTelefon}}<div style="color:#555;">Tel: {{telefon .KlijentTelefon}}</div>{{end}}
</div>
<!-- DESNO: barkod na vrhu, ispod broj + status + datumi + serviser -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}} {{if .Barkod}}
<div class="barkod"><img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}"></div> <div class="barkod"><img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}"></div>
{{end}} {{end}}
</div> <div class="nalog-naslov">Broj naloga</div>
</div> <div class="nalog-broj">{{.Nalog.BrojNaloga}}</div>
<div><span class="status">{{.Nalog.Status}}</span></div>
<!-- osnovni podaci --> <div style="font-size:11px;color:#555;margin-top:6px;line-height:1.7;">
<div class="odeljak"> Prijem: {{.Nalog.DatumPrijema.Format "02.01.2006."}}
<div class="odeljak-naslov">Osnovni podaci</div> {{if .Nalog.PredvidjenDatum}}<br>Rok: {{.Nalog.PredvidjenDatum.Format "02.01.2006."}}{{end}}
<div class="podaci-grid"> {{if .TehnicarNaziv}}<br>Serviser: {{.TehnicarNaziv}}{{end}}
<div>
<div class="polje-labela">Datum prijema</div>
<div class="polje-vrednost">{{.Nalog.DatumPrijema.Format "02.01.2006. u 15:04"}}</div>
</div> </div>
{{if .Nalog.PredvidjenDatum}}
<div>
<div class="polje-labela">Predviđen rok</div>
<div class="polje-vrednost">{{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</div>
</div>
{{end}}
{{if .TehnicarNaziv}}
<div>
<div class="polje-labela">Serviser</div>
<div class="polje-vrednost">{{.TehnicarNaziv}}</div>
</div>
{{end}}
<div>
<div class="polje-labela">Klijent</div>
<div class="polje-vrednost">{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}<span class="prazno"></span>{{end}}</div>
</div>
{{if .KlijentTelefon}}
<div>
<div class="polje-labela">Telefon klijenta</div>
<div class="polje-vrednost">{{telefon .KlijentTelefon}}</div>
</div>
{{end}}
</div> </div>
</div> </div>
+71 -70
View File
@@ -10,14 +10,14 @@
.strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; } .strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; }
/* zaglavlje */ /* zaglavlje: tri okvira (firma · klijent · dokument) */
.zaglavlje { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 2px solid #111; gap: 20px; } .zaglavlje { display: flex; align-items: stretch; margin-bottom: 20px; gap: 12px; }
.firma-naziv { font-size: 20px; font-weight: 700; } .zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.firma-naziv { font-size: 18px; font-weight: 700; }
.firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; } .firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; }
.dok-naslov { text-align: right; }
.dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; } .dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; }
.dok-broj { font-size: 22px; font-weight: 700; font-family: monospace; } .dok-broj { font-size: 18px; font-weight: 700; font-family: monospace; }
.dok-datum { font-size: 12px; color: #555; margin-top: 6px; } .dok-datum { font-size: 12px; color: #555; margin-top: 4px; }
/* strane */ /* strane */
.strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; } .strane-blok { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
@@ -69,96 +69,97 @@
<!-- zaglavlje --> <!-- zaglavlje -->
<div class="zaglavlje"> <div class="zaglavlje">
<div> <!-- LEVO: firma — logo na vrhu, tekst ispod -->
<div class="zg-okvir">
{{if .LogoPutanja}}
<img src="{{.LogoPutanja}}" alt="Logo" style="max-height:54px;max-width:100%;object-fit:contain;display:block;margin-bottom:8px;">
{{else}}
<div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div> <div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}— naziv firme —{{end}}</div>
{{end}}
<div class="firma-info"> <div class="firma-info">
{{if .Podnazlov}}{{.Podnazlov}}<br>{{end}} {{if .Podnazlov}}{{.Podnazlov}}<br>{{end}}
{{if .Adresa}}{{.Adresa}}<br>{{end}} {{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}} {{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}}
{{if .PIB}}PIB: {{.PIB}}{{end}} {{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div> </div>
</div> </div>
<div style="display:flex;align-items:flex-start;gap:14px;"> <!-- SREDINA: klijent -->
<div class="dok-naslov"> <div class="zg-okvir">
<div class="dok-tip">Revers — potvrda o prijemu</div> <div class="strana-tip">Klijent</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum prijema: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.PredvidjenDatum}}
<div class="dok-datum">Predviđen rok: {{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</div>
{{end}}
</div>
{{if .QRKod}}
<img src="data:image/png;base64,{{.QRKod}}" width="76" height="76"
alt="QR {{.Nalog.BrojNaloga}}"
style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">
{{end}}
</div>
</div>
<!-- primalac (firma) i predao (klijent) -->
<div class="strane-blok">
<div class="strana-kartica">
<div class="strana-tip">Primio (servis)</div>
<div class="strana-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}—{{end}}</div>
<div class="strana-info">
{{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}{{telefon .Telefon}}{{end}}
</div>
</div>
<div class="strana-kartica">
<div class="strana-tip">Predao (klijent)</div>
{{if .KlijentNaziv}} {{if .KlijentNaziv}}
<div class="strana-naziv">{{.KlijentNaziv}}</div> <div class="strana-naziv">{{.KlijentNaziv}}</div>
<div class="strana-info"> <div class="strana-info">
{{if .Klijent}} {{if .Klijent}}
{{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}} {{if .Klijent.Telefon}}Tel: {{telefon .Klijent.Telefon}}<br>{{end}}
{{if .Klijent.Email}}{{.Klijent.Email}}<br>{{end}}
{{if .Klijent.Mesto}}{{.Klijent.Mesto}}<br>{{end}} {{if .Klijent.Mesto}}{{.Klijent.Mesto}}<br>{{end}}
{{if .Klijent.PIB}}PIB: {{.Klijent.PIB}}{{end}}
{{end}} {{end}}
{{if .KlijentBrojIdent}}{{.KlijentOznakaIdent}}: {{.KlijentBrojIdent}}{{end}}
</div> </div>
{{else}} {{else}}
<div class="strana-naziv prazno">— klijent nije naveden —</div> <div class="strana-naziv prazno">— klijent nije naveden —</div>
{{end}} {{end}}
</div> </div>
<!-- DESNO: barkod na vrhu, ispod dokument i datumi (QR je u sekciji „Uređaj na servisu") -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div class="dok-tip">Revers — potvrda o prijemu</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum prijema: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.PredvidjenDatum}}
<div class="dok-datum">Predviđen rok: {{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</div>
{{end}}
</div>
</div> </div>
<!-- uređaj --> <!-- uređaj (QR skroz desno — klijent ga skenira da prati status) -->
<div class="odeljak"> <div class="odeljak">
<div class="odeljak-naslov">Uređaj na servisu</div> <div class="odeljak-naslov">Uređaj na servisu</div>
<div class="podaci-grid" style="margin-bottom:10px;"> <div style="display:flex;gap:16px;align-items:flex-start;">
<div> <div style="flex:1;">
<div class="polje-labela">Naziv uređaja</div> <div class="podaci-grid" style="margin-bottom:10px;">
<div class="polje-vrednost">{{if .Nalog.Uredjaj}}{{.Nalog.Uredjaj}}{{else}}<span class="prazno"></span>{{end}}</div> <div>
<div class="polje-labela">Naziv uređaja</div>
<div class="polje-vrednost">{{if .Nalog.Uredjaj}}{{.Nalog.Uredjaj}}{{else}}<span class="prazno"></span>{{end}}</div>
</div>
<div>
<div class="polje-labela">Serijski broj</div>
<div class="polje-vrednost-mono">{{if .Nalog.SerijskiBroj}}{{.Nalog.SerijskiBroj}}{{else}}<span class="prazno"></span>{{end}}</div>
</div>
{{if .Nalog.PinUredjaja}}
<div>
<div class="polje-labela">PIN / lozinka</div>
<div><span class="pin-vrednost">{{.Nalog.PinUredjaja}}</span></div>
</div>
{{end}}
</div>
{{if .Nalog.Pribor}}
<div style="margin-top:8px;">
<div class="polje-labela">Pribor predat uz uređaj</div>
<div class="polje-tekst">{{.Nalog.Pribor}}</div>
</div>
{{end}}
{{if .Nalog.Ostecenja}}
<div style="margin-top:8px;">
<div class="polje-labela">Vidljiva oštećenja pri prijemu</div>
<div class="polje-tekst">{{.Nalog.Ostecenja}}</div>
</div>
{{end}}
{{if .Nalog.TrazeneNadogradnje}}
<div style="margin-top:8px;">
<div class="polje-labela">Tražene nadogradnje</div>
<div class="polje-tekst">{{.Nalog.TrazeneNadogradnje}}</div>
</div>
{{end}}
</div> </div>
<div> {{if .QRKod}}
<div class="polje-labela">Serijski broj</div> <div style="text-align:center;flex-shrink:0;">
<div class="polje-vrednost-mono">{{if .Nalog.SerijskiBroj}}{{.Nalog.SerijskiBroj}}{{else}}<span class="prazno"></span>{{end}}</div> <img src="data:image/png;base64,{{.QRKod}}" width="96" height="96" alt="QR {{.Nalog.BrojNaloga}}"
</div> style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;">
{{if .Nalog.PinUredjaja}} <div style="font-size:9px;color:#888;margin-top:3px;">Skenirajte za status</div>
<div>
<div class="polje-labela">PIN / lozinka</div>
<div><span class="pin-vrednost">{{.Nalog.PinUredjaja}}</span></div>
</div> </div>
{{end}} {{end}}
</div> </div>
{{if .Nalog.Pribor}}
<div style="margin-top:8px;">
<div class="polje-labela">Pribor predat uz uređaj</div>
<div class="polje-tekst">{{.Nalog.Pribor}}</div>
</div>
{{end}}
{{if .Nalog.Ostecenja}}
<div style="margin-top:8px;">
<div class="polje-labela">Vidljiva oštećenja pri prijemu</div>
<div class="polje-tekst">{{.Nalog.Ostecenja}}</div>
</div>
{{end}}
{{if .Nalog.TrazeneNadogradnje}}
<div style="margin-top:8px;">
<div class="polje-labela">Tražene nadogradnje</div>
<div class="polje-tekst">{{.Nalog.TrazeneNadogradnje}}</div>
</div>
{{end}}
</div> </div>
<!-- prijavljeni kvar --> <!-- prijavljeni kvar -->
@@ -189,7 +190,7 @@
<div class="potpis-linija">Predao (klijent)</div> <div class="potpis-linija">Predao (klijent)</div>
</div> </div>
<div> <div>
<div class="potpis-linija">Primio{{if .TehnicarNaziv}} — {{.TehnicarNaziv}}{{end}} (servis)</div> <div class="potpis-linija">Primio (servis)</div>
</div> </div>
</div> </div>
+44 -58
View File
@@ -78,10 +78,22 @@
<body> <body>
<div class="omotac"> <div class="omotac">
<!-- zaglavlje firme --> <!-- naslov stranice -->
<div style="text-align:center;font-size:12px;color:#999;font-weight:600;text-transform:uppercase;letter-spacing:0.8px;margin-bottom:14px;">Praćenje statusa popravke</div>
<!-- zaglavlje firme — logo (ili naziv) + podaci, isto kao na dokumentima -->
<div class="zaglavlje"> <div class="zaglavlje">
{{if .LogoPutanja}}
<img src="{{.LogoPutanja}}" alt="Logo" style="max-height:60px;max-width:220px;object-fit:contain;margin-bottom:8px;">
{{else}}
<div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}Servis{{end}}</div> <div class="firma-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}Servis{{end}}</div>
{{if .Adresa}}<div class="firma-info">{{.Adresa}}</div>{{end}} {{end}}
<div class="firma-info">
{{if .Podnazlov}}{{.Podnazlov}}<br>{{end}}
{{if .Adresa}}{{.Adresa}}<br>{{end}}
{{if .Telefon}}Tel: {{telefon .Telefon}}<br>{{end}}
{{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div>
</div> </div>
<!-- kartica: uređaj i status --> <!-- kartica: uređaj i status -->
@@ -129,75 +141,49 @@
<span class="red-vrednost">{{.Nalog.DatumPrijema.Format "02.01.2006."}}</span> <span class="red-vrednost">{{.Nalog.DatumPrijema.Format "02.01.2006."}}</span>
</div> </div>
{{if .Nalog.DatumZavrsetka}} {{if .Nalog.PredvidjenDatum}}
<div class="red"> <div class="red">
<span class="red-labela">Datum završetka</span> <span class="red-labela">Predviđeni datum završetka</span>
<span class="red-vrednost">{{.Nalog.DatumZavrsetka.Format "02.01.2006."}}</span> <span class="red-vrednost">{{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</span>
</div> </div>
{{end}} {{end}}
{{if .Nalog.SerijskiBroj}}
<div class="red"> <div class="red">
<span class="red-labela">Serijski broj</span> <span class="red-labela">Garancija</span>
<span class="red-vrednost">{{.Nalog.SerijskiBroj}}</span> <span class="red-vrednost">{{garancijaTekst .Nalog.GarancijaDana}}</span>
</div> </div>
{{end}}
{{if .Nalog.OpisKvara}} {{if .Nalog.NapomenaKlijentu}}
<div class="red">
<span class="red-labela">Opis kvara</span>
<span class="red-vrednost">{{.Nalog.OpisKvara}}</span>
</div>
{{end}}
{{if .Nalog.GarancijaDo}}
<div class="red">
<span class="red-labela">Garancija do</span>
<span class="red-vrednost">{{.Nalog.GarancijaDo.Format "02.01.2006."}}</span>
</div>
{{end}}
<!-- procenjena cena -->
{{if or .Nalog.CenaOd .Nalog.CenaDo .Nalog.CenaKonacna}}
<div style="margin-top:12px;">
<div class="red-labela" style="margin-bottom:8px;">Procena cene</div>
<div class="cena-blok">
{{if .Nalog.CenaKonacna}}
<div class="cena-od-do">
<span class="cena-vrednost">{{formatBroj .Nalog.CenaKonacna}} din</span>
</div>
<div class="cena-labela">Konačna cena popravke</div>
{{else if and .Nalog.CenaOd .Nalog.CenaDo}}
<div class="cena-od-do">
<span class="cena-vrednost">{{formatBroj .Nalog.CenaOd}}</span>
<span class="cena-sep"></span>
<span class="cena-vrednost">{{formatBroj .Nalog.CenaDo}} din</span>
</div>
<div class="cena-labela">Procenjeni raspon cene</div>
{{else if .Nalog.CenaOd}}
<div class="cena-od-do">
<span class="cena-vrednost">od {{formatBroj .Nalog.CenaOd}} din</span>
</div>
<div class="cena-labela">Procenjena cena od</div>
{{end}}
</div>
</div>
{{end}}
{{if .Nalog.Napomena}}
<div style="margin-top:12px;"> <div style="margin-top:12px;">
<div class="red-labela" style="margin-bottom:6px;">Napomena</div> <div class="red-labela" style="margin-bottom:6px;">Napomena</div>
<div class="napomena-blok">{{.Nalog.Napomena}}</div> <div class="napomena-blok">{{.Nalog.NapomenaKlijentu}}</div>
</div> </div>
{{end}} {{end}}
</div> </div>
<!-- kontakt --> <!-- kartica: radovi i delovi sa procenom -->
{{if .Telefon}} {{if or .Radovi .ServisniDelovi}}
<div class="kontakt"> <div class="kartica">
<div class="kontakt-naslov">Kontakt</div> <div class="kartica-naslov">Radovi i delovi</div>
<a href="tel:{{.Telefon}}" class="kontakt-tel">{{telefon .Telefon}}</a>
{{if .Adresa}}<div class="kontakt-adresa">{{.Adresa}}</div>{{end}} {{range .Radovi}}
<div class="red">
<span class="red-labela">{{.Naziv}}{{if gt .Kolicina 1.0}} &times;{{.Kolicina}}{{end}}</span>
<span class="red-vrednost">{{dinari .Ukupno}} din</span>
</div>
{{end}}
{{range .ServisniDelovi}}
<div class="red">
<span class="red-labela">{{.ArtikalNaziv}}{{if gt .Kolicina 1}} &times;{{.Kolicina}}{{end}}</span>
<span class="red-vrednost">{{dinari .Ukupno}} din</span>
</div>
{{end}}
<div class="cena-blok" style="margin-top:12px;display:flex;justify-content:space-between;align-items:center;">
<span class="cena-labela" style="margin:0;">Ukupno (procena)</span>
<span class="cena-vrednost">{{dinari .UkupnoSve}} din</span>
</div>
</div> </div>
{{end}} {{end}}