FINPROD ACCTH 启用付款批次并收口代账交接

这个提交包含在:
2026-05-17 12:01:53 +08:00
父节点 426a96816a
当前提交 a3a4a861c7
共修改 8 个文件,包含 395 行新增和 20 行删除
@@ -95,6 +95,7 @@ const baseUrl = process.env.LIVE_SMOKE_BASE_URL?.trim() || "https://oa.hyinda.co
const reportDir = process.env.P2_FIN_LIVE_REPORT_DIR?.trim() || const reportDir = process.env.P2_FIN_LIVE_REPORT_DIR?.trim() ||
path.resolve(process.cwd(), "..", "artifacts/qa-flow/p2-fin-live-local"); path.resolve(process.cwd(), "..", "artifacts/qa-flow/p2-fin-live-local");
const summaryPath = path.join(reportDir, "live-result.json"); const summaryPath = path.join(reportDir, "live-result.json");
const finalFlagState = process.env.P2_FIN_LIVE_FINAL_STATE?.trim() === "force_on" ? "force_on" : "force_off";
function nowMarker() { function nowMarker() {
return `${markerPrefix}-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`; return `${markerPrefix}-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
@@ -363,11 +364,11 @@ async function expectAuditAction(
.toBe(true); .toBe(true);
} }
test.describe("P2-FIN-LIVE 公网付款批次短窗口", () => { test.describe("公网付款批次受控验收", () => {
test.skip(process.env.E2E_MODE !== "live", "仅在 live 模式下执行"); test.skip(process.env.E2E_MODE !== "live", "仅在 live 模式下执行");
test.describe.configure({ mode: "serial" }); test.describe.configure({ mode: "serial" });
test("公网付款批次 flag-on 闭环后强制回滚到 flag-off", async ({}, testInfo) => { test("公网付款批次 flag-on 闭环后按 final mode 收口", async ({}, testInfo) => {
test.setTimeout(420_000); test.setTimeout(420_000);
if (process.env.P2_FIN_LIVE_APPROVED !== "1") { if (process.env.P2_FIN_LIVE_APPROVED !== "1") {
throw new Error("P2_FIN_LIVE_APPROVED=1 is required for public write test"); throw new Error("P2_FIN_LIVE_APPROVED=1 is required for public write test");
@@ -377,12 +378,14 @@ test.describe("P2-FIN-LIVE 公网付款批次短窗口", () => {
const marker = nowMarker(); const marker = nowMarker();
const summary: LiveSummary = { const summary: LiveSummary = {
issueId, issueId,
mode: "p2-fin-live", mode: finalFlagState === "force_on" ? "fin-prod-enable" : "p2-fin-live",
status: "RUNNING", status: "RUNNING",
baseUrl, baseUrl,
marker, marker,
startedAt: new Date().toISOString(), startedAt: new Date().toISOString(),
stages: {}, stages: {
finalFlagState,
},
}; };
const clients: AuthenticatedApiClient[] = []; const clients: AuthenticatedApiClient[] = [];
@@ -543,13 +546,29 @@ test.describe("P2-FIN-LIVE 公网付款批次短窗口", () => {
} finally { } finally {
if (admin) { if (admin) {
try { try {
const rolledBack = await forcePaymentBatchOff(admin.api, `${issueId} rollback ${marker}`); if (finalFlagState === "force_on" && !caughtError) {
summary.stages.rollback = { paymentFlagAfterRollback: snapshotFlag(rolledBack) }; const paymentFlag = await loadFlag(admin.api, "payment_batch_v1");
expect(rolledBack.effectiveEnabled).toBe(false); const finalPaymentFlag =
paymentFlag.overrideMode === "force_on" && paymentFlag.effectiveEnabled
? paymentFlag
: await updateFlag(admin.api, "payment_batch_v1", "force_on", `${issueId} keep force_on ${marker}`);
const finalErpFlag = await loadFlag(admin.api, "erp_sync");
summary.stages.finalState = {
paymentFlag: snapshotFlag(finalPaymentFlag),
erpSyncEffectiveEnabled: finalErpFlag.effectiveEnabled,
};
expect(finalPaymentFlag.effectiveEnabled).toBe(true);
expect(finalPaymentFlag.overrideMode).toBe("force_on");
expect(finalErpFlag.effectiveEnabled).toBe(false);
} else {
const rolledBack = await forcePaymentBatchOff(admin.api, `${issueId} rollback ${marker}`);
summary.stages.rollback = { paymentFlagAfterRollback: snapshotFlag(rolledBack) };
expect(rolledBack.effectiveEnabled).toBe(false);
}
} catch (error) { } catch (error) {
rollbackError = error; rollbackError = error;
summary.status = "FAIL"; summary.status = "FAIL";
summary.stages.rollback = { error: sanitizeError(error) }; summary.stages.finalState = { error: sanitizeError(error) };
} }
} }
+6
查看文件
@@ -29,6 +29,8 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
- 2026-05-17 PRELAUNCH 已按“系统尚未正式使用”的新前提完成正式启用前公网预回归:公网 `/ready`、public bundle、live smoke、PDF live OCR、远端 Caddy/compose/migration 只读基线、隔离核心业务流、付款批次公网 PRELAUNCH 窗口、公网移动矩阵和企业微信 UA/渲染矩阵均形成证据;公网测试数据均带 `PRELAUNCH` marker。最终 `payment_batch_v1=flag_force_off`,未部署、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR。浏览器全链路 `all` 中报销 PDF 因样票重复记可解释 `SKIP`,采购分流程功能报告通过但手工 live spec 存在长等待/退出码稳定性缺口,后续作为 QA 自动化维护项。 - 2026-05-17 PRELAUNCH 已按“系统尚未正式使用”的新前提完成正式启用前公网预回归:公网 `/ready`、public bundle、live smoke、PDF live OCR、远端 Caddy/compose/migration 只读基线、隔离核心业务流、付款批次公网 PRELAUNCH 窗口、公网移动矩阵和企业微信 UA/渲染矩阵均形成证据;公网测试数据均带 `PRELAUNCH` marker。最终 `payment_batch_v1=flag_force_off`,未部署、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR。浏览器全链路 `all` 中报销 PDF 因样票重复记可解释 `SKIP`,采购分流程功能报告通过但手工 live spec 存在长等待/退出码稳定性缺口,后续作为 QA 自动化维护项。
- 2026-05-17 CASHIER-VOUCHER-V1 已按“无 ERP/独立财务系统、只有代账”的新业务前提完成正式启用前财务闭环补强:新增付款批次银行回单附件、复核后补凭证、银行渠道执行前回单阻断和 PC 付款批次详情操作区;业务口径为 `wangzhiling` 出纳执行、`wangshunli` 管理员复核,后续正式流程是 OA 内审批/台账/付款批次 + 银行对公付款回单 + 月度代账交接。CASHV 代码已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网,不接真实支付、不写 ERP、不开放图片 OCR、不导入银行流水;下一步需另建或延续 `FIN-PROD-ENABLE` 和 `ACCOUNTING-HANDOFF-V1` 合同。 - 2026-05-17 CASHIER-VOUCHER-V1 已按“无 ERP/独立财务系统、只有代账”的新业务前提完成正式启用前财务闭环补强:新增付款批次银行回单附件、复核后补凭证、银行渠道执行前回单阻断和 PC 付款批次详情操作区;业务口径为 `wangzhiling` 出纳执行、`wangshunli` 管理员复核,后续正式流程是 OA 内审批/台账/付款批次 + 银行对公付款回单 + 月度代账交接。CASHV 代码已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网,不接真实支付、不写 ERP、不开放图片 OCR、不导入银行流水;下一步需另建或延续 `FIN-PROD-ENABLE` 和 `ACCOUNTING-HANDOFF-V1` 合同。
- 2026-05-17 LAUNCH-DEPLOY-FINANCE 已按用户要求完成“本地全流程/页面门禁 -> 部署 -> 公网复检”:本地基础代码门禁、业务流、PC/移动/企业微信页面矩阵均通过;部署 commit `ab5ab4d` 到 `https://oa.hyinda.com`,`SYNC_ENV=0` 未覆盖远端 env,新增回单附件 migration 已应用;公网 readiness、PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口均通过。CASHV 公网测试报销 `BX-20260517-0025` 完成无回单执行阻断、上传/下载回单、付款执行、AP 导出和审计核验;最终 `payment_batch_v1=flag_force_off`,正式常开仍需 `FIN-PROD-ENABLE`。 - 2026-05-17 LAUNCH-DEPLOY-FINANCE 已按用户要求完成“本地全流程/页面门禁 -> 部署 -> 公网复检”:本地基础代码门禁、业务流、PC/移动/企业微信页面矩阵均通过;部署 commit `ab5ab4d` 到 `https://oa.hyinda.com`,`SYNC_ENV=0` 未覆盖远端 env,新增回单附件 migration 已应用;公网 readiness、PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口均通过。CASHV 公网测试报销 `BX-20260517-0025` 完成无回单执行阻断、上传/下载回单、付款执行、AP 导出和审计核验;最终 `payment_batch_v1=flag_force_off`,正式常开仍需 `FIN-PROD-ENABLE`。
- 2026-05-17 FIN-PROD-ENABLE 已完成公网付款批次正式常开:未重新部署业务代码;新增 QA-only 正式启用 runner 后,公网测试报销 `BX-20260517-0026` 完成审批、付款批次创建/复核、无回单执行阻断、回单上传/下载、付款执行、报销 `paid`、票据 `archived`、AP 台账 `paid`、AP 导出和审计核验;公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed。最终 `payment_batch_v1=force_on`,`erp_sync=force_off`;不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水。
- 2026-05-17 ACCOUNTING-HANDOFF-V1 已固化月度代账交接 SOP:OA 侧导出 AP 台账、报销、票据中心、付款批次/回单附件清单和审计日志;银行流水和银行回单原件由 `wangzhiling` 从银行渠道导出,交给代账人工核对。公网只读/导出核对显示付款批次清单、回单附件列表/下载、AP 导出、报销导出、票据导出和审计日志导出均返回 200;不开发银行流水导入或一键 zip 包。
## 关键证据索引 ## 关键证据索引
@@ -65,6 +67,8 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
| PRELAUNCH | 已收口:正式启用前公网预回归完成;公网 readiness/PDF live OCR、远端只读基线、隔离核心业务流、PRELAUNCH 付款批次窗口、公网移动和企业微信渲染矩阵通过;最终 `payment_batch_v1=flag_force_off` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv`、`artifacts/qa-flow/p2-fin-live-20260517-014144/live-result.json`、`artifacts/qa-flow/p2-safe-regression-20260517-014436/summary.json`、`artifacts/prelaunch/browser-business/report.md`、`artifacts/prelaunch/browser-business-purchase-rerun/report.md` | | PRELAUNCH | 已收口:正式启用前公网预回归完成;公网 readiness/PDF live OCR、远端只读基线、隔离核心业务流、PRELAUNCH 付款批次窗口、公网移动和企业微信渲染矩阵通过;最终 `payment_batch_v1=flag_force_off` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv`、`artifacts/qa-flow/p2-fin-live-20260517-014144/live-result.json`、`artifacts/qa-flow/p2-safe-regression-20260517-014436/summary.json`、`artifacts/prelaunch/browser-business/report.md`、`artifacts/prelaunch/browser-business-purchase-rerun/report.md` |
| CASHIER-VOUCHER-V1 | 已收口:正式启用前财务闭环与银行回单附件完成;后端 focused 回归 12 tests passed,前端 typecheck/build 通过,本地隔离 reimbursement 业务域 10 passed/1 skipped,governance 业务域 9 passed;已由 LDF 部署 | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv`、`artifacts/qa-flow/business-flow-20260517-091904/summary.txt`、`artifacts/qa-flow/business-flow-20260517-092824/summary.txt` | | CASHIER-VOUCHER-V1 | 已收口:正式启用前财务闭环与银行回单附件完成;后端 focused 回归 12 tests passed,前端 typecheck/build 通过,本地隔离 reimbursement 业务域 10 passed/1 skipped,governance 业务域 9 passed;已由 LDF 部署 | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv`、`artifacts/qa-flow/business-flow-20260517-091904/summary.txt`、`artifacts/qa-flow/business-flow-20260517-092824/summary.txt` |
| LAUNCH-DEPLOY-FINANCE | 已收口:CASHV 部署和公网复检完成;本地全流程/页面门禁通过,公网 readiness/PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口通过;最终 `payment_batch_v1=flag_force_off` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv`、`artifacts/qa-flow/business-flow-20260517-094407/summary.txt`、`artifacts/qa-flow/live-smoke-readiness-20260517-102904/summary.json`、`artifacts/qa-flow/p2-fin-live-20260517-103450/live-result.json` | | LAUNCH-DEPLOY-FINANCE | 已收口:CASHV 部署和公网复检完成;本地全流程/页面门禁通过,公网 readiness/PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口通过;最终 `payment_batch_v1=flag_force_off` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv`、`artifacts/qa-flow/business-flow-20260517-094407/summary.txt`、`artifacts/qa-flow/live-smoke-readiness-20260517-102904/summary.json`、`artifacts/qa-flow/p2-fin-live-20260517-103450/live-result.json` |
| FIN-PROD-ENABLE | 已收口:公网付款批次正式启用完成;测试报销 `BX-20260517-0026` 付款闭环到 paid,票据 archived,AP 台账 paid,导出和审计核验通过;公网移动矩阵 6 passed,企业微信渲染矩阵 8 passed;最终 `payment_batch_v1=force_on`、`erp_sync=force_off` | `issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv`、`artifacts/qa-flow/fin-prod-enable-20260517-114731/summary.json`、`artifacts/qa-flow/fin-prod-enable-20260517-114731/live-result.json` |
| ACCOUNTING-HANDOFF-V1 | 已收口:月度代账交接 SOP 固化;OA 侧 AP/报销/票据/付款批次/回单附件/审计资料清单可用,公网导出和回单下载状态核对 200;银行流水和回单原件由出纳线下导出给代账 | `issues/2026-05-17_11-40-48-accounting-handoff-v1.csv`、`docs/管理员手册.md` |
## 当前门禁 ## 当前门禁
@@ -91,6 +95,8 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
| PRELAUNCH 正式启用前预回归 | 通过,含 QA 稳定性观察项,未部署 | 公网 live readiness PASS,远端 Caddy active、compose db/server Up、Prisma migration up to date;脱敏数据清点 activeEmployees=12、activeWecomBindings=5、pendingWorkflowTasks=7;`run-p2-fin-live-window.sh` PRELAUNCH PASS,测试报销 `BX-20260517-0024` 付款闭环 paid、票据 archived、AP 台账 paid;`run-p2-safe-regression.sh` PASS。浏览器 `all` 长链路中 PDF 样票重复和采购超时按证据分流:采购分流程报告 PASS,本地隔离 procurement PASS,记录为手工 live spec 稳定性维护项,不作为业务 P0/P1 阻断。 | | PRELAUNCH 正式启用前预回归 | 通过,含 QA 稳定性观察项,未部署 | 公网 live readiness PASS,远端 Caddy active、compose db/server Up、Prisma migration up to date;脱敏数据清点 activeEmployees=12、activeWecomBindings=5、pendingWorkflowTasks=7;`run-p2-fin-live-window.sh` PRELAUNCH PASS,测试报销 `BX-20260517-0024` 付款闭环 paid、票据 archived、AP 台账 paid;`run-p2-safe-regression.sh` PASS。浏览器 `all` 长链路中 PDF 样票重复和采购超时按证据分流:采购分流程报告 PASS,本地隔离 procurement PASS,记录为手工 live spec 稳定性维护项,不作为业务 P0/P1 阻断。 |
| CASHIER-VOUCHER-V1 财务闭环与银行回单附件 | 通过,已部署 | 新增付款批次回单附件模型/API/PC 操作区,银行渠道执行付款前必须上传回单,复核后仍可补凭证号/付款日期/付款渠道;`prisma validate`、`node --check`、后端 focused 单测、前端 typecheck/build、隔离 reimbursement 业务流和 governance 权限直连业务流均通过;已由 LDF 部署并完成公网 CASHV 短窗口复检。正式启用前仍需设置 `payment_batch_v1=force_on` 并完成代账交接 SOP。 | | CASHIER-VOUCHER-V1 财务闭环与银行回单附件 | 通过,已部署 | 新增付款批次回单附件模型/API/PC 操作区,银行渠道执行付款前必须上传回单,复核后仍可补凭证号/付款日期/付款渠道;`prisma validate`、`node --check`、后端 focused 单测、前端 typecheck/build、隔离 reimbursement 业务流和 governance 权限直连业务流均通过;已由 LDF 部署并完成公网 CASHV 短窗口复检。正式启用前仍需设置 `payment_batch_v1=force_on` 并完成代账交接 SOP。 |
| LAUNCH-DEPLOY-FINANCE 部署与公网复检 | 通过,最终关闭付款批次 | 本地业务流 auth/reimbursement/approval/leave/procurement/governance 通过,本地 PC/移动/企业微信矩阵通过;部署 commit `ab5ab4d`,`SYNC_ENV=0`,新增 migration `20260517090437_cashier_payment_receipts` 已应用,公网 readiness/PDF live OCR 通过,公网移动/企微矩阵通过;CASHV 短窗口验证无回单执行 409、回单上传/下载、付款 executed、报销 paid、票据 archived、AP 台账 paid、AP 导出 200 和审计可查;最终 `payment_batch_v1=flag_force_off`。 | | LAUNCH-DEPLOY-FINANCE 部署与公网复检 | 通过,最终关闭付款批次 | 本地业务流 auth/reimbursement/approval/leave/procurement/governance 通过,本地 PC/移动/企业微信矩阵通过;部署 commit `ab5ab4d`,`SYNC_ENV=0`,新增 migration `20260517090437_cashier_payment_receipts` 已应用,公网 readiness/PDF live OCR 通过,公网移动/企微矩阵通过;CASHV 短窗口验证无回单执行 409、回单上传/下载、付款 executed、报销 paid、票据 archived、AP 台账 paid、AP 导出 200 和审计可查;最终 `payment_batch_v1=flag_force_off`。 |
| FIN-PROD-ENABLE 付款批次正式常开 | 通过,未重新部署,最终开启付款批次 | 新增 QA-only `run-fin-prod-enable-window.sh` 和 Playwright force-on 模式;`client` typecheck/build 通过;公网 pre flag-off PASS 后完成 FINPROD 付款闭环,`BX-20260517-0026` paid、票据 archived、AP 台账 paid、无回单执行 409、回单下载 200、AP 导出 200、关键审计可查;公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed;最终 `payment_batch_v1=force_on`、`erp_sync=force_off`。 |
| ACCOUNTING-HANDOFF-V1 代账交接 | 通过,无需开发一键包 | 现有能力核对:付款批次清单 200,回单附件列表 200,回单下载 200,AP 导出 200,报销导出 200,票据中心导出 200,审计日志导出 200;`docs/管理员手册.md` 已补月度交接 SOP。AP 台账不是银行流水,银行流水和回单原件由出纳从银行侧导出,不导入 OA。 |
## R7EP / OPS8 / QAF8 / UX8 / P2T 预检推进 ## R7EP / OPS8 / QAF8 / UX8 / P2T 预检推进
+5 -3
查看文件
@@ -50,6 +50,8 @@
| `PRELAUNCH` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv` | `EVIDENCE` | 正式启用前公网预回归已收口;公网 readiness、远端只读基线、隔离核心业务流、付款批次 PRELAUNCH 窗口、移动/企业微信矩阵和 Go/No-Go 摘要完成;最终 `payment_batch_v1=flag_force_off`,未部署 | | `PRELAUNCH` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv` | `EVIDENCE` | 正式启用前公网预回归已收口;公网 readiness、远端只读基线、隔离核心业务流、付款批次 PRELAUNCH 窗口、移动/企业微信矩阵和 Go/No-Go 摘要完成;最终 `payment_batch_v1=flag_force_off`,未部署 |
| `CASHIER-VOUCHER-V1` | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv` | `EVIDENCE` | 正式启用前财务闭环与银行回单附件已收口;新增付款批次银行回单附件、复核后补凭证和银行渠道执行前回单阻断;已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网 | | `CASHIER-VOUCHER-V1` | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv` | `EVIDENCE` | 正式启用前财务闭环与银行回单附件已收口;新增付款批次银行回单附件、复核后补凭证和银行渠道执行前回单阻断;已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网 |
| `LAUNCH-DEPLOY-FINANCE` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv` | `EVIDENCE` | CASHV 部署与公网复检已收口;本地全流程/页面门禁、受控部署、migration 应用、公网 readiness、PDF live OCR、移动/企微矩阵和 CASHV 短窗口均通过;最终 `payment_batch_v1=flag_force_off` | | `LAUNCH-DEPLOY-FINANCE` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv` | `EVIDENCE` | CASHV 部署与公网复检已收口;本地全流程/页面门禁、受控部署、migration 应用、公网 readiness、PDF live OCR、移动/企微矩阵和 CASHV 短窗口均通过;最终 `payment_batch_v1=flag_force_off` |
| `FIN-PROD-ENABLE` | `issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv` | `EVIDENCE` | 公网付款批次正式常开已收口;测试报销 `BX-20260517-0026` 完成付款闭环、AP 导出、审计和移动/企微矩阵,最终 `payment_batch_v1=force_on`、`erp_sync=force_off` |
| `ACCOUNTING-HANDOFF-V1` | `issues/2026-05-17_11-40-48-accounting-handoff-v1.csv` | `EVIDENCE` | 月度代账交接 SOP 已收口;OA 侧导出和回单附件清单可用,银行流水和回单原件由出纳从银行侧导出,不导入 OA |
旧 Issue CSV 保留为历史审计证据:不删除、不批量回写、不移动到 `docs/archive/` 或其他归档目录。新连续合同如替代旧合同,只在新合同 `Notes` 或文档索引中说明 supersedes。 旧 Issue CSV 保留为历史审计证据:不删除、不批量回写、不移动到 `docs/archive/` 或其他归档目录。新连续合同如替代旧合同,只在新合同 `Notes` 或文档索引中说明 supersedes。
@@ -57,8 +59,8 @@
| Doc_ID | Path | Category | Authority | Status | Owner | Related_Issues | Evidence | Supersedes | Last_Audited | Audit_Method | Risk | Notes | | Doc_ID | Path | Category | Authority | Status | Owner | Related_Issues | Evidence | Supersedes | Last_Audited | Audit_Method | Risk | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE` | `rg` | none | 2026-05-17 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 | | `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1` | `rg` | none | 2026-05-17 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 |
| `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE` | `audit-docs` | none | 2026-05-17 | `audit-docs --check-registry` | medium | 判断文档权威性 | | `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1` | `audit-docs` | none | 2026-05-17 | `audit-docs --check-registry` | medium | 判断文档权威性 |
| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8` | Issue CSV | `docs/requirements-specification.md` | 2026-05-13 | `rg` | high | 定义做什么、不做什么和验收口径 | | `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8` | Issue CSV | `docs/requirements-specification.md` | 2026-05-13 | `rg` | high | 定义做什么、不做什么和验收口径 |
| `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T` | `rg` | none | 2026-05-13 | `rg` | high | 记录已拍板产品边界 | | `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T` | `rg` | none | 2026-05-13 | `rg` | high | 记录已拍板产品边界 |
| `DESIGN-UI` | `docs/产品设计规则.md` | 设计事实源 | PC/移动/企业微信设计事实源 | `CURRENT` | design/frontend | `MIA7,MIF7,GOV8,DG8,DG9` | Playwright/视觉审查/DG8/DG9 | none | 2026-05-13 | `rg` | high | 页面改动必须读取;DG8 后飞书为主 UI/布局参考;DG9 后按页面分层和样板选型 | | `DESIGN-UI` | `docs/产品设计规则.md` | 设计事实源 | PC/移动/企业微信设计事实源 | `CURRENT` | design/frontend | `MIA7,MIF7,GOV8,DG8,DG9` | Playwright/视觉审查/DG8/DG9 | none | 2026-05-13 | `rg` | high | 页面改动必须读取;DG8 后飞书为主 UI/布局参考;DG9 后按页面分层和样板选型 |
@@ -163,4 +165,4 @@
- `ME6-3` 代表性企业微信真机门禁已关闭。 - `ME6-3` 代表性企业微信真机门禁已关闭。
- MIF7-1..7 与 MIF7T 已完成本地整改、公网部署、公网匿名复检和带凭据 live smoke/OCR 复检。 - MIF7-1..7 与 MIF7T 已完成本地整改、公网部署、公网匿名复检和带凭据 live smoke/OCR 复检。
- R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件以及 LAUNCH-DEPLOY-FINANCE 部署复检均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同;P2-FIN-LIVE、PRELAUNCH 和 LDF 均验证付款批次公网短窗口并回到 `payment_batch_v1=flag_force_off`;后续正式常开付款批次和代账交接 SOP 必须另建或延续对应连续合同。 - R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件、LAUNCH-DEPLOY-FINANCE 部署复检、FIN-PROD-ENABLE 正式常开和 ACCOUNTING-HANDOFF-V1 代账交接 SOP 均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同;当前公网 `payment_batch_v1=force_on`,`erp_sync=force_off`,正式支付接口、ERP、图片 OCR 和银行流水导入继续冻结。
+5 -1
查看文件
@@ -20,7 +20,7 @@
## 最近事实源链 ## 最近事实源链
R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE。 R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE -> FIN-PROD-ENABLE -> ACCOUNTING-HANDOFF-V1。
- R6、PC6、PA6、FL6、AP6、RI6、LP6 已完成并部署。 - R6、PC6、PA6、FL6、AP6、RI6、LP6 已完成并部署。
- ME6 自动化、公网视觉矩阵和 `ME6-3` 代表性企业微信真机门禁已完成。 - ME6 自动化、公网视觉矩阵和 `ME6-3` 代表性企业微信真机门禁已完成。
@@ -44,6 +44,8 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
- PRELAUNCH 是未正式使用前的正式启用准备合同:公网作为准生产预启用环境承载带 `PRELAUNCH` marker 的测试数据和自动化回归;公网 readiness、远端只读基线、隔离核心业务流、付款批次 PRELAUNCH 窗口、移动/企业微信自动化和 Go/No-Go 摘要已完成。最终 `payment_batch_v1=flag_force_off`,未部署、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR;采购公网手工 live spec 长等待/退出码问题作为 QA 自动化稳定性维护项。 - PRELAUNCH 是未正式使用前的正式启用准备合同:公网作为准生产预启用环境承载带 `PRELAUNCH` marker 的测试数据和自动化回归;公网 readiness、远端只读基线、隔离核心业务流、付款批次 PRELAUNCH 窗口、移动/企业微信自动化和 Go/No-Go 摘要已完成。最终 `payment_batch_v1=flag_force_off`,未部署、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR;采购公网手工 live spec 长等待/退出码问题作为 QA 自动化稳定性维护项。
- CASHIER-VOUCHER-V1 是正式启用前财务闭环与代账交接第一轮实现合同:基于“无 ERP/独立财务系统、只有代账”的业务事实,将付款闭环固定为 OA 内审批/台账/付款批次 + 银行对公付款回单附件 + 月度代账交接;已新增批次级银行回单附件模型/API/PC 操作区、复核后补凭证和银行渠道执行前回单阻断,代码已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网,不接真实支付、不写 ERP、不开放图片 OCR、不导入银行流水。 - CASHIER-VOUCHER-V1 是正式启用前财务闭环与代账交接第一轮实现合同:基于“无 ERP/独立财务系统、只有代账”的业务事实,将付款闭环固定为 OA 内审批/台账/付款批次 + 银行对公付款回单附件 + 月度代账交接;已新增批次级银行回单附件模型/API/PC 操作区、复核后补凭证和银行渠道执行前回单阻断,代码已由 `LAUNCH-DEPLOY-FINANCE` 部署到公网,不接真实支付、不写 ERP、不开放图片 OCR、不导入银行流水。
- LAUNCH-DEPLOY-FINANCE 是 CASHIER-VOUCHER-V1 后的部署与公网复检合同:先完成本地基础门禁、业务流、PC/移动/企业微信页面矩阵,再以 `SYNC_ENV=0` 部署到 `https://oa.hyinda.com`;新增银行回单附件 migration 已应用,公网 readiness、PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口均通过,最终 `payment_batch_v1=flag_force_off`,正式常开仍需 `FIN-PROD-ENABLE`。 - LAUNCH-DEPLOY-FINANCE 是 CASHIER-VOUCHER-V1 后的部署与公网复检合同:先完成本地基础门禁、业务流、PC/移动/企业微信页面矩阵,再以 `SYNC_ENV=0` 部署到 `https://oa.hyinda.com`;新增银行回单附件 migration 已应用,公网 readiness、PDF live OCR、移动/企业微信矩阵和 CASHV 短窗口均通过,最终 `payment_batch_v1=flag_force_off`,正式常开仍需 `FIN-PROD-ENABLE`。
- FIN-PROD-ENABLE 是公网付款批次正式常开合同:未重新部署业务代码;新增 QA-only 正式启用 runner 后完成公网正式验收,测试报销 `BX-20260517-0026` 完成审批、付款批次创建/复核、无回单执行阻断、回单上传/下载、付款执行、AP 导出和审计核验;公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed;最终 `payment_batch_v1=force_on`,`erp_sync=force_off`。
- ACCOUNTING-HANDOFF-V1 是月度代账交接 SOP 合同:公司无 ERP/独立财务系统,OA 侧交接资料固定为 AP 台账、报销导出、票据中心导出、付款批次/回单附件清单和审计日志;银行侧流水和回单原件由出纳从银行渠道导出交给代账人工核对,不导入 OA,不开发一键 zip 包。
## 当前活跃治理流 ## 当前活跃治理流
@@ -74,6 +76,8 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
| `PRELAUNCH` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv` | 已收口:正式启用前公网预回归完成,最终 `payment_batch_v1=flag_force_off` | 公网环境基线、远端只读状态、PRELAUNCH 测试数据、核心业务自动化、付款批次公网窗口、移动/企业微信矩阵、启用范围和 Go/No-Go 摘要 | 不部署、不执行生产恢复、不重置数据库、不打印远端 env、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR | | `PRELAUNCH` | `issues/2026-05-17_00-46-49-prelaunch-production-readiness.csv` | 已收口:正式启用前公网预回归完成,最终 `payment_batch_v1=flag_force_off` | 公网环境基线、远端只读状态、PRELAUNCH 测试数据、核心业务自动化、付款批次公网窗口、移动/企业微信矩阵、启用范围和 Go/No-Go 摘要 | 不部署、不执行生产恢复、不重置数据库、不打印远端 env、不接真实支付、不写 ERP 实时凭证、不开放图片 OCR |
| `CASHIER-VOUCHER-V1` | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv` | 已收口:正式启用前财务闭环与银行回单附件完成,已由 LDF 部署 | 付款批次银行回单附件、复核后补凭证、银行渠道执行前回单阻断、管理员复核审计、出纳执行、代账交接前置 | 不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水 | | `CASHIER-VOUCHER-V1` | `issues/2026-05-17_09-04-37-cashier-payment-voucher-v1.csv` | 已收口:正式启用前财务闭环与银行回单附件完成,已由 LDF 部署 | 付款批次银行回单附件、复核后补凭证、银行渠道执行前回单阻断、管理员复核审计、出纳执行、代账交接前置 | 不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水 |
| `LAUNCH-DEPLOY-FINANCE` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv` | 已收口:CASHV 部署与公网复检完成,最终 `payment_batch_v1=flag_force_off` | 本地全流程/页面门禁、受控部署、migration 应用、公网 readiness、PDF live OCR、移动/企微矩阵、CASHV 公网短窗口 | 不正式常开付款批次、不接真实支付、不接 ERP、不开放图片 OCR、不重置数据库 | | `LAUNCH-DEPLOY-FINANCE` | `issues/2026-05-17_09-38-55-launch-deploy-finance.csv` | 已收口:CASHV 部署与公网复检完成,最终 `payment_batch_v1=flag_force_off` | 本地全流程/页面门禁、受控部署、migration 应用、公网 readiness、PDF live OCR、移动/企微矩阵、CASHV 公网短窗口 | 不正式常开付款批次、不接真实支付、不接 ERP、不开放图片 OCR、不重置数据库 |
| `FIN-PROD-ENABLE` | `issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv` | 已收口:公网付款批次正式启用完成,最终 `payment_batch_v1=force_on` | 公网正式启用 runner、测试报销 `BX-20260517-0026`、银行回单附件、AP 导出、审计、移动/企微矩阵、最终 flag-on 证据 | 不重新部署、不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水 |
| `ACCOUNTING-HANDOFF-V1` | `issues/2026-05-17_11-40-48-accounting-handoff-v1.csv` | 已收口:月度代账交接 SOP 固化 | OA 侧 AP/报销/票据/付款批次/回单附件/审计资料清单,银行侧流水和回单原件由出纳线下导出,代账人工核对 | 不开发银行流水导入、不开发一键 zip 包、不保存真实银行资料到仓库 |
旧 Issue CSV 不删除、不批量回写、不移动到归档目录。若新治理流替代旧合同,只在新 CSV 的 `Notes` 或本索引说明 supersedes,旧文件保留历史审计语义。 旧 Issue CSV 不删除、不批量回写、不移动到归档目录。若新治理流替代旧合同,只在新 CSV 的 `Notes` 或本索引说明 supersedes,旧文件保留历史审计语义。
+43 -8
查看文件
@@ -1,6 +1,6 @@
# hyb-oa 管理员手册(10 人以下团队版) # hyb-oa 管理员手册(10 人以下团队版)
**当前状态(2026-05-13 / DCL8)**:R6 已通过,PC6、PA6、FL6、AP6、RI6、LP6、ME6、QG6、DG7/MRF7、MIA7、MIF7/MIF7T 和 MIF7TD 已完成相应收口;`ME6-3` 代表性企业微信真机门禁已关闭。R7 未真实启动,R7/OPS7/DOC7 仍只是准备材料,不代表已启动或已上线;下一步先做 R7E 自动门禁和参与人/窗口确认。 **当前状态(2026-05-17 / FINPROD)**:R7E、PRELAUNCH、CASHIER-VOUCHER-V1 和 LAUNCH-DEPLOY-FINANCE 均已收口;银行回单附件能力已部署到公网。FIN-PROD-ENABLE 已完成公网正式启用验收,`payment_batch_v1=force_on`,`erp_sync=force_off`。公司当前无 ERP/独立财务系统,财务闭环以 OA 内审批、台账、付款批次、银行对公付款回单和月度代账交接为准。
## 1. 适用范围 ## 1. 适用范围
- 适用于 `small_team_internal` 工作区模式。 - 适用于 `small_team_internal` 工作区模式。
@@ -15,16 +15,16 @@
## 3. 首次上线最小配置 ## 3. 首次上线最小配置
1. 进入 `工作区设置`,确认产品模式为 `small_team_internal`。 1. 进入 `工作区设置`,确认产品模式为 `small_team_internal`。
2. 首批主路径优先保留:`Portal`、`审批待办`、`报销`、`票据/OCR`、`请假`、`项目`、`采购/费用`、`合同/附件`。 2. 首批主路径优先保留:`Portal`、`审批待办`、`报销`、`票据/OCR`、`请假`、`项目`、`采购/费用`、`合同/附件`。
3. `团队状态`、`周报`、`待办`、`公告`、`人员`、`资产` 可按真实试运行需要开启;`预算`、`支付批次`、`AP 运营`、`ERP`、`AI`、完整差旅能力默认作为管理员备用或历史能力,不作为当前 MVP 首批主线。 3. `团队状态`、`周报`、`待办`、`公告`、`人员`、`资产` 可按真实试运行需要开启;`支付批次` 和 `AP 运营` 已作为财务闭环正式能力面向出纳、财务和管理员开放,普通员工不显示该入口;`预算`、`ERP`、`AI`、完整差旅能力仍作为备用或历史能力。
4. 在 `用户管理` 中按推荐预设配置:老板 / 管理员 / 主管 / 员工。 4. 在 `用户管理` 中按推荐预设配置:老板 / 管理员 / 主管 / 员工。
- 正式审批组织口径:`majianyong` 配置为员工可见直属主管和 `manager`;`wangshunli` 配置为后台公司负责人 `ceo + admin`,不配置为普通 `manager`。 - 正式审批组织口径:`majianyong` 配置为员工可见直属主管和 `manager`;`wangshunli` 配置为后台公司负责人 `ceo + admin`,不配置为普通 `manager`。
- 普通员工和专用测试员工的直属主管配置为 `majianyong`;`majianyong` 的直属领导配置为 `wangshunli`。 - 普通员工和专用测试员工的直属主管配置为 `majianyong`;`majianyong` 的直属领导配置为 `wangshunli`。
- `admin` 只代表系统管理权限,不代表业务审批权;需要业务审批时必须配置 `manager`、`ceo`、`finance`、`hr` 等正式业务角色。 - `admin` 只代表系统管理权限,不代表业务审批权;需要业务审批时必须配置 `manager`、`ceo`、`finance`、`hr` 等正式业务角色。
- 缺直属主管、主管停用、主管链断裂或审批节点解析到申请人本人时,应先修正组织或审批规则,不要用管理员账号代批。 - 缺直属主管、主管停用、主管链断裂或审批节点解析到申请人本人时,应先修正组织或审批规则,不要用管理员账号代批。
5. 检查功能开关: 5. 检查功能开关:
- 建议开启:`portal_home_v1`、企业微信入口相关开关、报销/OCR、审批待办、请假和项目基础能力。 - 建议开启:`portal_home_v1`、企业微信入口相关开关、报销/OCR、审批待办、请假、项目基础能力和 `payment_batch_v1`。
- 按需开启:`announcements_v1`、`presence_board_v1`、`weekly_report_v1`、`employee_lifecycle_v1`、`todo_board_v1`、`global_search_v1`。 - 按需开启:`announcements_v1`、`presence_board_v1`、`weekly_report_v1`、`employee_lifecycle_v1`、`todo_board_v1`、`global_search_v1`。
- 建议保留备用:`payment_batch_v1`、`cutover_console_v1`、预算/AP/ERP/AI 相关开关。 - 建议保留备用:`cutover_console_v1`、预算、ERP、AI 和完整差旅相关开关。
### 3.1 ORG8 组织账号与角色边界 ### 3.1 ORG8 组织账号与角色边界
@@ -163,6 +163,38 @@ WHERE e.status = 'active'
ORDER BY e.employee_no; ORDER BY e.employee_no;
``` ```
### 3.2 正式财务闭环与代账交接
公司当前没有 ERP 或独立财务系统,OA 不生成 ERP 实时凭证,也不接真实支付接口。正式财务闭环如下:
1. 员工在 OA 提交报销,发票/OCR 正式入口保持 PDF-only,图片只作为普通附件。
2. 直属主管、财务或负责人按审批规则在 OA 内完成审批。
3. `wangzhiling` 作为出纳,在付款批次中创建待付款批次,按批次准备对公银行付款。
4. `wangshunli` 以管理员身份复核付款批次;管理员复核是当前明确业务选择,系统保留 maker-checker 和审计记录。
5. 出纳在 OA 外通过网银或银行渠道付款,然后在付款批次详情上传银行回单附件,补齐凭证号、付款日期和付款渠道。
6. 出纳执行 OA 已付款标记;系统将报销单置为 `paid`,票据归档为 `archived`,AP 台账变为已付款状态。
银行渠道付款必须至少有一份银行回单附件后才能在 OA 内执行付款标记。回单附件支持 PDF、JPG、PNG、WEBP,作为批次级付款证据保存;导出和报告中不复制回单原件内容。
月度代账交接按以下清单执行:
| 资料 | 来源 | 负责人 | 说明 |
| --- | --- | --- | --- |
| AP 台账导出 | OA `AP 运营` | 出纳/财务 | 用于核对已付款、待付款和异常项;AP 台账不是银行流水 |
| 报销导出 | OA 报销导出 | 出纳/财务 | 按月导出,必要时筛选已通过或已付款状态 |
| 票据中心导出 | OA 票据/OCR | 出纳/财务 | 用于核对 PDF 发票识别、绑定和归档状态 |
| 付款批次清单 | OA `付款批次` | 出纳/财务 | 记录批次、复核、执行和对应报销单 |
| 银行回单附件清单 | OA 付款批次详情 | 出纳 | 只交接清单和必要回单原件,不把真实回单提交到代码仓库 |
| 审计日志导出 | OA 审计日志 | 管理员 | 覆盖导出、付款批次创建、复核、回单上传和执行动作 |
| 银行流水和回单原件 | 网银或银行渠道 | 出纳 | 由出纳从银行侧导出,交给代账人工核对;不导入 OA |
交接建议:
- 每月固定一个交接目录或压缩包,由出纳线下维护,命名建议为 `YYYY-MM-海音达-代账交接`。
- OA 导出文件、银行流水、银行回单原件和异常说明分目录保存;仓库只记录流程和脱敏证据,不保存正式财务资料。
- 代账如发现金额、收款方、日期或票据状态不一致,先回查 OA 报销单、付款批次、银行回单和审计日志,再决定是否由出纳补充说明。
- 若代账方后续要求一键交接包,再另建开发合同,明确包内文件、权限、脱敏、审计和下载回滚规则。
## 4. 人员生命周期管理 ## 4. 人员生命周期管理
### 4.1 入职 ### 4.1 入职
1. 在 `人员管理` 创建员工账号。 1. 在 `人员管理` 创建员工账号。
@@ -205,20 +237,23 @@ ORDER BY e.employee_no;
## 8. 备用模块治理 ## 8. 备用模块治理
- 采购/费用、合同/附件和项目轻管理属于 P1 轻量能力,可在 P0 审批、报销/OCR、请假和企业微信入口稳定后逐步开放。 - 采购/费用、合同/附件和项目轻管理属于 P1 轻量能力,可在 P0 审批、报销/OCR、请假和企业微信入口稳定后逐步开放。
- 预算、支付批次、AP 运营、ERP、AI、完整差旅、资产深度管理等保留代码和历史数据,但不作为当前 MVP 首批主路径。 - 支付批次和 AP 运营已作为正式财务闭环开放给出纳、财务和管理员;普通员工仍不显示财务运营入口。
- 预算、ERP、AI、完整差旅、资产深度管理等保留代码和历史数据,但不作为当前 MVP 首批主路径。
- 若短期完全不用,保持管理员可见即可,不必删除。 - 若短期完全不用,保持管理员可见即可,不必删除。
- 只有出现真实场景时,再恢复到主导航或单独扩展。 - 只有出现真实场景时,再恢复到主导航或单独扩展。
## 9. 推荐上线顺序 ## 9. 推荐上线顺序
1. 先完成账号、角色、部门、企业微信自建应用入口和账号密码回退路径。 1. 先完成账号、角色、部门、企业微信自建应用入口和账号密码回退路径。
2. 再启用 `OA 统一审批中心 + 报销/发票/OCR/附件`,跑通提交、审批、退回、查重、付款和导出闭环。 2. 再启用 `OA 统一审批中心 + 报销/发票/OCR/附件`,跑通提交、审批、退回、查重、付款和导出闭环。
3. 同步启用 `请假/补卡/外出/加班`,明确企业微信打卡只是原始采集,正式考勤解释回到 OA 审批结果。 3. 同步启用付款批次、AP 台账和银行回单附件,付款动作仍由出纳在 OA 外通过银行渠道完成。
4. 在 P0 稳定后开放 P1:`采购/费用审批`、`合同/附件归档`、`项目轻管理`。 4. 同步启用 `请假/补卡/外出/加班`,明确企业微信打卡只是原始采集,正式考勤解释回到 OA 审批结果。
5. 最后按真实需要评估周报、团队状态、公告、人员生命周期、资产、预算、支付、ERP、AI 和完整差旅。 5. 在 P0 稳定后开放 P1:`采购/费用审批`、`合同/附件归档`、`项目轻管理`。
6. 最后按真实需要评估周报、团队状态、公告、人员生命周期、资产、预算、ERP、AI 和完整差旅。
## 10. 试点验收口径 ## 10. 试点验收口径
- 全员都能账号密码登录;已绑定员工能从企业微信 `海音达工作台` 进入移动工作台。 - 全员都能账号密码登录;已绑定员工能从企业微信 `海音达工作台` 进入移动工作台。
- 至少 1 笔报销完成:上传发票或附件 -> OCR/查重 -> 提交 -> OA 审批 -> 财务复核/付款标记 -> 导出。 - 至少 1 笔报销完成:上传发票或附件 -> OCR/查重 -> 提交 -> OA 审批 -> 财务复核/付款标记 -> 导出。
- 至少 1 个付款批次完成:出纳创建 -> 管理员复核 -> 出纳上传银行回单 -> 执行 OA 已付款标记 -> AP 台账和审计可查。
- 至少 1 条请假或补卡完成:员工提交 -> OA 审批 -> 团队状态或考勤解释口径不破坏。 - 至少 1 条请假或补卡完成:员工提交 -> OA 审批 -> 团队状态或考勤解释口径不破坏。
- 至少 1 个审批待办从企业微信提醒 deeplink 回到 OA 页面处理。 - 至少 1 个审批待办从企业微信提醒 deeplink 回到 OA 页面处理。
- P1 试点时,至少 1 条采购/费用申请、1 条合同台账、1 个项目关联事项可创建、审批或归档。 - P1 试点时,至少 1 条采购/费用申请、1 条合同台账、1 个项目关联事项可创建、审批或归档。
@@ -0,0 +1,9 @@
"ID","Title","Description","Acceptance","Test_Method","Tools","Dev_Status","Review1_Status","Regression_Status","Files","Dependencies","Notes"
"FINPROD-0","FIN-PROD-ENABLE 合同建档","建立正式启用公网付款批次合同;基线为 426a968,CASHIER-VOUCHER-V1 已部署,目标是正式设置 payment_batch_v1=force_on 并完成 OA 内付款闭环验收。","1) CSV 校验通过;2) 本轮不新增 API/schema/UI;3) 使用公网现有测试账号和授权 PDF 样票;4) wangzhiling 作为出纳/付款执行口径,wangshunli 作为管理员复核和回滚决策人口径;5) 不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水、不重置数据库、不打印 secret。","受影响流程:CASHV 部署完成 -> FIN-PROD-ENABLE 正式常开准备;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv;人工核对本轮边界和用户批准。","python3|manual","DONE","DONE","DONE","issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv","[]","完成:CSV 初始校验通过;用户已批准正式启用付款批次;本轮不新增业务 API/schema/UI,不接真实支付,不接 ERP,不开放图片 OCR;失败回滚路径为 payment_batch_v1 force_off。"
"FINPROD-1","公网正式启用前置门禁","启用前确认公网健康、live smoke/PDF OCR 凭据可用、当前 payment_batch_v1 为关闭态、文档登记无新增阻断,且工作区没有未解释变更。","1) check-live-smoke-env --strict 通过;2) check-payment-batch-flag-off --json 通过或明确当前已关闭;3) audit-docs 仅允许既有 warning;4) git diff --check 通过;5) 不打印 env、cookie、PDF 路径或导出内容。","受影响流程:公网登录/凭据 -> 付款批次 flag-off 只读门禁 -> 文档门禁;验证步骤:set -a && source ~/.hyb-oa/live-smoke.env && set +a;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-smoke-env.mjs --strict;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-payment-batch-flag-off.mjs --json;node scripts/qa/audit-docs.mjs --check-registry;git diff --check。","node|bash|git","DONE","DONE","DONE","scripts/qa/check-live-smoke-env.mjs|scripts/qa/check-payment-batch-flag-off.mjs|docs","[""FINPROD-0""]","完成:check-live-smoke-env --strict PASS,publicReady/liveSmokeReady/liveOcrReady=true;pre flag-off PASS,finance/employee/admin 均为 409 payment_batch_v1_disabled / flag_force_off;audit-docs errors=0 warnings=1 为既有未登记文档 warning;git diff --check PASS。"
"FINPROD-2","正式启用 QA runner 准备","复用或新增 QA-only runner,使公网付款批次验收通过后可保持 payment_batch_v1=force_on;默认失败时仍恢复 force_off;不改业务运行时代码。","1) runner 必须要求 P2_FIN_LIVE_APPROVED=1 和 FIN_PROD_ENABLE_APPROVED=1;2) PASS 时最终检查 payment_batch_v1=force_on;3) FAIL 时强制恢复 force_off;4) erp_sync 全程 force_off;5) runner 报告只记录脱敏 ID、状态、HTTP 结果和审计动作。","受影响流程:公网付款批次正式启用自动化 -> 成功保持开启/失败回滚;验证步骤:node --check scripts/qa/check-payment-batch-flag-off.mjs;bash -n scripts/qa/run-fin-prod-enable-window.sh;cd client && npm run typecheck && npm run build;如修改 Playwright spec,执行对应 typecheck。","node|bash|npm|playwright","DONE","DONE","DONE","scripts/qa/run-fin-prod-enable-window.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts","[""FINPROD-1""]","完成:新增 QA-only run-fin-prod-enable-window.sh;p2-fin-live spec 增加显式 force_on final mode,默认短窗口仍 force_off;bash -n PASS,node --check check-payment-batch-flag-off PASS,client typecheck/build PASS;未改业务运行时代码,未重新部署。"
"FINPROD-3","公网付款批次正式闭环验收","在公网正式开启 payment_batch_v1 后,用带 FINPROD marker 的报销完成审批、出纳建批次、管理员/复核人复核、出纳上传银行回单、执行 OA 已付款标记。","1) 新建或选用专用测试报销并审批到 approved;2) payment_batch_v1 更新为 force_on 且 erp_sync 仍为 force_off;3) finance/cashier 可创建和执行付款批次;4) 管理员/复核人复核审计可查;5) 银行渠道无回单执行被 409 阻断;6) 上传回单后执行成功,报销 paid、票据 archived、AP 台账 paid。","受影响流程:报销提交 -> 审批 -> PDF 发票绑定 -> 付款批次创建 -> 复核 -> 上传银行回单 -> 执行 OA 已付款;验证步骤:FIN_PROD_ENABLE_APPROVED=1 P2_FIN_LIVE_APPROVED=1 QA_ISSUE_ID=FINPROD P2_FIN_LIVE_MARKER_PREFIX=FINPROD LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-fin-prod-enable-window.sh。","bash|playwright","DONE","DONE","DONE","scripts/qa/run-fin-prod-enable-window.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|artifacts/qa-flow","[""FINPROD-2""]","完成:报告 artifacts/qa-flow/fin-prod-enable-20260517-114731;测试报销 BX-20260517-0026 审批后进入付款批次;无回单执行 409;上传/下载银行回单后执行成功;报销 paid、票据 archived、AP 台账 paid;真实银行付款仍在 OA 外。"
"FINPROD-4","权限、AP 导出与审计核验","核验付款批次常开后,员工、审批人和 admin-only 不越权;AP 导出成功;关键审计动作可查且不打印导出内容。","1) employee/manager 创建付款批次被拒绝;2) admin-only 若非 wildcard 应拒绝创建/执行,若为 wildcard 记录 SKIP_WILDCARD_SUPERADMIN;3) AP 导出返回 200;4) FEATURE_FLAG_UPDATED、PAYMENT_BATCH_CREATED、PAYMENT_BATCH_REVIEWED、PAYMENT_BATCH_RECEIPT_UPLOADED、PAYMENT_BATCH_EXECUTED、REIMBURSEMENT_PAYMENT_MARKED、EXPORT_AP_OPERATIONS 审计可查;5) 报告不包含导出明细。","受影响流程:权限边界 -> AP 导出 -> 审计追踪;验证步骤:同 FINPROD-3 runner 内置权限、导出和审计断言;必要时用 admin 只读审计列表核验动作,不下载或打印完整导出内容。","playwright|manual","DONE","DONE","DONE","client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|server/src/routes/exports.js|server/src/routes/audit.js","[""FINPROD-3""]","完成:employee/manager 创建付款批次均 403;admin 为 wildcard superadmin,admin-only 负例按 SKIP_WILDCARD_SUPERADMIN 记录;AP 导出 200;FEATURE_FLAG_UPDATED、PAYMENT_BATCH_CREATED/REVIEWED/RECEIPT_UPLOADED/EXECUTED、REIMBURSEMENT_PAYMENT_MARKED、EXPORT_AP_OPERATIONS 审计断言通过。"
"FINPROD-5","公网移动与企业微信自动化复检","付款批次正式启用后复跑公网移动和企业微信 UA/渲染矩阵,确认常开状态不影响移动入口和查看体验。","1) dg7-mobile-information-dedupe 通过;2) r124-mobile-entry-matrix 通过;3) r6-wecom-mobile-rendering-hardening 通过;4) 真机仅保留入口/免登/查看确认,不在手机执行付款动作。","受影响流程:公网移动首页/业务入口/通知/企业微信 UA 查看;验证步骤:cd client && E2E_BASE_URL=https://oa.hyinda.com npx playwright test tests/e2e/dg7-mobile-information-dedupe.spec.ts tests/e2e/r124-mobile-entry-matrix.spec.ts tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts --workers=1 --reporter=list。","playwright","DONE","DONE","DONE","client/tests/e2e/dg7-mobile-information-dedupe.spec.ts|client/tests/e2e/r124-mobile-entry-matrix.spec.ts|client/tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts","[""FINPROD-3""]","完成:公网移动矩阵 6 passed;企业微信渲染矩阵 8 passed;自动化覆盖 320/360/375/390/393/414/430,真机仍仅作为后续入口/免登/查看差异确认。"
"FINPROD-6","最终 flag 状态确认","验收通过后保持 payment_batch_v1=force_on;若 FINPROD-3/4/5 任一阻断,则恢复 force_off 并记录原因;erp_sync 必须保持 force_off。","1) PASS 时 payment_batch_v1 effectiveEnabled=true 且 overrideMode=force_on;2) FAIL 时 payment_batch_v1 恢复 force_off;3) erp_sync effectiveEnabled=false;4) 记录最终状态、报告目录和测试报销 formNumber;5) 不停留在未记录状态。","受影响流程:付款批次正式常开决策 -> 回滚或保持开启;验证步骤:runner 输出 live-result.json;必要时 admin 只读 GET /api/system/feature-flags 核对 payment_batch_v1 与 erp_sync;不打印 token/env。","node|playwright|manual","DONE","DONE","DONE","scripts/qa/run-fin-prod-enable-window.sh|artifacts/qa-flow","[""FINPROD-4"",""FINPROD-5""]","完成:final-force-on-check PASS;最终 payment_batch_v1 override=force_on effective=true reason=flag_force_on_global;erp_sync override=force_off effective=false reason=flag_force_off;报告 artifacts/qa-flow/fin-prod-enable-20260517-114731。"
"FINPROD-7","收口回填与提交","回填 FINPROD CSV、文档索引、事实源矩阵和人工试运行报告,提交中文 commit。","1) CSV 状态按证据回填;2) docs/文档索引.md、docs/文档事实源状态矩阵.md、docs/trialrun/人工试运行报告.md 更新;3) validate、audit-docs、rg、git diff --check 通过;4) 中文 commit 引用 FINPROD;5) 最终说明公网 URL、部署状态、/ready、最终 flag 状态。","流程级验证:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv;node scripts/qa/audit-docs.mjs --check-registry;rg -n 'FINPROD|FIN-PROD-ENABLE|payment_batch_v1|银行回单|EXPORT_AP_OPERATIONS|PAYMENT_BATCH' docs issues scripts client/tests;git diff --check;git status --short。","python3|node|rg|git","DONE","DONE","DONE","issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv|docs/文档索引.md|docs/文档事实源状态矩阵.md|docs/trialrun/人工试运行报告.md","[""FINPROD-6""]","完成:FINPROD CSV/docs 已回填;validate PASS,audit-docs errors=0 warnings=1(既有 unregistered docs),rg 关键词核对完成,git diff --check PASS;公网 https://oa.hyinda.com 未重新部署业务代码,最终 payment_batch_v1=force_on、erp_sync=force_off。"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 FINPROD-0 FIN-PROD-ENABLE 合同建档 建立正式启用公网付款批次合同;基线为 426a968,CASHIER-VOUCHER-V1 已部署,目标是正式设置 payment_batch_v1=force_on 并完成 OA 内付款闭环验收。 1) CSV 校验通过;2) 本轮不新增 API/schema/UI;3) 使用公网现有测试账号和授权 PDF 样票;4) wangzhiling 作为出纳/付款执行口径,wangshunli 作为管理员复核和回滚决策人口径;5) 不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水、不重置数据库、不打印 secret。 受影响流程:CASHV 部署完成 -> FIN-PROD-ENABLE 正式常开准备;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv;人工核对本轮边界和用户批准。 python3|manual DONE DONE DONE issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv [] 完成:CSV 初始校验通过;用户已批准正式启用付款批次;本轮不新增业务 API/schema/UI,不接真实支付,不接 ERP,不开放图片 OCR;失败回滚路径为 payment_batch_v1 force_off。
3 FINPROD-1 公网正式启用前置门禁 启用前确认公网健康、live smoke/PDF OCR 凭据可用、当前 payment_batch_v1 为关闭态、文档登记无新增阻断,且工作区没有未解释变更。 1) check-live-smoke-env --strict 通过;2) check-payment-batch-flag-off --json 通过或明确当前已关闭;3) audit-docs 仅允许既有 warning;4) git diff --check 通过;5) 不打印 env、cookie、PDF 路径或导出内容。 受影响流程:公网登录/凭据 -> 付款批次 flag-off 只读门禁 -> 文档门禁;验证步骤:set -a && source ~/.hyb-oa/live-smoke.env && set +a;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-smoke-env.mjs --strict;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-payment-batch-flag-off.mjs --json;node scripts/qa/audit-docs.mjs --check-registry;git diff --check。 node|bash|git DONE DONE DONE scripts/qa/check-live-smoke-env.mjs|scripts/qa/check-payment-batch-flag-off.mjs|docs ["FINPROD-0"] 完成:check-live-smoke-env --strict PASS,publicReady/liveSmokeReady/liveOcrReady=true;pre flag-off PASS,finance/employee/admin 均为 409 payment_batch_v1_disabled / flag_force_off;audit-docs errors=0 warnings=1 为既有未登记文档 warning;git diff --check PASS。
4 FINPROD-2 正式启用 QA runner 准备 复用或新增 QA-only runner,使公网付款批次验收通过后可保持 payment_batch_v1=force_on;默认失败时仍恢复 force_off;不改业务运行时代码。 1) runner 必须要求 P2_FIN_LIVE_APPROVED=1 和 FIN_PROD_ENABLE_APPROVED=1;2) PASS 时最终检查 payment_batch_v1=force_on;3) FAIL 时强制恢复 force_off;4) erp_sync 全程 force_off;5) runner 报告只记录脱敏 ID、状态、HTTP 结果和审计动作。 受影响流程:公网付款批次正式启用自动化 -> 成功保持开启/失败回滚;验证步骤:node --check scripts/qa/check-payment-batch-flag-off.mjs;bash -n scripts/qa/run-fin-prod-enable-window.sh;cd client && npm run typecheck && npm run build;如修改 Playwright spec,执行对应 typecheck。 node|bash|npm|playwright DONE DONE DONE scripts/qa/run-fin-prod-enable-window.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts ["FINPROD-1"] 完成:新增 QA-only run-fin-prod-enable-window.sh;p2-fin-live spec 增加显式 force_on final mode,默认短窗口仍 force_off;bash -n PASS,node --check check-payment-batch-flag-off PASS,client typecheck/build PASS;未改业务运行时代码,未重新部署。
5 FINPROD-3 公网付款批次正式闭环验收 在公网正式开启 payment_batch_v1 后,用带 FINPROD marker 的报销完成审批、出纳建批次、管理员/复核人复核、出纳上传银行回单、执行 OA 已付款标记。 1) 新建或选用专用测试报销并审批到 approved;2) payment_batch_v1 更新为 force_on 且 erp_sync 仍为 force_off;3) finance/cashier 可创建和执行付款批次;4) 管理员/复核人复核审计可查;5) 银行渠道无回单执行被 409 阻断;6) 上传回单后执行成功,报销 paid、票据 archived、AP 台账 paid。 受影响流程:报销提交 -> 审批 -> PDF 发票绑定 -> 付款批次创建 -> 复核 -> 上传银行回单 -> 执行 OA 已付款;验证步骤:FIN_PROD_ENABLE_APPROVED=1 P2_FIN_LIVE_APPROVED=1 QA_ISSUE_ID=FINPROD P2_FIN_LIVE_MARKER_PREFIX=FINPROD LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-fin-prod-enable-window.sh。 bash|playwright DONE DONE DONE scripts/qa/run-fin-prod-enable-window.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|artifacts/qa-flow ["FINPROD-2"] 完成:报告 artifacts/qa-flow/fin-prod-enable-20260517-114731;测试报销 BX-20260517-0026 审批后进入付款批次;无回单执行 409;上传/下载银行回单后执行成功;报销 paid、票据 archived、AP 台账 paid;真实银行付款仍在 OA 外。
6 FINPROD-4 权限、AP 导出与审计核验 核验付款批次常开后,员工、审批人和 admin-only 不越权;AP 导出成功;关键审计动作可查且不打印导出内容。 1) employee/manager 创建付款批次被拒绝;2) admin-only 若非 wildcard 应拒绝创建/执行,若为 wildcard 记录 SKIP_WILDCARD_SUPERADMIN;3) AP 导出返回 200;4) FEATURE_FLAG_UPDATED、PAYMENT_BATCH_CREATED、PAYMENT_BATCH_REVIEWED、PAYMENT_BATCH_RECEIPT_UPLOADED、PAYMENT_BATCH_EXECUTED、REIMBURSEMENT_PAYMENT_MARKED、EXPORT_AP_OPERATIONS 审计可查;5) 报告不包含导出明细。 受影响流程:权限边界 -> AP 导出 -> 审计追踪;验证步骤:同 FINPROD-3 runner 内置权限、导出和审计断言;必要时用 admin 只读审计列表核验动作,不下载或打印完整导出内容。 playwright|manual DONE DONE DONE client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|server/src/routes/exports.js|server/src/routes/audit.js ["FINPROD-3"] 完成:employee/manager 创建付款批次均 403;admin 为 wildcard superadmin,admin-only 负例按 SKIP_WILDCARD_SUPERADMIN 记录;AP 导出 200;FEATURE_FLAG_UPDATED、PAYMENT_BATCH_CREATED/REVIEWED/RECEIPT_UPLOADED/EXECUTED、REIMBURSEMENT_PAYMENT_MARKED、EXPORT_AP_OPERATIONS 审计断言通过。
7 FINPROD-5 公网移动与企业微信自动化复检 付款批次正式启用后复跑公网移动和企业微信 UA/渲染矩阵,确认常开状态不影响移动入口和查看体验。 1) dg7-mobile-information-dedupe 通过;2) r124-mobile-entry-matrix 通过;3) r6-wecom-mobile-rendering-hardening 通过;4) 真机仅保留入口/免登/查看确认,不在手机执行付款动作。 受影响流程:公网移动首页/业务入口/通知/企业微信 UA 查看;验证步骤:cd client && E2E_BASE_URL=https://oa.hyinda.com npx playwright test tests/e2e/dg7-mobile-information-dedupe.spec.ts tests/e2e/r124-mobile-entry-matrix.spec.ts tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts --workers=1 --reporter=list。 playwright DONE DONE DONE client/tests/e2e/dg7-mobile-information-dedupe.spec.ts|client/tests/e2e/r124-mobile-entry-matrix.spec.ts|client/tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts ["FINPROD-3"] 完成:公网移动矩阵 6 passed;企业微信渲染矩阵 8 passed;自动化覆盖 320/360/375/390/393/414/430,真机仍仅作为后续入口/免登/查看差异确认。
8 FINPROD-6 最终 flag 状态确认 验收通过后保持 payment_batch_v1=force_on;若 FINPROD-3/4/5 任一阻断,则恢复 force_off 并记录原因;erp_sync 必须保持 force_off。 1) PASS 时 payment_batch_v1 effectiveEnabled=true 且 overrideMode=force_on;2) FAIL 时 payment_batch_v1 恢复 force_off;3) erp_sync effectiveEnabled=false;4) 记录最终状态、报告目录和测试报销 formNumber;5) 不停留在未记录状态。 受影响流程:付款批次正式常开决策 -> 回滚或保持开启;验证步骤:runner 输出 live-result.json;必要时 admin 只读 GET /api/system/feature-flags 核对 payment_batch_v1 与 erp_sync;不打印 token/env。 node|playwright|manual DONE DONE DONE scripts/qa/run-fin-prod-enable-window.sh|artifacts/qa-flow ["FINPROD-4","FINPROD-5"] 完成:final-force-on-check PASS;最终 payment_batch_v1 override=force_on effective=true reason=flag_force_on_global;erp_sync override=force_off effective=false reason=flag_force_off;报告 artifacts/qa-flow/fin-prod-enable-20260517-114731。
9 FINPROD-7 收口回填与提交 回填 FINPROD CSV、文档索引、事实源矩阵和人工试运行报告,提交中文 commit。 1) CSV 状态按证据回填;2) docs/文档索引.md、docs/文档事实源状态矩阵.md、docs/trialrun/人工试运行报告.md 更新;3) validate、audit-docs、rg、git diff --check 通过;4) 中文 commit 引用 FINPROD;5) 最终说明公网 URL、部署状态、/ready、最终 flag 状态。 流程级验证:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv;node scripts/qa/audit-docs.mjs --check-registry;rg -n 'FINPROD|FIN-PROD-ENABLE|payment_batch_v1|银行回单|EXPORT_AP_OPERATIONS|PAYMENT_BATCH' docs issues scripts client/tests;git diff --check;git status --short。 python3|node|rg|git DONE DONE DONE issues/2026-05-17_11-40-47-fin-prod-enable-payment-batch.csv|docs/文档索引.md|docs/文档事实源状态矩阵.md|docs/trialrun/人工试运行报告.md ["FINPROD-6"] 完成:FINPROD CSV/docs 已回填;validate PASS,audit-docs errors=0 warnings=1(既有 unregistered docs),rg 关键词核对完成,git diff --check PASS;公网 https://oa.hyinda.com 未重新部署业务代码,最终 payment_batch_v1=force_on、erp_sync=force_off。
@@ -0,0 +1,7 @@
"ID","Title","Description","Acceptance","Test_Method","Tools","Dev_Status","Review1_Status","Regression_Status","Files","Dependencies","Notes"
"ACCTH-0","ACCOUNTING-HANDOFF-V1 合同建档","建立月度代账交接 SOP 合同;业务口径为 OA 内审批/台账/付款批次 + 银行对公付款回单 + 月度代账人工交接,不做银行流水自动导入。","1) CSV 校验通过;2) 不开发银行流水导入、不接 ERP、不接真实支付接口;3) OA 侧固定交接资料范围;4) 银行侧原始流水和回单由出纳从银行渠道导出;5) 不提交真实银行回单或隐私导出内容。","受影响流程:FIN-PROD-ENABLE -> 月度 AP/报销/票据/付款批次/审计资料整理 -> 代账人工核对;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-48-accounting-handoff-v1.csv;人工核对交接边界。","python3|manual","DONE","DONE","DONE","issues/2026-05-17_11-40-48-accounting-handoff-v1.csv","[]","完成:CSV 初始校验通过;边界固定为月度人工代账交接,不开发银行流水导入,不接 ERP/真实支付,不保存真实银行回单或隐私导出内容到仓库。"
"ACCTH-1","现有导出与回单附件能力只读核对","核对 AP 台账导出、报销导出、票据中心导出、付款批次清单、银行回单附件清单和审计日志导出的现有能力与权限。","1) AP 台账导出存在且 FINPROD 验证 200;2) 报销、票据、审计导出能力存在或记录缺口;3) 付款批次回单附件可按批次列表/下载;4) 不打印导出明细、不提交真实附件;5) 缺口仅记录,不顺手开发。","受影响流程:月度代账资料准备 -> OA 导出/清单 -> 银行侧资料人工核对;验证步骤:rg -n 'exports/(ap-operations|reimbursements|invoice|audit)|receipt-attachments|payment-batches' server/src/routes client/src docs;必要时用公网测试数据只读确认回单附件列表和导出 API 状态。","rg|manual|node","DONE","DONE","DONE","server/src/routes/exports.js|server/src/routes/paymentBatches.js|client/src|docs","[""ACCTH-0""]","完成:公网状态核对仅输出状态和字节数,不打印内容;付款批次清单 200,回单附件列表 200,回单下载 200,AP 导出 200,报销导出 200,票据中心导出 200,审计日志导出 200。"
"ACCTH-2","月度代账交接 SOP 回写","在既有文档中补充月度代账交接 SOP:出纳准备银行侧流水/回单原件,OA 导出 AP/报销/票据/付款批次/回单附件清单/审计日志,代账人工核对。","1) 优先更新既有文档,不新建综合规划文档;2) 写清月度资料、责任人、时间点、命名规则、隐私边界和异常处理;3) 明确 AP 台账不是银行流水;4) 明确不导入银行流水;5) 图片 OCR、ERP、真实支付接口仍冻结。","受影响流程:月末出纳整理 -> 代账接收 -> 人工核对 -> 异常回查 OA;验证步骤:审阅 docs/管理员手册.md 或现有运营手册;更新 docs/trialrun/人工试运行报告.md、docs/文档索引.md、docs/文档事实源状态矩阵.md 的状态摘要;git diff --check。","manual|git","DONE","DONE","DONE","docs/管理员手册.md|docs/trialrun/人工试运行报告.md|docs/文档索引.md|docs/文档事实源状态矩阵.md","[""ACCTH-1""]","完成:docs/管理员手册.md 新增正式财务闭环与代账交接 SOP;索引、事实源矩阵和人工试运行报告已同步 FINPROD/ACCTH 状态;明确 AP 台账不是银行流水,银行流水不导入 OA,ERP/真实支付/图片 OCR 继续冻结。"
"ACCTH-3","代账交接样例清单","基于 FINPROD 或预启用测试数据生成一组脱敏样例清单,证明资料项能从 OA 和银行侧分工获得。","1) 样例只包含月份、资料项、来源、负责人、状态、脱敏 ID 或数量;2) 不包含真实银行账号、完整票据号码、税号、手机号、导出明细或回单原件;3) 记录 FINPROD 测试报销/付款批次的脱敏 formNumber 或报告路径;4) 标明银行侧资料由出纳线下导出。","受影响流程:测试月份资料核对 -> 代账交接清单 -> 异常项回查;验证步骤:阅读 FINPROD live-result.json 和既有 LDF/PRELAUNCH 报告,只摘录 formNumber、状态和报告路径;不得复制导出内容。","manual|node","DONE","DONE","DONE","artifacts/qa-flow|docs/trialrun/人工试运行报告.md","[""ACCTH-2""]","完成:样例使用 FINPROD 脱敏证据,formNumber=BX-20260517-0026,报告 artifacts/qa-flow/fin-prod-enable-20260517-114731;只记录状态和报告路径,不复制导出内容或银行回单原件。"
"ACCTH-4","一键交接包决策","判断现有导出和 SOP 是否足够支撑代账交接;若足够则不开发;若需要一键 zip,另建实现合同。","1) 结论为 NO_BUILD_NEEDED 或 GO_TO_PACKAGE_CONTRACT;2) 若 NO_BUILD_NEEDED,说明现有导出+银行侧资料足够;3) 若 GO_TO_PACKAGE_CONTRACT,列出包内文件、权限、脱敏、审计和下载回滚要求;4) 不在本合同临时开发 zip 功能。","受影响流程:月度代账交接效率评估 -> 是否需要一键包;验证步骤:结合 ACCTH-1/2/3 结论人工判断并写入 CSV Notes。","manual","DONE","DONE","DONE","issues/2026-05-17_11-40-48-accounting-handoff-v1.csv","[""ACCTH-3""]","完成:结论 NO_BUILD_NEEDED;现有 OA 导出 + 付款批次回单附件 + 银行侧出纳线下资料足够支撑代账人工核对;一键 zip 交接包不在本轮开发,如代账方提出固定格式再另建合同。"
"ACCTH-5","收口回填与提交","回填 ACCTH CSV、索引、事实源矩阵和人工试运行报告;与 FINPROD 一并或分批提交中文 commit。","1) CSV 状态按证据回填;2) validate、audit-docs、rg、git diff --check 通过;3) 文档明确代账交接边界和冻结项;4) 中文 commit 引用 ACCTH;5) 给出后续 Go/No-Go 摘要。","流程级验证:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-48-accounting-handoff-v1.csv;node scripts/qa/audit-docs.mjs --check-registry;rg -n 'ACCTH|ACCOUNTING-HANDOFF|代账|银行回单|AP 台账|银行流水|payment_batch_v1' docs issues;git diff --check;git status --short。","python3|node|rg|git","DONE","DONE","DONE","issues/2026-05-17_11-40-48-accounting-handoff-v1.csv|docs","[""ACCTH-4""]","完成:ACCTH CSV/docs 已回填;validate PASS,audit-docs errors=0 warnings=1(既有 unregistered docs),rg 关键词核对完成,git diff --check PASS;结论 NO_BUILD_NEEDED,正式银行付款制度不由系统自动执行。"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 ACCTH-0 ACCOUNTING-HANDOFF-V1 合同建档 建立月度代账交接 SOP 合同;业务口径为 OA 内审批/台账/付款批次 + 银行对公付款回单 + 月度代账人工交接,不做银行流水自动导入。 1) CSV 校验通过;2) 不开发银行流水导入、不接 ERP、不接真实支付接口;3) OA 侧固定交接资料范围;4) 银行侧原始流水和回单由出纳从银行渠道导出;5) 不提交真实银行回单或隐私导出内容。 受影响流程:FIN-PROD-ENABLE -> 月度 AP/报销/票据/付款批次/审计资料整理 -> 代账人工核对;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-48-accounting-handoff-v1.csv;人工核对交接边界。 python3|manual DONE DONE DONE issues/2026-05-17_11-40-48-accounting-handoff-v1.csv [] 完成:CSV 初始校验通过;边界固定为月度人工代账交接,不开发银行流水导入,不接 ERP/真实支付,不保存真实银行回单或隐私导出内容到仓库。
3 ACCTH-1 现有导出与回单附件能力只读核对 核对 AP 台账导出、报销导出、票据中心导出、付款批次清单、银行回单附件清单和审计日志导出的现有能力与权限。 1) AP 台账导出存在且 FINPROD 验证 200;2) 报销、票据、审计导出能力存在或记录缺口;3) 付款批次回单附件可按批次列表/下载;4) 不打印导出明细、不提交真实附件;5) 缺口仅记录,不顺手开发。 受影响流程:月度代账资料准备 -> OA 导出/清单 -> 银行侧资料人工核对;验证步骤:rg -n 'exports/(ap-operations|reimbursements|invoice|audit)|receipt-attachments|payment-batches' server/src/routes client/src docs;必要时用公网测试数据只读确认回单附件列表和导出 API 状态。 rg|manual|node DONE DONE DONE server/src/routes/exports.js|server/src/routes/paymentBatches.js|client/src|docs ["ACCTH-0"] 完成:公网状态核对仅输出状态和字节数,不打印内容;付款批次清单 200,回单附件列表 200,回单下载 200,AP 导出 200,报销导出 200,票据中心导出 200,审计日志导出 200。
4 ACCTH-2 月度代账交接 SOP 回写 在既有文档中补充月度代账交接 SOP:出纳准备银行侧流水/回单原件,OA 导出 AP/报销/票据/付款批次/回单附件清单/审计日志,代账人工核对。 1) 优先更新既有文档,不新建综合规划文档;2) 写清月度资料、责任人、时间点、命名规则、隐私边界和异常处理;3) 明确 AP 台账不是银行流水;4) 明确不导入银行流水;5) 图片 OCR、ERP、真实支付接口仍冻结。 受影响流程:月末出纳整理 -> 代账接收 -> 人工核对 -> 异常回查 OA;验证步骤:审阅 docs/管理员手册.md 或现有运营手册;更新 docs/trialrun/人工试运行报告.md、docs/文档索引.md、docs/文档事实源状态矩阵.md 的状态摘要;git diff --check。 manual|git DONE DONE DONE docs/管理员手册.md|docs/trialrun/人工试运行报告.md|docs/文档索引.md|docs/文档事实源状态矩阵.md ["ACCTH-1"] 完成:docs/管理员手册.md 新增正式财务闭环与代账交接 SOP;索引、事实源矩阵和人工试运行报告已同步 FINPROD/ACCTH 状态;明确 AP 台账不是银行流水,银行流水不导入 OA,ERP/真实支付/图片 OCR 继续冻结。
5 ACCTH-3 代账交接样例清单 基于 FINPROD 或预启用测试数据生成一组脱敏样例清单,证明资料项能从 OA 和银行侧分工获得。 1) 样例只包含月份、资料项、来源、负责人、状态、脱敏 ID 或数量;2) 不包含真实银行账号、完整票据号码、税号、手机号、导出明细或回单原件;3) 记录 FINPROD 测试报销/付款批次的脱敏 formNumber 或报告路径;4) 标明银行侧资料由出纳线下导出。 受影响流程:测试月份资料核对 -> 代账交接清单 -> 异常项回查;验证步骤:阅读 FINPROD live-result.json 和既有 LDF/PRELAUNCH 报告,只摘录 formNumber、状态和报告路径;不得复制导出内容。 manual|node DONE DONE DONE artifacts/qa-flow|docs/trialrun/人工试运行报告.md ["ACCTH-2"] 完成:样例使用 FINPROD 脱敏证据,formNumber=BX-20260517-0026,报告 artifacts/qa-flow/fin-prod-enable-20260517-114731;只记录状态和报告路径,不复制导出内容或银行回单原件。
6 ACCTH-4 一键交接包决策 判断现有导出和 SOP 是否足够支撑代账交接;若足够则不开发;若需要一键 zip,另建实现合同。 1) 结论为 NO_BUILD_NEEDED 或 GO_TO_PACKAGE_CONTRACT;2) 若 NO_BUILD_NEEDED,说明现有导出+银行侧资料足够;3) 若 GO_TO_PACKAGE_CONTRACT,列出包内文件、权限、脱敏、审计和下载回滚要求;4) 不在本合同临时开发 zip 功能。 受影响流程:月度代账交接效率评估 -> 是否需要一键包;验证步骤:结合 ACCTH-1/2/3 结论人工判断并写入 CSV Notes。 manual DONE DONE DONE issues/2026-05-17_11-40-48-accounting-handoff-v1.csv ["ACCTH-3"] 完成:结论 NO_BUILD_NEEDED;现有 OA 导出 + 付款批次回单附件 + 银行侧出纳线下资料足够支撑代账人工核对;一键 zip 交接包不在本轮开发,如代账方提出固定格式再另建合同。
7 ACCTH-5 收口回填与提交 回填 ACCTH CSV、索引、事实源矩阵和人工试运行报告;与 FINPROD 一并或分批提交中文 commit。 1) CSV 状态按证据回填;2) validate、audit-docs、rg、git diff --check 通过;3) 文档明确代账交接边界和冻结项;4) 中文 commit 引用 ACCTH;5) 给出后续 Go/No-Go 摘要。 流程级验证:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_11-40-48-accounting-handoff-v1.csv;node scripts/qa/audit-docs.mjs --check-registry;rg -n 'ACCTH|ACCOUNTING-HANDOFF|代账|银行回单|AP 台账|银行流水|payment_batch_v1' docs issues;git diff --check;git status --short。 python3|node|rg|git DONE DONE DONE issues/2026-05-17_11-40-48-accounting-handoff-v1.csv|docs ["ACCTH-4"] 完成:ACCTH CSV/docs 已回填;validate PASS,audit-docs errors=0 warnings=1(既有 unregistered docs),rg 关键词核对完成,git diff --check PASS;结论 NO_BUILD_NEEDED,正式银行付款制度不由系统自动执行。
+293
查看文件
@@ -0,0 +1,293 @@
#!/usr/bin/env bash
set -u -o pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CLIENT_DIR="$ROOT_DIR/client"
PUBLIC_BASE_URL="${LIVE_SMOKE_BASE_URL:-https://oa.hyinda.com}"
REPORT_DIR="${FIN_PROD_ENABLE_REPORT_DIR:-$ROOT_DIR/artifacts/qa-flow/fin-prod-enable-$(date +%Y%m%d-%H%M%S)}"
SUMMARY_TXT="$REPORT_DIR/summary.txt"
STATUS=0
mkdir -p "$REPORT_DIR"
: >"$SUMMARY_TXT"
load_default_env() {
local env_file="${FIN_PROD_ENABLE_ENV_FILE:-$HOME/.hyb-oa/live-smoke.env}"
if [[ "${FIN_PROD_ENABLE_SKIP_ENV_FILE:-0}" == "1" || ! -f "$env_file" ]]; then
return 0
fi
set -a
# shellcheck disable=SC1090
source "$env_file"
set +a
PUBLIC_BASE_URL="${LIVE_SMOKE_BASE_URL:-$PUBLIC_BASE_URL}"
echo "[fin-prod-enable] loaded masked env file" | tee -a "$SUMMARY_TXT"
}
run_step() {
local name="$1"
shift
local log_file="$REPORT_DIR/${name}.log"
echo ">>> [fin-prod-enable] $name" | tee -a "$SUMMARY_TXT"
if "$@" > >(tee "$log_file") 2>&1; then
echo "[fin-prod-enable][PASS] $name" | tee -a "$SUMMARY_TXT"
else
local code="$?"
echo "[fin-prod-enable][FAIL] $name exit=$code" | tee -a "$SUMMARY_TXT"
STATUS=1
fi
}
run_shell_step() {
local name="$1"
local command="$2"
run_step "$name" bash -lc "$command"
}
fetch_feature_flags_node() {
local expected="$1"
EXPECTED_PAYMENT_BATCH_STATE="$expected" node <<'NODE'
const expected = process.env.EXPECTED_PAYMENT_BATCH_STATE;
const baseUrl = (process.env.LIVE_SMOKE_BASE_URL || "https://oa.hyinda.com").replace(/\/$/, "");
const identifier = process.env.LIVE_SMOKE_ADMIN_IDENTIFIER?.trim();
const password = process.env.LIVE_SMOKE_ADMIN_PASSWORD?.trim();
if (!identifier || !password) {
console.error("[fin-prod-enable][flag-check] missing admin credentials");
process.exit(1);
}
async function fetchJson(url, init = {}) {
const response = await fetch(url, {
...init,
signal: AbortSignal.timeout(20_000),
});
const text = await response.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch {
json = null;
}
return { response, json };
}
function errorSummary(json, status) {
const error = json?.error ?? {};
return `${status} ${error.code ?? ""} ${error.message ?? ""}`.trim();
}
const login = await fetchJson(`${baseUrl}/api/auth/login`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-device-fingerprint": "fin-prod-enable-flag-check",
},
body: JSON.stringify({ identifier, password }),
});
if (!login.response.ok || !login.json?.data?.accessToken) {
console.error(`[fin-prod-enable][flag-check] login failed: ${errorSummary(login.json, login.response.status)}`);
process.exit(1);
}
const token = login.json.data.accessToken;
const list = await fetchJson(`${baseUrl}/api/system/feature-flags`, {
headers: { authorization: `Bearer ${token}`, accept: "application/json" },
});
if (!list.response.ok) {
console.error(`[fin-prod-enable][flag-check] list flags failed: ${errorSummary(list.json, list.response.status)}`);
process.exit(1);
}
const items = list.json?.data?.items ?? [];
const payment = items.find((item) => item.flagKey === "payment_batch_v1");
const erp = items.find((item) => item.flagKey === "erp_sync");
if (!payment || !erp) {
console.error("[fin-prod-enable][flag-check] missing payment_batch_v1 or erp_sync");
process.exit(1);
}
console.log(`[fin-prod-enable][flag-check] payment_batch_v1 override=${payment.overrideMode} effective=${payment.effectiveEnabled} reason=${payment.effectiveReason}`);
console.log(`[fin-prod-enable][flag-check] erp_sync override=${erp.overrideMode} effective=${erp.effectiveEnabled} reason=${erp.effectiveReason}`);
const paymentOn = payment.overrideMode === "force_on" && payment.effectiveEnabled === true;
const paymentOff = payment.overrideMode === "force_off" && payment.effectiveEnabled === false;
const erpOff = erp.effectiveEnabled === false;
if (expected === "force_on" && (!paymentOn || !erpOff)) {
process.exit(1);
}
if (expected === "force_off" && (!paymentOff || !erpOff)) {
process.exit(1);
}
NODE
}
force_payment_batch_flag_off() {
node <<'NODE'
const baseUrl = (process.env.LIVE_SMOKE_BASE_URL || "https://oa.hyinda.com").replace(/\/$/, "");
const identifier = process.env.LIVE_SMOKE_ADMIN_IDENTIFIER?.trim();
const password = process.env.LIVE_SMOKE_ADMIN_PASSWORD?.trim();
const issueId = process.env.QA_ISSUE_ID?.trim() || "FINPROD";
if (!identifier || !password) {
console.error("[fin-prod-enable][rollback] missing admin credentials");
process.exit(1);
}
async function fetchJson(url, init = {}) {
const response = await fetch(url, {
...init,
signal: AbortSignal.timeout(20_000),
});
const text = await response.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch {
json = null;
}
return { response, json };
}
function errorSummary(json, status) {
const error = json?.error ?? {};
return `${status} ${error.code ?? ""} ${error.message ?? ""}`.trim();
}
const login = await fetchJson(`${baseUrl}/api/auth/login`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-device-fingerprint": "fin-prod-enable-rollback",
},
body: JSON.stringify({ identifier, password }),
});
if (!login.response.ok || !login.json?.data?.accessToken) {
console.error(`[fin-prod-enable][rollback] login failed: ${errorSummary(login.json, login.response.status)}`);
process.exit(1);
}
const token = login.json.data.accessToken;
const list = await fetchJson(`${baseUrl}/api/system/feature-flags`, {
headers: { authorization: `Bearer ${token}`, accept: "application/json" },
});
if (!list.response.ok) {
console.error(`[fin-prod-enable][rollback] list flags failed: ${errorSummary(list.json, list.response.status)}`);
process.exit(1);
}
const flag = list.json?.data?.items?.find((item) => item.flagKey === "payment_batch_v1");
if (!flag) {
console.error("[fin-prod-enable][rollback] missing payment_batch_v1");
process.exit(1);
}
if (flag.overrideMode === "force_off" && flag.effectiveEnabled === false) {
console.log("[fin-prod-enable][rollback] payment_batch_v1 already force_off");
process.exit(0);
}
const updated = await fetchJson(`${baseUrl}/api/system/feature-flags/payment_batch_v1`, {
method: "PUT",
headers: {
authorization: `Bearer ${token}`,
"content-type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
overrideMode: "force_off",
rolloutType: "global",
departmentIds: [],
note: `${issueId} failed final rollback`,
expectedVersion: flag.version,
}),
});
if (!updated.response.ok) {
console.error(`[fin-prod-enable][rollback] update failed: ${errorSummary(updated.json, updated.response.status)}`);
process.exit(1);
}
const item = updated.json?.data?.item;
console.log(`[fin-prod-enable][rollback] payment_batch_v1 override=${item?.overrideMode ?? "unknown"} effective=${item?.effectiveEnabled ?? "unknown"}`);
NODE
}
write_summary_json() {
local qa_status="PASS"
local notes="FINPROD 正式启用:公网付款批次验收通过后保持 payment_batch_v1=force_on;失败时回滚 force_off;不接真实支付、不接 ERP、不开放图片 OCR。"
if [[ "$STATUS" -ne 0 ]]; then
qa_status="FAIL"
notes="FINPROD 正式启用失败或门禁失败:已尝试将 payment_batch_v1 回滚到 force_off;不接真实支付、不接 ERP、不开放图片 OCR。"
fi
QA_REPORT_DIR="$REPORT_DIR" \
QA_ISSUE_ID="${QA_ISSUE_ID:-FINPROD}" \
QA_BASE_URL="$PUBLIC_BASE_URL" \
QA_MODE="fin-prod-enable" \
QA_STATUS="$qa_status" \
QA_SUMMARY_NOTES="$notes" \
node "$ROOT_DIR/scripts/qa/write-qa-summary.mjs" >/dev/null 2>&1 || true
}
finish() {
if [[ "${P2_FIN_LIVE_APPROVED:-0}" == "1" && "${FIN_PROD_ENABLE_APPROVED:-0}" == "1" ]]; then
if [[ "$STATUS" -eq 0 ]]; then
echo ">>> [fin-prod-enable] final-force-on-check" | tee -a "$SUMMARY_TXT"
if LIVE_SMOKE_BASE_URL="$PUBLIC_BASE_URL" fetch_feature_flags_node "force_on" > >(tee "$REPORT_DIR/final-force-on-check.log") 2>&1; then
echo "[fin-prod-enable][PASS] final-force-on-check" | tee -a "$SUMMARY_TXT"
else
local code="$?"
echo "[fin-prod-enable][FAIL] final-force-on-check exit=$code" | tee -a "$SUMMARY_TXT"
STATUS=1
fi
fi
if [[ "$STATUS" -ne 0 ]]; then
echo ">>> [fin-prod-enable] failure-force-flag-off" | tee -a "$SUMMARY_TXT"
if force_payment_batch_flag_off > >(tee "$REPORT_DIR/failure-force-flag-off.log") 2>&1; then
echo "[fin-prod-enable][PASS] failure-force-flag-off" | tee -a "$SUMMARY_TXT"
else
local code="$?"
echo "[fin-prod-enable][FAIL] failure-force-flag-off exit=$code" | tee -a "$SUMMARY_TXT"
fi
echo ">>> [fin-prod-enable] final-flag-off-check" | tee -a "$SUMMARY_TXT"
if LIVE_SMOKE_BASE_URL="$PUBLIC_BASE_URL" fetch_feature_flags_node "force_off" > >(tee "$REPORT_DIR/final-flag-off-check.log") 2>&1; then
echo "[fin-prod-enable][PASS] final-flag-off-check" | tee -a "$SUMMARY_TXT"
else
local code="$?"
echo "[fin-prod-enable][FAIL] final-flag-off-check exit=$code" | tee -a "$SUMMARY_TXT"
fi
fi
fi
write_summary_json
echo "[fin-prod-enable] report=$REPORT_DIR" | tee -a "$SUMMARY_TXT"
exit "$STATUS"
}
trap finish EXIT
load_default_env
if [[ "${P2_FIN_LIVE_APPROVED:-0}" != "1" || "${FIN_PROD_ENABLE_APPROVED:-0}" != "1" ]]; then
echo "[fin-prod-enable][ERROR] P2_FIN_LIVE_APPROVED=1 and FIN_PROD_ENABLE_APPROVED=1 are required for public write enablement" | tee -a "$SUMMARY_TXT"
STATUS=2
exit "$STATUS"
fi
run_shell_step "live-env-strict" "LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' node '$ROOT_DIR/scripts/qa/check-live-smoke-env.mjs' --strict"
[[ "$STATUS" -eq 0 ]] || exit "$STATUS"
run_shell_step "pre-flag-off-check" "LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' node '$ROOT_DIR/scripts/qa/check-payment-batch-flag-off.mjs' --json"
[[ "$STATUS" -eq 0 ]] || exit "$STATUS"
run_shell_step "fin-prod-enable-spec" "cd '$CLIENT_DIR' && PLAYWRIGHT_MANUAL=1 E2E_MODE=live P2_FIN_LIVE_APPROVED=1 P2_FIN_LIVE_FINAL_STATE=force_on QA_ISSUE_ID='${QA_ISSUE_ID:-FINPROD}' P2_FIN_LIVE_MARKER_PREFIX='${P2_FIN_LIVE_MARKER_PREFIX:-${QA_ISSUE_ID:-FINPROD}}' P2_FIN_LIVE_REPORT_DIR='$REPORT_DIR' LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/manual/p2-fin-live-payment-batch.spec.ts --workers=1 --reporter=list"
if [[ "${FIN_PROD_ENABLE_SKIP_MOBILE:-0}" == "1" ]]; then
echo "[fin-prod-enable][SKIP] mobile-wecom FIN_PROD_ENABLE_SKIP_MOBILE=1" | tee -a "$SUMMARY_TXT"
else
run_shell_step "public-mobile-matrix" "cd '$CLIENT_DIR' && E2E_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/dg7-mobile-information-dedupe.spec.ts tests/e2e/r124-mobile-entry-matrix.spec.ts --workers=1 --reporter=list"
run_shell_step "wecom-rendering-matrix" "cd '$CLIENT_DIR' && E2E_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts --workers=1 --reporter=list"
fi