Servis: sprečeno dupliranje KIR/KPO/fiskalnog pri ponovnom Preuzeto; KPO redni_broj
Ponovni ulazak naloga u status Preuzeto (dupli klik, dupli submit modala naplate, sekvenca Preuzeto→Završeno→Preuzeto) je ponovo pokretao fiskalizaciju i upis u KIR/KPO bez provere da li već postoje — svaki ulazak je duplirao prihod i PDV obavezu, a dashboard/backfill duplikat nikad nije prijavljivao jer je dovoljan bio bar jedan zapis. Dodate PostojiZaIzvor/DohvatiPoServisu provere pre svakog upisa (isti obrazac kao RetryFiskalizacija). KIR upis servisa refaktorisan u model.KirIzServisa (deljeno sa budućim backfill-om). KpoRepo.Kreiraj sad dodeljuje redni_broj automatski (COALESCE(MAX,0)+1) — kolona je postojala u šemi ali se nikad nije popunjavala, pa knjiga o ostvarenom prometu paušalaca nije imala redni broj koji Pravilnik zahteva.
This commit is contained in:
@@ -70,12 +70,14 @@ func (r *KpoRepo) Lista(ctx context.Context, od, do time.Time) ([]model.KpoZapis
|
||||
return rezultat, redovi.Err()
|
||||
}
|
||||
|
||||
// Kreiraj upisuje novi KPO zapis i vraća njegov ID.
|
||||
// Kreiraj upisuje novi KPO zapis i vraća njegov ID. redni_broj se dodeljuje
|
||||
// automatski kao sledeći u nizu (Pravilnik o KPO zahteva kontinuiran redni broj
|
||||
// bez prekida — knjiga se nikad ne briše, pa brojevi ostaju u nizu i posle storna).
|
||||
func (r *KpoRepo) Kreiraj(ctx context.Context, z *model.KpoZapis) (int64, error) {
|
||||
rez, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO kpo_unosi
|
||||
(datum_prometa, broj_dokumenta, opis, prihod, nacin_placanja, napomena, izvor, izvor_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
(datum_prometa, redni_broj, broj_dokumenta, opis, prihod, nacin_placanja, napomena, izvor, izvor_id)
|
||||
VALUES (?, (SELECT COALESCE(MAX(redni_broj), 0) + 1 FROM kpo_unosi), ?, ?, ?, ?, ?, ?, ?)`,
|
||||
z.DatumPrometa.Format("2006-01-02"),
|
||||
z.BrojDokumenta,
|
||||
nullString(z.Opis),
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"ntech/internal/model"
|
||||
)
|
||||
|
||||
// TestKpoRedniBroj: redni_broj mora biti dodeljen automatski i bez prekida —
|
||||
// Pravilnik o KPO zahteva kontinuiran niz, i knjiga se nikad ne briše (storno
|
||||
// se dograđuje kao nov red, ne zamenjuje stari).
|
||||
func TestKpoRedniBroj(t *testing.T) {
|
||||
db := testDB(t)
|
||||
repo := NoviKpoRepo(db)
|
||||
ctx := context.Background()
|
||||
dp := time.Date(2026, 7, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
for _, brojDok := range []string{"SN-1", "SN-2", "SN-3"} {
|
||||
if _, err := repo.Kreiraj(ctx, &model.KpoZapis{
|
||||
DatumPrometa: dp, BrojDokumenta: brojDok, Prihod: 100,
|
||||
}); err != nil {
|
||||
t.Fatalf("Kreiraj %s: %v", brojDok, err)
|
||||
}
|
||||
}
|
||||
|
||||
zapisi, err := repo.Lista(ctx, time.Time{}, time.Time{})
|
||||
if err != nil {
|
||||
t.Fatalf("Lista: %v", err)
|
||||
}
|
||||
if len(zapisi) != 3 {
|
||||
t.Fatalf("očekivano 3 zapisa, dobijeno %d", len(zapisi))
|
||||
}
|
||||
for i, z := range zapisi {
|
||||
if z.RedniBroj == nil || *z.RedniBroj != i+1 {
|
||||
t.Errorf("zapis %q: redni_broj=%v, očekivano %d", z.BrojDokumenta, z.RedniBroj, i+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user