fix(detail-page-structure-progress-actions): 收敛操作面板定位并补充制单诊断
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-03 16:41:32 +08:00
父节点 59e91b8789
当前提交 a5b7e18507
共修改 8 个文件,包含 147 行新增和 12 行删除
@@ -2415,6 +2415,81 @@ describe("payment batch reimbursement routes", () => {
await app.close();
});
it("logs BIFF8 runtime guidance without exposing it in the finance API response", async () => {
const payerEncrypted = encryptStringOrThrow(
{ fieldEncryptionKey: FIELD_ENCRYPTION_KEY },
`6217${"0".repeat(8)}1234`,
);
const payeeEncrypted = encryptStringOrThrow(
{ fieldEncryptionKey: FIELD_ENCRYPTION_KEY },
SYNTHETIC_BANK_ACCOUNT,
);
const { app, tx } = await buildApp({
actor: {
id: ACTOR_ID,
department_id: "dept-1",
permissionCodes: ["payment.batch.manage", "payment.order.export"],
roleCodes: ["finance"],
},
batch: {
status: "reviewed",
payment_account_snapshot_json: {
accountName: "合成测试公司",
bankName: "中国建设银行",
bankInstitutionCode: "CCB",
accountNumberMasked: "6217********1234",
accountNumberEncrypted: payerEncrypted,
},
items: buildPaymentBatch().items.map((item) => ({
...item,
snapshot_json: {
payee: {
name: "测试员工",
bankName: "中国建设银行",
bankInstitutionCode: "CCB",
bankAccountMasked: "6222********5678",
bankAccountEncrypted: payeeEncrypted,
},
},
})),
},
});
const logError = vi.spyOn(app.log, "error");
const originalPythonBin = process.env.PAYMENT_ORDER_PYTHON_BIN;
process.env.PAYMENT_ORDER_PYTHON_BIN = "/definitely-missing/payment-order-python";
try {
const response = await app.inject({
method: "POST",
url: `/api/payment-batches/${BATCH_ID}/payment-order`,
headers: { authorization: "Bearer test" },
payload: { reason: "运行时依赖负向验证" },
});
const body = response.json();
expect(response.statusCode).toBe(409);
expect(body.error).toEqual({
code: "PAYMENT_ORDER_EXPORT_BLOCKED",
message: "银行制单生成失败",
details: { reason: "payment_order_generator_unavailable" },
});
expect(response.body).not.toContain("payment-order-biff8.txt");
expect(response.body).not.toContain("PAYMENT_ORDER_PYTHON_BIN");
expect(response.body).not.toContain("definitely-missing");
expect(logError).toHaveBeenCalledWith(
expect.objectContaining({
diagnostic: expect.stringContaining("server/requirements/payment-order-biff8.txt"),
}),
"payment order generator unavailable",
);
expect(tx.paymentBatch.update).not.toHaveBeenCalled();
} finally {
if (originalPythonBin === undefined) delete process.env.PAYMENT_ORDER_PYTHON_BIN;
else process.env.PAYMENT_ORDER_PYTHON_BIN = originalPythonBin;
await app.close();
}
});
it("does not let an admin without a finance business role export a payment order", async () => {
const { app, tx } = await buildApp({
actor: {