1) 客服 Agent 四份交付文档 + 构建脚手架:品牌由包装占位 XX科技 / 旧名 南方财富 统一为南方基金(热线 400-889-8899 / 官网 nffund.com),系统名改为「智能服务系统」; 同步追加 §0.4 修订记录行,工程记录行保留原占位字面以支撑硬编码扫描验收。 2) 开发文档:清理 28 份已作废/残留文档(14 份移出归档 + 14 份仓库副本), 新增《文档规整方案与开发前待决事项-2026-09-17》。 3) 客服agent 四份交付文档首次纳入本分支。
397 lines
24 KiB
Python
397 lines
24 KiB
Python
"""场内基金模拟交易域(fin_*)只读 ORM 映射。
|
||
|
||
设计约定(强约束):
|
||
|
||
1. 本模块只做「列映射」:不提供任何写辅助方法(无 insert/update/delete/save/merge),
|
||
底座、Agent 与业务组员都不得借本模块下单、改持仓或改交易数据(项目硬性业务红线)。
|
||
2. 列名、类型、可空性严格对齐 MySQL 实际结构(information_schema.COLUMNS 逐列核对),
|
||
不允许任何 DDL / Alembic 迁移改动库结构;回归校验由 tools/audit_constraints.py 负责。
|
||
3. 不声明 ForeignKey:跨表关系由 app/repository/fund_query_repository.py 的
|
||
客户数据范围解析器表达,避免 ORM 引入 flush 期级联写语义。
|
||
4. 未映射 MySQL 生成列(GENERATION_EXPRESSION 非空)——本域当前没有生成列。
|
||
5. 只读查询统一走 app/repository/fund_query_repository.py,Agent(Service 层)
|
||
不得直接访问本模块的 ORM 实体。
|
||
"""
|
||
|
||
from datetime import date, datetime
|
||
from decimal import Decimal
|
||
from typing import Any
|
||
|
||
from sqlalchemy import JSON, Date, Integer, Numeric, String, Text
|
||
from sqlalchemy.dialects.mysql import BIGINT, DATETIME, TINYINT
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.model.base import Base
|
||
|
||
__all__ = [
|
||
"FundCapitalFlow",
|
||
"FundCashLedger",
|
||
"FundCustomerProfile",
|
||
"FundFeeRule",
|
||
"FundHolding",
|
||
"FundMarketPrice",
|
||
"FundNavHistory",
|
||
"FundProduct",
|
||
"FundRiskAlert",
|
||
"FundRiskAssessment",
|
||
"FundRiskNotification",
|
||
"FundSimAccount",
|
||
"FundSimOrder",
|
||
"FundTransaction",
|
||
]
|
||
|
||
|
||
class FundProduct(Base):
|
||
"""场内基金产品主数据(fin_product)。"""
|
||
|
||
__tablename__ = "fin_product"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
product_code: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
product_name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||
exchange_code: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
product_category: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
risk_level: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
fund_manager: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||
currency: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
lot_size: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
price_tick: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
current_nav: Mapped[Decimal | None] = mapped_column(Numeric(18, 6), nullable=True)
|
||
current_nav_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
min_amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
open_start_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
open_end_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
open_period_start: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||
open_period_end: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||
transaction_fee_rate: Mapped[Decimal | None] = mapped_column(Numeric(10, 6), nullable=True)
|
||
single_investor_max_holding_ratio: Mapped[Decimal] = mapped_column(
|
||
Numeric(7, 4), nullable=False
|
||
)
|
||
management_fee_rate: Mapped[Decimal | None] = mapped_column(Numeric(7, 4), nullable=True)
|
||
custodian_fee_rate: Mapped[Decimal | None] = mapped_column(Numeric(7, 4), nullable=True)
|
||
risk_disclosure_required: Mapped[int] = mapped_column(TINYINT(display_width=1), nullable=False)
|
||
second_confirmation_required: Mapped[int] = mapped_column(
|
||
TINYINT(display_width=1), nullable=False
|
||
)
|
||
recording_required: Mapped[int] = mapped_column(TINYINT(display_width=1), nullable=False)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundMarketPrice(Base):
|
||
"""场内日行情(fin_market_price),行情为公共数据,无客户归属。"""
|
||
|
||
__tablename__ = "fin_market_price"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
product_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
trade_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||
open_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
high_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
low_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
close_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
#: 当日涨跌幅(%),来自行情源。**可空**:源未提供、或该行由不提供涨跌幅的降级路径
|
||
#: (如 `eastmoney_nav_fallback`)写入时为 NULL —— 调用方必须显示"暂无"而不是当成 0。
|
||
change_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4), nullable=True)
|
||
volume: Mapped[Decimal | None] = mapped_column(Numeric(24, 4), nullable=True)
|
||
turnover_amount: Mapped[Decimal | None] = mapped_column(Numeric(24, 2), nullable=True)
|
||
total_fund_shares: Mapped[Decimal] = mapped_column(Numeric(24, 4), nullable=False)
|
||
source: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
source_updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundNavHistory(Base):
|
||
"""基金净值历史(fin_nav_history),公共数据。"""
|
||
|
||
__tablename__ = "fin_nav_history"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
product_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
nav_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||
nav: Mapped[Decimal] = mapped_column(Numeric(12, 6), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundSimAccount(Base):
|
||
"""模拟资金账户(fin_sim_account)。"""
|
||
|
||
__tablename__ = "fin_sim_account"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
account_no: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
currency: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
cash_balance: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
available_cash: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
frozen_cash: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
initial_balance: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
version: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundCashLedger(Base):
|
||
"""资金流水(fin_cash_ledger)。无 customer_id,客户归属经 account_id 间接解析。"""
|
||
|
||
__tablename__ = "fin_cash_ledger"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
ledger_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
account_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
transaction_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
entry_type: Mapped[str] = mapped_column(String(24), nullable=False)
|
||
amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
balance_after: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
available_cash_after: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
frozen_cash_after: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
idempotency_key: Mapped[str] = mapped_column(String(128), nullable=False)
|
||
occurred_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundCapitalFlow(Base):
|
||
"""资金划转/出入金流水(fin_capital_flow)。"""
|
||
|
||
__tablename__ = "fin_capital_flow"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
flow_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
account_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
transaction_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
flow_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
balance_after: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
settled_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
occurred_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
payer_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||
source_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
related_work_order_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
match_status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundFeeRule(Base):
|
||
"""费率规则(fin_fee_rule),配置型公共数据。"""
|
||
|
||
__tablename__ = "fin_fee_rule"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
rule_code: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
product_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
exchange_code: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||
order_side: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
customer_tier: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||
min_trade_amount: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
max_trade_amount: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
fee_rate: Mapped[Decimal] = mapped_column(Numeric(10, 6), nullable=False)
|
||
minimum_fee: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
fixed_fee: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
priority: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
effective_from: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
effective_until: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundSimOrder(Base):
|
||
"""模拟委托单(fin_sim_order)。只读查询,禁止在此写入委托。"""
|
||
|
||
__tablename__ = "fin_sim_order"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
order_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
account_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
product_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
order_side: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
price_type: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
limit_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 6), nullable=True)
|
||
quote_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
quote_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
quote_source: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
channel: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||
advisor_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
filled_quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
average_executed_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 6), nullable=True)
|
||
status: Mapped[str] = mapped_column(String(24), nullable=False)
|
||
risk_rule_hits: Mapped[Any | None] = mapped_column(JSON, nullable=True)
|
||
risk_disclosure_ack_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
second_confirmation_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
recording_reference: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||
ops_handler_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
ops_handled_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
compliance_handler_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
compliance_handled_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
reject_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
submitted_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
cancelled_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundTransaction(Base):
|
||
"""成交记录(fin_transaction)。只读查询,禁止在此写入成交。"""
|
||
|
||
__tablename__ = "fin_transaction"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
transaction_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
order_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
work_order_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
account_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
product_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
order_side: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
transaction_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
executed_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
nav: Mapped[Decimal] = mapped_column(Numeric(12, 6), nullable=False)
|
||
executed_quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
shares: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
gross_amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
fee_rule_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
fee_rate_snapshot: Mapped[Decimal] = mapped_column(Numeric(10, 6), nullable=False)
|
||
fee_amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
fee: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
net_amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
quote_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
quote_source: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
executed_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
confirmed_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
confirmed_by: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||
auto_confirmed: Mapped[int] = mapped_column(TINYINT(display_width=1), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundHolding(Base):
|
||
"""持仓(fin_holding)。只读查询,禁止在此修改持仓。"""
|
||
|
||
__tablename__ = "fin_holding"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
trade_account: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
product_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
total_quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
shares: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
available_quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
frozen_quantity: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
|
||
average_cost: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False)
|
||
cost_amount: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
market_value: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
current_value: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
profit_loss: Mapped[Decimal | None] = mapped_column(Numeric(18, 2), nullable=True)
|
||
profit_loss_ratio: Mapped[Decimal | None] = mapped_column(Numeric(10, 4), nullable=True)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
first_acquired_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
version: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundCustomerProfile(Base):
|
||
"""客户画像(fin_customer_profile),主键为 customer_id。"""
|
||
|
||
__tablename__ = "fin_customer_profile"
|
||
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
trade_account: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
real_name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
birth_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||
occupation: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||
mobile_masked: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||
investor_type: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
investment_horizon: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||
preferred_asset_class: Mapped[Any | None] = mapped_column(JSON, nullable=True)
|
||
trading_frequency: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||
last_active_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
total_asset: Mapped[Decimal] = mapped_column(Numeric(18, 2), nullable=False)
|
||
behavior_score: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
risk_tags: Mapped[Any | None] = mapped_column(JSON, nullable=True)
|
||
opened_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundRiskAssessment(Base):
|
||
"""风险测评记录(fin_risk_assessment)。"""
|
||
|
||
__tablename__ = "fin_risk_assessment"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
questionnaire_version: Mapped[str] = mapped_column(String(32), nullable=False)
|
||
answers: Mapped[Any] = mapped_column(JSON, nullable=False)
|
||
total_score: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
investor_type: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
assessed_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
valid_until: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundRiskAlert(Base):
|
||
"""风险预警事件(fin_risk_alert)。"""
|
||
|
||
__tablename__ = "fin_risk_alert"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
alert_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
customer_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
related_transaction_id: Mapped[int | None] = mapped_column(
|
||
BIGINT(unsigned=True), nullable=True
|
||
)
|
||
related_order_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
related_work_order_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
primary_risk_work_order_id: Mapped[int | None] = mapped_column(
|
||
BIGINT(unsigned=True), nullable=True
|
||
)
|
||
alert_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
alert_level: Mapped[str] = mapped_column(String(8), nullable=False)
|
||
trigger_rule_codes: Mapped[Any] = mapped_column(JSON, nullable=False)
|
||
evidence_summary: Mapped[str] = mapped_column(Text, nullable=False)
|
||
evidence_snapshot: Mapped[Any] = mapped_column(JSON, nullable=False)
|
||
priority_score: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
event_status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
ack_status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
ack_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
handler_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
due_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
is_escalated: Mapped[int] = mapped_column(TINYINT(display_width=1), nullable=False)
|
||
escalated_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
escalation_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
handle_result: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
closed_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
close_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
ai_analysis: Mapped[Any | None] = mapped_column(JSON, nullable=True)
|
||
manual_remark: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
updated_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|
||
|
||
|
||
class FundRiskNotification(Base):
|
||
"""风险通知(fin_risk_notification)。无 customer_id,客户归属经 alert_id 间接解析。"""
|
||
|
||
__tablename__ = "fin_risk_notification"
|
||
|
||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||
notification_no: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
alert_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), nullable=False)
|
||
channel: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
receiver_user_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True), nullable=True)
|
||
receiver_email: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||
title: Mapped[str] = mapped_column(String(128), nullable=False)
|
||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||
send_status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||
sent_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
read_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
acknowledged_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=0), nullable=True)
|
||
fail_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DATETIME(fsp=0), nullable=False)
|