fix(cma): 工作台跨实体污染治本 — 全局键拆账套 + 缺列收口 + 预警归属兜底
任务 dama-workbench-entity-isolation-fullstack-20260922(DAMA 诊断 / 项目Bot batch5 §B / 任总 2026-09-22「都批」) B1 现金基线拆账套(零 DDL) - cash_forecast_engine: 键 cash.current_balance → cash.current_balance.<entity_id>; 读只读本账套键、不做旧键回退;set_* 签名 entity_id 必传(漏传 TypeError) - cash.py: POST /balance 挂 get_entity_id;网银流水联动写回带账套 B3(a) alignment_config 拆账套(零 DDL) - alignment.py: GET/POST /config、GET /tree 只读 alignment_config.<entity_id>;未配置=configured:false B3(b) 预警 KPI 归属兜底 - bot_bridge_v2: 去掉 kpi_id or 1 兜底;本账套无 KPI 定义 → 跳过建预警 + OperationLog 留痕 (kpi_alerts.kpi_id NOT NULL ⇒ 方案A 置 NULL 不可行,走方案B 跳过+审计) B2 缺列五表分表处置 - notification_logs: 经 alert_id → kpi_alerts.entity_id join 归属(无父键行不返回) - notification_channels / okr_templates: 集团共享口径写入 docstring(有意不过滤) - system_configs: 由 B1/B3(a) 拆键覆盖;kpi_data_quality_logs 沿用 batch5 的 join 收口 P0 语义收敛 - tenant.py: current_tenant 收敛为项目Bot A2A 状态记录,GET 仅 it/ceo;POST 补 operation_logs 审计 证据:新增/改写用例 22 条;全量 1370 passed(基线 1348)
This commit is contained in:
@@ -221,8 +221,33 @@ def calc_trend(values: list) -> float:
|
||||
return slope / max(abs(avg_y), 1.0) * 100 # 趋势百分比
|
||||
|
||||
|
||||
# ── B1 现金基线拆账套(2026-09-22 dama-workbench-entity-isolation-fullstack-20260922)──
|
||||
# 背景:`SystemConfig.config_key` 为 unique 单行键 → `cash.current_balance` 全库仅一行,
|
||||
# 所有账套共用;任一账套导入网银流水(`cash.py::_sync_cash_balance_from_ledger` 按 entity
|
||||
# 算完余额后丢账套写回)即覆盖其他账套的预测基线。实测事故值 -9.3 被全账套共用。
|
||||
#
|
||||
# 治本(方案 A,零 DDL):键名带账套后缀 → `cash.current_balance.<entity_id>`。
|
||||
# · 读:只读本账套键;本账套未设值 → None(由 KPI 实际值兜底,**不跨账套借用**)。
|
||||
# 不做「回退旧全局键」——那正是本次污染通路(其余账套会读到别家的基线)。
|
||||
# · 写:只写本账套键(调用方必须传会话 entity)。
|
||||
# · 旧值搬运:一次性落到「当前生产账套」名下(脚本
|
||||
# `scripts/migrate_cash_balance_key_entity_20260922.py`,--check/--apply/--down)。
|
||||
# 回退路径:--down 删新键(旧全局键原样保留,回退老码即可继续读)。
|
||||
CASH_BALANCE_KEY_PREFIX = "cash.current_balance"
|
||||
|
||||
|
||||
def cash_balance_key(entity_id: int) -> str:
|
||||
"""账套维度的现金基线键名:cash.current_balance.<entity_id>"""
|
||||
return f"{CASH_BALANCE_KEY_PREFIX}.{int(entity_id)}"
|
||||
|
||||
|
||||
def get_current_cash_balance(db: Session, entity_id: int) -> Optional[float]:
|
||||
"""获取当前现金余额(万元)— 优先级:KPI实际值 > SystemConfig > None"""
|
||||
"""获取当前现金余额(万元)— 优先级:KPI实际值 > 本账套SystemConfig键 > None
|
||||
|
||||
账套隔离(B1,2026-09-22):只读 `cash.current_balance.<entity_id>`。
|
||||
本账套未设基线 → 返回 None(由 KPI 实际值兜底 / 预测引擎默认值),
|
||||
**不回退旧全局键 `cash.current_balance`**——回退即恢复跨账套借用。
|
||||
"""
|
||||
from app.models import SystemConfig, KPIValue
|
||||
# C3(2026-09-19 dama-20260919):补传实体前缀后缀候选(与 F2 的应收/应付路径一致)
|
||||
# 修复前漏传 → 博海/演示企业一条候选都不命中 → 回退 SystemConfig.cash.current_balance(全库唯一键 -9.3)
|
||||
@@ -236,7 +261,7 @@ def get_current_cash_balance(db: Session, entity_id: int) -> Optional[float]:
|
||||
if latest_cash and latest_cash.actual_value is not None:
|
||||
return float(latest_cash.actual_value)
|
||||
cfg = db.query(SystemConfig).filter(
|
||||
SystemConfig.config_key == "cash.current_balance"
|
||||
SystemConfig.config_key == cash_balance_key(entity_id)
|
||||
).first()
|
||||
if cfg and cfg.config_value:
|
||||
try:
|
||||
@@ -246,19 +271,27 @@ def get_current_cash_balance(db: Session, entity_id: int) -> Optional[float]:
|
||||
return None
|
||||
|
||||
|
||||
def set_current_cash_balance(db: Session, value: float) -> float:
|
||||
"""设置当前现金余额(写入SystemConfig,供预测引擎使用)"""
|
||||
def set_current_cash_balance(db: Session, value: float, entity_id: int) -> float:
|
||||
"""设置当前现金余额(写入本账套键 `cash.current_balance.<entity_id>`,供预测引擎使用)
|
||||
|
||||
entity_id 为**必传**(2026-09-22 B1):签名中不设默认值,强制调用方带上会话账套,
|
||||
防「漏传 → 落默认账套」重演本次污染。全部调用点见 cash.py(POST /balance、
|
||||
网银流水导入联动)。
|
||||
"""
|
||||
from app.models import SystemConfig
|
||||
if entity_id is None:
|
||||
raise ValueError("set_current_cash_balance 必须传 entity_id(账套隔离,2026-09-22 B1)")
|
||||
key = cash_balance_key(entity_id)
|
||||
cfg = db.query(SystemConfig).filter(
|
||||
SystemConfig.config_key == "cash.current_balance"
|
||||
SystemConfig.config_key == key
|
||||
).first()
|
||||
if cfg:
|
||||
cfg.config_value = str(value)
|
||||
else:
|
||||
cfg = SystemConfig(
|
||||
config_key="cash.current_balance",
|
||||
config_key=key,
|
||||
config_value=str(value),
|
||||
description="当前现金余额(万元),资金预测基线",
|
||||
description=f"当前现金余额(万元),资金预测基线 — 账套 {int(entity_id)}",
|
||||
)
|
||||
db.add(cfg)
|
||||
db.commit()
|
||||
|
||||
Reference in New Issue
Block a user