# 订单与定制部件状态梳理

来源文档：[ERP功能与权限需求规格草案_V1.0.md](ERP功能与权限需求规格草案_V1.0.md)

本文重新梳理三类状态：

- 订单状态
- 定制部件-镜框状态
- 定制部件-镜片状态

核心原则：订单主状态、部件主状态、定制履约阶段、Hold 状态、异常状态、付款状态、退款状态、发货状态应分字段表达，不能互相覆盖。

# 1. 总体状态原则

## 1.1 Shopify 与 ERP 边界

普通销售订单的核心业务资料以 Shopify 为主，包括订单、商品、数量、处方、地址、金额、退款等。

ERP 负责保存 Shopify 同步版本、内部执行状态和执行记录，包括：

- 订单核查
- 镜框采购或库存占用
- 镜片下单
- 裁片加工
- QC
- 仓库发货
- 客服工单
- 供应商对账
- 审计日志

普通销售订单不得在 ERP 手工补建；同步失败应走异常处理和重试。

## 1.2 Hold 独立于生产状态

Hold 是独立暂停状态，不应覆盖订单原生产阶段。

示例：

```text
生产状态 = 部件准备中
Hold状态 = 已暂停
```

解除 Hold 后，订单应回到原生产阶段继续流转。

Hold 来源可以包括：

- 镜框无库存
- 处方异常
- 客户修改订单
- 地址异常
- 付款或补差价问题
- 运营人工暂停

## 1.3 异常不等于取消

异常表示当前对象需要人工处理；取消表示对象已终止，不再参与正常履约。

异常状态从主状态中剥离，使用独立状态字段表示。订单、镜框部件、镜片部件的主状态都只表达正常履约进度或终止结果；异常发生时保留原主状态，同时写入异常状态、异常原因和异常日志。

异常可以恢复，取消原则上不可恢复，只能创建新关联单据或重新生成履约对象。

## 1.4 重做、补发、换货

重做、补发、换货必须创建独立关联订单，不覆盖原订单。

退货只建立退货记录，不作为订单类型。

# 2. 订单状态

## 2.1 建议拆分字段

订单层建议至少拆分为以下状态维度：

| 状态维度 | 建议字段 | 说明 |
| --- | --- | --- |
| 订单类型 | `type` / `order_type` | 普通、红人、重做、补发、换货。退货不是订单类型。 |
| 审核状态 | `audit_status` | 编辑中、审核中、退回、审核通过。红人订单必须下单员审批。 |
| 主状态 | `status` | 定制项目订单主流程状态，可承载核查、镜框、镜片、齐套、裁片、QC、待发货等履约阶段。 |
| 付款状态 | `pay_status` | 未付款、部分付款、已付款等。 |
| 退款状态 | `refund_status` | 无退款、部分退款、全额退款。 |
| 发货状态 | `delivery_status` | 未发货、运输中、部分发货、已发货、已签收。 |
| 看板阶段 | `custom_stage` / 聚合字段 | 可由订单主状态直接提供，也可由定制履约项、部件和工序聚合后展示。 |
| Hold 状态 | `hold_status` / `pause_status` | 独立暂停状态，不覆盖主状态和履约阶段。 |
| 异常状态 | `abnormal_status` | 是否存在未处理业务异常。 |

## 2.2 订单类型

| 类型 | 说明 | 创建来源 |
| --- | --- | --- |
| 普通订单 | Shopify 销售订单 | Shopify 自动同步，ERP 不允许手工创建 |
| 红人订单 | 样品或合作订单 | 红人开发专员/红人组长在 ERP 创建，下单员审批 |
| 重做订单 | 售后重做 | 下单员创建，必须关联原订单 |
| 补发订单 | 售后补发 | 下单员创建，必须关联原订单 |
| 换货订单 | 售后换货 | 下单员创建，必须关联原订单 |

## 2.3 订单主状态

