# 委外单 EntrustController 接口文档

## 1. 基本说明

控制器：`App\Controller\Admin\EntrustController`

路由前缀：`/admin/entrust/`

接口分组：Admin 接口组

认证方式：沿用后台 Admin 登录鉴权与菜单权限。

数据范围：

- 普通后台用户按公司数据范围过滤。
- 供应商角色沿用 `BelongToSupplier` 范围控制，只能操作属于自己的委外单。

返回结构：沿用项目 `outputFormat()` 统一响应格式。

## 2. 委外单状态

枚举来源：`config/autoload/variable.php` 的 `ENTRUST_STATUS`

| 状态值 | 状态 | 说明 |
| --- | --- | --- |
| `0` | 待审核 | 委外单创建后待审核 |
| `10` | 待接单 | 审核通过后等待供应商接单 |
| `20` | 加工中 | 供应商已接单或开始加工 |
| `30` | 已发货 | 供应商已填写运单号并寄出 |
| `50` | 待入库 | 仓库确认到货，等待正式入库 |
| `70` | 部分入库 | 已部分入库，入库比例低于 70% |
| `90` | 近全合格 | 已部分入库，入库比例达到 70% 但未全入 |
| `100` | 已完成 | 已全部入库 |

审核接口不是 `EntrustController` 单独定义的接口，走后台通用接口：

```http
POST /admin/base/audit
```

审核通过后，模型会把委外单状态推进到 `10 待接单`，并把关联镜片部件的供应商状态从 `0 待派单` 推进到 `5 待接单`。

## 3. 状态流转建议

标准链路：

```text
0 待审核
  -> 审核通过
10 待接单
  -> startProcessing
20 加工中
  -> ship
30 已发货
  -> markWaitStockIn
50 待入库
  -> receiveStockIn
70/90/100 入库进度
```

说明：

- `ship` 必须填写运单号。
- `markWaitStockIn` 只做“确认到货/待入库”状态标记，不加库存。
- `receiveStockIn` 会生成并审核委外入库单，触发库存增加，并联动 `CustomItemComponent`。

## 4. 接口列表

### 4.1 开始加工

```http
POST /admin/entrust/startProcessing
```

用途：将委外单从 `10 待接单` 推进到 `20 加工中`。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |

请求示例：

```json
{
  "id": 7
}
```

业务规则：

- 委外单必须审核通过。
- 如果委外单已经到 `30 已发货` 或更后状态，接口幂等返回当前委外单。
- 会同步关联镜片部件的 `supplier_status` 至少推进到 `20 生产中`。

返回数据：委外单对象。

### 4.2 委外发货

```http
POST /admin/entrust/ship
```

用途：供应商加工完成后填写运单号，委外单进入 `30 已发货`。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |
| `tracking_num` | string | 是 | 运单号，最大 64 字符 |
| `shipped_time` | string | 否 | 发货时间，不传默认当前时间 |

请求示例：

```json
{
  "id": 7,
  "tracking_num": "SF1234567890",
  "shipped_time": "2026-07-28 15:30:00"
}
```

业务规则：

- 委外单必须审核通过。
- 运单号必填。
- 委外单已进入 `50 待入库` 或更后状态时，不允许再次执行发货。
- 会同步关联 `CustomItemComponent`：
  - `tracking_num`
  - `status` 至少推进到 `30 委外中`
  - `supplier_status` 至少推进到 `50 已寄出`
  - `supplier_finish_time`

返回数据：委外单对象。

### 4.3 标记待入库

```http
POST /admin/entrust/markWaitStockIn
```

用途：仓库确认收到供应商寄回的镜片包裹，但尚未正式入库，委外单进入 `50 待入库`。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |

请求示例：

```json
{
  "id": 7
}
```

业务规则：

- 委外单必须审核通过。
- 委外单必须已发货，即状态至少为 `30 已发货`。
- 如果状态已经是 `50 待入库` 或更后状态，接口幂等返回当前委外单。
- 本接口不生成入库单、不加库存。

返回数据：委外单对象。

### 4.4 接收入库

```http
POST /admin/entrust/receiveStockIn
```

