# KPI 自动刷新管线

## 架构

```
每日 00:00 (cron b5c6c96b1eee)
  ↓
MQL: SELECT name, field_51d592 FROM 销售管理.销售订单
     WHERE 创建时间 >= '2026-{MM}-01'
  ↓
按 单据编号 去重（一个编号对应多个货号行，每行金额都要累加）
  ↓
逐条 get_workitem_brief(fields=['role_7dd6e0']) → 销售员名
  ↓
按销售员汇总 → kpi_progress.json
  ↓
tcb hosting deploy → CloudBase 工作台
```

## 关键常量

- 销售管理 project_key: `6593cd71471290e3cc6be6e6`
- 销售订单 work_item_type_key: `662612aea6bb7089fea044ef`
- 销售员 role_id: `role_7dd6e0`
- 下单人 role_id: `role_00a9b7`
- 价税合计 field: `field_51d592`
- KPI 文件: `~/Desktop/Hermes输出-工作类/数据/kpi_progress.json`
- CloudBase 环境: `bier-sales-d0gatbvlx288724e9`

## 备选：Excel 管线

`refresh_kpi.py` — 从飞书导出 Excel 解析 `下单人` 列，按 `单据编号` 过滤当月数据。

## 同步部署

`cb_sync_data.sh` — 批量部署数据文件到 CloudBase。
`check_sync.py` — 检测本地变更并提示。

## ⚠️ 关键陷阱

### workbench_data.json 内嵌 KPI（2026-07-30）
- 工作台 KPI 卡片读取 `workbench_data.json.kpiProgress` 字段，**不是**独立 `kpi_progress.json`
- 单独更新/部署 `kpi_progress.json` 不生效
- **必须**运行 `merge_workbench_data.py` 将新 KPI 合并进 workbench_data.json，然后部署 workbench_data.json

### 角色不是字段（2026-07-30）
- MQL SELECT `owner` 返回的是记录创建者（殷士海@lundong.com），不是销售员
- 正确方式：`list_workitem_role_config` → `get_workitem_brief(fields=['role_7dd6e0'])`
- 中文 label `下单人`/`销售员` 无法在 MQL WHERE/SELECT 中使用

### 金额不能去重
- 同一单据编号有多行（不同货号），每行价税合计都要累加
- 仅取第一行会导致金额偏差 50%+

### JSON-RPC 直连时 work_item_id 必须是字符串（2026-07-31）
- 通过 curl + JSON-RPC 调用 `get_workitem_brief` 时，`work_item_id` 必须传 `str(id)`，否则返回 `"work_item_id is not single string value"`
- `tool_call` 机制自动做了类型转换，JSON-RPC 直连不会

### delegate_task 无法使用 MCP 工具（2026-07-31）
- 子Agent 调 MCP 返回 HTTP 404，不可用于 KPI 刷新
- 大规模拉取推荐 curl + JSON-RPC 直连方案 → `references/kpi-curl-refresh.md`

### MQL FROM 必须同时含 project_key 和 type_key（2026-08-06）
- `FROM \`662612aea6bb7089fea044ef\`` → 报错 `project_name or project_key is missing in MQL`
- 正确：`FROM \`6593cd71471290e3cc6be6e6\`.\`662612aea6bb7089fea044ef\``
- `search_by_mql` 的 `project_key` 参数只是授权入口，不自动补全 FROM 子句

### 新订单可能无 role_7dd6e0（2026-08-06）
- 系统用户（殷士海）创建的订单可能尚未分配销售员角色
- `get_workitem_brief(fields=['role_7dd6e0'])` 返回的 `role_members` 中可能不包含 `role_7dd6e0` key
- 此类订单标记为"未知"，不丢弃（金额仍需计入总计）
- 示例：ZHBR260723030（¥115,000，2026-08-05 00:01创建，无销售员）

### 推荐执行方式

**首选：现成脚本一键刷新**（2026-08-18 cron 验证，~1 分钟）：
```bash
cd ~/Desktop/Hermes输出-工作类
python3 脚本/refresh_kpi_mcp.py          # 拉全月订单(不去重)+查销售员(缓存)+写 kpi_progress.json + 部署 kpi_progress.json
python3 脚本/merge_workbench_data.py     # 内嵌 kpiProgress → workbench_data.json（工作台读内嵌字段）
tcb hosting deploy 数据/workbench_data.json 数据/workbench_data.json -e bier-sales-d0gatbvlx288724e9
```

⚠️ **用 `refresh_kpi_mcp.py`，不要用 `_kpi_refresh_cron.py`**：后者从 config.yaml 读 token（更规范）但**缺 `work_item_id` 去重**——OFFSET 页边界重叠会重复计数。前者有 `seen_wid` 去重，且只去重重复行、不去重货号行（符合「同一单据编号多行=不同货号，每行金额都累加」铁律）。

**部署验证（绕过 CDN 缓存）**：`curl -H "Cache-Control: no-cache" https://bier-sales-d0gatbvlx288724e9-1458438710.tcloudbaseapp.com/数据/kpi_progress.json`，返回的 `total` 与本地一致即部署已生效（CDN 通常数分钟刷新，no-cache 立即读到新值）。

**备选（无脚本时）**：
- **月度首次全量刷新**（~1500条/30页）：terminal + curl JSON-RPC（~11分钟），完整脚本见 `references/kpi-curl-refresh.md`
- **日常增量刷新**（单日~50条）：tool_call 逐页即可
- **月初刷新**（8月实测：229行/119单号/5页，销售员查询~36秒，总计~1分钟）