fix(alerts): enforce caliber rulings R1-R4 for alert generation

R1: exclude status=demo entities from alert traversal (alert_generator / deviation_engine / kpi_bep_deriver / alert_rules / cash engine)

R2: only generate alerts within the last 6 calendar months (incl. current)

R3: only regular month periods (YYYY-MM) participate

R4: decouple generation from push - empty notification_channels never blocks

Single source of truth: app/utils/alert_entity_scope.py
This commit is contained in:
Hermes CI Fix
2026-09-19 10:05:11 +08:00
parent d785a22efd
commit 3beec14d96
7 changed files with 641 additions and 21 deletions
@@ -806,9 +806,17 @@ def check_cash_alerts(db: Session, entity_id: int = 1) -> dict:
(此前博海走无排序兜底 → 命中 uk_entity_kpi 索引必中 BH_ADM_EXPENSE(437 管理费用))
F3 去重命中时刷新文本/等级/逾期天数/归属(此前直接 continue → 金额与天数永久冻结在首版)
F4 余额快照批次行按开关处理(默认 skip,不再逐户生成伪"到期未收款")
R1(裁定 2026-09-19):demo 演示账套不产生业务预警 → 直接返回 skipped。
"""
import json as _json
from app.models import KPIAlert, CashPlan, KPIDefinition
from app.utils.alert_entity_scope import is_excluded_entity
if is_excluded_entity(db, entity_id):
logger.info("资金预警检查跳过(demo 账套 R1): entity_id=%s", entity_id)
return {"entity_id": entity_id, "skipped": True, "reason": "R1_demo_entity_excluded",
"new_alerts": [], "refreshed": []}
result = forecast_cash_flow_with_plans(entity_id, db, days=30)
new_alerts = []