188 lines
5.8 KiB
Python
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="删除成功")
|