196 lines
5.1 KiB
Python
196 lines
5.1 KiB
Python
"""项目成本相关 Schema"""
|
||
|
||
from typing import Optional, List
|
||
from datetime import datetime
|
||
from enum import Enum
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
class CostItemType(str, Enum):
|
||
"""成本明细类型枚举"""
|
||
|
||
MATERIAL = "material" # 耗材
|
||
EQUIPMENT = "equipment" # 设备
|
||
|
||
|
||
class AllocationMethod(str, Enum):
|
||
"""固定成本分摊方式枚举"""
|
||
|
||
COUNT = "count" # 按项目数量平均分摊
|
||
REVENUE = "revenue" # 按项目营收占比分摊
|
||
DURATION = "duration" # 按项目时长占比分摊
|
||
|
||
|
||
# ============ 项目成本明细(耗材/设备)Schema ============
|
||
|
||
class CostItemBase(BaseModel):
|
||
"""成本明细基础字段"""
|
||
|
||
item_type: CostItemType = Field(..., description="类型:material/equipment")
|
||
item_id: int = Field(..., description="耗材/设备ID")
|
||
quantity: float = Field(..., gt=0, description="用量")
|
||
remark: Optional[str] = Field(None, max_length=200, description="备注")
|
||
|
||
|
||
class CostItemCreate(CostItemBase):
|
||
"""创建成本明细请求"""
|
||
pass
|
||
|
||
|
||
class CostItemUpdate(BaseModel):
|
||
"""更新成本明细请求"""
|
||
|
||
quantity: Optional[float] = Field(None, gt=0, description="用量")
|
||
remark: Optional[str] = Field(None, max_length=200, description="备注")
|
||
|
||
|
||
class CostItemResponse(BaseModel):
|
||
"""成本明细响应"""
|
||
|
||
id: int
|
||
item_type: CostItemType
|
||
item_id: int
|
||
item_name: Optional[str] = Field(None, description="耗材/设备名称")
|
||
quantity: float
|
||
unit: Optional[str] = Field(None, description="单位")
|
||
unit_cost: float
|
||
total_cost: float
|
||
remark: Optional[str] = None
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
class Config:
|
||
from_attributes = True
|
||
|
||
|
||
# ============ 项目人工成本 Schema ============
|
||
|
||
class LaborCostBase(BaseModel):
|
||
"""人工成本基础字段"""
|
||
|
||
staff_level_id: int = Field(..., description="人员级别ID")
|
||
duration_minutes: int = Field(..., gt=0, description="操作时长(分钟)")
|
||
remark: Optional[str] = Field(None, max_length=200, description="备注")
|
||
|
||
|
||
class LaborCostCreate(LaborCostBase):
|
||
"""创建人工成本请求"""
|
||
pass
|
||
|
||
|
||
class LaborCostUpdate(BaseModel):
|
||
"""更新人工成本请求"""
|
||
|
||
staff_level_id: Optional[int] = Field(None, description="人员级别ID")
|
||
duration_minutes: Optional[int] = Field(None, gt=0, description="操作时长(分钟)")
|
||
remark: Optional[str] = Field(None, max_length=200, description="备注")
|
||
|
||
|
||
class LaborCostResponse(BaseModel):
|
||
"""人工成本响应"""
|
||
|
||
id: int
|
||
staff_level_id: int
|
||
level_name: Optional[str] = Field(None, description="级别名称")
|
||
duration_minutes: int
|
||
hourly_rate: float
|
||
labor_cost: float
|
||
remark: Optional[str] = None
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
class Config:
|
||
from_attributes = True
|
||
|
||
|
||
# ============ 成本计算相关 Schema ============
|
||
|
||
class CalculateCostRequest(BaseModel):
|
||
"""计算成本请求"""
|
||
|
||
fixed_cost_allocation_method: AllocationMethod = Field(
|
||
AllocationMethod.COUNT,
|
||
description="固定成本分摊方式"
|
||
)
|
||
|
||
|
||
class CostBreakdownItem(BaseModel):
|
||
"""成本明细项"""
|
||
|
||
name: str
|
||
quantity: Optional[float] = None
|
||
unit: Optional[str] = None
|
||
unit_cost: Optional[float] = None
|
||
depreciation_per_use: Optional[float] = None
|
||
duration_minutes: Optional[int] = None
|
||
hourly_rate: Optional[float] = None
|
||
total: float
|
||
|
||
|
||
class CostBreakdown(BaseModel):
|
||
"""成本分项"""
|
||
|
||
items: List[CostBreakdownItem]
|
||
subtotal: float
|
||
|
||
|
||
class FixedCostAllocationDetail(BaseModel):
|
||
"""固定成本分摊详情"""
|
||
|
||
method: str
|
||
total_fixed_cost: float
|
||
project_count: Optional[int] = None
|
||
total_revenue: Optional[float] = None
|
||
total_duration: Optional[int] = None
|
||
allocation: float
|
||
|
||
|
||
class CostCalculationResult(BaseModel):
|
||
"""成本计算结果"""
|
||
|
||
project_id: int
|
||
project_name: str
|
||
cost_breakdown: dict = Field(..., description="成本分项明细")
|
||
total_cost: float = Field(..., description="总成本")
|
||
min_price_suggestion: float = Field(..., description="建议最低售价(等于总成本)")
|
||
calculated_at: datetime
|
||
|
||
|
||
class CostSummaryResponse(BaseModel):
|
||
"""成本汇总响应"""
|
||
|
||
project_id: int
|
||
material_cost: float
|
||
equipment_cost: float
|
||
labor_cost: float
|
||
fixed_cost_allocation: float
|
||
total_cost: float
|
||
calculated_at: datetime
|
||
|
||
class Config:
|
||
from_attributes = True
|
||
|
||
|
||
# ============ 项目详情(含成本)Schema ============
|
||
|
||
class ProjectDetailResponse(BaseModel):
|
||
"""项目详情响应(含成本明细)"""
|
||
|
||
id: int
|
||
project_code: str
|
||
project_name: str
|
||
category_id: Optional[int]
|
||
category_name: Optional[str]
|
||
description: Optional[str]
|
||
duration_minutes: int
|
||
is_active: bool
|
||
cost_items: List[CostItemResponse] = []
|
||
labor_costs: List[LaborCostResponse] = []
|
||
cost_summary: Optional[CostSummaryResponse] = None
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
class Config:
|
||
from_attributes = True
|