# 千路·智贸中枢（AI-CRM）— 流程与规则说明

**范围**：本文档以 **询价管理系统** 的交易环节与数据规则为主。**出入库管理系统**（WMS）为千路产品另一部分，**持续开发中**，履约与库内细节以 WMS 需求文档为准，勿默认与本节流程等同。

本文档汇总项目中的**业务流程**、**数据校验规则**、**格式与命名约定**及**技术边界**，供开发与业务参考。业务术语与 UI 用词以同目录 [naming-and-terminology.md](naming-and-terminology.md) 为准。

*（本文件为 kam-qianlu-doc-standards SKILL 内冗余副本，便于独立打包后使用；与项目 `apps/inquiry-server/docs/functions/process-and-rules.md` 同步。）*

---

## 1. 项目定位与业务模式

- **产品**：智能询价管理中枢，用自动化和智能对比提升贸易效率。
- **业务模式**：公司作为贸易中间商，上游对接国内供应商，下游服务俄罗斯客户。
- **两大环节**：
  - **交易环节**：客户询价 → 供应商比价 → 客户报价 → 确认下单
  - **履约环节**：供应商交货 → 入库 → 装箱 → 报关清关 → 发票结算

---

## 2. 核心业务流程

### 2.1 交易环节（询价 → 下单）

```
俄罗斯客户                    我方（中间商）                    国内供应商
    │                              │                              │
    │  ① 发送询价单                 │                              │
    │ ──────────────────────────▶  │                              │
    │                              │  ② 向多家供应商询价             │
    │                              │ ──────────────────────────▶   │
    │                              │  ③ 供应商提交报价单             │
    │                              │  ◀──────────────────────────  │
    │                              │  ④ 按零件号比价（同品对比）      │
    │  ⑤ 向客户生成报价单/回询单     │                              │
    │  ◀──────────────────────────  │                              │
    │  ⑥ 客户确认（订货单）          │                              │
    │ ──────────────────────────▶  │  ⑦ 向选定供应商生成采购单       │
    │                              │ ──────────────────────────▶   │
```

**系统内对应**：

| 步骤 | 系统操作 | 数据实体 |
|------|----------|----------|
| ① 客户询价 | 创建询价单（或 Excel 导入） | `rfq`、`rfq_item` |
| ②③ 供应商报价 | 导入报价单并关联询价单 | `quotation`、`quotation_item`，关联 `rfq_id` |
| ④ 比价 | **报价对比**（询价子系统）：① **基准单对比**——选基准报价单，与历史有效报价（`is_valid=1`）比低价，导出对比 Excel；② **品牌矩阵对比**——选品牌 + 报价日期范围，按供货商矩阵导出（仅有效报价单明细） | `quotation_item` + 品牌归一化；对比结果见导出文件，无单独「客户上传模板」 |
| ⑤ 给客户报价 | 生成/维护回询单（价格可编辑） | `rfq_reply`、`rfq_reply_item` |
| ⑥ 客户确认 | 导入订货单，必选询价单，行与回询单匹配 | `customer_order`、`customer_order_item`，匹配 `rfq_reply_item` |
| ⑦ 给供应商采购 | 采购单工作台 / 已确认采购：按供应商拆分、导出采购单 Excel、回传校对（见文件标准第八～九节） | 工作台草稿多在前端 localStorage；`purchase_workbench` 以当前迁移/库表为准；`confirmed_purchase` 含 `order_id`；导出路由为 `/api/purchase/export`、`/export-supplier` 等（非 `export-workbench`） |

### 2.2 履约环节（交货 → 结算）

```
国内供应商                我方（仓库/单证）                 海关/物流              俄罗斯客户
    │                          │                            │                      │
    │  ① 供应商交货（交货单）    │                            │                      │
    │ ────────────────────▶    │  ② 验收入库                 │                      │
    │                    ③ 仓库装箱                        │                      │
    │                    ④ 报关/清关文件                    │  申报/清关            │
    │                    ⑤ 发票明细、发票比对                 │                      │
```

当前系统主要覆盖**交易环节**；履约环节为 P1 规划，随需求推进。

---

## 3. 数据校验规则

### 3.1 报价单内：同品牌+同零件号报价一致

