diff --git a/internal/db/sqlite/servisni_delovi.go b/internal/db/sqlite/servisni_delovi.go index 5a2c3a6..95a74a1 100644 --- a/internal/db/sqlite/servisni_delovi.go +++ b/internal/db/sqlite/servisni_delovi.go @@ -3,6 +3,7 @@ package sqlite import ( "context" "database/sql" + "errors" "fmt" "ntech/internal/model" @@ -76,18 +77,43 @@ func (r *ServisniDeloviRepo) Dodaj(ctx context.Context, nalogID, artikalID int64 return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: update stanje: %w", err) } - rezultat, err := tx.ExecContext(ctx, ` - INSERT INTO servisni_delovi (nalog_id, artikal_id, kolicina, cena_komada) - VALUES (?, ?, ?, ?)`, - nalogID, artikalID, kolicina, cenaKomada, - ) - if err != nil { - return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: insert: %w", err) - } + // ako isti artikal već postoji na nalogu — saberi količinu i osveži cenu; + // u suprotnom kreiraj novi red (bez dupliranja istog artikla) + var deoID int64 + var postojeciID int64 + var postojeciKol int + err = tx.QueryRowContext(ctx, + "SELECT id, kolicina FROM servisni_delovi WHERE nalog_id = ? AND artikal_id = ?", + nalogID, artikalID, + ).Scan(&postojeciID, &postojeciKol) - deoID, err := rezultat.LastInsertId() - if err != nil { - return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: last insert id: %w", err) + if err == nil { + // već postoji — saberi + novaKol := postojeciKol + kolicina + _, err = tx.ExecContext(ctx, + "UPDATE servisni_delovi SET kolicina = ?, cena_komada = ? WHERE id = ?", + novaKol, cenaKomada, postojeciID, + ) + if err != nil { + return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: merge update: %w", err) + } + deoID = postojeciID + } else if errors.Is(err, sql.ErrNoRows) { + // novi artikal na nalogu — insert + rezultat, err := tx.ExecContext(ctx, ` + INSERT INTO servisni_delovi (nalog_id, artikal_id, kolicina, cena_komada) + VALUES (?, ?, ?, ?)`, + nalogID, artikalID, kolicina, cenaKomada, + ) + if err != nil { + return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: insert: %w", err) + } + deoID, err = rezultat.LastInsertId() + if err != nil { + return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: last insert id: %w", err) + } + } else { + return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: proveri postojanje: %w", err) } err = zabeleziMagacinPromenu(ctx, tx, artikalID, model.PromenaIzlazServis, diff --git a/web/static/css/main.css b/web/static/css/main.css index 9088a7f..9f21fc6 100644 --- a/web/static/css/main.css +++ b/web/static/css/main.css @@ -1116,6 +1116,10 @@ select { .prekoraceno { border-color: #dc2626 !important; } #deo-umagacinu.prekoraceno { color: #dc2626; border-color: #dc2626; } +/* poravnanje „U magacinu" sa Artiklom i Kol. — svi inputi/selectovi imaju + height: 38px (main.css:728); div-u nedostaje eksplicitna visina */ +#deo-umagacinu { height: 38px; } + /* korisnikova preferencija animacije: body[data-animacija] nadjačava podrazumevano. Kad korisnik odabere stil, animiraju se i redovi tabela i mobilne kartice. */ [data-animacija="bez"] .animiraj, diff --git a/web/templates/stranice/servis_detalji.html b/web/templates/stranice/servis_detalji.html index 52b0b78..819136e 100644 --- a/web/templates/stranice/servis_detalji.html +++ b/web/templates/stranice/servis_detalji.html @@ -410,6 +410,20 @@ osveziPrekoracenje(); }); if (kol) kol.addEventListener('input', osveziPrekoracenje); + + // resetuj prikaz „U magacinu" nakon dodavanja dela — base.html poziva + // f.reset() posle AJAX osvežavanja tabele, ali .reset() ne dira
+ var formaDelovi = document.querySelector('form[action$="/delovi"]'); + if (formaDelovi) { + formaDelovi.addEventListener('reset', function () { + if (umagacinu) { + umagacinu.textContent = '—'; + umagacinu.classList.remove('prekoraceno'); + } + stanjeIzabrano = 0; + if (kol) kol.classList.remove('prekoraceno'); + }); + } })(); {{end}}