用途：签收并正式接收入库。接口会生成委外入库单、生成入库明细、自动审核入库单并增加库存。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |
| `num` | integer | 否 | 本次入库数量，不传默认全部剩余待入库数量 |
| `repository_id` | integer/string | 否 | 入库仓库/仓位 ID，不传默认使用委外产品默认仓位 |
| `date` | string | 否 | 入库日期，不传默认当天 |
| `admin_remark` | string | 否 | 入库备注 |

请求示例：

```json
{
  "id": 7,
  "num": 1,
  "repository_id": 3,
  "admin_remark": "镜片签收并入库"
}
```

业务规则：

- 委外单必须审核通过。
- 委外单必须已发货，即状态至少为 `30 已发货`。
- 委外单必须有 `product_id`。
- `num` 必须大于 0，且不能超过剩余待入库数量。
- 会创建 `RepositoryReceipt`：
  - `type = RepositorySet::TYPE_ENTRUST_IN`
  - `pm = RepositorySet::PM_IN`
  - `entrust_id = 当前委外单 ID`
- 会创建 `RepositoryReceiptDetail`。
- 会自动审核入库单，触发库存增加。
- 会根据入库数量联动委外单状态：
  - 已入库但比例低于 70%：`70 部分入库`
  - 已入库且比例达到 70% 但未全部入库：`90 近全合格`
  - 全部入库：`100 已完成`
- 会联动 `CustomItemComponent`：
  - `status` 至少推进到 `50 已完成`
  - `supplier_status` 至少推进到 `50 已寄出`
  - `actual_finish_time`
- 会触发定制订单阶段同步。

返回数据：委外单对象。

### 4.5 接收入库并触发组装

```http
POST /admin/entrust/receiveStockInAndTriggerAssemble
```

用途：先执行 `receiveStockIn`，再尝试触发关联定制单元的组装工序。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |
| `num` | integer | 否 | 本次入库数量，不传默认全部剩余待入库数量 |
| `repository_id` | integer/string | 否 | 入库仓库/仓位 ID |
| `date` | string | 否 | 入库日期 |
| `admin_remark` | string | 否 | 入库备注 |

请求示例：

```json
{
  "id": 7,
  "num": 1,
  "repository_id": 3
}
```

返回示例：

```json
{
  "entrust": {},
  "assemble_triggered": 1,
  "assemble_trigger_error": null
}
```

业务规则：

- 入库逻辑同 `receiveStockIn`。
- 组装触发失败不会回滚已完成的入库动作。
- 如果组装前序工序未完成或部件未齐套，`assemble_triggered = 0`，`assemble_trigger_error` 返回失败原因。

### 4.6 手动触发组装

```http
POST /admin/entrust/triggerAssemble
```

用途：委外件入库后，手动触发关联定制单元的组装工序。

请求参数：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 是 | 委外单 ID |

请求示例：

```json
{
  "id": 7
}
```

业务规则：

- 委外单必须已经接收入库。
- `50 待入库` 且 `stock_in_num = 0` 时不能触发。
- 前序工序未完成时不能触发。

返回示例：

```json
{
  "triggered": 1
}
```

## 5. 前端调用建议

委外单主流程建议按钮展示：

| 当前状态 | 建议操作 |
| --- | --- |
| `0 待审核` | 审核 |
| `10 待接单` | 开始加工 |
| `20 加工中` | 发货 |
| `30 已发货` | 标记待入库 / 接收入库 |
| `50 待入库` | 接收入库 |
| `70/90 部分入库` | 继续接收入库 |
| `100 已完成` | 触发组装 / 触发质检 |

如果业务上不需要“待入库”中间状态，可以在 `30 已发货` 后直接调用 `receiveStockIn`。

## 6. 注意事项

- `receiveStockIn` 是库存变更接口，会创建并审核入库单，前端不要把它当作单纯签收。
- `markWaitStockIn` 是单纯到货确认，不会增加库存。
- `ship` 会同步关联镜片部件的运单号和供应商状态。
- 组装、质检是否能启动取决于关联定制单元的工序顺序和部件齐套情况。
