From c53ec231099683dd9d18533d4342621b7efb14e9 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 9 Jun 2026 15:15:22 +0200 Subject: [PATCH] fix(final-docs): round-scope file query + guard empty-required edge case --- src/server/services/final-documents.ts | 5 +++-- tests/unit/final-documents.test.ts | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/server/services/final-documents.ts b/src/server/services/final-documents.ts index 1acf75f..bb64670 100644 --- a/src/server/services/final-documents.ts +++ b/src/server/services/final-documents.ts @@ -57,7 +57,7 @@ export async function getFinalDocumentStatusForProject( }) const files = await prisma.projectFile.findMany({ - where: { projectId, requirementId: { in: requirements.map((r) => r.id) } }, + where: { projectId, roundId: round.id, requirementId: { in: requirements.map((r) => r.id) } }, orderBy: { createdAt: 'desc' }, select: { id: true, requirementId: true, fileName: true, mimeType: true, bucket: true, objectKey: true, createdAt: true }, }) @@ -73,7 +73,8 @@ export async function getFinalDocumentStatusForProject( } }) - const allRequiredUploaded = reqStatuses.filter((r) => r.isRequired).every((r) => r.uploaded) + const required = reqStatuses.filter((r) => r.isRequired) + const allRequiredUploaded = required.length > 0 && required.every((r) => r.uploaded) const deadline = round.windowCloseAt ?? null return { roundId: round.id, diff --git a/tests/unit/final-documents.test.ts b/tests/unit/final-documents.test.ts index 3e445b0..c855f51 100644 --- a/tests/unit/final-documents.test.ts +++ b/tests/unit/final-documents.test.ts @@ -13,7 +13,9 @@ import { getFinalDocumentStatusForProject } from '@/server/services/final-docume const programIds: string[] = [] -async function makeFinaleProgram(opts: { roundStatus?: 'ROUND_ACTIVE' | 'ROUND_DRAFT'; closeAt?: Date } = {}) { +async function makeFinaleProgram( + opts: { roundStatus?: 'ROUND_ACTIVE' | 'ROUND_DRAFT'; closeAt?: Date; skipRequirements?: boolean } = {}, +) { const program = await createTestProgram() programIds.push(program.id) const comp = await createTestCompetition(program.id, { status: 'ACTIVE' }) @@ -23,6 +25,9 @@ async function makeFinaleProgram(opts: { roundStatus?: 'ROUND_ACTIVE' | 'ROUND_D sortOrder: 6, windowCloseAt: opts.closeAt ?? new Date(Date.now() + 86_400_000), }) + if (opts.skipRequirements) { + return { program, comp, round, reqPlan: undefined, reqVideo: undefined } + } const reqPlan = await prisma.fileRequirement.create({ data: { id: uid('req'), roundId: round.id, name: 'Final Business Plan', acceptedMimeTypes: ['application/pdf'], isRequired: true, sortOrder: 1 }, }) @@ -61,8 +66,8 @@ describe('getFinalDocumentStatusForProject', () => { const project = await createTestProject(program.id) await createTestProjectRoundState(project.id, round.id) for (const [req, type, mime] of [ - [reqPlan, 'BUSINESS_PLAN', 'application/pdf'], - [reqVideo, 'VIDEO', 'video/mp4'], + [reqPlan!, 'BUSINESS_PLAN', 'application/pdf'], + [reqVideo!, 'VIDEO', 'video/mp4'], ] as const) { await prisma.projectFile.create({ data: { @@ -84,4 +89,14 @@ describe('getFinalDocumentStatusForProject', () => { const status = await getFinalDocumentStatusForProject(prisma, project.id) expect(status).toBeNull() }) + + it('reports allRequiredUploaded false when the round has no required requirements', async () => { + const { program, round } = await makeFinaleProgram({ skipRequirements: true }) + const project = await createTestProject(program.id) + await createTestProjectRoundState(project.id, round.id) + const status = await getFinalDocumentStatusForProject(prisma, project.id) + expect(status).not.toBeNull() + expect(status!.requirements).toHaveLength(0) + expect(status!.allRequiredUploaded).toBe(false) + }) })