from fastapi import APIRouter, Depends, HTTPException, status from typing import List from models import ReportPeriodCreate, ReportPeriodUpdate, ReportPeriodResponse, ReportPeriodInDB, UserInDB from database import get_database from routes.auth_routes import get_current_user from bson import ObjectId from datetime import datetime router = APIRouter(prefix="/periods", tags=["report-periods"]) @router.post("", response_model=ReportPeriodResponse, status_code=status.HTTP_201_CREATED) async def create_period( period: ReportPeriodCreate, current_user: UserInDB = Depends(get_current_user) ): """Create a new report period""" db = get_database() period_in_db = ReportPeriodInDB( **period.model_dump(), user_id=current_user.id ) period_dict = period_in_db.model_dump(by_alias=True) period_dict["_id"] = ObjectId(period_dict["_id"]) result = await db.periods.insert_one(period_dict) period_dict["_id"] = str(result.inserted_id) return ReportPeriodResponse(**period_dict) @router.get("", response_model=List[ReportPeriodResponse]) async def get_periods(current_user: UserInDB = Depends(get_current_user)): """Get all report periods for the current user""" db = get_database() cursor = db.periods.find({"user_id": current_user.id}).sort("start_date", -1) periods = await cursor.to_list(length=None) for period in periods: period["_id"] = str(period["_id"]) return [ReportPeriodResponse(**period) for period in periods] @router.get("/{period_id}", response_model=ReportPeriodResponse) async def get_period( period_id: str, current_user: UserInDB = Depends(get_current_user) ): """Get a specific report period""" db = get_database() if not ObjectId.is_valid(period_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid period ID" ) period = await db.periods.find_one({ "_id": ObjectId(period_id), "user_id": current_user.id }) if not period: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Report period not found" ) period["_id"] = str(period["_id"]) return ReportPeriodResponse(**period) @router.put("/{period_id}", response_model=ReportPeriodResponse) async def update_period( period_id: str, period_update: ReportPeriodUpdate, current_user: UserInDB = Depends(get_current_user) ): """Update a report period""" db = get_database() if not ObjectId.is_valid(period_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid period ID" ) # Check if period exists and belongs to user existing_period = await db.periods.find_one({ "_id": ObjectId(period_id), "user_id": current_user.id }) if not existing_period: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Report period not found" ) # Update only provided fields update_data = period_update.model_dump(exclude_unset=True) if update_data: update_data["updated_at"] = datetime.utcnow() await db.periods.update_one( {"_id": ObjectId(period_id)}, {"$set": update_data} ) # Fetch updated period updated_period = await db.periods.find_one({"_id": ObjectId(period_id)}) updated_period["_id"] = str(updated_period["_id"]) return ReportPeriodResponse(**updated_period) @router.delete("/{period_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_period( period_id: str, current_user: UserInDB = Depends(get_current_user) ): """Delete a report period""" db = get_database() if not ObjectId.is_valid(period_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid period ID" ) # Check if period exists and belongs to user period = await db.periods.find_one({ "_id": ObjectId(period_id), "user_id": current_user.id }) if not period: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Report period not found" ) # Delete period await db.periods.delete_one({"_id": ObjectId(period_id)}) return None