refactor(api): extract timeline holiday load support
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
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();
|
||||
});
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
import { buildSplitAllocationReadModel } from "@capakraken/application";
|
||||
import { Prisma, VacationType } from "@capakraken/db";
|
||||
import { z } from "zod";
|
||||
import { asHolidayResolverDb, getResolvedCalendarHolidays } from "../lib/holiday-availability.js";
|
||||
import { controllerProcedure, protectedProcedure } from "../trpc.js";
|
||||
import {
|
||||
buildSelfServiceTimelineInput,
|
||||
createTimelineDateRange,
|
||||
createTimelineFilters,
|
||||
fmtDate,
|
||||
loadTimelineEntriesReadModel,
|
||||
TimelineEntriesDbClient,
|
||||
TimelineEntriesFilters,
|
||||
TimelineWindowFiltersSchema,
|
||||
} from "./timeline-read-shared.js";
|
||||
import {
|
||||
loadTimelineHolidayOverlays,
|
||||
} from "./timeline-holiday-load-support.js";
|
||||
import {
|
||||
buildTimelineHolidayOverlayDetailResponse,
|
||||
buildTimelineHolidayResourceIds,
|
||||
buildTimelineHolidayResourceWhere,
|
||||
formatTimelineHolidayOverlays,
|
||||
summarizeTimelineHolidayOverlays,
|
||||
type TimelineHolidayOverlayRecord,
|
||||
} from "./timeline-holiday-support.js";
|
||||
|
||||
export {
|
||||
loadTimelineHolidayOverlays,
|
||||
loadTimelineHolidayOverlaysForReadModel,
|
||||
} from "./timeline-holiday-load-support.js";
|
||||
|
||||
export function formatHolidayOverlays(
|
||||
overlays: TimelineHolidayOverlayRecord[],
|
||||
) {
|
||||
@@ -34,94 +33,6 @@ export function summarizeHolidayOverlays(
|
||||
return summarizeTimelineHolidayOverlays(overlays);
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
export const timelineHolidayReadProcedures = {
|
||||
getHolidayOverlays: controllerProcedure
|
||||
.input(TimelineWindowFiltersSchema)
|
||||
|
||||
Reference in New Issue
Block a user