2026-11-01 20:42:53 -05:00
|
|
|
"""T+ 基础导入与试算的隔离工作区,任何表均不关联正式工资台账。"""
|
|
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import JSON, DateTime, Index, Integer, String, UniqueConstraint
|
|
|
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
|
|
|
|
|
|
from app.models.base import BIGINT_UNSIGNED, Base, TimestampMixin, mysql_table_args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TPlusSourceHead(Base):
|
|
|
|
|
"""一次完整读取实际观察到的源版本;解决 A→B→A 去重后的旧版本误选。"""
|
|
|
|
|
|
|
|
|
|
__tablename__ = "tplus_source_heads"
|
|
|
|
|
__table_args__ = mysql_table_args(
|
|
|
|
|
"T+ 源当前快照指针(按成功全量批次读取,删除不自动回写业务表)",
|
|
|
|
|
UniqueConstraint(
|
|
|
|
|
"source_database",
|
|
|
|
|
"entity_type",
|
|
|
|
|
"source_id",
|
|
|
|
|
name="uk_tplus_source_heads_source_entity_id",
|
|
|
|
|
),
|
|
|
|
|
Index("idx_tplus_source_heads_batch_entity", "batch_no", "entity_type"),
|
2026-11-05 05:47:13 -05:00
|
|
|
Index("idx_tplus_source_heads_parent", "source_database", "entity_type", "source_parent_id"),
|
|
|
|
|
Index("idx_tplus_source_heads_customer_date", "source_database", "entity_type", "source_customer_id", "source_date"),
|
|
|
|
|
Index("idx_tplus_source_heads_date", "source_database", "entity_type", "source_date", "id"),
|
2026-11-01 20:42:53 -05:00
|
|
|
)
|
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
|
|
|
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
|
|
|
|
)
|
|
|
|
|
source_database: Mapped[str] = mapped_column(String(128), comment="源账套")
|
|
|
|
|
entity_type: Mapped[str] = mapped_column(String(32), comment="实体类型")
|
|
|
|
|
source_id: Mapped[str] = mapped_column(String(64), comment="源内部ID")
|
|
|
|
|
record_id: Mapped[int] = mapped_column(BIGINT_UNSIGNED, comment="原始快照ID")
|
2026-11-05 05:47:13 -05:00
|
|
|
source_parent_id: Mapped[str | None] = mapped_column(String(64), comment="源父单据ID查询投影")
|
|
|
|
|
source_customer_id: Mapped[str | None] = mapped_column(String(64), comment="源客户ID查询投影")
|
|
|
|
|
source_date: Mapped[str | None] = mapped_column(String(10), comment="源业务日期查询投影")
|
2026-11-01 20:42:53 -05:00
|
|
|
batch_no: Mapped[str] = mapped_column(String(32), comment="最后观察批次")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TPlusFact(Base, TimestampMixin):
|
|
|
|
|
"""补充资料追加版本,旧版本永久保留,乐观锁防止静默覆盖。"""
|
|
|
|
|
|
|
|
|
|
__tablename__ = "tplus_facts"
|
|
|
|
|
__table_args__ = mysql_table_args(
|
|
|
|
|
"T+ 人工补充事实版本表",
|
|
|
|
|
UniqueConstraint(
|
|
|
|
|
"source_database",
|
|
|
|
|
"kind",
|
|
|
|
|
"fact_key",
|
|
|
|
|
"version",
|
|
|
|
|
name="uk_tplus_facts_source_kind_key_version",
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
|
|
|
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
|
|
|
|
)
|
|
|
|
|
source_database: Mapped[str] = mapped_column(String(128), comment="源账套")
|
|
|
|
|
kind: Mapped[str] = mapped_column(String(32), comment="事实类别")
|
|
|
|
|
fact_key: Mapped[str] = mapped_column(String(128), comment="事实业务键")
|
|
|
|
|
version: Mapped[int] = mapped_column(Integer, comment="版本号")
|
|
|
|
|
data_json: Mapped[dict] = mapped_column(JSON, comment="经校验的事实内容")
|
|
|
|
|
evidence: Mapped[str] = mapped_column(String(500), comment="依据和修改原因")
|
|
|
|
|
requested_by: Mapped[int] = mapped_column(BIGINT_UNSIGNED, comment="操作者ID")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TPlusSourceLink(Base, TimestampMixin):
|
|
|
|
|
"""源稳定身份与业务目标的唯一关联;不按名称猜测合并。"""
|
|
|
|
|
|
|
|
|
|
__tablename__ = "tplus_source_links"
|
|
|
|
|
__table_args__ = mysql_table_args(
|
|
|
|
|
"T+ 基础数据源目标关联",
|
|
|
|
|
UniqueConstraint(
|
|
|
|
|
"source_database",
|
|
|
|
|
"entity_type",
|
|
|
|
|
"source_id",
|
|
|
|
|
name="uk_tplus_source_links_source_entity_id",
|
|
|
|
|
),
|
|
|
|
|
UniqueConstraint("entity_type", "target_id", name="uk_tplus_source_links_entity_target"),
|
|
|
|
|
)
|
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
|
|
|
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
|
|
|
|
)
|
|
|
|
|
source_database: Mapped[str] = mapped_column(String(128), comment="源账套")
|
|
|
|
|
entity_type: Mapped[str] = mapped_column(String(32), comment="实体类型")
|
|
|
|
|
source_id: Mapped[str] = mapped_column(String(64), comment="源内部ID")
|
|
|
|
|
target_id: Mapped[int] = mapped_column(BIGINT_UNSIGNED, comment="业务目标ID")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TPlusWorkRun(Base, TimestampMixin):
|
|
|
|
|
"""后台导入、预览和试算运行记录,固定输入,保留终态。"""
|
|
|
|
|
|
|
|
|
|
__tablename__ = "tplus_work_runs"
|
|
|
|
|
__table_args__ = mysql_table_args(
|
|
|
|
|
"T+ 导入与预演运行表",
|
|
|
|
|
UniqueConstraint("run_no", name="uk_tplus_work_runs_run_no"),
|
|
|
|
|
UniqueConstraint("request_key", name="uk_tplus_work_runs_request_key"),
|
|
|
|
|
Index("idx_tplus_work_runs_status_id", "status", "id"),
|
|
|
|
|
)
|
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
|
|
|
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
|
|
|
|
)
|
|
|
|
|
run_no: Mapped[str] = mapped_column(String(32), comment="运行编号")
|
|
|
|
|
request_key: Mapped[str] = mapped_column(String(36), comment="请求幂等键")
|
|
|
|
|
kind: Mapped[str] = mapped_column(
|
|
|
|
|
String(32), comment="MASTER_PREVIEW/MASTER_APPLY/CALC_PREVIEW"
|
|
|
|
|
)
|
|
|
|
|
status: Mapped[str] = mapped_column(String(16), default="QUEUED", comment="运行状态")
|
|
|
|
|
source_database: Mapped[str] = mapped_column(String(128), comment="固定源账套")
|
|
|
|
|
requested_by: Mapped[int] = mapped_column(BIGINT_UNSIGNED, comment="操作者ID")
|
|
|
|
|
input_json: Mapped[dict] = mapped_column(JSON, comment="请求输入")
|
|
|
|
|
snapshot_json: Mapped[dict | None] = mapped_column(JSON, comment="规则和补充资料的固定快照")
|
|
|
|
|
snapshot_hash: Mapped[str | None] = mapped_column(String(64), comment="输入指纹")
|
|
|
|
|
summary_json: Mapped[dict | None] = mapped_column(JSON, comment="结果汇总")
|
|
|
|
|
error_code: Mapped[str | None] = mapped_column(String(64), comment="固定错误编码")
|
|
|
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime, comment="开始时间")
|
|
|
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime, comment="结束时间")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TPlusWorkLine(Base):
|
|
|
|
|
"""固定输入及结果逐行留存,仅经授权的工作区接口可访问。"""
|
|
|
|
|
|
|
|
|
|
__tablename__ = "tplus_work_lines"
|
|
|
|
|
__table_args__ = mysql_table_args(
|
|
|
|
|
"T+ 导入预览与核算预演明细",
|
|
|
|
|
UniqueConstraint("run_no", "line_no", name="uk_tplus_work_lines_run_line"),
|
|
|
|
|
)
|
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
|
|
|
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
|
|
|
|
)
|
|
|
|
|
run_no: Mapped[str] = mapped_column(String(32), comment="运行编号")
|
|
|
|
|
line_no: Mapped[int] = mapped_column(Integer, comment="稳定行序号")
|
|
|
|
|
entity_type: Mapped[str] = mapped_column(String(32), comment="实体或分组类型")
|
|
|
|
|
source_id: Mapped[str] = mapped_column(String(128), comment="源ID或平账组")
|
|
|
|
|
action: Mapped[str] = mapped_column(String(32), comment="新增/更新/跳过/待补/冲突/分配")
|
|
|
|
|
reason: Mapped[str | None] = mapped_column(String(128), comment="固定原因编码")
|
|
|
|
|
data_json: Mapped[dict] = mapped_column(JSON, comment="最小必要的业务明细")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WORKBENCH_MODELS = (TPlusSourceHead, TPlusFact, TPlusSourceLink, TPlusWorkRun, TPlusWorkLine)
|