批次5:inventory服务下沉收口 + Pydantic v2 / datetime弃用清零

- inventory业务层下沉(薄路由+service orchestration模式):
  - customer/supplier/warehouse -> master_data_service
  - material_routes(价格历史/趋势/供应商关联)-> material_service
  - product_routes(CRUD/BOM/from-task跨模块桥接)-> product_service
  - dashboard_routes(首页统计/低库存预警)-> dashboard_service
- inventory侧新增service回归覆盖(dashboard 2 / master_data 10 /
  material 10 / product 14),含跨模块桥接测试种子
- Pydantic v2弃用清零:全仓14处 class Config 全部迁移到
  model_config = ConfigDict(from_attributes=True)(含 shared auth)
- datetime.utcnow() 弃用清零:auth_service 3处统一改 datetime.now(timezone.utc)
- 同步文档:STATUS / ROADMAP / TECH_DEBT(D12清偿)/ AGENTS 代码地图

测试基线:126 passed, 4 skipped(无deprecation warning)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-22 16:13:45 +08:00
parent c51e6b793a
commit 64dc85bd14
32 changed files with 1495 additions and 690 deletions
+6 -38
View File
@@ -9,17 +9,15 @@
路由前缀: /api/customers
"""
from fastapi import APIRouter, Depends, Query, HTTPException
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from typing import Optional, List
from datetime import datetime
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user, get_current_admin_user
from shared.models.identity import User
from inventory.models import Customer
from ..schemas import CustomerCreate, CustomerResponse
from ..services.master_data_service import master_data_service
router = APIRouter(prefix="/customers", tags=["客户管理"])
@@ -32,12 +30,7 @@ async def list_customers(
db_session: AsyncSession = Depends(get_db_session),
current_user: User = Depends(get_current_active_user)
):
query = select(Customer).where(Customer.is_active == True)
if search:
query = query.where(Customer.name.ilike(f"%{search}%"))
query = query.offset(skip).limit(limit).order_by(Customer.created_at.desc())
result = await db_session.execute(query)
return [CustomerResponse.from_orm(c) for c in result.scalars().all()]
return await master_data_service.list_customers(db_session, skip, limit, search)
@router.post("", response_model=CustomerResponse, status_code=201)
@@ -46,15 +39,7 @@ async def create_customer(
db_session: AsyncSession = Depends(get_db_session),
current_user: User = Depends(get_current_active_user)
):
data = customer_data.dict()
if not data.get("code"):
data["code"] = f"C{datetime.now().strftime('%Y%m%d%H%M%S')}"
customer = Customer(**data)
db_session.add(customer)
await db_session.flush()
await db_session.refresh(customer)
return CustomerResponse.from_orm(customer)
return await master_data_service.create_customer(db_session, customer_data, current_user)
@router.put("/{customer_id}", response_model=CustomerResponse)
@@ -64,17 +49,7 @@ async def update_customer(
db_session: AsyncSession = Depends(get_db_session),
current_user: User = Depends(get_current_active_user)
):
result = await db_session.execute(select(Customer).where(Customer.id == customer_id))
customer = result.scalar_one_or_none()
if not customer:
raise HTTPException(status_code=404, detail="客户不存在")
for key, value in customer_data.dict().items():
setattr(customer, key, value)
await db_session.flush()
await db_session.refresh(customer)
return CustomerResponse.from_orm(customer)
return await master_data_service.update_customer(db_session, customer_id, customer_data, current_user)
@router.delete("/{customer_id}")
@@ -83,11 +58,4 @@ async def delete_customer(
db_session: AsyncSession = Depends(get_db_session),
current_user: User = Depends(get_current_admin_user)
):
result = await db_session.execute(select(Customer).where(Customer.id == customer_id))
customer = result.scalar_one_or_none()
if not customer:
raise HTTPException(status_code=404, detail="客户不存在")
customer.is_active = False
await db_session.flush()
return {"message": "客户已删除"}
return await master_data_service.delete_customer(db_session, customer_id, current_user)