作为定制化项目，`sale_order.status` 可以从通用销售订单生命周期调整为“订单执行主状态”。它应直接服务生产看板和履约推进，表达订单当前最主要的执行阶段。

付款、退款、发货、Hold、异常仍应独立表达：

- `pay_status` 表达付款。
- `refund_status` 表达退款。
- `delivery_status` 表达物流/发货。
- `pause_status` 或 Hold 记录表达暂停。
- `abnormal_status` 表达是否有未处理异常。

订单和部件主状态统一约定：`-1=已取消`，`100=已完成`。正常流转状态值控制在 `0-99` 内，异常状态从主状态中剥离，使用独立异常字段表示。

镜框和镜片是并行推进的部件，不应在订单主状态中拆成互斥的“待镜片下单、镜片生产中、待镜框”。订单主状态应表达订单整体推进到哪个大阶段；镜框库存/采购进度、镜片下单/生产进度分别落在 `custom_item_component`、供应商状态和相关单据中。

订单主状态建议如下：

| 状态值 | 状态名 | 业务含义 | 备注 |
| --- | --- | --- | --- |
| -1 | 已取消 | 订单终止，不再正常履约 | 取消后不应硬删除 |
| 0 | 待核查 | 检查处方、PD、商品、镜片 SKU 是否完整正确 | Shopify 同步后或红人订单审批通过后进入 |
| 10 | 部件准备中 | 镜框和镜片并行启动：镜框占库/采购，镜片匹配供应商并生成下单单 | 部件细节看镜框、镜片部件状态 |
| 20 | 待齐套 | 镜框和镜片路径已启动，等待双方到位 | 需要镜片的订单必须齐套后才能裁片 |
| 50 | 待送裁片 | 镜框和镜片已齐套，等待送裁片厂 | 裁片厂不登录 ERP，由下单员维护 |
| 60 | 裁片加工中 | 裁片厂加工中 | 进度由下单员更新 |
| 65 | 待接收成品 | 裁片完成，等待下单员接收装配成品 | 接收后进入 QC |
| 70 | QC 中 | 等待或正在质检 | 所有出库商品均需 QC |
| 75 | 待发货 | QC 通过，等待仓库打包发货 | 必须无 Hold、资料完整 |
| 80 | 已发货 | 已交给承运商 | `delivery_status` 同步进入已发货/运输中 |
| 100 | 已完成 | 订单闭环完成 | 完成终态 |

说明：

- 对于通用销售字段，原 `SaleOrderSet` 的“编辑中、审核中、审核通过、待付款、备货中”等状态可保留在审核/付款维度，不必继续占用定制订单主状态。
- 如果需要兼容旧数据，可以通过迁移或展示层映射把旧 `30=备货中` 映射到新的“待核查/部件准备中/待齐套”等具体状态。
- 异常状态不进入 `sale_order.status`，由 `abnormal_status`、异常原因和异常日志表示。
- `100=已完成` 是唯一完成态；已发货、取消均不应使用 100。
- 发货后的运输异常、售后处理不进入订单主状态，使用 `delivery_status`、售后工单、客服工单或 `abnormal_status` 表达。

## 2.4 定制履约阶段

如果订单主状态已采用上面的定制化枚举，则“定制履约阶段”可以直接等同于订单主状态。若一个销售订单下存在多个定制履约项，则订单主状态应由所有履约项、镜框部件、镜片部件和工序汇总得出。

