package handlers import ( "net/http" "github.com/jmoiron/sqlx" "workorders/internal/model" ) type RegistryHandler struct{ db *sqlx.DB } func NewRegistryHandler(db *sqlx.DB) *RegistryHandler { return &RegistryHandler{db: db} } // ── People ──────────────────────────────────────────────────────────────────── func (h *RegistryHandler) ListPeople(w http.ResponseWriter, r *http.Request) { search := r.URL.Query().Get("search") all := r.URL.Query().Get("all") == "1" var rows []model.RegistryPerson var err error pat := "%" + search + "%" if all && search != "" { err = h.db.Select(&rows, `SELECT id,name,role,email,phone,active FROM resource_people WHERE (name LIKE @p1 OR email LIKE @p1 OR role LIKE @p1) ORDER BY name`, pat) } else if all { err = h.db.Select(&rows, `SELECT id,name,role,email,phone,active FROM resource_people ORDER BY name`) } else if search != "" { err = h.db.Select(&rows, `SELECT id,name,role,email,phone,active FROM resource_people WHERE active=1 AND (name LIKE @p1 OR email LIKE @p1 OR role LIKE @p1) ORDER BY name`, pat) } else { err = h.db.Select(&rows, `SELECT id,name,role,email,phone,active FROM resource_people WHERE active=1 ORDER BY name`) } if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } if rows == nil { rows = []model.RegistryPerson{} } respond(w, http.StatusOK, rows) } func (h *RegistryHandler) CreatePerson(w http.ResponseWriter, r *http.Request) { var body model.RegistryPerson if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } var id int err := h.db.QueryRow(`INSERT INTO resource_people (name,role,email,phone) OUTPUT INSERTED.id VALUES (@p1,@p2,@p3,@p4)`, body.Name, body.Role, body.Email, body.Phone).Scan(&id) if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } var person model.RegistryPerson h.db.Get(&person, `SELECT id,name,role,email,phone,active FROM resource_people WHERE id=@p1`, id) respond(w, http.StatusCreated, person) } func (h *RegistryHandler) UpdatePerson(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } var body model.RegistryPerson if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } h.db.Exec(`UPDATE resource_people SET name=@p1,role=@p2,email=@p3,phone=@p4,active=@p5 WHERE id=@p6`, body.Name, body.Role, body.Email, body.Phone, body.Active, id) var person model.RegistryPerson h.db.Get(&person, `SELECT id,name,role,email,phone,active FROM resource_people WHERE id=@p1`, id) respond(w, http.StatusOK, person) } func (h *RegistryHandler) DeletePerson(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } h.db.Exec(`UPDATE resource_people SET active=0 WHERE id=@p1`, id) respond(w, http.StatusOK, map[string]any{"deactivated": id}) } // ── Vehicles ────────────────────────────────────────────────────────────────── func (h *RegistryHandler) ListVehicles(w http.ResponseWriter, r *http.Request) { search := r.URL.Query().Get("search") all := r.URL.Query().Get("all") == "1" var rows []model.RegistryVehicle var err error pat := "%" + search + "%" if all && search != "" { err = h.db.Select(&rows, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles WHERE (unit_number LIKE @p1 OR description LIKE @p1 OR vehicle_type LIKE @p1) ORDER BY unit_number`, pat) } else if all { err = h.db.Select(&rows, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles ORDER BY unit_number`) } else if search != "" { err = h.db.Select(&rows, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles WHERE active=1 AND (unit_number LIKE @p1 OR description LIKE @p1) ORDER BY unit_number`, pat) } else { err = h.db.Select(&rows, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles WHERE active=1 ORDER BY unit_number`) } if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } if rows == nil { rows = []model.RegistryVehicle{} } respond(w, http.StatusOK, rows) } func (h *RegistryHandler) CreateVehicle(w http.ResponseWriter, r *http.Request) { var body model.RegistryVehicle if err := decode(r, &body); err != nil || body.UnitNumber == "" { respondError(w, http.StatusBadRequest, "unit_number required") return } var id int err := h.db.QueryRow(`INSERT INTO resource_vehicles (unit_number,description,vehicle_type) OUTPUT INSERTED.id VALUES (@p1,@p2,@p3)`, body.UnitNumber, body.Description, body.VehicleType).Scan(&id) if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } var v model.RegistryVehicle h.db.Get(&v, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles WHERE id=@p1`, id) respond(w, http.StatusCreated, v) } func (h *RegistryHandler) UpdateVehicle(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } var body model.RegistryVehicle if err := decode(r, &body); err != nil || body.UnitNumber == "" { respondError(w, http.StatusBadRequest, "unit_number required") return } h.db.Exec(`UPDATE resource_vehicles SET unit_number=@p1,description=@p2,vehicle_type=@p3,active=@p4 WHERE id=@p5`, body.UnitNumber, body.Description, body.VehicleType, body.Active, id) var v model.RegistryVehicle h.db.Get(&v, `SELECT id,unit_number,description,vehicle_type,active FROM resource_vehicles WHERE id=@p1`, id) respond(w, http.StatusOK, v) } func (h *RegistryHandler) DeleteVehicle(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } h.db.Exec(`UPDATE resource_vehicles SET active=0 WHERE id=@p1`, id) respond(w, http.StatusOK, map[string]any{"deactivated": id}) } // ── Equipment ───────────────────────────────────────────────────────────────── func (h *RegistryHandler) ListEquipment(w http.ResponseWriter, r *http.Request) { search := r.URL.Query().Get("search") all := r.URL.Query().Get("all") == "1" var rows []model.RegistryEquipment var err error pat := "%" + search + "%" if all && search != "" { err = h.db.Select(&rows, `SELECT id,name,asset_tag,category,active FROM resource_equipment WHERE (name LIKE @p1 OR asset_tag LIKE @p1 OR category LIKE @p1) ORDER BY name`, pat) } else if all { err = h.db.Select(&rows, `SELECT id,name,asset_tag,category,active FROM resource_equipment ORDER BY name`) } else if search != "" { err = h.db.Select(&rows, `SELECT id,name,asset_tag,category,active FROM resource_equipment WHERE active=1 AND (name LIKE @p1 OR asset_tag LIKE @p1) ORDER BY name`, pat) } else { err = h.db.Select(&rows, `SELECT id,name,asset_tag,category,active FROM resource_equipment WHERE active=1 ORDER BY name`) } if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } if rows == nil { rows = []model.RegistryEquipment{} } respond(w, http.StatusOK, rows) } func (h *RegistryHandler) CreateEquipment(w http.ResponseWriter, r *http.Request) { var body model.RegistryEquipment if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } var id int err := h.db.QueryRow(`INSERT INTO resource_equipment (name,asset_tag,category) OUTPUT INSERTED.id VALUES (@p1,@p2,@p3)`, body.Name, body.AssetTag, body.Category).Scan(&id) if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } var eq model.RegistryEquipment h.db.Get(&eq, `SELECT id,name,asset_tag,category,active FROM resource_equipment WHERE id=@p1`, id) respond(w, http.StatusCreated, eq) } func (h *RegistryHandler) UpdateEquipment(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } var body model.RegistryEquipment if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } h.db.Exec(`UPDATE resource_equipment SET name=@p1,asset_tag=@p2,category=@p3,active=@p4 WHERE id=@p5`, body.Name, body.AssetTag, body.Category, body.Active, id) var eq model.RegistryEquipment h.db.Get(&eq, `SELECT id,name,asset_tag,category,active FROM resource_equipment WHERE id=@p1`, id) respond(w, http.StatusOK, eq) } func (h *RegistryHandler) DeleteEquipment(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } h.db.Exec(`UPDATE resource_equipment SET active=0 WHERE id=@p1`, id) respond(w, http.StatusOK, map[string]any{"deactivated": id}) } // ── Materials ───────────────────────────────────────────────────────────────── func (h *RegistryHandler) ListMaterials(w http.ResponseWriter, r *http.Request) { search := r.URL.Query().Get("search") all := r.URL.Query().Get("all") == "1" var rows []model.RegistryMaterial var err error pat := "%" + search + "%" if all && search != "" { err = h.db.Select(&rows, `SELECT id,name,unit,part_number,active FROM resource_materials WHERE (name LIKE @p1 OR part_number LIKE @p1) ORDER BY name`, pat) } else if all { err = h.db.Select(&rows, `SELECT id,name,unit,part_number,active FROM resource_materials ORDER BY name`) } else if search != "" { err = h.db.Select(&rows, `SELECT id,name,unit,part_number,active FROM resource_materials WHERE active=1 AND (name LIKE @p1 OR part_number LIKE @p1) ORDER BY name`, pat) } else { err = h.db.Select(&rows, `SELECT id,name,unit,part_number,active FROM resource_materials WHERE active=1 ORDER BY name`) } if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } if rows == nil { rows = []model.RegistryMaterial{} } respond(w, http.StatusOK, rows) } func (h *RegistryHandler) CreateMaterial(w http.ResponseWriter, r *http.Request) { var body model.RegistryMaterial if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } var id int err := h.db.QueryRow(`INSERT INTO resource_materials (name,unit,part_number) OUTPUT INSERTED.id VALUES (@p1,@p2,@p3)`, body.Name, body.Unit, body.PartNumber).Scan(&id) if err != nil { respondError(w, http.StatusInternalServerError, err.Error()) return } var m model.RegistryMaterial h.db.Get(&m, `SELECT id,name,unit,part_number,active FROM resource_materials WHERE id=@p1`, id) respond(w, http.StatusCreated, m) } func (h *RegistryHandler) UpdateMaterial(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } var body model.RegistryMaterial if err := decode(r, &body); err != nil || body.Name == "" { respondError(w, http.StatusBadRequest, "name required") return } h.db.Exec(`UPDATE resource_materials SET name=@p1,unit=@p2,part_number=@p3,active=@p4 WHERE id=@p5`, body.Name, body.Unit, body.PartNumber, body.Active, id) var m model.RegistryMaterial h.db.Get(&m, `SELECT id,name,unit,part_number,active FROM resource_materials WHERE id=@p1`, id) respond(w, http.StatusOK, m) } func (h *RegistryHandler) DeleteMaterial(w http.ResponseWriter, r *http.Request) { id, err := intParam(r, "id") if err != nil { respondError(w, http.StatusBadRequest, "invalid id") return } h.db.Exec(`UPDATE resource_materials SET active=0 WHERE id=@p1`, id) respond(w, http.StatusOK, map[string]any{"deactivated": id}) }