# 客户归属权威源：《诊断原料&生命科学客户清单》

## 结论

**归属最高权威源 =《诊断原料&生命科学客户清单YYYYMMDD.xls》的「部门表」**，
优先级链：`官方清单(auth_list) > 重点客户表(key_customers) > 月报库(report_store) > detail`。

- 导入脚本：`脚本/import_auth_customers.py` → `数据/pricing/_auth_customers_<日期>.json`
- 权限表校正：`脚本/align_key_customers.py [--apply]`
- 消费方：`脚本/build_customer_360.py` 的 `load_auth_sales()`（priority 0）

## 表结构陷阱

| 表 | 列 | 陷阱 |
|---|---|---|
| 大客户销售部 / 销售拓展部 | 序号\|集团简称\|客户名称\|销售员\|是否上市 | 5 列，客户名 idx2、销售员 idx3 |
| **生命科学销售部** | 序号\|客户名称\|销售员\|区域 | **只有 4 列**，客户名 idx1、销售员 idx2；按 idx2/idx3 读会把「区域」当销售员 |
| 华北华西/华中华南/华东 | 集团简称\|客户名称\|销售员 | **旧快照，弃用** |

## 判定「哪张表是权威」的方法（可复用）

文档自带「汇总表」（按部门→按人给客户数）。**按人统计部门表，与汇总表逐人比对**：
全中 → 部门表自洽、可信；区域表人名（如已离职的龙友波、不在册的李丽佳）根本不在汇总表里
→ 区域表是历史快照。**不要凭「哪张表看起来新」判断，用汇总表对账。**

另注意文档计数口径：集团算 1 个单位（汇总表），而明细表按客户实体逐行展开，
所以「汇总表 51」对「部门表 92 行」不是矛盾。

## 交叉验证（改权限表前的必做步骤）

用第三个独立源验证方向，不要只信一份文件：
- 基准项：用业务方已确认的既成事实（如「英和领源＝陈溪子」）先验三个源是否都指向它；
- 批量项：统计「官方清单 vs 月报库」的同向/分歧/无记录数。
  **本次 46 处分歧 100% 同向、0 分歧**，才敢落库。
- 单边证据（只有一份文件支持）时不要改，先报给用户。

## 官方清单的三种特殊取值

1. **区域占位**：销售员列填「上海」这类区域名（非人名）→ 记入 `unassigned`，
   后续数据源**不得顶替成人名**（`load_auth_sales()` 里用 `unassigned` 集合拦截）。
   否则前端会把「上海」显示成某个销售员。
2. **联合归属**：值形如「吴云/韩远怀」→ 双线/共管，原样保留。
3. **双线客户**（24 个）：同一客户同时出现在诊断线 + 生命科学线、两人不同。
   数据模型须按 `(业务线, 销售员)` 二元组存，用 `sales_line` 字段区分 `da`/`ls`；
   单值 `sales` 只能存主线，会让 ls 人员的客户数被低估。

## 集团简称列的价值

官方清单带显式「集团简称」（本次 182 个集团 / 覆盖 418 客户），
**解决了「重点表只有集团聚合条目时，具体子客户拿不到归属」的结构性缺口**
（此前需靠月报库回填 796 条来源不明的归属）。
`auth_group()` 优先于 detail 的 group 字段。

## 集团聚合条目的同步规则

`_key_customers.json` 里的集团条目（如「圣湘集团」）：
- 成员销售员**唯一** → 同步为该人；
- 成员**跨多人** → **保留不动**（真实多人共管，不可强判）。

## 归属来源可审计字段

每条归属写 `sales_source`：`auth_list` / `key_customers` / `report_store` / `unassigned` / `detail`。
**不标记等于把未逐条确认的归属藏进「100% 覆盖」，比留空更危险。**
验收标准：官方清单命中部分与清单 **0 不一致**、金额来源 100% = `auth_list`、离职人员残留 0。

## 上线后必查的三项

1. 档案与官方清单逐条对照 → 不一致数必须为 0；
2. `_key_customers.json`（权限源）与官方清单对照 → 不一致数必须为 0；
3. CDN 拉回 JSON 实测（`curl -H "Cache-Control: no-cache"` + `?t=<ts>`），
   确认改动的客户在**线上**已生效，而不只是本地文件。

## CDN 路径陷阱

- 工具页部署在 **CDN 根级** `/工具/xxx.html`，**不是** `/workbench/工具/`；
  工作台 `index.html` 里用的是绝对路径 `/工具/...`（`/workbench/` 只有 index.html）。
  路径猜错会拿到 404 `NoSuchKey`。
- 中文路径必须**分段编码**：`"/".join(quote(s, safe='') for s in path.split("/"))`。
  整串 `quote(path)` 会把 `/` 编成 `%2F` → CloudBase 报 `NoSuchKey`。
- `工具/` 工具页不进 `file_manifest.json`（manifest 只收内容文件）。
