修正CEO报销财务兜底与部署护栏(07-28-ceo-finance-fallback)
这个提交包含在:
@@ -0,0 +1,103 @@
|
||||
const {
|
||||
assertPeopleBaseline,
|
||||
buildRulePlan,
|
||||
parseArgs,
|
||||
} = require("../../../src/scripts/apply-ceo-finance-fallback");
|
||||
|
||||
function currentRows() {
|
||||
return [
|
||||
{
|
||||
id: "small-id",
|
||||
min_amount: "0.00",
|
||||
max_amount: "500.00",
|
||||
level1_role: "manager",
|
||||
level2_role: "finance",
|
||||
level3_role: null,
|
||||
owner_self_fallback_role: "finance_mgr",
|
||||
},
|
||||
{
|
||||
id: "medium-id",
|
||||
min_amount: "500.00",
|
||||
max_amount: "5000.00",
|
||||
level1_role: "manager",
|
||||
level2_role: "finance_mgr",
|
||||
level3_role: null,
|
||||
owner_self_fallback_role: "finance_mgr",
|
||||
},
|
||||
{
|
||||
id: "large-id",
|
||||
min_amount: "5000.00",
|
||||
max_amount: null,
|
||||
level1_role: "manager",
|
||||
level2_role: "ceo",
|
||||
level3_role: "finance_mgr",
|
||||
owner_self_fallback_role: "finance_mgr",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
describe("CEO finance fallback production apply contract", () => {
|
||||
it("builds the exact three-band target without exposing identifiers in the result shape", () => {
|
||||
const plan = buildRulePlan(currentRows());
|
||||
expect(plan.map((item) => ({ band: item.band, after: item.after }))).toEqual([
|
||||
{
|
||||
band: "small",
|
||||
after: {
|
||||
level1_role: "manager",
|
||||
level2_role: "finance",
|
||||
level3_role: null,
|
||||
owner_self_fallback_role: "finance",
|
||||
},
|
||||
},
|
||||
{
|
||||
band: "medium",
|
||||
after: {
|
||||
level1_role: "manager",
|
||||
level2_role: "finance",
|
||||
level3_role: null,
|
||||
owner_self_fallback_role: "finance",
|
||||
},
|
||||
},
|
||||
{
|
||||
band: "large",
|
||||
after: {
|
||||
level1_role: "manager",
|
||||
level2_role: "ceo",
|
||||
level3_role: "finance",
|
||||
owner_self_fallback_role: "finance",
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[currentRows().slice(0, 2), "approval_rule_count_drift"],
|
||||
[[...currentRows(), currentRows()[0]], "approval_rule_count_drift"],
|
||||
[currentRows().map((row, index) => index === 1 ? { ...row, level2_role: "finance" } : row), "approval_rule_role_drift:medium"],
|
||||
[currentRows().map((row, index) => index === 2 ? { ...row, min_amount: "6000" } : row), "approval_rule_amount_band_drift"],
|
||||
])("fails closed on approval-rule drift", (rows, message) => {
|
||||
expect(() => buildRulePlan(rows)).toThrow(message);
|
||||
});
|
||||
|
||||
it("requires one bound CEO without manager/fallback role, one bound non-CEO finance, and one admin", () => {
|
||||
expect(() => assertPeopleBaseline({
|
||||
ceos: [{ direct_manager_id: null, has_wecom_binding: true, roles: ["ceo"] }],
|
||||
finances: [{ has_wecom_binding: true, roles: ["finance"] }],
|
||||
admins: [{ roles: ["admin"] }],
|
||||
})).not.toThrow();
|
||||
|
||||
expect(() => assertPeopleBaseline({ ceos: [], finances: [], admins: [] }))
|
||||
.toThrow("active_ceo_count_drift");
|
||||
expect(() => assertPeopleBaseline({
|
||||
ceos: [{ direct_manager_id: null, has_wecom_binding: true, roles: ["ceo", "finance"] }],
|
||||
finances: [{ has_wecom_binding: true, roles: ["finance"] }],
|
||||
admins: [{ roles: ["admin"] }],
|
||||
})).toThrow("ceo_holds_fallback_role");
|
||||
});
|
||||
|
||||
it("defaults to dry-run and rejects unknown arguments", () => {
|
||||
expect(parseArgs([])).toEqual({ apply: false, format: "text" });
|
||||
expect(parseArgs(["--apply", "--format=json"])).toEqual({ apply: true, format: "json" });
|
||||
expect(() => parseArgs(["--force"])).toThrow("Unsupported argument");
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户