恢复付款入口与常开基线(08-01-reimbursement-notification-progress-clarity)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-01 23:12:23 +08:00
父节点 aa6b9bc373
当前提交 37b4ef2d10
共修改 20 个文件,包含 655 行新增和 244 行删除
@@ -19,7 +19,7 @@ type FeatureFlagItem = {
type FeatureFlagSnapshot = Pick<
FeatureFlagItem,
"flagKey" | "overrideMode" | "rolloutType" | "departmentIds" | "version" | "effectiveEnabled" | "effectiveReason"
"flagKey" | "overrideMode" | "rolloutType" | "departmentIds" | "note" | "version" | "effectiveEnabled" | "effectiveReason"
>;
type ReimbursementDetail = {
@@ -99,7 +99,7 @@ const baseUrl = process.env.LIVE_SMOKE_BASE_URL?.trim() || "https://oa.hyinda.co
const reportDir = process.env.P2_FIN_LIVE_REPORT_DIR?.trim() ||
path.resolve(process.cwd(), "..", "artifacts/qa-flow/p2-fin-live-local");
const summaryPath = path.join(reportDir, "live-result.json");
const finalFlagState = process.env.P2_FIN_LIVE_FINAL_STATE?.trim() === "force_on" ? "force_on" : "force_off";
const finalFlagState = process.env.P2_FIN_LIVE_FINAL_STATE?.trim() === "force_on" ? "force_on" : "restore";
const alreadyOnMode =
process.env.P2_FIN_LIVE_ALREADY_ON === "1" ||
process.env.LAUNCH_AUTO_PAYMENT_BATCH_ALREADY_ON === "1";
@@ -130,6 +130,7 @@ function snapshotFlag(item: FeatureFlagItem): FeatureFlagSnapshot {
overrideMode: item.overrideMode,
rolloutType: item.rolloutType,
departmentIds: item.departmentIds,
note: item.note,
version: item.version,
effectiveEnabled: item.effectiveEnabled,
effectiveReason: item.effectiveReason,
@@ -183,13 +184,15 @@ async function updateFlag(
flagKey: string,
overrideMode: FeatureFlagItem["overrideMode"],
note: string,
rolloutType: FeatureFlagItem["rolloutType"] = "global",
departmentIds: string[] = [],
) {
const current = await loadFlag(api, flagKey);
const response = await api.put(`/api/system/feature-flags/${flagKey}`, {
data: {
overrideMode,
rolloutType: "global",
departmentIds: [],
rolloutType,
departmentIds,
note,
expectedVersion: current.version,
},
@@ -198,12 +201,24 @@ async function updateFlag(
return data.item;
}
async function forcePaymentBatchOff(api: APIRequestContext, note: string) {
async function restoreFlagSnapshot(api: APIRequestContext, snapshot: FeatureFlagSnapshot) {
const current = await loadFlag(api, "payment_batch_v1");
if (current.overrideMode === "force_off" && !current.effectiveEnabled) {
const configurationMatches =
current.overrideMode === snapshot.overrideMode &&
current.rolloutType === snapshot.rolloutType &&
JSON.stringify(current.departmentIds) === JSON.stringify(snapshot.departmentIds) &&
current.note === snapshot.note;
if (configurationMatches) {
return current;
}
return updateFlag(api, "payment_batch_v1", "force_off", note);
return updateFlag(
api,
"payment_batch_v1",
snapshot.overrideMode,
snapshot.note,
snapshot.rolloutType,
snapshot.departmentIds,
);
}
function resolveLivePdfBuffer(marker: string) {
@@ -397,6 +412,7 @@ test.describe("公网付款批次受控验收", () => {
const clients: AuthenticatedApiClient[] = [];
let admin: AuthenticatedApiClient | null = null;
let paymentFlagBefore: FeatureFlagItem | null = null;
let caughtError: unknown = null;
let rollbackError: unknown = null;
@@ -408,7 +424,7 @@ test.describe("公网付款批次受控验收", () => {
const financeMgr = await createLiveClientWithRetry("financeMgr");
clients.push(admin, employee, manager, finance, financeMgr);
const paymentFlagBefore = await loadFlag(admin.api, "payment_batch_v1");
paymentFlagBefore = await loadFlag(admin.api, "payment_batch_v1");
const erpFlagBefore = await loadFlag(admin.api, "erp_sync");
summary.stages.preflight = {
paymentFlagBefore: snapshotFlag(paymentFlagBefore),
@@ -587,19 +603,7 @@ test.describe("公网付款批次受控验收", () => {
} finally {
if (admin) {
try {
if (alreadyOnMode) {
const finalPaymentFlag = await loadFlag(admin.api, "payment_batch_v1");
const finalErpFlag = await loadFlag(admin.api, "erp_sync");
summary.stages.finalState = {
paymentFlag: snapshotFlag(finalPaymentFlag),
erpSyncEffectiveEnabled: finalErpFlag.effectiveEnabled,
alreadyOnMode,
};
expect(finalPaymentFlag.effectiveEnabled).toBe(true);
expect(finalPaymentFlag.overrideMode).toBe("force_on");
expect(finalFlagState).toBe("force_on");
expect(finalErpFlag.effectiveEnabled).toBe(false);
} else if (finalFlagState === "force_on" && !caughtError) {
if (finalFlagState === "force_on" && !caughtError) {
const paymentFlag = await loadFlag(admin.api, "payment_batch_v1");
const finalPaymentFlag =
paymentFlag.overrideMode === "force_on" && paymentFlag.effectiveEnabled
@@ -609,14 +613,18 @@ test.describe("公网付款批次受控验收", () => {
summary.stages.finalState = {
paymentFlag: snapshotFlag(finalPaymentFlag),
erpSyncEffectiveEnabled: finalErpFlag.effectiveEnabled,
alreadyOnMode,
};
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);
} else if (paymentFlagBefore) {
const restored = await restoreFlagSnapshot(admin.api, snapshotFlag(paymentFlagBefore));
summary.stages.rollback = { paymentFlagAfterRestore: snapshotFlag(restored) };
expect(restored.overrideMode).toBe(paymentFlagBefore.overrideMode);
expect(restored.rolloutType).toBe(paymentFlagBefore.rolloutType);
expect(restored.departmentIds).toEqual(paymentFlagBefore.departmentIds);
expect(restored.note).toBe(paymentFlagBefore.note);
}
} catch (error) {
rollbackError = error;