diff --git a/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts b/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts index 013bfbe..cb1c4c5 100644 --- a/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts +++ b/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts @@ -174,6 +174,7 @@ export class InspectionVisitLifecycleService { pendingActs: pending.map((act) => ({ id: act.id, code: act.code, status: act.status })), }); } + await this.assertVerificationResultsComplete(manager, id); const serverClosedAt = new Date(); const clientClosedAt = new Date(dto.clientClosedAt); @@ -216,6 +217,7 @@ export class InspectionVisitLifecycleService { transition: 'CLOSE', source: 'ANDROID', allActsSealed: true, + allVerificationResultsRecorded: true, }, }, manager); }); @@ -277,6 +279,22 @@ export class InspectionVisitLifecycleService { return visit; } + private async assertVerificationResultsComplete(manager: EntityManager, inspectionId: string): Promise { + const [row] = await manager.query(` + SELECT + COUNT(*)::integer AS total, + COUNT(*) FILTER (WHERE outcome IS NOT NULL)::integer AS completed + FROM inspection_finding_verification_visits + WHERE visit_id=$1 + `, [inspectionId]) as Array<{ total: number; completed: number }>; + if (Number(row?.total ?? 0) > 0 && Number(row.completed) !== Number(row.total)) { + throw new ConflictException({ + code: 'INSPECTION_VERIFICATION_RESULTS_REQUIRED', + message: 'Registrá el resultado de todas las verificaciones antes de cerrar la Inspección', + }); + } + } + private async validatePlanningContext(manager: EntityManager, visit: InspectionVisit): Promise { if (!visit.operationalAreaId || !visit.operatorCompanyId || !visit.leadInspectorUserId || !visit.plannedStartAt) { throw new ConflictException({