feat(m3): week close, overtime/undertime delta, frozen settings snapshot

This commit is contained in:
2026-04-30 16:39:42 +02:00
parent 4a0e0c8318
commit d0ef0387f2
5 changed files with 383 additions and 2 deletions

View File

@@ -0,0 +1,81 @@
package handler
import (
"errors"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/wotra/wotra/internal/service"
)
// WeekHandler serves /api/weeks routes.
type WeekHandler struct {
svc *service.WeekService
}
func NewWeekHandler(svc *service.WeekService) *WeekHandler {
return &WeekHandler{svc: svc}
}
func (h *WeekHandler) Routes(r chi.Router) {
r.Get("/weeks", h.List)
r.Post("/weeks/{week_key}/close", h.Close)
r.Delete("/weeks/{week_key}/close", h.Reopen)
}
// List GET /api/weeks?from=YYYY-Www&to=YYYY-Www
func (h *WeekHandler) List(w http.ResponseWriter, r *http.Request) {
from := r.URL.Query().Get("from")
to := r.URL.Query().Get("to")
if from == "" {
from = "0000-W01"
}
if to == "" {
to = "9999-W53"
}
weeks, err := h.svc.ListWeeks(r.Context(), from, to)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if weeks == nil {
writeJSON(w, http.StatusOK, []struct{}{})
return
}
writeJSON(w, http.StatusOK, weeks)
}
// Close POST /api/weeks/{week_key}/close
func (h *WeekHandler) Close(w http.ResponseWriter, r *http.Request) {
weekKey := chi.URLParam(r, "week_key")
cw, err := h.svc.CloseWeek(r.Context(), weekKey)
if err != nil {
switch {
case errors.Is(err, service.ErrWeekAlreadyClosed):
writeError(w, http.StatusConflict, err.Error())
case errors.Is(err, service.ErrWeekHasUnclosedDays):
writeError(w, http.StatusUnprocessableEntity, err.Error())
case errors.Is(err, service.ErrNoSettings):
writeError(w, http.StatusUnprocessableEntity, err.Error())
default:
writeError(w, http.StatusInternalServerError, err.Error())
}
return
}
writeJSON(w, http.StatusOK, cw)
}
// Reopen DELETE /api/weeks/{week_key}/close
func (h *WeekHandler) Reopen(w http.ResponseWriter, r *http.Request) {
weekKey := chi.URLParam(r, "week_key")
if err := h.svc.ReopenWeek(r.Context(), weekKey); err != nil {
switch {
case errors.Is(err, service.ErrWeekNotClosed):
writeError(w, http.StatusNotFound, err.Error())
default:
writeError(w, http.StatusInternalServerError, err.Error())
}
return
}
w.WriteHeader(http.StatusNoContent)
}