# 外部印染订单“按 external_order_id 获取当前完整快照”接口需求

日期：2026-04-16

## 1. 背景

我方系统当前已接入外部印染 records 的增量同步能力。

现有同步模式为：

- 外部系统通过增量接口返回 records
- 我方按 `BianHaoID` 分组，同步为 1 条 `PrintingOrder`
- 分组内每条 record 同步为 1 条 `PrintingJob`

也就是说，在我方系统内，外部订单和本地数据关系为：

- 1 个 `external_order_id`（即外部 `BianHaoID`）
- 对应 1 条本地 `PrintingOrder`
- 对应 N 条本地 `PrintingJob`

当前业务中已经出现这样一种场景：

- 某个外部订单已经完成首次同步
- 之后外部系统中的订单头信息或明细信息又被人工修改
- 我方人工发现本地数据与外部数据不一致
- 需要针对某一个 `external_order_id` 手动触发“重新获取该订单当前最新数据”

## 2. 当前问题

我方现有的 retry 能力，并不能解决“外部订单后来被修改”的问题。

当前 retry 的本质是：

- 仅针对历史失败的外部 record
- 从我方失败表中取出当时保存的 `raw` 原始数据
- 再次重放同一批旧数据

因此它适用于：

- 网络失败
- 产品图片拉取失败
- 某次处理异常后重新跑一遍旧 payload

但它不适用于：

- 外部订单字段后来被改了
- 外部订单新增了新的明细
- 外部订单删掉了原有明细
- 外部订单状态发生变化

原因是：

- retry 并不会重新向外部系统按订单号取最新数据
- retry 重放的仍然是旧快照，而不是外部当前状态

## 3. 需求目标

希望外部系统提供一个能力：

> 按 `external_order_id` 精确查询，并返回该订单“当前完整快照”的全部 records。

这里的“当前完整快照”有明确含义：

- 返回的是该订单当前时点下的完整明细集合
- 不是历史增量
- 不是游标区间结果
- 不是“最近有变化的几条记录”
- 不依赖我方先知道哪些 record 发生过变化

这个能力将用于我方后续提供“按 external_order_id 手动重同步”的内部 API / 工具。

## 4. 为什么必须是“完整快照”

我方不是单条明细落库，而是订单头 + 多条任务明细的结构。

如果外部系统只提供：

- 某个订单最近变化的几条 record
- 或者只提供单条 record 查询

则我方无法可靠完成以下动作：

- 更新订单头字段
- 判断本地哪些明细需要新增
- 判断本地哪些明细需要更新
- 判断本地哪些旧明细已经在外部被删除

因此，对我方来说，最小可用能力不是“按单号查某几条变化记录”，而是：

- 按单号返回该订单当前全部有效 records

只有拿到完整快照，我方才能把这个订单重新对齐到外部当前状态。

## 5. 建议接口方案

推荐新增一个独立接口。

建议路径：

```http
GET /api/v1/records/by-order?external_order_id=KD20432358
```

推荐原因：

- 语义清晰，和现有增量游标接口职责分离
- 可以明确约束“不读 cursor、不推进 cursor”
- 便于后续扩展该接口的专属返回字段

如果外部系统暂时不方便新增路径，也可以接受兼容方案：

```http
GET /api/v1/records?external_order_id=KD20432358&query_mode=snapshot
```

但前提必须满足：

- 该模式下不使用游标逻辑
- 不推进 cursor
- 返回该订单当前完整快照，而不是增量结果

## 6. 请求参数要求

### 必填参数

| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| `external_order_id` | string | 外部订单编号，对应现有 records 中的 `BianHaoID` |

### 匹配要求

- 必须按 `external_order_id` 精确匹配
- 不应做模糊匹配
- 不应返回多个订单的混合结果

### 关于唯一性

推荐外部系统保证：

- `external_order_id` 在其业务域内能够唯一定位 1 张订单

如果外部系统暂时无法保证这一点，则需要在接口层明确处理：

- 若命中 0 条订单，返回 not found
- 若命中多张订单，返回明确的重复错误，不能返回混合 records

## 7. 返回数据要求

### 核心原则

返回的每条 record 字段结构，应尽量与现有增量接口 `GET /api/v1/records` 保持一致。

这样我方可以最大程度复用既有字段映射和同步逻辑。

### 推荐响应结构

```json
{
  "external_order_id": "KD20432358",
  "status": "active",
  "snapshot_at": "2026-04-16T10:12:34Z",
  "total_count": 3,
  "records": [
    {
      "ID": 1000001,
      "BianHaoID": "KD20432358",
      "KhID": "KH00999",
      "YanSe": "Tj1712#12号色-24码",
      "ShuLiang": "10.00",
      "JiJiaDW": "/段",
      "ShuLiangZ": "2.68",
      "BeiZhu": "手感一定要柔软",
      "BeiZhuC": "10件",
      "CaoZY": "钰涵",
      "HpName": "120克本白四面弹单定",
      "SeHao": "1.51",
      "MeoA": "LWQ15",
      "FidJ": "\\\\fw\\\\2026年-LWQ15\\\\2026\\\\H鸿烨\\\\Tj1712#",
      "KdRiQi": "2026-01-26T20:00:52Z",
      "area": "周边",
      "customer": {
        "KhID": "KH00999",
        "KhName": "鸿烨服饰"
      }
    }
  ]
}
```

