# ERP导出文件列布局变异

不同时期的ERP导出文件，列布局可能不完全一致。**严禁假设列索引固定，每次处理前必须先打印列头确认。**

## 已知变异案例

### 2026年7月导出（标准格式）
```
Col0=合同日期 (datetime)  // 日期时间型
Col1=单据类型
Col2=单据编号
Col3=单据状态
Col4=客户
Col5=销售员           // 5号位
Col6=关闭状态
Col7=物料编码
Col8=物料名称
Col9=销售单位
Col10=销售数量
Col11=含税单价
Col12=税率%
Col13=价税合计        // 13号位
Col14=是否赠品
...
Col24=产品类型#
Col25=产品大类#
Col26=销售分组（二级）
```

### 2026年8月24日导出（新格式变体·无销售员列·金额不含税）

**触发**：用户上传 `销售订单_20260801-0824订单ERP导出.xlsx`（仅当月8/1~8/24），与标准格式差异极大：

| 字段 | 标准(7月) | 8/24新格式 | 说明 |
|------|----------|-----------|------|
| 销售员 | Col5 | **无此列** | `对应组织`列全空；销售员需用映射兜底 |
| 金额 | 价税合计(Col13,含税) | **金额(Col15,不含税)** | 必须 ×(1+税率) 才是价税合计 |
| 税率% | Col12 | Col14 | 实测统一13% |
| 单据编号 | Col2 | Col3 | 用于精确匹配 |

**验证结论（铁律）**：`金额 × 1.13 = 价税合计`（8/1~8/16 逐日与旧文件完全吻合，误差0）。

**销售员兜底方案**（`erp_sales_core.py` 已实现，2026-08-24）：
1. `order_sp_map.json`：单据编号→销售员（从旧全量文件提取，精确匹配，优先）
2. `customer_sp_map.json`：客户→销售员（取最近月份最常见，兜底新订单/新客户）
3. 仍未映射 → 按 `客户采购类型#` 推断部门（生命科学→生命科学部，诊断→销售拓展部）

**⚠️ 仅当月文件会清空历史月**：`mcp_kpi_pipeline.py` 原逻辑从文件重建 H1(1-6月) 和 H2 各月，拿"仅8月"文件跑会把 H1 和 7月 全清零。**已修复**：H1 仅在文件含 H1 月时更新；H2 仅更新文件中存在的月份；totals 从部门汇总反推。

### 2026年H1订单导出（旧格式变体）
```
Col0=合同月份 (YYYY-MM 字符串)  // 字符串型，非datetime！
Col1=单据类型
Col2=单据编号
Col3=单据状态
Col4=客户
Col5=区域              // 多了区域列
Col6=销售员            // 6号位（比7月偏右1列！）
Col7=物料编码
Col8=物料名称
Col9=销售单位
Col10=销售数量
Col11=含税单价
Col12=税率%
Col13=价税合计         // 13号位（比7月偏左1列）
Col14=要货日期
Col15=是否赠品         // 比7月偏右1列
```

## 关键差异

| 字段 | 7月导出列 | H1导出列 | 差异 |
|------|----------|----------|------|
| 销售员 | Col5 | Col6 | H1多了一列"区域" |
| 价税合计 | Col13 | Col13 | 巧合相同 |
| 是否赠品 | Col14 | Col15 | H1偏右1列 |
| 日期格式 | datetime | "YYYY-MM"字符串 | 完全不同 |

## 检测方法

每次加载新ERP文件时必须执行：

```python
# 打印所有列头
for c in range(1, min(ws.max_column + 1, 35)):
    h = str(ws.cell(1, c).value or '').strip()
    print(f"Col{c-1}: {h}")
```

然后用 Python dict 按名称查找而非硬编码索引：

```python
headers = {}
for c in range(1, ws.max_column + 1):
    headers[str(ws.cell(1, c).value or '').strip()] = c - 1

sp_col = headers.get('销售员', 5)  # 按名查找 + 兜底
amt_col = headers.get('价税合计', 13)
gift_col = headers.get('是否赠品', 14)
```

## 异常大单检测

H1文件发现冯贤平有一笔 ¥23,076,867 的单笔订单（ZHBR260104002），远超正常水平。此类异常需排查：

1. 是否为内部调拨/冲抵
2. 是否为数据录入错误（销售员选错）
3. 是否为真实巨额订单

排查命令：
```python
# 按销售员+单据编号聚合，找出单笔>500万的订单
big_orders = defaultdict(float)
for r in range(2, ws.max_row + 1):
    sp = str(ws.cell(r, sp_col).value or '').strip()
    oid = str(ws.cell(r, doc_col).value or '').strip()
    amt = float(ws.cell(r, amt_col).value or 0)
    key = f"{sp}|{oid}"
    big_orders[key] += amt

for k, amt in sorted(big_orders.items(), key=lambda x: x[1], reverse=True):
    if amt > 5000000:
        print(f"⚠️ 异常大单: {k} = ¥{amt:,.0f}")
```
