101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
import { buildSplitAllocationReadModel } from "@capakraken/application";
|
|
import { VacationType } from "@capakraken/db";
|
|
import { asHolidayResolverDb, getResolvedCalendarHolidays } from "../lib/holiday-availability.js";
|
|
import {
|
|
buildTimelineHolidayResourceIds,
|
|
buildTimelineHolidayResourceWhere,
|
|
} from "./timeline-holiday-support.js";
|
|
import {
|
|
loadTimelineEntriesReadModel,
|
|
TimelineEntriesDbClient,
|
|
TimelineEntriesFilters,
|
|
} from "./timeline-read-shared.js";
|
|
|
|
export async function loadTimelineHolidayOverlays(
|
|
db: TimelineEntriesDbClient,
|
|
input: TimelineEntriesFilters,
|
|
) {
|
|
const readModel = await loadTimelineEntriesReadModel(db, input);
|
|
return loadTimelineHolidayOverlaysForReadModel(db, input, readModel);
|
|
}
|
|
|
|
export async function loadTimelineHolidayOverlaysForReadModel(
|
|
db: TimelineEntriesDbClient,
|
|
input: TimelineEntriesFilters,
|
|
readModel: ReturnType<typeof buildSplitAllocationReadModel>,
|
|
) {
|
|
const resourceWhere = buildTimelineHolidayResourceWhere({
|
|
chapters: input.chapters,
|
|
eids: input.eids,
|
|
countryCodes: input.countryCodes,
|
|
});
|
|
const matchingResources = resourceWhere
|
|
? await db.resource.findMany({
|
|
where: resourceWhere,
|
|
select: { id: true },
|
|
})
|
|
: [];
|
|
const resourceIds = buildTimelineHolidayResourceIds({
|
|
assignmentResourceIds: readModel.assignments.map((assignment) => assignment.resourceId),
|
|
requestedResourceIds: input.resourceIds,
|
|
matchingFilterResourceIds: matchingResources.map((resource) => resource.id),
|
|
});
|
|
|
|
if (resourceIds.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const resources = await db.resource.findMany({
|
|
where: { id: { in: resourceIds } },
|
|
select: {
|
|
id: true,
|
|
countryId: true,
|
|
federalState: true,
|
|
metroCityId: true,
|
|
country: { select: { code: true, name: true } },
|
|
metroCity: { select: { name: true } },
|
|
},
|
|
});
|
|
|
|
const overlays = await Promise.all(
|
|
resources.map(async (resource) => {
|
|
const holidays = await getResolvedCalendarHolidays(asHolidayResolverDb(db), {
|
|
periodStart: input.startDate,
|
|
periodEnd: input.endDate,
|
|
countryId: resource.countryId,
|
|
countryCode: resource.country?.code ?? null,
|
|
federalState: resource.federalState,
|
|
metroCityId: resource.metroCityId,
|
|
metroCityName: resource.metroCity?.name ?? null,
|
|
});
|
|
|
|
return holidays.map((holiday) => {
|
|
const holidayDate = new Date(`${holiday.date}T00:00:00.000Z`);
|
|
return {
|
|
id: `calendar-holiday:${resource.id}:${holiday.date}`,
|
|
resourceId: resource.id,
|
|
type: VacationType.PUBLIC_HOLIDAY,
|
|
status: "APPROVED" as const,
|
|
startDate: holidayDate,
|
|
endDate: holidayDate,
|
|
note: holiday.name,
|
|
scope: holiday.scope,
|
|
calendarName: holiday.calendarName,
|
|
sourceType: holiday.sourceType,
|
|
countryCode: resource.country?.code ?? null,
|
|
countryName: resource.country?.name ?? null,
|
|
federalState: resource.federalState ?? null,
|
|
metroCityName: resource.metroCity?.name ?? null,
|
|
};
|
|
});
|
|
}),
|
|
);
|
|
|
|
return overlays.flat().sort((left, right) => {
|
|
if (left.resourceId !== right.resourceId) {
|
|
return left.resourceId.localeCompare(right.resourceId);
|
|
}
|
|
return left.startDate.getTime() - right.startDate.getTime();
|
|
});
|
|
}
|