### 推荐返回字段说明

| 字段名 | 类型 | 是否必需 | 说明 |
| --- | --- | --- | --- |
| `external_order_id` | string | 是 | 当前查询的订单号 |
| `status` | string | 建议 | 订单当前状态，建议值见下文 |
| `snapshot_at` | string(datetime) | 建议 | 当前快照生成时间 |
| `total_count` | integer | 是 | 当前快照下 records 数量 |
| `records` | array | 是 | 当前订单下的全部有效明细 |

### `status` 建议枚举

建议至少支持以下值：

- `active`：订单有效，`records` 为当前有效明细
- `cancelled`：订单已取消
- `deleted`：订单已删除或已逻辑删除
- `not_found`：未找到该订单

说明：

- 如果外部系统更倾向于用 HTTP 状态码表达，也可以配合状态码返回
- 但建议仍返回明确业务语义，便于我方人工工具直接展示

## 8. 行为约束

这个接口需要满足以下行为约束。

### 8.1 不参与游标逻辑

必须保证：

- 不读取当前增量 cursor 作为查询依据
- 不推进 cursor
- 不影响现有增量同步任务的执行结果

这是最重要的约束之一。

### 8.2 返回整单当前全量明细

必须保证：

- `records` 是这个订单当前全部有效明细
- 不能只返回“最近变更的明细”
- 不能截断
- 不能分页后只给第一页

如果确实存在分页压力，也请至少支持：

- 单个 `external_order_id` 查询时直接返回该订单完整数据

因为我方对单号重同步的前提就是一次拿到完整快照。

### 8.3 快照一致性

必须尽量保证：

- 同一次响应中的 `records` 来自同一时点
- 不出现一半旧数据、一半新数据的混合快照

如果外部系统底层实现上存在事务或视图快照能力，建议使用该能力。

### 8.4 稳定排序

建议返回顺序固定，例如：

- 按 `ID` 升序

这样有利于：

- 人工核对
- 接口调试
- 我方日志审计
- 幂等比较

## 9. 错误返回建议

### 9.1 未找到订单

建议：

- HTTP `404 Not Found`

```json
{
  "external_order_id": "KD20432358",
  "status": "not_found",
  "message": "未找到该 external_order_id 对应的订单"
}
```

### 9.2 命中多张订单

建议：

- HTTP `409 Conflict` 或 `400 Bad Request`

```json
{
  "external_order_id": "KD20432358",
  "message": "该 external_order_id 命中多张订单，无法返回单一快照"
}
```

### 9.3 服务内部错误

建议：

- HTTP `500 Internal Server Error`

```json
{
  "message": "查询订单快照失败，请稍后重试"
}
```

## 10. 我方使用方式

在外部系统提供该接口后，我方计划这样使用：

1. 由人工输入或选择 `external_order_id`
2. 我方服务调用该接口获取该订单当前完整快照
3. 我方按现有映射规则重新同步该订单头信息和明细信息
4. 若未来补充“整单对账清理”逻辑，还会基于该快照识别哪些本地旧明细已在外部不存在

因此，这个接口是我方后续“单号级人工纠偏同步”能力的前置条件。

## 11. 最小可用验收标准

外部接口完成后，至少需要满足以下验收标准：

1. 能按 `external_order_id` 精确查询
2. 返回该订单当前全部有效 records
3. 返回字段结构与现有增量接口的单条 record 基本一致
4. 查询过程不推进 cursor，也不影响增量同步
5. 未命中或歧义命中时，返回明确错误，而不是空数组混过

## 12. 推荐实现优先级

建议外部系统按如下优先级实现：

### P0

- 支持按 `external_order_id` 查询
- 返回整单完整快照
- 不影响 cursor

### P1

- 增加 `snapshot_at`
- 增加 `status`
- 明确未找到 / 命中多张订单的错误语义

### P2

- 若未来需要，也可以补充订单级更新时间字段，例如 `order_updated_at`
- 便于我方后续做缓存或重复请求优化

## 13. 结论

我方当前需要的不是“按单号查若干变更明细”，而是：

> 按 `external_order_id` 返回该订单当前完整快照。

这是因为我方本地结构是：

- 1 张订单头
- 对应 N 条任务明细

只有拿到整单当前全量快照，我方才能支持：

- 人工按单号重同步
- 修复首次同步后外部又发生变更的场景
- 后续扩展为整单级对账更新

因此，建议外部系统尽快提供上述查询接口能力。