feat(podesavanja): profil firme — pravni i poreski status (Faza 0)
Dodata kartica „Pravni i poreski status" na Podešavanja → Opšte: pravni oblik, režim rada, PDV obveznik, fiskalizacija. Čuva se u postojećoj key-value tabeli podesavanja (bez migracije). Fiskalizacija se zasivi i forsira na „Ne" u režimu „samo evidencija".
This commit is contained in:
@@ -23,25 +23,30 @@ import (
|
|||||||
// PodaciPodesavanja su podaci za stranicu podešavanja
|
// PodaciPodesavanja su podaci za stranicu podešavanja
|
||||||
type PodaciPodesavanja struct {
|
type PodaciPodesavanja struct {
|
||||||
model.PodaciStranice
|
model.PodaciStranice
|
||||||
NazivFirme string
|
NazivFirme string
|
||||||
Podnazlov string
|
Podnazlov string
|
||||||
Adresa string
|
Adresa string
|
||||||
Telefon string
|
Telefon string
|
||||||
PIB string
|
PIB string
|
||||||
LogoTip string
|
LogoTip string
|
||||||
LogoPutanja string
|
LogoPutanja string
|
||||||
Sacuvano bool
|
// profil firme — pravni/poreski status (Faza 0); određuje koji se zakonski moduli pale
|
||||||
Verzija string
|
FirmaPravniOblik string
|
||||||
LogoGreska string
|
FirmaPdvObveznik string
|
||||||
BackupVracen bool
|
FirmaFiskalizacija string
|
||||||
Backupi []BackupInfo
|
FirmaRezim string
|
||||||
BackupIntervalSati string
|
Sacuvano bool
|
||||||
BackupBrojKopija string
|
Verzija string
|
||||||
LoginPozadina string
|
LogoGreska string
|
||||||
LoginPozadinaOpacity string
|
BackupVracen bool
|
||||||
LoginPozadinaBlurPozadine string
|
Backupi []BackupInfo
|
||||||
LoginPozadinaBlurKartice string
|
BackupIntervalSati string
|
||||||
LoginPozadinaZatamnjenjeKartice string
|
BackupBrojKopija string
|
||||||
|
LoginPozadina string
|
||||||
|
LoginPozadinaOpacity string
|
||||||
|
LoginPozadinaBlurPozadine string
|
||||||
|
LoginPozadinaBlurKartice string
|
||||||
|
LoginPozadinaZatamnjenjeKartice string
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackupInfo opisuje jedan backup fajl
|
// BackupInfo opisuje jedan backup fajl
|
||||||
@@ -69,19 +74,19 @@ func (h *Handler) Podesavanja(w http.ResponseWriter, r *http.Request) {
|
|||||||
ps.Stranica = "podesavanja"
|
ps.Stranica = "podesavanja"
|
||||||
ps.NaslovStranice = "Podešavanja"
|
ps.NaslovStranice = "Podešavanja"
|
||||||
podaci := PodaciPodesavanja{
|
podaci := PodaciPodesavanja{
|
||||||
PodaciStranice: ps,
|
PodaciStranice: ps,
|
||||||
NazivFirme: podesavanja["naziv_firme"],
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
Podnazlov: podesavanja["podnazlov"],
|
Podnazlov: podesavanja["podnazlov"],
|
||||||
Adresa: podesavanja["adresa"],
|
Adresa: podesavanja["adresa"],
|
||||||
Telefon: podesavanja["telefon"],
|
Telefon: podesavanja["telefon"],
|
||||||
PIB: podesavanja["pib"],
|
PIB: podesavanja["pib"],
|
||||||
LogoTip: podesavanja["logo_tip"],
|
LogoTip: podesavanja["logo_tip"],
|
||||||
LogoPutanja: podesavanja["logo_putanja"],
|
LogoPutanja: podesavanja["logo_putanja"],
|
||||||
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
||||||
BackupVracen: r.URL.Query().Get("sacuvano") == "vraceno",
|
BackupVracen: r.URL.Query().Get("sacuvano") == "vraceno",
|
||||||
Verzija: h.Verzija,
|
Verzija: h.Verzija,
|
||||||
LogoGreska: r.URL.Query().Get("logo_greska"),
|
LogoGreska: r.URL.Query().Get("logo_greska"),
|
||||||
Backupi: ucitajListuBackupa(),
|
Backupi: ucitajListuBackupa(),
|
||||||
LoginPozadina: podesavanja["login_pozadina"],
|
LoginPozadina: podesavanja["login_pozadina"],
|
||||||
LoginPozadinaOpacity: vrednostIliDefault(podesavanja, "login_pozadina_opacity", "50"),
|
LoginPozadinaOpacity: vrednostIliDefault(podesavanja, "login_pozadina_opacity", "50"),
|
||||||
LoginPozadinaBlurPozadine: vrednostIliDefault(podesavanja, "login_pozadina_blur_pozadine", "0"),
|
LoginPozadinaBlurPozadine: vrednostIliDefault(podesavanja, "login_pozadina_blur_pozadine", "0"),
|
||||||
@@ -234,6 +239,11 @@ func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
|
|||||||
"telefon": r.FormValue("telefon"),
|
"telefon": r.FormValue("telefon"),
|
||||||
"pib": r.FormValue("pib"),
|
"pib": r.FormValue("pib"),
|
||||||
"logo_tip": r.FormValue("logo_tip"),
|
"logo_tip": r.FormValue("logo_tip"),
|
||||||
|
// profil firme (Faza 0) — radio dugmad uvek šalju vrednost, pa se uredno čuvaju
|
||||||
|
"firma_pravni_oblik": r.FormValue("firma_pravni_oblik"),
|
||||||
|
"firma_pdv_obveznik": r.FormValue("firma_pdv_obveznik"),
|
||||||
|
"firma_fiskalizacija": r.FormValue("firma_fiskalizacija"),
|
||||||
|
"firma_rezim": r.FormValue("firma_rezim"),
|
||||||
}
|
}
|
||||||
|
|
||||||
for kljuc, vrednost := range polja {
|
for kljuc, vrednost := range polja {
|
||||||
@@ -566,10 +576,10 @@ func (h *Handler) SacuvajLoginPozadinaStilove(w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
for kljuc, vrednost := range map[string]string{
|
for kljuc, vrednost := range map[string]string{
|
||||||
"login_pozadina_blur_pozadine": blurPozadineStr,
|
"login_pozadina_blur_pozadine": blurPozadineStr,
|
||||||
"login_pozadina_blur_kartice": blurKarticeStr,
|
"login_pozadina_blur_kartice": blurKarticeStr,
|
||||||
"login_pozadina_opacity": opacityStr,
|
"login_pozadina_opacity": opacityStr,
|
||||||
"login_pozadina_zatamnjenje_kartice": zatamnjenjeKarticeStr,
|
"login_pozadina_zatamnjenje_kartice": zatamnjenjeKarticeStr,
|
||||||
} {
|
} {
|
||||||
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil {
|
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil {
|
||||||
slog.Error("greška pri čuvanju stila login pozadine", "kljuc", kljuc, "error", err)
|
slog.Error("greška pri čuvanju stila login pozadine", "kljuc", kljuc, "error", err)
|
||||||
@@ -593,19 +603,23 @@ func (h *Handler) napuniPodaciPodesavanja(r *http.Request, naslov string) (Podac
|
|||||||
ps.Stranica = "podesavanja"
|
ps.Stranica = "podesavanja"
|
||||||
ps.NaslovStranice = naslov
|
ps.NaslovStranice = naslov
|
||||||
return PodaciPodesavanja{
|
return PodaciPodesavanja{
|
||||||
PodaciStranice: ps,
|
PodaciStranice: ps,
|
||||||
NazivFirme: podesavanja["naziv_firme"],
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
Podnazlov: podesavanja["podnazlov"],
|
Podnazlov: podesavanja["podnazlov"],
|
||||||
Adresa: podesavanja["adresa"],
|
Adresa: podesavanja["adresa"],
|
||||||
Telefon: podesavanja["telefon"],
|
Telefon: podesavanja["telefon"],
|
||||||
PIB: podesavanja["pib"],
|
PIB: podesavanja["pib"],
|
||||||
LogoTip: podesavanja["logo_tip"],
|
LogoTip: podesavanja["logo_tip"],
|
||||||
LogoPutanja: podesavanja["logo_putanja"],
|
LogoPutanja: podesavanja["logo_putanja"],
|
||||||
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
FirmaPravniOblik: vrednostIliDefault(podesavanja, "firma_pravni_oblik", "pausalac"),
|
||||||
BackupVracen: r.URL.Query().Get("sacuvano") == "vraceno",
|
FirmaPdvObveznik: vrednostIliDefault(podesavanja, "firma_pdv_obveznik", "ne"),
|
||||||
Verzija: h.Verzija,
|
FirmaFiskalizacija: vrednostIliDefault(podesavanja, "firma_fiskalizacija", "ne"),
|
||||||
LogoGreska: r.URL.Query().Get("logo_greska"),
|
FirmaRezim: vrednostIliDefault(podesavanja, "firma_rezim", "samo_evidencija"),
|
||||||
Backupi: ucitajListuBackupa(),
|
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
||||||
|
BackupVracen: r.URL.Query().Get("sacuvano") == "vraceno",
|
||||||
|
Verzija: h.Verzija,
|
||||||
|
LogoGreska: r.URL.Query().Get("logo_greska"),
|
||||||
|
Backupi: ucitajListuBackupa(),
|
||||||
LoginPozadina: podesavanja["login_pozadina"],
|
LoginPozadina: podesavanja["login_pozadina"],
|
||||||
LoginPozadinaOpacity: vrednostIliDefault(podesavanja, "login_pozadina_opacity", "50"),
|
LoginPozadinaOpacity: vrednostIliDefault(podesavanja, "login_pozadina_opacity", "50"),
|
||||||
LoginPozadinaBlurPozadine: vrednostIliDefault(podesavanja, "login_pozadina_blur_pozadine", "0"),
|
LoginPozadinaBlurPozadine: vrednostIliDefault(podesavanja, "login_pozadina_blur_pozadine", "0"),
|
||||||
@@ -657,4 +671,3 @@ func (h *Handler) PodesavanjaSistem(w http.ResponseWriter, r *http.Request) {
|
|||||||
podaci.Stranica = "podesavanja-sistem"
|
podaci.Stranica = "podesavanja-sistem"
|
||||||
h.renderujTemplate(w, "podesavanja_sistem", podaci)
|
h.renderujTemplate(w, "podesavanja_sistem", podaci)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,94 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<!-- profil firme: pravni/poreski status (Faza 0) — određuje koji se zakonski moduli pale -->
|
||||||
|
<form method="POST" action="/podesavanja/sacuvaj">
|
||||||
|
<input type="hidden" name="_next" value="/admin/podesavanja/opste">
|
||||||
|
<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);">
|
||||||
|
<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"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>
|
||||||
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Pravni i poreski status</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kolona" style="gap:18px;">
|
||||||
|
|
||||||
|
<!-- pravni oblik -->
|
||||||
|
<div>
|
||||||
|
<label class="polje-labela">Pravni oblik</label>
|
||||||
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaPravniOblik "pausalac"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_pravni_oblik" value="pausalac" {{if eq .FirmaPravniOblik "pausalac"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Paušalac</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaPravniOblik "preduzetnik_knjige"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_pravni_oblik" value="preduzetnik_knjige" {{if eq .FirmaPravniOblik "preduzetnik_knjige"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Preduzetnik (knjige)</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaPravniOblik "doo"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_pravni_oblik" value="doo" {{if eq .FirmaPravniOblik "doo"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">DOO</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- režim rada -->
|
||||||
|
<div>
|
||||||
|
<label class="polje-labela">Režim rada</label>
|
||||||
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaRezim "pun"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_rezim" value="pun" {{if eq .FirmaRezim "pun"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Pun (vodi poslovne knjige)</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaRezim "samo_evidencija"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_rezim" value="samo_evidencija" {{if eq .FirmaRezim "samo_evidencija"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Samo evidencija</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="pomocni-tekst" style="font-size:12px;margin-top:6px;">„Samo evidencija" gasi ceo zakonski sloj — program vodi servis i zalihe, ali ne izdaje fiskalne ni poreske dokumente.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PDV obveznik -->
|
||||||
|
<div>
|
||||||
|
<label class="polje-labela">U sistemu PDV-a</label>
|
||||||
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaPdvObveznik "da"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_pdv_obveznik" value="da" {{if eq .FirmaPdvObveznik "da"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Da</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaPdvObveznik "ne"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_pdv_obveznik" value="ne" {{if eq .FirmaPdvObveznik "ne"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Ne</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- fiskalizacija — zasivljena i forsirana na „Ne" kad je režim „samo evidencija" (vidi skriptu na dnu) -->
|
||||||
|
<div id="fiskalizacija-grupa">
|
||||||
|
<label class="polje-labela">Izdaje fiskalne račune (promet građanima)</label>
|
||||||
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaFiskalizacija "da"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_fiskalizacija" value="da" {{if eq .FirmaFiskalizacija "da"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Da</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .FirmaFiskalizacija "ne"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="firma_fiskalizacija" value="ne" {{if eq .FirmaFiskalizacija "ne"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Ne</span>
|
||||||
|
</label>
|
||||||
|
</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>
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if .LogoGreska}}
|
{{if .LogoGreska}}
|
||||||
@@ -135,4 +223,37 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Fiskalizacija ima smisla samo u punom režimu. Kad je „samo evidencija", grupa se
|
||||||
|
// zasivi i forsira na „Ne". Ne koristimo disabled (jer disabled polje se ne šalje u
|
||||||
|
// POST pa bi stara vrednost ostala u bazi) — umesto toga pointer-events:none, a radio
|
||||||
|
// „Ne" ostaje aktivan i čekiran, pa se uredno sačuva „ne".
|
||||||
|
(function() {
|
||||||
|
var rezim = document.querySelectorAll('input[name="firma_rezim"]');
|
||||||
|
var grupa = document.getElementById('fiskalizacija-grupa');
|
||||||
|
var fisk = document.querySelectorAll('input[name="firma_fiskalizacija"]');
|
||||||
|
if (!grupa || !rezim.length) return;
|
||||||
|
|
||||||
|
function azuriraj() {
|
||||||
|
var izabran = document.querySelector('input[name="firma_rezim"]:checked');
|
||||||
|
var samoEvidencija = izabran && izabran.value === 'samo_evidencija';
|
||||||
|
grupa.style.opacity = samoEvidencija ? '0.45' : '';
|
||||||
|
grupa.style.pointerEvents = samoEvidencija ? 'none' : '';
|
||||||
|
if (samoEvidencija) {
|
||||||
|
fisk.forEach(function(r) {
|
||||||
|
r.checked = (r.value === 'ne');
|
||||||
|
var lab = r.closest('label');
|
||||||
|
if (lab) {
|
||||||
|
lab.style.borderColor = r.checked ? 'var(--sb-akcent)' : 'var(--ivica)';
|
||||||
|
lab.style.background = r.checked ? 'var(--pozadina)' : 'transparent';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rezim.forEach(function(r) { r.addEventListener('change', azuriraj); });
|
||||||
|
azuriraj();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user