penti/backend/app/api/v1/portfolios.py

180 lines
4.5 KiB
Python
Raw Normal View History

2026-01-31 23:30:51 +09:00
"""Portfolio API endpoints."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import Optional
from uuid import UUID
from app.database import get_db
from app.schemas.portfolio import (
PortfolioCreate,
PortfolioUpdate,
PortfolioResponse,
PortfolioListResponse
)
from app.services.rebalancing_service import PortfolioService
router = APIRouter()
@router.post("/", response_model=PortfolioResponse, status_code=status.HTTP_201_CREATED)
async def create_portfolio(
portfolio: PortfolioCreate,
user_id: Optional[str] = None,
db: Session = Depends(get_db)
):
"""
포트폴리오 생성.
Args:
portfolio: 포트폴리오 생성 요청
user_id: 사용자 ID (선택)
db: 데이터베이스 세션
Returns:
생성된 포트폴리오
"""
try:
assets_data = [
{'ticker': asset.ticker, 'target_ratio': asset.target_ratio}
for asset in portfolio.assets
]
created_portfolio = PortfolioService.create_portfolio(
name=portfolio.name,
description=portfolio.description,
assets=assets_data,
user_id=user_id,
db_session=db
)
return created_portfolio
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"포트폴리오 생성 오류: {str(e)}"
)
@router.get("/{portfolio_id}", response_model=PortfolioResponse)
async def get_portfolio(
portfolio_id: UUID,
db: Session = Depends(get_db)
):
"""
포트폴리오 조회.
Args:
portfolio_id: 포트폴리오 ID
db: 데이터베이스 세션
Returns:
포트폴리오
"""
portfolio = PortfolioService.get_portfolio(portfolio_id, db)
if not portfolio:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)
return portfolio
@router.get("/", response_model=PortfolioListResponse)
async def list_portfolios(
user_id: Optional[str] = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db)
):
"""
포트폴리오 목록 조회.
Args:
user_id: 사용자 ID (필터)
skip: 건너뛸 레코드
limit: 최대 레코드
db: 데이터베이스 세션
Returns:
포트폴리오 목록
"""
result = PortfolioService.list_portfolios(db, user_id, skip, limit)
return result
@router.put("/{portfolio_id}", response_model=PortfolioResponse)
async def update_portfolio(
portfolio_id: UUID,
portfolio: PortfolioUpdate,
db: Session = Depends(get_db)
):
"""
포트폴리오 수정.
Args:
portfolio_id: 포트폴리오 ID
portfolio: 포트폴리오 수정 요청
db: 데이터베이스 세션
Returns:
수정된 포트폴리오
"""
try:
assets_data = None
if portfolio.assets:
assets_data = [
{'ticker': asset.ticker, 'target_ratio': asset.target_ratio}
for asset in portfolio.assets
]
updated_portfolio = PortfolioService.update_portfolio(
portfolio_id=portfolio_id,
name=portfolio.name,
description=portfolio.description,
assets=assets_data,
db_session=db
)
if not updated_portfolio:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)
return updated_portfolio
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e)
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"포트폴리오 수정 오류: {str(e)}"
)
@router.delete("/{portfolio_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_portfolio(
portfolio_id: UUID,
db: Session = Depends(get_db)
):
"""
포트폴리오 삭제.
Args:
portfolio_id: 포트폴리오 ID
db: 데이터베이스 세션
"""
success = PortfolioService.delete_portfolio(portfolio_id, db)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)