fix: 制单备注仅保留报销编号(09-04-reimbursement-state-gap-finance-view)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-11 23:54:53 +08:00
父节点 98eabdde7f
当前提交 1eeda7cd92
共修改 6 个文件,包含 35 行新增和 11 行删除
@@ -1,5 +1,19 @@
# 报销状态空隙与财务处理视角:实施计划
## 2026-09-11 备注精简增量(本地验证完成,已获提交授权)
用户随后明确同意复核、提交这六个文件并准备发布。本轮仅提交这一增量,不推送、不连接生产、不部署;实际提交标识以Git记录及本地发布准备回执为准。下文“未提交”描述的是本地验证结束时的历史阶段,不是提交完成后的状态。
基于已发布98eabdde的干净独立副本实施;不改旧冻结证据包或发布克隆。将备注映射改为entityCode,姓名仍保留在收款户名列并继续必填;付款模板合同同步09-08既有任务。
- [x] 备注仅完整编号;同人同账号多张单保持多行、各自金额及客户流水号。
- [x] 回归制单逐列BIFF8读回、长姓名不影响备注、缺失姓名/编号整批拒绝及付款路由/就绪门。
- [x] 主会话检查diff与治理,记录实际结果;不自动提交/推送/部署,不重跑真实付款。
先改测试,在旧实现15项中3项按预期失败;修改一行运行时后,server下使用既有BIFF8解释器运行 `npm test -- tests/unit/services/paymentOrderXls.test.js tests/unit/documentSequence.service.test.js tests/unit/routes/paymentBatches.reimbursement.test.js tests/unit/services/paymentBatchReadiness.test.js`,4文件121/121通过,退出0。两处node --check、Trellis治理、process-contract baseline和git diff --check通过。实际生成BIFF8并读回表头/列宽/15列/账号文字类型/用途/备注/金额;无前端变更,未重跑浏览器。
主会话只读复查确认权限、审批、下载审计、编号生成与排序不变;不是独立复核。新版规则已同步09-08 PRD及模板映射设计,不在通用spec重复业务规则。短备注降低长度风险,但仍不宣称已核实银行上限或实际导入通过。当前仅本地完成,未提交、推送或部署;旧98eabdde复核不覆盖本增量。下一步按此六文件差异复核并在明确授权后提交,再准备发布预检。
## 本轮复核输入与提交准备(未提交)
用户批准整理两笔独立改动的复核/提交方案。基线均为5d8cdf12;01为制单备注5文件,02为UI布局11文件,路径无重叠。仅生成补丁、摘要清单并用临时索引验证顺序合并,不改变实际HEAD/index,不创建commit,不推送或部署。复核入口位于layout副本的artifacts/qa-layout/review-preparation/README.md;临时合并树不是发布候选commit。既有验证按输入不变复用,本轮不新增测试通过计数;UI补跑外层143、网银导入未验证、未独立复核等边界保留。提交前须核对冻结摘要,发布前还需验证合并后的实际候选,不能把单包测试冒充集成验收。
@@ -2,6 +2,10 @@
## Goal
### 2026-09-11 最新确认:制单备注只保留报销编号
用户批准用途为“报销款”、备注仅完整报销编号;一张报销单对应一行银行转账,同一付款批次允许多张单,同人同账号不合并。本次复用当前任务承接,付款模板事实同步09-08任务,不新建task。只修改备注映射及回归,不改编号、权限、审批或生产数据;提交、推送和部署另批。
### 2026-09-11 追加:侧栏等宽与票据紧凑展示(已批准)
用户同轮要求“查看完整账号”改为账号旁Eye图标,保留44px触控、title/aria-label及键盘入口;账号仍默认脱敏,权限/角色/状态条件和填写原因、审计流程不变,不改为悬浮或点击即解密。
@@ -2,7 +2,7 @@
## 2026-09-11 已批准备注增量
仅修改buildPaymentOrderRows的备注列,使用已验证且已trim的payeeName和entityCode拼成“姓名报销款 单号”。payeeName来自组批冻结的snapshot_json.payee.name;路由将归属人的收款信息冻结为payee,生成器不另查现职员工/提交人。每个batch item保持一行,即使姓名/收款账号相同也不合并。姓名或单号为空沿现有blockers整批拒绝。
最新确认仅修改buildPaymentOrderRows的备注列,使用已验证且已trim的entityCode,不再拼接姓名和用途。收款户名列的payeeName仍来自组批冻结的snapshot_json.payee.name;路由将归属人的收款信息冻结为payee,生成器不另查现职员工/提交人。每个batch item保持一行,即使姓名/收款账号相同也不合并;一个批次仍允许多张报销单。姓名或单号为空沿现有blockers整批拒绝。
不改模板列宽/格式、不缩写或截断、不引入未经银行证明的长度阈值。测试使用合成姓名,逐列xlrd读回用途、备注及文字类型,并证明同名两单独立对应、旧序号不重排。BX/PB编号规则本轮不改;编号说明以PRD最新节为准,不将日期前缀误当每日重置的证据。
@@ -24,7 +24,7 @@
| 9 | 客户方流水号 | 批次号+行号,稳定、唯一并满足长度限制 |
| 10 | 金额 | 已批准批次项金额,数值且两位小数 |
| 11 | 用途 | 报销款,不复制工资/公积金用途 |
| 12 | 备注 | 冻结收款人姓名+“报销款 ”+完整报销单号(09-11已批准增量) |
| 12 | 备注 | 仅完整报销单号,不重复姓名或用途(09-11最新确认) |
| 13–15 | 短信标志/手机/附加信息 | 0、不通知,后两列空;不读样例手机号 |
用户三个 input 文档的表头完全一致,空白模板与内置模板相同,账号列为文本。检查原件只提取结构与摘要,原件不改、不重新保存、不复制真实行到测试夹具。工资及公积金样例仅用于确定文件格式,不暗中扩为新业务。
@@ -2,9 +2,9 @@
## Goal
### 2026-09-11 制单备注与编号解释(已批准规划实施,未部署)
### 2026-09-11 制单备注与编号解释(最新精简方案已批准,增量未部署)
- 用途继续为“报销款”;每行备注为冻结收款快照姓名+“报销款 ”+该行完整报销编号,例如“合成收款人报销款 BX-20260828-0014”。不从提交人、当前员工资料或固定真人姓名取值。
- 最新确认覆盖此前姓名拼接方案:用途继续为“报销款”;每行备注仅该行完整报销编号,例如“BX-20260828-0014”。收款人姓名仍单独来自冻结快照,不在备注重复。增量实施与验证记录归当前09-04任务,不另建task。
- 现有一单一行保持,不按收款人合并转账;同一批次同一收款人的多张单仍逐行对应完整编号。缺少姓名或单号继续整批拒绝,不猜测、不截断。
- 保留BIFF8模板、15列、用途、金额、账号文本、客户流水号、排序、权限/复核/审计与下载行为;不修改历史文件、历史单号、计数器或生产配置,不新增迁移。
- 编号只标识创建顺序,不表示此前单据已经报销/付款。BX当前生成器优先既有序列配置,回退resetPeriod=none;PB按日三位流水,从001起。不能把讨论中的“若按日则0001起”直接改成重置生产BX或将PB扩位;周期变化另行确认。本轮仅解释并保留现状,生产具体BX序列配置未查询。
+1 -1
查看文件
@@ -156,7 +156,7 @@ function buildPaymentOrderRows(config, batch) {
serial,
Number(amount.toFixed(2)),
"报销款",
`${payeeName}报销款 ${entityCode}`,
entityCode,
"0",
"",
"",
@@ -43,18 +43,22 @@ function buildBatch(overrides = {}) {
}
describe("payment order BIFF8 generator", () => {
it("uses frozen payee names and keeps separate rows for the same payee", () => {
it("keeps document-only remarks and separate transfers for the same frozen payee account", () => {
const batch = buildBatch();
for (const item of batch.items) {
item.snapshot_json.payee.name = " 合成收款人 ";
item.snapshot_json.payee.bankAccountEncrypted = batch.items[0].snapshot_json.payee.bankAccountEncrypted;
item.snapshot_json.submitter = { name: "合成提交人" };
item.owner = { name: "已改名归属人" };
}
const result = buildPaymentOrderRows(config, batch);
expect(result.rows.map((row) => row.slice(10, 12))).toEqual([
["报销款", "合成收款人报销款 BX-20260802-0001"],
["报销款", "合成收款人报销款 BX-20260802-0002"],
["报销款", "BX-20260802-0001"],
["报销款", "BX-20260802-0002"],
]);
expect(result.rows.map((row) => row[5])).toEqual(["合成收款人", "合成收款人"]);
expect(result.rows[0][4]).toBe(result.rows[1][4]);
expect(result.rows.map((row) => row[9])).toEqual([1.2, 2]);
expect(result.serials).toEqual(["PB-20260802-002-R001", "PB-20260802-002-R002"]);
expect(result.totalAmount).toBe("3.20");
});
@@ -66,7 +70,9 @@ describe("payment order BIFF8 generator", () => {
batch.items = [batch.items[0]];
batch.items[0].snapshot_json.payee.name = ` ${name} `;
batch.items[0].entity_code = ` ${code} `;
expect(buildPaymentOrderRows(config, batch).rows[0][11]).toBe(`${name}报销款 ${code}`);
const row = buildPaymentOrderRows(config, batch).rows[0];
expect(row[5]).toBe(name);
expect(row[11]).toBe(code);
});
it.each([
@@ -120,10 +126,10 @@ describe("payment order BIFF8 generator", () => {
expect(parsed.rows).toHaveLength(2);
expect(parsed.rows[0]).toEqual([
"1", payerAccount, "合成测试公司", "01", payeeAccount, "甲", "中国建设银行", "",
"PB-20260802-002-R001", 1.2, "报销款", "甲报销款 BX-20260802-0001", "0", "", "",
"PB-20260802-002-R001", 1.2, "报销款", "BX-20260802-0001", "0", "", "",
]);
expect(parsed.rows[1][9]).toBe(2);
expect(parsed.rows[1].slice(10, 12)).toEqual(["报销款", "乙报销款 BX-20260802-0002"]);
expect(parsed.rows[1].slice(10, 12)).toEqual(["报销款", "BX-20260802-0002"]);
});
it("fails the whole export and reports every blocking payee issue", () => {