feat(analytics): /overview 端点+unmapped_accounts 标注字段
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
"""/api/analytics/health:E0-lite 冒烟。"""
|
||||
"""/api/analytics/health + /overview:E0-lite 与 A1 冒烟。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as dt
|
||||
|
||||
from app.db.models import Customer, MsgDailyStats
|
||||
from app.analytics import metrics
|
||||
from app.db.models import Customer, MsgDailyStats, StatDailyStaff, WechatAccount
|
||||
|
||||
# naive:updated_at 列是无时区 DateTime;fromisoformat 构造不触发 DTZ 检查
|
||||
_SEEN = "2026-09-04T12:00:00"
|
||||
|
||||
# overview 的 today_key 是真实今天——固定 day 键的 seed 必须 monkeypatch
|
||||
_TODAY = 20260904
|
||||
|
||||
|
||||
async def test_health_empty(make_client):
|
||||
async def seed(session):
|
||||
@@ -55,3 +59,86 @@ async def test_health_with_stats(make_client):
|
||||
assert dt.datetime.fromisoformat(entities["customer"]) == dt.datetime.fromisoformat(
|
||||
_SEEN
|
||||
)
|
||||
|
||||
|
||||
async def test_overview_endpoint(make_client, monkeypatch):
|
||||
monkeypatch.setattr(metrics, "today_key", lambda: _TODAY)
|
||||
|
||||
async def seed(session):
|
||||
session.add(MsgDailyStats(channel="wechat", owner_account_id="wx1",
|
||||
peer_kind="friend", peer_id="t1", day=_TODAY,
|
||||
send_cnt=4, recv_cnt=1, last_ts=1788500000000,
|
||||
last_is_send=True))
|
||||
await session.commit()
|
||||
|
||||
client = await make_client(seed)
|
||||
r = await client.get(
|
||||
"/api/analytics/overview", params={"channel": "wechat", "scope": "today"}
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["cards"]["msg_total"] == 5
|
||||
assert isinstance(body["trend"], list) and body["trend"]
|
||||
# scope 非法 → 422
|
||||
r2 = await client.get(
|
||||
"/api/analytics/overview", params={"channel": "wechat", "scope": "year"}
|
||||
)
|
||||
assert r2.status_code == 422
|
||||
|
||||
|
||||
async def test_overview_unmapped_accounts(make_client, monkeypatch):
|
||||
"""控制器追加:cards 带 unmapped_accounts 计数(spec §8「未映射账号按账号计并标注」的标注通道)。"""
|
||||
monkeypatch.setattr(metrics, "today_key", lambda: _TODAY)
|
||||
|
||||
async def seed(session):
|
||||
session.add(WechatAccount(wx_id="wx1", user_id="u1"))
|
||||
# wx2 无账号表记录 → 未映射
|
||||
session.add(MsgDailyStats(channel="wechat", owner_account_id="wx1",
|
||||
peer_kind="friend", peer_id="t1", day=_TODAY,
|
||||
send_cnt=2, recv_cnt=0, last_ts=1788500000000,
|
||||
last_is_send=True))
|
||||
session.add(MsgDailyStats(channel="wechat", owner_account_id="wx2",
|
||||
peer_kind="friend", peer_id="t2", day=_TODAY,
|
||||
send_cnt=1, recv_cnt=0, last_ts=1788501000000,
|
||||
last_is_send=True))
|
||||
await session.commit()
|
||||
|
||||
client = await make_client(seed)
|
||||
r = await client.get(
|
||||
"/api/analytics/overview", params={"channel": "wechat", "scope": "today"}
|
||||
)
|
||||
body = r.json()
|
||||
assert body["cards"]["active_staff"] == 2 # u1 + wx2(按账号计)
|
||||
assert body["cards"]["unmapped_accounts"] == 1 # wx2 标注
|
||||
|
||||
|
||||
async def test_overview_unmapped_rollup(make_client, monkeypatch):
|
||||
"""rollup 路径未映射口径与回退路径一致:当窗 user_id 不在映射值集 → 未映射。
|
||||
|
||||
recompute 以 amap.get(owner, owner) 落表,映射不上的 owner 以原值进
|
||||
stat_daily_staff(user_id=wx2);account_map.values() 只含在册员工 user_id,
|
||||
wx2 落在值集之外 → 被识别并标注。
|
||||
"""
|
||||
monkeypatch.setattr(metrics, "today_key", lambda: _TODAY)
|
||||
|
||||
async def seed(session):
|
||||
session.add(WechatAccount(wx_id="wx1", user_id="u1"))
|
||||
session.add(StatDailyStaff(day=_TODAY, channel="wechat", user_id="u1",
|
||||
msg_sent=2, msg_recv=0,
|
||||
active_friends=1, active_rooms=0))
|
||||
session.add(StatDailyStaff(day=_TODAY, channel="wechat", user_id="wx2",
|
||||
msg_sent=1, msg_recv=0,
|
||||
active_friends=1, active_rooms=0))
|
||||
session.add(MsgDailyStats(channel="wechat", owner_account_id="wx1",
|
||||
peer_kind="friend", peer_id="t1", day=_TODAY,
|
||||
send_cnt=2, recv_cnt=0, last_ts=1788500000000,
|
||||
last_is_send=True))
|
||||
await session.commit()
|
||||
|
||||
client = await make_client(seed)
|
||||
r = await client.get(
|
||||
"/api/analytics/overview", params={"channel": "wechat", "scope": "today"}
|
||||
)
|
||||
body = r.json()
|
||||
assert body["cards"]["active_staff"] == 2
|
||||
assert body["cards"]["unmapped_accounts"] == 1
|
||||
|
||||
Reference in New Issue
Block a user