F4: add explicit inspection unplan lifecycle action

This commit is contained in:
2026-09-07 23:08:34 -03:00
parent 69bc720899
commit 0a6500fbff
@@ -43,7 +43,6 @@ export class InspectionVisitLifecycleService {
});
}
await this.validatePlanningContext(manager, visit);
const before = visit.status;
visit.status = InspectionVisitStatus.PLANNED;
visit.cancellationReason = null;
visit.updatedBy = principal.userId;
@@ -53,7 +52,7 @@ export class InspectionVisitLifecycleService {
action: AuditAction.INSPECTION_VISIT_STATUS_CHANGED,
entityType: 'inspection_visit',
entityId: id,
beforeData: { status: before },
beforeData: { status: InspectionVisitStatus.DRAFT },
afterData: { status: InspectionVisitStatus.PLANNED },
metadata: { transition: 'PLAN' },
}, manager);
@@ -61,6 +60,48 @@ export class InspectionVisitLifecycleService {
return this.visits.getById(id);
}
async unplan(
id: string,
principal: AuthPrincipal,
request: RequestWithContext,
) {
await this.dataSource.transaction(async (manager) => {
const visit = await this.lockVisit(manager, id);
if (visit.status !== InspectionVisitStatus.PLANNED) {
throw new ConflictException({
code: 'INSPECTION_NOT_PLANNED_FOR_UNPLAN',
message: 'Sólo una Inspección planificada puede volver a borrador',
});
}
const [startedAct] = await manager.query(`
SELECT 1
FROM inspection_acts act
WHERE act.visit_id=$1
AND act.status NOT IN ('DRAFT','CANCELLED')
LIMIT 1
`, [id]) as unknown[];
if (startedAct) {
throw new ConflictException({
code: 'INSPECTION_UNPLAN_ACT_ALREADY_ADVANCED',
message: 'La Inspección ya tiene un Acta avanzada y no puede volver a borrador',
});
}
visit.status = InspectionVisitStatus.DRAFT;
visit.updatedBy = principal.userId;
await manager.getRepository(InspectionVisit).save(visit);
await this.audit.record({
...administrationAuditContext(principal, request),
action: AuditAction.INSPECTION_VISIT_STATUS_CHANGED,
entityType: 'inspection_visit',
entityId: id,
beforeData: { status: InspectionVisitStatus.PLANNED },
afterData: { status: InspectionVisitStatus.DRAFT },
metadata: { transition: 'UNPLAN', explicitAction: true },
}, manager);
});
return this.visits.getById(id);
}
async start(
id: string,
principal: AuthPrincipal,