8.1 KiB
8.1 KiB
| 1 | ID | Title | Description | Acceptance | Test_Method | Tools | Dev_Status | Review1_Status | Regression_Status | Files | Dependencies | Notes |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | A1 | R57 执行合同建档与范围冻结 | 创建并校验 R57 报销模板与差旅申请关联执行合同 CSV,冻结范围仅包含 ReimbursementTemplate 模型与 CRUD、报销创建支持 templateId/linkedTravelRequestId、报销详情新增差旅关联摘要、报销模板管理页和创建入口改造。 | issues/2026-04-08_r57-reimbursement-templates.csv 12 列完整、Dependencies 为 JSON 数组字符串、Test_Method 可复现;范围仅覆盖 A1-A6,不混入报销 submit 流程改造、TravelRequestsPage 主界面重构或 travel_orders 回写。 | 命令:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-04-08_r57-reimbursement-templates.csv。检查:1) 对照 AGENTS.md 与 issues/README.md 校验字段完整;2) A2-A6 依赖链正确;3) Notes 写明迁移回滚路径和差旅关联兼容规则。 | manual | DONE | DONE | DONE | issues/2026-04-08_r57-reimbursement-templates.csv | [] | 回滚路径:删除本次 CSV 不影响业务。 |
| 3 | A2 | ReimbursementTemplate 模型、迁移与 CRUD 路由 | 新增 ReimbursementTemplate Prisma 模型和 ReimbursementForm.linked_travel_request_id 字段,落地模板 CRUD 路由与只读列表接口。 | schema.prisma 含 ReimbursementTemplate、ReimbursementForm.linked_travel_request_id 与 TravelRequest.linked_reimbursements relation;迁移目录为 20260408120000_r57_reimbursement_templates;/api/reimbursement-templates 支持 authenticated 读取、system.settings 管理、items 严格校验、DELETE 软删除。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && npx prisma validate && node --check src/routes/reimbursementTemplates.js && npm test -- tests/unit/routes/reimbursementTemplates.test.js。业务:1) enabled 过滤正常;2) items 非法 schema 被拒绝;3) expenseTypeId 不存在或停用被拒绝;4) DELETE 仅将 enabled 置为 false。 | manual | DONE | DONE | DONE | server/prisma/schema.prisma|server/prisma/migrations/20260408120000_r57_reimbursement_templates/*|server/src/routes/reimbursementTemplates.js|server/src/app.js|server/tests/unit/routes/reimbursementTemplates.test.js | ["A1"] | 回滚路径:回退路由与注册,并在回滚迁移中 DROP TABLE reimbursement_templates、DROP COLUMN reimbursement_forms.linked_travel_request_id。 |
| 4 | A3 | 报销创建支持模板与差旅关联 | 增强 POST /reimbursements 支持 templateId/linkedTravelRequestId,新增 linkable-travel-requests 查询,并扩展报销详情返回差旅关联摘要。 | POST /reimbursements 支持空白/模板/差旅三种创建;templateId 与 linkedTravelRequestId 互斥;模板创建自动生成明细并更新 total_amount;差旅关联仅允许本人或合法代理关联 approved 且未关联的申请;GET /api/reimbursements/:id 返回 linkedTravelRequestId 与 linkedTravelRequest;GET /api/reimbursements/linkable-travel-requests 正确过滤本人/代理可关联申请。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/routes/reimbursements.js && npm test -- tests/unit/routes/reimbursements.create.test.js。业务:1) 空白创建不回归;2) 模板创建会预填明细;3) 差旅关联创建会预填 description 和交通明细;4) 已通过 linked_travel_request_id 或 travel_orders.linked_reimbursement_id 关联过的申请不会再次暴露。 | manual | DONE | DONE | DONE | server/src/routes/reimbursements.js|server/tests/unit/routes/reimbursements.create.test.js|server/prisma/schema.prisma | ["A1","A2"] | 回滚路径:移除 templateId/linkedTravelRequestId 创建分支、linkable 路由和详情摘要返回,保留空白创建行为。 |
| 5 | A4 | 报销模板管理前端页面与路由 | 新增报销模板管理页、前端 API、路由懒加载和系统设置入口。 | /system/reimbursement-templates 仅 system.settings 用户可访问;页面支持模板卡片列表、新增/编辑弹窗、动态增减预设明细和软删除;前端通过 reimbursementTemplates API 调用后端接口。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 可在系统设置进入模板页;2) 可创建/编辑/停用模板;3) 预设明细费用类型名称与默认金额展示正确。 | manual | DONE | DONE | DONE | client/src/api/reimbursementTemplates.ts|client/src/pages/ReimbursementTemplatesPage.tsx|client/src/pages/SystemSettingsPage.tsx|client/src/router/index.tsx|client/src/router/lazy/ReimbursementTemplatesPage.ts|client/src/router/lazy/index.ts | ["A1","A2"] | 回滚路径:移除模板页面、API、路由和系统设置入口。 |
| 6 | A5 | 报销创建入口与详情页差旅关联 UX | 在报销列表创建入口集成空白/模板/关联差旅三种创建方式,并在报销详情页展示关联差旅申请卡片。 | ReimbursementsPage 的创建入口改为下拉分区菜单,可直接选择模板或可关联差旅申请创建并跳转详情;ReimbursementDetailPage 在存在 linkedTravelRequestId 时展示可跳转的差旅摘要卡片;前端类型支持创建响应、详情和 linkable 列表。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 新建报销菜单可见空白/模板/差旅三个入口;2) 选择模板或差旅后创建成功并跳转;3) 详情页能看到关联差旅申请摘要并跳转到 /travel-requests?tab=requests&id=<id>。 | manual | DONE | DONE | DONE | client/src/pages/ReimbursementsPage.tsx|client/src/pages/ReimbursementDetailPage.tsx|client/src/api/reimbursements.ts|client/src/api/travelRequests.ts | ["A1","A2","A3","A4"] | 回滚路径:恢复单一空白创建按钮,移除详情页差旅关联卡片和相关类型扩展。 |
| 7 | A6 | Reviewer、QA、CSV 回填与提交收口 | 执行 reviewer 自检、post-check、远端迁移核验项准备与 CSV 回填,完成提交收口。 | review 覆盖模板 JSON 校验、差旅归属与已关联过滤、模板/差旅创建后的明细结构一致性、linked_travel_request_id 可空兼容和迁移回滚;post-check 全部通过;CSV 三列状态回填为实测结果;完成 git commit。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && npx prisma validate && npx prisma migrate status && node --check src/routes/reimbursements.js && node --check src/routes/reimbursementTemplates.js && npm test -- tests/unit/routes/reimbursementTemplates.test.js tests/unit/routes/reimbursements.create.test.js && cd ../client && npm run typecheck && npm run build。部署准备:记录远端需执行 docker compose -f deploy/trialrun/docker-compose.yml --env-file deploy/trialrun/.env exec -T server npx prisma migrate status。业务:1) 模板和差旅创建都成功;2) 已关联差旅申请不再可选;3) CSV 状态已回填。 | manual | DONE | DONE | DONE | issues/2026-04-08_r57-reimbursement-templates.csv|server/prisma/schema.prisma|server/prisma/migrations/20260408120000_r57_reimbursement_templates/*|server/src/routes/reimbursementTemplates.js|server/src/routes/reimbursements.js|server/tests/unit/routes/reimbursementTemplates.test.js|server/tests/unit/routes/reimbursements.create.test.js|client/src/api/reimbursementTemplates.ts|client/src/pages/ReimbursementTemplatesPage.tsx|client/src/pages/ReimbursementsPage.tsx|client/src/pages/ReimbursementDetailPage.tsx|client/src/pages/SystemSettingsPage.tsx|client/src/router/index.tsx|client/src/router/lazy/ReimbursementTemplatesPage.ts|client/src/router/lazy/index.ts|client/src/api/reimbursements.ts | ["A2","A3","A4","A5"] | 回滚路径:若 QA 发现关键回归,暂停提交并回退对应代码与迁移;部署后已在远端执行 prisma migrate deploy + prisma migrate status,确认 R57 迁移已应用。本地 prisma migrate status 受既有历史迁移漂移影响未通过:本地数据库缺失若干仓库内迁移且存在 20260312193000_p22_prod_1_invoice_pool_travel_bind_constraint 本地目录缺口。 |