"""库存管理 Pydantic 模式""" from typing import Optional, List, Any from datetime import date, datetime from decimal import Decimal from pydantic import BaseModel # ── 物料分类 ────────────────────────────────────────────────────────────────── class CategoryCreate(BaseModel): name: str code: str description: Optional[str] = None class CategoryResponse(BaseModel): id: int name: str code: str description: Optional[str] = None created_at: Optional[datetime] = None class Config: from_attributes = True # ── 物料 ────────────────────────────────────────────────────────────────────── class MaterialCreate(BaseModel): category_id: int name: str model: Optional[str] = None specification: Optional[str] = None brand: Optional[str] = None unit: str = "个" safe_quantity: int = 0 notes: Optional[str] = None class MaterialUpdate(BaseModel): name: Optional[str] = None model: Optional[str] = None specification: Optional[str] = None brand: Optional[str] = None unit: Optional[str] = None safe_quantity: Optional[int] = None notes: Optional[str] = None class MaterialResponse(BaseModel): id: int category_id: int category_name: Optional[str] = None name: str model: Optional[str] = None specification: Optional[str] = None brand: Optional[str] = None unit: str safe_quantity: int notes: Optional[str] = None total_quantity: int = 0 available_quantity: int = 0 created_at: Optional[datetime] = None class Config: from_attributes = True class MaterialListResponse(BaseModel): total: int items: List[MaterialResponse] # ── 库存批次 ────────────────────────────────────────────────────────────────── class BatchCreate(BaseModel): material_id: int batch_no: str quantity: int supplier: Optional[str] = None purchase_date: Optional[date] = None purchase_price: Optional[Decimal] = None location: Optional[str] = None notes: Optional[str] = None class BatchResponse(BaseModel): id: int material_id: int material_name: Optional[str] = None batch_no: str quantity: int available_quantity: int supplier: Optional[str] = None purchase_date: Optional[date] = None purchase_price: Optional[Decimal] = None location: Optional[str] = None status: str created_at: Optional[datetime] = None class Config: from_attributes = True # ── 序列号设备 ──────────────────────────────────────────────────────────────── class SerialDeviceCreate(BaseModel): material_id: int batch_id: Optional[int] = None serial_no: str mac_address: Optional[str] = None asset_no: Optional[str] = None notes: Optional[str] = None class SerialDeviceResponse(BaseModel): id: int material_id: int material_name: Optional[str] = None batch_id: Optional[int] = None serial_no: str mac_address: Optional[str] = None asset_no: Optional[str] = None status: str current_location: Optional[str] = None installed_info: Optional[Any] = None notes: Optional[str] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class Config: from_attributes = True class SerialDeviceListResponse(BaseModel): total: int items: List[SerialDeviceResponse] # ── 出入库操作 ──────────────────────────────────────────────────────────────── class PurchaseInRequest(BaseModel): material_id: int batch_no: str quantity: int supplier: Optional[str] = None purchase_date: Optional[date] = None purchase_price: Optional[Decimal] = None location: Optional[str] = None serial_nos: Optional[List[str]] = None # 高价值设备的序列号列表 notes: Optional[str] = None class AllocateOutRequest(BaseModel): serial_device_id: Optional[int] = None # 序列号设备 batch_id: Optional[int] = None # 批次设备 quantity: int = 1 project_name: Optional[str] = None installation_info: Optional[Any] = None # 方案三:领用时补录设备标识(适用于批次出库场景) mac_address: Optional[str] = None # MAC 地址 serial_no: Optional[str] = None # 序列号 asset_no: Optional[str] = None # 资产编号 notes: Optional[str] = None class ReturnInRequest(BaseModel): serial_device_id: int return_type: str # simple, repair, scrap notes: Optional[str] = None class TransactionResponse(BaseModel): id: int transaction_no: str transaction_type: str material_id: int material_name: Optional[str] = None quantity: int from_status: Optional[str] = None to_status: Optional[str] = None operator_id: Optional[int] = None project_name: Optional[str] = None installation_info: Optional[Any] = None # 包含补录的设备信息 notes: Optional[str] = None created_at: Optional[datetime] = None class Config: from_attributes = True class TransactionListResponse(BaseModel): total: int items: List[TransactionResponse] # ── 盘点 ────────────────────────────────────────────────────────────────────── class CheckCreate(BaseModel): check_date: date material_id: int batch_id: Optional[int] = None actual_quantity: int reason: Optional[str] = None class CheckResponse(BaseModel): id: int check_no: str check_date: date material_id: int material_name: Optional[str] = None batch_id: Optional[int] = None book_quantity: Optional[int] = None actual_quantity: Optional[int] = None difference: Optional[int] = None reason: Optional[str] = None adjusted: bool created_at: Optional[datetime] = None class Config: from_attributes = True class CheckListResponse(BaseModel): total: int items: List[CheckResponse] # ── 统计 ────────────────────────────────────────────────────────────────────── class InventorySummary(BaseModel): total_materials: int total_quantity: int available_quantity: int allocated_quantity: int low_stock_count: int category_stats: List[dict]