# 顺丰物流 + 飞书弹窗推送全链路

## 架构

```
sf_delivery_watchdog.py (cron: 20 9,15 * * *)
  ├─ ① pull_orders.py        MCP 拉 7 天内订单
  ├─ ② shipment_pipeline.py  顺丰查轨迹(批量10单，checkPhoneNo必传)
  ├─ ③ 状态 diff             对比 ~/.hermes/scripts/sf_watchdog_state.json
  └─ ④ 飞书卡片推送          按销售员 email → POST /im/v1/messages
```

## 关键字段映射

### pull_orders.py — MCP → 订单数据

| MCP 字段 | 输出字段 | 说明 |
|----------|---------|------|
| `name` | 单据编号 | 如 ZHBR260727023 |
| `field_96a245` | 物流单号 | 顺丰单号，如 SF5150058238731 |
| `field_3f38c1` | 收货人联系电话# | 顺丰 API 必传（取后4位） |
| `field_51d592` | 价税合计 | 销售订单类型，double_value |
| `field_e1001d` | 销售订单关联客户 | key_label_value.label = 客户名 |

### 销售员识别（三层降级）

1. **MCP 客户 owner** — `mcp_customers.json` 中按客户名匹配，过滤 `@biori.com` 邮箱
2. **ERP _key_customers** — `salesperson` 字段兜底（无邮箱，仅名称）
3. **跳过** — 无邮箱的不推送（避免飞书 API 400）

## 飞书消息 API

```
POST /open-apis/im/v1/messages?receive_id_type=email
Authorization: Bearer {tenant_access_token}
Content-Type: application/json

{
  "receive_id": "zhaoyunhao@biori.com",
  "msg_type": "interactive",
  "content": "{\"config\":{\"wide_screen_mode\":true},\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"📦 顺丰物流动态\"}},\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"lark_md\",\"content\":\"✅ 新签收 2 单\\n• 圣湘生物｜SF5112860018518｜¥371,396\"}}]}"
}
```

**关键点**：
- `receive_id_type=email` 直接用邮箱，不需要 user_key→open_id 转换
- tenant_access_token 从 `app_id` + `app_secret` 获取，2h 过期
- 消息卡片格式：interactive card，支持 lark_md

## Cron

```bash
cronjob create --name "顺丰物流监控推送" \
  --schedule "20 9,15 * * *" \
  --script sf_delivery_watchdog.py --no_agent \
  --deliver origin
```

每天 9:20 和 15:20 自动运行，有新签收/派送变化时静默推送飞书卡片。

## 已知限制

- 顺丰 API checkPhoneNo 需要手机后4位，但 MCP 收货人电话字段部分为空 → 无手机的单返回"暂无数据"
- 客户 owner 非 @biori.com 邮箱时无法推送（如何超锦、自动化规则、殷士海等）→ 需 IT 修正
- 首次运行只建基线（不推送），第二次开始检测变化
