Files
CapaKraken/packages/api/src/router/timeline-shift-support.ts
T

82 lines
2.3 KiB
TypeScript

import type {
SplitAssignmentRecord,
SplitDemandRequirementRecord,
} from "@capakraken/application";
import { validateShift } from "@capakraken/engine";
import type { ShiftValidationResult } from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import type { TimelineShiftPlan } from "./timeline-shift-planning.js";
export interface TimelineShiftProjectRecord {
id: string;
budgetCents: number;
winProbability: number;
startDate: Date;
endDate: Date;
}
export interface LoadedTimelineShiftContext {
project: TimelineShiftProjectRecord;
demandRequirements: SplitDemandRequirementRecord[];
assignments: SplitAssignmentRecord[];
shiftPlan: TimelineShiftPlan;
}
export interface TimelineProjectShiftEventPayload extends Record<string, unknown> {
projectId: string;
newStartDate: string;
newEndDate: string;
costDeltaCents: number;
resourceIds: Array<string | null>;
}
export function buildTimelineProjectShiftValidation(input: {
context: LoadedTimelineShiftContext;
newStartDate: Date;
newEndDate: Date;
}) {
const { context, newStartDate, newEndDate } = input;
return validateShift({
project: {
id: context.project.id,
budgetCents: context.project.budgetCents,
winProbability: context.project.winProbability,
startDate: context.project.startDate,
endDate: context.project.endDate,
},
newStartDate,
newEndDate,
allocations: context.shiftPlan.validationAllocations,
});
}
export function assertTimelineProjectShiftValid(
validation: ShiftValidationResult,
): void {
if (validation.valid) {
return;
}
throw new TRPCError({
code: "BAD_REQUEST",
message: `Shift validation failed: ${validation.errors.map((error) => error.message).join(", ")}`,
});
}
export function buildTimelineProjectShiftEventPayload(input: {
projectId: string;
newStartDate: Date;
newEndDate: Date;
validation: ShiftValidationResult;
assignments: SplitAssignmentRecord[];
}): TimelineProjectShiftEventPayload {
return {
projectId: input.projectId,
newStartDate: input.newStartDate.toISOString(),
newEndDate: input.newEndDate.toISOString(),
costDeltaCents: input.validation.costImpact.deltaCents,
resourceIds: input.assignments.map((assignment) => assignment.resourceId),
};
}