R62 A1-A6:2026年中国法定假期日历
这个提交包含在:
+72
-6
@@ -8,7 +8,7 @@ const { ensureCutoverAllowed } = require("../services/cutover");
|
||||
const {
|
||||
DEFAULT_ATTACHMENT_MIME_TYPES,
|
||||
calculateRequestedDays,
|
||||
calculateRequestedDaysByWorkingCalendar,
|
||||
calculateRequestedDaysPreviewByWorkingCalendar,
|
||||
createLeaveLedgerEntry,
|
||||
formatDateOnly,
|
||||
leaveRangesOverlap,
|
||||
@@ -37,6 +37,13 @@ const createLeaveSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
const workingDaysPreviewQuerySchema = z.object({
|
||||
startDate: DATE_ONLY_SCHEMA,
|
||||
endDate: DATE_ONLY_SCHEMA,
|
||||
startSession: SESSION_SCHEMA,
|
||||
endSession: SESSION_SCHEMA,
|
||||
});
|
||||
|
||||
const leaveListQuerySchema = z.object({
|
||||
status: STATUS_SCHEMA.optional(),
|
||||
scope: z.enum(["own", "all"]).optional(),
|
||||
@@ -189,9 +196,49 @@ function parseCreateBody(body) {
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveRequestedDaysForCreate(fastify, employee, body) {
|
||||
function parseWorkingDaysPreviewQuery(query) {
|
||||
const parsed = workingDaysPreviewQuerySchema.safeParse(query ?? {});
|
||||
if (!parsed.success) {
|
||||
throw buildValidationError(parsed.error.flatten());
|
||||
}
|
||||
|
||||
const startDate = new Date(`${parsed.data.startDate}T00:00:00.000Z`);
|
||||
const endDate = new Date(`${parsed.data.endDate}T00:00:00.000Z`);
|
||||
|
||||
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
||||
throw buildValidationError({ date: "invalid" });
|
||||
}
|
||||
|
||||
const requestedDays = calculateRequestedDays({
|
||||
startDate,
|
||||
endDate,
|
||||
startSession: parsed.data.startSession,
|
||||
endSession: parsed.data.endSession,
|
||||
});
|
||||
|
||||
return {
|
||||
startDate,
|
||||
endDate,
|
||||
startSession: parsed.data.startSession,
|
||||
endSession: parsed.data.endSession,
|
||||
requestedDays,
|
||||
};
|
||||
}
|
||||
|
||||
function buildNaturalWorkingDaysPreview(body) {
|
||||
return {
|
||||
requestedDays: body.requestedDays,
|
||||
naturalRequestedDays: body.requestedDays,
|
||||
holidayDayCount: 0,
|
||||
weekendDayCount: 0,
|
||||
adjustedWorkdayCount: 0,
|
||||
calendarApplied: false,
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveWorkingDaysPreview(fastify, employee, body) {
|
||||
if (!employee?.legal_entity_id) {
|
||||
return body.requestedDays;
|
||||
return buildNaturalWorkingDaysPreview(body);
|
||||
}
|
||||
|
||||
const featureFlag = await evaluateFeatureFlag({
|
||||
@@ -203,7 +250,7 @@ async function resolveRequestedDaysForCreate(fastify, employee, body) {
|
||||
});
|
||||
|
||||
if (!featureFlag.enabled) {
|
||||
return body.requestedDays;
|
||||
return buildNaturalWorkingDaysPreview(body);
|
||||
}
|
||||
|
||||
const legalEntity = await fastify.prisma.legalEntity.findUnique({
|
||||
@@ -232,10 +279,10 @@ async function resolveRequestedDaysForCreate(fastify, employee, body) {
|
||||
|
||||
const calendar = legalEntity?.default_holiday_calendar;
|
||||
if (!calendar || calendar.archived_at) {
|
||||
return body.requestedDays;
|
||||
return buildNaturalWorkingDaysPreview(body);
|
||||
}
|
||||
|
||||
return calculateRequestedDaysByWorkingCalendar({
|
||||
return calculateRequestedDaysPreviewByWorkingCalendar({
|
||||
startDate: body.startDate,
|
||||
endDate: body.endDate,
|
||||
startSession: body.startSession,
|
||||
@@ -244,6 +291,11 @@ async function resolveRequestedDaysForCreate(fastify, employee, body) {
|
||||
});
|
||||
}
|
||||
|
||||
async function resolveRequestedDaysForCreate(fastify, employee, body) {
|
||||
const preview = await resolveWorkingDaysPreview(fastify, employee, body);
|
||||
return preview.requestedDays;
|
||||
}
|
||||
|
||||
async function collectCreatePayload(request) {
|
||||
if (typeof request.isMultipart === "function" && request.isMultipart()) {
|
||||
const fields = {};
|
||||
@@ -519,6 +571,20 @@ async function leaveRoutes(fastify) {
|
||||
},
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
"/leave-requests/working-days",
|
||||
{
|
||||
schema: { tags: ["Leave"], summary: "Preview Leave Working Days" },
|
||||
preHandler: fastify.authenticate,
|
||||
},
|
||||
async (request, reply) => {
|
||||
const query = parseWorkingDaysPreviewQuery(request.query);
|
||||
const preview = await resolveWorkingDaysPreview(fastify, request.employee, query);
|
||||
|
||||
return sendData(reply, request, preview);
|
||||
},
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
"/leave-requests",
|
||||
{
|
||||
|
||||
在新工单中引用
屏蔽一个用户