import type { WeekdayAvailability } from "../types/resource.js"; export const DISPO_RESOURCE_CHAPTER_BY_TOKEN = { "2D": "Digital Content Production", "3D": "Digital Content Production", PM: "Project Management", AD: "Art Direction", } as const; export const DISPO_ASSIGNMENT_ROLE_BY_TOKEN = { "2D": "2D Artist", "3D": "3D Artist", PM: "Project Manager", AD: "Art Director", } as const; export const DISPO_UTILIZATION_CODE_BY_TOKEN = { CH: "Chg", MO: "M&O", MD: "MD&I", PD: "PD&R", AB: "Absence", NA: "Absence", UN: null, } as const; export const DISPO_UTILIZATION_CATEGORIES = [ { code: "Chg", name: "Chargeable", description: "Billable client project work", sortOrder: 1, isDefault: true, }, { code: "BD", name: "Business Development", description: "Sales, proposals, presales activities", sortOrder: 2, isDefault: false, }, { code: "MD&I", name: "Market Development & Initiatives", description: "R&D, innovation, market development", sortOrder: 3, isDefault: false, }, { code: "M&O", name: "Management & Operations", description: "Internal admin, management overhead", sortOrder: 4, isDefault: false, }, { code: "PD&R", name: "People Development & Recruitment", description: "Training, hiring, onboarding", sortOrder: 5, isDefault: false, }, { code: "Absence", name: "Absence & Non Standard", description: "Vacation, illness, non-standard leave (reduces SAH)", sortOrder: 6, isDefault: false, }, ] as const; export const DISPO_INTERNAL_PROJECT_BUCKETS = [ { sourceToken: "MO", shortCode: "INT-MO", name: "Management & Operations", utilizationCategoryCode: "M&O", }, { sourceToken: "MD", shortCode: "INT-MD", name: "Market Development & Initiatives", utilizationCategoryCode: "MD&I", }, { sourceToken: "PD", shortCode: "INT-PD", name: "People Development & Recruitment", utilizationCategoryCode: "PD&R", }, ] as const; export const DISPO_REQUIRED_ROLE_SEEDS = [ { name: "2D Artist", description: "Canonical Dispo assignment role for 2D delivery work", }, { name: "3D Artist", description: "Canonical Dispo assignment role for 3D delivery work", }, { name: "Project Manager", description: "Canonical Dispo assignment role for project management delivery", }, { name: "Art Director", description: "Canonical Dispo assignment role for art direction delivery", }, ] as const; export type DispoRoleToken = keyof typeof DISPO_ASSIGNMENT_ROLE_BY_TOKEN; export type DispoChapterToken = keyof typeof DISPO_RESOURCE_CHAPTER_BY_TOKEN; export type DispoUtilizationToken = keyof typeof DISPO_UTILIZATION_CODE_BY_TOKEN; export type DispoInternalBucketDefinition = (typeof DISPO_INTERNAL_PROJECT_BUCKETS)[number]; function normalizeDispoTokenValue(value: string): string { return value.trim().replace(/\s+/g, " ").toUpperCase(); } function roundToTwoDecimals(value: number): number { return Math.round(value * 100) / 100; } export function normalizeCanonicalResourceIdentity(value: string): string { return value.trim().toLowerCase(); } export function resolveCanonicalResourceIdentity(enterpriseId?: string | null, eid?: string | null) { const normalizedEnterpriseId = enterpriseId ? normalizeCanonicalResourceIdentity(enterpriseId) : null; const normalizedEid = eid ? normalizeCanonicalResourceIdentity(eid) : null; const conflict = Boolean( normalizedEnterpriseId && normalizedEid && normalizedEnterpriseId !== normalizedEid, ); return { canonicalId: conflict ? null : normalizedEnterpriseId ?? normalizedEid, normalizedEnterpriseId, normalizedEid, conflict, }; } export function normalizeDispoChapterToken(token?: string | null): string | null { if (!token) return null; const normalizedToken = normalizeDispoTokenValue(token) as DispoChapterToken; return DISPO_RESOURCE_CHAPTER_BY_TOKEN[normalizedToken] ?? null; } export function normalizeDispoRoleToken(token?: string | null): string | null { if (!token) return null; const normalizedToken = normalizeDispoTokenValue(token) as DispoRoleToken; return DISPO_ASSIGNMENT_ROLE_BY_TOKEN[normalizedToken] ?? null; } export function normalizeDispoUtilizationToken(token?: string | null): string | null { if (!token) return null; const normalizedToken = normalizeDispoTokenValue(token) as DispoUtilizationToken; return DISPO_UTILIZATION_CODE_BY_TOKEN[normalizedToken] ?? null; } export function createWeekdayAvailabilityFromFte( fte: number, dailyWorkingHours = 8, ): WeekdayAvailability { const safeFte = Math.min(Math.max(fte, 0), 1); const hoursPerDay = roundToTwoDecimals(dailyWorkingHours * safeFte); return { monday: hoursPerDay, tuesday: hoursPerDay, wednesday: hoursPerDay, thursday: hoursPerDay, friday: hoursPerDay, }; }