feat(management): 通话日聚合小表——无渠道维/接通=duration>0/24h任一账号跟进(渠道按通话类型收窄)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-09 13:51:11 +08:00
parent 99773f69b9
commit b2e1b699eb
2 changed files with 201 additions and 0 deletions
@@ -0,0 +1,69 @@
"""employee_call_daily / employee_metric_daily 生成判别测试(批次A Task5/6)。
判据(v2 §1.1 #2/#5、§1.2 #9、§1.3 #11):
- 通话无渠道维,独立小表;接通=duration>0;followup=24h 内任一账号有消息;
- 幽灵员工(owner 映射不上/不在 staff)过滤;
- 宽表消息计数 friend-only;串类与 fact 同源。
"""
import datetime as dt
from zoneinfo import ZoneInfo
import sqlalchemy as sa
from app.db.models import (
EmployeeCallDaily,
Message,
PhoneCall,
Staff,
WechatAccount,
)
from app.storage.employee_metrics import recompute_call_days
_SH = ZoneInfo("Asia/Shanghai")
def _ts(*args) -> int:
return int(dt.datetime(*args, tzinfo=_SH).timestamp() * 1000)
async def _seed_org(session):
session.add(Staff(user_id="u1", name="张三", is_on_job=True))
session.add(WechatAccount(wx_id="wx1", user_id="u1"))
await session.commit()
async def test_call_daily_aggregates(make_session):
s = make_session
await _seed_org(s)
s.add(PhoneCall(call_id="c1", channel="voice_call", user_id="u1",
call_number="p1", start_call_time=_ts(2026, 9, 1, 10, 0),
call_duration=120))
s.add(PhoneCall(call_id="c2", channel="voice_call", user_id="u1",
call_number="p2", start_call_time=_ts(2026, 9, 1, 15, 0),
call_duration=0)) # 未接通
# c1 后 2h 员工有跟进消息(多账号语义:u1 只有 wx1)
s.add(Message(msg_id="f1", channel="wechat", owner_account_id="wx1",
talker_id="p1", timestamp=_ts(2026, 9, 1, 12, 0),
is_send=True, type="text", text="跟进"))
await s.commit()
n = await recompute_call_days(s, [20260901])
await s.commit()
assert n == 1
row = (await s.execute(sa.select(EmployeeCallDaily))).scalar_one()
assert row.call_count == 2
assert row.call_seconds == 120 # duration 单位=秒(Task0 已核实)
assert row.answered_call_count == 1
assert row.call_followup_count == 1
async def test_call_daily_ignores_unknown_staff(make_session):
s = make_session
await _seed_org(s)
s.add(PhoneCall(call_id="c9", channel="phone_call", user_id="ghost",
call_number="p9", start_call_time=_ts(2026, 9, 1, 10, 0),
call_duration=60))
await s.commit()
await recompute_call_days(s, [20260901])
await s.commit()
assert (await s.execute(
sa.select(sa.func.count()).select_from(EmployeeCallDaily))).scalar_one() == 0