fix(budget): 偏差检查同 KPI 多计划去重(deviation-check 补 db.flush)
autoflush=False 下,check_budget_deviation 循环内 existing_alert 去重查询 查不到本次刚 add 未 flush 的行 → 同期间同 KPI 多 active 预算计划会重复告警。 add 后补 db.flush() 使其对下一次循环可见。附回归测试。 Ref: yanxue-20260914-budget-p13p14-activation 遗留②试跑发现的缺陷
This commit is contained in:
@@ -908,6 +908,9 @@ def check_budget_deviation(
|
|||||||
)
|
)
|
||||||
db.add(alert)
|
db.add(alert)
|
||||||
alerts_generated += 1
|
alerts_generated += 1
|
||||||
|
# 立即 flush:autoflush=False 下,下一次循环的同 KPI 去重查询
|
||||||
|
# (existing_alert) 需看到本次已 add 的行,否则同期间同 KPI 多预算计划会重复告警
|
||||||
|
db.flush()
|
||||||
|
|
||||||
alerts.append({
|
alerts.append({
|
||||||
"kpi_id": bp.kpi_id,
|
"kpi_id": bp.kpi_id,
|
||||||
|
|||||||
@@ -461,6 +461,34 @@ class TestBudgetDeviationCheck:
|
|||||||
json={"period": "2026-06", "threshold": 20})
|
json={"period": "2026-06", "threshold": 20})
|
||||||
assert resp.json()["alerts_generated"] == 0
|
assert resp.json()["alerts_generated"] == 0
|
||||||
|
|
||||||
|
def test_deviation_check_dedups_same_kpi_multiple_plans(self, client: TestClient, db: Session):
|
||||||
|
"""回归:同期间同 KPI 有多条 active 预算计划时,只应生成 1 条 open 告警
|
||||||
|
|
||||||
|
根因:database.py sessionmaker(autoflush=False),端点内循环的 existing_alert
|
||||||
|
去重查询查不到本次刚 add 未 flush 的行 → 第二个计划重复 INSERT。
|
||||||
|
"""
|
||||||
|
create_test_user(db)
|
||||||
|
token = get_token_for_user(client)
|
||||||
|
kpi = create_test_kpi(db, kpi_code="BUDGET_ALERT_DUP")
|
||||||
|
for _ in range(2): # 两条同 KPI 计划(模拟数据面重复计划)
|
||||||
|
db.add(BudgetPlan(kpi_id=kpi.id, period="2026-06", budget_value=100.0,
|
||||||
|
budget_year=2026, budget_month=6, status="active"))
|
||||||
|
from app.models import KPIValue
|
||||||
|
db.add(KPIValue(kpi_id=kpi.id, period="2026-06", actual_value=150.0)) # +50%
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
resp = client.post(f"{self.BASE}/deviation-check", headers=auth_header(token),
|
||||||
|
json={"period": "2026-06", "threshold": 20})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["alerts_generated"] == 1
|
||||||
|
from app.models import BudgetDeviationAlert
|
||||||
|
n = db.query(BudgetDeviationAlert).filter(
|
||||||
|
BudgetDeviationAlert.kpi_id == kpi.id,
|
||||||
|
BudgetDeviationAlert.period == "2026-06",
|
||||||
|
BudgetDeviationAlert.status == "open",
|
||||||
|
).count()
|
||||||
|
assert n == 1, f"同 KPI 重复告警未去重,落库 {n} 条"
|
||||||
|
|
||||||
|
|
||||||
class TestBudgetDeviationAlerts:
|
class TestBudgetDeviationAlerts:
|
||||||
"""偏差预警记录查询/更新"""
|
"""偏差预警记录查询/更新"""
|
||||||
|
|||||||
Reference in New Issue
Block a user