KIR: prikaz sumnjivih duplikata (double-submit) preskočenih pri backfill-u

Na KIR stranici se sad vidi kartica sa B2B prodajama koje je automatski
backfill preskočio jer izgledaju kao dupli submit forme naplate (isti kupac
i iznos u roku od 60s) — sa objašnjenjem i linkom na ručni unos ili storno.
This commit is contained in:
2026-07-02 10:41:53 +02:00
parent 45831467e0
commit e26bda5d34
2 changed files with 73 additions and 11 deletions
+29 -11
View File
@@ -8,6 +8,7 @@ import (
"strings" "strings"
"time" "time"
appdb "ntech/internal/db"
"ntech/internal/db/sqlite" "ntech/internal/db/sqlite"
"ntech/internal/middleware" "ntech/internal/middleware"
"ntech/internal/model" "ntech/internal/model"
@@ -20,11 +21,12 @@ import (
// PodaciPdvKir su podaci za pregled knjige izdatih računa // PodaciPdvKir su podaci za pregled knjige izdatih računa
type PodaciPdvKir struct { type PodaciPdvKir struct {
model.PodaciStranice model.PodaciStranice
Zapisi []model.PdvKir Zapisi []model.PdvKir
Sume model.PdvKirSume Sume model.PdvKirSume
Od string // filter perioda (YYYY-MM-DD), prazno = bez granice Od string
Do string Do string
Zastareo map[int64]bool // ID zapisa dnevnog pazara čiji je iznos van sinhronizacije sa trenutnim prometom (npr. posle naknadnog storna) Zastareo map[int64]bool
SumnjiviDuplikati []model.ProdajniNalogSaDetaljem // B2B prodaje preskočene pri backfill-u (double-submit)
} }
// PodaciPdvKirForma su podaci za formu unosa zapisa KIR // PodaciPdvKirForma su podaci za formu unosa zapisa KIR
@@ -105,13 +107,29 @@ func (h *Handler) PdvKir(w http.ResponseWriter, r *http.Request) {
ps := h.popuniPodaciStranice(r, podesavanja) ps := h.popuniPodaciStranice(r, podesavanja)
ps.Stranica = "pdv-kir" ps.Stranica = "pdv-kir"
ps.NaslovStranice = "KIR — knjiga izdatih računa" ps.NaslovStranice = "KIR — knjiga izdatih računa"
// detektuj sumnjive duplikate (double-submit) da ih korisnik vidi
var sumnjivi []model.ProdajniNalogSaDetaljem
if _, _, kandidati, err := h.kirKandidatiProdaje(r.Context()); err == nil {
duplikati := sumnjiviDuplikati(kandidati)
if len(duplikati) > 0 {
nalozi, _ := h.ProdajaRepo.Lista(r.Context(), appdb.ProdajaFilter{})
for _, nd := range nalozi {
if duplikati[nd.ID] {
sumnjivi = append(sumnjivi, nd)
}
}
}
}
h.renderujTemplate(w, "pdv_kir", PodaciPdvKir{ h.renderujTemplate(w, "pdv_kir", PodaciPdvKir{
PodaciStranice: ps, PodaciStranice: ps,
Zapisi: zapisi, Zapisi: zapisi,
Sume: model.SumirajKir(zapisi), Sume: model.SumirajKir(zapisi),
Od: odStr, Od: odStr,
Do: doStr, Do: doStr,
Zastareo: zastareo, Zastareo: zastareo,
SumnjiviDuplikati: sumnjivi,
}) })
} }
+44
View File
@@ -101,5 +101,49 @@
</div> </div>
</div> </div>
<!-- sumnjivi duplikati (double-submit) — prodaje preskočene pri automatskom uvozu -->
{{if .SumnjiviDuplikati}}
<div class="kartica animiraj" style="margin-top:24px;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;">
<span style="font-size:14px;font-weight:600;">⚠ Sumnjivi duplikati</span>
<span style="font-size:12px;color:var(--tekst-sporedni);">({{len .SumnjiviDuplikati}} preskočeno pri uvozu — mogući double-submit, proveri ručno)</span>
</div>
<div style="overflow-x:auto;">
<table class="tabela" style="width:100%;border-collapse:collapse;font-size:13px;min-width:600px;">
<thead>
<tr style="text-align:left;color:var(--tekst-sporedni);border-bottom:0.5px solid var(--ivica);">
<th style="padding:8px 12px;">Broj</th>
<th style="padding:8px 12px;">Datum</th>
<th style="padding:8px 12px;">Kupac</th>
<th style="padding:8px 12px;text-align:right;">Iznos</th>
<th style="padding:8px 12px;"></th>
</tr>
</thead>
<tbody>
{{range .SumnjiviDuplikati}}
<tr style="border-bottom:0.5px solid var(--ivica);{{if .Stornirano}}opacity:.5;{{end}}">
<td style="padding:8px 12px;font-family:monospace;">{{.BrojNaloga}}</td>
<td style="padding:8px 12px;white-space:nowrap;">{{.Datum.Format "02.01.2006. 15:04"}}</td>
<td style="padding:8px 12px;">{{.KlijentNaziv}}</td>
<td style="padding:8px 12px;text-align:right;font-weight:500;">{{dinari .Ukupno}}</td>
<td style="padding:8px 12px;text-align:right;white-space:nowrap;">
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML"
href="/prodaja/{{.ID}}" class="btn-sekundarno" style="font-size:12px;padding:4px 10px;">Pregled</a>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div style="margin-top:12px;font-size:12px;color:var(--tekst-sporedni);line-height:1.6;">
Ovo su prodaje koje izgledaju kao dupli unos (isti kupac, isti iznos, unutar 60 sekundi).
Automatski uvoz ih preskače da ne bi duplirao prihod u KIR-u.
<strong>Ako su to stvarno dve odvojene prodaje</strong> — unesi ručno preko
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/pdv/kir/nova">+ Nov izlazni račun</a>.
<strong>Ako je greška (double-submit)</strong> — storniraj/obriši duplikat u Prodaji.
</div>
</div>
{{end}}
</div> </div>
{{end}} {{end}}