import { z } from "zod"; import { reportEntitySchema, ReportTemplateConfigSchema, type EntityKey, } from "./report-query-config.js"; export const RESOURCE_MONTH_RECOMMENDED_COLUMNS = [ "monthKey", "displayName", "eid", "chapter", "countryCode", "countryName", "federalState", "metroCityName", "orgUnitName", "managementLevelGroupName", "monthlyBaseWorkingDays", "monthlyEffectiveWorkingDays", "monthlyBaseAvailableHours", "monthlyPublicHolidayCount", "monthlyPublicHolidayWorkdayCount", "monthlyPublicHolidayHoursDeduction", "monthlyAbsenceDayEquivalent", "monthlyAbsenceHoursDeduction", "monthlySahHours", "monthlyChargeabilityTargetPct", "monthlyTargetHours", "monthlyActualBookedHours", "monthlyExpectedBookedHours", "monthlyActualChargeabilityPct", "monthlyExpectedChargeabilityPct", "monthlyUnassignedHours", ] as const; export const RESOURCE_MONTH_MINIMUM_AUDIT_COLUMNS = [ "monthKey", "displayName", "countryName", "federalState", "metroCityName", "monthlyPublicHolidayCount", "monthlyPublicHolidayHoursDeduction", "monthlyAbsenceDayEquivalent", "monthlyAbsenceHoursDeduction", "monthlySahHours", "monthlyTargetHours", "monthlyActualBookedHours", "monthlyUnassignedHours", ] as const; export const ReportBlueprintSummarySchema = z.object({ id: z.string().min(1), label: z.string().min(1), description: z.string().min(1), entity: reportEntitySchema, templateName: z.string().min(1), config: ReportTemplateConfigSchema, }); export const ReportBlueprintCatalogSchema = z.array(ReportBlueprintSummarySchema); export type ReportBlueprintSummary = z.infer; export type ResourceMonthTemplateCompleteness = { scope: "resource_month"; isAuditReady: boolean; isRecommendedComplete: boolean; recommendedColumnCount: number; selectedRecommendedColumnCount: number; minimumAuditColumnCount: number; selectedMinimumAuditColumnCount: number; missingRecommendedColumns: string[]; missingMinimumAuditColumns: string[]; }; const REPORT_BLUEPRINTS = ReportBlueprintCatalogSchema.parse([ { id: "resource-month-sah-transparency", label: "SAH transparency", description: "Explains how monthly SAH is reduced by holidays and absences per person.", entity: "resource_month", templateName: "Monthly SAH transparency", config: { entity: "resource_month", columns: [ "monthKey", "displayName", "eid", "chapter", "countryName", "federalState", "metroCityName", "orgUnitName", "managementLevelGroupName", "monthlyBaseWorkingDays", "monthlyEffectiveWorkingDays", "monthlyBaseAvailableHours", "monthlyPublicHolidayCount", "monthlyPublicHolidayWorkdayCount", "monthlyPublicHolidayHoursDeduction", "monthlyAbsenceDayEquivalent", "monthlyAbsenceHoursDeduction", "monthlySahHours", "monthlyChargeabilityTargetPct", "monthlyTargetHours", ], filters: [], sortBy: "displayName", sortDir: "asc", }, }, { id: "resource-month-chargeability-audit", label: "Chargeability audit", description: "Shows the full path from monthly SAH to booked, target and unassigned hours.", entity: "resource_month", templateName: "Monthly chargeability audit", config: { entity: "resource_month", columns: [ "monthKey", "displayName", "eid", "chapter", "countryName", "federalState", "metroCityName", "orgUnitName", "managementLevelGroupName", "monthlyBaseAvailableHours", "monthlyPublicHolidayCount", "monthlyPublicHolidayHoursDeduction", "monthlyAbsenceDayEquivalent", "monthlyAbsenceHoursDeduction", "monthlySahHours", "monthlyChargeabilityTargetPct", "monthlyTargetHours", "monthlyActualBookedHours", "monthlyExpectedBookedHours", "monthlyActualChargeabilityPct", "monthlyExpectedChargeabilityPct", "monthlyUnassignedHours", "lcrCents", "currency", ], filters: [], sortBy: "monthlyActualChargeabilityPct", sortDir: "desc", }, }, { id: "resource-month-location-comparison", label: "Location comparison", description: "Compares holiday impact across country, state and city contexts for the same month.", entity: "resource_month", templateName: "Monthly holiday comparison by location", config: { entity: "resource_month", columns: [ "monthKey", "displayName", "chapter", "countryName", "federalState", "metroCityName", "orgUnitName", "monthlyBaseWorkingDays", "monthlyBaseAvailableHours", "monthlyPublicHolidayCount", "monthlyPublicHolidayWorkdayCount", "monthlyPublicHolidayHoursDeduction", "monthlyAbsenceDayEquivalent", "monthlyAbsenceHoursDeduction", "monthlySahHours", "monthlyActualChargeabilityPct", ], filters: [], groupBy: "federalState", sortBy: "monthlyPublicHolidayHoursDeduction", sortDir: "desc", }, }, ]); export function listReportBlueprints(entity?: EntityKey): ReportBlueprintSummary[] { return entity ? REPORT_BLUEPRINTS.filter((blueprint) => blueprint.entity === entity) : REPORT_BLUEPRINTS; } export function buildResourceMonthTemplateCompleteness( columns: Iterable, ): ResourceMonthTemplateCompleteness { const selectedColumns = new Set(columns); const missingRecommendedColumns = RESOURCE_MONTH_RECOMMENDED_COLUMNS .filter((column) => !selectedColumns.has(column)); const missingMinimumAuditColumns = RESOURCE_MONTH_MINIMUM_AUDIT_COLUMNS .filter((column) => !selectedColumns.has(column)); return { scope: "resource_month", isAuditReady: missingMinimumAuditColumns.length === 0, isRecommendedComplete: missingRecommendedColumns.length === 0, recommendedColumnCount: RESOURCE_MONTH_RECOMMENDED_COLUMNS.length, selectedRecommendedColumnCount: RESOURCE_MONTH_RECOMMENDED_COLUMNS.length - missingRecommendedColumns.length, minimumAuditColumnCount: RESOURCE_MONTH_MINIMUM_AUDIT_COLUMNS.length, selectedMinimumAuditColumnCount: RESOURCE_MONTH_MINIMUM_AUDIT_COLUMNS.length - missingMinimumAuditColumns.length, missingRecommendedColumns, missingMinimumAuditColumns, }; }