from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from datetime import datetime, date from typing import Optional import uuid from backend.database import get_db from backend.models import DeploymentRecord, RosterUnit router = APIRouter(prefix="/api", tags=["deployments"]) def _serialize(record: DeploymentRecord) -> dict: return { "id": record.id, "unit_id": record.unit_id, "deployed_date": record.deployed_date.isoformat() if record.deployed_date else None, "estimated_removal_date": record.estimated_removal_date.isoformat() if record.estimated_removal_date else None, "actual_removal_date": record.actual_removal_date.isoformat() if record.actual_removal_date else None, "project_ref": record.project_ref, "project_id": record.project_id, "location_name": record.location_name, "notes": record.notes, "created_at": record.created_at.isoformat() if record.created_at else None, "updated_at": record.updated_at.isoformat() if record.updated_at else None, "is_active": record.actual_removal_date is None, } @router.get("/deployments/{unit_id}") def get_deployments(unit_id: str, db: Session = Depends(get_db)): """Get all deployment records for a unit, newest first.""" unit = db.query(RosterUnit).filter_by(id=unit_id).first() if not unit: raise HTTPException(status_code=404, detail=f"Unit {unit_id} not found") records = ( db.query(DeploymentRecord) .filter_by(unit_id=unit_id) .order_by(DeploymentRecord.deployed_date.desc(), DeploymentRecord.created_at.desc()) .all() ) return {"deployments": [_serialize(r) for r in records]} @router.get("/deployments/{unit_id}/active") def get_active_deployment(unit_id: str, db: Session = Depends(get_db)): """Get the current active deployment (actual_removal_date is NULL), or null.""" record = ( db.query(DeploymentRecord) .filter( DeploymentRecord.unit_id == unit_id, DeploymentRecord.actual_removal_date == None ) .order_by(DeploymentRecord.created_at.desc()) .first() ) return {"deployment": _serialize(record) if record else None} @router.post("/deployments/{unit_id}") def create_deployment(unit_id: str, payload: dict, db: Session = Depends(get_db)): """ Create a new deployment record for a unit. Body fields (all optional): deployed_date (YYYY-MM-DD) estimated_removal_date (YYYY-MM-DD) project_ref (freeform string) project_id (UUID if linked to Project) location_name notes """ unit = db.query(RosterUnit).filter_by(id=unit_id).first() if not unit: raise HTTPException(status_code=404, detail=f"Unit {unit_id} not found") def parse_date(val) -> Optional[date]: if not val: return None if isinstance(val, date): return val return date.fromisoformat(str(val)) record = DeploymentRecord( id=str(uuid.uuid4()), unit_id=unit_id, deployed_date=parse_date(payload.get("deployed_date")), estimated_removal_date=parse_date(payload.get("estimated_removal_date")), actual_removal_date=None, project_ref=payload.get("project_ref"), project_id=payload.get("project_id"), location_name=payload.get("location_name"), notes=payload.get("notes"), created_at=datetime.utcnow(), updated_at=datetime.utcnow(), ) db.add(record) db.commit() db.refresh(record) return _serialize(record) @router.put("/deployments/{unit_id}/{deployment_id}") def update_deployment(unit_id: str, deployment_id: str, payload: dict, db: Session = Depends(get_db)): """ Update a deployment record. Used for: - Setting/changing estimated_removal_date - Closing a deployment (set actual_removal_date to mark unit returned) - Editing project_ref, location_name, notes """ record = db.query(DeploymentRecord).filter_by(id=deployment_id, unit_id=unit_id).first() if not record: raise HTTPException(status_code=404, detail="Deployment record not found") def parse_date(val) -> Optional[date]: if val is None: return None if val == "": return None if isinstance(val, date): return val return date.fromisoformat(str(val)) if "deployed_date" in payload: record.deployed_date = parse_date(payload["deployed_date"]) if "estimated_removal_date" in payload: record.estimated_removal_date = parse_date(payload["estimated_removal_date"]) if "actual_removal_date" in payload: record.actual_removal_date = parse_date(payload["actual_removal_date"]) if "project_ref" in payload: record.project_ref = payload["project_ref"] if "project_id" in payload: record.project_id = payload["project_id"] if "location_name" in payload: record.location_name = payload["location_name"] if "notes" in payload: record.notes = payload["notes"] record.updated_at = datetime.utcnow() db.commit() db.refresh(record) return _serialize(record) @router.delete("/deployments/{unit_id}/{deployment_id}") def delete_deployment(unit_id: str, deployment_id: str, db: Session = Depends(get_db)): """Delete a deployment record.""" record = db.query(DeploymentRecord).filter_by(id=deployment_id, unit_id=unit_id).first() if not record: raise HTTPException(status_code=404, detail="Deployment record not found") db.delete(record) db.commit() return {"ok": True}