Klijent: izbor JMBG/Br. lične karte i kontakt osoba za pravno lice

- Nova kolona tip_identifikacije ('jmbg'/'licna_karta'), migracija 062; postojeći klijenti podrazumevano 'jmbg'
- model.Klijent: polje TipIdentifikacije + helper OznakaIdentifikacije za prikaz
- sqlite/klijent.go: kolona u svim upitima (Lista, DohvatiID, ListaFilter, Kreiraj, Izmeni)
- parseFormuKlijenta i mozdaKreirajKlijenta čitaju tip_identifikacije (fallback 'jmbg')
- Forme klijenta i servisnog naloga: selektor vrste dokumenta + polje vrednosti
- Servisni nalog: kontakt osoba (ime/prezime) za pravno lice
- Validnost broja (JMBG 13 cifara, broj lične karte) ostavljena za kasnije
This commit is contained in:
2026-06-21 12:28:39 +02:00
parent 045ea766f1
commit 8bdefd0561
7 changed files with 129 additions and 60 deletions
+25 -16
View File
@@ -22,15 +22,15 @@ func NoviKlijentRepo(db *sql.DB) *KlijentRepo {
// Lista vraća listu klijenata sa opcionom pretragom po imenu, prezimenu ili nazivu firme
func (r *KlijentRepo) Lista(ctx context.Context, pretraga string) ([]model.Klijent, error) {
upit := `
SELECT id, tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
SELECT id, tip, ime, prezime, jmbg, tip_identifikacije, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
FROM klijenti
WHERE 1=1`
args := []any{}
if pretraga != "" {
upit += " AND (ime LIKE ? OR prezime LIKE ? OR (ime || ' ' || prezime) LIKE ? OR naziv_firme LIKE ? OR telefon LIKE ? OR email LIKE ?)"
p := "%" + pretraga + "%"
upit += " AND (ime LIKE ? OR prezime LIKE ? OR (ime || ' ' || prezime) LIKE ? OR naziv_firme LIKE ? OR telefon LIKE ? OR email LIKE ?)"
p := "%" + pretraga + "%"
args = append(args, p, p, p, p, p, p)
}
@@ -45,9 +45,9 @@ upit += " AND (ime LIKE ? OR prezime LIKE ? OR (ime || ' ' || prezime) LIKE ? OR
var rezultat []model.Klijent
for redovi.Next() {
var k model.Klijent
var ime, prezime, jmbg, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
var ime, prezime, jmbg, tipIdent, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
err := redovi.Scan(
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &tipIdent, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
)
if err != nil {
return nil, fmt.Errorf("ntech: KlijentRepo.Lista: scan: %w", err)
@@ -55,6 +55,7 @@ upit += " AND (ime LIKE ? OR prezime LIKE ? OR (ime || ' ' || prezime) LIKE ? OR
k.Ime = ime.String
k.Prezime = prezime.String
k.JMBG = jmbg.String
k.TipIdentifikacije = tipIdent.String
k.NazivFirme = nazivFirme.String
k.PIB = pib.String
k.Telefon = telefon.String
@@ -70,12 +71,12 @@ upit += " AND (ime LIKE ? OR prezime LIKE ? OR (ime || ' ' || prezime) LIKE ? OR
// DohvatiID vraća jednog klijenta po ID-u
func (r *KlijentRepo) DohvatiID(ctx context.Context, id int64) (*model.Klijent, error) {
var k model.Klijent
var ime, prezime, jmbg, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
var ime, prezime, jmbg, tipIdent, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
err := r.db.QueryRowContext(ctx, `
SELECT id, tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
SELECT id, tip, ime, prezime, jmbg, tip_identifikacije, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
FROM klijenti WHERE id = ?`, id).Scan(
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &tipIdent, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
)
if err != nil {
return nil, fmt.Errorf("ntech: KlijentRepo.DohvatiID: %w", err)
@@ -84,6 +85,7 @@ func (r *KlijentRepo) DohvatiID(ctx context.Context, id int64) (*model.Klijent,
k.Ime = ime.String
k.Prezime = prezime.String
k.JMBG = jmbg.String
k.TipIdentifikacije = tipIdent.String
k.NazivFirme = nazivFirme.String
k.PIB = pib.String
k.Telefon = telefon.String
@@ -99,10 +101,13 @@ func (r *KlijentRepo) Kreiraj(ctx context.Context, k *model.Klijent) (int64, err
if k.Tip == "" {
k.Tip = "fizicko"
}
if k.TipIdentifikacije == "" {
k.TipIdentifikacije = "jmbg"
}
rezultat, err := r.db.ExecContext(ctx, `
INSERT INTO klijenti (tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, mesto, napomena)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG),
INSERT INTO klijenti (tip, ime, prezime, jmbg, tip_identifikacije, naziv_firme, pib, telefon, email, mesto, napomena)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG), k.TipIdentifikacije,
nullString(k.NazivFirme), nullString(k.PIB), nullString(k.Telefon),
nullString(k.Email), nullString(k.Mesto), nullString(k.Napomena),
)
@@ -123,12 +128,15 @@ func (r *KlijentRepo) Izmeni(ctx context.Context, k *model.Klijent) error {
if k.Tip == "" {
k.Tip = "fizicko"
}
if k.TipIdentifikacije == "" {
k.TipIdentifikacije = "jmbg"
}
_, err := r.db.ExecContext(ctx, `
UPDATE klijenti SET
tip = ?, ime = ?, prezime = ?, jmbg = ?, naziv_firme = ?,
tip = ?, ime = ?, prezime = ?, jmbg = ?, tip_identifikacije = ?, naziv_firme = ?,
pib = ?, telefon = ?, email = ?, mesto = ?, napomena = ?
WHERE id = ?`,
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG),
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG), k.TipIdentifikacije,
nullString(k.NazivFirme), nullString(k.PIB), nullString(k.Telefon),
nullString(k.Email), nullString(k.Mesto), nullString(k.Napomena), k.ID,
)
@@ -142,7 +150,7 @@ func (r *KlijentRepo) Izmeni(ctx context.Context, k *model.Klijent) error {
// ListaFilter vraća listu klijenata sa limitom i offsetom (paginacija)
func (r *KlijentRepo) ListaFilter(ctx context.Context, filter db.KlijentFilter) ([]model.Klijent, error) {
upit := `
SELECT id, tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
SELECT id, tip, ime, prezime, jmbg, tip_identifikacije, naziv_firme, pib, telefon, email, mesto, napomena, datum_unosa
FROM klijenti
WHERE 1=1`
@@ -178,9 +186,9 @@ func (r *KlijentRepo) ListaFilter(ctx context.Context, filter db.KlijentFilter)
var rezultat []model.Klijent
for redovi.Next() {
var k model.Klijent
var ime, prezime, jmbg, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
var ime, prezime, jmbg, tipIdent, nazivFirme, pib, telefon, email, mesto, napomena sql.NullString
err := redovi.Scan(
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &tipIdent, &nazivFirme, &pib, &telefon, &email, &mesto, &napomena, &k.DatumUnosa,
)
if err != nil {
return nil, fmt.Errorf("ntech: KlijentRepo.ListaFilter: scan: %w", err)
@@ -188,6 +196,7 @@ func (r *KlijentRepo) ListaFilter(ctx context.Context, filter db.KlijentFilter)
k.Ime = ime.String
k.Prezime = prezime.String
k.JMBG = jmbg.String
k.TipIdentifikacije = tipIdent.String
k.NazivFirme = nazivFirme.String
k.PIB = pib.String
k.Telefon = telefon.String
+17 -10
View File
@@ -300,17 +300,24 @@ func parseFormuKlijenta(r *http.Request) (model.Klijent, string) {
return model.Klijent{Tip: tip}, "Adresa e-pošte nije ispravna."
}
// tip identifikacionog broja: 'jmbg' ili 'licna_karta' (podrazumevano jmbg)
tipIdent := r.FormValue("tip_identifikacije")
if tipIdent != "jmbg" && tipIdent != "licna_karta" {
tipIdent = "jmbg"
}
return model.Klijent{
Tip: tip,
Ime: ime,
Prezime: strings.TrimSpace(r.FormValue("prezime")),
JMBG: strings.TrimSpace(r.FormValue("jmbg")),
NazivFirme: nazivFirme,
PIB: strings.TrimSpace(r.FormValue("pib")),
Telefon: strings.TrimSpace(r.FormValue("telefon")),
Email: email,
Mesto: strings.TrimSpace(r.FormValue("mesto")),
Napomena: strings.TrimSpace(r.FormValue("napomena")),
Tip: tip,
Ime: ime,
Prezime: strings.TrimSpace(r.FormValue("prezime")),
JMBG: strings.TrimSpace(r.FormValue("jmbg")),
TipIdentifikacije: tipIdent,
NazivFirme: nazivFirme,
PIB: strings.TrimSpace(r.FormValue("pib")),
Telefon: strings.TrimSpace(r.FormValue("telefon")),
Email: email,
Mesto: strings.TrimSpace(r.FormValue("mesto")),
Napomena: strings.TrimSpace(r.FormValue("napomena")),
}, ""
}
+16 -9
View File
@@ -619,16 +619,23 @@ func (h *Handler) mozdaKreirajKlijenta(ctx context.Context, r *http.Request, nal
return "Adresa e-pošte nije ispravna."
}
// tip identifikacionog broja: 'jmbg' ili 'licna_karta' (podrazumevano jmbg)
tipIdent := r.FormValue("tip_identifikacije")
if tipIdent != "jmbg" && tipIdent != "licna_karta" {
tipIdent = "jmbg"
}
klijent := model.Klijent{
Tip: tip,
Ime: ime,
Prezime: strings.TrimSpace(r.FormValue("prezime")),
JMBG: strings.TrimSpace(r.FormValue("jmbg")),
NazivFirme: nazivFirme,
PIB: strings.TrimSpace(r.FormValue("pib")),
Telefon: strings.TrimSpace(r.FormValue("telefon")),
Email: email,
Mesto: strings.TrimSpace(r.FormValue("mesto")),
Tip: tip,
Ime: ime,
Prezime: strings.TrimSpace(r.FormValue("prezime")),
JMBG: strings.TrimSpace(r.FormValue("jmbg")),
TipIdentifikacije: tipIdent,
NazivFirme: nazivFirme,
PIB: strings.TrimSpace(r.FormValue("pib")),
Telefon: strings.TrimSpace(r.FormValue("telefon")),
Email: email,
Mesto: strings.TrimSpace(r.FormValue("mesto")),
}
id, err := h.KlijentiRepo.Kreiraj(ctx, &klijent)
+23 -12
View File
@@ -7,18 +7,21 @@ import (
// Klijent predstavlja jednog klijenta — fizičko lice ili firmu
type Klijent struct {
ID int64
Tip string
Ime string
Prezime string
JMBG string
NazivFirme string
PIB string
Telefon string
Email string
Mesto string
Napomena string
DatumUnosa time.Time
ID int64
Tip string
Ime string
Prezime string
JMBG string // vrednost identifikacionog broja (JMBG ili broj lične karte)
// TipIdentifikacije govori šta je u polju JMBG: "jmbg" ili "licna_karta".
// Validnost vrednosti (JMBG = 13 cifara, format broja lične karte) proverava se kasnije.
TipIdentifikacije string
NazivFirme string
PIB string
Telefon string
Email string
Mesto string
Napomena string
DatumUnosa time.Time
}
// PunoIme vraća ime i prezime za fizičko lice, ili naziv firme za pravno
@@ -28,3 +31,11 @@ func (k Klijent) PunoIme() string {
}
return strings.TrimSpace(k.Ime + " " + k.Prezime)
}
// OznakaIdentifikacije vraća labelu za prikaz: „Br. lične karte" ili „JMBG" (podrazumevano)
func (k Klijent) OznakaIdentifikacije() string {
if k.TipIdentifikacije == "licna_karta" {
return "Br. lične karte"
}
return "JMBG"
}