import type { Prisma, PrismaClient, StoryStatus } from '@prisma/client' export type EligibilityReason = 'DONE' | 'IN_OTHER_SPRINT' export type CrossSprintBlock = { storyId: string sprintId: string sprintName: string } export type EligibilityPartition = { eligible: string[] notEligible: { storyId: string; reason: EligibilityReason }[] crossSprint: CrossSprintBlock[] } type StoryEligibilityInput = { sprint_id: string | null status: StoryStatus } export function isEligibleForSprint(story: StoryEligibilityInput): boolean { return story.sprint_id === null && story.status !== 'DONE' } type PrismaLike = Pick | Prisma.TransactionClient export async function partitionByEligibility( prisma: PrismaLike, storyIds: string[], excludeSprintId?: string, ): Promise { if (storyIds.length === 0) { return { eligible: [], notEligible: [], crossSprint: [] } } const stories = await prisma.story.findMany({ where: { id: { in: storyIds } }, select: { id: true, sprint_id: true, status: true, sprint: { select: { id: true, code: true, status: true } }, }, }) const eligible: string[] = [] const notEligible: { storyId: string; reason: EligibilityReason }[] = [] const crossSprint: CrossSprintBlock[] = [] for (const story of stories) { const inOtherSprint = story.sprint_id !== null && story.sprint_id !== excludeSprintId const inSameSprint = excludeSprintId !== undefined && story.sprint_id === excludeSprintId if (inOtherSprint) { if (story.sprint && story.sprint.status === 'OPEN') { crossSprint.push({ storyId: story.id, sprintId: story.sprint.id, sprintName: story.sprint.code, }) } notEligible.push({ storyId: story.id, reason: 'IN_OTHER_SPRINT' }) continue } if (story.status === 'DONE') { notEligible.push({ storyId: story.id, reason: 'DONE' }) continue } if (inSameSprint) { eligible.push(story.id) continue } eligible.push(story.id) } return { eligible, notEligible, crossSprint } } export async function getBlockingSprintMap( prisma: PrismaLike, productId: string, storyIds: string[], excludeSprintId?: string, ): Promise> { const out = new Map() if (storyIds.length === 0) return out const stories = await prisma.story.findMany({ where: { id: { in: storyIds }, product_id: productId, sprint_id: { not: null }, sprint: { status: 'OPEN' }, }, select: { id: true, sprint_id: true, sprint: { select: { id: true, code: true, status: true } }, }, }) for (const story of stories) { if (!story.sprint) continue if (excludeSprintId !== undefined && story.sprint.id === excludeSprintId) continue out.set(story.id, { sprintId: story.sprint.id, sprintName: story.sprint.code, }) } return out }