feat: 添加线索引擎、NLQ、场景检测、前端界面等核心功能模块

This commit is contained in:
freedakgmail
2026-06-16 08:15:15 +08:00
parent 7b1e2b10a8
commit 48340f6011
62 changed files with 6772 additions and 65 deletions
+14
View File
@@ -41,6 +41,10 @@ class RelationshipType(str, Enum):
SUPPLIES = "supplies" # 供应商 —供货→ 合同/工单
HANDLED_BY = "handled_by" # 工单 —处理人→ 员工
SETTLES = "settles" # 结算单 —结算→ 合同
EMPLOYED_BY = "employed_by" # 员工 —任职于→ 客户/供应商(组织)
OPERATES = "operates" # 员工 —操作→ 号码/账户(R15 越权检测)
SUBSCRIBES = "subscribes" # 号码 —订购→ 合同(R9/R10 订购关联)
BIDS_FOR = "bids_for" # 供应商 —投标→ 工单(R12 招投标关联)
# 关系的合法 (源实体类型, 目标实体类型) 约束,用于校验图谱写入
@@ -72,6 +76,16 @@ RELATIONSHIP_DOMAIN: dict[RelationshipType, tuple[set[EntityType], set[EntityTyp
),
RelationshipType.HANDLED_BY: ({EntityType.WORK_ORDER}, {EntityType.EMPLOYEE}),
RelationshipType.SETTLES: ({EntityType.SETTLEMENT}, {EntityType.CONTRACT}),
RelationshipType.EMPLOYED_BY: (
{EntityType.EMPLOYEE},
{EntityType.CUSTOMER, EntityType.SUPPLIER},
),
RelationshipType.OPERATES: (
{EntityType.EMPLOYEE},
{EntityType.MSISDN, EntityType.ACCOUNT},
),
RelationshipType.SUBSCRIBES: ({EntityType.MSISDN}, {EntityType.CONTRACT}),
RelationshipType.BIDS_FOR: ({EntityType.SUPPLIER}, {EntityType.WORK_ORDER}),
}
+502
View File
@@ -0,0 +1,502 @@
"""源明细落地层(Staging / Raw)。
保存数据中心按 `数据要求.md` 提供的原始明细,作为"原始证据"留存;
再由接入适配器(app/ingest)映射/投影到通用本体(entity/relationship/metric_event)。
两层并存:源明细可回溯原始数据,本体支撑关联穿透与时序分析。
"""
from __future__ import annotations
import datetime as dt
import uuid
from sqlalchemy import Date, DateTime, Float, Index, Integer, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.db import Base
def _uuid() -> uuid.UUID:
return uuid.uuid4()
def _now() -> dt.datetime:
return dt.datetime.now(dt.timezone.utc)
# ---------------------------------------------------------------------------
# R8 · 政企收入全链路穿透 / 拆单规避(§4.1)
# ---------------------------------------------------------------------------
class SrcContract(Base):
"""源明细:政企合同(对应数据要求 §4.1 / R8)。"""
__tablename__ = "src_contract"
__table_args__ = (Index("ix_src_contract_customer", "customer_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
contract_no: Mapped[str] = mapped_column(String(64), nullable=False)
customer_key: Mapped[str] = mapped_column(String(64), nullable=False)
customer_name: Mapped[str | None] = mapped_column(String(256))
amount: Mapped[float] = mapped_column(Float, nullable=False)
sign_date: Mapped[dt.date | None] = mapped_column(Date)
approval_threshold: Mapped[float | None] = mapped_column(Float)
approval_level: Mapped[str | None] = mapped_column(String(32))
legal_person: Mapped[str | None] = mapped_column(String(128))
register_address: Mapped[str | None] = mapped_column(String(256))
pay_account: Mapped[str | None] = mapped_column(String(64))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcContractApproval(Base):
"""源明细:合同审批流水(对应 R8 补充)。"""
__tablename__ = "src_contract_approval"
__table_args__ = (Index("ix_src_approval_contract", "contract_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
contract_no: Mapped[str] = mapped_column(String(64), nullable=False)
approval_step: Mapped[int] = mapped_column(Integer, nullable=False)
approver: Mapped[str | None] = mapped_column(String(128))
approval_result: Mapped[str | None] = mapped_column(String(32)) # approved/rejected
approval_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
remark: Mapped[str | None] = mapped_column(Text)
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcPayment(Base):
"""源明细:回款流水(对应 R8 回款时序违约)。"""
__tablename__ = "src_payment"
__table_args__ = (Index("ix_src_payment_contract", "contract_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
contract_no: Mapped[str] = mapped_column(String(64), nullable=False)
pay_account: Mapped[str | None] = mapped_column(String(64))
pay_amount: Mapped[float] = mapped_column(Float, nullable=False)
pay_date: Mapped[dt.date | None] = mapped_column(Date)
pay_type: Mapped[str | None] = mapped_column(String(32)) # 预付/尾款/全款
overdue_flag: Mapped[str | None] = mapped_column(String(8)) # Y/N
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R9 · 市场业务真实性 / 养卡骗补(§4.2)
# ---------------------------------------------------------------------------
class SrcChannelMonthly(Base):
"""源明细:渠道用户月度留存与佣金/活跃(对应数据要求 §4.2 / R9)。"""
__tablename__ = "src_channel_monthly"
__table_args__ = (Index("ix_src_channel_key", "channel_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
channel_key: Mapped[str] = mapped_column(String(64), nullable=False)
cohort_label: Mapped[str] = mapped_column(String(32), nullable=False) # 新增批次(如 2025-01
month_index: Mapped[int] = mapped_column(Integer, nullable=False) # 第N月
cohort_size: Mapped[int] = mapped_column(Integer, default=0)
retained: Mapped[int] = mapped_column(Integer, default=0)
commission_paid: Mapped[float] = mapped_column(Float, default=0.0)
active_ratio: Mapped[float] = mapped_column(Float, default=0.0)
zero_usage_ratio: Mapped[float] = mapped_column(Float, default=0.0)
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcSubscription(Base):
"""源明细:用户订购与退订流水(对应 R9 订购退订分析)。"""
__tablename__ = "src_subscription"
__table_args__ = (Index("ix_src_sub_msisdn", "msisdn"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
msisdn: Mapped[str] = mapped_column(String(32), nullable=False)
channel_key: Mapped[str | None] = mapped_column(String(64))
product_code: Mapped[str | None] = mapped_column(String(64))
subscribe_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
unsubscribe_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
region: Mapped[str | None] = mapped_column(String(64))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R10 · 收入与成本跨期匹配(§4.3)
# ---------------------------------------------------------------------------
class SrcRevenueRecognition(Base):
"""源明细:收入确认凭证与明细(对应 R10)。"""
__tablename__ = "src_revenue_recognition"
__table_args__ = (Index("ix_src_rev_contract", "contract_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
voucher_no: Mapped[str] = mapped_column(String(64), nullable=False)
contract_no: Mapped[str | None] = mapped_column(String(64))
recognition_date: Mapped[dt.date | None] = mapped_column(Date)
recognition_amount: Mapped[float] = mapped_column(Float, nullable=False)
billing_mode: Mapped[str | None] = mapped_column(String(32)) # 按量/包年/趸交
period_start: Mapped[dt.date | None] = mapped_column(Date)
period_end: Mapped[dt.date | None] = mapped_column(Date)
prepaid_flag: Mapped[str | None] = mapped_column(String(8)) # Y/N 预收/趸交
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcCostAmortization(Base):
"""源明细:成本摊销明细(对应 R10)。"""
__tablename__ = "src_cost_amortization"
__table_args__ = (Index("ix_src_cost_contract", "contract_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
voucher_no: Mapped[str] = mapped_column(String(64), nullable=False)
contract_no: Mapped[str | None] = mapped_column(String(64))
cost_type: Mapped[str | None] = mapped_column(String(64)) # 设备/安装/维护
amortization_date: Mapped[dt.date | None] = mapped_column(Date)
amortization_amount: Mapped[float] = mapped_column(Float, nullable=False)
total_periods: Mapped[int | None] = mapped_column(Integer)
current_period: Mapped[int | None] = mapped_column(Integer)
delivery_date: Mapped[dt.date | None] = mapped_column(Date) # 交付/上架日期
acceptance_date: Mapped[dt.date | None] = mapped_column(Date) # 验收日期
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R11 · 渠道佣金与代理商套利(§4.4)
# ---------------------------------------------------------------------------
class SrcTerminalBinding(Base):
"""源明细:终端 IMEI 与号码绑定 / 补贴发放(对应 R11)。"""
__tablename__ = "src_terminal_binding"
__table_args__ = (
Index("ix_src_terminal_imei", "imei"),
Index("ix_src_terminal_msisdn", "msisdn"),
)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
imei: Mapped[str] = mapped_column(String(32), nullable=False)
msisdn: Mapped[str] = mapped_column(String(32), nullable=False)
brand_model: Mapped[str | None] = mapped_column(String(128))
activate_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
subsidy_amount: Mapped[float] = mapped_column(Float, default=0.0)
commission_amount: Mapped[float] = mapped_column(Float, default=0.0)
online_days: Mapped[int | None] = mapped_column(Integer) # 在网天数
post_activate_traffic_mb: Mapped[float | None] = mapped_column(Float) # 激活后流量
region: Mapped[str | None] = mapped_column(String(64)) # 归属地
cross_province_flag: Mapped[str | None] = mapped_column(String(8)) # 跨省入网 Y/N
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R12 · 网络建设与工程采购(§4.5)
# ---------------------------------------------------------------------------
class SrcBidding(Base):
"""源明细:招投标记录(对应 R12)。"""
__tablename__ = "src_bidding"
__table_args__ = (Index("ix_src_bidding_project", "project_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
project_no: Mapped[str] = mapped_column(String(64), nullable=False)
project_name: Mapped[str | None] = mapped_column(String(256))
bidder_key: Mapped[str] = mapped_column(String(64), nullable=False) # 投标人/供应商编号
bidder_name: Mapped[str | None] = mapped_column(String(256))
bid_amount: Mapped[float | None] = mapped_column(Float)
bid_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
win_flag: Mapped[str | None] = mapped_column(String(8)) # 中标 Y/N
technical_score: Mapped[float | None] = mapped_column(Float)
legal_person: Mapped[str | None] = mapped_column(String(128))
shareholder_info: Mapped[str | None] = mapped_column(Text) # JSON or 描述
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcProjectSignoff(Base):
"""源明细:工程量签证与施工(对应 R12)。"""
__tablename__ = "src_project_signoff"
__table_args__ = (Index("ix_src_signoff_project", "project_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
project_no: Mapped[str] = mapped_column(String(64), nullable=False)
work_order_no: Mapped[str | None] = mapped_column(String(64))
signoff_quantity: Mapped[float | None] = mapped_column(Float) # 签证工程量
unit: Mapped[str | None] = mapped_column(String(32))
resource_consumed: Mapped[float | None] = mapped_column(Float) # 实际资源消耗
contractor_key: Mapped[str | None] = mapped_column(String(64)) # 施工队
signoff_date: Mapped[dt.date | None] = mapped_column(Date)
inspection_lat: Mapped[float | None] = mapped_column(Float) # 巡检 GPS 纬度
inspection_lng: Mapped[float | None] = mapped_column(Float) # 巡检 GPS 经度
inspection_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R13 · 互联互通与网间结算(§4.6)
# ---------------------------------------------------------------------------
class SrcCdr(Base):
"""源明细:话单 CDR(对应 R13,大数据量增量接入)。"""
__tablename__ = "src_cdr"
__table_args__ = (
Index("ix_src_cdr_caller", "caller"),
Index("ix_src_cdr_time", "start_time"),
)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
caller: Mapped[str] = mapped_column(String(32), nullable=False)
callee: Mapped[str] = mapped_column(String(32), nullable=False)
start_time: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), nullable=False)
duration_sec: Mapped[int] = mapped_column(Integer, nullable=False)
call_type: Mapped[str | None] = mapped_column(String(16)) # voice/sms/data
peer_operator: Mapped[str | None] = mapped_column(String(32)) # 对端运营商
route_info: Mapped[str | None] = mapped_column(String(128)) # 路由信息
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcInterconnectSettlement(Base):
"""源明细:网间结算单(对应 R13)。"""
__tablename__ = "src_interconnect_settlement"
__table_args__ = (Index("ix_src_ics_period", "settle_period"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
settlement_no: Mapped[str] = mapped_column(String(64), nullable=False)
peer_operator: Mapped[str] = mapped_column(String(32), nullable=False)
settle_period: Mapped[str] = mapped_column(String(16), nullable=False) # 如 2025-06
settle_type: Mapped[str | None] = mapped_column(String(32)) # 语音/短信/SP/CP
volume: Mapped[float] = mapped_column(Float, default=0.0) # 结算量(分钟/条)
unit_price: Mapped[float | None] = mapped_column(Float)
settle_amount: Mapped[float] = mapped_column(Float, default=0.0)
sms_delivery_rate: Mapped[float | None] = mapped_column(Float) # 短信到达率
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R14 · 云业务 / IDC 与新兴业务(§4.7)
# ---------------------------------------------------------------------------
class SrcCloudUsage(Base):
"""源明细:云资源用量(对应 R14)。"""
__tablename__ = "src_cloud_usage"
__table_args__ = (Index("ix_src_cloud_contract", "contract_no"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
contract_no: Mapped[str] = mapped_column(String(64), nullable=False)
customer_key: Mapped[str | None] = mapped_column(String(64))
resource_type: Mapped[str | None] = mapped_column(String(32)) # CPU/存储/带宽
usage_date: Mapped[dt.date | None] = mapped_column(Date)
actual_usage: Mapped[float] = mapped_column(Float, default=0.0) # 实际用量
contracted_quota: Mapped[float | None] = mapped_column(Float) # 合同约定量
billed_usage: Mapped[float | None] = mapped_column(Float) # 计费量
unit: Mapped[str | None] = mapped_column(String(16)) # vCPU/GB/Mbps
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcIdcCabinet(Base):
"""源明细:IDC 机柜出租与电力消耗(对应 R14)。"""
__tablename__ = "src_idc_cabinet"
__table_args__ = (Index("ix_src_idc_cabinet_id", "cabinet_id"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
cabinet_id: Mapped[str] = mapped_column(String(64), nullable=False)
customer_key: Mapped[str | None] = mapped_column(String(64))
contract_no: Mapped[str | None] = mapped_column(String(64))
report_month: Mapped[str | None] = mapped_column(String(16)) # 如 2025-06
occupancy_rate: Mapped[float | None] = mapped_column(Float) # 出租率
power_kwh: Mapped[float | None] = mapped_column(Float) # 电力消耗 kWh
revenue_amount: Mapped[float | None] = mapped_column(Float) # 收入金额
acceptance_date: Mapped[dt.date | None] = mapped_column(Date) # 验收日期
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# R15 · 员工内部舞弊与资源滥用(§4.8)
# ---------------------------------------------------------------------------
class SrcEmployeeOperation(Base):
"""源明细:员工权限与操作日志(对应 R15)。"""
__tablename__ = "src_employee_operation"
__table_args__ = (
Index("ix_src_emp_op_employee", "employee_key"),
Index("ix_src_emp_op_time", "operation_time"),
)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
employee_key: Mapped[str] = mapped_column(String(64), nullable=False)
employee_name: Mapped[str | None] = mapped_column(String(128))
position: Mapped[str | None] = mapped_column(String(64))
role_permissions: Mapped[str | None] = mapped_column(Text) # 岗位-权限
operation_type: Mapped[str | None] = mapped_column(String(64))
operation_target: Mapped[str | None] = mapped_column(String(256)) # 操作对象
operation_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
department: Mapped[str | None] = mapped_column(String(128))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcInternalMsisdn(Base):
"""源明细:内部测试号及用量(对应 R15)。"""
__tablename__ = "src_internal_msisdn"
__table_args__ = (Index("ix_src_int_msisdn", "msisdn"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
msisdn: Mapped[str] = mapped_column(String(32), nullable=False)
assigned_employee: Mapped[str | None] = mapped_column(String(64))
purpose: Mapped[str | None] = mapped_column(String(128)) # 测试/演示/其他
traffic_mb: Mapped[float] = mapped_column(Float, default=0.0)
voice_min: Mapped[float] = mapped_column(Float, default=0.0)
revenue_attributed: Mapped[float] = mapped_column(Float, default=0.0) # 收入归属
report_month: Mapped[str | None] = mapped_column(String(16))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcPointsTransaction(Base):
"""源明细:积分/电子券发放与兑换流水(对应 R15)。"""
__tablename__ = "src_points_transaction"
__table_args__ = (Index("ix_src_points_employee", "operator_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
transaction_no: Mapped[str] = mapped_column(String(64), nullable=False)
operator_key: Mapped[str] = mapped_column(String(64), nullable=False) # 操作人工号
target_account: Mapped[str | None] = mapped_column(String(64)) # 受益账户
transaction_type: Mapped[str | None] = mapped_column(String(32)) # 发放/兑换/变现
points_amount: Mapped[float] = mapped_column(Float, default=0.0)
cash_value: Mapped[float | None] = mapped_column(Float) # 变现金额
transaction_time: Mapped[dt.datetime | None] = mapped_column(DateTime(timezone=True))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
# ---------------------------------------------------------------------------
# 主数据源明细(§3 实体级原始数据)
# ---------------------------------------------------------------------------
class SrcCustomer(Base):
"""源明细:客户主数据(§3 Customer)。"""
__tablename__ = "src_customer"
__table_args__ = (Index("ix_src_cust_key", "customer_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
customer_key: Mapped[str] = mapped_column(String(64), nullable=False)
customer_name: Mapped[str] = mapped_column(String(256), nullable=False)
customer_type: Mapped[str | None] = mapped_column(String(32)) # 政企/公众
register_address: Mapped[str | None] = mapped_column(String(256))
legal_person: Mapped[str | None] = mapped_column(String(128))
uscc: Mapped[str | None] = mapped_column(String(32)) # 统一社会信用代码
open_date: Mapped[dt.date | None] = mapped_column(Date)
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcSupplier(Base):
"""源明细:供应商主数据(§3 Supplier)。"""
__tablename__ = "src_supplier"
__table_args__ = (Index("ix_src_supplier_key", "supplier_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
supplier_key: Mapped[str] = mapped_column(String(64), nullable=False)
supplier_name: Mapped[str] = mapped_column(String(256), nullable=False)
legal_person: Mapped[str | None] = mapped_column(String(128))
shareholder_info: Mapped[str | None] = mapped_column(Text)
register_address: Mapped[str | None] = mapped_column(String(256))
uscc: Mapped[str | None] = mapped_column(String(32))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcEmployee(Base):
"""源明细:员工主数据(§3 Employee)。"""
__tablename__ = "src_employee"
__table_args__ = (Index("ix_src_emp_key", "employee_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
employee_key: Mapped[str] = mapped_column(String(64), nullable=False)
employee_name: Mapped[str | None] = mapped_column(String(128))
position: Mapped[str | None] = mapped_column(String(64))
department: Mapped[str | None] = mapped_column(String(128))
role_permissions: Mapped[str | None] = mapped_column(Text)
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcChannel(Base):
"""源明细:渠道/代理商主数据(§3 Channel)。"""
__tablename__ = "src_channel"
__table_args__ = (Index("ix_src_chan_key", "channel_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
channel_key: Mapped[str] = mapped_column(String(64), nullable=False)
channel_name: Mapped[str | None] = mapped_column(String(256))
commission_policy: Mapped[str | None] = mapped_column(Text) # 佣金政策描述
region: Mapped[str | None] = mapped_column(String(64))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcMsisdn(Base):
"""源明细:号码主数据(§3 MSISDN)。"""
__tablename__ = "src_msisdn"
__table_args__ = (Index("ix_src_msisdn_no", "msisdn"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
msisdn: Mapped[str] = mapped_column(String(32), nullable=False)
customer_key: Mapped[str | None] = mapped_column(String(64))
region: Mapped[str | None] = mapped_column(String(64))
activate_date: Mapped[dt.date | None] = mapped_column(Date)
deactivate_date: Mapped[dt.date | None] = mapped_column(Date)
status: Mapped[str | None] = mapped_column(String(16)) # active/suspended/cancelled
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
class SrcAccount(Base):
"""源明细:账户主数据(§3 Account)。"""
__tablename__ = "src_account"
__table_args__ = (Index("ix_src_acct_key", "account_key"),)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=_uuid)
account_key: Mapped[str] = mapped_column(String(64), nullable=False)
account_name: Mapped[str | None] = mapped_column(String(256))
owner_key: Mapped[str | None] = mapped_column(String(64)) # 所属主体编号
owner_type: Mapped[str | None] = mapped_column(String(32)) # customer/supplier/legal_person
bank_name: Mapped[str | None] = mapped_column(String(128))
branch_name: Mapped[str | None] = mapped_column(String(128))
data_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
ingested_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)