feat(P25-1/P25-5/P26-1/P26-3/P24-1/P29-4): 落地内部OA够用版后端与试运行能力

关联 Issue: P25-1, P25-2, P25-3, P25-4, P25-5, P26-1, P26-3, P24-1, P24-2, P29-1, P29-2, P29-3, P29-4
这个提交包含在:
2026-03-21 18:03:20 +08:00
父节点 9b7cd818f7
当前提交 e39e41287e
共修改 45 个文件,包含 4571 行新增和 328 行删除
+22
查看文件
@@ -4,6 +4,7 @@ const { AppError } = require("../utils/AppError");
const { sendData } = require("../utils/reply");
const { resolveActionableStep } = require("../utils/workflow");
const { FEATURE_FLAG_KEYS, evaluateFeatureFlag } = require("../services/featureFlags");
const { ensureCutoverAllowed } = require("../services/cutover");
const {
DEFAULT_ATTACHMENT_MIME_TYPES,
calculateRequestedDays,
@@ -476,6 +477,13 @@ async function leaveRoutes(fastify) {
preHandler: fastify.requireEntityPermission("leave", "create"),
},
async (request, reply) => {
await ensureCutoverAllowed({
prisma: fastify.prisma,
config: fastify.config,
request,
domain: "leave",
departmentId: request.employee.department_id ?? null,
});
const { body, filePart } = await collectCreatePayload(request);
const leaveType = await loadLeaveTypeOrThrow(fastify.prisma, body.leaveTypeId);
const attachment = await assertLeaveTypeAttachment(
@@ -648,6 +656,13 @@ async function leaveRoutes(fastify) {
}
const leave = leaveRows[0];
await ensureCutoverAllowed({
prisma: tx,
config: fastify.config,
request,
domain: "leave",
departmentId: leave.department_id ?? request.employee.department_id ?? null,
});
if (leave.owner_id !== request.employee.id) {
throw new AppError({
code: "PERM_001",
@@ -877,6 +892,13 @@ async function leaveRoutes(fastify) {
}
const leave = leaveRows[0];
await ensureCutoverAllowed({
prisma: tx,
config: fastify.config,
request,
domain: "leave",
departmentId: leave.department_id ?? request.employee.department_id ?? null,
});
if (leave.owner_id !== request.employee.id) {
throw new AppError({
code: "PERM_001",