package handler import ( "encoding/json" "fmt" "net/http" "strconv" "strings" "Engine/internal/database" ) type ReferenceHandler struct { repo *database.ReferenceRepo } func NewReferenceHandler(repo *database.ReferenceRepo) *ReferenceHandler { return &ReferenceHandler{repo: repo} } // ── Departments ─────────────────────────────────────────────────────────────── // POST /api/v1/department/create // PUT /api/v1/departments/{id} (same body, id from path) func (h *ReferenceHandler) CreateDepartment(w http.ResponseWriter, r *http.Request) { var req database.Department if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("invalid body: %v", err)) return } req.Code = strings.TrimSpace(req.Code) req.Name = strings.TrimSpace(req.Name) if req.Code == "" || req.Name == "" { writeError(w, http.StatusBadRequest, "code and name are required") return } // Default active to true when not explicitly set to false if !req.Active { req.Active = true } dept, err := h.repo.CreateDepartment(r.Context(), req) if err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("create department: %v", err)) return } writeJSON(w, http.StatusCreated, dept) } // GET /api/v1/department/list func (h *ReferenceHandler) ListDepartments(w http.ResponseWriter, r *http.Request) { depts, err := h.repo.ListDepartments(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("list departments: %v", err)) return } if depts == nil { depts = []database.Department{} } writeJSON(w, http.StatusOK, depts) } // DELETE /api/v1/department/delete func (h *ReferenceHandler) DeleteDepartment(w http.ResponseWriter, r *http.Request) { var req struct { ID int `json:"id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("invalid body: %v", err)) return } id, err := pathID(r, "id") if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.repo.DeleteDepartment(r.Context(), id); err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("delete department: %v", err)) return } w.WriteHeader(http.StatusNoContent) } // ── GL Accounts ─────────────────────────────────────────────────────────────── var validGLTypes = map[string]bool{ "revenue": true, "cogs": true, "opex": true, "capex": true, "headcount": true, } // POST /api/v1/gl-accounts func (h *ReferenceHandler) CreateGLAccount(w http.ResponseWriter, r *http.Request) { var req database.GLAccount if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("invalid body: %v", err)) return } req.Code = strings.TrimSpace(req.Code) req.Description = strings.TrimSpace(req.Description) if req.Code == "" || req.Description == "" { writeError(w, http.StatusBadRequest, "code and description are required") return } if !validGLTypes[req.Type] { writeError(w, http.StatusBadRequest, "type must be one of: revenue, cogs, opex, capex, headcount") return } if !req.Active { req.Active = true } acct, err := h.repo.CreateGLAccount(r.Context(), req) if err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("create gl_account: %v", err)) return } writeJSON(w, http.StatusCreated, acct) } // GET /api/v1/gl-accounts func (h *ReferenceHandler) ListGLAccounts(w http.ResponseWriter, r *http.Request) { accts, err := h.repo.ListGLAccounts(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("list gl_accounts: %v", err)) return } if accts == nil { accts = []database.GLAccount{} } writeJSON(w, http.StatusOK, accts) } // DELETE /api/v1/gl-accounts/{id} func (h *ReferenceHandler) DeleteGLAccount(w http.ResponseWriter, r *http.Request) { id, err := pathID(r, "id") if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.repo.DeleteGLAccount(r.Context(), id); err != nil { writeError(w, http.StatusInternalServerError, fmt.Sprintf("delete gl_account: %v", err)) return } w.WriteHeader(http.StatusNoContent) } // ── Shared helpers ──────────────────────────────────────────────────────────── func pathID(r *http.Request, key string) (int, error) { return strconv.Atoi(r.PathValue(key)) }