# 销售订单定制组装入库接口文档

## 接口说明

接口用于对销售订单下的定制履约单元执行组装生产，并自动完成成品入库。

该接口会按订单维度处理 `custom_order_item`：

- 检查部件是否齐套。
- 镜框部件如已补库存，会尝试重新锁定库存。
- 自动完成组装前置工序。
- 启动并完成组装工序。
- 自动质检通过。
- 启动并完成成品入库工序。
- 生成并审核 `RepositoryAssemble`，消耗部件库存，增加成品库存。

## 请求信息

```http
POST /admin/sale-order/customAssembleStockIn
```

接口分组：Admin 接口组

控制器：`App\Controller\Admin\SaleOrderController@customAssembleStockIn`

服务类：`App\Service\Common\CustomOrderAssembleStockInService`

## 请求参数

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 销售订单 ID，即 `sale_order.id` |

请求示例：

```json
{
  "id": 14
}
```

## 前置条件

- 销售订单必须存在。
- 销售订单必须审核通过。
- 当前操作人必须有该销售订单的数据权限。
- 销售订单下必须存在定制履约单元 `custom_order_item`。
- 每个履约单元必须存在以下工序：
  - `assemble`
  - `qc`
  - `stock_in`
- 组装前置工序如果未完成，系统只会在部件已满足条件时自动补完成：
  - `frame_prepare`：镜框部件已齐套。
  - `lens_outsource` / `lens_stock_in`：镜片部件已齐套。
- 所有待组装部件必须齐套：
  - 普通部件：`custom_item_component.status >= 50`
  - 镜框库存锁定部件：`source_type = 1` 且存在 `repository_freeze_log_id` 且 `status >= 10`

## 主要处理流程

```text
销售订单
  -> custom_order_item
  -> 检查部件齐套
  -> 补完成组装前置工序
  -> 启动组装
  -> 完成组装
  -> 启动质检
  -> 质检通过
  -> 启动成品入库
  -> 完成成品入库
  -> 生成 RepositoryAssemble
  -> 审核 RepositoryAssemble
  -> 自动生成部件出库单和成品入库单
  -> 增加成品库存，消耗部件库存
```

## 返回数据

返回结构沿用系统 `outputFormat()`。

`data` 字段示例：

```json
{
  "sale_order_id": 14,
  "item_count": 1,
  "items": [
    {
      "custom_order_item_id": 23,
      "item_status": 40,
      "assemble_status": 20,
      "qc_status": 20,
      "stock_in_status": 20,
      "stock_in_ref_module": "repository_assemble",
      "stock_in_ref_id": 12,
      "stock_reconcile": {
        "checked": 1,
        "locked": 1,
        "items": []
      },
      "process_reconcile": {
        "checked": 3,
        "items": []
      }
    }
  ]
}
```

## 返回字段说明

| 字段 | 说明 |
| --- | --- |
| `sale_order_id` | 销售订单 ID |
| `item_count` | 本次处理的定制履约单元数量 |
| `items` | 每个履约单元处理结果 |
| `custom_order_item_id` | 定制履约单元 ID |
| `item_status` | 履约单元最终状态，`40` 表示已生产入库 |
| `assemble_status` | 组装工序状态，`20` 表示已完成 |
| `qc_status` | 质检工序状态，`20` 表示已完成 |
| `stock_in_status` | 成品入库工序状态，`20` 表示已完成 |
| `stock_in_ref_module` | 成品入库引用模块，成功时通常为 `repository_assemble` |
| `stock_in_ref_id` | 自动生成的组装单 ID，即 `repository_assemble.id` |
| `stock_reconcile` | 镜框补库存后重新锁库的检查结果 |
| `process_reconcile` | 自动补完成组装前置工序的结果 |

## 常见失败原因

| 错误提示 | 说明 |
| --- | --- |
| `销售订单未审核通过，不能组装入库` | 订单未审核通过 |
| `订单没有定制履约单元` | 销售订单下没有 `custom_order_item` |
| `部件尚未齐套，无法进入组装，component_id=...` | 仍有部件未完成或未锁库 |
| `履约单元{id}缺少工序assemble` | 缺少组装工序 |
| `履约单元{id}缺少工序qc` | 缺少质检工序 |
| `履约单元{id}缺少工序stock_in` | 缺少成品入库工序 |
| `前序工序未完成，暂不能开始` | 存在不能自动补完成的前置工序 |
| `成品缺少默认入库仓位` | 成品产品没有默认入库仓位，且公司也没有默认仓位 |
| `部件[...]无可用库存，无法完成成品入库` | 组装入库时部件库存不足 |
| `未找到可用于组装入库的部件` | 没有可消耗的部件库存 |

## 前端交互建议

建议在销售订单详情页或定制履约详情页提供按钮：

```text
生成组装并入库
```

按钮显示条件：

- 订单已审核通过。
- 订单存在定制履约单元。
- 至少有一个履约单元未达到 `item_status >= 40`。

点击后调用：

```http
POST /admin/sale-order/customAssembleStockIn
```

成功后刷新：

- 销售订单详情
- `custom_order_item`
- `custom_item_component`
- `custom_item_process`
- 库存/组装单关联信息

## 注意事项

- 该接口会真实改变库存。
- 该接口会自动质检通过，适用于后端自动化主流程或人工确认后的一键流转。
- 如果业务需要独立质检确认，应改用工序接口逐步执行，而不要直接调用本接口。
- 该接口会复用 MVP 主流程测试中的核心生产逻辑，当前 MVP 测试也已改为调用同一个服务实现。
