F2.3: crear servicio de hallazgos desde Inventario
This commit is contained in:
@@ -0,0 +1,107 @@
|
|||||||
|
import { ConflictException, Injectable } from '@nestjs/common';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context';
|
||||||
|
import { FindingCatalogService } from '../inspection-findings/finding-catalog.service';
|
||||||
|
import type { CreateInspectionFindingDto } from '../inspection-findings/dto/create-inspection-finding.dto';
|
||||||
|
import { InspectionFindingsService } from '../inspection-findings/inspection-findings.service';
|
||||||
|
import type { CreateFieldFindingDto } from './dto/create-field-finding.dto';
|
||||||
|
import { FieldInventoryService } from './field-inventory.service';
|
||||||
|
|
||||||
|
interface DraftActRow {
|
||||||
|
id: string;
|
||||||
|
code: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FieldFindingsService {
|
||||||
|
constructor(
|
||||||
|
private readonly dataSource: DataSource,
|
||||||
|
private readonly fieldInventory: FieldInventoryService,
|
||||||
|
private readonly catalog: FindingCatalogService,
|
||||||
|
private readonly findings: InspectionFindingsService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async options(visitId: string, assetId: string, principal: AuthPrincipal) {
|
||||||
|
const gate = await this.fieldInventory.requireReadyForFinding(visitId, assetId, principal);
|
||||||
|
const act = await this.requireDraftAct(visitId);
|
||||||
|
const [catalog, findings] = await Promise.all([
|
||||||
|
this.catalog.listApplicableForAsset(assetId, {}),
|
||||||
|
this.findings.listForAct(act.id),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
context: gate.context,
|
||||||
|
act,
|
||||||
|
capture: gate.capture,
|
||||||
|
catalog,
|
||||||
|
findings: findings.data.filter((finding) => finding.assetId === assetId),
|
||||||
|
canAddAnother: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(visitId: string, assetId: string, principal: AuthPrincipal) {
|
||||||
|
const gate = await this.fieldInventory.requireReadyForFinding(visitId, assetId, principal);
|
||||||
|
const act = await this.requireDraftAct(visitId);
|
||||||
|
const findings = await this.findings.listForAct(act.id);
|
||||||
|
return {
|
||||||
|
context: gate.context,
|
||||||
|
act,
|
||||||
|
capture: gate.capture,
|
||||||
|
data: findings.data.filter((finding) => finding.assetId === assetId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
visitId: string,
|
||||||
|
assetId: string,
|
||||||
|
dto: CreateFieldFindingDto,
|
||||||
|
principal: AuthPrincipal,
|
||||||
|
request: RequestWithContext,
|
||||||
|
) {
|
||||||
|
const gate = await this.fieldInventory.requireReadyForFinding(visitId, assetId, principal);
|
||||||
|
const act = await this.requireDraftAct(visitId);
|
||||||
|
const payload: CreateInspectionFindingDto = {
|
||||||
|
assetId,
|
||||||
|
catalogItemId: dto.catalogItemId ?? null,
|
||||||
|
customTitle: dto.customTitle ?? null,
|
||||||
|
customLegalBasis: dto.customLegalBasis ?? null,
|
||||||
|
description: dto.description,
|
||||||
|
severity: dto.severity,
|
||||||
|
correctionDueOn: dto.correctionDueOn ?? null,
|
||||||
|
};
|
||||||
|
const finding = await this.findings.create(act.id, payload, principal, request);
|
||||||
|
return {
|
||||||
|
context: gate.context,
|
||||||
|
act,
|
||||||
|
capture: gate.capture,
|
||||||
|
finding,
|
||||||
|
canAddAnother: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async requireDraftAct(visitId: string): Promise<DraftActRow> {
|
||||||
|
const rows = await this.dataSource.query(`
|
||||||
|
SELECT id, code, status
|
||||||
|
FROM inspection_acts
|
||||||
|
WHERE visit_id = $1::uuid
|
||||||
|
AND status = 'DRAFT'
|
||||||
|
ORDER BY created_at DESC, id DESC
|
||||||
|
LIMIT 2
|
||||||
|
`, [visitId]) as DraftActRow[];
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
throw new ConflictException({
|
||||||
|
code: 'FIELD_FINDING_DRAFT_ACT_REQUIRED',
|
||||||
|
message: 'La inspección no tiene un Acta borrador abierta para registrar hallazgos',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (rows.length > 1) {
|
||||||
|
throw new ConflictException({
|
||||||
|
code: 'FIELD_FINDING_MULTIPLE_DRAFT_ACTS',
|
||||||
|
message: 'La inspección tiene más de un Acta borrador. Debe resolverse antes de continuar',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rows[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user