| 阶段 | 业务含义 | 进入条件 | 退出条件 |
| --- | --- | --- | --- |
| 待核查 | 检查处方、PD、商品、镜片 SKU 是否完整正确 | Shopify 同步后或红人订单审批后 | 下单员核查通过 |
| 部件准备中 | 镜框和镜片并行准备 | 核查通过后，需要镜框占库/采购或镜片委外下单 | 镜框、镜片处理路径均已启动 |
| 待齐套 | 等待镜框和镜片同时到位 | 镜框、镜片路径已启动但任一关键部件未完成 | 镜框、镜片均到位 |
| 待送裁片 | 已齐套，准备送裁片厂 | 齐套后 | 下单员送裁片 |
| 裁片加工中 | 裁片厂加工，进度由下单员维护 | 已送裁片 | 裁片完成/成品接收 |
| 待接收成品 | 等待下单员接收装配成品 | 裁片加工完成 | 接收完成，进入 QC |
| QC 中 | 等待或正在质检 | 成品接收后 | QC 通过或生成返工任务 |
| 待发货 | QC 通过，等待仓库发货 | QC 通过、无 Hold、资料完整 | 仓库发货 |
| 已完成 | 生产任务完成或订单闭环 | 已发货/已签收/结案 | 终态 |

## 2.5 订单 Hold 状态

| 状态 | 说明 |
| --- | --- |
| 无 Hold | 正常流转 |
| 已暂停 | 阻止受影响的后续操作 |
| 已解除 | 保留历史，订单回到原生产阶段 |

Hold 解除权限必须按原因控制：

| Hold 原因 | 建议解除岗位 |
| --- | --- |
| 镜框缺货、停产、交期过长 | 采购 |
| 处方异常、镜片参数异常 | 下单员 |
| 客户修改订单、改地址、补差价 | 运营或客服按工单授权 |
| 同步异常 | 运营或系统管理员 |

## 2.6 订单发货前置条件

订单进入发货前必须满足：

- 所有应发商品均已 QC 通过。
- 不存在有效 Hold。
- 发货资料完整。
- 需要镜片的订单已完成镜框与镜片齐套。
- 仅镜框、仅配件订单虽然跳过镜片和裁片，但仍必须 QC。

# 3. 定制部件-镜框状态

镜框是 `custom_item_component.component_type = frame` 的定制部件。

镜框状态应表达“是否可用于齐套/装配”，采购、库存、供应商交期等是辅助维度。

## 3.1 建议字段

| 字段 | 说明 |
| --- | --- |
| `component_type` | 固定为 `frame` |
| `status` | 部件主状态 |
| `source_type` | 来源：库存、采购、委外、自制等 |
| `supplier_progress_status` | 供应侧进度，适合镜框采购/供应状态 |
| `repository_freeze_log_id` | 库存占用记录 |
| `purchase_plan_detail_id` | 采购计划明细 |
| `purchase_order_id` / `purchase_order_detail_id` | 采购单据 |
| `actual_finish_time` | 镜框实际备齐时间 |
| `expected_finish_time` | 镜框预计备齐时间 |
| `abnormal_status` | 镜框部件异常状态，独立于 `status` |
| `abnormal_reason` / `abnormal_log` | 镜框部件异常原因和处理记录 |

## 3.2 镜框部件主状态

| 状态值 | 状态名 | 业务含义 | 典型来源 |
| --- | --- | --- | --- |
| 0 | 待处理 | 尚未判断库存或采购路径 | Shopify 拆解后、红人订单生成后 |
| 10 | 已备齐 | 已占用库存或已验收到可用镜框 | 库存占用成功、采购验收合格 |
| 20 | 采购中 | 已生成采购计划/采购单，等待到货 | 无库存后采购 |
| 30 | 委外中 | 镜框需要外部处理或供应商确认 | 特殊镜框供应场景 |
| 40 | 生产中 | 自制或生产中 | 如后续存在自制镜框 |
| -1 | 已取消 | 部件终止，不参与正常履约 | 订单取消、履约重建 |
| 100 | 已完成 | 镜框部件完成，可进入齐套判断 | 仓库验收或流程完成 |

说明：

