From 203443d9c65a6316688f86eb9cd0315c381b62dc Mon Sep 17 00:00:00 2001 From: enlineawork Date: Mon, 7 Sep 2026 16:12:03 -0300 Subject: [PATCH] =?UTF-8?q?F3.2:=20resolver=20Hallazgos=20contra=20Acta=20?= =?UTF-8?q?expl=C3=ADcita?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../field-findings.service.ts | 71 +++++++++++++++++-- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/api-v3/src/inspection-visits/field-findings.service.ts b/api-v3/src/inspection-visits/field-findings.service.ts index 9aa8218..ad1d6ad 100644 --- a/api-v3/src/inspection-visits/field-findings.service.ts +++ b/api-v3/src/inspection-visits/field-findings.service.ts @@ -36,9 +36,15 @@ export class FieldFindingsService { private readonly findings: InspectionFindingsService, ) {} - async options(visitId: string, assetId: string, principal: AuthPrincipal) { + async options( + visitId: string, + assetId: string, + actId: string | undefined, + principal: AuthPrincipal, + ) { const gate = await this.requireGate(visitId, assetId, principal); - const act = await this.requireDraftAct(visitId); + const act = await this.requireDraftAct(visitId, actId); + const assetIncludedInAct = await this.actContainsAsset(act.id, assetId); const [catalog, findings] = await Promise.all([ this.catalog.listApplicableForAsset(assetId, {}), this.findings.listForAct(act.id), @@ -48,21 +54,30 @@ export class FieldFindingsService { context: gate.context, act, capture: gate.capture, + assetIncludedInAct, catalog, findings: findings.data.filter((finding) => finding.assetId === assetId), - canAddAnother: true, + canAddAnother: assetIncludedInAct, + actSelectionMode: actId ? 'EXPLICIT' : 'LEGACY_SINGLE_DRAFT', }; } - async list(visitId: string, assetId: string, principal: AuthPrincipal) { + async list( + visitId: string, + assetId: string, + actId: string | undefined, + principal: AuthPrincipal, + ) { const gate = await this.requireGate(visitId, assetId, principal); - const act = await this.requireDraftAct(visitId); + const act = await this.requireDraftAct(visitId, actId); const findings = await this.findings.listForAct(act.id); return { context: gate.context, act, capture: gate.capture, + assetIncludedInAct: await this.actContainsAsset(act.id, assetId), data: findings.data.filter((finding) => finding.assetId === assetId), + actSelectionMode: actId ? 'EXPLICIT' : 'LEGACY_SINGLE_DRAFT', }; } @@ -74,7 +89,15 @@ export class FieldFindingsService { request: RequestWithContext, ) { const gate = await this.requireGate(visitId, assetId, principal); - const act = await this.requireDraftAct(visitId); + const act = await this.requireDraftAct(visitId, dto.actId); + if (!await this.actContainsAsset(act.id, assetId)) { + throw new ConflictException({ + code: 'FIELD_FINDING_ASSET_NOT_IN_ACT', + message: 'Agregá este Inventario al Acta seleccionada antes de registrar el Hallazgo', + actId: act.id, + assetId, + }); + } const payload: CreateInspectionFindingDto = { assetId, catalogItemId: dto.catalogItemId ?? null, @@ -91,6 +114,7 @@ export class FieldFindingsService { capture: gate.capture, finding, canAddAnother: true, + actSelectionMode: dto.actId ? 'EXPLICIT' : 'LEGACY_SINGLE_DRAFT', }; } @@ -268,7 +292,40 @@ export class FieldFindingsService { }; } - private async requireDraftAct(visitId: string): Promise { + private async actContainsAsset(actId: string, assetId: string): Promise { + const [row] = await this.dataSource.query(` + SELECT EXISTS ( + SELECT 1 FROM inspection_act_assets + WHERE act_id=$1::uuid AND asset_id=$2::uuid AND included=true + ) AS included + `, [actId, assetId]) as Array<{ included: boolean }>; + return Boolean(row?.included); + } + + private async requireDraftAct(visitId: string, requestedActId?: string): Promise { + if (requestedActId) { + const [act] = await this.dataSource.query(` + SELECT id,code,status + FROM inspection_acts + WHERE id=$1::uuid AND visit_id=$2::uuid + `, [requestedActId, visitId]) as DraftActRow[]; + if (!act) { + throw new NotFoundException({ + code: 'FIELD_FINDING_ACT_NOT_FOUND', + message: 'El Acta seleccionada no pertenece a esta inspección', + }); + } + if (act.status !== 'DRAFT') { + throw new ConflictException({ + code: 'FIELD_FINDING_ACT_NOT_DRAFT', + message: 'Los Hallazgos nuevos sólo pueden agregarse a un Acta en borrador', + actId: act.id, + actStatus: act.status, + }); + } + return act; + } + const rows = await this.dataSource.query(` SELECT id, code, status FROM inspection_acts