## [ERR-20260425-003] ADP WFN Time Off API 是 v3 不是 v2；`$filter` 三件套必填

**日期**: 2026-04-25
**类别**: ADP API
**严重度**: 高（之前误判为权限问题，浪费多个 session 催管理员）

### 问题描述
长期以来访问 `/time/v2/workers/{aoid}/time-off-requests` 返回 404 `Canonical URI Not Found`，多次以为是 ADP Developer Portal 上 "List Of Requests" 权限没开通，反复催管理员。

### 真正根因
1. **路径版本错**：ADP WFN（schemeAgencyName=WFN）的 Time Off API 是 **`/time/v3/...`**，不是 v2。v2 在 WFN 上根本不存在，所以返 "Canonical URI Not Found" 不是因为 scope，而是 URI 本身没有。
2. **`$filter` 必填三件套**：路径修对后 v3 端点要求 `$filter` 必须同时包含 datePeriod/startDate、datePeriod/endDate、requestStatusCode/codeValue 三个条件，缺 status 会报 "missing :STATUS"。
3. 改对路径 + 三件套 filter 后立即 HTTP 200 返回真实数据。

### 排查方法（下次照做）
ADP 返 "Canonical URI Not Found" 时按这个顺序排查：
1. 用同 token 调 `/hr/v2/workers` 验证 token + mTLS 健康
2. 从官方 PDF guide（marketplace-cdn.adp.com/dev-portal/pdf/...）拉端点路径，**特别注意版本号**（v1/v2/v3，按产品不同：WFN 主要 v2 HR + v3 Time Off；Workforce 是 v3；Time Connect 是 v3）
3. 查 PDF "Application Scope" 段，确认 canonical scope URI；让管理员到 Portal 对照添加
4. 查 PDF "Supported OData Query Options"，看 $filter 是否必填、字段是哪些
5. 路径和 filter 都对了仍报错，才考虑 scope 没开

### 工具：从 ADP marketplace PDF 提取 API 路径
PDF 用 Chromium 生成，pdftotext 找不到时用 Node：
```bash
cd /tmp && npm install --no-save pdf-parse
node -e "
const { PDFParse } = require('pdf-parse');
const fs = require('fs');
(async () => {
  const p = new PDFParse({ data: fs.readFileSync('xxx.pdf') });
  console.log((await p.getText()).text);
})();
"
```
注意 `pdf-parse` v2+ 的 API 是 `PDFParse` 类，不是默认 export 的函数。

### 关键启示
- ADP "Canonical URI Not Found" 错误信息**对路径错误和 scope 缺失给出完全相同的 404**，无法从响应区分。**先怀疑路径，再怀疑权限**。
- 不同 ADP 产品（WFN / Workforce / Time Connect / iHCM / Link）有不同的 API 版本号和 endpoint 习惯。**确认实例所属产品**（看响应 header `schemeAgencyName`）后再翻对应 PDF。
- 自己 agent 以"权限没开"为由让管理员去操作，没拿到 200 就别下"已开通"或"未开通"的结论，否则容易让对方背锅 + 浪费时间。

---
