docs: 品牌全量口径统一为「南方基金」+ 作废文档清理
1) 客服 Agent 四份交付文档 + 构建脚手架:品牌由包装占位 XX科技 / 旧名 南方财富 统一为南方基金(热线 400-889-8899 / 官网 nffund.com),系统名改为「智能服务系统」; 同步追加 §0.4 修订记录行,工程记录行保留原占位字面以支撑硬编码扫描验收。 2) 开发文档:清理 28 份已作废/残留文档(14 份移出归档 + 14 份仓库副本), 新增《文档规整方案与开发前待决事项-2026-09-17》。 3) 客服agent 四份交付文档首次纳入本分支。
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""产品推介材料接口请求结构。"""
|
||||
|
||||
from datetime import date
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class StrictPayload(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
|
||||
class PromotionTaskCreate(StrictPayload):
|
||||
product_name: str = Field(min_length=1, max_length=128)
|
||||
product_code: str | None = Field(default=None, max_length=32)
|
||||
material_title: str = Field(min_length=1, max_length=200)
|
||||
style_code: str = Field(
|
||||
default="balanced_allocation",
|
||||
pattern="^(steady_professional|balanced_allocation|growth_research)$",
|
||||
)
|
||||
output_formats: list[str] = Field(default_factory=lambda: ["pptx"], min_length=1, max_length=2)
|
||||
|
||||
@field_validator("output_formats")
|
||||
@classmethod
|
||||
def validate_output_formats(cls, value: list[str]) -> list[str]:
|
||||
invalid = set(value) - {"pptx", "pdf", "poster"}
|
||||
if invalid:
|
||||
raise ValueError("输出格式只支持 pptx、pdf 或 poster")
|
||||
if len(set(value)) != len(value):
|
||||
raise ValueError("输出格式不能重复")
|
||||
return value
|
||||
|
||||
|
||||
class ProductInfo(StrictPayload):
|
||||
fund_type: str = Field(min_length=1, max_length=64)
|
||||
operation_mode: str = Field(min_length=1, max_length=64)
|
||||
product_status: str = Field(default="new_product", max_length=64)
|
||||
investment_objective: str = Field(min_length=1, max_length=2000)
|
||||
benchmark: str | None = Field(default=None, max_length=500)
|
||||
risk_level: str | None = Field(default=None, max_length=32)
|
||||
|
||||
|
||||
class ManagerInfo(StrictPayload):
|
||||
manager_name: str = Field(min_length=1, max_length=64)
|
||||
management_company: str = Field(min_length=1, max_length=128)
|
||||
registration_code: str = Field(min_length=1, max_length=64)
|
||||
employment_years: str | None = Field(default=None, max_length=64)
|
||||
investment_management_experience: str | None = Field(default=None, max_length=1000)
|
||||
profile: str | None = Field(default=None, max_length=3000)
|
||||
|
||||
|
||||
class TeamInfo(StrictPayload):
|
||||
team_description: str = Field(min_length=1, max_length=3000)
|
||||
research_capability: str | None = Field(default=None, max_length=2000)
|
||||
|
||||
|
||||
class StrategyInfo(StrictPayload):
|
||||
investment_scope: str = Field(min_length=1, max_length=3000)
|
||||
strategy: str = Field(min_length=1, max_length=3000)
|
||||
restrictions: str = Field(min_length=1, max_length=3000)
|
||||
index_tool_attribute: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class FeeStructure(StrictPayload):
|
||||
subscription_fee: str | None = Field(default=None, max_length=500)
|
||||
purchase_fee: str | None = Field(default=None, max_length=500)
|
||||
redemption_fee: str | None = Field(default=None, max_length=500)
|
||||
sales_service_fee: str | None = Field(default=None, max_length=500)
|
||||
management_fee: str | None = Field(default=None, max_length=500)
|
||||
custody_fee: str | None = Field(default=None, max_length=500)
|
||||
client_maintenance_fee: str | None = Field(default=None, max_length=500)
|
||||
|
||||
|
||||
class RankingInfo(StrictPayload):
|
||||
enabled: bool = False
|
||||
institution_name: str | None = Field(default=None, max_length=128)
|
||||
evaluation_period_years: str | None = Field(default=None, max_length=32)
|
||||
ranking_text: str | None = Field(default=None, max_length=1000)
|
||||
public_source: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class PerformanceInfo(StrictPayload):
|
||||
as_of_date: date | None = None
|
||||
history_months: int | None = Field(default=None, ge=0, le=600)
|
||||
product_return: str | None = Field(default=None, max_length=64)
|
||||
max_drawdown: str | None = Field(default=None, max_length=64)
|
||||
volatility: str | None = Field(default=None, max_length=64)
|
||||
sharpe_ratio: str | None = Field(default=None, max_length=64)
|
||||
show_product_performance: bool = False
|
||||
show_manager_performance: bool = False
|
||||
ranking: RankingInfo = Field(default_factory=RankingInfo)
|
||||
|
||||
|
||||
class RiskDisclosure(StrictPayload):
|
||||
special_risks: list[str] = Field(default_factory=list, max_length=20)
|
||||
additional_notes: str | None = Field(default=None, max_length=2000)
|
||||
|
||||
|
||||
class PromotionInputsUpdate(StrictPayload):
|
||||
product_info: ProductInfo
|
||||
manager_info: ManagerInfo
|
||||
team_info: TeamInfo
|
||||
strategy_info: StrategyInfo
|
||||
fee_structure: FeeStructure
|
||||
performance_info: PerformanceInfo
|
||||
risk_disclosure: RiskDisclosure = Field(default_factory=RiskDisclosure)
|
||||
source_notes: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class PromotionGenerationRequest(StrictPayload):
|
||||
output_formats: list[str] | None = Field(default=None, min_length=1, max_length=2)
|
||||
|
||||
@field_validator("output_formats")
|
||||
@classmethod
|
||||
def validate_generation_formats(cls, value: list[str] | None) -> list[str] | None:
|
||||
if value is None:
|
||||
return value
|
||||
if set(value) - {"pptx", "pdf", "poster"} or len(set(value)) != len(value):
|
||||
raise ValueError("输出格式只支持不重复的 pptx、pdf 或 poster")
|
||||
return value
|
||||
|
||||
|
||||
class PromotionReviewRequest(StrictPayload):
|
||||
material_version_id: int = Field(gt=0)
|
||||
decision: str = Field(pattern="^(approved|rejected|revision_requested)$")
|
||||
comment: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class PromotionDeliveryRequest(StrictPayload):
|
||||
material_version_id: int = Field(gt=0)
|
||||
advisor_ids: list[int] = Field(min_length=1, max_length=100)
|
||||
delivery_channel: str = Field(default="internal_record", max_length=32)
|
||||
Reference in New Issue
Block a user