fix: project status counts now show latest round state per project

Previously counted distinct projects per state across ALL rounds,
inflating counts (e.g., 215 Passed when many were later rejected).
Now picks each project's latest round state (highest sortOrder) to
determine its current status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 14:44:14 +01:00
parent 8d6f3ca11f
commit 2be7318cb9

View File

@@ -165,28 +165,40 @@ export const projectRouter = router({
}, },
}), }),
ctx.prisma.project.count({ where }), ctx.prisma.project.count({ where }),
// Count distinct projects per state (avoids double-counting projects that passed multiple rounds) // Count projects by their LATEST round state (highest sortOrder round).
// This avoids inflated counts where a project that passed round 1
// but was rejected in round 2 shows up in both PASSED and REJECTED.
(async () => { (async () => {
const stateFilter = where.programId ? { project: { programId: where.programId as string } } : {} const stateFilter: Record<string, unknown> = {}
const states = ['PENDING', 'IN_PROGRESS', 'PASSED', 'REJECTED', 'COMPLETED', 'WITHDRAWN'] as const if (where.programId) stateFilter.project = { programId: where.programId as string }
const counts = await Promise.all(
states.map(async (state) => ({ const allStates = await ctx.prisma.projectRoundState.findMany({
state, where: stateFilter,
count: await ctx.prisma.projectRoundState.findMany({ select: { projectId: true, state: true, round: { select: { sortOrder: true } } },
where: { ...stateFilter, state }, orderBy: { round: { sortOrder: 'desc' } },
select: { projectId: true }, })
distinct: ['projectId'],
}).then((rows) => rows.length), // Pick the latest round state per project
})) const latestByProject = new Map<string, string>()
) for (const s of allStates) {
return counts if (!latestByProject.has(s.projectId)) {
latestByProject.set(s.projectId, s.state)
}
}
// Aggregate counts
const countMap = new Map<string, number>()
for (const state of latestByProject.values()) {
countMap.set(state, (countMap.get(state) ?? 0) + 1)
}
return countMap
})(), })(),
]) ])
// Build round-state counts (distinct projects per state) // Build round-state counts from the latest-state map
const statusCounts: Record<string, number> = {} const statusCounts: Record<string, number> = {}
for (const g of roundStateCounts) { for (const [state, count] of roundStateCounts) {
statusCounts[g.state] = g.count statusCounts[state] = count
} }
const projectsWithLogos = await attachProjectLogoUrls(projects) const projectsWithLogos = await attachProjectLogoUrls(projects)