12 KiB
12 KiB
报销状态空隙与财务处理视角
Goal
消除报销从审批通过到付款批次创建之间、以及报销回到草稿状态之后的两个运营空隙:财务应能在付款页直接发现并处理尚未组批的已通过报销,同时“全范围”不得暴露他人从未提交的私人草稿,但必须保留对已经进入过流程的退回或撤回草稿的追踪能力。
本任务来自真实业务单据 0014 的首次使用反馈。两个 Requirement 共享“状态空隙必须有明确责任人和可见入口”的产品原则,但必须保持代码边界、测试证据和回滚点独立,不能因一项回滚而被迫撤销另一项。
Scope
- R1 覆盖付款页待组批视图、报销详情下一步深链及报销处理进度中的组批/复核阶段区分。
- R2 覆盖报销列表、详情、材料、提交前检查、全局搜索、导出和报销统计的“本人草稿或已进入流程”服务端读取边界。
- 两项分别实施、分别测试、分别提交和回滚;具体行为以 Requirements 为准,排除项以 Out of Scope 为准。
Background
- 2026-09-04 对生产做了只读核验:目标单据唯一匹配,状态为
approved、未付款、无任何付款批次关联,payment_batch_v1为force_on/global,满足现有/payment-batches/candidates候选合同;未创建批次或改动单据。 - 同次脱敏统计显示:生产当前只有 1 张
approved且未付款、未被活动批次占用的报销,即本次目标单据;当前 1 张draft从未产生 workflow 实例,暂无“有历史 workflow 的 draft”。这些计数只用于评估本次行为,不作为测试 fixture 或实现常量。 - 付款首页只查询已经创建的
PaymentBatch;候选报销仅在财务点击“新建批次”后才加载。待我审批查询 workflow task,而付款批次复核不是报销 workflow task;组批前也不存在可复核的付款批次。 - 报销详情目前把无批次的
approved投影为“付款复核 / 待安排 / 待财务安排付款”,同时页面下一步仅写“等待财务处理”。批次draft才真正表示“已创建并提交付款复核”。当前投影把批次级阶段提前套在尚未组批的报销上。 - 报销列表的状态与范围相互独立。具备
expense.view_all的财务、财务负责人、CEO、HR、管理员可在草稿 + 全范围查看全公司的草稿;经理可查看本人、代填及直属下属草稿。现有详情和材料读取辅助函数也对expense.view_all无条件放行。 - 报销
return和申请人withdraw都会把业务状态改回draft,并保留 workflow 实例;从未提交的草稿没有 workflow 实例。仓库统计查询已使用 workflow 实例创建时间作为提交事实,因此“是否存在 workflow 实例”是现有、可推导且无需 schema 变更的“是否进入过流程”判据。
Requirements
R1:已通过但未组批的报销必须成为财务可见、可执行的队列
- 报销
approved且未付款、未进入任何非取消付款批次、付款能力对其部门有效时,必须出现在付款页一级“待组批”视图;候选资格继续由服务端现有候选合同决定,前端不得自行复制状态或部门门禁。 - “待组批”只对具备
payment.batch.manage的人员显示和查询;仅具备payment.batch.review的复核人继续查看已创建的付款批次,不获得组批候选或创建能力。 - 付款页在无批次详情参数时提供“待组批”和“付款批次”两个明确视图。对组批管理员默认进入“待组批”,标签显示服务端返回的候选总数;复核只读角色默认进入“付款批次”。URL 必须可表达当前视图并支持刷新、返回和报销详情深链。
- “待组批”复用现有候选 API、搜索、分页和创建合同,显示单号、报销人、报销日期、权威总额及摘要。它不是第二套候选计算,也不得同时保留一份隐藏在“新建批次”里的重复候选列表。
- 财务可从待组批列表选择一张或多张报销并进入现有“创建并提交复核”流程;创建成功后候选立即从待组批队列消失,付款批次视图出现新批次,其状态为“待付款复核”。不得自动组批、自动选择、自动复核或改动 maker-checker 规则。
- 报销详情在无批次的
approved状态下,把下一步明确写为“等待财务组建付款批次”。具备payment.batch.manage时提供进入付款页待组批视图的单一入口,并以当前报销编号预置搜索;其他用户只看到状态说明,不暴露付款管理能力。 - 报销处理进度必须区分“组建付款批次”和“付款复核”:
- 无批次的
approved:组批阶段为当前,说明“待财务组建付款批次”;付款复核仍为待处理。 - 已有
draft批次:组批阶段已完成,付款复核为当前,继续使用“待付款复核”。 - 后续
reviewed/executed/failed/cancelled继续由共享付款阶段语义投影,不改变付款写状态机。
- 无批次的
- 列表必须有加载、错误、空态和分页反馈;空态只说明当前没有待组批报销,不把“系统正常”写成解释性噪音。PC 与现有响应式付款页保持同一数据源,移动端不新建第二套付款状态机。
R2:全范围只展示已经成为业务事实的他人草稿
- “业务事实”判据固定为:报销单至少存在一个
entity_type=reimbursement的 workflow 实例。不得用当前 workflow 状态、最后一次 outcome、页面标签、单号是否为空或更新时间猜测。 - 报销人为本人或提交人为本人时,仍可查看自己的全部草稿,不要求存在 workflow 实例。
- 对他人的
draft:- 从未进入流程、无 workflow 实例:从全范围列表、全局搜索、导出和按报销聚合的统计中排除,直接访问详情或材料接口返回无权限。
- 曾经进入流程、有 workflow 实例:继续按既有全范围角色边界可见,包括审批人退回和申请人撤回后回到
draft的记录。
- 非
draft状态的既有可见性不变;经理仍限本人、提交人及直属下属,财务/财务负责人/CEO/HR/管理员仍限现有全局范围。本任务不新增角色、不授予expense.view_all、不改变编辑权限。 - 服务端必须统一强制该判据。前端可以隐藏不可见记录,但不得作为授权边界;详情、普通附件下载、附件预览 URL、完整材料预览和
POST /reimbursements/:id/precheck必须共同收紧,避免通过已知 ID 绕过列表。precheck返回的预算提示、费用标准、审批规则和风险标记同样属于受保护的报销内容。 - 报销统计与导出不得把他人从未提交的草稿当作正式台账事实;本人草稿是否进入个人视角统计沿用既有行为。付款候选只接受
approved,不受本条授权筛选影响。 - 被排除的记录对无权读取者使用既有自然中文无权限合同,不泄露“该 ID 存在但尚未提交”、workflow 计数或内部判据。
Acceptance Criteria
- AC1(R1):以
approved + unpaid + no active batch + gate enabledfixture 请求待组批视图,能看到目标报销;任一条件不满足时不出现。生产只读复核能在待组批视图搜索到0014,但自动化不得创建真实付款批次。 - AC2(R1):付款批次管理员默认看到“待组批”及准确总数,搜索/分页/空态/错误态可用;仅复核角色看不到待组批和创建入口,原有批次复核能力不变。
- AC3(R1):从报销详情点击入口进入可刷新、可返回的待组批 URL,并预置当前单号;无管理权限时入口为 0,但“等待财务组建付款批次”仍准确显示。
- AC4(R1):无批次时进度显示“组建付款批次”为当前且“付款复核”为待处理;创建批次后前者完成、后者当前。
draft/reviewed/executed/failed/cancelled付款批次的既有语义、通知、权限和写状态机回归通过。 - AC5(R1):创建成功只刷新候选与批次查询,不出现重复候选列表,不自动执行任何付款写动作;PC 1280px 无横向溢出,移动端可完成搜索、选择和进入创建流程,交互目标不小于现有 44px 约束。
- AC6(R2):表驱动服务端测试覆盖本人/提交人、全局角色、经理直属团队、无关人员 ×
draft无 workflow、draft有 returned workflow、draft有 cancelled/withdrawn workflow、所有非 draft 状态;只有“他人且从未进入流程的 draft”被排除。另有负向保护证明当前或历史 workflow 审批人读取自己任务关联的报销不受新过滤误伤。 - AC7(R2):同一未提交他人草稿在列表、全局搜索、CSV/XLSX 导出和报销统计中均不可见/不计入;直接详情、普通附件、预览 URL、完整材料预览和
precheck均返回无权限。不得只做前端筛选。 - AC8(R2):退回或撤回后为
draft且有 workflow 实例的报销仍可由原授权范围内人员查看;既有审批历史、只读投影和申请人编辑重提/再次提交路径不变。 - AC9(独立性):R1 与 R2 分成独立业务提交或至少独立可逆提交单元、独立 focused 测试组;分别回滚任一项时另一项仍可构建并通过自己的测试,不需要 schema、migration、seed、flag 或生产数据修正。
- AC10(门禁):前后端 focused 测试、前端 typecheck/build、UI strict/self-test、Prisma validate、workflow/权限过程级回归、Trellis governance 和
git diff --check通过;涉及权限和 workflow 投影,实施后必须进行只读 review。 - AC11(部署后):
/ready与 bundle marker 等于候选短 SHA,公网文案扫描 findings=0;真实账号只读确认0014位于待组批且未被自动修改,未提交他人草稿不再可见,退回/撤回历史草稿 fixture 仍可见。真实组批、复核和付款仍由财务人工执行。
Test Plan
- R1 focused:付款候选资格、manage/review 权限矩阵、待组批 URL/搜索/分页/空态、创建后查询刷新,以及无批次到五种批次状态的进度投影。
- R2 focused:角色与归属 × draft/非 draft × workflow 无/有的表驱动矩阵,并覆盖列表、详情、材料、
precheck、全局搜索、CSV/XLSX 和统计旁路;单列 workflow reviewer 待办读取的负向保护。 - 回归与门禁:付款 maker-checker、报销退回/撤回/重提、B1/B2、非报销 workflow、前端 typecheck/build、UI strict/self-test、Prisma validate、Trellis governance 和
git diff --check。 - 生产验收只读检查候选可见性和授权结果;不自动创建、复核或执行真实付款批次。
Out of Scope
- 不在本任务替财务创建
0014的付款批次、复核或登记付款。 - 不修改 Prisma schema,不新增
submitted_at,不回写历史报销或 workflow 数据。 - 不合并报销 workflow 与付款批次状态机,不把付款复核塞进“待我审批”。
- 不修改 maker-checker、付款账号、回单、网银制单、B1/B2、预算、票据或通知 routing。
- 不改变采购、差旅、请假、补卡的列表、草稿权限或工作流。
- 不借本任务调整
expense.view_all的角色授予;HR/CEO 是否应继续拥有该权限另行评估。 - 不新增批量自动组批、自动付款、真实支付接口或第二套移动付款页。
Risks and Deferred Items
- workflow 实例存在表示“曾进入流程”,因此会有意保留退回和撤回草稿的全范围可见性;若后续业务要求撤回后重新私有化,必须新增独立产品判据,不能悄悄改成 outcome 白名单。
- 当前数据库无
submitted_at;workflow 关系查询需要通过 focused 性能测试确认列表、搜索、导出和统计没有不可接受退化。本任务不以冗余字段或 migration 预优化。 - 全局搜索、导出和统计是列表之外的旁路;若实现评估发现某一旁路无法在本候选安全收紧,必须阻断 R2 发布或拆出明确依赖任务,不能把列表隐藏冒充权限修复完成。
- 真实付款批次创建属于财务业务动作,不作为自动化验收。部署后只证明候选可见、入口可用和数据未被自动修改。