Files
smart-project-pricing/后端服务/app/routers/fixed_costs.py
2026-01-31 21:33:06 +08:00

188 lines
5.8 KiB
Python

"""固定成本路由
实现固定成本的 CRUD 操作
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models.fixed_cost import FixedCost
from app.schemas.common import ResponseModel, PaginatedData, ErrorCode
from app.schemas.fixed_cost import (
FixedCostCreate,
FixedCostUpdate,
FixedCostResponse,
CostType,
AllocationMethod,
)
router = APIRouter()
@router.get("", response_model=ResponseModel[PaginatedData[FixedCostResponse]])
async def get_fixed_costs(
page: int = Query(1, ge=1, description="页码"),
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
year_month: Optional[str] = Query(None, description="年月筛选"),
cost_type: Optional[CostType] = Query(None, description="类型筛选"),
is_active: Optional[bool] = Query(None, description="是否启用筛选"),
db: AsyncSession = Depends(get_db),
):
"""获取固定成本列表"""
query = select(FixedCost)
if year_month:
query = query.where(FixedCost.year_month == year_month)
if cost_type:
query = query.where(FixedCost.cost_type == cost_type.value)
if is_active is not None:
query = query.where(FixedCost.is_active == is_active)
query = query.order_by(FixedCost.year_month.desc(), FixedCost.id)
# 分页
offset = (page - 1) * page_size
query = query.offset(offset).limit(page_size)
result = await db.execute(query)
fixed_costs = result.scalars().all()
# 统计总数
count_query = select(func.count(FixedCost.id))
if year_month:
count_query = count_query.where(FixedCost.year_month == year_month)
if cost_type:
count_query = count_query.where(FixedCost.cost_type == cost_type.value)
if is_active is not None:
count_query = count_query.where(FixedCost.is_active == is_active)
total_result = await db.execute(count_query)
total = total_result.scalar() or 0
return ResponseModel(
data=PaginatedData(
items=[FixedCostResponse.model_validate(f) for f in fixed_costs],
total=total,
page=page,
page_size=page_size,
total_pages=(total + page_size - 1) // page_size,
)
)
@router.get("/summary", response_model=ResponseModel)
async def get_fixed_costs_summary(
year_month: str = Query(..., description="年月"),
db: AsyncSession = Depends(get_db),
):
"""获取指定月份的固定成本汇总"""
query = select(FixedCost).where(
FixedCost.year_month == year_month,
FixedCost.is_active == True,
)
result = await db.execute(query)
fixed_costs = result.scalars().all()
# 按类型汇总
summary_by_type = {}
total_amount = 0
for cost in fixed_costs:
cost_type = cost.cost_type
if cost_type not in summary_by_type:
summary_by_type[cost_type] = 0
summary_by_type[cost_type] += float(cost.monthly_amount)
total_amount += float(cost.monthly_amount)
return ResponseModel(
data={
"year_month": year_month,
"total_amount": total_amount,
"by_type": summary_by_type,
"count": len(fixed_costs),
}
)
@router.get("/{fixed_cost_id}", response_model=ResponseModel[FixedCostResponse])
async def get_fixed_cost(
fixed_cost_id: int,
db: AsyncSession = Depends(get_db),
):
"""获取单个固定成本详情"""
result = await db.execute(select(FixedCost).where(FixedCost.id == fixed_cost_id))
fixed_cost = result.scalar_one_or_none()
if not fixed_cost:
raise HTTPException(
status_code=404,
detail={"code": ErrorCode.NOT_FOUND, "message": "固定成本不存在"}
)
return ResponseModel(data=FixedCostResponse.model_validate(fixed_cost))
@router.post("", response_model=ResponseModel[FixedCostResponse])
async def create_fixed_cost(
data: FixedCostCreate,
db: AsyncSession = Depends(get_db),
):
"""创建固定成本"""
fixed_cost = FixedCost(**data.model_dump())
db.add(fixed_cost)
await db.flush()
await db.refresh(fixed_cost)
return ResponseModel(message="创建成功", data=FixedCostResponse.model_validate(fixed_cost))
@router.put("/{fixed_cost_id}", response_model=ResponseModel[FixedCostResponse])
async def update_fixed_cost(
fixed_cost_id: int,
data: FixedCostUpdate,
db: AsyncSession = Depends(get_db),
):
"""更新固定成本"""
result = await db.execute(select(FixedCost).where(FixedCost.id == fixed_cost_id))
fixed_cost = result.scalar_one_or_none()
if not fixed_cost:
raise HTTPException(
status_code=404,
detail={"code": ErrorCode.NOT_FOUND, "message": "固定成本不存在"}
)
update_data = data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(fixed_cost, field, value)
await db.flush()
await db.refresh(fixed_cost)
return ResponseModel(message="更新成功", data=FixedCostResponse.model_validate(fixed_cost))
@router.delete("/{fixed_cost_id}", response_model=ResponseModel)
async def delete_fixed_cost(
fixed_cost_id: int,
db: AsyncSession = Depends(get_db),
):
"""删除固定成本"""
result = await db.execute(select(FixedCost).where(FixedCost.id == fixed_cost_id))
fixed_cost = result.scalar_one_or_none()
if not fixed_cost:
raise HTTPException(
status_code=404,
detail={"code": ErrorCode.NOT_FOUND, "message": "固定成本不存在"}
)
await db.delete(fixed_cost)
return ResponseModel(message="删除成功")