- 现有代码中库存占用成功会将镜框 `status` 置为 10。
- 镜框采购过程中会将 `status` 置为 20。
- 齐套判断中，库存来源且已占用库存的镜框，`status=10` 即可视为镜框可用；采购或加工完成的镜框可提升到 `100=已完成`。
- `10=已备齐` 表示镜框已经可参与齐套；`100=已完成` 表示镜框部件自身流程已闭环。
- 缺货、停产、交期过长、资料缺失等异常不写入 `status`，应保留异常发生前的部件主状态，同时写入 `abnormal_status` 和异常处理记录。

## 3.3 镜框来源状态

| `source_type` | 来源 | 说明 |
| --- | --- | --- |
| 0 | 未定 | 尚未决定库存/采购/委外/自制 |
| 1 | 库存 | 从现有镜框库存占用 |
| 2 | 采购 | 需要采购镜框 |
| 3 | 委外 | 需要供应商或外协处理 |
| 4 | 自制 | 内部生产 |

## 3.4 镜框供应/采购子状态

镜框厂家提交库存、交期、状态、价格变更后，必须由采购审核后才更新正式数据。

建议采购子状态：

| 子状态 | 业务含义 |
| --- | --- |
| 待判断库存 | 系统尚未完成库存检查 |
| 库存已占用 | 有库存并已冻结 |
| 待采购 | 无库存，需要采购确认 |
| 采购计划已生成 | 已生成采购计划，但未形成正式采购订单 |
| 采购订单已生成 | 已进入采购订单 |
| 厂家待确认 | 等待镜框厂确认库存、交期或价格 |
| 厂家已确认 | 厂家确认可供应 |
| 到货待验收 | 货到仓库，等待验收 |
| 验收合格 | 仓库确认可用，进入月度对账范围 |
| 验收异常 | 数量、质量或型号异常 |
| 无货/停产/交期过长 | 采购确认后生成发货前工单 |

## 3.5 镜框状态流转

```text
待处理
  ├─ 有库存 -> 库存已占用 -> 已备齐
  └─ 无库存 -> 待采购 -> 采购中 -> 到货待验收 -> 已备齐/已完成

任意非终态
  ├─ 资料异常/缺货/停产/交期过长 -> 保留原主状态 + 部件异常状态 + 订单Hold
  └─ 订单取消/履约重建 -> 已取消
```

## 3.6 镜框对订单的影响

| 镜框状态 | 对订单影响 |
| --- | --- |
| 待处理 | 订单停留在待核查或部件准备中 |
| 已备齐/已完成 | 可参与齐套判断 |
| 采购中 | 订单显示部件准备中或待齐套，不应进入裁片 |
| 存在未处理异常 | 设置订单 Hold，并按原因生成采购待办或发货前工单，镜框主状态保持在异常发生前的进度 |
| 已取消 | 不参与正常齐套与发货 |

# 4. 定制部件-镜片状态

镜片是以下部件类型：

- `lens_left`
- `lens_right`
- `lens_pair`

需求文档明确：ERP 不管理镜片库存。镜片以“下单单/委外单 + 供应商进度 + 价格版本”为核心。

## 4.1 建议字段

| 字段 | 说明 |
| --- | --- |
| `component_type` | `lens_left` / `lens_right` / `lens_pair` |
| `status` | 镜片部件主状态 |
| `source_type` | 通常为委外 |
| `supplier_id` | 镜片厂 |
| `entrust_id` | 镜片委外/下单单 |
| `supplier_status` | 镜片厂侧状态 |
| `supplier_eta_time` | 镜片厂预计完成时间 |
| `supplier_finish_time` | 镜片厂完成时间 |
| `tracking_num` | 镜片厂发货/物流单号 |
| `expected_finish_time` | ERP 预计完成时间 |
| `actual_finish_time` | ERP 认定部件完成时间 |
| `supplier_remark` | 给委外供应商看的备注 |
| `params_snapshot` | 镜片 SKU、处方、折射率、镜片组、镜片选项等快照 |
| `abnormal_status` | 镜片部件异常状态，独立于 `status` |
| `abnormal_reason` / `abnormal_log` | 镜片部件异常原因和处理记录 |

