BUGFIX: fiskalni_racuni — dodata podrška za servisne naloge (servis_id kolona)
Migracija 083: rekreira fiskalni_racuni tabelu sa servis_id (nullable) i bez FK constraint-a Model: dodat ServisID int64 polje Repo: INSERT/SELECT sada koristi i servis_id Handler: fiskalizujServis koristi ServisID umesto negativnog ProdajaID
This commit is contained in:
@@ -19,16 +19,23 @@ func NoviFiskalRepo(db *sql.DB) *FiskalRepo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Kreiraj dodaje novi fiskalni račun u bazu. Vraća ID kreiranog reda.
|
// 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) {
|
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, `
|
rez, err := r.db.ExecContext(ctx, `
|
||||||
INSERT INTO fiskalni_racuni (
|
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,
|
brojac, ekstenzija_brojaca, url_verifikacija, qr_kod,
|
||||||
poreske_stavke, ukupno_za_naplatu, ukupan_porez,
|
poreske_stavke, ukupno_za_naplatu, ukupan_porez,
|
||||||
sirovi_odgovor, potpisao, zatrazio, poruka
|
sirovi_odgovor, potpisao, zatrazio, poruka
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`, fr.ProdajaID, fr.TipRacuna, fr.TipTransakcije, fr.PfrBroj, fr.PfrVreme,
|
`, prodajaID, servisID, fr.TipRacuna, fr.TipTransakcije, fr.PfrBroj, fr.PfrVreme,
|
||||||
fr.Brojac, fr.EkstenzijaBrojaca, fr.UrlVerifikacija, fr.QRKod,
|
fr.Brojac, fr.EkstenzijaBrojaca, fr.UrlVerifikacija, fr.QRKod,
|
||||||
fr.PoreskeStavke, fr.UkupnoZaNaplatu, fr.UkupanPorez,
|
fr.PoreskeStavke, fr.UkupnoZaNaplatu, fr.UkupanPorez,
|
||||||
fr.SiroviOdgovor, fr.Potpisao, fr.Zatrazio, fr.Poruka,
|
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.
|
// 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) {
|
func (r *FiskalRepo) DohvatiPoProdaji(ctx context.Context, prodajaID int64) (*model.FiskalniRacun, error) {
|
||||||
fr := &model.FiskalniRacun{}
|
fr := &model.FiskalniRacun{}
|
||||||
var storniran int
|
var storniran int
|
||||||
|
var sID sql.NullInt64
|
||||||
err := r.db.QueryRowContext(ctx, `
|
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,
|
brojac, ekstenzija_brojaca, url_verifikacija, qr_kod,
|
||||||
poreske_stavke, ukupno_za_naplatu, ukupan_porez,
|
poreske_stavke, ukupno_za_naplatu, ukupan_porez,
|
||||||
sirovi_odgovor, potpisao, zatrazio, poruka, storniran, vreme_kreiranja
|
sirovi_odgovor, potpisao, zatrazio, poruka, storniran, vreme_kreiranja
|
||||||
FROM fiskalni_racuni WHERE prodaja_id = ?
|
FROM fiskalni_racuni WHERE prodaja_id = ?
|
||||||
`, prodajaID).Scan(
|
`, 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.Brojac, &fr.EkstenzijaBrojaca, &fr.UrlVerifikacija, &fr.QRKod,
|
||||||
&fr.PoreskeStavke, &fr.UkupnoZaNaplatu, &fr.UkupanPorez,
|
&fr.PoreskeStavke, &fr.UkupnoZaNaplatu, &fr.UkupanPorez,
|
||||||
&fr.SiroviOdgovor, &fr.Potpisao, &fr.Zatrazio, &fr.Poruka, &storniran, &fr.VremeKreiranja,
|
&fr.SiroviOdgovor, &fr.Potpisao, &fr.Zatrazio, &fr.Poruka, &storniran, &fr.VremeKreiranja,
|
||||||
)
|
)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil // nije fiskalizovano — nije greška
|
return nil, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ntech: FiskalRepo.DohvatiPoProdaji: %w", err)
|
return nil, fmt.Errorf("ntech: FiskalRepo.DohvatiPoProdaji: %w", err)
|
||||||
}
|
}
|
||||||
|
if sID.Valid {
|
||||||
|
fr.ServisID = sID.Int64
|
||||||
|
}
|
||||||
fr.Storniran = storniran != 0
|
fr.Storniran = storniran != 0
|
||||||
return fr, nil
|
return fr, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2065,7 +2065,7 @@ func (h *Handler) fiskalizujServis(ctx context.Context, servisID int64, klijent
|
|||||||
poreskeJSON, _ := json.Marshal(odgovor.TaxItems)
|
poreskeJSON, _ := json.Marshal(odgovor.TaxItems)
|
||||||
siroviJSON, _ := json.Marshal(odgovor)
|
siroviJSON, _ := json.Marshal(odgovor)
|
||||||
fr := &model.FiskalniRacun{
|
fr := &model.FiskalniRacun{
|
||||||
ProdajaID: -servisID, // negativan ID za servis (razlikuje se od prodaje)
|
ServisID: servisID,
|
||||||
TipRacuna: "Normal",
|
TipRacuna: "Normal",
|
||||||
TipTransakcije: "Sale",
|
TipTransakcije: "Sale",
|
||||||
PfrBroj: odgovor.InvoiceNumber,
|
PfrBroj: odgovor.InvoiceNumber,
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ package model
|
|||||||
// Polja prate tačno ono što Fisk server vraća u JSON odgovoru (vidi NtechFisk.md §3.2).
|
// Polja prate tačno ono što Fisk server vraća u JSON odgovoru (vidi NtechFisk.md §3.2).
|
||||||
type FiskalniRacun struct {
|
type FiskalniRacun struct {
|
||||||
ID int64
|
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"
|
TipRacuna string // "Normal", "Advance", "Copy", "Training"
|
||||||
TipTransakcije string // "Sale", "Refund"
|
TipTransakcije string // "Sale", "Refund"
|
||||||
PfrBroj string // invoiceNumber — jedinstven broj fiskalnog računa
|
PfrBroj string // invoiceNumber — jedinstven broj fiskalnog računa
|
||||||
|
|||||||
@@ -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);
|
||||||
Reference in New Issue
Block a user