# 【修改接口·管理后台】移除核单分类手动确认门禁 (#5264)

> **PR**: #5274 | **服务**: hl-order-service-v3 | **更新时间**: 2026-07-27 00:00

## 1. 接口背景

核单流程不再要求财务在八个核单分类上逐一点击“本分类已确认”。管理后台只需要保存各分类明细；明细完整且可用于报账时，即可生成主报账人报账表。旧分类确认查询和确认接口保留兼容返回，但确认状态不再作为主报账、单团核算、Step6 提交或财务确认的门禁。

## 2. 变更清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 查询原型八个核单分类确认状态 | GET | `/v3/admin/order/{orderId}/settlement/category-checks` | 修改接口 | 响应字段保留，但 `allConfirmed` / `confirmStatus` 仅用于兼容展示，不再决定后续流程能否继续 |
| 2 | 按最近读取指纹确认单个核单分类 | POST | `/v3/admin/order/{orderId}/settlement/category-checks/{category}/confirm` | 修改接口 | 标记为废弃兼容；管理后台停止调用并移除“本分类已确认”入口 |
| 3 | 生成主报账人报账表 | POST | `/v3/admin/order/{orderId}/settlement/reports/reimbursement/generate` | 修改接口 | 生成条件改为核单明细保存完整，不再要求八分类手动确认 |

## 3. 接口详情

### 3.1 查询原型八个核单分类确认状态

- **方法 / 路径**：`GET /v3/admin/order/{orderId}/settlement/category-checks`
- **使用场景**：旧页面或兼容逻辑读取八分类状态。
- **认证**：需要管理后台登录态；房控角色不可访问。
- **幂等性**：是，只读查询。
- **限流**：无单独接口限流约定。
- **接口说明**：字段结构保持不变；`allConfirmed` 和 `items[].confirmStatus` 不再用于判断主报账、单团核算、Step6 或财务确认是否可继续。

### 3.2 按最近读取指纹确认单个核单分类（废弃兼容）

- **方法 / 路径**：`POST /v3/admin/order/{orderId}/settlement/category-checks/{category}/confirm`
- **使用场景**：仅兼容旧前端请求；新管理后台不再调用。
- **认证**：需要管理后台登录态和财务写权限；房控角色不可访问。
- **幂等性**：同一分类、同一 `expectedSourceFingerprint` 重复确认返回当前兼容状态。
- **限流**：无单独接口限流约定。
- **接口说明**：接口仍校验请求体和分类枚举，但确认投影不再作为后续流程门禁。前端应移除“本分类已确认”按钮、状态卡门禁和基于 `allConfirmed` 的下一步禁用逻辑。

### 3.3 生成主报账人报账表

- **方法 / 路径**：`POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/generate`
- **使用场景**：核单明细保存完整后生成或刷新主报账人报账表。
- **认证**：需要管理后台登录态和财务写权限；房控角色不可访问。
- **幂等性**：同一来源数据已生成时，可返回当前报账表；来源变化后重新生成。
- **限流**：无单独接口限流约定。
- **接口说明**：生成门禁改为逐分类明细完整性校验；不再要求先调用八分类确认接口。

## 4. 接口入参

### 4.1 路径参数 / Query 参数

| 接口 | 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|------|----------|
| 三个接口共用 | `orderId` | `String` | 是 | 订单 ID，按字符串处理 | 必须为大于 0 的数字 |
| 分类确认接口 | `category` | `String` | 是 | 核单分类编码 | 见 §6.1 `SettlementCategory` |

### 4.2 请求体字段

#### 4.2.1 `GET /category-checks`

无请求体。

#### 4.2.2 `POST /category-checks/{category}/confirm`（废弃兼容）

| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| `expectedSourceFingerprint` | `String` | 是 | 最近读取的分类源事实 SHA-256；废弃兼容字段 | 64 位小写十六进制字符串 |
| `confirmEmpty` | `Boolean` | 是 | 是否明确确认空分类；废弃兼容字段 | `true` / `false` |

#### 4.2.3 `POST /reports/reimbursement/generate`

无请求体。

## 5. 出参字段

### 5.1 `SettlementCategoryChecksRespVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `orderId` | `String` | 订单 ID |
| `allConfirmed` | `Boolean` | 兼容字段；不再作为后续流程门禁 |
| `items` | `Array<ItemVO>` | 八个分类状态列表 |

### 5.2 `SettlementCategoryChecksRespVO.ItemVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `category` | `String` | 分类编码，见 §6.1 |
| `categoryName` | `String` | 分类中文名 |
| `rowCount` | `Integer` | 当前分类明细行数 |
| `empty` | `Boolean` | 当前分类是否为空 |
| `sourceFingerprint` | `String` | 当前分类源事实指纹 |
| `confirmStatus` | `String` | 兼容字段，见 §6.2；不再作为后续流程门禁 |
| `confirmedBy` | `String/null` | 兼容字段，确认人 ID |
| `confirmedByName` | `String/null` | 兼容字段，确认人姓名 |
| `confirmedAt` | `String/null` | 兼容字段，确认时间，格式 `yyyy-MM-dd'T'HH:mm:ss` |

### 5.3 `SettlementReimbursementReportRespVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | `String` | 主报账表 ID |
| `orderId` | `String` | 订单 ID |
| `reportStatus` | `String` | 报告状态，见 §6.3 |
| `sourceFingerprint` | `String` | 报账来源指纹 |
| `primaryReporterId` | `String/null` | 主报账人 ID |
| `primaryReporterName` | `String/null` | 主报账人姓名 |
| `primaryReporterRole` | `String/null` | 主报账人角色 |
| `reportVersion` | `Integer` | 报告版本号 |
| `driverCollectedTailAmount` | `Decimal` | 司机代收尾款金额 |
| `approvedAdvanceAmount` | `Decimal` | 已审批预支金额 |
| `reportablePaidCostAmount` | `Decimal` | 可报账已支付成本 |
| `reporterNetAmount` | `Decimal` | 报账人净额 |
| `primaryReporterCollectedAmount` | `Decimal` | 主报账人已收金额 |
| `publicPrepaidAmount` | `Decimal` | 公共预付金额 |
| `primaryReporterDueAmount` | `Decimal` | 主报账人应结金额 |
| `advanceOutstandingAmount` | `Decimal` | 预支未结金额 |
| `reconNetAmount` | `Decimal` | 对账净额 |
| `transferDirection` | `String/null` | 转账方向 |
| `transferAmount` | `Decimal` | 转账金额 |
| `incomeLines` | `Array<Object>` | 收入明细行 |
| `expenseLines` | `Array<Object>` | 支出明细行 |
| `advanceLines` | `Array<Object>` | 预支明细行 |
| `vehicleLines` | `Array<Object>` | 车辆费用明细行 |
| `transferStatus` | `String/null` | 转账状态 |
| `transferDate` | `String/null` | 转账日期，格式 `yyyy-MM-dd` |
| `transferRef` | `String/null` | 转账凭证号 |
| `advanceSettledFlag` | `Boolean/null` | 预支是否已结清 |
| `signedVoucher` | `Object/null` | 签字凭证信息 |
| `generatedBy` | `String/null` | 生成人 ID |
| `generatedByName` | `String/null` | 生成人姓名 |
| `generatedAt` | `String/null` | 生成时间，格式 `yyyy-MM-dd'T'HH:mm:ss` |
| `confirmedBy` | `String/null` | 确认人 ID |
| `confirmedByName` | `String/null` | 确认人姓名 |
| `confirmedAt` | `String/null` | 确认时间，格式 `yyyy-MM-dd'T'HH:mm:ss` |

## 6. 枚举 / 数据字典

### 6.1 `category`（SettlementCategory）

**所属字段**：路径参数 `category`、响应 `items[].category` | **类型**：`String`

| 值 | 中文 | 说明 |
|----|------|------|
| `HOTEL` | 住宿 | 住宿核单明细 |
| `TICKET` | 门票/游玩项目 | 门票和游玩项目核单明细 |
| `MEAL` | 餐食 | 餐食费用明细 |
| `VEHICLE` | 车辆 | 车辆费用明细 |
| `GUIDE` | 导游 | 导游费用明细 |
| `PHOTOGRAPHER` | 摄影 | 摄影费用明细 |
| `OTHER_INCOME` | 其他收入 | 其他收入明细 |
| `OTHER_EXPENSE` | 其他支出 | 其他支出明细 |

