feat(final-docs): hasRequired/allUploaded on FinalDocumentStatus for optional-uploads mode
This commit is contained in:
@@ -18,6 +18,8 @@ export type FinalDocumentStatus = {
|
|||||||
deadlinePassed: boolean
|
deadlinePassed: boolean
|
||||||
requirements: FinalDocRequirement[]
|
requirements: FinalDocRequirement[]
|
||||||
allRequiredUploaded: boolean
|
allRequiredUploaded: boolean
|
||||||
|
hasRequired: boolean // any slot is marked required
|
||||||
|
allUploaded: boolean // every listed slot has a file (false when no slots exist)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A LIVE_FINAL round is "open for documents" during the lead-up — while it is
|
// A LIVE_FINAL round is "open for documents" during the lead-up — while it is
|
||||||
@@ -94,6 +96,8 @@ export async function getFinalDocumentStatusForProject(
|
|||||||
|
|
||||||
const required = reqStatuses.filter((r) => r.isRequired)
|
const required = reqStatuses.filter((r) => r.isRequired)
|
||||||
const allRequiredUploaded = required.length > 0 && required.every((r) => r.uploaded)
|
const allRequiredUploaded = required.length > 0 && required.every((r) => r.uploaded)
|
||||||
|
const hasRequired = required.length > 0
|
||||||
|
const allUploaded = reqStatuses.length > 0 && reqStatuses.every((r) => r.uploaded)
|
||||||
const deadline = round.windowCloseAt ?? null
|
const deadline = round.windowCloseAt ?? null
|
||||||
return {
|
return {
|
||||||
roundId: round.id,
|
roundId: round.id,
|
||||||
@@ -102,6 +106,8 @@ export async function getFinalDocumentStatusForProject(
|
|||||||
deadlinePassed: deadline ? new Date() > deadline : false,
|
deadlinePassed: deadline ? new Date() > deadline : false,
|
||||||
requirements: reqStatuses,
|
requirements: reqStatuses,
|
||||||
allRequiredUploaded,
|
allRequiredUploaded,
|
||||||
|
hasRequired,
|
||||||
|
allUploaded,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { BUCKET_NAME, generateObjectKey } from '@/lib/minio'
|
|||||||
const programIds: string[] = []
|
const programIds: string[] = []
|
||||||
|
|
||||||
async function makeFinaleProgram(
|
async function makeFinaleProgram(
|
||||||
opts: { roundStatus?: 'ROUND_ACTIVE' | 'ROUND_DRAFT' | 'ROUND_CLOSED'; closeAt?: Date; skipRequirements?: boolean; uploadsEnabled?: boolean } = {},
|
opts: { roundStatus?: 'ROUND_ACTIVE' | 'ROUND_DRAFT' | 'ROUND_CLOSED'; closeAt?: Date; skipRequirements?: boolean; uploadsEnabled?: boolean; optionalRequirements?: boolean } = {},
|
||||||
) {
|
) {
|
||||||
const program = await createTestProgram()
|
const program = await createTestProgram()
|
||||||
programIds.push(program.id)
|
programIds.push(program.id)
|
||||||
@@ -41,10 +41,10 @@ async function makeFinaleProgram(
|
|||||||
return { program, comp, round, reqPlan: undefined, reqVideo: undefined }
|
return { program, comp, round, reqPlan: undefined, reqVideo: undefined }
|
||||||
}
|
}
|
||||||
const reqPlan = await prisma.fileRequirement.create({
|
const reqPlan = await prisma.fileRequirement.create({
|
||||||
data: { id: uid('req'), roundId: round.id, name: 'Final Business Plan', acceptedMimeTypes: ['application/pdf'], isRequired: true, sortOrder: 1 },
|
data: { id: uid('req'), roundId: round.id, name: 'Final Business Plan', acceptedMimeTypes: ['application/pdf'], isRequired: !opts.optionalRequirements, sortOrder: 1 },
|
||||||
})
|
})
|
||||||
const reqVideo = await prisma.fileRequirement.create({
|
const reqVideo = await prisma.fileRequirement.create({
|
||||||
data: { id: uid('req'), roundId: round.id, name: '1-minute Video', acceptedMimeTypes: ['video/*'], isRequired: true, sortOrder: 2 },
|
data: { id: uid('req'), roundId: round.id, name: '1-minute Video', acceptedMimeTypes: ['video/*'], isRequired: !opts.optionalRequirements, sortOrder: 2 },
|
||||||
})
|
})
|
||||||
return { program, comp, round, reqPlan, reqVideo }
|
return { program, comp, round, reqPlan, reqVideo }
|
||||||
}
|
}
|
||||||
@@ -128,6 +128,49 @@ describe('getFinalDocumentStatusForProject', () => {
|
|||||||
expect(status!.requirements).toHaveLength(0)
|
expect(status!.requirements).toHaveLength(0)
|
||||||
expect(status!.allRequiredUploaded).toBe(false)
|
expect(status!.allRequiredUploaded).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('all-optional round: hasRequired false, allUploaded flips when every slot has a file', async () => {
|
||||||
|
const { program, round, reqPlan, reqVideo } = await makeFinaleProgram({ optionalRequirements: true })
|
||||||
|
const project = await createTestProject(program.id)
|
||||||
|
await createTestProjectRoundState(project.id, round.id)
|
||||||
|
|
||||||
|
const before = await getFinalDocumentStatusForProject(prisma, project.id)
|
||||||
|
expect(before!.hasRequired).toBe(false)
|
||||||
|
expect(before!.allUploaded).toBe(false)
|
||||||
|
expect(before!.allRequiredUploaded).toBe(false)
|
||||||
|
|
||||||
|
for (const req of [reqPlan!, reqVideo!]) {
|
||||||
|
await prisma.projectFile.create({
|
||||||
|
data: {
|
||||||
|
id: uid('file'), projectId: project.id, roundId: round.id, requirementId: req.id,
|
||||||
|
fileType: 'SUPPORTING_DOC', fileName: `f-${req.id}`, mimeType: 'application/pdf', size: 10,
|
||||||
|
bucket: 'b', objectKey: uid('key'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const after = await getFinalDocumentStatusForProject(prisma, project.id)
|
||||||
|
expect(after!.hasRequired).toBe(false)
|
||||||
|
expect(after!.allUploaded).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('mixed round: hasRequired true; allUploaded only when optional slots are filled too', async () => {
|
||||||
|
const { program, round, reqPlan } = await makeFinaleProgram()
|
||||||
|
await prisma.fileRequirement.update({ where: { id: reqPlan!.id }, data: { isRequired: false } })
|
||||||
|
const project = await createTestProject(program.id)
|
||||||
|
await createTestProjectRoundState(project.id, round.id)
|
||||||
|
const status = await getFinalDocumentStatusForProject(prisma, project.id)
|
||||||
|
expect(status!.hasRequired).toBe(true) // reqVideo still required
|
||||||
|
expect(status!.allUploaded).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('zero slots: allUploaded false (no vacuous completeness)', 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!.hasRequired).toBe(false)
|
||||||
|
expect(status!.allUploaded).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('applicant.getFinalDocumentStatus', () => {
|
describe('applicant.getFinalDocumentStatus', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user