## 4.2 镜片部件主状态

| 状态值 | 状态名 | 业务含义 |
| --- | --- | --- |
| 0 | 待处理 | 尚未生成镜片下单单，或镜片产品/供应商未匹配 |
| 30 | 委外中 | 已生成镜片下单单/委外单，等待镜片厂处理 |
| -1 | 已取消 | 部件终止，不参与履约 |
| 100 | 已完成 | 镜片已完成并可用于齐套/装配 |

说明：

- 镜片不应出现库存状态。
- 镜片厂报价不阻塞生产，但必须保留报价版本，财务后续核对。
- 财务核对状态与生产状态分离，不应因为价格差异回退生产状态。
- 处方异常、供应商拒单、生产异常、参数缺失等不写入镜片部件主状态，应保留异常发生前的 `status`，同时写入镜片部件 `abnormal_status` 和异常处理记录。

## 4.3 镜片供应商侧状态

现有供应商接口允许镜片厂更新 `supplier_status`，建议统一语义如下：

| `supplier_status` | 状态名 | 业务含义 | 操作方 |
| --- | - | --- | --- |
| 0 | 待接单 | 镜片下单单已生成，等待镜片厂接单 | 系统 |
| 5 | 已拒绝/需退回 | 镜片厂拒单或要求补充信息 | 镜片厂 |
| 10 | 已接单 | 镜片厂确认接单 | 镜片厂 |
| 20 | 生产中 | 镜片厂生产加工中 | 镜片厂 |
| 30 | 生产完成 | 镜片厂完成生产 | 镜片厂 |
| 40 | 待发出 | 完成但尚未寄出或交付 | 镜片厂 |
| 50 | 已发出 | 镜片厂已发货或交付，有物流/交接记录 | 镜片厂/系统 |
| 70 | 已入库/已接收 | ERP 仓库或生产流程已接收镜片 | 系统 |
| 80 | 异常上报 | 镜片厂侧异常事件，触发镜片部件独立异常状态 | 镜片厂/内部人员 |

说明：

- 供应商前台可手动更新的状态建议限制为 `0/5/10/20/30/40/50/80`。
- `70=已入库/已接收` 建议由 ERP 系统在委外入库或接收动作后写入。
- 当供应商状态达到 `30` 及以上，可记录 `supplier_finish_time`。
- `supplier_status=80` 仅表示供应商侧上报了异常事件，系统接收后应写入镜片部件 `abnormal_status`，不应把镜片部件主状态改为异常。

## 4.4 镜片状态流转

```text
待处理
  ├─ 匹配镜片SKU和供应商失败 -> 保留原主状态 + 部件异常状态 + 订单Hold
  └─ 匹配成功 -> 生成镜片下单单 -> 委外中

委外中
  ├─ 待确认 -> 已接单 -> 生产中 -> 生产完成 -> 已发出 -> 已入库/已接收 -> 已完成
  ├─ 已拒绝/需退回 -> 保留委外中 + 部件异常状态 + 订单Hold
  └─ 生产异常/参数异常 -> 保留委外中 + 部件异常状态 + 订单Hold

已完成
  └─ 参与齐套判断
```

## 4.5 镜片对订单的影响

| 镜片状态 | 对订单影响 |
| --- | --- |
| 待处理 | 订单停留在待核查或部件准备中 |
| 委外中 | 订单显示部件准备中或待齐套 |
| 已完成 | 可参与齐套判断 |
| 存在未处理异常 | 设置订单 Hold，并由下单员/运营/客服按原因处理，镜片主状态保持在异常发生前的进度 |
| 已取消 | 不参与齐套，应重新生成或创建关联订单 |

## 4.6 镜片价格与生产状态解耦

镜片厂可以逐单提交价格。价格差异不阻塞生产。

