Files
cmroubao/docs/tasks/T-242.md
T

90 lines
5.4 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.
---
id: T-242
title: 增加受约束的本地货运单删除
phase: 2
deps:
- T-241
status: DONE
created: 2026-07-29
context_ref: 7e3aaac
work_branch: null
write_paths:
- docs/tasks/T-242.md
- docs/current-state.md
- backend-api/internal/usecase/freight_*
- backend-api/internal/repository/sqlite/freight_*
- backend-api/internal/transport/httpapi/**
- backend-api/internal/transport/webui/**
---
## 问题 / 背景
Admin 可以导入、查看和生成采购需求,但误导入或不再需要的本地货运信息无法清理。货运商品
可能已经关联采购需求、采购任务和本地缓存图片,直接删除 `freight_orders` 会被外键阻止,
强制级联又会破坏采购来源审计或留下不可访问的 JPEG。
本功能只管理当前系统保存的 ERP 投影,不调用顺运宝删除接口,也不声称删除 ERP 源数据。
## 关联需求与交互
- ADMIN 在货运详情页明确确认后删除本系统中的货运单。
- 尚未创建任何采购需求的货运单可以删除;只要任一商品已进入采购流程,整单禁止删除。
- 删除成功后返回货运列表;操作不影响 ERP,可通过完整订单号重新导入。
- JSON 管理 API 提供同一删除能力和稳定的成功、冲突、未找到响应。
## 方案
1. 在 `FreightService` 增加删除命令;校验 ADMIN 作用域和 UUID 后调用仓储事务,并在提交后
通过图片服务清理已收集的本地缓存文件。
2. SQLite 使用 immediate 写事务锁定删除过程:按 `creator_subject` 读取订单,检查其全部
当前/历史商品是否被 `procurement_requests` 引用;有关联则不改数据并返回稳定冲突。
3. 无采购关联时先收集 READY 图片 `storage_key`,再删除全部商品明细和货运单;图片数据库
记录依赖现有 `ON DELETE CASCADE`。保留 `erp_sync_runs` 和增量水位作为同步审计。
4. 文件删除在数据库提交后以独立短超时执行。失败文件不再有数据库记录或鉴权读取路径,
不把文件系统失败伪装成数据库回滚,也不记录 storage key 或真实订单内容;Web 成功事件
只记录内部订单 UUID 和操作人 UUID。
5. Admin API 增加 `DELETE /api/v1/freight-orders/:id`:首次或重复删除均返回 `204`,
其他 ADMIN 作用域中的 ID 也按不存在处理;已有采购关联返回 `409` 和稳定错误码
`FREIGHT_ORDER_IN_USE`。
6. SSR 增加 `POST /freight/:id/delete`,复用 ADMIN session、CSRF 和安全响应头。删除入口
位于详情页标题操作区,危险样式与“返回列表”分开;提交前确认本地删除边界。
7. 成功后 `303` 到 `/freight?notice=deleted`;冲突时仍在详情页显示
“该货运单已进入采购流程,不能删除”。不在密集列表中增加直接删除按钮。
## 验收要点
- [x] 未创建采购需求的货运单可删除,订单、商品和图片数据库记录均不存在。
- [x] 所有缓存图片文件在提交后删除;文件已不存在时仍视为成功。
- [x] 任一商品有关联采购需求时整单返回冲突,订单、全部商品、图片和采购记录均不变化。
- [x] 删除不改变同步运行历史、同步水位或顺运宝 ERP 数据。
- [x] 重复 API 删除为幂等 `204`;无权访问的 ID 不泄漏存在性。
- [x] Web 删除必须通过 ADMIN session、CSRF 和确认交互,成功/冲突反馈明确。
- [x] 删除后使用相同完整订单号重新导入可创建新的本地货运快照。
- [x] 既有货运导入、图片读取、采购需求和采购任务流程不回归。
- [x] 1440×900、390×844 和 375×667 下详情操作区无重叠、溢出或误触风险。
- [x] 标准 Go 测试、race、vet 和三个入口构建通过。
## 边界
- 不删除或修改顺运宝 ERP 数据。
- 不删除同步运行记录,不回退日期增量水位;恢复必须使用完整订单号重新导入。
- 不级联删除采购需求、参考图、采购任务、执行结果或订单提交记录。
- 不提供批量删除、回收站、撤销、归档或自动过期清理。
- 不在页面、日志、fixture 或提交中加入真实货运单、店铺、商品或图片。
## 执行记录
- 2026-07-29:创建任务。第一版采用详情页单单删除和服务端强约束,以最小界面面积提供
可恢复的本地清理能力;采购审计优先于删除便利性。
- 2026-07-29:仓储使用现有 `_txlock=immediate` 事务按 ADMIN 作用域检查整单采购引用;
成功时收集 READY 图片键、删除全部商品和订单并保留同步运行/水位。跨作用域与重复删除
均为空操作,采购关联映射为 `FREIGHT_ORDER_IN_USE`;同单号新同步可建立全新 revision 1
快照。本任务不需要 schema migration。
- 2026-07-29:图片服务在数据库提交后用 5 秒总预算调用受路径约束且幂等的本地删除;
Admin API `DELETE` 返回 204/409,SSR POST 强制 CSRF 与 `confirm_delete=1`,详情页使用
二次确认 dialog 和 noscript 复选框回退,成功事件只记录内部 UUID。
- 2026-07-29:`go test ./...`、`go test -race ./...`、`go vet ./...` 和 API、authctl、
migrate 三个入口构建通过。Playwright 连接隔离 Gin/SQLite,在 1440×900、390×844、
375×667 验证弹窗无越界,首次焦点位于保留动作,三个操作按钮均高 44px;实际删除后
跳转空列表、原图片接口返回 404、本地 JPEG 消失,控制台无警告或错误。