82 lines
2.3 KiB
TypeScript
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),
|
|
};
|
|
}
|