Servis: fiskalizacija pri preuzimanju — način plaćanja + iznos + PFR račun
Migracija 082: nacin_placanja i naplaceno na servisni_nalog Model, repo, handler — pun lanac za čuvanje naplate fiskalizujServis helper — šalje radove+delove ka PFR serveru Modal za Preuzeto dobio izbor načina plaćanja (Gotovina/Kartica/Virman)
This commit is contained in:
@@ -206,6 +206,7 @@ type ServisRepository interface {
|
|||||||
ObrisiOdlukuKlijenta(ctx context.Context, id int64) error
|
ObrisiOdlukuKlijenta(ctx context.Context, id int64) error
|
||||||
Obrisi(ctx context.Context, id int64, korisnikID *int64) error
|
Obrisi(ctx context.Context, id int64, korisnikID *int64) error
|
||||||
SledeciBroj(ctx context.Context) (string, error)
|
SledeciBroj(ctx context.Context) (string, error)
|
||||||
|
SacuvajNaplatu(ctx context.Context, id int64, nacinPlacanja string, naplaceno float64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProdajaRepository definiše operacije nad prodajnim nalozima
|
// ProdajaRepository definiše operacije nad prodajnim nalozima
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (r *ServisRepo) Lista(ctx context.Context, pretraga, status string) ([]mode
|
|||||||
sn.id, sn.klijent_id, sn.tehnicar_id, sn.broj_naloga, sn.uredjaj, sn.serijski_broj,
|
sn.id, sn.klijent_id, sn.tehnicar_id, sn.broj_naloga, sn.uredjaj, sn.serijski_broj,
|
||||||
sn.opis_kvara, sn.trazene_nadogradnje, sn.status, sn.cena_od, sn.cena_do, sn.cena_konacna,
|
sn.opis_kvara, sn.trazene_nadogradnje, sn.status, sn.cena_od, sn.cena_do, sn.cena_konacna,
|
||||||
sn.avans, sn.napomena, sn.garancija_do, sn.garancija_dana, sn.datum_prijema, sn.datum_zavrsetka, sn.predvidjen_datum,
|
sn.avans, sn.napomena, sn.garancija_do, sn.garancija_dana, sn.datum_prijema, sn.datum_zavrsetka, sn.predvidjen_datum,
|
||||||
sn.ostecenja, sn.pin_uredjaja, sn.pribor, sn.napomena_klijentu, sn.nalaz_dijagnostike, sn.uradjeno, sn.cena_dijagnostike, sn.popravka_odbijena, sn.javni_token, sn.komentar_klijenta, sn.odluka_klijenta, sn.datum_odluke,
|
sn.ostecenja, sn.pin_uredjaja, sn.pribor, sn.napomena_klijentu, sn.nalaz_dijagnostike, sn.uradjeno, sn.cena_dijagnostike, sn.popravka_odbijena, sn.javni_token, sn.komentar_klijenta, sn.odluka_klijenta, sn.datum_odluke, sn.nacin_placanja, sn.naplaceno,
|
||||||
COALESCE(kp.naziv, '') AS klijent_naziv,
|
COALESCE(kp.naziv, '') AS klijent_naziv,
|
||||||
(EXISTS(SELECT 1 FROM servis_radovi sr WHERE sr.nalog_id = sn.id AND sr.predlozeno = 1)
|
(EXISTS(SELECT 1 FROM servis_radovi sr WHERE sr.nalog_id = sn.id AND sr.predlozeno = 1)
|
||||||
OR EXISTS(SELECT 1 FROM servisni_delovi sd WHERE sd.nalog_id = sn.id AND sd.predlozeno = 1)
|
OR EXISTS(SELECT 1 FROM servisni_delovi sd WHERE sd.nalog_id = sn.id AND sd.predlozeno = 1)
|
||||||
@@ -108,7 +108,7 @@ func (r *ServisRepo) DohvatiID(ctx context.Context, id int64) (*model.ServisniNa
|
|||||||
id, klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj,
|
id, klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj,
|
||||||
opis_kvara, trazene_nadogradnje, status, cena_od, cena_do, cena_konacna,
|
opis_kvara, trazene_nadogradnje, status, cena_od, cena_do, cena_konacna,
|
||||||
avans, napomena, garancija_do, garancija_dana, datum_prijema, datum_zavrsetka, predvidjen_datum,
|
avans, napomena, garancija_do, garancija_dana, datum_prijema, datum_zavrsetka, predvidjen_datum,
|
||||||
ostecenja, pin_uredjaja, pribor, napomena_klijentu, nalaz_dijagnostike, uradjeno, cena_dijagnostike, popravka_odbijena, javni_token, komentar_klijenta, odluka_klijenta, datum_odluke
|
ostecenja, pin_uredjaja, pribor, napomena_klijentu, nalaz_dijagnostike, uradjeno, cena_dijagnostike, popravka_odbijena, javni_token, komentar_klijenta, odluka_klijenta, datum_odluke, nacin_placanja, naplaceno
|
||||||
FROM servisni_nalozi WHERE id = ?`, id)
|
FROM servisni_nalozi WHERE id = ?`, id)
|
||||||
|
|
||||||
var n model.ServisniNalog
|
var n model.ServisniNalog
|
||||||
@@ -160,7 +160,7 @@ func (r *ServisRepo) DohvatiJavniToken(ctx context.Context, token string) (*mode
|
|||||||
id, klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj,
|
id, klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj,
|
||||||
opis_kvara, trazene_nadogradnje, status, cena_od, cena_do, cena_konacna,
|
opis_kvara, trazene_nadogradnje, status, cena_od, cena_do, cena_konacna,
|
||||||
avans, napomena, garancija_do, garancija_dana, datum_prijema, datum_zavrsetka, predvidjen_datum,
|
avans, napomena, garancija_do, garancija_dana, datum_prijema, datum_zavrsetka, predvidjen_datum,
|
||||||
ostecenja, pin_uredjaja, pribor, napomena_klijentu, nalaz_dijagnostike, uradjeno, cena_dijagnostike, popravka_odbijena, javni_token, komentar_klijenta, odluka_klijenta, datum_odluke
|
ostecenja, pin_uredjaja, pribor, napomena_klijentu, nalaz_dijagnostike, uradjeno, cena_dijagnostike, popravka_odbijena, javni_token, komentar_klijenta, odluka_klijenta, datum_odluke, nacin_placanja, naplaceno
|
||||||
FROM servisni_nalozi WHERE javni_token = ?`, token)
|
FROM servisni_nalozi WHERE javni_token = ?`, token)
|
||||||
|
|
||||||
var n model.ServisniNalog
|
var n model.ServisniNalog
|
||||||
@@ -451,6 +451,18 @@ func (r *ServisRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SacuvajNaplatu beleži način plaćanja i naplaćeni iznos pri preuzimanju uređaja.
|
||||||
|
func (r *ServisRepo) SacuvajNaplatu(ctx context.Context, id int64, nacinPlacanja string, naplaceno float64) error {
|
||||||
|
_, err := r.db.ExecContext(ctx,
|
||||||
|
"UPDATE servisni_nalozi SET nacin_placanja = ?, naplaceno = ? WHERE id = ?",
|
||||||
|
nacinPlacanja, naplaceno, id,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ntech: ServisRepo.SacuvajNaplatu: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// scanNalog čita redove iz upita u ServisniNalog struct —
|
// scanNalog čita redove iz upita u ServisniNalog struct —
|
||||||
// klijentNaziv je opcioni pokazivač, nil kada se čita bez JOIN-a
|
// klijentNaziv je opcioni pokazivač, nil kada se čita bez JOIN-a
|
||||||
func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *string, imaPredlog *bool) error {
|
func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *string, imaPredlog *bool) error {
|
||||||
@@ -461,11 +473,15 @@ func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *st
|
|||||||
var garancijaDana sql.NullInt64
|
var garancijaDana sql.NullInt64
|
||||||
var popravkaOdbijena sql.NullInt64
|
var popravkaOdbijena sql.NullInt64
|
||||||
|
|
||||||
|
var nacinPlacanja sql.NullString
|
||||||
|
var naplaceno sql.NullFloat64
|
||||||
|
|
||||||
args := []any{
|
args := []any{
|
||||||
&n.ID, &klijentID, &tehnicarID, &n.BrojNaloga, &n.Uredjaj, &serijskiBroj,
|
&n.ID, &klijentID, &tehnicarID, &n.BrojNaloga, &n.Uredjaj, &serijskiBroj,
|
||||||
&n.OpisKvara, &n.TrazeneNadogradnje, &n.Status, &cenaOd, &cenaDo, &cenaKonacna,
|
&n.OpisKvara, &n.TrazeneNadogradnje, &n.Status, &cenaOd, &cenaDo, &cenaKonacna,
|
||||||
&avans, &napomena, &garancijaDo, &garancijaDana, &n.DatumPrijema, &datumZavrsetka, &predvidjenDatum,
|
&avans, &napomena, &garancijaDo, &garancijaDana, &n.DatumPrijema, &datumZavrsetka, &predvidjenDatum,
|
||||||
&ostecenja, &pinUredjaja, &pribor, &napomenaKlijentu, &nalazDijagnostike, &uradjeno, &n.CenaDijagnostike, &popravkaOdbijena, &javniToken, &komentarKlijenta, &odlukaKlijenta, &datumOdluke,
|
&ostecenja, &pinUredjaja, &pribor, &napomenaKlijentu, &nalazDijagnostike, &uradjeno, &n.CenaDijagnostike, &popravkaOdbijena, &javniToken, &komentarKlijenta, &odlukaKlijenta, &datumOdluke,
|
||||||
|
&nacinPlacanja, &naplaceno,
|
||||||
}
|
}
|
||||||
|
|
||||||
if klijentNaziv != nil {
|
if klijentNaziv != nil {
|
||||||
@@ -535,6 +551,10 @@ func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *st
|
|||||||
v := datumOdluke.Time
|
v := datumOdluke.Time
|
||||||
n.DatumOdluke = &v
|
n.DatumOdluke = &v
|
||||||
}
|
}
|
||||||
|
n.NacinPlacanja = nacinPlacanja.String
|
||||||
|
if naplaceno.Valid {
|
||||||
|
n.Naplaceno = naplaceno.Float64
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+148
-1
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/png"
|
"image/png"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@@ -12,8 +13,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"ntech/internal/config"
|
||||||
appdbPkg "ntech/internal/db"
|
appdbPkg "ntech/internal/db"
|
||||||
"ntech/internal/db/sqlite"
|
"ntech/internal/db/sqlite"
|
||||||
|
"ntech/internal/fiskal"
|
||||||
"ntech/internal/middleware"
|
"ntech/internal/middleware"
|
||||||
"ntech/internal/model"
|
"ntech/internal/model"
|
||||||
|
|
||||||
@@ -1935,10 +1938,154 @@ func (h *Handler) PromeniStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "Greška pri promeni statusa", http.StatusInternalServerError)
|
http.Error(w, "Greška pri promeni statusa", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pri prelasku u Preuzeto — sačuvaj naplatu i fiskalizuj
|
||||||
|
if noviStatus == model.StatusPreuzeto {
|
||||||
|
nacin := strings.TrimSpace(r.FormValue("nacin_placanja"))
|
||||||
|
if nacin == "" {
|
||||||
|
nacin = "Gotovina"
|
||||||
|
}
|
||||||
|
iznosStr := strings.TrimSpace(r.FormValue("naplaceno"))
|
||||||
|
iznos := 0.0
|
||||||
|
if iznosStr != "" {
|
||||||
|
if v, e := strconv.ParseFloat(iznosStr, 64); e == nil && v > 0 {
|
||||||
|
iznos = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iznos == 0 {
|
||||||
|
// izračunaj iz za naplatu ako nije prosleđen
|
||||||
|
nalog, _ := h.ServisRepo.DohvatiID(r.Context(), id)
|
||||||
|
if nalog != nil {
|
||||||
|
iznos = nalog.CenaDijagnostike
|
||||||
|
if !nalog.PopravkaOdbijena && nalog.CenaKonacna != nil {
|
||||||
|
delovi, _ := h.ServisniDeloviRepo.DohvatiZaNalog(r.Context(), id)
|
||||||
|
ukupnoDelovi := 0.0
|
||||||
|
for _, d := range delovi {
|
||||||
|
ukupnoDelovi += d.Ukupno()
|
||||||
|
}
|
||||||
|
iznos = *nalog.CenaKonacna + ukupnoDelovi
|
||||||
|
}
|
||||||
|
if nalog.Avans != nil {
|
||||||
|
iznos -= *nalog.Avans
|
||||||
|
}
|
||||||
|
if iznos < 0 {
|
||||||
|
iznos = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = h.ServisRepo.SacuvajNaplatu(r.Context(), id, nacin, iznos)
|
||||||
|
|
||||||
|
// fiskalizacija servisa — ako je modul uključen
|
||||||
|
if h.modulUkljucen(r.Context(), config.ModulFiskalizacija) {
|
||||||
|
klijent := h.fiskalKlijent()
|
||||||
|
if klijent != nil && iznos > 0 {
|
||||||
|
h.fiskalizujServis(r.Context(), id, klijent, nacin, iznos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10)+"?sacuvano=1", http.StatusSeeOther)
|
http.Redirect(w, r, "/servis/"+strconv.FormatInt(id, 10)+"?sacuvano=1", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AzurirajGaranciju ažurira datum garancije na servisnom nalogu
|
// fiskalizujServis šalje fiskalni zahtev za servisni nalog pri preuzimanju.
|
||||||
|
// Best-effort: greške se loguju, ne zaustavljaju promenu statusa.
|
||||||
|
func (h *Handler) fiskalizujServis(ctx context.Context, servisID int64, klijent *fiskal.Klijent, nacinPlacanja string, iznos float64) {
|
||||||
|
nalog, err := h.ServisRepo.DohvatiID(ctx, servisID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("fiskalizujServis: nije pronađen nalog", "id", servisID, "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
radovi, _ := h.ServisniRadoviRepo.DohvatiZaNalog(ctx, servisID)
|
||||||
|
delovi, _ := h.deloviSaPotrazivanima(ctx, servisID)
|
||||||
|
|
||||||
|
// napravi stavke za fiskalni račun
|
||||||
|
items := make([]fiskal.InvoiceItem, 0)
|
||||||
|
for _, r := range radovi {
|
||||||
|
if r.Predlozeno {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stopa := 20.0 // podrazumevano — servisne usluge su 20% PDV
|
||||||
|
items = append(items, fiskal.InvoiceItem{
|
||||||
|
Name: r.Naziv,
|
||||||
|
Labels: []string{fiskal.OznakaPDV(stopa)},
|
||||||
|
TotalAmount: fiskal.BrutoCena(r.Ukupno(), stopa),
|
||||||
|
UnitPrice: fiskal.BrutoCena(r.CenaKomada, stopa),
|
||||||
|
Quantity: r.Kolicina,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, d := range delovi {
|
||||||
|
if d.Predlozeno {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stopa := 20.0
|
||||||
|
items = append(items, fiskal.InvoiceItem{
|
||||||
|
Name: d.ArtikalNaziv,
|
||||||
|
Labels: []string{fiskal.OznakaPDV(stopa)},
|
||||||
|
TotalAmount: fiskal.BrutoCena(d.Ukupno(), stopa),
|
||||||
|
UnitPrice: fiskal.BrutoCena(d.CenaKomada, stopa),
|
||||||
|
Quantity: float64(d.Kolicina),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pib := ""
|
||||||
|
if nalog.KlijentID != nil {
|
||||||
|
if k, e := h.KlijentiRepo.DohvatiID(ctx, *nalog.KlijentID); e == nil {
|
||||||
|
pib = k.PIB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kasir, _ := sqlite.DohvatiPodesavanje(ctx, h.DB, "pfr_kasir")
|
||||||
|
if kasir == "" {
|
||||||
|
kasir = "NTech"
|
||||||
|
}
|
||||||
|
|
||||||
|
zahtev := fiskal.InvoiceRequest{
|
||||||
|
InvoiceRequest: fiskal.InvoiceRequestBody{
|
||||||
|
InvoiceType: "Normal",
|
||||||
|
TransactionType: "Sale",
|
||||||
|
Payment: []fiskal.PaymentItem{
|
||||||
|
{Amount: iznos, PaymentType: fiskal.TipPlacanja(nacinPlacanja)},
|
||||||
|
},
|
||||||
|
Items: items,
|
||||||
|
Cashier: kasir,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if pib != "" {
|
||||||
|
zahtev.InvoiceRequest.BuyerID = "10:" + pib
|
||||||
|
}
|
||||||
|
|
||||||
|
odgovor, errFisk := klijent.IzdajRacun(ctx, zahtev)
|
||||||
|
if errFisk != nil {
|
||||||
|
slog.Error("fiskalizacija servisa nije uspela", "servis_id", servisID, "error", errFisk)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// sačuvaj fiskalni račun (kao i za prodaju, ali bez veze prodaja_id — koristimo negativan ID)
|
||||||
|
poreskeJSON, _ := json.Marshal(odgovor.TaxItems)
|
||||||
|
siroviJSON, _ := json.Marshal(odgovor)
|
||||||
|
fr := &model.FiskalniRacun{
|
||||||
|
ProdajaID: -servisID, // negativan ID za servis (razlikuje se od prodaje)
|
||||||
|
TipRacuna: "Normal",
|
||||||
|
TipTransakcije: "Sale",
|
||||||
|
PfrBroj: odgovor.InvoiceNumber,
|
||||||
|
PfrVreme: odgovor.SdcDateTime,
|
||||||
|
Brojac: odgovor.InvoiceCounter,
|
||||||
|
EkstenzijaBrojaca: odgovor.InvoiceCounterExtension,
|
||||||
|
UrlVerifikacija: odgovor.VerificationURL,
|
||||||
|
QRKod: odgovor.VerificationQRCode,
|
||||||
|
PoreskeStavke: string(poreskeJSON),
|
||||||
|
UkupnoZaNaplatu: odgovor.TotalAmount,
|
||||||
|
UkupanPorez: odgovor.TotalTax,
|
||||||
|
SiroviOdgovor: string(siroviJSON),
|
||||||
|
Potpisao: odgovor.SignedBy,
|
||||||
|
Zatrazio: odgovor.RequestedBy,
|
||||||
|
Poruka: odgovor.Messages,
|
||||||
|
}
|
||||||
|
if _, err := h.FiskalRepo.Kreiraj(ctx, fr); err != nil {
|
||||||
|
slog.Error("greška pri čuvanju fiskalnog računa za servis", "servis_id", servisID, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
func (h *Handler) AzurirajGaranciju(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) AzurirajGaranciju(w http.ResponseWriter, r *http.Request) {
|
||||||
if _, ok := h.zahtevajDozvolu(w, r, "servis.izmeni"); !ok {
|
if _, ok := h.zahtevajDozvolu(w, r, "servis.izmeni"); !ok {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ type ServisniNalog struct {
|
|||||||
OdlukaKlijenta string // '' / 'prihvaceno' / 'odbijeno'
|
OdlukaKlijenta string // '' / 'prihvaceno' / 'odbijeno'
|
||||||
DatumOdluke *time.Time // kada je klijent doneo odluku
|
DatumOdluke *time.Time // kada je klijent doneo odluku
|
||||||
JavniToken string
|
JavniToken string
|
||||||
|
NacinPlacanja string // način plaćanja pri preuzimanju (Gotovina, Kartica, Virman...)
|
||||||
|
Naplaceno float64 // iznos koji je naplaćen pri preuzimanju
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServisniDeo predstavlja jedan artikal ugrađen u servisni nalog
|
// ServisniDeo predstavlja jedan artikal ugrađen u servisni nalog
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Servis: način plaćanja i naplaćeni iznos pri preuzimanju uređaja.
|
||||||
|
-- Koristi se za evidenciju i fiskalizaciju pri prelasku u status "Preuzeto".
|
||||||
|
ALTER TABLE servisni_nalozi ADD COLUMN nacin_placanja TEXT DEFAULT '';
|
||||||
|
ALTER TABLE servisni_nalozi ADD COLUMN naplaceno REAL DEFAULT 0;
|
||||||
@@ -150,6 +150,15 @@
|
|||||||
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#sadrzaj" style="margin-top:8px;">
|
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#sadrzaj" style="margin-top:8px;">
|
||||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||||
<input type="hidden" name="status" value="Preuzeto">
|
<input type="hidden" name="status" value="Preuzeto">
|
||||||
|
<input type="hidden" name="naplaceno" value="{{printf "%.2f" .PreostaloSve}}">
|
||||||
|
<div style="margin-bottom:10px;">
|
||||||
|
<label class="polje-labela">Način plaćanja</label>
|
||||||
|
<select name="nacin_placanja" style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:13px;">
|
||||||
|
<option value="Gotovina">Gotovina</option>
|
||||||
|
<option value="Kartica">Kartica</option>
|
||||||
|
<option value="Virman">Virman</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn-primarno" style="width:100%;">Naplati i preuzmi</button>
|
<button type="submit" class="btn-primarno" style="width:100%;">Naplati i preuzmi</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user