feat: UPC deadline determination — event-driven proceeding timeline wizard
This commit is contained in:
127
backend/internal/handlers/determine.go
Normal file
127
backend/internal/handlers/determine.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"mgit.msbls.de/m/KanzlAI-mGMT/internal/auth"
|
||||
"mgit.msbls.de/m/KanzlAI-mGMT/internal/services"
|
||||
)
|
||||
|
||||
// DetermineHandlers holds handlers for deadline determination endpoints
|
||||
type DetermineHandlers struct {
|
||||
determine *services.DetermineService
|
||||
deadlines *services.DeadlineService
|
||||
}
|
||||
|
||||
// NewDetermineHandlers creates determine handlers
|
||||
func NewDetermineHandlers(determine *services.DetermineService, deadlines *services.DeadlineService) *DetermineHandlers {
|
||||
return &DetermineHandlers{determine: determine, deadlines: deadlines}
|
||||
}
|
||||
|
||||
// GetTimeline handles GET /api/proceeding-types/{code}/timeline
|
||||
// Returns the full event tree for a proceeding type (no date calculations)
|
||||
func (h *DetermineHandlers) GetTimeline(w http.ResponseWriter, r *http.Request) {
|
||||
code := r.PathValue("code")
|
||||
if code == "" {
|
||||
writeError(w, http.StatusBadRequest, "proceeding type code required")
|
||||
return
|
||||
}
|
||||
|
||||
timeline, pt, err := h.determine.GetTimeline(code)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "proceeding type not found")
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"proceeding_type": pt,
|
||||
"timeline": timeline,
|
||||
})
|
||||
}
|
||||
|
||||
// Determine handles POST /api/deadlines/determine
|
||||
// Calculates the full timeline with cascading dates and conditional logic
|
||||
func (h *DetermineHandlers) Determine(w http.ResponseWriter, r *http.Request) {
|
||||
var req services.DetermineRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.ProceedingType == "" || req.TriggerEventDate == "" {
|
||||
writeError(w, http.StatusBadRequest, "proceeding_type and trigger_event_date are required")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.determine.Determine(req)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// BatchCreate handles POST /api/cases/{caseID}/deadlines/batch
|
||||
// Creates multiple deadlines on a case from determined timeline
|
||||
func (h *DetermineHandlers) BatchCreate(w http.ResponseWriter, r *http.Request) {
|
||||
tenantID, ok := auth.TenantFromContext(r.Context())
|
||||
if !ok {
|
||||
writeError(w, http.StatusForbidden, "missing tenant")
|
||||
return
|
||||
}
|
||||
|
||||
caseID, err := parsePathUUID(r, "caseID")
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid case ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Deadlines []struct {
|
||||
Title string `json:"title"`
|
||||
DueDate string `json:"due_date"`
|
||||
OriginalDueDate *string `json:"original_due_date,omitempty"`
|
||||
RuleID *uuid.UUID `json:"rule_id,omitempty"`
|
||||
RuleCode *string `json:"rule_code,omitempty"`
|
||||
Notes *string `json:"notes,omitempty"`
|
||||
} `json:"deadlines"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Deadlines) == 0 {
|
||||
writeError(w, http.StatusBadRequest, "at least one deadline is required")
|
||||
return
|
||||
}
|
||||
|
||||
var created int
|
||||
for _, d := range req.Deadlines {
|
||||
if d.Title == "" || d.DueDate == "" {
|
||||
continue
|
||||
}
|
||||
input := services.CreateDeadlineInput{
|
||||
CaseID: caseID,
|
||||
Title: d.Title,
|
||||
DueDate: d.DueDate,
|
||||
Source: "determined",
|
||||
RuleID: d.RuleID,
|
||||
Notes: d.Notes,
|
||||
}
|
||||
_, err := h.deadlines.Create(r.Context(), tenantID, input)
|
||||
if err != nil {
|
||||
internalError(w, "failed to create deadline", err)
|
||||
return
|
||||
}
|
||||
created++
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusCreated, map[string]any{
|
||||
"created": created,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user