100 lines
3.5 KiB
TypeScript
100 lines
3.5 KiB
TypeScript
import { loadAllocationEntry, updateAllocationEntry } from "@capakraken/application";
|
|
import type { PrismaClient } from "@capakraken/db";
|
|
import type { RecurrencePattern, WeekdayAvailability } from "@capakraken/shared";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { assertTimelineDateRangeValid } from "./timeline-allocation-mutation-support.js";
|
|
import {
|
|
buildTimelineAllocationEntryUpdate,
|
|
buildTimelineAllocationMetadata,
|
|
buildTimelineAllocationUpdateAuditChanges,
|
|
} from "./timeline-allocation-update-support.js";
|
|
import { calculateTimelineAllocationDailyCost } from "./timeline-cost-support.js";
|
|
|
|
export async function applyTimelineInlineAllocationUpdate(input: {
|
|
db: PrismaClient;
|
|
allocationId: string;
|
|
hoursPerDay?: number | undefined;
|
|
startDate?: Date | undefined;
|
|
endDate?: Date | undefined;
|
|
includeSaturday?: boolean | undefined;
|
|
role?: string | undefined;
|
|
}) {
|
|
const resolved = await loadAllocationEntry(input.db, input.allocationId);
|
|
const existing = resolved.entry;
|
|
const existingResource = resolved.resourceId
|
|
? await input.db.resource.findUnique({
|
|
where: { id: resolved.resourceId },
|
|
select: { id: true, lcrCents: true, availability: true },
|
|
})
|
|
: null;
|
|
|
|
const newHoursPerDay = input.hoursPerDay ?? existing.hoursPerDay;
|
|
const newStartDate = input.startDate ?? existing.startDate;
|
|
const newEndDate = input.endDate ?? existing.endDate;
|
|
|
|
assertTimelineDateRangeValid(newStartDate, newEndDate);
|
|
const { metadata: newMeta, includeSaturday } = buildTimelineAllocationMetadata({
|
|
existingMetadata: existing.metadata as Record<string, unknown> | null | undefined,
|
|
includeSaturday: input.includeSaturday,
|
|
});
|
|
|
|
let newDailyCostCents = 0;
|
|
if (resolved.resourceId) {
|
|
if (!existingResource) {
|
|
throw new TRPCError({ code: "NOT_FOUND", message: "Resource not found" });
|
|
}
|
|
|
|
const availability = existingResource.availability as unknown as WeekdayAvailability;
|
|
const recurrence = newMeta.recurrence as RecurrencePattern | undefined;
|
|
newDailyCostCents = await calculateTimelineAllocationDailyCost({
|
|
db: input.db,
|
|
resourceId: resolved.resourceId,
|
|
lcrCents: existingResource.lcrCents,
|
|
hoursPerDay: newHoursPerDay,
|
|
startDate: newStartDate,
|
|
endDate: newEndDate,
|
|
availability,
|
|
includeSaturday,
|
|
...(recurrence ? { recurrence } : {}),
|
|
});
|
|
}
|
|
|
|
return input.db.$transaction(async (tx) => {
|
|
const { allocation: updatedAllocation } = await updateAllocationEntry(
|
|
tx as unknown as Parameters<typeof updateAllocationEntry>[0],
|
|
{
|
|
id: input.allocationId,
|
|
...buildTimelineAllocationEntryUpdate({
|
|
hoursPerDay: newHoursPerDay,
|
|
startDate: newStartDate,
|
|
endDate: newEndDate,
|
|
metadata: newMeta,
|
|
dailyCostCents: newDailyCostCents,
|
|
role: input.role,
|
|
}),
|
|
},
|
|
);
|
|
|
|
await tx.auditLog.create({
|
|
data: {
|
|
entityType: "Allocation",
|
|
entityId: input.allocationId,
|
|
action: "UPDATE",
|
|
changes: buildTimelineAllocationUpdateAuditChanges({
|
|
allocationId: resolved.entry.id,
|
|
previousHoursPerDay: existing.hoursPerDay,
|
|
previousStartDate: existing.startDate,
|
|
previousEndDate: existing.endDate,
|
|
nextAllocationId: updatedAllocation.id,
|
|
nextHoursPerDay: newHoursPerDay,
|
|
nextStartDate: newStartDate,
|
|
nextEndDate: newEndDate,
|
|
includeSaturday,
|
|
}),
|
|
},
|
|
});
|
|
|
|
return updatedAllocation;
|
|
});
|
|
}
|