### 6.2 `confirmStatus`（兼容状态）

**所属字段**：`items[].confirmStatus` | **类型**：`String`

| 值 | 中文 | 说明 |
|----|------|------|
| `UNCONFIRMED` | 未确认 | 兼容旧确认投影；不再阻止生成主报账表 |
| `CONFIRMED` | 已确认 | 兼容旧确认投影；不再作为后续流程门禁 |
| `STALE` | 已变化 | 兼容旧确认投影；不再作为后续流程门禁 |

### 6.3 `reportStatus`（SettlementReportStatus）

**所属字段**：`reportStatus` | **类型**：`String`

| 值 | 中文 | 说明 |
|----|------|------|
| `GENERATED` | 已生成 | 主报账表已生成，尚未确认 |
| `CONFIRMED` | 已确认 | 主报账表已确认 |
| `STALE` | 来源已变化 | 当前来源指纹与已保存报账表不一致 |

## 7. 错误码

| code | 含义 | 触发场景 |
|------|------|----------|
| `200` | 成功 | 查询、兼容确认或生成主报账表成功 |
| `400` | 请求参数错误 | `orderId` 非法、兼容确认接口缺少请求体、`expectedSourceFingerprint` 不是 64 位小写十六进制、`confirmEmpty` 缺失 |
| `404` | 接口或资源不存在 | 路径不存在，或访问不存在的订单 |
| `584315` | 核单来源数据已变化，请刷新后重新生成 | 报告来源指纹变化 |
| `584317` | 当前报告状态不允许执行该操作 | 当前核单状态不允许生成或确认报告 |
| `584319` | 核单存在未知分类或历史迁移数据不完整 | `category` 不是 §6.1 中的值 |
| `584320` | 核单分类「{categoryName}」明细尚未保存完整或数据不可用于报账 | 生成主报账表时，某个分类明细缺必填业务信息或不可用于报账 |

## 8. 示例

### 8.1 典型成功：未逐类确认也可生成主报账表

**请求**：

```http
POST /v3/admin/order/60001/settlement/reports/reimbursement/generate
Authorization: Bearer <token>
```

无请求体。

**响应**：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "910000000000000001",
    "orderId": "60001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "primaryReporterId": "11001",
    "primaryReporterName": "张三",
    "primaryReporterRole": "GUIDE",
    "reportVersion": 1,
    "driverCollectedTailAmount": 0.00,
    "approvedAdvanceAmount": 2000.00,
    "reportablePaidCostAmount": 8300.00,
    "reporterNetAmount": 6300.00,
    "primaryReporterCollectedAmount": 0.00,
    "publicPrepaidAmount": 1000.00,
    "primaryReporterDueAmount": 6300.00,
    "advanceOutstandingAmount": 0.00,
    "reconNetAmount": 6300.00,
    "transferDirection": "PAY_TO_REPORTER",
    "transferAmount": 6300.00,
    "incomeLines": [],
    "expenseLines": [
      {
        "category": "HOTEL",
        "categoryName": "住宿",
        "amount": 3600.00
      }
    ],
    "advanceLines": [],
    "vehicleLines": [],
    "transferStatus": "PENDING",
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": false,
    "signedVoucher": null,
    "generatedBy": "11",
    "generatedByName": "旧核单员",
    "generatedAt": "2026-07-27T10:15:30",
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}
```

### 8.2 边界情况：查询兼容状态仍返回 `allConfirmed=false`

**请求**：

```http
GET /v3/admin/order/60001/settlement/category-checks
Authorization: Bearer <token>
```

无请求体。

**响应**：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "orderId": "60001",
    "allConfirmed": false,
    "items": [
      {
        "category": "HOTEL",
        "categoryName": "住宿",
        "rowCount": 1,
        "empty": false,
        "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "confirmStatus": "UNCONFIRMED",
        "confirmedBy": null,
        "confirmedByName": null,
        "confirmedAt": null
      }
    ]
  }
}
```

### 8.3 业务失败：分类明细未保存完整

**请求**：

