feat(informes): manage manual GEDO responses and shared due date
DH V2 CI / WEB · typecheck, build (push) Successful in 27s
Production dependency audit / API · production dependencies (push) Successful in 15s
Production dependency audit / WEB · production dependencies (push) Successful in 15s
DH V2 CI / API · typecheck, tests, build (push) Successful in 2m3s
DH V2 CI / Docker / migrations / production images (push) Successful in 2m58s
DH V2 CI / Promote verified main to deploy (push) Successful in 3s
Android CI / RC / Android · lint, tests, debug APK, release compile (push) Successful in 5m55s
DH V2 CI / WEB · typecheck, build (push) Successful in 27s
Production dependency audit / API · production dependencies (push) Successful in 15s
Production dependency audit / WEB · production dependencies (push) Successful in 15s
DH V2 CI / API · typecheck, tests, build (push) Successful in 2m3s
DH V2 CI / Docker / migrations / production images (push) Successful in 2m58s
DH V2 CI / Promote verified main to deploy (push) Successful in 3s
Android CI / RC / Android · lint, tests, debug APK, release compile (push) Successful in 5m55s
This commit is contained in:
@@ -11,6 +11,8 @@ import {
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
import { administrationAuditContext } from '../administration/common/administration-audit';
|
||||
import { ActAdministrationService, type UploadedActResponseFile } from '../act-administration/act-administration.service';
|
||||
import type { CreateActCompanyResponseDto } from '../act-administration/dto/create-act-company-response.dto';
|
||||
import { AuditService } from '../audit/audit.service';
|
||||
import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context';
|
||||
import {
|
||||
@@ -20,6 +22,7 @@ import {
|
||||
import type { CreateInspectionReportFollowUpDto } from './dto/create-inspection-report-follow-up.dto';
|
||||
import type { OfficializeInspectionReportDto } from './dto/officialize-inspection-report.dto';
|
||||
import type { UpdateInspectionReportDto } from './dto/update-inspection-report.dto';
|
||||
import type { SetInspectionReportResponseDeadlineDto } from './dto/set-inspection-report-response-deadline.dto';
|
||||
|
||||
export const MAX_INSPECTION_REPORT_FILE_BYTES = 40 * 1024 * 1024;
|
||||
|
||||
@@ -56,6 +59,7 @@ export class InspectionReportWorkflowService {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly audit: AuditService,
|
||||
private readonly administration: ActAdministrationService,
|
||||
config: ConfigService,
|
||||
) {
|
||||
const configured = config.get<string>('INSPECTION_REPORT_UPLOAD_ROOT')
|
||||
@@ -220,6 +224,42 @@ export class InspectionReportWorkflowService {
|
||||
}
|
||||
}
|
||||
|
||||
async setResponseDeadline(
|
||||
reportId: string,
|
||||
dto: SetInspectionReportResponseDeadlineDto,
|
||||
principal: AuthPrincipal,
|
||||
request: RequestWithContext,
|
||||
) {
|
||||
const report = await this.requireOfficializedReport(reportId);
|
||||
const reason = dto.reason ?? `Vencimiento general de respuestas definido desde el Informe ${report.code}`;
|
||||
await this.administration.setDeadline(
|
||||
report.actId,
|
||||
{ responseDueOn: dto.responseDueOn, reason },
|
||||
principal,
|
||||
request,
|
||||
report.id,
|
||||
);
|
||||
return this.getWorkflowView(this.dataSource.manager, reportId);
|
||||
}
|
||||
|
||||
async addCompanyResponse(
|
||||
reportId: string,
|
||||
dto: CreateActCompanyResponseDto,
|
||||
file: UploadedActResponseFile | undefined,
|
||||
principal: AuthPrincipal,
|
||||
request: RequestWithContext,
|
||||
) {
|
||||
const report = await this.requireOfficializedReport(reportId);
|
||||
await this.administration.addResponse(report.actId, dto, file, principal, request, report.id);
|
||||
return this.getWorkflowView(this.dataSource.manager, reportId);
|
||||
}
|
||||
|
||||
async companyResponseContent(reportId: string, responseId: string) {
|
||||
const report = await this.getReport(this.dataSource.manager, reportId);
|
||||
if (!report) throw reportNotFound();
|
||||
return this.administration.responseContent(responseId, reportId);
|
||||
}
|
||||
|
||||
async officialPdfContent(reportId: string): Promise<{ filePath: string; originalName: string; mimeType: string }> {
|
||||
const [row] = await this.dataSource.query(`
|
||||
SELECT
|
||||
@@ -300,6 +340,15 @@ export class InspectionReportWorkflowService {
|
||||
try {
|
||||
return await this.dataSource.transaction(async (manager) => {
|
||||
const report = await this.lockReport(manager, reportId);
|
||||
if (
|
||||
(dto.type === 'COMPANY_NOTE' || dto.type === 'COMPANY_DOCUMENT')
|
||||
&& report.status !== InspectionReportStatus.OFFICIALIZED
|
||||
) {
|
||||
throw new ConflictException({
|
||||
code: 'INSPECTION_REPORT_GEDO_REQUIRED_FOR_COMPANY_RESPONSE',
|
||||
message: 'Las respuestas de la empresa se registran después de cargar el PDF oficial de GEDO',
|
||||
});
|
||||
}
|
||||
const occurredAt = new Date(dto.occurredAt);
|
||||
await manager.query(`
|
||||
INSERT INTO inspection_report_follow_ups (
|
||||
@@ -407,6 +456,18 @@ export class InspectionReportWorkflowService {
|
||||
return /^\.[a-z0-9]{1,10}$/.test(ext) ? ext : '';
|
||||
}
|
||||
|
||||
private async requireOfficializedReport(reportId: string): Promise<ReportRow> {
|
||||
const report = await this.getReport(this.dataSource.manager, reportId);
|
||||
if (!report) throw reportNotFound();
|
||||
if (report.status !== InspectionReportStatus.OFFICIALIZED) {
|
||||
throw new ConflictException({
|
||||
code: 'INSPECTION_REPORT_GEDO_REQUIRED',
|
||||
message: 'Primero debe cargarse manualmente el PDF oficial de GEDO',
|
||||
});
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
private async lockReport(manager: EntityManager, id: string): Promise<ReportRow> {
|
||||
const [row] = await manager.query(`
|
||||
SELECT id,act_id AS "actId",visit_id AS "visitId",code,status,
|
||||
|
||||
Reference in New Issue
Block a user