feat(strategy-map): A3 三维切片(时间/门店/产品)——切片重算 + 显式空态 + entity 隔离
ci/woodpecker/push/main Pipeline was successful
ci/woodpecker/push/main Pipeline was successful
- 新增 /api/cma/maps/{id}/dimension-options 与 /{id}/slice(只读)
- 时间:kpi_values.period 月/季/年;flow 求和、ratio 均值、balance/status 取最新
- 产品:product_sales + 逐月源一致性闸门(偏差>1% 不切片)
- 门店:库内无门店级事实 ⇒ available=false + reason,绝不回退总额
- 前端 MapDimensionFilter 挂到 MapCanvas,切换即 emit 切片,清除恢复 /review
This commit is contained in:
committed by
Hermes CI Fix
parent
c92dbab96a
commit
d85dd2a155
@@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A3 自测:直接调 build_slice(不启服务),校验真实库切片与空态。"""
|
||||
import os, sys, json
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
for line in open('/root/cma-management/backend/.env'):
|
||||
line = line.strip()
|
||||
if '=' in line and not line.startswith('#') and line.split('=')[0].startswith(('CMA_DB', 'ERP_DB')):
|
||||
k, v = line.split('=', 1); os.environ.setdefault(k, v)
|
||||
|
||||
from app.database import get_session_local
|
||||
from app.api.map_dimensions import build_slice, _time_options, _store_options, _product_options
|
||||
|
||||
db = get_session_local()()
|
||||
|
||||
def brief(r):
|
||||
print("slice:", r["slice"], "| empty:", r["empty"], "|", r["empty_reason"])
|
||||
for o in r["objectives"]:
|
||||
ks = [f'{k["kpi_code"]}={k["actual_value"]}/{k["target_value"]}@{k["achievement_pct"]}%({k["level"]},{k["aggregation"]}){"" if k["available"] else "[空:"+str(k["reason"])[:36]+"]"}' for k in o["kpis"]]
|
||||
if ks:
|
||||
print(" ", o["dimension_key"], o["name"], "|", "; ".join(ks))
|
||||
|
||||
print("=== 1) 2026-08 月切片 (map 65)")
|
||||
brief(build_slice(db, 1, 65, "2026-08", None, None))
|
||||
print("\n=== 2) 2026-Q3 季切片")
|
||||
brief(build_slice(db, 1, 65, "2026-Q3", None, None))
|
||||
print("\n=== 3) 2026 年切片")
|
||||
brief(build_slice(db, 1, 65, "2026", None, None))
|
||||
print("\n=== 4) 产品切片 酣客酱酒 @2026-08")
|
||||
brief(build_slice(db, 1, 65, "2026-08", None, "酣客酱酒"))
|
||||
print("\n=== 5) 产品切片 不存在产品 @2026-08")
|
||||
brief(build_slice(db, 1, 65, "2026-08", None, "不存在的产品X"))
|
||||
print("\n=== 6) 门店切片 一店 @2026-08")
|
||||
brief(build_slice(db, 1, 65, "2026-08", "一店", None))
|
||||
print("\n=== 7) entity 隔离: map65 + entity2")
|
||||
try:
|
||||
build_slice(db, 2, 65, "2026-08", None, None)
|
||||
print("FAIL 未拦截")
|
||||
except Exception as e:
|
||||
print("OK 拦截:", type(e).__name__, getattr(e, "status_code", ""), getattr(e, "detail", e))
|
||||
|
||||
print("\n=== 8) options map65")
|
||||
o = build_slice(db, 1, 65, None, None, None)
|
||||
print("time dims:", json.dumps(o["dims"]["time"], ensure_ascii=False)[:300])
|
||||
print("store:", json.dumps(o["dims"]["store"], ensure_ascii=False)[:300])
|
||||
print("product:", json.dumps(o["dims"]["product"], ensure_ascii=False)[:300])
|
||||
db.close()
|
||||
Reference in New Issue
Block a user