chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import type { PrismaClient } from "@planarchy/db";
|
||||
import { listAssignmentBookings } from "../allocation/list-assignment-bookings.js";
|
||||
import { getAverageDailyAvailabilityHours, getMonthBucketKey, getWeekBucketKey } from "./shared.js";
|
||||
|
||||
export interface GetDashboardPeakTimesInput {
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
granularity: "week" | "month";
|
||||
groupBy: "project" | "chapter" | "resource";
|
||||
}
|
||||
|
||||
export async function getDashboardPeakTimes(
|
||||
db: PrismaClient,
|
||||
input: GetDashboardPeakTimesInput,
|
||||
) {
|
||||
const allocations = await listAssignmentBookings(db, {
|
||||
startDate: input.startDate,
|
||||
endDate: input.endDate,
|
||||
});
|
||||
|
||||
const buckets = new Map<string, Map<string, number>>();
|
||||
|
||||
const getBucketKey = input.granularity === "week" ? getWeekBucketKey : getMonthBucketKey;
|
||||
|
||||
for (const allocation of allocations) {
|
||||
const allocStart = new Date(
|
||||
Math.max(allocation.startDate.getTime(), input.startDate.getTime()),
|
||||
);
|
||||
const allocEnd = new Date(
|
||||
Math.min(allocation.endDate.getTime(), input.endDate.getTime()),
|
||||
);
|
||||
const group =
|
||||
input.groupBy === "project"
|
||||
? allocation.project.shortCode
|
||||
: input.groupBy === "chapter"
|
||||
? allocation.resource?.chapter ?? "Unassigned"
|
||||
: allocation.resource?.displayName ?? "Unknown";
|
||||
|
||||
const cursor = new Date(allocStart);
|
||||
while (cursor <= allocEnd) {
|
||||
const bucketKey = getBucketKey(cursor);
|
||||
if (!buckets.has(bucketKey)) {
|
||||
buckets.set(bucketKey, new Map());
|
||||
}
|
||||
|
||||
const bucket = buckets.get(bucketKey)!;
|
||||
bucket.set(group, (bucket.get(group) ?? 0) + allocation.hoursPerDay);
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const resources = await db.resource.findMany({
|
||||
where: { isActive: true },
|
||||
select: { availability: true },
|
||||
});
|
||||
|
||||
const dailyCapacityHours = resources.reduce(
|
||||
(sum, resource) =>
|
||||
sum +
|
||||
getAverageDailyAvailabilityHours(
|
||||
resource.availability as Record<string, number | null | undefined>,
|
||||
),
|
||||
0,
|
||||
);
|
||||
|
||||
return [...buckets.entries()]
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([period, groups]) => ({
|
||||
period,
|
||||
groups: [...groups.entries()].map(([name, hours]) => ({ name, hours })),
|
||||
totalHours: [...groups.values()].reduce((sum, hours) => sum + hours, 0),
|
||||
capacityHours:
|
||||
dailyCapacityHours * (input.granularity === "week" ? 5 : 22),
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user