"""库存管理 API""" from typing import Optional from fastapi import APIRouter, Depends, Query, HTTPException from sqlalchemy.orm import Session from app.core.database import get_db from app.middleware.permission_middleware import require_permission from app.schemas.inventory import ( CategoryCreate, CategoryResponse, MaterialCreate, MaterialUpdate, MaterialListResponse, PurchaseInRequest, AllocateOutRequest, ReturnInRequest, TransactionListResponse, SerialDeviceListResponse, CheckCreate, CheckListResponse, InventorySummary, ) import app.services.inventory_service as svc router = APIRouter(prefix="/api/inventory", tags=["库存管理"]) # ── 物料分类 ────────────────────────────────────────────────────────────────── @router.get("/categories") def list_categories( db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_categories(db) @router.post("/categories", response_model=CategoryResponse) def create_category( body: CategoryCreate, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.manage")), ): return svc.create_category(db, body.name, body.code, body.description) # ── 物料 ────────────────────────────────────────────────────────────────────── @router.get("/materials", response_model=MaterialListResponse) def list_materials( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), category_id: Optional[int] = None, keyword: Optional[str] = None, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_materials(db, skip, limit, category_id, keyword) @router.post("/materials") def create_material( body: MaterialCreate, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.manage")), ): return svc.create_material(db, body.model_dump()) @router.put("/materials/{material_id}") def update_material( material_id: int, body: MaterialUpdate, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.manage")), ): return svc.update_material(db, material_id, body.model_dump(exclude_none=True)) @router.delete("/materials/{material_id}") def delete_material( material_id: int, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.manage")), ): svc.delete_material(db, material_id) return {"message": "删除成功"} # ── 出入库操作 ──────────────────────────────────────────────────────────────── @router.post("/transactions/purchase") def purchase_in( body: PurchaseInRequest, db: Session = Depends(get_db), current: dict = Depends(require_permission("inventory.transaction")), ): return svc.purchase_in(db, body.model_dump(), int(current.get("sub", 0))) @router.post("/transactions/allocate") def allocate_out( body: AllocateOutRequest, db: Session = Depends(get_db), current: dict = Depends(require_permission("inventory.transaction")), ): return svc.allocate_out(db, body.model_dump(), int(current.get("sub", 0))) @router.post("/transactions/return") def return_in( body: ReturnInRequest, db: Session = Depends(get_db), current: dict = Depends(require_permission("inventory.transaction")), ): return svc.return_in(db, body.serial_device_id, body.return_type, body.notes, int(current.get("sub", 0))) @router.get("/transactions", response_model=TransactionListResponse) def list_transactions( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), transaction_type: Optional[str] = None, material_id: Optional[int] = None, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_transactions(db, skip, limit, transaction_type, material_id) @router.get("/transactions/{transaction_id}") def get_transaction( transaction_id: int, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_transaction_detail(db, transaction_id) @router.get("/batches") def list_batches( material_id: int, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_batches_by_material(db, material_id) # ── 序列号设备 ──────────────────────────────────────────────────────────────── @router.get("/serial-devices", response_model=SerialDeviceListResponse) def list_serial_devices( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), material_id: Optional[int] = None, status: Optional[str] = None, keyword: Optional[str] = None, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_serial_devices(db, skip, limit, material_id, status, keyword) # ── 库存统计 ────────────────────────────────────────────────────────────────── @router.get("/summary", response_model=InventorySummary) def get_summary( db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_summary(db) # ── 盘点 ────────────────────────────────────────────────────────────────────── @router.get("/checks", response_model=CheckListResponse) def list_checks( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), material_id: Optional[int] = None, db: Session = Depends(get_db), _: dict = Depends(require_permission("inventory.view")), ): return svc.get_checks(db, skip, limit, material_id) @router.post("/checks") def create_check( body: CheckCreate, db: Session = Depends(get_db), current: dict = Depends(require_permission("inventory.check")), ): return svc.create_check(db, body.model_dump(), int(current.get("sub", 0))) @router.post("/checks/{check_id}/adjust") def adjust_check( check_id: int, db: Session = Depends(get_db), current: dict = Depends(require_permission("inventory.check")), ): return svc.adjust_check(db, check_id, int(current.get("sub", 0)))