cd78f72f33
Complete rename of all technical identifiers across the codebase: Package names (11 packages): - @planarchy/* → @capakraken/* in all package.json, tsconfig, imports Import statements: 277 files, 548 occurrences replaced Database & Docker: - PostgreSQL user/db: planarchy → capakraken - Docker volumes: planarchy_pgdata → capakraken_pgdata - Connection strings updated in docker-compose, .env, CI CI/CD: - GitHub Actions workflow: all filter commands updated - Test database credentials updated Infrastructure: - Redis channel: planarchy:sse → capakraken:sse - Logger service name: planarchy-api → capakraken-api - Anonymization seed updated - Start/stop/restart scripts updated Test data: - Seed emails: @planarchy.dev → @capakraken.dev - E2E test credentials: all 11 spec files updated - Email defaults: @planarchy.app → @capakraken.app - localStorage keys: planarchy_* → capakraken_* Documentation: 30+ .md files updated Verification: - pnpm install: workspace resolution works - TypeScript: only pre-existing TS2589 (no new errors) - Engine: 310/310 tests pass - Staffing: 37/37 tests pass Co-Authored-By: claude-flow <ruv@ruv.net>
130 lines
3.0 KiB
TypeScript
130 lines
3.0 KiB
TypeScript
import type { Prisma, PrismaClient } from "@capakraken/db";
|
|
import { buildSplitAllocationReadModel } from "./build-split-allocation-read-model.js";
|
|
|
|
type DbClient =
|
|
| Pick<PrismaClient, "demandRequirement" | "assignment">
|
|
| Pick<Prisma.TransactionClient, "demandRequirement" | "assignment">;
|
|
|
|
export interface CountPlanningEntriesInput {
|
|
projectIds?: string[];
|
|
roleIds?: string[];
|
|
}
|
|
|
|
export interface CountPlanningEntriesResult {
|
|
countsByProjectId: Map<string, number>;
|
|
countsByRoleId: Map<string, number>;
|
|
totalCount: number;
|
|
}
|
|
|
|
function normalizeIds(ids?: string[]): string[] | undefined {
|
|
if (!ids) {
|
|
return undefined;
|
|
}
|
|
|
|
const normalized = [...new Set(ids.filter(Boolean))];
|
|
return normalized.length > 0 ? normalized : undefined;
|
|
}
|
|
|
|
function buildScopedWhere(input: CountPlanningEntriesInput) {
|
|
const projectIds = normalizeIds(input.projectIds);
|
|
const roleIds = normalizeIds(input.roleIds);
|
|
|
|
if (input.projectIds && !projectIds) {
|
|
return null;
|
|
}
|
|
|
|
if (input.roleIds && !roleIds) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
...(projectIds ? { projectId: { in: projectIds } } : {}),
|
|
...(roleIds ? { roleId: { in: roleIds } } : {}),
|
|
};
|
|
}
|
|
|
|
export async function countPlanningEntries(
|
|
db: DbClient,
|
|
input: CountPlanningEntriesInput = {},
|
|
): Promise<CountPlanningEntriesResult> {
|
|
const scopedWhere = buildScopedWhere(input);
|
|
if (scopedWhere === null) {
|
|
return {
|
|
countsByProjectId: new Map(),
|
|
countsByRoleId: new Map(),
|
|
totalCount: 0,
|
|
};
|
|
}
|
|
|
|
const [demandRequirements, assignments] = await Promise.all([
|
|
db.demandRequirement.findMany({
|
|
where: scopedWhere,
|
|
select: {
|
|
id: true,
|
|
|
|
projectId: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
hoursPerDay: true,
|
|
percentage: true,
|
|
role: true,
|
|
roleId: true,
|
|
headcount: true,
|
|
status: true,
|
|
metadata: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
},
|
|
}),
|
|
db.assignment.findMany({
|
|
where: scopedWhere,
|
|
select: {
|
|
id: true,
|
|
|
|
demandRequirementId: true,
|
|
resourceId: true,
|
|
projectId: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
hoursPerDay: true,
|
|
percentage: true,
|
|
role: true,
|
|
roleId: true,
|
|
dailyCostCents: true,
|
|
status: true,
|
|
metadata: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
},
|
|
}),
|
|
]);
|
|
|
|
const readModel = buildSplitAllocationReadModel({
|
|
demandRequirements,
|
|
assignments,
|
|
});
|
|
|
|
const countsByProjectId = new Map<string, number>();
|
|
const countsByRoleId = new Map<string, number>();
|
|
|
|
for (const allocation of readModel.allocations) {
|
|
countsByProjectId.set(
|
|
allocation.projectId,
|
|
(countsByProjectId.get(allocation.projectId) ?? 0) + 1,
|
|
);
|
|
|
|
if (allocation.roleId) {
|
|
countsByRoleId.set(
|
|
allocation.roleId,
|
|
(countsByRoleId.get(allocation.roleId) ?? 0) + 1,
|
|
);
|
|
}
|
|
}
|
|
|
|
return {
|
|
countsByProjectId,
|
|
countsByRoleId,
|
|
totalCount: readModel.allocations.length,
|
|
};
|
|
}
|