170 lines
5.2 KiB
TypeScript
170 lines
5.2 KiB
TypeScript
import {
|
|
buildSplitAllocationReadModel,
|
|
createAssignment,
|
|
} from "@capakraken/application";
|
|
import type { PrismaClient } from "@capakraken/db";
|
|
import {
|
|
AllocationStatus,
|
|
PermissionKey,
|
|
UpdateAllocationHoursSchema,
|
|
} from "@capakraken/shared";
|
|
import { z } from "zod";
|
|
import {
|
|
emitAllocationCreated,
|
|
emitAllocationUpdated,
|
|
} from "../sse/event-bus.js";
|
|
import { managerProcedure, requirePermission } from "../trpc.js";
|
|
import {
|
|
assertTimelineDateRangeValid,
|
|
buildTimelineQuickAssignAssignmentInput,
|
|
validateTimelineAllocationDateRanges,
|
|
} from "./timeline-allocation-mutation-support.js";
|
|
import { applyTimelineInlineAllocationUpdate } from "./timeline-allocation-inline-support.js";
|
|
import { applyTimelineBatchAllocationShift } from "./timeline-allocation-shift-support.js";
|
|
|
|
export const timelineAllocationMutationProcedures = {
|
|
updateAllocationInline: managerProcedure
|
|
.input(UpdateAllocationHoursSchema)
|
|
.mutation(async ({ ctx, input }) => {
|
|
requirePermission(ctx, PermissionKey.MANAGE_ALLOCATIONS);
|
|
const updated = await applyTimelineInlineAllocationUpdate({
|
|
db: ctx.db as PrismaClient,
|
|
allocationId: input.allocationId,
|
|
hoursPerDay: input.hoursPerDay,
|
|
startDate: input.startDate,
|
|
endDate: input.endDate,
|
|
includeSaturday: input.includeSaturday,
|
|
role: input.role,
|
|
});
|
|
|
|
emitAllocationUpdated({
|
|
id: updated.id,
|
|
projectId: updated.projectId,
|
|
resourceId: updated.resourceId,
|
|
});
|
|
|
|
return updated;
|
|
}),
|
|
|
|
quickAssign: managerProcedure
|
|
.input(
|
|
z.object({
|
|
resourceId: z.string(),
|
|
projectId: z.string(),
|
|
startDate: z.coerce.date(),
|
|
endDate: z.coerce.date(),
|
|
hoursPerDay: z.number().min(0.5).max(24).default(8),
|
|
role: z.string().min(1).max(200).default("Team Member"),
|
|
roleId: z.string().optional(),
|
|
status: z.nativeEnum(AllocationStatus).default(AllocationStatus.PROPOSED),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
requirePermission(ctx, PermissionKey.MANAGE_ALLOCATIONS);
|
|
assertTimelineDateRangeValid(input.startDate, input.endDate);
|
|
|
|
const allocation = await ctx.db.$transaction(async (tx) => {
|
|
const assignment = await createAssignment(
|
|
tx as unknown as Parameters<typeof createAssignment>[0],
|
|
buildTimelineQuickAssignAssignmentInput({
|
|
...input,
|
|
source: "quickAssign",
|
|
}),
|
|
);
|
|
|
|
return buildSplitAllocationReadModel({
|
|
demandRequirements: [],
|
|
assignments: [assignment],
|
|
}).allocations[0]!;
|
|
});
|
|
|
|
emitAllocationCreated({
|
|
id: allocation.id,
|
|
projectId: allocation.projectId,
|
|
resourceId: allocation.resourceId,
|
|
});
|
|
|
|
return allocation;
|
|
}),
|
|
|
|
batchQuickAssign: managerProcedure
|
|
.input(
|
|
z.object({
|
|
assignments: z
|
|
.array(
|
|
z.object({
|
|
resourceId: z.string(),
|
|
projectId: z.string(),
|
|
startDate: z.coerce.date(),
|
|
endDate: z.coerce.date(),
|
|
hoursPerDay: z.number().min(0.5).max(24).default(8),
|
|
role: z.string().min(1).max(200).default("Team Member"),
|
|
status: z
|
|
.nativeEnum(AllocationStatus)
|
|
.default(AllocationStatus.PROPOSED),
|
|
}),
|
|
)
|
|
.min(1)
|
|
.max(50),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
requirePermission(ctx, PermissionKey.MANAGE_ALLOCATIONS);
|
|
validateTimelineAllocationDateRanges(input.assignments);
|
|
|
|
const results = await ctx.db.$transaction(async (tx) => {
|
|
const created = [];
|
|
for (const assignment of input.assignments) {
|
|
const createdAssignment = await createAssignment(
|
|
tx as unknown as Parameters<typeof createAssignment>[0],
|
|
buildTimelineQuickAssignAssignmentInput({
|
|
...assignment,
|
|
source: "batchQuickAssign",
|
|
}),
|
|
);
|
|
created.push(createdAssignment);
|
|
}
|
|
return created;
|
|
});
|
|
|
|
for (const assignment of results) {
|
|
emitAllocationCreated({
|
|
id: assignment.id,
|
|
projectId: assignment.projectId,
|
|
resourceId: assignment.resourceId,
|
|
});
|
|
}
|
|
|
|
return { count: results.length };
|
|
}),
|
|
|
|
batchShiftAllocations: managerProcedure
|
|
.input(
|
|
z.object({
|
|
allocationIds: z.array(z.string()).min(1).max(100),
|
|
daysDelta: z.number().int().min(-3650).max(3650),
|
|
mode: z.enum(["move", "resize-start", "resize-end"]).default("move"),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
requirePermission(ctx, PermissionKey.MANAGE_ALLOCATIONS);
|
|
|
|
const results = await applyTimelineBatchAllocationShift({
|
|
db: ctx.db as PrismaClient,
|
|
allocationIds: input.allocationIds,
|
|
daysDelta: input.daysDelta,
|
|
mode: input.mode,
|
|
});
|
|
|
|
for (const allocation of results) {
|
|
emitAllocationUpdated({
|
|
id: allocation.id,
|
|
projectId: allocation.projectId,
|
|
resourceId: allocation.resourceId,
|
|
});
|
|
}
|
|
|
|
return { count: results.length };
|
|
}),
|
|
};
|