Servis delovi: merge istog artikla, poravnanje, reset magacina

Dodaj: isti artikal na istom nalogu sabira kolicinu (bez duplikata). CSS: #deo-umagacinu height 38px — poravnat sa inputima. JS: reset event vraca U magacinu na — nakon dodavanja.
This commit is contained in:
2026-06-22 02:29:07 +02:00
parent 110b3e87eb
commit a66b49958c
3 changed files with 55 additions and 11 deletions
+37 -11
View File
@@ -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,
+4
View File
@@ -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,
@@ -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 <div>
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');
});
}
})();
</script>
{{end}}