| 规则 | 说明 | 实现位置 |
|------|------|----------|
| 同一报价单内，相同 `brand` + `part_number` 且 `price_status=1`（已报价）的行，`quoted_price` 必须相同 | 避免同一张报价单中同品多价导致比价混乱 | 导入时：`shared.utils.check_price_consistency()`；入库后：`scripts/check_inquiry.py` |

- **导入时**：解析完批次后调用 `check_price_consistency(batch)`，若有冲突返回冲突列表，前端弹窗警告，**不阻断导入**。
- **脚本校验**：`python scripts/check_inquiry.py [--quotation-no xxx]` 可检查指定报价单或全部。

### 3.2 订货单导入：行必须匹配回询单

| 规则 | 说明 | 实现位置 |
|------|------|----------|
| 导入订货单必须先选择询价单（`rfq_id`） | 订货单与询价单 N:1 | `order_import_service.import_order_excel` |
| 该询价单下必须存在已确认的回询单（`rfq_reply.status=1`） | 否则无法匹配行 | 同上 |
| 每一订货行必须能按（品牌、零件号、客户单价）匹配到该询价单下某条回询单行 | 匹配键：`brand`、`part_number`、`unit_price` ≈ `customer_price`；任一行不匹配则**整单拒绝导入** | 同上 |

- 订货单**无替换号**列也可导入；替换号为选填，有则存 `customer_order_item.replace_no`。
- 若存在目标价（Target）列，目标价与回询单价不一致时提示，**不阻断导入**。

### 3.3 订货行有效性与采购确认

| 规则 | 说明 |
|------|------|
| 订货行可有有效/无效状态（`customer_order_item.is_valid`，1=有效，0=无效） | 无效行不参与采购单生成与导出 |
| 若某行已在采购单中确认采购（`purchase_confirmation` 有记录），则**不允许直接修改**该行的有效状态 | 需先在采购 Tab 解除该行的采购确认，再回校对页修改有效性 |
| 采购单生成与导出只包含有效订货行（`is_valid=1`） | 导出 Excel 中 Invalid 列默认留空，由供应商标注不供货后，回传校对再更新为无效 |

### 3.4 采购单回传校对：Invalid 与替换号

| 规则 | 说明 |
|------|------|
| 回传文件命名约定：`校对-采购单-{供应商名或自由文本}.xlsx` | 用于识别为采购单回传校对 |
| Invalid 列：留空=供货；有值（Y/Yes/是/1 等）= 不供货，对应订货行标为无效（`is_valid=0`） | 与订货单 Invalid 列语义一致 |
| **替换号可定性优先于 Invalid**：替换号在 `part_availability` 中不可定时，无论 Invalid 是否填写，该行均标为无效（替换号不可定） | 上游客户不接受不可定替换号 |
| 已确认采购的行：回传校对若要将该行标无效，**不自动解除采购确认**，预览中提示需先解除采购确认后再改 | 保证采购确认的权威性 |

---

## 4. 品牌名归一化规则

报价对比、回询单聚合等按「品牌 + 零件号」匹配时，品牌名先做归一化再比较。

| 策略 | 说明 |
|------|------|
| 大小写统一 | 先 `strip().upper()` 再查别名或使用 |
| 别名映射 | 见下表，维护在 `shared/utils.py` 的 `BRAND_ALIASES` |

**当前别名表**（`shared/utils.py`）：

| 原始名称 | 标准名称 |
|----------|----------|
| LUK | INA-LUK |
| INA | INA-LUK |
| MANN | MANN-FILTER |

- 新增别名：编辑 `shared/utils.py` 中 `BRAND_ALIASES`；若后续改为库表配置，以库表为准。

---

## 5. 文件名与格式规范

### 5.1 上传文件名约定

| 单据类型 | 格式 | 示例 |
|----------|------|------|
| 报价单 | `报价单-XXX-日期.xlsx` 或 `报价单-XXX日期.xlsx`；日期支持 YYYYMMDD 或 YYYY-MM-DD | `报价单-ROLF001-20260304.xlsx` |
| 询价单 | `询价单-XXX-日期.xlsx`，日期 6 位或 8 位 | `询价单-RFQ202603-20260304.xlsx` |
| 订货单 | `订货单-XXXX-日期.xlsx`，日期支持 YYYYMMDD 或 YYYY-MM-DD | `订货单-YUDA2301-20260305.xlsx` |
| 采购单回传校对 | `校对-采购单-{供应商名或自由文本}.xlsx` | `校对-采购单-北方通宝.xlsx` |

