diff --git a/docs/task/234-档口入库码安全回写.md b/docs/task/234-档口入库码安全回写.md new file mode 100644 index 0000000..e18bd01 --- /dev/null +++ b/docs/task/234-档口入库码安全回写.md @@ -0,0 +1,60 @@ +# 234 Admin:档口入库码安全回写、核验与异常恢复 + +- 类型:需求 +- 父级大工单:#14 +- 所属 MVP / 版本:#224 +- 状态:已完成 +- 日期:2026-08-15 +- Gitea 工单: + +## 背景与目标 + +在操作员明确勾选并二次确认后,把档口入库码安全写入顺运宝商品明细的 +`innerExpCode`,并对删除旧值、网络未知结果和 Admin 中断提供保守恢复路径。 + +## 最终方案 + +- `syb.Client` 增加清除旧值和写入新值两个封装;参数先在本地校验,每个动作只发送一次。 + 网络错误、5xx、响应读取失败或成功响应损坏统一标识为“写入结果未知”。 +- 每条记录先用数据库条件状态从 `ready` 原子领取为 `applying`,然后重新读取远端并核对 + stock/detail、规格、sku、variationSku、采购字段和规划旧值。任一变化都停止写入。 +- 旧值为空时直接写;旧值非空时删除明确成功才写。写入成功响应后再次读取,只有远端值 + 与目标一致才标为已回写;未知或不一致进入需核对,绝不自动重试。 +- “重新核对”只读取 `listByStock`。远端已是目标值时收敛为已回写,否则继续需核对。 +- Admin 启动时把遗留 `applying` 改为 `needs_check`,不会在启动过程中发送远端请求。 + +## 改了哪些 + +- `admin/syb/client.go`:增加单次删除/写入接口和未知结果错误分类。 +- `admin/repository/inner_code.go`:增加领取、完成、只读核对和启动恢复。 +- `admin/service/inner_code_apply.go`:增加写前门禁、删后写、写后核验和批量统计。 +- `admin/handler/web/inner_code.go`、`admin/handler/web/web.go`:接通回写和重新核对 POST。 +- `admin/main.go`:启动时收敛中断记录。 +- `admin/syb/client_test.go`、`admin/service/inner_code_apply_test.go`、 + `admin/repository/inner_code_test.go`:覆盖单次请求、安全门禁和恢复。 +- `admin/repository/mysql_db_integration_test.go`:增加 v22→v23 隔离 MySQL 测试。 +- `docs/admin/08-顺运宝接口.md`:记录两个写接口和禁止重试规则。 + +## 验收结果 + +| 验收标准 | 结果 | +|---|---| +| 非 ready 或重复领取记录不发送写请求 | 通过(条件领取实现) | +| 写前重新核对商品身份、采购字段和旧值 | 通过 | +| 空旧值不删;非空旧值删除成功才写;每个动作一次 | 通过 | +| 写后复读一致才完成,未知结果不自动重试 | 通过 | +| 重新核对只有读取,没有写入 | 通过 | +| 重启把 applying 转为 needs_check | 通过 | + +## 测试 + +- 执行的命令:`go test ./syb ./service ./repository ./handler/web -run InnerCode -count=1`; + 固定 `GOTOOLCHAIN=go1.23.0` 执行 `go build ./...`、`go test ./... -count=1`、 + `go vet ./...`;`git diff --check`。 +- 结果:全部通过。假服务端验证了请求路径、参数、单次发送、业务失败和未知结果分类。 +- **没验证到的部分**:没有执行真实顺运宝删除/写入;没有提供 `_test` MySQL 8.4 配置, + 因此新增的 v22→v23 集成测试已编译但按环境门禁跳过;未测试进程恰好在远端写入瞬间被强杀。 + +## 相关提交 + +- `2778eed` feat: 安全回写档口入库码并支持核验恢复 (#234)