Files
H3ConuMS-v2/backend/app/api/v1/inventory.py
T
v6ole f1f8518985 ```
feat(auth): 添加用户权限获取接口并完善JWT令牌角色信息

- 在JWT令牌中添加用户角色信息
- 新增get_my_permissions接口用于获取当前用户权限码列表
- 重构认证回调逻辑,增加错误日志记录
- 更新用户信息获取接口使用Authorization头验证
```
2026-04-06 00:40:08 +08:00

197 lines
6.8 KiB
Python

"""库存管理 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)))