Files
docs/入库测量与计费/第三方入仓测量接口联调说明-2026-08-04.md
T

194 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第三方入仓测量接口联调说明
> 版本:2026-08-04
> 网关基地址:`http://127.0.0.1:9000`(测试环境替换为实际网关域名)
## 一、接口用途
第三方测量设备每次回传一条箱规测量数据和一张对应图片。后端按入仓码匹配入库单,并校验指定货物明细属于该入库单关联订单,然后形成一条测量明细。
接口只保存测量结果,不执行客服审核、计费、托盘拆分、库位占用或完成入库。
## 二、提交接口
```http
POST /openapi/v1/inbound-measurements
Content-Type: multipart/form-data
```
请求头:
```http
X-App-Key: <第三方应用Key>
X-Timestamp: <Unix毫秒时间戳>
X-Nonce: <本次请求唯一随机串>
X-Signature: <HMAC-SHA256签名>
Idempotency-Key: <本次业务操作幂等键>
```
multipart 内容:
| part 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `data` | UTF-8 JSON 文本 | 是 | 一条箱规测量数据,服务端使用原文验签 |
| `image` | 二进制文件 | 是 | 该条明细唯一对应图片;JPG、PNG、BMP,最大 5 MB |
`data` 示例:
```json
{
"eventNo": "M202608040001",
"externalDetailNo": "BOX-20260804-0001",
"warehouseCode": "CN-YW-01",
"inboundCode": "ZBYHK2604100412",
"inboundDetailId": "190000000000000001",
"deviceCode": "DEVICE-01",
"measuredAt": "2026-08-04T10:30:00+08:00",
"boxSpecification": "40*30*47cm",
"packageCount": 50,
"lengthCm": 40.000,
"widthCm": 30.000,
"heightCm": 47.000,
"unitWeightKg": 20.000,
"remark": ""
}
```
字段说明:
| 字段 | 必填 | 规则 |
|---|---|---|
| `eventNo` | 是 | 同一 AppKey 下唯一;1~128 位字母、数字、点、下划线、冒号或横线 |
| `externalDetailNo` | 是 | 第三方物理测量明细唯一号;重复绑定会被拒绝 |
| `warehouseCode` | 是 | 必须属于该 AppKey 预先绑定的仓库 |
| `inboundCode` | 是 | 柏悦入仓码,后端据此匹配入库单 |
| `inboundDetailId` | 是 | 柏悦提供的订单货物明细 ID;必须属于该入库单关联订单 |
| `deviceCode` | 是 | 测量设备编码,最长 64 位 |
| `measuredAt` | 是 | ISO 8601 时间且必须包含时区 |
| `boxSpecification` | 是 | 箱规显示文本,最长 64 位 |
| `packageCount` | 是 | 本箱规箱数,1~1,000,000 |
| `lengthCm` | 是 | 单箱长度,单位厘米且大于 0 |
| `widthCm` | 是 | 单箱宽度,单位厘米且大于 0 |
| `heightCm` | 是 | 单箱高度,单位厘米且大于 0 |
| `unitWeightKg` | 否 | 单箱重量,单位 KG且大于 0;重量 OCR 流程可另行确认 |
| `remark` | 否 | 最长 500 字符 |
## 三、签名算法
先计算图片内容摘要:
```text
imageSha256 = SHA256(image原始字节).lowerHex
```
构造签名 body,`LF` 是单个换行符 `\n`:
```text
signatureBody = data原始UTF-8文本 + LF + imageSha256
bodySha256 = SHA256(signatureBody的UTF-8字节).lowerHex
```
构造六行 canonical string,末尾不追加换行:
```text
POST
/openapi/v1/inbound-measurements
<X-Timestamp>
<X-Nonce>
<Idempotency-Key>
<bodySha256>
```
最终签名:
```text
X-Signature = HMAC-SHA256(appSecret, canonicalString).lowerHex
```
`data` 中任何空格、换行或字段顺序变化都会改变签名。计算签名后必须发送完全相同的 `data` 原文和图片字节。
## 四、成功响应
```json
{
"code": "200",
"message": "success",
"data": {
"eventNo": "M202608040001",
"inboundCode": "ZBYHK2604100412",
"inboundDetailId": "190000000000000001",
"measurementId": "190000000000000010",
"measurementItemId": "190000000000000020",
"imageFileId": "190000000000000030",
"accepted": true,
"status": "RECEIVED",
"receivedAt": "2026-08-04T02:30:00Z"
},
"requestId": "...",
"traceId": "...",
"timestamp": "2026-08-04T02:30:01Z"
}
```
所有 ID 都是字符串,调用方不得转换为 JavaScript Number。
## 五、事件查询
```http
GET /openapi/v1/inbound-measurements/events/{eventNo}
```
GET 同样需要 `X-App-Key`、`X-Timestamp`、`X-Nonce` 和 `X-Signature`,不需要 `Idempotency-Key`。canonical string 中幂等键行为空字符串,body 摘要使用空字节 SHA-256。
## 六、幂等与重复规则
- `X-Nonce`:短时间防重放,使用后不能再次使用。
- `Idempotency-Key`:一次 HTTP 写操作标识;网络重试必须复用原值。
- `appKey + eventNo`:第三方业务事件唯一标识。
- `tenantId + inboundDetailId + externalDetailNo`:测量明细绑定唯一约束。
- 相同事件号或幂等键重试时,`data` 原文及图片内容必须与首次完全一致,否则返回冲突。
## 七、主要失败场景
| 业务码 | 场景 |
|---|---|
| `A0400` | data 不是有效 JSON、图片为空或无法读取 |
| `A0401` | AppKey、时间戳或签名无效 |
| `A0403` | AppKey 未绑定请求仓库,或内部凭证无效 |
| `A0404` | 入仓码不存在,或货物明细不属于入库单关联订单 |
| `A0409` | 入库状态不允许测量、Nonce 重放、事件/幂等内容不一致、明细重复绑定 |
| `A0422` | 字段缺失、格式或数值范围不符合要求 |
| `S0503` | Order 或 File 服务暂不可用 |
普通业务失败应以响应体 `code` 判断,不能只判断 HTTP 状态。
## 八、后台处理过程
```text
验签和防重放
→ 按入仓码及绑定仓库查入库单
→ 调用 Order 校验货物明细归属
→ 检查第三方明细号是否已经绑定
→ 调用 File 保存并校验真实图片
→ 写入一条测量批次和一条测量明细
→ 返回测量、明细和图片ID
```
如果图片已保存但测量数据落库失败,Firstleg 会调用 File 执行补偿清理。
## 九、上线前置
部署新版 Firstleg 前,先执行:
```text
firstleg/src/main/resources/db/phase2-third-party-single-measurement-migration.sql
```
或执行已内联该增量的入库测量与计费统一脚本:
```text
deploy/sql/2026-08-04-入库新增表字段-MySQL8一键执行.sql
```
同时确认 Firstleg、Order、File 使用一致的 `INTERNAL_SERVICE_TOKEN`,并配置 `ORDER_SERVICE_URL`、`FILE_SERVICE_URL` 或启用 Nacos 服务发现。