收紧报销草稿读取边界 [09-04-reimbursement-state-gap-finance-view][R2]

这个提交包含在:
2026-09-05 09:13:53 +08:00
父节点 1b120e0829
当前提交 8e0af8235e
共修改 14 个文件,包含 704 行新增和 120 行删除
@@ -0,0 +1,92 @@
const GLOBAL_REIMBURSEMENT_VIEW_ROLES = new Set([
"admin",
"ceo",
"finance",
"finance_mgr",
"hr",
]);
function isGlobalReimbursementViewRole(roleCodes = []) {
return roleCodes.some((code) => GLOBAL_REIMBURSEMENT_VIEW_ROLES.has(code));
}
function buildOwnReimbursementScopeWhere(employeeId) {
return {
OR: [{ owner_id: employeeId }, { submitter_id: employeeId }],
};
}
function buildViewAllReimbursementScopeWhere(employee) {
if (isGlobalReimbursementViewRole(employee.roleCodes ?? [])) {
return {};
}
return {
OR: [
{ owner_id: employee.id },
{ submitter_id: employee.id },
{ owner: { direct_manager_id: employee.id } },
],
};
}
function buildReimbursementBusinessFactWhere(employeeId) {
return {
OR: [
{ status: { not: "draft" } },
{ owner_id: employeeId },
{ submitter_id: employeeId },
{ workflow_instances: { some: {} } },
],
};
}
function buildReadableReimbursementWhere({ employee, scope = "all", filters = {} }) {
const scopeWhere = scope === "own"
? buildOwnReimbursementScopeWhere(employee.id)
: buildViewAllReimbursementScopeWhere(employee);
if (scope === "own") {
return { AND: [scopeWhere, filters] };
}
return {
AND: [scopeWhere, buildReimbursementBusinessFactWhere(employee.id), filters],
};
}
async function canReadReimbursementBusinessFact(prisma, reimbursement, employeeId) {
if (reimbursement.owner_id === employeeId || reimbursement.submitter_id === employeeId) {
return true;
}
let status = reimbursement.status;
if (!status) {
const current = await prisma.reimbursementForm.findUnique({
where: { id: reimbursement.id },
select: { status: true },
});
status = current?.status ?? null;
}
if (status !== "draft") {
return Boolean(status);
}
const workflowInstance = await prisma.workflowInstance.findFirst({
where: {
entity_type: "reimbursement",
entity_id: reimbursement.id,
},
select: { id: true },
});
return Boolean(workflowInstance);
}
module.exports = {
buildOwnReimbursementScopeWhere,
buildReadableReimbursementWhere,
buildReimbursementBusinessFactWhere,
buildViewAllReimbursementScopeWhere,
canReadReimbursementBusinessFact,
isGlobalReimbursementViewRole,
};