Popravka sidebara: kolaps, podmeni i HTMX navigacija
This commit is contained in:
@@ -25,7 +25,7 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod
|
||||
SELECT
|
||||
a.id, a.kategorija_id, a.naziv, a.opis,
|
||||
a.kolicina, a.kolicina_min, a.lokacija,
|
||||
a.prodajna_cena, a.napomena, a.datum_unosa,
|
||||
a.nabavna_cena, a.prodajna_cena, a.pdv_stopa, a.napomena, a.datum_unosa,
|
||||
COALESCE(k.naziv, '') as kategorija_naziv
|
||||
FROM artikli a
|
||||
LEFT JOIN kategorije k ON a.kategorija_id = k.id
|
||||
@@ -63,7 +63,7 @@ func (r *ArtikalRepo) Lista(ctx context.Context, filter db.ArtikalFilter) ([]mod
|
||||
err := redovi.Scan(
|
||||
&a.ID, &kategorijaID, &a.Naziv, &a.Opis,
|
||||
&a.Kolicina, &a.KolicinMin, &a.Lokacija,
|
||||
&a.ProdajnaCena, &a.Napomena, &a.DatumUnosa,
|
||||
&a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &a.Napomena, &a.DatumUnosa,
|
||||
&a.KategorijaNaziv,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -89,11 +89,11 @@ func (r *ArtikalRepo) DohvatiID(ctx context.Context, id int64) (*model.Artikal,
|
||||
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT id, kategorija_id, naziv, opis, kolicina, kolicina_min,
|
||||
lokacija, prodajna_cena, napomena, datum_unosa
|
||||
lokacija, nabavna_cena, prodajna_cena, pdv_stopa, napomena, datum_unosa
|
||||
FROM artikli WHERE id = ?`, id).Scan(
|
||||
&a.ID, &kategorijaID, &a.Naziv, &a.Opis,
|
||||
&a.Kolicina, &a.KolicinMin, &a.Lokacija,
|
||||
&a.ProdajnaCena, &a.Napomena, &a.DatumUnosa,
|
||||
&a.NabavnaCena, &a.ProdajnaCena, &a.PdvStopa, &a.Napomena, &a.DatumUnosa,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: ArtikalRepo.DohvatiID: %w", err)
|
||||
@@ -111,10 +111,10 @@ func (r *ArtikalRepo) Kreiraj(ctx context.Context, a *model.Artikal) (int64, err
|
||||
rezultat, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO artikli
|
||||
(kategorija_id, naziv, opis, kolicina, kolicina_min, lokacija,
|
||||
prodajna_cena, napomena)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
nabavna_cena, prodajna_cena, pdv_stopa, napomena)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
a.KategorijaID, a.Naziv, a.Opis, a.Kolicina, a.KolicinMin,
|
||||
a.Lokacija, a.ProdajnaCena, a.Napomena,
|
||||
a.Lokacija, a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Napomena,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ArtikalRepo.Kreiraj: %w", err)
|
||||
@@ -134,11 +134,11 @@ func (r *ArtikalRepo) Izmeni(ctx context.Context, a *model.Artikal) error {
|
||||
UPDATE artikli SET
|
||||
kategorija_id = ?, naziv = ?, opis = ?, kolicina = ?,
|
||||
kolicina_min = ?, lokacija = ?,
|
||||
prodajna_cena = ?, napomena = ?
|
||||
nabavna_cena = ?, prodajna_cena = ?, pdv_stopa = ?, napomena = ?
|
||||
WHERE id = ?`,
|
||||
a.KategorijaID, a.Naziv, a.Opis, a.Kolicina,
|
||||
a.KolicinMin, a.Lokacija,
|
||||
a.ProdajnaCena, a.Napomena, a.ID,
|
||||
a.NabavnaCena, a.ProdajnaCena, a.PdvStopa, a.Napomena, a.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ArtikalRepo.Izmeni: %w", err)
|
||||
|
||||
@@ -21,7 +21,7 @@ func NoviKlijentRepo(db *sql.DB) *KlijentRepo {
|
||||
// Lista vraća listu klijenata sa opcionom pretragom po imenu, prezimenu ili nazivu firme
|
||||
func (r *KlijentRepo) Lista(ctx context.Context, pretraga string) ([]model.Klijent, error) {
|
||||
upit := `
|
||||
SELECT id, ime, prezime, naziv_firme, pib, telefon, email, napomena, datum_unosa
|
||||
SELECT id, tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, napomena, datum_unosa
|
||||
FROM klijenti
|
||||
WHERE 1=1`
|
||||
|
||||
@@ -44,15 +44,16 @@ func (r *KlijentRepo) Lista(ctx context.Context, pretraga string) ([]model.Klije
|
||||
var rezultat []model.Klijent
|
||||
for redovi.Next() {
|
||||
var k model.Klijent
|
||||
var ime, prezime, nazivFirme, pib, telefon, email, napomena sql.NullString
|
||||
var ime, prezime, jmbg, nazivFirme, pib, telefon, email, napomena sql.NullString
|
||||
err := redovi.Scan(
|
||||
&k.ID, &ime, &prezime, &nazivFirme, &pib, &telefon, &email, &napomena, &k.DatumUnosa,
|
||||
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &nazivFirme, &pib, &telefon, &email, &napomena, &k.DatumUnosa,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: KlijentRepo.Lista: scan: %w", err)
|
||||
}
|
||||
k.Ime = ime.String
|
||||
k.Prezime = prezime.String
|
||||
k.JMBG = jmbg.String
|
||||
k.NazivFirme = nazivFirme.String
|
||||
k.PIB = pib.String
|
||||
k.Telefon = telefon.String
|
||||
@@ -67,12 +68,12 @@ func (r *KlijentRepo) Lista(ctx context.Context, pretraga string) ([]model.Klije
|
||||
// DohvatiID vraća jednog klijenta po ID-u
|
||||
func (r *KlijentRepo) DohvatiID(ctx context.Context, id int64) (*model.Klijent, error) {
|
||||
var k model.Klijent
|
||||
var ime, prezime, nazivFirme, pib, telefon, email, napomena sql.NullString
|
||||
var ime, prezime, jmbg, nazivFirme, pib, telefon, email, napomena sql.NullString
|
||||
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT id, ime, prezime, naziv_firme, pib, telefon, email, napomena, datum_unosa
|
||||
SELECT id, tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, napomena, datum_unosa
|
||||
FROM klijenti WHERE id = ?`, id).Scan(
|
||||
&k.ID, &ime, &prezime, &nazivFirme, &pib, &telefon, &email, &napomena, &k.DatumUnosa,
|
||||
&k.ID, &k.Tip, &ime, &prezime, &jmbg, &nazivFirme, &pib, &telefon, &email, &napomena, &k.DatumUnosa,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: KlijentRepo.DohvatiID: %w", err)
|
||||
@@ -80,6 +81,7 @@ func (r *KlijentRepo) DohvatiID(ctx context.Context, id int64) (*model.Klijent,
|
||||
|
||||
k.Ime = ime.String
|
||||
k.Prezime = prezime.String
|
||||
k.JMBG = jmbg.String
|
||||
k.NazivFirme = nazivFirme.String
|
||||
k.PIB = pib.String
|
||||
k.Telefon = telefon.String
|
||||
@@ -91,11 +93,15 @@ func (r *KlijentRepo) DohvatiID(ctx context.Context, id int64) (*model.Klijent,
|
||||
|
||||
// Kreiraj dodaje novog klijenta u bazu
|
||||
func (r *KlijentRepo) Kreiraj(ctx context.Context, k *model.Klijent) (int64, error) {
|
||||
if k.Tip == "" {
|
||||
k.Tip = "fizicko"
|
||||
}
|
||||
rezultat, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO klijenti (ime, prezime, naziv_firme, pib, telefon, email, napomena)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
nullString(k.Ime), nullString(k.Prezime), nullString(k.NazivFirme),
|
||||
nullString(k.PIB), nullString(k.Telefon), nullString(k.Email), nullString(k.Napomena),
|
||||
INSERT INTO klijenti (tip, ime, prezime, jmbg, naziv_firme, pib, telefon, email, napomena)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG),
|
||||
nullString(k.NazivFirme), nullString(k.PIB), nullString(k.Telefon),
|
||||
nullString(k.Email), nullString(k.Napomena),
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: KlijentRepo.Kreiraj: %w", err)
|
||||
@@ -111,13 +117,17 @@ func (r *KlijentRepo) Kreiraj(ctx context.Context, k *model.Klijent) (int64, err
|
||||
|
||||
// Izmeni ažurira postojećeg klijenta
|
||||
func (r *KlijentRepo) Izmeni(ctx context.Context, k *model.Klijent) error {
|
||||
if k.Tip == "" {
|
||||
k.Tip = "fizicko"
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE klijenti SET
|
||||
ime = ?, prezime = ?, naziv_firme = ?, pib = ?, telefon = ?, email = ?, napomena = ?
|
||||
tip = ?, ime = ?, prezime = ?, jmbg = ?, naziv_firme = ?,
|
||||
pib = ?, telefon = ?, email = ?, napomena = ?
|
||||
WHERE id = ?`,
|
||||
nullString(k.Ime), nullString(k.Prezime), nullString(k.NazivFirme),
|
||||
nullString(k.PIB), nullString(k.Telefon), nullString(k.Email), nullString(k.Napomena),
|
||||
k.ID,
|
||||
k.Tip, nullString(k.Ime), nullString(k.Prezime), nullString(k.JMBG),
|
||||
nullString(k.NazivFirme), nullString(k.PIB), nullString(k.Telefon),
|
||||
nullString(k.Email), nullString(k.Napomena), k.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: KlijentRepo.Izmeni: %w", err)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"ntech/internal/model"
|
||||
)
|
||||
|
||||
// MagacinskePromeneRepo je SQLite implementacija MagacinskePromeneRepository interfejsa
|
||||
type MagacinskePromeneRepo struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NoviMagacinskePromeneRepo kreira novi MagacinskePromeneRepo
|
||||
func NoviMagacinskePromeneRepo(db *sql.DB) *MagacinskePromeneRepo {
|
||||
return &MagacinskePromeneRepo{db: db}
|
||||
}
|
||||
|
||||
// Lista vraća listu magacinskih promena, opcionalno filtrirano po artiklu
|
||||
func (r *MagacinskePromeneRepo) Lista(ctx context.Context, artikalID *int64, limit int) ([]model.MagacinskaPromenaSaDetaljem, error) {
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
}
|
||||
|
||||
upit := `
|
||||
SELECT mp.id, mp.artikal_id, a.naziv, mp.tip_promene, mp.referentni_id,
|
||||
mp.promena_kolicine, mp.stanje_pre, mp.stanje_posle,
|
||||
mp.korisnik_id, mp.napomena, mp.datum
|
||||
FROM magacinske_promene mp
|
||||
JOIN artikli a ON a.id = mp.artikal_id
|
||||
WHERE 1=1`
|
||||
|
||||
args := []any{}
|
||||
|
||||
if artikalID != nil {
|
||||
upit += " AND mp.artikal_id = ?"
|
||||
args = append(args, *artikalID)
|
||||
}
|
||||
|
||||
upit += " ORDER BY mp.datum DESC LIMIT ?"
|
||||
args = append(args, limit)
|
||||
|
||||
redovi, err := r.db.QueryContext(ctx, upit, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: MagacinskePromeneRepo.Lista: %w", err)
|
||||
}
|
||||
defer redovi.Close()
|
||||
|
||||
var rezultat []model.MagacinskaPromenaSaDetaljem
|
||||
for redovi.Next() {
|
||||
var p model.MagacinskaPromenaSaDetaljem
|
||||
var korisnikID sql.NullInt64
|
||||
var napomena sql.NullString
|
||||
|
||||
err := redovi.Scan(
|
||||
&p.ID, &p.ArtikalID, &p.ArtikalNaziv, &p.TipPromene, &p.ReferentniID,
|
||||
&p.PromenaKolicine, &p.StanjePre, &p.StanjePosle,
|
||||
&korisnikID, &napomena, &p.Datum,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: MagacinskePromeneRepo.Lista: scan: %w", err)
|
||||
}
|
||||
|
||||
if korisnikID.Valid {
|
||||
v := korisnikID.Int64
|
||||
p.KorisnikID = &v
|
||||
}
|
||||
p.Napomena = napomena.String
|
||||
|
||||
rezultat = append(rezultat, p)
|
||||
}
|
||||
|
||||
return rezultat, nil
|
||||
}
|
||||
|
||||
// zabeleziMagacinPromenu je interni helper koji upisuje jednu promenu stanja artikla.
|
||||
// Poziva se iz Kreiraj/Storno unutar postojeće transakcije.
|
||||
func zabeleziMagacinPromenu(
|
||||
ctx context.Context,
|
||||
tx *sql.Tx,
|
||||
artikalID int64,
|
||||
tipPromene string,
|
||||
promenaKolicine, stanjePre, stanjePosle int,
|
||||
referentniID int64,
|
||||
korisnikID *int64,
|
||||
napomena string,
|
||||
) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO magacinske_promene
|
||||
(artikal_id, tip_promene, promena_kolicine, stanje_pre, stanje_posle,
|
||||
referentni_id, korisnik_id, napomena)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
artikalID, tipPromene, promenaKolicine, stanjePre, stanjePosle,
|
||||
referentniID, nullInt64(korisnikID), nullString(napomena),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: zabeleziMagacinPromenu: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -4,8 +4,10 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
@@ -82,7 +84,13 @@ func PokreniMigracije(db *sql.DB, fsys fs.FS) error {
|
||||
|
||||
// izvršavamo SQL
|
||||
if _, err := db.Exec(string(sadrzaj)); err != nil {
|
||||
return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err)
|
||||
// "duplicate column name" znači da kolona već postoji — željeno stanje je ispunjeno,
|
||||
// pa nastavljamo i beležimo migraciju kao izvršenu
|
||||
if strings.Contains(err.Error(), "duplicate column name") {
|
||||
log.Printf("Upozorenje: migration %s: kolona već postoji, preskačemo", naziv)
|
||||
} else {
|
||||
return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err)
|
||||
}
|
||||
}
|
||||
|
||||
// upisujemo u tabelu migracija da je izvršena
|
||||
|
||||
+178
-64
@@ -41,7 +41,8 @@ func (r *ProdajaRepo) SledeciBroj(ctx context.Context) (string, error) {
|
||||
func (r *ProdajaRepo) Lista(ctx context.Context, pretraga string) ([]model.ProdajniNalogSaDetaljem, error) {
|
||||
upit := `
|
||||
SELECT
|
||||
pn.id, pn.klijent_id, pn.broj_naloga, pn.napomena, pn.ukupno, pn.datum,
|
||||
pn.id, pn.klijent_id, pn.broj_naloga, pn.napomena, pn.ukupno,
|
||||
pn.nacin_placanja, pn.stornirano, pn.datum,
|
||||
COALESCE(NULLIF(k.naziv_firme, ''), TRIM(COALESCE(k.ime, '') || ' ' || COALESCE(k.prezime, '')), '') AS klijent_naziv
|
||||
FROM prodajni_nalozi pn
|
||||
LEFT JOIN klijenti k ON k.id = pn.klijent_id
|
||||
@@ -69,7 +70,8 @@ func (r *ProdajaRepo) Lista(ctx context.Context, pretraga string) ([]model.Proda
|
||||
var napomena sql.NullString
|
||||
|
||||
err := redovi.Scan(
|
||||
&n.ID, &klijentID, &n.BrojNaloga, &napomena, &n.Ukupno, &n.Datum,
|
||||
&n.ID, &klijentID, &n.BrojNaloga, &napomena, &n.Ukupno,
|
||||
&n.NacinPlacanja, &n.Stornirano, &n.Datum,
|
||||
&n.KlijentNaziv,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -91,14 +93,18 @@ func (r *ProdajaRepo) Lista(ctx context.Context, pretraga string) ([]model.Proda
|
||||
// DohvatiID vraća jedan prodajni nalog po ID-u
|
||||
func (r *ProdajaRepo) DohvatiID(ctx context.Context, id int64) (*model.ProdajniNalog, error) {
|
||||
red := r.db.QueryRowContext(ctx, `
|
||||
SELECT id, klijent_id, broj_naloga, napomena, ukupno, datum
|
||||
SELECT id, klijent_id, broj_naloga, napomena, ukupno,
|
||||
nacin_placanja, stornirano, razlog_storniranja, datum
|
||||
FROM prodajni_nalozi WHERE id = ?`, id)
|
||||
|
||||
var n model.ProdajniNalog
|
||||
var klijentID sql.NullInt64
|
||||
var napomena sql.NullString
|
||||
var napomena, razlogStorniranja sql.NullString
|
||||
|
||||
err := red.Scan(&n.ID, &klijentID, &n.BrojNaloga, &napomena, &n.Ukupno, &n.Datum)
|
||||
err := red.Scan(
|
||||
&n.ID, &klijentID, &n.BrojNaloga, &napomena, &n.Ukupno,
|
||||
&n.NacinPlacanja, &n.Stornirano, &razlogStorniranja, &n.Datum,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: ProdajaRepo.DohvatiID: %w", err)
|
||||
}
|
||||
@@ -108,15 +114,16 @@ func (r *ProdajaRepo) DohvatiID(ctx context.Context, id int64) (*model.ProdajniN
|
||||
n.KlijentID = &v
|
||||
}
|
||||
n.Napomena = napomena.String
|
||||
n.RazlogStorniranja = razlogStorniranja.String
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
// DohvatiStavke vraća stavke prodaje sa nazivima artikala za dati nalog
|
||||
// DohvatiStavke vraća stavke prodaje sa nazivima artikala i PDV podacima za dati nalog
|
||||
func (r *ProdajaRepo) DohvatiStavke(ctx context.Context, nalogID int64) ([]model.StavkaProdajeSaArtiklom, error) {
|
||||
redovi, err := r.db.QueryContext(ctx, `
|
||||
SELECT sp.id, sp.nalog_id, sp.artikal_id, sp.kolicina, sp.cena_po_komadu, sp.ukupno,
|
||||
a.naziv
|
||||
sp.pdv_stopa, sp.pdv_iznos, sp.cena_bez_pdv, a.naziv
|
||||
FROM stavke_prodaje sp
|
||||
JOIN artikli a ON a.id = sp.artikal_id
|
||||
WHERE sp.nalog_id = ?
|
||||
@@ -131,7 +138,9 @@ func (r *ProdajaRepo) DohvatiStavke(ctx context.Context, nalogID int64) ([]model
|
||||
var s model.StavkaProdajeSaArtiklom
|
||||
err := redovi.Scan(
|
||||
&s.ID, &s.NalogID, &s.ArtikalID, &s.Kolicina,
|
||||
&s.CenaPoKomadu, &s.Ukupno, &s.ArtikalNaziv,
|
||||
&s.CenaPoKomadu, &s.Ukupno,
|
||||
&s.PdvStopa, &s.PdvIznos, &s.CenaBezPdv,
|
||||
&s.ArtikalNaziv,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: ProdajaRepo.DohvatiStavke: scan: %w", err)
|
||||
@@ -143,44 +152,24 @@ func (r *ProdajaRepo) DohvatiStavke(ctx context.Context, nalogID int64) ([]model
|
||||
}
|
||||
|
||||
// Kreiraj upisuje novi prodajni nalog u bazu u okviru jedne transakcije.
|
||||
// Za svaku stavku proverava stanje u magacinu i smanjuje ga.
|
||||
// Za svaku stavku proverava stanje u magacinu, smanjuje ga i beleži promenu.
|
||||
// Ako bilo koji artikal nema dovoljno stanja, vraća ErrNedovoljnoKolicine.
|
||||
func (r *ProdajaRepo) Kreiraj(ctx context.Context, n *model.ProdajniNalog, stavke []model.StavkaProdaje) (int64, error) {
|
||||
func (r *ProdajaRepo) Kreiraj(ctx context.Context, n *model.ProdajniNalog, stavke []model.StavkaProdaje, korisnikID *int64) (int64, error) {
|
||||
if n.NacinPlacanja == "" {
|
||||
n.NacinPlacanja = "gotovina"
|
||||
}
|
||||
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// provera i smanjenje stanja za svaku stavku
|
||||
for _, s := range stavke {
|
||||
var naziv string
|
||||
var kolicinaNaStanju int
|
||||
err := tx.QueryRowContext(ctx,
|
||||
"SELECT naziv, kolicina FROM artikli WHERE id = ?", s.ArtikalID,
|
||||
).Scan(&naziv, &kolicinaNaStanju)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: dohvati artikal: %w", err)
|
||||
}
|
||||
|
||||
if kolicinaNaStanju < s.Kolicina {
|
||||
return 0, &db.ErrNedovoljnoKolicine{ArtikalNaziv: naziv}
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = kolicina - ? WHERE id = ?",
|
||||
s.Kolicina, s.ArtikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: update stanje: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// insert zaglavlja naloga
|
||||
// insert zaglavlja naloga pre stavki da bismo imali nalogID za magacin
|
||||
rezultat, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO prodajni_nalozi (klijent_id, broj_naloga, napomena, ukupno, datum)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
nullInt64(n.KlijentID), n.BrojNaloga, nullString(n.Napomena), n.Ukupno, n.Datum,
|
||||
INSERT INTO prodajni_nalozi (klijent_id, broj_naloga, napomena, ukupno, nacin_placanja, datum)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
nullInt64(n.KlijentID), n.BrojNaloga, nullString(n.Napomena), n.Ukupno, n.NacinPlacanja, n.Datum,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: insert nalog: %w", err)
|
||||
@@ -191,17 +180,54 @@ func (r *ProdajaRepo) Kreiraj(ctx context.Context, n *model.ProdajniNalog, stavk
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: last insert id: %w", err)
|
||||
}
|
||||
|
||||
// insert stavki
|
||||
// provera stanja, smanjenje i insert stavki
|
||||
for _, s := range stavke {
|
||||
var naziv string
|
||||
var stanjePre int
|
||||
err := tx.QueryRowContext(ctx,
|
||||
"SELECT naziv, kolicina FROM artikli WHERE id = ?", s.ArtikalID,
|
||||
).Scan(&naziv, &stanjePre)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: dohvati artikal: %w", err)
|
||||
}
|
||||
|
||||
if stanjePre < s.Kolicina {
|
||||
return 0, &db.ErrNedovoljnoKolicine{ArtikalNaziv: naziv}
|
||||
}
|
||||
|
||||
stanjePosle := stanjePre - s.Kolicina
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?", stanjePosle, s.ArtikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: update stanje: %w", err)
|
||||
}
|
||||
|
||||
// PDV računamo iz cene ako nije eksplicitno postavljeno
|
||||
cenaBezPdv := s.CenaBezPdv
|
||||
pdvIznos := s.PdvIznos
|
||||
if cenaBezPdv == 0 && s.PdvStopa > 0 {
|
||||
cenaBezPdv = s.CenaPoKomadu / (1 + s.PdvStopa/100)
|
||||
pdvIznos = s.CenaPoKomadu - cenaBezPdv
|
||||
}
|
||||
|
||||
ukupnoStavke := float64(s.Kolicina) * s.CenaPoKomadu
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO stavke_prodaje (nalog_id, artikal_id, kolicina, cena_po_komadu, ukupno)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO stavke_prodaje
|
||||
(nalog_id, artikal_id, kolicina, cena_po_komadu, ukupno, pdv_stopa, pdv_iznos, cena_bez_pdv)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
nalogID, s.ArtikalID, s.Kolicina, s.CenaPoKomadu, ukupnoStavke,
|
||||
s.PdvStopa, pdvIznos, cenaBezPdv,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: insert stavka: %w", err)
|
||||
}
|
||||
|
||||
err = zabeleziMagacinPromenu(ctx, tx, s.ArtikalID, model.PromenaIzlazProdaja,
|
||||
-s.Kolicina, stanjePre, stanjePosle, nalogID, korisnikID, "")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ProdajaRepo.Kreiraj: magacin: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
@@ -211,6 +237,83 @@ func (r *ProdajaRepo) Kreiraj(ctx context.Context, n *model.ProdajniNalog, stavk
|
||||
return nalogID, nil
|
||||
}
|
||||
|
||||
// Storno označava prodajni nalog kao storniran i vraća sve artikle na stanje
|
||||
func (r *ProdajaRepo) Storno(ctx context.Context, id int64, razlog string, korisnikID *int64) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// proverava da li je već storniran
|
||||
var stornirano bool
|
||||
err = tx.QueryRowContext(ctx, "SELECT stornirano FROM prodajni_nalozi WHERE id = ?", id).Scan(&stornirano)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: provera: %w", err)
|
||||
}
|
||||
if stornirano {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: nalog je već storniran")
|
||||
}
|
||||
|
||||
// vraćanje stanja u magacin
|
||||
redovi, err := tx.QueryContext(ctx,
|
||||
"SELECT artikal_id, kolicina FROM stavke_prodaje WHERE nalog_id = ?", id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: dohvati stavke: %w", err)
|
||||
}
|
||||
|
||||
type stavkaPovrat struct {
|
||||
artikalID int64
|
||||
kolicina int
|
||||
}
|
||||
var stavke []stavkaPovrat
|
||||
for redovi.Next() {
|
||||
var p stavkaPovrat
|
||||
if err := redovi.Scan(&p.artikalID, &p.kolicina); err != nil {
|
||||
redovi.Close()
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: scan stavke: %w", err)
|
||||
}
|
||||
stavke = append(stavke, p)
|
||||
}
|
||||
redovi.Close()
|
||||
|
||||
for _, p := range stavke {
|
||||
var stanjePre int
|
||||
err := tx.QueryRowContext(ctx, "SELECT kolicina FROM artikli WHERE id = ?", p.artikalID).Scan(&stanjePre)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: dohvati stanje: %w", err)
|
||||
}
|
||||
|
||||
stanjePosle := stanjePre + p.kolicina
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?", stanjePosle, p.artikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: vrati stanje: %w", err)
|
||||
}
|
||||
|
||||
err = zabeleziMagacinPromenu(ctx, tx, p.artikalID, model.PromenaPovracaj,
|
||||
p.kolicina, stanjePre, stanjePosle, id, korisnikID, razlog)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: magacin: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE prodajni_nalozi SET stornirano = 1, razlog_storniranja = ? WHERE id = ?",
|
||||
nullString(razlog), id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: update nalog: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Storno: commit: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Obrisi briše prodajni nalog i vraća količine artikala na stanje (u transakciji)
|
||||
func (r *ProdajaRepo) Obrisi(ctx context.Context, id int64) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
@@ -219,32 +322,43 @@ func (r *ProdajaRepo) Obrisi(ctx context.Context, id int64) error {
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// vraćanje stanja u magacin
|
||||
redovi, err := tx.QueryContext(ctx,
|
||||
"SELECT artikal_id, kolicina FROM stavke_prodaje WHERE nalog_id = ?", id)
|
||||
// vraćanje stanja u magacin samo ako nalog nije storniran (storno je već vratio)
|
||||
var stornirano bool
|
||||
err = tx.QueryRowContext(ctx, "SELECT stornirano FROM prodajni_nalozi WHERE id = ?", id).Scan(&stornirano)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: dohvati stavke: %w", err)
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: provera: %w", err)
|
||||
}
|
||||
|
||||
type povrat struct{ artikalID int64; kolicina int }
|
||||
var stavke []povrat
|
||||
for redovi.Next() {
|
||||
var p povrat
|
||||
if err := redovi.Scan(&p.artikalID, &p.kolicina); err != nil {
|
||||
redovi.Close()
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: scan stavke: %w", err)
|
||||
}
|
||||
stavke = append(stavke, p)
|
||||
}
|
||||
redovi.Close()
|
||||
|
||||
for _, p := range stavke {
|
||||
_, err := tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = kolicina + ? WHERE id = ?",
|
||||
p.kolicina, p.artikalID,
|
||||
)
|
||||
if !stornirano {
|
||||
redovi, err := tx.QueryContext(ctx,
|
||||
"SELECT artikal_id, kolicina FROM stavke_prodaje WHERE nalog_id = ?", id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: vrati stanje: %w", err)
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: dohvati stavke: %w", err)
|
||||
}
|
||||
|
||||
type povrat struct {
|
||||
artikalID int64
|
||||
kolicina int
|
||||
}
|
||||
var stavke []povrat
|
||||
for redovi.Next() {
|
||||
var p povrat
|
||||
if err := redovi.Scan(&p.artikalID, &p.kolicina); err != nil {
|
||||
redovi.Close()
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: scan stavke: %w", err)
|
||||
}
|
||||
stavke = append(stavke, p)
|
||||
}
|
||||
redovi.Close()
|
||||
|
||||
for _, p := range stavke {
|
||||
_, err := tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = kolicina + ? WHERE id = ?",
|
||||
p.kolicina, p.artikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ProdajaRepo.Obrisi: vrati stanje: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ func (r *ServisRepo) SledeciBroj(ctx context.Context) (string, error) {
|
||||
func (r *ServisRepo) Lista(ctx context.Context, pretraga, status string) ([]model.ServisniNalogSaKlijentom, error) {
|
||||
upit := `
|
||||
SELECT
|
||||
sn.id, sn.klijent_id, sn.broj_naloga, sn.uredjaj, sn.serijski_broj,
|
||||
sn.id, sn.klijent_id, sn.tehnicar_id, sn.broj_naloga, sn.uredjaj, sn.serijski_broj,
|
||||
sn.opis_kvara, sn.status, sn.cena_od, sn.cena_do, sn.cena_konacna,
|
||||
sn.avans, sn.napomena, sn.datum_prijema, sn.datum_zavrsetka,
|
||||
sn.avans, sn.napomena, sn.garancija_do, sn.datum_prijema, sn.datum_zavrsetka,
|
||||
COALESCE(NULLIF(k.naziv_firme, ''), TRIM(COALESCE(k.ime, '') || ' ' || COALESCE(k.prezime, '')), '') AS klijent_naziv
|
||||
FROM servisni_nalozi sn
|
||||
LEFT JOIN klijenti k ON k.id = sn.klijent_id
|
||||
@@ -86,9 +86,9 @@ func (r *ServisRepo) Lista(ctx context.Context, pretraga, status string) ([]mode
|
||||
func (r *ServisRepo) DohvatiID(ctx context.Context, id int64) (*model.ServisniNalog, error) {
|
||||
red := r.db.QueryRowContext(ctx, `
|
||||
SELECT
|
||||
id, klijent_id, broj_naloga, uredjaj, serijski_broj,
|
||||
id, klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj,
|
||||
opis_kvara, status, cena_od, cena_do, cena_konacna,
|
||||
avans, napomena, datum_prijema, datum_zavrsetka
|
||||
avans, napomena, garancija_do, datum_prijema, datum_zavrsetka
|
||||
FROM servisni_nalozi WHERE id = ?`, id)
|
||||
|
||||
var n model.ServisniNalog
|
||||
@@ -104,13 +104,14 @@ func (r *ServisRepo) DohvatiID(ctx context.Context, id int64) (*model.ServisniNa
|
||||
func (r *ServisRepo) Kreiraj(ctx context.Context, n *model.ServisniNalog) (int64, error) {
|
||||
rezultat, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO servisni_nalozi
|
||||
(klijent_id, broj_naloga, uredjaj, serijski_broj, opis_kvara,
|
||||
status, cena_od, cena_do, cena_konacna, avans, napomena, datum_zavrsetka)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
nullInt64(n.KlijentID), n.BrojNaloga, n.Uredjaj, nullString(n.SerijskiBroj),
|
||||
n.OpisKvara, n.Status, nullFloat64(n.CenaOd), nullFloat64(n.CenaDo),
|
||||
nullFloat64(n.CenaKonacna), nullFloat64(n.Avans), nullString(n.Napomena),
|
||||
nullTime(n.DatumZavrsetka),
|
||||
(klijent_id, tehnicar_id, broj_naloga, uredjaj, serijski_broj, opis_kvara,
|
||||
status, cena_od, cena_do, cena_konacna, avans, napomena, garancija_do, datum_zavrsetka)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
nullInt64(n.KlijentID), nullInt64(n.TehnicarID), n.BrojNaloga, n.Uredjaj,
|
||||
nullString(n.SerijskiBroj), n.OpisKvara, n.Status,
|
||||
nullFloat64(n.CenaOd), nullFloat64(n.CenaDo), nullFloat64(n.CenaKonacna),
|
||||
nullFloat64(n.Avans), nullString(n.Napomena),
|
||||
nullTime(n.GarancijaDo), nullTime(n.DatumZavrsetka),
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisRepo.Kreiraj: %w", err)
|
||||
@@ -128,13 +129,13 @@ func (r *ServisRepo) Kreiraj(ctx context.Context, n *model.ServisniNalog) (int64
|
||||
func (r *ServisRepo) Izmeni(ctx context.Context, n *model.ServisniNalog) error {
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE servisni_nalozi SET
|
||||
klijent_id = ?, uredjaj = ?, serijski_broj = ?, opis_kvara = ?,
|
||||
klijent_id = ?, tehnicar_id = ?, uredjaj = ?, serijski_broj = ?, opis_kvara = ?,
|
||||
status = ?, cena_od = ?, cena_do = ?, cena_konacna = ?,
|
||||
avans = ?, napomena = ?, datum_zavrsetka = ?
|
||||
avans = ?, napomena = ?, garancija_do = ?, datum_zavrsetka = ?
|
||||
WHERE id = ?`,
|
||||
nullInt64(n.KlijentID), n.Uredjaj, nullString(n.SerijskiBroj), n.OpisKvara,
|
||||
nullInt64(n.KlijentID), nullInt64(n.TehnicarID), n.Uredjaj, nullString(n.SerijskiBroj), n.OpisKvara,
|
||||
n.Status, nullFloat64(n.CenaOd), nullFloat64(n.CenaDo), nullFloat64(n.CenaKonacna),
|
||||
nullFloat64(n.Avans), nullString(n.Napomena), nullTime(n.DatumZavrsetka),
|
||||
nullFloat64(n.Avans), nullString(n.Napomena), nullTime(n.GarancijaDo), nullTime(n.DatumZavrsetka),
|
||||
n.ID,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -157,15 +158,15 @@ func (r *ServisRepo) Obrisi(ctx context.Context, id int64) error {
|
||||
// scanNalog čita redove iz upita u ServisniNalog struct —
|
||||
// klijentNaziv je opcioni pokazivač, nil kada se čita bez JOIN-a
|
||||
func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *string) error {
|
||||
var klijentID sql.NullInt64
|
||||
var klijentID, tehnicarID sql.NullInt64
|
||||
var serijskiBroj, napomena sql.NullString
|
||||
var cenaOd, cenaDo, cenaKonacna, avans sql.NullFloat64
|
||||
var datumZavrsetka sql.NullTime
|
||||
var garancijaDo, datumZavrsetka sql.NullTime
|
||||
|
||||
args := []any{
|
||||
&n.ID, &klijentID, &n.BrojNaloga, &n.Uredjaj, &serijskiBroj,
|
||||
&n.ID, &klijentID, &tehnicarID, &n.BrojNaloga, &n.Uredjaj, &serijskiBroj,
|
||||
&n.OpisKvara, &n.Status, &cenaOd, &cenaDo, &cenaKonacna,
|
||||
&avans, &napomena, &n.DatumPrijema, &datumZavrsetka,
|
||||
&avans, &napomena, &garancijaDo, &n.DatumPrijema, &datumZavrsetka,
|
||||
}
|
||||
|
||||
if klijentNaziv != nil {
|
||||
@@ -180,6 +181,10 @@ func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *st
|
||||
v := klijentID.Int64
|
||||
n.KlijentID = &v
|
||||
}
|
||||
if tehnicarID.Valid {
|
||||
v := tehnicarID.Int64
|
||||
n.TehnicarID = &v
|
||||
}
|
||||
n.SerijskiBroj = serijskiBroj.String
|
||||
n.Napomena = napomena.String
|
||||
if cenaOd.Valid {
|
||||
@@ -198,6 +203,10 @@ func scanNalog(scan func(...any) error, n *model.ServisniNalog, klijentNaziv *st
|
||||
v := avans.Float64
|
||||
n.Avans = &v
|
||||
}
|
||||
if garancijaDo.Valid {
|
||||
v := garancijaDo.Time
|
||||
n.GarancijaDo = &v
|
||||
}
|
||||
if datumZavrsetka.Valid {
|
||||
v := datumZavrsetka.Time
|
||||
n.DatumZavrsetka = &v
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"ntech/internal/db"
|
||||
"ntech/internal/model"
|
||||
)
|
||||
|
||||
// ServisniDeloviRepo je SQLite implementacija ServisniDeloviRepository interfejsa
|
||||
type ServisniDeloviRepo struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NoviServisniDeloviRepo kreira novi ServisniDeloviRepo
|
||||
func NoviServisniDeloviRepo(db *sql.DB) *ServisniDeloviRepo {
|
||||
return &ServisniDeloviRepo{db: db}
|
||||
}
|
||||
|
||||
// DohvatiZaNalog vraća sve ugrađene delove za dati servisni nalog
|
||||
func (r *ServisniDeloviRepo) DohvatiZaNalog(ctx context.Context, nalogID int64) ([]model.ServisniDeoSaArtiklom, error) {
|
||||
redovi, err := r.db.QueryContext(ctx, `
|
||||
SELECT sd.id, sd.nalog_id, sd.artikal_id, sd.kolicina, sd.cena_komada, sd.datum,
|
||||
a.naziv
|
||||
FROM servisni_delovi sd
|
||||
JOIN artikli a ON a.id = sd.artikal_id
|
||||
WHERE sd.nalog_id = ?
|
||||
ORDER BY sd.datum`, nalogID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: ServisniDeloviRepo.DohvatiZaNalog: %w", err)
|
||||
}
|
||||
defer redovi.Close()
|
||||
|
||||
var rezultat []model.ServisniDeoSaArtiklom
|
||||
for redovi.Next() {
|
||||
var d model.ServisniDeoSaArtiklom
|
||||
err := redovi.Scan(
|
||||
&d.ID, &d.NalogID, &d.ArtikalID, &d.Kolicina, &d.CenaKomada, &d.Datum,
|
||||
&d.ArtikalNaziv,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ntech: ServisniDeloviRepo.DohvatiZaNalog: scan: %w", err)
|
||||
}
|
||||
rezultat = append(rezultat, d)
|
||||
}
|
||||
|
||||
return rezultat, nil
|
||||
}
|
||||
|
||||
// Dodaj dodaje jedan artikal u servisni nalog, smanjuje stanje u magacinu i beleži promenu
|
||||
func (r *ServisniDeloviRepo) Dodaj(ctx context.Context, nalogID, artikalID int64, kolicina int, cenaKomada float64, korisnikID *int64) (int64, error) {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
var naziv string
|
||||
var stanjePre int
|
||||
err = tx.QueryRowContext(ctx,
|
||||
"SELECT naziv, kolicina FROM artikli WHERE id = ?", artikalID,
|
||||
).Scan(&naziv, &stanjePre)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: dohvati artikal: %w", err)
|
||||
}
|
||||
|
||||
if stanjePre < kolicina {
|
||||
return 0, &db.ErrNedovoljnoKolicine{ArtikalNaziv: naziv}
|
||||
}
|
||||
|
||||
stanjePosle := stanjePre - kolicina
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?", stanjePosle, artikalID,
|
||||
)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
deoID, err := rezultat.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: last insert id: %w", err)
|
||||
}
|
||||
|
||||
err = zabeleziMagacinPromenu(ctx, tx, artikalID, model.PromenaIzlazServis,
|
||||
-kolicina, stanjePre, stanjePosle, nalogID, korisnikID, "")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: magacin: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, fmt.Errorf("ntech: ServisniDeloviRepo.Dodaj: commit: %w", err)
|
||||
}
|
||||
|
||||
return deoID, nil
|
||||
}
|
||||
|
||||
// Obrisi uklanja servisni deo i vraća količinu na stanje u magacinu
|
||||
func (r *ServisniDeloviRepo) Obrisi(ctx context.Context, id int64, korisnikID *int64) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
var artikalID int64
|
||||
var nalogID int64
|
||||
var kolicina int
|
||||
err = tx.QueryRowContext(ctx,
|
||||
"SELECT artikal_id, nalog_id, kolicina FROM servisni_delovi WHERE id = ?", id,
|
||||
).Scan(&artikalID, &nalogID, &kolicina)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: dohvati deo: %w", err)
|
||||
}
|
||||
|
||||
var stanjePre int
|
||||
err = tx.QueryRowContext(ctx,
|
||||
"SELECT kolicina FROM artikli WHERE id = ?", artikalID,
|
||||
).Scan(&stanjePre)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: dohvati stanje: %w", err)
|
||||
}
|
||||
|
||||
stanjePosle := stanjePre + kolicina
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"UPDATE artikli SET kolicina = ? WHERE id = ?", stanjePosle, artikalID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: vrati stanje: %w", err)
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, "DELETE FROM servisni_delovi WHERE id = ?", id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: delete: %w", err)
|
||||
}
|
||||
|
||||
err = zabeleziMagacinPromenu(ctx, tx, artikalID, model.PromenaPovracaj,
|
||||
kolicina, stanjePre, stanjePosle, nalogID, korisnikID, "uklonjen servisni deo")
|
||||
if err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: magacin: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("ntech: ServisniDeloviRepo.Obrisi: commit: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user