校验逻辑在 `shared/utils.py`：`validate_quotation_filename`、`validate_rfq_filename`、`validate_order_filename`。

### 5.2 Excel 列名识别（报价单/询价单/订货单）

系统通过关键词匹配表头（前几行内包含「品牌」或 brand 的行作为表头行），支持多语言/多别名，例如：

| 字段 | 可识别的列名示例 |
|------|------------------|
| 品牌 | 品牌、BRAND、Brand |
| 零件号 | 零件号、Part、Parts、Part No、Part No. |
| 替换号 | 替换号、变号、编号、中国、CN、China、Mann No |
| 数量/件数 | 数量、QTY、件数 |
| 报价含税 | 报价含税、含税报价、价格、报价、Price |
| 单价（订货单） | 单价、货物单价、含税单价、价格、PRICE |
| 无效 | Invalid、无效、作废 |

具体别名集见项目 `server/services/order_import_service.py` 的 `ORDER_HEADER_ALIASES` 及 `shared/utils.py` 的列映射；本 SKILL 的 [REFERENCE.md](REFERENCE.md) 第一～十节为表头与文件名权威。

---

## 6. 报价解析规则（报价单 Excel）

| 规则 | 说明 |
|------|------|
| 报价列（价格单元格） | 数字 → 已报价（`price_status=1`）；空 → 未报价（0）；`X`、`#N/A`、非数字文本 → 无法报价（2），原文保留到备注 |
| 日期 | 可从文件名中提取 8 位日期作为报价日期；也支持表单传入 |
| 报价单名 | 默认从文件名去掉 `.xlsx` 得到；可编辑 |
| 品牌名 | 从文件名或表单解析；导入时可选关联询价单、供应商 |

---

## 7. 回询单与订货单数据关系

### 7.1 实体关系

- **询价单** `rfq`：一个询价单下有多个 `rfq_item`（询价明细）。
- **回询单** `rfq_reply`：与询价单 N:1（`rfq_id` 必填）；一个回询单下多条 `rfq_reply_item`（品牌、零件号、数量、客户单价等）。
- **订货单** `customer_order`：与询价单 N:1（`rfq_id` 必填）；一个订货单下多条 `customer_order_item`。
- **订货行 ↔ 回询单行**：N:N，通过 `customer_order_item_reply_item` 关联；匹配键为（品牌、零件号、客户单价）。

### 7.2 回询单生成与维护

- 回询单由「该询价单下有效报价单」比价结果生成；按品牌+零件号取最低价等逻辑在 `rfq_reply_service`。
- 回询单价格可编辑，保存到 `rfq_reply_item.customer_price`；订货单导入时用此单价与订货行 `unit_price` 匹配。

### 7.3 采购单生成依赖

- 以订货单为入口，关联询价单 → 该询价单下的回询单、报价单。
- 每条订货行通过回询单行找到选定的供应商与报价行（`selected_supplier_id`、`selected_quotation_item_id`），再按供应商维度汇总生成采购单。

---

## 8. 替换号与可定性（part_availability）

- **替换号**：零件在中国市场的对应编号（如 `quotation_item.cn_part_number`、`customer_order_item.replace_no`）。
- **可定性**：来自 `part_availability` 表（可订/不可订、来源、更新日期等）。
- **规则摘要**：
  - 采购单回传中，若替换号在 `part_availability` 中为不可订，则该订货行标为无效（替换号不可定优先于 Invalid 列）。
  - 回传中出现系统未收录的新替换号时，可写入 `customer_order_item.replace_no` 并标记 `replace_no_is_new=1`，供校对页标注「新替换号待确认」，不自动标无效。
  - 订货单导出时，替换号列仅填写需要客户关注的新替换号与不可定替换号，已有有效替换号可不填。

---

## 9. 术语与命名

- 所有业务术语、UI 用词、文件名规范以同目录 **[naming-and-terminology.md](naming-and-terminology.md)** 为准。
- 关键约定：报价单对应 `quotation`；「零件号」仅指标识明细的 `part_number`，报价单主表标识用「报价单名」；统一用「替换号」而非「中国零件号」；统一用「采购单」而非「采购订单」。
