/** * Auto-import public holidays for all active resources. * * For each resource, determines the applicable federal state from: * 1. resource.federalState (explicit, e.g. "BY") * 2. Falls back to federal-only holidays when no state is set * * Creates Vacation entries with type PUBLIC_HOLIDAY and status APPROVED. * Duplicate-safe: skips holidays that already exist (by date + type + resourceId). */ import { getPublicHolidays } from "@planarchy/shared"; interface MinimalVacation { resourceId: string; startDate: Date; endDate: Date; } interface AutoImportDb { resource: { findMany: (args: { where: { isActive: boolean }; select: { id: string; federalState: string }; }) => Promise>; }; vacation: { findMany: (args: unknown) => Promise; createMany: (args: { data: unknown[]; skipDuplicates?: boolean }) => Promise<{ count: number }>; }; } export interface AutoImportResult { year: number; holidaysCreated: number; resourcesProcessed: number; skippedExisting: number; } /** * Import public holidays for all active resources in a given year. * Returns the number of holiday vacation records created. */ export async function autoImportPublicHolidays( // eslint-disable-next-line @typescript-eslint/no-explicit-any db: any, year: number, ): Promise { const resources: Array<{ id: string; federalState: string | null }> = await db.resource.findMany({ where: { isActive: true }, select: { id: true, federalState: true }, }); if (resources.length === 0) { return { year, holidaysCreated: 0, resourcesProcessed: 0, skippedExisting: 0 }; } // Group resources by federal state (null = federal-only holidays) const byState = new Map(); for (const resource of resources) { const state = resource.federalState ?? null; const group = byState.get(state) ?? []; group.push(resource.id); byState.set(state, group); } let totalCreated = 0; let totalSkipped = 0; for (const [state, resourceIds] of byState) { const holidays = getPublicHolidays(year, state ?? undefined); if (holidays.length === 0) continue; for (const holiday of holidays) { const holidayDate = new Date(holiday.date); // Find existing records for this date + type to skip duplicates const existing: MinimalVacation[] = await db.vacation.findMany({ where: { resourceId: { in: resourceIds }, type: "PUBLIC_HOLIDAY", startDate: holidayDate, endDate: holidayDate, }, select: { resourceId: true, startDate: true, endDate: true }, }); const existingResourceIds = new Set(existing.map((v: MinimalVacation) => v.resourceId)); const newResourceIds = resourceIds.filter((id) => !existingResourceIds.has(id)); totalSkipped += existingResourceIds.size; if (newResourceIds.length === 0) continue; const records = newResourceIds.map((resourceId) => ({ resourceId, type: "PUBLIC_HOLIDAY", status: "APPROVED", startDate: holidayDate, endDate: holidayDate, note: holiday.name, isHalfDay: false, approvedAt: new Date(), })); const result = await db.vacation.createMany({ data: records, skipDuplicates: true, }); totalCreated += result.count; } } return { year, holidaysCreated: totalCreated, resourcesProcessed: resources.length, skippedExisting: totalSkipped, }; }