diff --git a/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md b/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md index 700db36a..aea266d1 100644 --- a/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md +++ b/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md @@ -30,6 +30,10 @@ duplicate detection or attachment behavior. require the same own-or-`expense.view_all` guard as reimbursement detail reads before invoking the precheck service; an ordinary nonparticipant must receive 403 without service-side evaluation. +- 取消或放宽必填校验时,必须继续审计该校验之后的代码是否依赖它提供的 + 非空、类型或状态保证,并为生产真实存在的空值路径补回归测试。不得只 + 删除前置错误分支;可空字段的 `.trim()`、`.length`、字符串拼接和传给 + 非空参数的调用都应逐处确认。 ## Scenario: OCR Disabled Without Mock Data @@ -996,8 +1000,10 @@ await selectApprovalRule(reimbursement.total_amount); - Only `travel_meal` and `travel_local_transport_allowance` are invoice-free in the initial policy. Invoice-free means skip invoice presence/amount checks; it does not remove explanation, formula, approval or attachment obligations. -- Every `assets` item requires a trimmed approval basis on create, update and - submit. Switching an item to a non-assets type clears the stored basis. +- 公司当前没有 assets 事前审批制度。Item create/update 继续兼容可空的 + `assetPriorApprovalBasis`:创建时缺失或空白落 null;更新时 omitted 保留 + 现值,显式 null/空白清空;切换到非 assets 类型仍清空。当前 PC/移动 UI + 不展示或发送该字段,历史值不得因普通编辑被静默清空。 - `office_supplies` at or above CNY 2,000 per item shows the same non-blocking office-electronics hint on editable PC/mobile forms and read-only finance detail. It does not change the type or decide accounting fixed-asset status. @@ -1027,9 +1033,9 @@ await selectApprovalRule(reimbursement.total_amount); ### 4. Validation & Error Matrix -- Assets item without basis -> `400 VALID_001` with - `assetPriorApprovalBasis=required_for_assets`; submit returns affected item - IDs under `asset_prior_approval_basis_required`. +- Assets item without basis -> 允许创建、编辑和提交;字段缺失、数据库现值 + 为 null 或显式清空均不得产生空值解引用或 `500`,其他金额和票据门禁照常 + 执行。 - Guard-on bind without `linkedItemId` -> `400 VALID_001` with `required_when_invoice_guard_enabled`; an item outside the form remains `item_not_in_reimbursement` with zero writes. @@ -1052,9 +1058,12 @@ await selectApprovalRule(reimbursement.total_amount); guard either on or off. - Base: guard off preserves an older draft and its auto-created link; later disabling the guard preserves links created during a guarded rollout. +- Good: assets 编辑请求 omitted 兼容字段时,数据库 null 保持 null、历史非空值 + 原样保留;显式 null/空白才清空。 - Bad: compare every positive item to a zero invoice total, silently create an item while explicit selection is required, use JavaScript floating-point - sums for money, or let repeated init erase finance account mappings. + sums for money, let repeated init erase finance account mappings, or 删除前置 + 必填校验后继续对可空值直接调用 `.trim()`。 ### 6. Tests Required @@ -1064,13 +1073,15 @@ await selectApprovalRule(reimbursement.total_amount); - Expense-type route tests assert list mapping, create/update persistence and audit changes for `requiresInvoice`; seed tests assert the two allowances, disabled legacy types, default-off flag and account-code preservation. -- Item/submit route tests cover assets create/update/submit, invoice-free zero - invoice, missing link, unlinked bound invoice, declared-over-invoice and - participant/nonparticipant side effects. +- Item/submit route tests 覆盖 assets 创建 omitted→null、编辑 null+omitted→null、 + 有值+omitted→保留、显式清空、切换非 assets 清空和无依据提交,并继续覆盖 + invoice-free zero invoice、missing link、unlinked bound invoice、 + declared-over-invoice 与 participant/nonparticipant side effects。 - Bind tests cover flag on/off, missing/foreign/successful explicit links and prove the guard-on path does not create a reimbursement item. -- PC/mobile Playwright covers descriptions, approval-basis input, the CNY 2,000 - warning, allowance-only submit projection, disabled add action until every +- PC/mobile Playwright covers asset 登记导向说明、批准依据输入/展示均不存在且 + 保存 payload omission、CNY 2,000 warning、allowance-only submit projection、 + disabled add action until every selected invoice has an item, and pending-OCR binding retaining that item. - Run full backend Vitest with the pinned BIFF8 Python dependencies, Prisma validate/generate check, frontend typecheck/build, focused Playwright, @@ -1090,6 +1101,11 @@ if (item.amount > linkedInvoices.reduce((sum, invoice) => sum + Number(invoice.t update: { account_code_default: null }; // erases finance configuration on init ``` +```js +// 旧必填校验删除后,omitted/null 会在这里变成 500。 +asset_prior_approval_basis: targetApprovalBasis.trim(); +``` + #### Correct ```js @@ -1107,6 +1123,10 @@ update: { name, description, requires_invoice }; // preserve account_code_defaul create: { name, description, requires_invoice, account_code_default: null }; ``` +```js +asset_prior_approval_basis: targetApprovalBasis?.trim() || null; +``` + ## Scenario: Payment Batch Receipt Attention Count ### 1. Scope / Trigger diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/check.jsonl b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/check.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/check.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/design.md b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/design.md new file mode 100644 index 00000000..4a3b3074 --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/design.md @@ -0,0 +1,58 @@ +# 设计:取消报销资产事前批准强制 + +## 设计边界 + +本轮是对 B1 产品口径的最小纠偏,不新增 schema、feature flag 或审批机制。生产继续运行 `0f9f403`,新候选只改变 assets 明细的保存/提交条件、前端呈现、seed description 与事实源。 + +## 服务端兼容合同 + +`asset_prior_approval_basis` 保持 nullable,API 的 `assetPriorApprovalBasis?: string | null` 保持兼容: + +| 场景 | 目标行为 | +| --- | --- | +| 新建 assets,字段缺失/空白 | 保存 null,允许创建 | +| 编辑 assets,字段 omitted、现值为 null | 保持 null,允许编辑,不发生 null `.trim()` | +| 编辑 assets,字段 omitted、现值有值 | 保留现有值,避免隐藏 UI 后静默清空 | +| 编辑 assets,字段显式 null/空白 | 清空为 null | +| assets 切换为非 assets | 清空为 null | +| 提交 assets 且字段为空 | 不阻断,继续执行金额、票据和 workflow 门禁 | + +创建/编辑仍查询费用类型以验证 enabled/category;category 只用于切换到非 assets 时清理兼容字段,不再决定必填。 + +删除创建/编辑必填分支时,原本被校验守卫保护的 `.trim()` 必须同时改为安全归一化: + +```js +body.assetPriorApprovalBasis?.trim() || null +targetApprovalBasis?.trim() || null +``` + +不允许用非空断言或默认虚构文本代替 null 兼容。 + +## 前端数据流 + +- PC `ReimbursementItemEditor` 的表单模型移除 `assetPriorApprovalBasis`,不渲染输入、不参与 disabled、不进入 `onSave`。 +- PC 详情保存 payload 不再写该字段,编辑初始值也不再从详情 DTO 映射。 +- 移动端 `ItemFormState`、新增/编辑初始化和 mutation payload 同步移除该字段。 +- PC 表格与移动卡片移除批准依据展示。API DTO 类型保留,避免对旧服务端/客户端契约做无收益破坏。 + +## 主数据说明 + +seed 继续通过 upsert 更新启用类型 description,不触碰 `account_code_default`。推荐文案: + +- 设备采购:`通用设备采购;请在明细说明中写明物品名称、实际使用人或责任人、存放位置,便于资产登记。` +- 家具采购:`办公家具采购;请在明细说明中写明物品名称、实际使用人或责任人、存放位置,便于资产登记。` +- 办公电子设备:`单条明细金额达到 2,000 元的办公电子设备通常选择本类型;请在明细说明中写明物品名称、实际使用人或责任人、存放位置,便于资产登记。该门槛不等同于会计固定资产确认标准。` + +## 发布与回滚 + +- 无 migration;init 仍可运行既有 migration status + seed 流程,必须确认 pending=none、seed 退出码 0。 +- 部署后核对三个 description、B2 仍为 global on、`/ready` 和 bundle marker 为新候选。 +- 公网用合成 assets 草稿验证 PC/移动保存和提交,不使用 0017 做 smoke。 +- 异常时回滚应用到本轮发布前候选 `0f9f403`;数据库兼容列和已存在值不需要补偿。回滚后旧候选会恢复强制,因此 0017 在纠偏验收完成前始终不得退回。 + +## 风险控制 + +- 最大兼容风险是隐藏输入后编辑请求携带 null,误清历史值;通过前端 payload 断言和服务端 omitted-field 测试锁定。 +- 最大运行时风险是删除必填校验后暴露下游 `.trim()` 的 null/undefined 假设;创建 omitted、编辑 null omitted 和编辑有值 omitted 三条路由测试必须同时覆盖。 +- 最大文案风险是四处 2,000 元提示只改一半;E2E 同时覆盖 PC/移动编辑态和展示态。 +- seed 失败会造成代码已取消强制但费用类型仍宣称要批准;部署验收必须同时核应用行为和三条主数据文案。 diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.jsonl b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.md b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.md new file mode 100644 index 00000000..20afea69 --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/implement.md @@ -0,0 +1,46 @@ +# 实施清单:取消报销资产事前批准强制 + +## 1. 规划与候选边界 + +- [x] PRD、design、implement 经用户审查并明确批准实施。 +- [x] 确认当前生产仍运行 `0f9f403`,0017 尚未退回;0016 可由真实财务并行推进,不把真人单据用于本轮 smoke。 + +## 2. 服务端纠偏 + +- [x] 删除明细创建、编辑和提交三处 assets 批准依据强制错误。 +- [x] 同步修复被原校验遮蔽的两处空值解引用:create 使用 `body.assetPriorApprovalBasis?.trim() || null`,patch 使用 `targetApprovalBasis?.trim() || null`。 +- [x] 规范创建/编辑字段语义:create omitted/空白落 null;patch 现值为 null 且 omitted 保持 null、有值且 omitted 保留、显式空清除、切换非 assets 清除。 +- [x] 保留 Prisma 列、请求 schema、详情响应和 API 兼容字段,不新增 migration。 + +## 3. PC 与移动端纠偏 + +- [x] PC editor 移除输入、状态、初始值、保存 payload 和 disabled 条件;详情表格移除展示。 +- [x] 移动端移除 ItemFormState 字段、新建/编辑映射、保存 payload、输入、disabled 条件和卡片展示。 +- [x] 四处 2,000 元提示统一删除“并填写事前批准依据”,保留原触发函数和提示级语义。 + +## 4. 主数据、文档与规约 + +- [x] 更新三个启用 assets seed description 为资产登记导向,确认 update/create 分支均落地且不写 account code。 +- [x] 更新 `docs/产品口径.md` 和 reimbursement spec,删除不存在的强制审批制度与错误矩阵。 +- [x] 在 reimbursement spec 记录:取消必填校验时必须检查下游依赖的非空/类型/状态假设,并覆盖真实空值路径,不能只删除前置校验。 +- [x] 不修改既有 migration;migration 单测继续验证 nullable 与无破坏性操作。 + +## 5. 测试 + +- [x] 后端路由测试覆盖 assets 无依据可提交,以及创建 omitted→null、patch null+omitted→null、patch 有值+omitted→保留、显式清空、切换非 assets 清空;全部不得出现 500,B2 门禁不回退。 +- [x] seed 测试断言三个 description 不含批准措辞且包含资产登记信息。 +- [x] r111 E2E 覆盖 PC/移动无输入、无展示、可保存和四处新提示;明确关联与免票合同继续通过。 +- [x] 运行 `cd server && npm run prisma:validate` 和聚焦 Vitest。 +- [x] 运行 `cd client && npm run typecheck && npm run build` 及聚焦 Playwright。 +- [x] 运行 Trellis governance、process contract、docs registry、敏感信息检查和 `git diff --check`。 + +## 6. 复核、提交与部署门禁 + +- [x] 实施后执行只读专项 review,重点核权限/提交门禁未误删、API 兼容和 seed 文案一致性。 +- [ ] 用户审查通过后,以中文 commit 引用 task 名,push 与部署分别取得授权。 +- [ ] 无 migration 部署仍显式记录 pre/post pending=none、init/seed 退出码 0、三条 description、B2 global on、`/ready` 和 bundle marker。 +- [ ] 公网合成 assets 草稿 PC/移动验证通过并清理后,才由真实财务按已批准理由退回 0017。 + +## 7. 回滚 + +- [ ] 应用或 seed 验收失败时停止 0017,回滚应用到 `0f9f403`;不回滚数据库列、不清历史值、不改 B2 关联数据。 diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/prd.md b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/prd.md new file mode 100644 index 00000000..6e0746f5 --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/prd.md @@ -0,0 +1,81 @@ +# 取消报销资产事前批准强制 + +## Goal + +纠正 B1 把不存在的公司制度做成系统强制的问题:公司当前不要求办公家具、通用设备或办公电子设备采购事前审批,报销系统不得要求员工填写“事前批准依据”才能保存或提交。保留已上线的兼容字段与历史数据,不做 migration;把 assets 类型的员工说明改为资产登记导向,要求在明细说明中写清物品、使用人或责任人、存放位置。 + +## Background and Confirmed Facts + +- 当前生产候选 `0f9f403` 已上线 B1/B2。B1 在 PC、移动端和服务端把所有 `category=assets` 明细一律要求填写事前批准依据,但公司没有对应的事前审批制度。 +- 继续保留必填或教员工填写固定话术都会制造虚假合规痕迹;改成大额门槛仍然是在实现一条不存在的规则,因此本轮直接取消强制,不设置金额触发条件。 +- `ReimbursementItem.asset_prior_approval_basis` 已是可空列;生产现有明细没有已填写值,但仍按兼容原则保留列、API 字段和任何历史值,不删除、不回填、不迁移。 +- `BX-20260828-0016` 是外部技术服务费用,不含 assets 明细,可在本任务并行规划/实施期间由真实财务作为真人 canary 退回。`BX-20260828-0017` 的实物是办公家具,必须等待本纠偏上线后再退回。 + +## Scope + +- 报销 assets 明细创建、编辑、提交的批准依据校验。 +- PC/移动端 assets 明细编辑、保存和展示,以及办公用品 2,000 元选类提示。 +- 三个启用 assets 费用类型的 seed description。 +- 产品口径、报销规约、聚焦后端与端到端测试,以及无 migration 的受控部署验收。 + +## Requirements + +### R1 取消所有 assets 批准依据阻断 + +- 服务端删除三个强制点:明细创建 `server/src/routes/reimbursements.js:3670`、明细编辑 `:3835`、提交时 `missingAssetApprovalItemIds` 检查 `:4061-4077`。 +- assets 明细未提供 `assetPriorApprovalBasis` 时允许创建、编辑和提交;票据—明细关联、票面金额、正金额、费用类型启用状态及其他既有门禁保持不变。 +- 创建 assets 明细时,批准依据缺失或空白保存为 null。编辑时字段未传必须保留历史值,显式传 null/空白才清空;切换为非 assets 类型继续清空该字段。不得因页面隐藏字段而在编辑日期、金额、类型或说明时静默丢失历史值。 +- 删除必填校验后必须同步消除其下游的非空假设:创建路径 `server/src/routes/reimbursements.js:3686-3687` 使用 `body.assetPriorApprovalBasis?.trim() || null`;编辑路径 `:3854-3856` 使用 `targetApprovalBasis?.trim() || null`。字段 omitted、数据库现值为 null 或显式 null 均不得触发 `.trim()` TypeError/500。 + +### R2 移除无用途的前端输入与展示 + +- PC `ReimbursementItemEditor.tsx` 和移动端 `MobileReimbursementDetailPage.tsx` 不再渲染“事前批准依据”输入框,也不再因其为空禁用保存按钮。 +- PC `ReimbursementDetailPage.tsx` 和移动端明细卡不再展示“事前批准依据”行。API 类型与详情响应字段保留以兼容旧客户端和历史数据,但当前 UI 不再发送该字段。 +- 清理 PC/移动端编辑状态、初始值和保存 payload 中只为该输入框服务的数据流,确保普通编辑不显式发送 null 清空历史值。 + +### R3 把资产类型说明改为资产登记导向 + +- `assets_equipment`、`assets_furniture`、`assets_office_electronics` 三个启用类型不再出现“事前批准”“批准人”“批准时间”或“批准依据”。 +- 类型说明要求员工在明细“说明”中写清物品名称、实际使用人或责任人、存放位置,供管理员后续人工建卡和资产登记使用。 +- `assets_office_electronics` 保留单条明细 `2,000 元`选类提示以及“不等同于会计固定资产确认标准”的声明。 + +### R4 统一 2,000 元提示文案 + +- 以下四处提示统一为“该金额通常应选择办公电子设备。”,删除“并填写事前批准依据”:PC 编辑态 `ReimbursementItemEditor.tsx:188`、PC 展示态 `ReimbursementDetailPage.tsx:1282`、移动编辑态 `MobileReimbursementDetailPage.tsx:1112`、移动展示态 `MobileReimbursementDetailPage.tsx:1143`。 +- 提示仍只在 `office_supplies` 且单条明细金额大于等于 `2,000 元`时显示,保持提示级、不阻断、不自动改类。 + +### R5 文档、规约与测试同步 + +- 更新 `docs/产品口径.md:194`,明确公司当前无 assets 事前审批要求,资产信息通过明细说明支持人工登记。 +- 更新 `.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md:984/988/1031/1032`,删除强制批准合同和对应错误矩阵,保留 nullable/API 兼容与非 assets 清理语义。 +- 反转 `server/tests/unit/routes/reimbursements.expense-standards.test.js:337-348` 的断言:缺批准依据的 assets 明细不得再返回 400,并补创建/编辑兼容测试。至少覆盖:创建 assets 且字段 omitted 返回成功并落库 null;编辑数据库现值为 null 的 assets 且字段 omitted 返回成功并保持 null;编辑有历史值的 assets 且字段 omitted 保留原值;显式 null/空白清空;切换非 assets 清空。 +- `server/tests/unit/scripts/reimbursement-expense-policy-migration.test.js:17` 继续证明列为 nullable 且 migration 无破坏性操作;本轮不得新建或修改生产 migration。 +- 更新 `client/tests/e2e/r111-invoice-reimbursement-guard.spec.ts:747-804`:PC/移动端不显示批准输入或展示,保存不被阻断,四处 2,000 元提示使用新文案;票据明确关联和免票补助合同继续通过。 +- 在 reimbursement spec 沉淀通用防回归规则:取消或放宽必填校验时,必须审计后续代码是否依赖该校验提供的非空、类型或状态保证,并为真实空值路径补回归测试;不得只删除前置错误分支。 + +## Acceptance Criteria + +- [x] PC 和移动端选择三个 assets 类型时均不出现“事前批准依据”输入框,未填写该字段也能保存明细并提交。 +- [x] 服务端创建、编辑、提交均不再返回 `required_for_assets` 或 `asset_prior_approval_basis_required`,其他 B2 票据门禁不回退。 +- [x] 创建 assets 字段 omitted、编辑 assets 现值为 null 且字段 omitted 均成功并保持 null,不出现 TypeError/500;有值 omitted、显式清空和切换非 assets 的兼容语义均有测试锁定。 +- [x] 当前 UI 编辑 assets 明细不会发送该兼容字段;服务端遗漏字段保留历史值,显式清空有效,切换非 assets 仍清空。 +- [x] PC/移动编辑态和展示态四处 2,000 元提示一致,仍为提示级且不自动改类型。 +- [x] 三个启用 assets 类型 description 均转为资产登记导向;办公电子设备仍保留 2,000 元及非会计固定资产门槛声明。 +- [x] 数据库列、Prisma schema、API 字段及历史数据保留,无 migration、无批量更新、无数据清理。 +- [x] 聚焦后端测试、前端 typecheck/build、r111 E2E、Trellis/process/docs 治理和 `git diff --check` 全部通过。 +- [ ] 新候选完成独立只读复核、push、无 migration 部署和公网 PC/移动验证后,才允许真实财务退回 0017。 + +## Out of Scope + +- 新增采购申请、审批流、金额批准门槛、数量/单价模型或自动资产建卡。 +- 改造票据直接重关联、明细删除联动、B3 财务一页式或恢复行内费用标准提示。 +- 修复 `deploy-existing.sh --no-deps`、PGDATA 容器内检查、admin smoke 治理等运维债。 +- 清空 `asset_prior_approval_basis` 历史值、删除数据库列或修改既有 migration。 +- 代替真实财务退回、审批或付款;0016 canary 和 0017 退回继续按生产写入门禁单独执行。 + +## Test Plan + +- 服务端:Prisma validate;聚焦 reimbursement expense-standards、创建/编辑路由、seed defaults 与既有 migration 测试,确认无批准依据可通过且 B2 金额/关联门禁不回退。 +- 前端:typecheck、build、r111 聚焦 Playwright;同时覆盖 PC/移动编辑态和展示态的字段消失、保存可用与新提示文案。 +- 数据与部署:确认无新增 migration、pre/post pending=none、init/seed exit 0、三个 description 正确、B2 仍 global on、合成 assets 草稿通过且 0017 未被当作 smoke。 +- 治理:task validate、Trellis governance、process contract、docs registry、敏感信息扫描和 `git diff --check`。 diff --git a/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/task.json b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/task.json new file mode 100644 index 00000000..24c7c185 --- /dev/null +++ b/.trellis/tasks/08-30-reimbursement-assets-prior-approval-correction/task.json @@ -0,0 +1,26 @@ +{ + "id": "reimbursement-assets-prior-approval-correction", + "name": "reimbursement-assets-prior-approval-correction", + "title": "取消报销资产事前批准强制", + "description": "纠正不存在的 assets 事前审批制度:取消报销明细强制批准依据,隐藏无用途 UI,保留兼容字段与历史数据,并把资产类型说明改为登记导向。", + "status": "in_progress", + "dev_type": null, + "scope": "assets reimbursement validation; PC/mobile item editing; expense-type seed descriptions; reimbursement product/spec contracts", + "package": null, + "priority": "P0", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-08-30", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": "08-29-reimbursement-expense-policy-invoice-guard", + "relatedFiles": [], + "notes": "生产 0f9f403 已上线 B1/B2;0016 非 assets 可并行作为真人 canary,0017 为家具采购,必须等待本纠偏上线后再退回。无 migration、无 flag 或生产账号写入。", + "meta": {} +} \ No newline at end of file diff --git a/client/src/pages/MobileReimbursementDetailPage.tsx b/client/src/pages/MobileReimbursementDetailPage.tsx index 1e473b22..3ba5ce9b 100644 --- a/client/src/pages/MobileReimbursementDetailPage.tsx +++ b/client/src/pages/MobileReimbursementDetailPage.tsx @@ -89,7 +89,6 @@ type ItemFormState = { expenseDate: string; amount: string; description: string; - assetPriorApprovalBasis: string; }; type SelectedInvoiceMap = Record; @@ -331,7 +330,6 @@ export function MobileReimbursementDetailPage() { expenseDate: detail?.reimbursementDate ?? todayDate(), amount: "", description: "", - assetPriorApprovalBasis: "", }); setItemError(""); }; @@ -344,7 +342,6 @@ export function MobileReimbursementDetailPage() { expenseDate: item.expenseDate ?? detail?.reimbursementDate ?? todayDate(), amount: item.amount, description: item.description ?? "", - assetPriorApprovalBasis: item.assetPriorApprovalBasis ?? "", }); setItemError(""); }; @@ -360,7 +357,6 @@ export function MobileReimbursementDetailPage() { expenseDate: form.expenseDate, amount: form.amount, description: form.description.trim() || undefined, - assetPriorApprovalBasis: form.assetPriorApprovalBasis.trim() || null, }; if (form.mode === "edit" && form.itemId) { @@ -1093,29 +1089,17 @@ export function MobileReimbursementDetailPage() { onChange={(event) => setItemForm((current) => current ? { ...current, description: event.target.value } : current)} /> - {expenseTypes.find((type) => type.id === itemForm.expenseTypeId)?.category === "assets" ? ( -