diff --git a/api-v3/src/inspection-reports/inspection-report-workflow.service.ts b/api-v3/src/inspection-reports/inspection-report-workflow.service.ts index 41d06d3..1ef9d01 100644 --- a/api-v3/src/inspection-reports/inspection-report-workflow.service.ts +++ b/api-v3/src/inspection-reports/inspection-report-workflow.service.ts @@ -5,7 +5,6 @@ import { BadRequestException, ConflictException, Injectable, - InternalServerErrorException, NotFoundException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @@ -15,9 +14,6 @@ import { AuditService } from '../audit/audit.service'; import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context'; import { AuditAction, - InspectionActUrgency, - InspectionDeadlineBasis, - InspectionDeadlineDayType, InspectionReportStatus, } from '../database/entities'; import type { CreateInspectionReportFollowUpDto } from './dto/create-inspection-report-follow-up.dto'; @@ -169,7 +165,9 @@ export class InspectionReportWorkflowService { file!.buffer.length, sha256, ]); - await this.activateNonUrgentDeadline(manager, report.actId, officializedAt); + // GEDO oficializa el INF, pero no equivale por sí solo a la notificación + // administrativa de un Acta no urgente. El vencimiento queda pendiente + // hasta que el procedimiento defina y registre el evento de notificación. await this.audit.record({ ...administrationAuditContext(principal, request), action: AuditAction.INSPECTION_REPORT_OFFICIALIZED, @@ -182,7 +180,12 @@ export class InspectionReportWorkflowService { gedoPdfOriginalName: file!.originalname, gedoPdfSha256: sha256, }, - metadata: { reportCode: report.code, actId: report.actId, immutable: true }, + metadata: { + reportCode: report.code, + actId: report.actId, + immutable: true, + deadlineActivation: 'PENDING_NOTIFICATION_EVENT', + }, }, manager); return this.getWorkflowView(manager, reportId); }); @@ -288,84 +291,6 @@ export class InspectionReportWorkflowService { `, [reportId]); } - private async activateNonUrgentDeadline( - manager: EntityManager, - actId: string, - officializedAt: Date, - ): Promise { - const [act] = await manager.query(` - SELECT urgency,deadline_days AS "deadlineDays",deadline_day_type AS "deadlineDayType", - deadline_basis AS "deadlineBasis",deadline_at AS "deadlineAt" - FROM inspection_acts WHERE id=$1 FOR UPDATE - `, [actId]) as Array<{ - urgency: InspectionActUrgency; - deadlineDays: number | null; - deadlineDayType: InspectionDeadlineDayType | null; - deadlineBasis: InspectionDeadlineBasis | null; - deadlineAt: Date | null; - }>; - if (!act) return; - if (act.urgency !== InspectionActUrgency.NON_URGENT) return; - if (act.deadlineBasis !== InspectionDeadlineBasis.GEDO_DATE) { - throw new ConflictException({ - code: 'INVALID_NON_URGENT_DEADLINE_BASIS', - message: 'El acta no urgente no conserva la regla GEDO necesaria para calcular su vencimiento', - }); - } - if (!act.deadlineDays || !act.deadlineDayType) { - throw new ConflictException({ - code: 'MISSING_ACT_DEADLINE_SNAPSHOT', - message: 'El acta no conserva la política de plazo aplicada al momento de finalizarse', - }); - } - const deadlineAt = await this.calculateDeadline( - manager, - officializedAt, - Number(act.deadlineDays), - act.deadlineDayType, - ); - await manager.query(` - UPDATE inspection_acts - SET deadline_base_at=$2,deadline_at=$3,updated_at=CURRENT_TIMESTAMP - WHERE id=$1 - `, [actId, officializedAt, deadlineAt]); - } - - private async calculateDeadline( - manager: EntityManager, - baseAt: Date, - days: number, - dayType: InspectionDeadlineDayType, - ): Promise { - if (dayType === InspectionDeadlineDayType.CALENDAR) { - const [row] = await manager.query(` - SELECT ( - (($1::timestamptz AT TIME ZONE 'America/Argentina/Mendoza')::date + $2::integer)::timestamp - + time '23:59:59' - ) AT TIME ZONE 'America/Argentina/Mendoza' AS due_at - `, [baseAt, days]) as Array<{ due_at: Date }>; - return row.due_at; - } - const [row] = await manager.query(` - WITH candidates AS ( - SELECT day::date AS day, - COALESCE(override.is_business_day, EXTRACT(ISODOW FROM day)::integer BETWEEN 1 AND 5) AS business - FROM generate_series( - (($1::timestamptz AT TIME ZONE 'America/Argentina/Mendoza')::date + 1)::timestamp, - (($1::timestamptz AT TIME ZONE 'America/Argentina/Mendoza')::date + 730)::timestamp, - interval '1 day' - ) day - LEFT JOIN inspection_business_calendar_days override ON override.date=day::date - ), ranked AS ( - SELECT day,ROW_NUMBER() OVER (ORDER BY day) AS position FROM candidates WHERE business=true - ) - SELECT ((day::timestamp + time '23:59:59') AT TIME ZONE 'America/Argentina/Mendoza') AS due_at - FROM ranked WHERE position=$2 LIMIT 1 - `, [baseAt, days]) as Array<{ due_at: Date }>; - if (!row?.due_at) throw new InternalServerErrorException('No se pudo calcular el vencimiento'); - return row.due_at; - } - private assertPdf(file: UploadedInspectionReportFile | undefined): void { if (!file?.buffer?.length) { throw new BadRequestException({