76 lines
5.9 KiB
Markdown
76 lines
5.9 KiB
Markdown
---
|
||
id: T-203
|
||
title: 表格查询与批量开始采购授权
|
||
phase: 2
|
||
deps: [T-202, T-209]
|
||
status: DOING
|
||
created: 2026-08-04
|
||
vikunja_task_id: 30
|
||
context_ref: 1f20271
|
||
work_branch: task/t-203-start-purchases
|
||
needs_device: false
|
||
needs_human_review: false
|
||
write_paths:
|
||
- docs/tasks/T-203.md
|
||
- admin/internal/tasks/**
|
||
- admin/internal/server/**
|
||
- admin/internal/transport/webui/**
|
||
- admin/internal/config/**
|
||
- admin/cmd/server/**
|
||
- admin/README.md
|
||
---
|
||
|
||
<!-- BEGIN VIKUNJA EXPORT id=30 synced=2026-08-04T09:16:48Z sha256=6c62ba368a760e96b8feb06f3f3ced8a2a40d10f7754a99471f7429c3862a80c -->
|
||
## 问题 / 背景
|
||
|
||
T-202 已完成手工 DRAFT 建单;T-209 将生产 schema/领域状态机迁移到单趟模型。项目所有者明确:管理员点击“开始采购(只创建待付款订单)”本身就是授权,不再增加试选后确认。T-203 负责采购服务查询和批量授权事务,使设备后续只能领取显式授权的 PENDING 任务。
|
||
|
||
## 关联需求与交互
|
||
|
||
F-004、F-008、F-018;US-003、US-005;IX-005;GET /tasks、POST /tasks/start-purchases;依赖 T-202、T-209。
|
||
|
||
## 方案
|
||
|
||
1. GET /tasks 支持 keyword、status、created_from、created_to;日期按 Asia/Shanghai 转为 UTC 半开区间,非法筛选返回可访问字段错误;默认全部状态并按 created_at DESC,rowid DESC。
|
||
2. 页面只让 DRAFT 行可勾选;表格上方显示选中数量、最高总额字符串合计、“系统不会付款”和唯一主按钮“开始采购(只创建待付款订单)”,不加逐行操作或重复确认弹窗。JS 只用同源静态文件,金额以分/BigInt 累计,不用浮点。
|
||
3. POST 使用服务端生成并渲染的 UUID v4 start_key,接收非空去重任务 id + expected_task_version;批量上限 100。created_by 只取已认证管理员,不接受请求字段。
|
||
4. 在一个有界 SQLite 写事务内先按 start_key 检查重放,再按 task_id 稳定排序读取并复核全部任务:存在、DRAFT、版本相等、锁定字段完整、数量/总额上限满足显式配置。任一失败整批不变。
|
||
5. 新请求为整批使用同一 created_at/expires_at;逐条创建 ACTIVE 一次性授权,锁定新 task_version、goods_id、颜色、尺码、数量和 total_price_cap;条件更新每条 DRAFT/version 为 PENDING/version+1,任一 RowsAffected != 1 则全批回滚。
|
||
6. 相同 start_key + 相同规范集合(输入顺序无关)返回原 authorization ids/版本/有效期,不再次改任务;同 key 子集、超集、不同版本或残缺集合返回 409。网络结果不明时前端冻结原 key/载荷,只允许原样重放。
|
||
7. 显式配置并启动时校验授权 TTL、最大任务数量、最大总额;金额只用规范十进制字符串。T-207 才关闭过期授权,T-203 只写 expires_at。
|
||
|
||
## 验收要点
|
||
|
||
- 覆盖单条/100条成功,任务版本仅加一次、快照逐字段相等、管理员来自服务端、UTC 过期时间正确。
|
||
- 任一缺失/非 DRAFT/版本冲突/字段不完整/数量或金额超限/中途 SQL 失败均整批零修改。
|
||
- 同 key 同集合、倒序集合、并发重放返回同一结果;同 key 不同集合冲突;不同 key 并发抢同一版本仅一个成功。
|
||
- 未登录、CSRF、空/重复/畸形/超大请求、配置边界和数据库故障 fail closed,不泄露内部错误。
|
||
- UI 只有 DRAFT 可选;筛选、全选当前可见项、选择反馈、网络不明重放、焦点/aria-live/横向滚动与不付款文案有测试;无同义确认弹窗。
|
||
- go test ./...、go test -race ./...、go vet ./...、go build ./...、node --check 静态 JS、完整 init.ps1、上下文校验和 diff-check 通过。
|
||
|
||
## 执行记录
|
||
|
||
### 2026-08-04T09:16:39Z · ila
|
||
|
||
2026-08-04 开始 T-203:依赖 T-209 已完成并合入 main。主 agent 已完成开工前只读审计,冻结 v2 schema 启动校验、单进程 writeGate、start_key 规范集合重放、Asia/Shanghai 到 UTC 半开区间、julianday 查询及 big.Int 分金额边界;本地状态转 DOING,分支 task/t-203-start-purchases。
|
||
<!-- END VIKUNJA EXPORT -->
|
||
|
||
## 边界
|
||
|
||
- 本任务只实现管理员任务查询与批量“开始采购”授权;不实现任务详情/截图、设备 Bearer 身份、领取/
|
||
租约、purchase attempt API、提交围栏、结果调和、真机自动化、创建订单点击或付款。
|
||
- “开始采购(只创建待付款订单)”按钮本身就是明确授权,不得再增加同义确认弹窗,也不得把它拆回
|
||
试选后确认。按钮附近必须持续显示系统不付款;页面不得提供逐行“开始采购”操作列。
|
||
- 只有 `DRAFT` 行可以勾选;批量事务必须全有或全无。任一任务缺失、状态/版本变化、锁定字段非法、
|
||
配置超限、授权插入失败或条件更新未命中,都不得留下部分授权或部分 `PENDING`。
|
||
- 幂等重放必须先于 DRAFT 状态检查:相同 `start_key` 和相同规范任务集合只返回原结果,任务版本不得
|
||
再增加;同 key 的子集、超集、不同 expected version 或残缺授权集合一律冲突。网络结果不明只能
|
||
原样重放同一个 key 和载荷,不能生成新 key。
|
||
- 授权只锁定任务的新版本、goods_id、颜色、尺码、数量和 `total_price_cap`;不得写入观察单价或
|
||
`authorized_unit_price`。金额校验、配置比较和浏览器合计均使用十进制字符串/整数分,不用浮点。
|
||
- `created_by` 只能来自已认证管理员会话;POST 必须验证 CSRF。设备凭据不能调用本接口,本任务也不
|
||
新增设备接口。内部数据库错误不得回显 SQL、路径、配置值或凭据。
|
||
- 过期授权的关闭/重置属于 T-207;本任务只创建 `expires_at`。授权一旦进入 `FENCED`,本任务没有
|
||
释放、取消、重新授权或重试入口。
|
||
- 本任务不实现、不引用通用真机点击、`submit_order_once()` 或任何支付、免密支付、先用后付能力。
|