357 lines
17 KiB
Python
357 lines
17 KiB
Python
"""
|
|
项目数据推送相关schema
|
|
"""
|
|
|
|
from typing import List, Optional
|
|
|
|
from fastapi import HTTPException
|
|
from pydantic import Field, BaseModel, field_validator
|
|
from ..common.push_system import BaseUpdateRequestSchema
|
|
from ..common.base import BaseResponseWithID
|
|
from ..common.datetime import get_current_date
|
|
from ..common.validators import DateStr
|
|
from .enums import ProgressType, KeyConstraints, DBTCSCORE
|
|
|
|
class ProjectResponseBase(BaseResponseWithID):
|
|
"""
|
|
项目基础信息, 复制自project_model
|
|
不进行继承,通过检查器确保字段和模型一致
|
|
"""
|
|
# 基础信息-不允许更改
|
|
id : str = Field(..., description="项目ID", examples=["uuid"])
|
|
project_type: str = Field("", description="项目类型")
|
|
region_name: List[str] = Field(default_factory=list, description="项目所属区域名称", examples=[["华东", "江苏"]])
|
|
region_path: List[str] = Field(default_factory=list, description="项目所属区域路径", examples=[["110000", "120000", "120001"]])
|
|
province: str = Field("", description="省份(region_path第一个)", examples=["110000"])
|
|
is_domestic :bool=Field(True, description="是否是国内项目")
|
|
company_id: str = Field("", description="所属公司ID", examples=["company123"])
|
|
company_name: str = Field("", description="所属公司名称", examples=["国电投江苏公司"])
|
|
syxs: Optional[str] = Field(None, description="升压站型式")
|
|
sub_type: Optional[str] = Field(None, description="光伏类别")
|
|
scgc_type: Optional[str] = Field(None, description="送出工程建设方式")
|
|
|
|
# 基础信息-允许更改
|
|
address: str = Field("", description="项目地址", examples=["某省某市某区"])
|
|
code: str = Field("", description="项目编码", examples=["XM2025001"])
|
|
name: str = Field(..., description="项目名称", examples=["XX新能源项目"])
|
|
short_name: str = Field("", description="项目简称", examples=["XX项目"])
|
|
manager_name: str = Field("", description="负责人姓名", examples=["张三"])
|
|
manager_phone: str = Field("", description="负责人电话", examples=["13800000000"])
|
|
|
|
|
|
# 容量信息
|
|
authorization_date: Optional[DateStr] = Field(None, description="核准日期", examples=["2024-01-01"])
|
|
authorized_capacity: float = Field(0.0, description="核准容量(万千瓦)", examples=[10.0])
|
|
# 投决
|
|
investment_decision_capacity: Optional[float] = Field(None, description="投资决策容量", examples=[8.0])
|
|
investment_decision_date: Optional[DateStr] = Field(None, description="投资决策日期", examples=["2024-02-01"])
|
|
# 开工
|
|
plan_construction_capacity: float = Field(0.0, description="本年度计划开工容量", examples=[5.0])
|
|
plan_construction_date: Optional[DateStr] = Field(None, description="本年度计划开工日期", examples=["2024-03-01"])
|
|
actual_construction_capacity: float = Field(0.0, description="本年度实际开工容量", examples=[4.0])
|
|
actual_construction_date: Optional[DateStr] = Field(None, description="本年度实际开工日期", examples=["2024-04-01"])
|
|
accumulated_construction_capacity: float = Field(0.0, description="累计开工容量", examples=[12.0])
|
|
constructing_capacity: float = Field(0.0, description="在建容量", examples=[6.0])
|
|
|
|
# 投产
|
|
ensure_production_capacity: float = Field(0.0, description="本年度确保投产容量", examples=[3.0])
|
|
challenge_production_capacity: float = Field(0.0, description="本年度揭榜投产容量", examples=[2.0])
|
|
climb_production_capacity: float = Field(0.0, description="本年度登高投产容量", examples=[1.0])
|
|
plan_production_date: Optional[DateStr] = Field(None, description="计划投产日期", examples=["2024-08-01"])
|
|
plan_full_production_date: Optional[DateStr] = Field(None, description="计划全部投产日期", examples=["2024-09-01"])
|
|
actual_production_date: Optional[DateStr] = Field(None, description="实际投产日期", examples=["2024-08-15"])
|
|
actual_full_production_date: Optional[DateStr] = Field(None, description="实际全投日期", examples=["2024-09-10"])
|
|
production_capacity: Optional[float] = Field(0.0, description="本年度投产容量", examples=[2.0])
|
|
production_date: Optional[DateStr] = Field(None, description="本年度首批投产日期", examples=["2024-09-01"])
|
|
total_production_capacity: Optional[float] = Field(0.0, description="全部投产容量", examples=[2.0])
|
|
|
|
# 投资
|
|
dynamic_investment: float = Field(0.0, description="动态总投资", examples=[100000.0])
|
|
complete_investment: float = Field(0.0, description="完成投资", examples=[80000.0])
|
|
|
|
# 其他信息
|
|
progress_type: ProgressType | None = Field(None, description="推进分类", examples=[ProgressType.A])
|
|
key_constraints: KeyConstraints = Field(KeyConstraints.NONE, description="关键制约", examples=[KeyConstraints.NONE])
|
|
key_constraints_remark: Optional[str] = Field("", description="关键制约备注", examples=["无"])
|
|
status: Optional[str] = Field(None, description="项目状态")
|
|
apply_file_ids: List[str] = Field(default_factory=list, description="申请表附件ID列表", examples=[[]])
|
|
|
|
# 拓展信息
|
|
dbtc_score_list: Optional[list] = Field(default_factory=list, description='达标投产评分列表') # 这里项目用的是list而不是List
|
|
|
|
|
|
|
|
class ProjectResponseBaseList(BaseModel):
|
|
page: int
|
|
page_size: int
|
|
total: int
|
|
list: List[ProjectResponseBase] = []
|
|
|
|
|
|
|
|
|
|
# ==================== Update ====================
|
|
|
|
class KeyConstraintsRemarkMixin:
|
|
"""关键制约备注校验混入类"""
|
|
|
|
@field_validator("key_constraints_remark")
|
|
def validate_key_constraints_remark(cls, v):
|
|
if v is None:
|
|
return v
|
|
if len(v) > 500:
|
|
raise HTTPException(detail="关键制约备注不能超过500个字符", status_code=400)
|
|
return v
|
|
|
|
class AuthorizationDateMixin:
|
|
"""关键制约备注校验混入类"""
|
|
|
|
@field_validator("authorization_date")
|
|
def validate_actual_date(cls, v):
|
|
if v is None:
|
|
return v
|
|
if v > get_current_date():
|
|
raise HTTPException(detail='核准/备案日期不能大于今天', status_code=400)
|
|
return v
|
|
|
|
class ProjectBaseInfoUpdate(BaseModel, KeyConstraintsRemarkMixin, AuthorizationDateMixin):
|
|
"""
|
|
项目基本信息 PROJECT_BASE_INFO
|
|
"""
|
|
# 基础信息-允许更改
|
|
id: str = Field(..., description="项目id", examples=["uuid"])
|
|
address: str | None = Field(None, description="项目地址", examples=["某省某市某区"])
|
|
code: str | None = Field(None, description="项目编码", examples=["XM2025001"])
|
|
name: str = Field(..., description="项目名称", examples=["XX新能源项目"])
|
|
short_name: str | None = Field(None, description="项目简称", examples=["XX项目"])
|
|
manager_name: str | None = Field(None, description="负责人姓名", examples=["张三"])
|
|
manager_phone: str | None = Field(None, description="负责人电话", examples=["13800000000"])
|
|
# 其他信息
|
|
progress_type: ProgressType = Field(..., description="推进分类", examples=[ProgressType.A])
|
|
key_constraints: KeyConstraints | None = Field(None, description="关键制约", examples=[KeyConstraints.NONE])
|
|
key_constraints_remark: str | None = Field(None, description="关键制约备注", examples=["无"])
|
|
apply_file_ids: List[str] | None = Field(None, description="申请表附件ID列表", examples=[[]])
|
|
# 拓展信息
|
|
dbtc_score_list: list[DBTCSCORE] | None = Field(None, description='达标投产评分列表') # 这里项目用的是list而不是List
|
|
|
|
# 核准
|
|
authorization_date: DateStr | None = Field(None, description="核准日期", examples=["2024-01-01"])
|
|
authorized_capacity: float | None = Field(None, description="核准容量(万千瓦)", examples=[10.0])
|
|
|
|
|
|
|
|
class _ProductionPlanNode(BaseModel):
|
|
year: int = Field(..., description="计划年份", examples=[2024])
|
|
capacity: float = Field(..., description="确保投产容量", examples=[3.0])
|
|
|
|
class ProjectEnsureCapacity(BaseModel):
|
|
"""
|
|
PROJECT_ENSURE_CAPACITY
|
|
填写项目确保投产容量列表,系统根据列表自动计算ensure_production_capacity字段
|
|
"""
|
|
# 确保投产容量
|
|
ensure_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="确保投产容量列表(每次必须填写全部)")
|
|
|
|
class ProjectClimbCapacity(BaseModel):
|
|
"""
|
|
PROJECT_CLIMB_CAPACITY
|
|
填写项目登高投产容量列表,系统根据列表自动计算climb_production_capacity字段
|
|
"""
|
|
# 登高投产容量
|
|
climb_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="登高投产容量列表(每次必须填写全部)")
|
|
class ProjectChallengeCapacity(BaseModel):
|
|
"""
|
|
PROJECT_CHALLENGE_CAPACITY
|
|
填写项目揭榜投产容量列表,系统根据列表自动计算challenge_production_capacity字段
|
|
"""
|
|
# 揭榜投产容量
|
|
challenge_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="揭榜投产容量列表(每次必须填写全部)")
|
|
|
|
|
|
|
|
class _ActualNodeData(BaseModel):
|
|
capacity: float = Field(..., description="实际节点容量", examples=[4.0])
|
|
date: DateStr = Field(..., description="实际节点日期", examples=["2024-04-01"])
|
|
class ProjectActualConstruction(BaseModel):
|
|
"""
|
|
PROJECT_ACTUAL_CONSTRUCTION
|
|
项目实际开工节点
|
|
|
|
系统根据实际开工节点自动计算以下字段:
|
|
actual_construction_capacity 本年度实际开工容量
|
|
actual_construction_date 本年度实际开工日期
|
|
accumulated_construction_capacity 累计开工容量
|
|
constructing_capacity 在建容量
|
|
"""
|
|
actual_construction_list : list[_ActualNodeData] | None = Field(None, description="实际开工节点列表(每次必须填写全部)")
|
|
|
|
class _PlanNodeData(BaseModel):
|
|
capacity: float = Field(..., description="计划节点容量", examples=[5.0])
|
|
date: DateStr = Field(..., description="本年度计日期", examples=["2024-03-01"])
|
|
|
|
@field_validator("capacity")
|
|
def validate_capacity(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="节点容量必须大于等于0")
|
|
return v
|
|
|
|
class ProjectPlanConstruction(BaseModel):
|
|
"""
|
|
PROJECT_PLAN_CONSTRUCTION
|
|
项目计划开工节点
|
|
|
|
系统根据计划开工节点自动计算:
|
|
plan_construction_capacity 本年度计划开工容量
|
|
plan_construction_date 本年度计划开工日期
|
|
"""
|
|
plan_construction_list : list[_PlanNodeData] | None = Field(None, description="计划开工节点列表(每次必须填写全部)")
|
|
|
|
class ProjectInvestmentDecision(BaseModel):
|
|
"""
|
|
PROJECT_INVESTMENT_DECISION
|
|
投资决策容量和日期
|
|
"""
|
|
investment_decision_capacity: float = Field(..., description="投资决策容量", examples=[8.0])
|
|
investment_decision_date: DateStr = Field(..., description="投资决策日期", examples=["2024-02-01"])
|
|
|
|
@field_validator("investment_decision_date")
|
|
def validate_investment_decision_date(cls, v):
|
|
if v is None:
|
|
return v
|
|
if v > get_current_date():
|
|
raise HTTPException(detail='投资决策日期不能大于今天', status_code=400)
|
|
return v
|
|
@field_validator("investment_decision_capacity")
|
|
def validate_investment_decision_capacity(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="投资决策容量必须大于等于0")
|
|
return v
|
|
|
|
class ProjectKeyConstraints(BaseModel, KeyConstraintsRemarkMixin):
|
|
"""
|
|
PROJECT_KEY_CONSTRAINTS
|
|
关键制约
|
|
"""
|
|
key_constraints: KeyConstraints | None = Field(None, description="关键制约", examples=[KeyConstraints.NONE])
|
|
key_constraints_remark: str | None = Field(None, description="关键制约备注", examples=["无"])
|
|
|
|
class _ActualProductionNode(BaseModel):
|
|
capacity: float = Field(..., description="实际投产容量", examples=[2.0])
|
|
date: DateStr = Field(..., description="实际投产日期", examples=["2024-08-15"])
|
|
|
|
@field_validator("capacity")
|
|
def validate_capacity(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="实际投产容量必须大于等于0")
|
|
return v
|
|
|
|
@field_validator("date")
|
|
def validate_date(cls, v):
|
|
if v is None:
|
|
return v
|
|
if v > get_current_date():
|
|
raise HTTPException(detail='实际投产日期不能大于今天', status_code=400)
|
|
return v
|
|
|
|
class ProjectProductionCapacity(BaseModel):
|
|
"""
|
|
PROJECT_PRODUCTION_CAPACITY
|
|
填写项目投产数据
|
|
每个项目在各年份或一年内可能有多次实际投产
|
|
系统会根据投产节点列表数据,自动计算
|
|
production_capacity 本年度投产容量
|
|
production_date 本年度首批投产日期
|
|
total_production_capacity 全部投产容量
|
|
"""
|
|
plan_production_date: DateStr | None = Field(None, description="集团公司计划投产日期", examples=["2024-08-01"])
|
|
plan_full_production_date: DateStr | None = Field(None, description="集团公司计划全部投产日期", examples=["2024-09-01"])
|
|
ic_plan_first_production_date: DateStr | None = Field(None, description="区域公司计划首批投产日期(只有新能源需要)",examples=["2024-08-01"])
|
|
ic_plan_full_production_date: DateStr | None = Field(None, description="区域公司计划全投日期(只有新能源需要)",examples=["2024-09-01"])
|
|
actual_production_date: DateStr | None = Field(None, description="实际投产日期(只有新能源需要)", examples=["2024-08-15"])
|
|
actual_full_production_date: DateStr | None = Field(None, description="实际全投日期(只有新能源需要)", examples=["2024-09-10"])
|
|
actual_production_list : list[_ActualProductionNode] | None = Field(None, description="实际投产节点列表(每次必须填写全部)(只有新能源需要)")
|
|
@field_validator("actual_production_date")
|
|
def validate_actual_production_date(cls, v):
|
|
if v is None:
|
|
return v
|
|
if v > get_current_date():
|
|
raise HTTPException(detail='实际投产日期不能大于今天', status_code=400)
|
|
return v
|
|
|
|
@field_validator("actual_full_production_date")
|
|
def validate_actual_full_production_date(cls, v):
|
|
if v is None:
|
|
return v
|
|
if v > get_current_date():
|
|
raise HTTPException(detail='实际全投日期不能大于今天', status_code=400)
|
|
return v
|
|
|
|
class ProjectCompleteInvestment(BaseModel):
|
|
"""
|
|
PROJECT_COMPLETE_INVESTMENT
|
|
完成投资投资
|
|
"""
|
|
|
|
complete_investment: float = Field(..., description="完成投资", examples=[80000.0])
|
|
|
|
@field_validator("complete_investment")
|
|
def validate_complete_investment(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400,detail="完成投资必须大于等于0")
|
|
return v
|
|
|
|
class ProjectSettlementInvestment(BaseModel):
|
|
"""
|
|
PROJECT_SETTLEMENT_INVESTMENT
|
|
合同结算投资情况
|
|
只有抽蓄-水电-煤电-气电项目类型可操作
|
|
"""
|
|
|
|
implementation_estimate: float = Field(..., description="执行概算", examples=[80000.0])
|
|
static_total_investment: float = Field(..., description="静态总投资", examples=[80000.0])
|
|
completed_investment: float = Field(..., description="完成投资", examples=[80000.0])
|
|
dynamic_investment: float = Field(..., description="动态总投资", examples=[80000.0])
|
|
|
|
@field_validator("implementation_estimate")
|
|
def validate_implementation_estimate(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400,detail="执行概算必须大于等于0")
|
|
return v
|
|
|
|
@field_validator("static_total_investment")
|
|
def validate_static_total_investment(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="静态总投资必须大于等于0")
|
|
return v
|
|
|
|
@field_validator("completed_investment")
|
|
def validate_completed_investment(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="完成投资必须大于等于0")
|
|
return v
|
|
|
|
@field_validator("dynamic_investment")
|
|
def validate_dynamic_investment(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="动态总投资必须大于等于0")
|
|
return v
|
|
|
|
class ProjectDynamicInvestment(BaseModel):
|
|
"""
|
|
PROJECT_DYNAMIC_INVESTMENT
|
|
"""
|
|
# 动态总投资
|
|
dynamic_investment: float | None = Field(None, description="动态总投资", examples=[100000.0])
|
|
|
|
@field_validator("dynamic_investment")
|
|
def validate_dynamic_investment(cls, v: float) -> float:
|
|
if v < 0:
|
|
raise HTTPException(status_code=400, detail="动态总投资必须大于等于0")
|
|
return v
|
|
|
|
# ======================= 水电抽蓄专用 =============================
|
|
|
|
|
|
# ==================== 枚举说明 用于文档自动生成 ====================
|
|
|