refactor(api): extract timeline quick assign support
This commit is contained in:
@@ -5,9 +5,6 @@ import {
|
||||
buildTimelineAllocationEntryUpdate,
|
||||
buildTimelineAllocationMetadata,
|
||||
buildTimelineBatchShiftAuditChanges,
|
||||
buildTimelineQuickAssignAssignmentInput,
|
||||
buildTimelineQuickAssignMetadata,
|
||||
calculateTimelineAllocationPercentage,
|
||||
shiftTimelineAllocationWindow,
|
||||
validateTimelineAllocationDateRanges,
|
||||
} from "../router/timeline-allocation-mutation-support.js";
|
||||
@@ -39,43 +36,6 @@ describe("timeline allocation mutation support", () => {
|
||||
)).toThrowError(TRPCError);
|
||||
});
|
||||
|
||||
it("rounds allocation percentages and clamps them to 100", () => {
|
||||
expect(calculateTimelineAllocationPercentage(3.9)).toBe(49);
|
||||
expect(calculateTimelineAllocationPercentage(9)).toBe(100);
|
||||
});
|
||||
|
||||
it("builds source metadata for quick assign operations", () => {
|
||||
expect(buildTimelineQuickAssignMetadata("quickAssign")).toEqual({ source: "quickAssign" });
|
||||
expect(buildTimelineQuickAssignMetadata("batchQuickAssign")).toEqual({ source: "batchQuickAssign" });
|
||||
});
|
||||
|
||||
it("builds assignment create payloads for quick assign flows", () => {
|
||||
expect(
|
||||
buildTimelineQuickAssignAssignmentInput({
|
||||
resourceId: "resource_1",
|
||||
projectId: "project_1",
|
||||
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
hoursPerDay: 6,
|
||||
role: "Engineer",
|
||||
roleId: "role_1",
|
||||
status: "PROPOSED",
|
||||
source: "quickAssign",
|
||||
}),
|
||||
).toEqual({
|
||||
resourceId: "resource_1",
|
||||
projectId: "project_1",
|
||||
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
hoursPerDay: 6,
|
||||
percentage: 75,
|
||||
role: "Engineer",
|
||||
roleId: "role_1",
|
||||
status: "PROPOSED",
|
||||
metadata: { source: "quickAssign" },
|
||||
});
|
||||
});
|
||||
|
||||
it("shifts and clamps allocation windows for each batch-shift mode", () => {
|
||||
expect(
|
||||
shiftTimelineAllocationWindow({
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildTimelineQuickAssignAssignmentInput,
|
||||
buildTimelineQuickAssignMetadata,
|
||||
calculateTimelineAllocationPercentage,
|
||||
} from "../router/timeline-allocation-quick-assign-support.js";
|
||||
|
||||
describe("timeline allocation quick assign support", () => {
|
||||
it("rounds allocation percentages and clamps them to 100", () => {
|
||||
expect(calculateTimelineAllocationPercentage(3.9)).toBe(49);
|
||||
expect(calculateTimelineAllocationPercentage(9)).toBe(100);
|
||||
});
|
||||
|
||||
it("builds source metadata for quick assign operations", () => {
|
||||
expect(buildTimelineQuickAssignMetadata("quickAssign")).toEqual({ source: "quickAssign" });
|
||||
expect(buildTimelineQuickAssignMetadata("batchQuickAssign")).toEqual({ source: "batchQuickAssign" });
|
||||
});
|
||||
|
||||
it("builds assignment create payloads for quick assign flows", () => {
|
||||
expect(
|
||||
buildTimelineQuickAssignAssignmentInput({
|
||||
resourceId: "resource_1",
|
||||
projectId: "project_1",
|
||||
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
hoursPerDay: 6,
|
||||
role: "Engineer",
|
||||
roleId: "role_1",
|
||||
status: "PROPOSED",
|
||||
source: "quickAssign",
|
||||
}),
|
||||
).toEqual({
|
||||
resourceId: "resource_1",
|
||||
projectId: "project_1",
|
||||
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
hoursPerDay: 6,
|
||||
percentage: 75,
|
||||
role: "Engineer",
|
||||
roleId: "role_1",
|
||||
status: "PROPOSED",
|
||||
metadata: { source: "quickAssign" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Prisma } from "@capakraken/db";
|
||||
import { AllocationStatus } from "@capakraken/shared";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
export type TimelineBatchShiftMode = "move" | "resize-start" | "resize-end";
|
||||
@@ -32,39 +31,6 @@ export function buildTimelineAllocationMetadata(input: {
|
||||
return { metadata, includeSaturday };
|
||||
}
|
||||
|
||||
export function calculateTimelineAllocationPercentage(hoursPerDay: number): number {
|
||||
return Math.min(100, Math.round((hoursPerDay / 8) * 100));
|
||||
}
|
||||
|
||||
export function buildTimelineQuickAssignMetadata(source: "quickAssign" | "batchQuickAssign") {
|
||||
return { source } satisfies Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function buildTimelineQuickAssignAssignmentInput(input: {
|
||||
resourceId: string;
|
||||
projectId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
hoursPerDay: number;
|
||||
role: string;
|
||||
roleId?: string | undefined;
|
||||
status: AllocationStatus;
|
||||
source: "quickAssign" | "batchQuickAssign";
|
||||
}) {
|
||||
return {
|
||||
resourceId: input.resourceId,
|
||||
projectId: input.projectId,
|
||||
startDate: input.startDate,
|
||||
endDate: input.endDate,
|
||||
hoursPerDay: input.hoursPerDay,
|
||||
percentage: calculateTimelineAllocationPercentage(input.hoursPerDay),
|
||||
role: input.role,
|
||||
...(input.roleId !== undefined ? { roleId: input.roleId } : {}),
|
||||
status: input.status,
|
||||
metadata: buildTimelineQuickAssignMetadata(input.source),
|
||||
};
|
||||
}
|
||||
|
||||
export function validateTimelineAllocationDateRanges(
|
||||
ranges: Array<{ startDate: Date; endDate: Date }>,
|
||||
): void {
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
} from "../sse/event-bus.js";
|
||||
import {
|
||||
assertTimelineDateRangeValid,
|
||||
buildTimelineQuickAssignAssignmentInput,
|
||||
validateTimelineAllocationDateRanges,
|
||||
} from "./timeline-allocation-mutation-support.js";
|
||||
import { buildTimelineQuickAssignAssignmentInput } from "./timeline-allocation-quick-assign-support.js";
|
||||
import { applyTimelineBatchAllocationShift } from "./timeline-allocation-shift-support.js";
|
||||
|
||||
export async function createTimelineQuickAssignment(
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { AllocationStatus } from "@capakraken/shared";
|
||||
|
||||
export function calculateTimelineAllocationPercentage(hoursPerDay: number): number {
|
||||
return Math.min(100, Math.round((hoursPerDay / 8) * 100));
|
||||
}
|
||||
|
||||
export function buildTimelineQuickAssignMetadata(source: "quickAssign" | "batchQuickAssign") {
|
||||
return { source } satisfies Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function buildTimelineQuickAssignAssignmentInput(input: {
|
||||
resourceId: string;
|
||||
projectId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
hoursPerDay: number;
|
||||
role: string;
|
||||
roleId?: string | undefined;
|
||||
status: AllocationStatus;
|
||||
source: "quickAssign" | "batchQuickAssign";
|
||||
}) {
|
||||
return {
|
||||
resourceId: input.resourceId,
|
||||
projectId: input.projectId,
|
||||
startDate: input.startDate,
|
||||
endDate: input.endDate,
|
||||
hoursPerDay: input.hoursPerDay,
|
||||
percentage: calculateTimelineAllocationPercentage(input.hoursPerDay),
|
||||
role: input.role,
|
||||
...(input.roleId !== undefined ? { roleId: input.roleId } : {}),
|
||||
status: input.status,
|
||||
metadata: buildTimelineQuickAssignMetadata(input.source),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user