"""Holding CRUD endpoints.""" from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session, select from ten31portal.audit import record_audit from ten31portal.auth import ( check_administrator_scope, require_internal_or_administrator, require_writer, ) from ten31portal.database import get_session from ten31portal.models import Entity, Holding, Position, User from ten31portal.schemas import HoldingCreate, HoldingResponse, HoldingUpdate router = APIRouter(tags=["holdings"]) @router.get("/api/entities/{entity_id}/holdings") def list_holdings( entity_id: int, user: User = Depends(require_internal_or_administrator), session: Session = Depends(get_session), ) -> list[HoldingResponse]: check_administrator_scope(user, entity_id, session) entity = session.get(Entity, entity_id) if entity is None: raise HTTPException(status_code=404, detail="Entity not found") rows = session.exec(select(Holding).where(Holding.entity_id == entity_id)).all() return [HoldingResponse.model_validate(r, from_attributes=True) for r in rows] @router.post("/api/entities/{entity_id}/holdings", status_code=201) def create_holding( entity_id: int, body: HoldingCreate, user: User = Depends(require_writer), session: Session = Depends(get_session), ) -> HoldingResponse: entity = session.get(Entity, entity_id) if entity is None: raise HTTPException(status_code=404, detail="Entity not found") holding = Holding(entity_id=entity_id, company_name=body.company_name) session.add(holding) session.flush() record_audit(session, user.id, "create", "holding", holding.id, {"entity_id": entity_id, **body.model_dump()}) session.commit() session.refresh(holding) return HoldingResponse.model_validate(holding, from_attributes=True) @router.patch("/api/holdings/{holding_id}") def update_holding( holding_id: int, body: HoldingUpdate, user: User = Depends(require_writer), session: Session = Depends(get_session), ) -> HoldingResponse: holding = session.get(Holding, holding_id) if holding is None: raise HTTPException(status_code=404, detail="Holding not found") changes = body.model_dump(exclude_unset=True) for key, val in changes.items(): setattr(holding, key, val) session.add(holding) session.flush() record_audit(session, user.id, "update", "holding", holding.id, changes) session.commit() session.refresh(holding) return HoldingResponse.model_validate(holding, from_attributes=True) @router.delete("/api/holdings/{holding_id}") def delete_holding( holding_id: int, user: User = Depends(require_writer), session: Session = Depends(get_session), ) -> dict[str, str]: holding = session.get(Holding, holding_id) if holding is None: raise HTTPException(status_code=404, detail="Holding not found") positions = session.exec(select(Position).where(Position.holding_id == holding_id)).all() if positions: raise HTTPException(status_code=409, detail="Cannot delete holding with existing positions. Remove positions first.") record_audit(session, user.id, "delete", "holding", holding.id, {"company_name": holding.company_name}) session.delete(holding) session.commit() return {"status": "deleted"}