fix(cma): scope alert list and alert locate to alert row entity_id; attach cash-balance suffix candidates to forecast baseline
- alerts list: filter KPIAlert.entity_id (was KPIDefinition.entity_id via join) -> entity2 225->223, rows 589/590 no longer leak into entity2 workspace - resolve/process/escalate/create-action-plan: same row-level scope (4 sites) - get_current_cash_balance: pass KPI_CODE_SUFFIXES[cash_balance] -> entity2 hits BH_CASH_BALANCE(434), entity6 hits DEMO_CASH_BALANCE(468) no data changes; no SystemConfig fallback change; no period ordering change
This commit is contained in:
+23
-13
@@ -16,8 +16,10 @@ router = APIRouter(prefix="/api/cma/alerts", tags=["预警"],
|
||||
|
||||
@router.get("")
|
||||
def list_alerts(status: str = None, page: int = Query(1, ge=1), db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
# 账套隔离: join kpi_definitions 按企业过滤 (2026-08-23 P1b)
|
||||
query = db.query(KPIAlert).join(KPIDefinition, KPIDefinition.id == KPIAlert.kpi_id).filter(KPIDefinition.entity_id == entity_id)
|
||||
# 账套隔离(2026-09-19 dama-20260919 C1):按**预警行自身** entity_id 过滤
|
||||
# 修复前按 KPI 归属企业过滤(2026-08-23 P1b)→ KPI 属他账套而预警行属本账套的行反向泄漏
|
||||
# (实测 entity 2 口径 225 → 223,泄漏 id=589/590)
|
||||
query = db.query(KPIAlert).filter(KPIAlert.entity_id == entity_id)
|
||||
if status:
|
||||
query = query.filter(KPIAlert.status == status)
|
||||
total = query.count()
|
||||
@@ -26,8 +28,10 @@ def list_alerts(status: str = None, page: int = Query(1, ge=1), db: Session = De
|
||||
|
||||
@router.post("/{alert_id}/resolve")
|
||||
def resolve_alert(alert_id: int, data: dict, db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
alert = db.query(KPIAlert).join(KPIDefinition, KPIDefinition.id == KPIAlert.kpi_id).filter(
|
||||
KPIAlert.id == alert_id, KPIDefinition.entity_id == entity_id).first()
|
||||
# 账套隔离(2026-09-19 dama-20260919 C2):按预警行自身 entity_id 定位
|
||||
# 修复前按 KPI 归属企业过滤 → KPI 属他账套的行可被本账套端点操作(跨账套泄漏/越权)
|
||||
alert = db.query(KPIAlert).filter(
|
||||
KPIAlert.id == alert_id, KPIAlert.entity_id == entity_id).first()
|
||||
if not alert:
|
||||
raise HTTPException(404, "预警不存在")
|
||||
alert.status = "resolved"
|
||||
@@ -46,9 +50,11 @@ def resolve_alert(alert_id: int, data: dict, db: Session = Depends(get_db), enti
|
||||
|
||||
@router.post("/{alert_id}/process")
|
||||
def process_alert(alert_id: int, data: dict, db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
"""标记预警为处理中(账套隔离: join kpi_definitions 按企业过滤, 2026-09-18)"""
|
||||
alert = db.query(KPIAlert).join(KPIDefinition, KPIDefinition.id == KPIAlert.kpi_id).filter(
|
||||
KPIAlert.id == alert_id, KPIDefinition.entity_id == entity_id).first()
|
||||
"""标记预警为处理中(账套隔离: 按预警行自身 entity_id, 2026-09-19)"""
|
||||
# 账套隔离(2026-09-19 dama-20260919 C2):按预警行自身 entity_id 定位
|
||||
# 修复前按 KPI 归属企业过滤 → KPI 属他账套的行可被本账套端点操作(跨账套泄漏/越权)
|
||||
alert = db.query(KPIAlert).filter(
|
||||
KPIAlert.id == alert_id, KPIAlert.entity_id == entity_id).first()
|
||||
if not alert:
|
||||
raise HTTPException(404, "预警不存在")
|
||||
if alert.status == "resolved":
|
||||
@@ -65,9 +71,11 @@ def process_alert(alert_id: int, data: dict, db: Session = Depends(get_db), enti
|
||||
|
||||
@router.post("/{alert_id}/escalate")
|
||||
def escalate_alert(alert_id: int, data: dict, db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
"""升级预警级别(账套隔离: join kpi_definitions 按企业过滤, 2026-09-18)"""
|
||||
alert = db.query(KPIAlert).join(KPIDefinition, KPIDefinition.id == KPIAlert.kpi_id).filter(
|
||||
KPIAlert.id == alert_id, KPIDefinition.entity_id == entity_id).first()
|
||||
"""升级预警级别(账套隔离: 按预警行自身 entity_id, 2026-09-19)"""
|
||||
# 账套隔离(2026-09-19 dama-20260919 C2):按预警行自身 entity_id 定位
|
||||
# 修复前按 KPI 归属企业过滤 → KPI 属他账套的行可被本账套端点操作(跨账套泄漏/越权)
|
||||
alert = db.query(KPIAlert).filter(
|
||||
KPIAlert.id == alert_id, KPIAlert.entity_id == entity_id).first()
|
||||
if not alert:
|
||||
raise HTTPException(404, "预警不存在")
|
||||
assignee = data.get("assignee")
|
||||
@@ -107,9 +115,11 @@ def check_alert_timeout(db: Session = Depends(get_db), entity_id: int = Depends(
|
||||
|
||||
@router.post("/{alert_id}/create-action-plan")
|
||||
def create_action_plan_from_alert(alert_id: int, data: dict, db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
"""从预警创建改善行动计划(账套隔离: join kpi_definitions 按企业过滤, 2026-09-18)"""
|
||||
alert = db.query(KPIAlert).join(KPIDefinition, KPIDefinition.id == KPIAlert.kpi_id).filter(
|
||||
KPIAlert.id == alert_id, KPIDefinition.entity_id == entity_id).first()
|
||||
"""从预警创建改善行动计划(账套隔离: 按预警行自身 entity_id, 2026-09-19)"""
|
||||
# 账套隔离(2026-09-19 dama-20260919 C2):按预警行自身 entity_id 定位
|
||||
# 修复前按 KPI 归属企业过滤 → KPI 属他账套的行可被本账套端点操作(跨账套泄漏/越权)
|
||||
alert = db.query(KPIAlert).filter(
|
||||
KPIAlert.id == alert_id, KPIAlert.entity_id == entity_id).first()
|
||||
if not alert:
|
||||
raise HTTPException(404, "预警不存在")
|
||||
if alert.action_plan_linked_id:
|
||||
|
||||
Reference in New Issue
Block a user