package handlers import ( "database/sql" "encoding/json" "net/http" "time" "github.com/go-chi/chi/v5" ) type HRHandler struct { DB *sql.DB } func NewHRHandler(db *sql.DB) *HRHandler { return &HRHandler{DB: db} } type Employee struct { ID string `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Email string `json:"email"` Phone string `json:"phone"` Department string `json:"department"` Position string `json:"position"` EmploymentType string `json:"employment_type"` Salary float64 `json:"salary"` Currency string `json:"currency"` StartDate *time.Time `json:"start_date"` Status string `json:"status"` CreatedAt time.Time `json:"created_at"` } type Leave struct { ID string `json:"id"` EmployeeID string `json:"employee_id"` Type string `json:"type"` StartDate time.Time `json:"start_date"` EndDate time.Time `json:"end_date"` Days float64 `json:"days"` Status string `json:"status"` ApprovedBy *string `json:"approved_by"` ApprovedAt *time.Time `json:"approved_at"` } type Timesheet struct { ID string `json:"id"` EmployeeID string `json:"employee_id"` Date time.Time `json:"date"` Hours float64 `json:"hours"` Project string `json:"project"` Task string `json:"task"` Description string `json:"description"` Status string `json:"status"` } func (h *HRHandler) ListEmployees(w http.ResponseWriter, r *http.Request) { rows, err := h.DB.Query(` SELECT id, first_name, last_name, email, phone, department, position, employment_type, salary, currency, start_date, status, created_at FROM boc_employees WHERE status = 'active' ORDER BY created_at DESC `) if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } defer rows.Close() employees := []Employee{} for rows.Next() { var e Employee if err := rows.Scan(&e.ID, &e.FirstName, &e.LastName, &e.Email, &e.Phone, &e.Department, &e.Position, &e.EmploymentType, &e.Salary, &e.Currency, &e.StartDate, &e.Status, &e.CreatedAt); err != nil { continue } employees = append(employees, e) } writeJSON(w, http.StatusOK, map[string]interface{}{ "employees": employees, "total": len(employees), }) } func (h *HRHandler) CreateEmployee(w http.ResponseWriter, r *http.Request) { var req Employee if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } var id string err := h.DB.QueryRow(` INSERT INTO boc_employees (first_name, last_name, email, phone, department, position, employment_type, salary, currency, start_date, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'active') RETURNING id `, req.FirstName, req.LastName, req.Email, req.Phone, req.Department, req.Position, req.EmploymentType, req.Salary, req.Currency, req.StartDate).Scan(&id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create employee") return } writeJSON(w, http.StatusCreated, map[string]interface{}{ "id": id, "message": "Employee created", }) } func (h *HRHandler) GetEmployee(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var e Employee err := h.DB.QueryRow(` SELECT id, first_name, last_name, email, phone, department, position, employment_type, salary, currency, start_date, status, created_at FROM boc_employees WHERE id = $1 `, id).Scan(&e.ID, &e.FirstName, &e.LastName, &e.Email, &e.Phone, &e.Department, &e.Position, &e.EmploymentType, &e.Salary, &e.Currency, &e.StartDate, &e.Status, &e.CreatedAt) if err == sql.ErrNoRows { writeError(w, http.StatusNotFound, "employee not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } writeJSON(w, http.StatusOK, e) } func (h *HRHandler) UpdateEmployee(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var req Employee if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } _, err := h.DB.Exec(` UPDATE boc_employees SET first_name = $1, last_name = $2, email = $3, phone = $4, department = $5, position = $6, employment_type = $7, salary = $8, currency = $9, start_date = $10, status = $11 WHERE id = $12 `, req.FirstName, req.LastName, req.Email, req.Phone, req.Department, req.Position, req.EmploymentType, req.Salary, req.Currency, req.StartDate, req.Status, id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to update employee") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "message": "Employee updated", }) } func (h *HRHandler) ListLeaves(w http.ResponseWriter, r *http.Request) { rows, err := h.DB.Query(` SELECT id, employee_id, type, start_date, end_date, days, status, approved_by, approved_at FROM boc_leaves ORDER BY start_date DESC LIMIT 100 `) if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } defer rows.Close() leaves := []Leave{} for rows.Next() { var l Leave if err := rows.Scan(&l.ID, &l.EmployeeID, &l.Type, &l.StartDate, &l.EndDate, &l.Days, &l.Status, &l.ApprovedBy, &l.ApprovedAt); err != nil { continue } leaves = append(leaves, l) } writeJSON(w, http.StatusOK, map[string]interface{}{ "leaves": leaves, "total": len(leaves), }) } func (h *HRHandler) CreateLeave(w http.ResponseWriter, r *http.Request) { var req Leave if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } var id string err := h.DB.QueryRow(` INSERT INTO boc_leaves (employee_id, type, start_date, end_date, days, status) VALUES ($1, $2, $3, $4, $5, 'pending') RETURNING id `, req.EmployeeID, req.Type, req.StartDate, req.EndDate, req.Days).Scan(&id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create leave") return } writeJSON(w, http.StatusCreated, map[string]interface{}{ "id": id, "message": "Leave request created", }) } func (h *HRHandler) ListTimesheets(w http.ResponseWriter, r *http.Request) { rows, err := h.DB.Query(` SELECT id, employee_id, date, hours, project, task, description, status FROM boc_timesheets ORDER BY date DESC LIMIT 100 `) if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } defer rows.Close() timesheets := []Timesheet{} for rows.Next() { var t Timesheet if err := rows.Scan(&t.ID, &t.EmployeeID, &t.Date, &t.Hours, &t.Project, &t.Task, &t.Description, &t.Status); err != nil { continue } timesheets = append(timesheets, t) } writeJSON(w, http.StatusOK, map[string]interface{}{ "timesheets": timesheets, "total": len(timesheets), }) } func (h *HRHandler) CreateTimesheet(w http.ResponseWriter, r *http.Request) { var req Timesheet if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } var id string err := h.DB.QueryRow(` INSERT INTO boc_timesheets (employee_id, date, hours, project, task, description, status) VALUES ($1, $2, $3, $4, $5, $6, 'draft') RETURNING id `, req.EmployeeID, req.Date, req.Hours, req.Project, req.Task, req.Description).Scan(&id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create timesheet") return } writeJSON(w, http.StatusCreated, map[string]interface{}{ "id": id, "message": "Timesheet created", }) }