f1f8518985
feat(auth): 添加用户权限获取接口并完善JWT令牌角色信息 - 在JWT令牌中添加用户角色信息 - 新增get_my_permissions接口用于获取当前用户权限码列表 - 重构认证回调逻辑,增加错误日志记录 - 更新用户信息获取接口使用Authorization头验证 ```
197 lines
6.8 KiB
Python
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)))
|