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-12 20:03:29 +08:00
父节点 31ab9fbb2b
当前提交 229867f5fd
共修改 18 个文件,包含 629 行新增和 20 行删除
+37 -1
查看文件
@@ -1,4 +1,7 @@
const { AppError } = require("./AppError");
const { buildBusinessValidationError } = require("./businessValidationError");
const FINANCE_OWNER_APPROVAL_STEP_ID = "approval_1_ceo_finance_owner";
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
const MAX_MANAGER_DEPTH = 10;
@@ -199,8 +202,39 @@ function assertOwnerSelfFallbackRole(roleCode, ownerRoleCodes) {
return roleCode;
}
async function buildApprovalWorkflowSnapshot({ tx, approvalRule, ownerId, logger }) {
async function buildFinanceOwnerApprovalSnapshot({ tx, ownerId, submitterId }) {
const ownerRoleCodes = await loadOwnerRoleCodes(tx, ownerId);
if (ownerRoleCodes?.has("finance")) {
const applicantIds = [...new Set([ownerId, submitterId].filter(Boolean))];
const ceo = await tx.employeeRole.findFirst({
where: {
role_code: "ceo",
employee_id: { notIn: applicantIds },
employee: { status: "active", archived_at: null },
},
select: { employee_id: true },
});
if (!ceo) {
throw buildBusinessValidationError("reimbursement.finance_owner_ceo_unavailable", {
workflow: "no_actionable_approver", reason: "finance_owner_ceo_unavailable",
}, 409);
}
return [{
id: FINANCE_OWNER_APPROVAL_STEP_ID,
name: "总经理审批",
type: "approval",
assignee_rule: { type: "role", value: "ceo" },
}];
}
return null;
}
async function buildApprovalWorkflowSnapshot({ tx, approvalRule, ownerId, submitterId, entityType, logger }) {
const rawSteps = buildWorkflowStepsFromApprovalRule(approvalRule);
if (entityType === "reimbursement") {
const financeOwnerSteps = await buildFinanceOwnerApprovalSnapshot({ tx, ownerId, submitterId });
if (financeOwnerSteps) return financeOwnerSteps;
}
const hasManagerStep = rawSteps.some((step) => isDepartmentManagerRule(step.assignee_rule));
if (!hasManagerStep || !approvalRule.owner_self_fallback_role) {
@@ -567,9 +601,11 @@ function toMoneyString(value) {
}
module.exports = {
FINANCE_OWNER_APPROVAL_STEP_ID,
BUSINESS_APPROVAL_ROLE_CODES,
OWNER_SELF_FALLBACK_ROLE_CODES,
buildApprovalWorkflowSnapshot,
buildFinanceOwnerApprovalSnapshot,
buildWorkflowStepsFromApprovalRule,
getWorkflowStepsSnapshot,
isBusinessApprovalRoleCode,