Initial commit: InternalAuditInterprise
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
"""线索 ORM 模型。
|
||||
|
||||
对应需求 R7(线索+证据链+解释)、R17(闭环状态)、R18(置信度分级)、R19(线索不可删)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as dt
|
||||
import enum
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import DateTime, Enum, Float, ForeignKey, Index, String, Text
|
||||
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.db import Base
|
||||
|
||||
|
||||
def _enum_values(enum_cls):
|
||||
"""让 SQLAlchemy 使用枚举的 value(小写)写入 PG 原生 enum,而非 name。"""
|
||||
return [m.value for m in enum_cls]
|
||||
|
||||
|
||||
def _uuid() -> uuid.UUID:
|
||||
return uuid.uuid4()
|
||||
|
||||
|
||||
def _now() -> dt.datetime:
|
||||
return dt.datetime.now(dt.UTC)
|
||||
|
||||
|
||||
class ConfidenceTier(str, enum.Enum):
|
||||
"""置信度三级分流(R18)。"""
|
||||
|
||||
HIGH = "high" # 高置信:直接推送处置
|
||||
MEDIUM = "medium" # 中置信:人工复核
|
||||
LOW = "low" # 低置信:归档备查
|
||||
|
||||
|
||||
class ClueStatus(str, enum.Enum):
|
||||
"""线索闭环状态机(R17)。"""
|
||||
|
||||
NEW = "new" # 新生成
|
||||
ASSIGNED = "assigned" # 已分派
|
||||
REVIEWING = "reviewing" # 研判中
|
||||
CONFIRMED = "confirmed" # 已定性属实
|
||||
DISMISSED = "dismissed" # 已定性误报
|
||||
RECTIFYING = "rectifying" # 整改中
|
||||
TRANSFERRED = "transferred" # 已移交
|
||||
CLOSED = "closed" # 已销项闭环
|
||||
|
||||
|
||||
class Clue(Base):
|
||||
"""审计线索。线索一经生成不可物理删除(R19),失效通过状态表达。"""
|
||||
|
||||
__tablename__ = "clue"
|
||||
__table_args__ = (
|
||||
Index("ix_clue_status", "status"),
|
||||
Index("ix_clue_scenario", "scenario_code"),
|
||||
Index("ix_clue_assignee", "assignee"),
|
||||
)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
|
||||
title: Mapped[str] = mapped_column(String(256), nullable=False)
|
||||
risk_domain: Mapped[str] = mapped_column(String(32), nullable=False) # 收入/成本/采购/资金/合规
|
||||
scenario_code: Mapped[str] = mapped_column(String(32), nullable=False) # 如 R8/R9
|
||||
confidence: Mapped[ConfidenceTier] = mapped_column(
|
||||
Enum(ConfidenceTier, name="confidence_tier", values_callable=_enum_values),
|
||||
nullable=False,
|
||||
)
|
||||
score: Mapped[float] = mapped_column(Float, default=0.0) # 0-1 风险评分
|
||||
status: Mapped[ClueStatus] = mapped_column(
|
||||
Enum(ClueStatus, name="clue_status", values_callable=_enum_values),
|
||||
default=ClueStatus.NEW,
|
||||
nullable=False,
|
||||
)
|
||||
# 人话解释(判定理由)与证据链
|
||||
rationale: Mapped[str] = mapped_column(Text, default="")
|
||||
evidence: Mapped[dict] = mapped_column(JSONB, default=dict)
|
||||
# 涉及的主体(金额、实体 id 列表等)
|
||||
subjects: Mapped[dict] = mapped_column(JSONB, default=dict)
|
||||
amount_involved: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
|
||||
assignee: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
# 误报/属实反馈(R18 反馈学习)
|
||||
feedback: Mapped[str | None] = mapped_column(String(16), nullable=True) # confirmed/false_positive
|
||||
|
||||
# 可追溯:产生该线索时的模型/规则/数据版本(R19 三重留痕)
|
||||
model_version: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
rule_version: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), nullable=True)
|
||||
|
||||
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
|
||||
updated_at: Mapped[dt.datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=_now, onupdate=_now
|
||||
)
|
||||
|
||||
history: Mapped[list[ClueStatusHistory]] = relationship(
|
||||
back_populates="clue", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class ClueStatusHistory(Base):
|
||||
"""线索状态流转留痕(R17/R19)。"""
|
||||
|
||||
__tablename__ = "clue_status_history"
|
||||
__table_args__ = (Index("ix_csh_clue", "clue_id"),)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
|
||||
clue_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), ForeignKey("clue.id"), nullable=False
|
||||
)
|
||||
from_status: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||||
to_status: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
actor: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
|
||||
|
||||
clue: Mapped[Clue] = relationship(back_populates="history")
|
||||
|
||||
|
||||
class WorkingPaper(Base):
|
||||
"""审计底稿(R17):研判完成自动生成,可追溯。"""
|
||||
|
||||
__tablename__ = "working_paper"
|
||||
__table_args__ = (Index("ix_wp_clue", "clue_id"),)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
|
||||
clue_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), ForeignKey("clue.id"), nullable=False
|
||||
)
|
||||
content: Mapped[str] = mapped_column(Text, default="")
|
||||
conclusion: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||||
author: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
snapshot: Mapped[dict] = mapped_column(JSONB, default=dict) # 证据/版本快照
|
||||
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
|
||||
Reference in New Issue
Block a user