```http
POST /v3/admin/order/60001/settlement/reports/reimbursement/generate
Authorization: Bearer <token>
```

无请求体。

**响应**：

```json
{
  "code": 584320,
  "msg": "核单分类「住宿」明细尚未保存完整或数据不可用于报账",
  "data": null
}
```

## 9. 业务边界

- **适用场景**：管理后台核单流程；分类明细已保存完整后生成主报账人报账表。
- **不适用场景**：继续用 `allConfirmed=true` 作为“生成主报账表”“生成单团核算表”“Step6 提交”“财务确认”的前置条件。
- **特殊边界**：`POST /category-checks/{category}/confirm` 仍可能返回 200，但它只是兼容旧调用，不代表新流程需要或应该调用。
- **明细完整性口径**：生成主报账表时，八个分类都必须存在可用于报账的明细快照；缺少分类、金额非法、业务必填项为空或来源数据不可用时返回 `584320`。

## 10. 修改前后对比

### 10.1 字段级对比

| 字段 | 改前 | 改后 |
|------|------|------|
| `allConfirmed` | 后续流程可能按该字段判断八分类是否已全部确认 | 字段保留兼容，但不再作为后续流程门禁 |
| `items[].confirmStatus` | `UNCONFIRMED` / `CONFIRMED` / `STALE` 可能影响页面下一步按钮 | 字段保留兼容，但不再作为后续流程门禁 |
| `SettlementCategoryConfirmReqVO.expectedSourceFingerprint` | 分类确认接口必填 | 仍为兼容接口必填；新前端停止调用该接口 |
| `SettlementCategoryConfirmReqVO.confirmEmpty` | 分类确认接口必填 | 仍为兼容接口必填；新前端停止调用该接口 |

### 10.2 行为级对比

| 行为 | 改前 | 改后 |
|------|------|------|
| 主报账表生成 | 要求八个分类确认状态全部满足手动确认口径 | 核单明细保存完整即可生成 |
| 分类确认按钮 | 前端需要逐分类调用确认接口 | 前端停止调用确认接口，并移除“本分类已确认”入口 |
| 单团核算 / Step6 / 财务确认门禁 | 可能间接受八分类确认状态影响 | 不再读取八分类手动确认状态作为门禁 |
| 明细不完整时生成主报账表 | 可能表现为八分类未确认或来源变化类提示 | 返回 `584320`，提示具体分类明细未保存完整或不可用于报账 |

## 11. 影响评估 / 回滚

### 11.1 影响评估

- **是否破坏向后兼容**：否。旧查询字段和旧确认接口保留，但确认接口已废弃。
- **前端是否必须同步上线**：建议同步。前端应移除“本分类已确认”按钮、`allConfirmed` 门禁和基于 `confirmStatus` 的下一步禁用逻辑。
- **影响已有数据**：不要求前端迁移数据；历史确认状态仅作为兼容显示值。

### 11.2 回滚方案

- **回滚方式**：如需恢复旧流程，回滚 PR #5274 对应后端变更。
- **回滚后清理**：前端若已移除按钮，回滚后需要恢复八分类确认入口和 `allConfirmed` 门禁。

## 12. 注意事项

- 管理后台不要再新增对 `POST /category-checks/{category}/confirm` 的调用。
- 页面上原“本分类已确认”按钮、确认进度提示和 `allConfirmed=false` 禁用下一步的逻辑可以移除。
- 查询分类状态接口可继续用于兼容老页面，但不要把 `UNCONFIRMED` 或 `STALE` 解释为主报账表不可生成。
- 生成主报账表失败时优先识别 `584320`，它表示需要补齐对应分类明细，而不是要求点击分类确认。

## 13. 关联 / 联系人

### 13.1 链接

- **Issue**: [#5264](https://git.1814.love:8443/wx/HL/issues/5264)
- **PR**: [#5274](https://git.1814.love:8443/wx/HL/pulls/5274)
- **Merge commit**: [8635973e6](https://git.1814.love:8443/wx/HL/commit/8635973e6)
- **Implementation commit**: [07ac323a1](https://git.1814.love:8443/wx/HL/commit/07ac323a1)

### 13.2 联系人

- **后端负责人**: @yaosu
- **前端对接**: 管理后台前端