| 状态维度 | 说明 |
| --- | --- |
| 生产状态 | 由 `supplier_status` / `status` 表达 |
| 报价状态 | 每次报价独立版本保存 |
| 财务核对状态 | 财务标记正常或差异 |
| 对账状态 | 只有价格已核对的镜片订单进入正式应付 |

# 5. 订单、镜框、镜片的汇总规则

## 5.1 齐套判断

需要镜片的订单必须同时满足：

- 镜框已备齐或已完成。
- 左右镜片或镜片对已完成。
- 不存在有效 Hold。
- 不存在未处理异常。

仅镜框、仅配件订单可以跳过镜片和裁片，但仍必须进入 QC。

## 5.2 订单阶段汇总建议

| 汇总判断 | 建议订单主状态 |
| --- | --- |
| 存在有效 Hold | 保留原主状态，同时展示已暂停 |
| 存在未处理异常 | 保留原主状态，同时设置异常状态 |
| 处方、商品、镜片 SKU 未核查 | 待核查 |
| 镜框或镜片任一路径未启动 | 部件准备中 |
| 镜框和镜片路径已启动，但任一部件未到位 | 待齐套 |
| 镜框和镜片齐套 | 待送裁片 |
| 裁片已送出未完成 | 裁片加工中 |
| 裁片完成等待接收 | 待接收成品 |
| 成品接收后未 QC | QC 中 |
| QC 通过未发货 | 待发货 |
| 已发货但未结案 | 已发货 |
| 发货后存在运输异常或售后 | 主状态保持已发货，另用物流异常、售后工单或异常状态表达 |
| 已签收且无未关闭问题 | 已完成 |

## 5.3 发货拦截规则

以下任一情况禁止打包发货：

- 未 QC 通过。
- 存在有效 Hold。
- 发货资料不完整。
- 需要镜片但镜片未完成。
- 需要镜框但镜框未备齐。
- 存在未处理异常。

# 6. 审计要求

以下状态变化必须记录操作日志：

- 订单、处方、地址、SKU、金额修改前后值。
- Hold 设置、解除、原因和操作岗位。
- 镜框库存占用、采购、供应商交期/状态/价格变化。
- 镜片下单、供应商接单、生产进度、发货、入库。
- QC、返工、复检。
- 订单重做、补发、换货关联关系。
- 供应商报价版本、财务核对和对账状态。

# 7. 实现落地建议

## 7.1 定制项目可以重定义 `sale_order.status`

作为定制化项目，`sale_order.status` 可以从通用销售订单生命周期调整为定制履约主状态。这样做的好处是生产看板、订单列表和下单员待办可以直接按订单主状态筛选。

但以下状态仍不建议塞进 `sale_order.status`：

- Hold/暂停状态。
- 异常明细和异常原因。
- 付款状态。
- 退款状态。
- 物流/签收细节。
- 财务核对和供应商对账状态。

也就是说，订单主状态可以表达“订单目前推进到哪一步”，但不应表达“为什么暂停、钱有没有付、供应商报价有没有核对”等并行维度。

## 7.2 部件主状态保持粗粒度

`custom_item_component.status` 建议只表达部件是否可用于齐套：

| 状态 | 含义 |
| --- | --- |
| 0 | 待处理 |
| 10 | 已备齐 |
| 20 | 采购中 |
| 30 | 委外中 |
| 40 | 生产中 |
| -1 | 已取消 |
| 100 | 已完成 |

镜框采购细节放到采购单、采购计划、供应商进度字段。

镜片供应商细节放到 `supplier_status` 和委外单。

异常不进入部件主状态。部件发生异常时，`custom_item_component.status` 保持在异常发生前的进度，另用 `abnormal_status`、`abnormal_reason`、异常日志表达。

## 7.3 Hold 和异常必须可叠加

同一个订单可以同时有：

```text
订单主状态 = 部件准备中
Hold状态 = 已暂停
异常状态 = 处方异常待确认
```

界面展示时应组合显示，而不是只显示一个状态。
