# 客户价格表生成模式（2026-07-10）

## 概述

从多年度ERP订单Excel中提取指定客户的完整采购历史，按货号#聚合，生成结构化JSON + 交互式HTML面板。

## 数据源

| 年份 | 路径 | Sheet | 行数 |
|------|------|-------|------|
| 2024 | `销售分析/2026订单分析/2024全年订单.xlsx` | Sheet1 | 26,661 |
| 2025 | `销售分析/2026订单分析/2025全年订单.xlsx` | Sheet1 | 30,630 |
| 2026H1 | `销售分析/2026订单分析/2026年1-6月订单.xlsx` | Sheet1 | 16,629 |

⚠️ **Sheet陷阱**：默认Sheet0是透视表，原始数据在Sheet1。遍历Sheet找含"客户"+"物料编码"列的。

## 字段映射

| 用途 | 列名 | 备注 |
|------|------|------|
| 客户 | `客户` | 精确匹配 |
| **货号#** | `货号#` (col21) | 2025文件有，2024/2026H1用`物料编码`fallback。一个货号可对应多个物料编码 |
| 物料编码 | `物料编码` | 内部编码，更细粒度 |
| 品名 | `物料名称` | |
| 规格 | `客户物料规格型号#`(col22) | 2025文件有；其他文件从`物料名称`正则提取浓度(如`5×`)，fallback到`销售单位` |
| 含税单价 | `含税单价` | NaN=免费 |
| 价税合计 | `价税合计` | |
| 销售数量 | `销售数量` | |
| 赠品标识 | `是否赠品` | "是" 或金额=0 |
| 日期 | `合同日期`/`合同月份` | 按文件不同 |

## 聚合：货号# vs 物料编码

- **用货号#聚合**（客户关心的对外SKU）→ 同一货号的多个物料编码（批次/规格差异）合并
- 物料编码留作内部追溯，不对外展示

## 价格字段定义

| 字段 | 含义 | 算法 |
|------|------|------|
| 最近成交价 | 最近一次有价采购的含税单价 | 按日期排序取最后一条 unit_price>0 |
| 历史成交价 | 价格区间 | `min~max`，单一时仅显示一个值 |
| 总成交金额 | 累计价税合计 | `sum(价税合计)` |

## 赠品识别

```python
is_gift = ('是' in str(是否赠品)) or (amt == 0)
```
赠品行半透明（opacity:.5），最近成交价="免费"。

## 规格提取

```python
import re
spec = ''
m = re.search(r'(\d+[×xX]\S*)', name)    # 5×, 10×
if m: spec = m.group(1)
if not spec and '客户物料规格型号#' in df.columns:
    spec = str(row['客户物料规格型号#'])
if not spec:
    spec = str(row.get('销售单位', ''))     # U, ml, T, 盒
```

## JSON输出结构

```json
{
  "customer": "深圳市新产业生物医学工程股份有限公司",
  "short_name": "新产业",
  "total_amount": 91240,
  "total_orders": 265,
  "years": ["2024", "2025", "2026"],
  "products": [{
    "sku": "M5274-073703",
    "name": "5×Neoscript RT Premix OT-UNG...",
    "spec": "5×",
    "total_qty": 45600, "total_amt": 82420,
    "latest_price": 2.60, "latest_price_date": "2026-06",
    "history_price": "2.6", "min_price": 2.60, "max_price": 2.60,
    "latest_date": "2026-06", "years": "2025, 2026H1",
    "is_gift": false
  }]
}
```

## 全量客户扩展 + 合并JSON加载（2026-07-11）

### 从KA到全量

初版仅覆盖大客户部89家。用户要求扩展到所有客户后，批量生成脚本扫描全部3年ERP（73,920行），匹配客户清单中的1,535家客户：

- 1,197家有ERP采购记录（生成独立JSON）
- 338家无ERP记录

### 合并JSON优化

1,197个独立JSON导致页面加载1,197次HTTP请求，极慢。解决方案：预生成单一合并文件：

```python
# 将所有客户的产品平铺到 _all_products.json（30,711条，~7MB）
products = []
for fn in os.listdir('数据/pricing/'):
    with open(fn) as f: d = json.load(f)
    for p in d['products']:
        products.append({'customer': d['customer'], 'sku': p['sku'], ...})
```

前端从 `fetch` 1197次 → 1次，秒级加载。

### 展示模式变更

从**两级钻取**（客户列表→点击展开产品）改为**单层产品表**：

| 客户 | 货号 | 最新价格 | 累计金额 | 最近采购 | 历史价格 |

所有产品平铺在一张表，赠品行半透明。

## 官方人员清单集成（2026-07-11）

用户提供了`统一工作台运行及授权.xlsx`，包含42人官方清单。替换了之前从客户清单推导的销售员映射。

### 人员清单结构

| 字段 | 说明 |
|------|------|
| 销售员 | 姓名（42人） |
| 部门 | 大客户部/销售拓展部/生命科学销售部 |
| 角色 | 销售总监/部门经理/区域经理/销售工程师/管培生 |
| 价格权限 | v1-v5 |
| 是否在职 | 在职22人 / 离职19人 / 调岗1人 |

### 价格权限体系

| 产品线 | v5 | v4 | v3 | v2/v1 |
|--------|----|----|----|----|
| 诊断原料 | 梯度价8折 | 8折 | — | 9折 |
| 生命科学 | 促销价5折 | 7折 | — | 8折 |

⚠ 报价低于权限范围需启动审批流程。

### 登录页更新

- 仅显示22名在职人员（排除20名离职/调岗）
- 显示 `[v1]-[v5]` 权限等级 + 所属部门 + 名下客户数
- 登录页展示完整价格权限参考卡
- 登录后KPI区显示当前用户可授权折扣范围

## 用户偏好

⚠ **客户价格表页面不要轻易改动**（2026-07-11 用户明确要求）。页面结构稳定后，后续迭代在独立分支/测试页进行。
