diff --git a/internal/db/sqlite/fiskal.go b/internal/db/sqlite/fiskal.go index 258dc38..d966a86 100644 --- a/internal/db/sqlite/fiskal.go +++ b/internal/db/sqlite/fiskal.go @@ -19,16 +19,23 @@ func NoviFiskalRepo(db *sql.DB) *FiskalRepo { } // Kreiraj dodaje novi fiskalni račun u bazu. Vraća ID kreiranog reda. -// ProdajaID je UNIQUE — drugi poziv sa istim ID-jem pada na constraint. +// Koristi prodaja_id (za prodaju) ILI servis_id (za servis) — ne oba. func (r *FiskalRepo) Kreiraj(ctx context.Context, fr *model.FiskalniRacun) (int64, error) { + var prodajaID, servisID any + if fr.ProdajaID > 0 { + prodajaID = fr.ProdajaID + } + if fr.ServisID > 0 { + servisID = fr.ServisID + } rez, err := r.db.ExecContext(ctx, ` INSERT INTO fiskalni_racuni ( - prodaja_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, + prodaja_id, servis_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, brojac, ekstenzija_brojaca, url_verifikacija, qr_kod, poreske_stavke, ukupno_za_naplatu, ukupan_porez, sirovi_odgovor, potpisao, zatrazio, poruka - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `, fr.ProdajaID, fr.TipRacuna, fr.TipTransakcije, fr.PfrBroj, fr.PfrVreme, + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `, prodajaID, servisID, fr.TipRacuna, fr.TipTransakcije, fr.PfrBroj, fr.PfrVreme, fr.Brojac, fr.EkstenzijaBrojaca, fr.UrlVerifikacija, fr.QRKod, fr.PoreskeStavke, fr.UkupnoZaNaplatu, fr.UkupanPorez, fr.SiroviOdgovor, fr.Potpisao, fr.Zatrazio, fr.Poruka, @@ -44,28 +51,32 @@ func (r *FiskalRepo) Kreiraj(ctx context.Context, fr *model.FiskalniRacun) (int6 } // DohvatiPoProdaji vraća fiskalni račun za dati prodajni nalog. -// Vraća nil bez greške ako račun ne postoji (nije fiskalizovano). +// Vraća nil bez greške ako račun ne postoji. func (r *FiskalRepo) DohvatiPoProdaji(ctx context.Context, prodajaID int64) (*model.FiskalniRacun, error) { fr := &model.FiskalniRacun{} var storniran int + var sID sql.NullInt64 err := r.db.QueryRowContext(ctx, ` - SELECT id, prodaja_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, + SELECT id, prodaja_id, servis_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, brojac, ekstenzija_brojaca, url_verifikacija, qr_kod, poreske_stavke, ukupno_za_naplatu, ukupan_porez, sirovi_odgovor, potpisao, zatrazio, poruka, storniran, vreme_kreiranja FROM fiskalni_racuni WHERE prodaja_id = ? `, prodajaID).Scan( - &fr.ID, &fr.ProdajaID, &fr.TipRacuna, &fr.TipTransakcije, &fr.PfrBroj, &fr.PfrVreme, + &fr.ID, &fr.ProdajaID, &sID, &fr.TipRacuna, &fr.TipTransakcije, &fr.PfrBroj, &fr.PfrVreme, &fr.Brojac, &fr.EkstenzijaBrojaca, &fr.UrlVerifikacija, &fr.QRKod, &fr.PoreskeStavke, &fr.UkupnoZaNaplatu, &fr.UkupanPorez, &fr.SiroviOdgovor, &fr.Potpisao, &fr.Zatrazio, &fr.Poruka, &storniran, &fr.VremeKreiranja, ) if err == sql.ErrNoRows { - return nil, nil // nije fiskalizovano — nije greška + return nil, nil } if err != nil { return nil, fmt.Errorf("ntech: FiskalRepo.DohvatiPoProdaji: %w", err) } + if sID.Valid { + fr.ServisID = sID.Int64 + } fr.Storniran = storniran != 0 return fr, nil } diff --git a/internal/handler/servis.go b/internal/handler/servis.go index d75bc0d..b27974e 100644 --- a/internal/handler/servis.go +++ b/internal/handler/servis.go @@ -2065,7 +2065,7 @@ func (h *Handler) fiskalizujServis(ctx context.Context, servisID int64, klijent poreskeJSON, _ := json.Marshal(odgovor.TaxItems) siroviJSON, _ := json.Marshal(odgovor) fr := &model.FiskalniRacun{ - ProdajaID: -servisID, // negativan ID za servis (razlikuje se od prodaje) + ServisID: servisID, TipRacuna: "Normal", TipTransakcije: "Sale", PfrBroj: odgovor.InvoiceNumber, diff --git a/internal/model/fiskal.go b/internal/model/fiskal.go index 41ab07c..ccd7e96 100644 --- a/internal/model/fiskal.go +++ b/internal/model/fiskal.go @@ -4,7 +4,8 @@ package model // Polja prate tačno ono što Fisk server vraća u JSON odgovoru (vidi NtechFisk.md §3.2). type FiskalniRacun struct { ID int64 - ProdajaID int64 + ProdajaID int64 // 0 ako nije vezan za prodaju (npr. servisni nalog) + ServisID int64 // 0 ako nije vezan za servis (npr. prodajni nalog) TipRacuna string // "Normal", "Advance", "Copy", "Training" TipTransakcije string // "Sale", "Refund" PfrBroj string // invoiceNumber — jedinstven broj fiskalnog računa diff --git a/migrations/083_fiskalni_racuni_servis.sql b/migrations/083_fiskalni_racuni_servis.sql new file mode 100644 index 0000000..c32ef34 --- /dev/null +++ b/migrations/083_fiskalni_racuni_servis.sql @@ -0,0 +1,49 @@ +-- Popravka: fiskalni_racuni mora da podrži i servisne naloge (pored prodajnih). +-- Originalna migracija 081 imala je FOREIGN KEY na prodajni_nalozi(id), +-- ali servisni nalozi ne idu u tu tabelu. Zamenjujemo FK sa nullable kolonom. +-- Rekreiramo tabelu: kopiramo podatke, brišemo staru, kreiramo novu bez FK. + +-- 1. Nova tabela bez FK — prodaja_id je nullable +CREATE TABLE IF NOT EXISTS fiskalni_racuni_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + prodaja_id INTEGER, -- NULL za servisne naloge + servis_id INTEGER, -- NULL za prodajne naloge + tip_racuna TEXT NOT NULL DEFAULT 'Normal', + tip_transakcije TEXT NOT NULL DEFAULT 'Sale', + pfr_broj TEXT NOT NULL, + pfr_vreme TEXT NOT NULL, + brojac TEXT, + ekstenzija_brojaca TEXT, + url_verifikacija TEXT, + qr_kod TEXT, + poreske_stavke TEXT, + ukupno_za_naplatu REAL, + ukupan_porez REAL, + sirovi_odgovor TEXT, + potpisao TEXT, + zatrazio TEXT, + poruka TEXT, + storniran INTEGER NOT NULL DEFAULT 0, + vreme_kreiranja TEXT NOT NULL DEFAULT (datetime('now','localtime')) +); + +-- 2. Kopiraj postojeće redove (ako ih ima) iz stare tabele +INSERT INTO fiskalni_racuni_new + (id, prodaja_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, + brojac, ekstenzija_brojaca, url_verifikacija, qr_kod, + poreske_stavke, ukupno_za_naplatu, ukupan_porez, + sirovi_odgovor, potpisao, zatrazio, poruka, storniran, vreme_kreiranja) +SELECT id, prodaja_id, tip_racuna, tip_transakcije, pfr_broj, pfr_vreme, + brojac, ekstenzija_brojaca, url_verifikacija, qr_kod, + poreske_stavke, ukupno_za_naplatu, ukupan_porez, + sirovi_odgovor, potpisao, zatrazio, poruka, storniran, vreme_kreiranja +FROM fiskalni_racuni; + +-- 3. Zameni tabele +DROP TABLE fiskalni_racuni; +ALTER TABLE fiskalni_racuni_new RENAME TO fiskalni_racuni; + +-- 4. Indeksi +CREATE INDEX IF NOT EXISTS idx_fiskalni_racuni_prodaja ON fiskalni_racuni(prodaja_id); +CREATE INDEX IF NOT EXISTS idx_fiskalni_racuni_servis ON fiskalni_racuni(servis_id); +CREATE INDEX IF NOT EXISTS idx_fiskalni_racuni_pfr_broj ON fiskalni_racuni(pfr_broj);