Files
dh-inspeccion-v2/api-v3/src/inspection-findings/f3-finding-catalog-resolver.service.ts
T

130 lines
5.0 KiB
TypeScript

import { Injectable, NotFoundException } from '@nestjs/common';
import { DataSource } from 'typeorm';
import type { ListFindingCatalogQueryDto } from './dto/list-finding-catalog-query.dto';
import { FindingCatalogService } from './finding-catalog.service';
@Injectable()
export class F3FindingCatalogResolverService {
constructor(
private readonly dataSource: DataSource,
private readonly contextualCatalog: FindingCatalogService,
) {}
async listApplicableForAsset(assetId: string, query: ListFindingCatalogQueryDto) {
const [asset] = await this.dataSource.query(`
SELECT asset.id,asset.code,asset.name,
type.code AS "typeCode",
asset.inventory_family_id AS "familyId",
family.code AS "familyCode",family.name AS "familyName",family.level AS "familyLevel",
family.is_active AS "familyActive"
FROM assets asset
JOIN asset_types type ON type.id=asset.asset_type_id
LEFT JOIN inventory_families family ON family.id=asset.inventory_family_id
WHERE asset.id=$1::uuid
`, [assetId]) as Array<{
id: string;
code: string;
name: string;
typeCode: string;
familyId: string | null;
familyCode: string | null;
familyName: string | null;
familyLevel: string | null;
familyActive: boolean | null;
}>;
if (!asset) {
throw new NotFoundException({ code: 'ASSET_NOT_FOUND', message: 'Registro de Inventario no encontrado' });
}
const other = {
enabled: true,
code: 'OTHER',
label: 'OTROS',
help: 'Usalo cuando el Hallazgo no exista entre los asociados a este Inventario. Quedará registrado para revisión en oficina.',
};
if (asset.typeCode.toLowerCase() === 'yacimiento') {
const contextual = await this.contextualCatalog.listApplicableForAsset(assetId, query);
return {
...contextual,
inventoryFamily: null,
catalogSource: 'ASSET_TYPE' as const,
configurationReason: contextual.configurationReason
?? 'Hallazgos asociados al tipo Yacimiento. OTROS permanece siempre disponible.',
other,
};
}
if (!asset.familyId || asset.familyActive !== true) {
return {
asset: { id: asset.id, code: asset.code, name: asset.name },
inventoryFamily: null,
catalogSource: 'INVENTORY_FAMILY' as const,
typeConfigured: false,
configurationReason: 'El elemento todavía no tiene una clasificación técnica activa.',
categories: [],
items: [],
other,
};
}
const filters = [
'mapping.inventory_family_id=$1::uuid',
'item.is_active=true',
'category.is_active=true',
'merge_record.source_item_id IS NULL',
];
const params: unknown[] = [asset.familyId];
if (query.categoryId) {
params.push(query.categoryId);
filters.push(`category.id=$${params.length}::uuid`);
}
if (query.search?.trim()) {
params.push(`%${query.search.trim()}%`);
const token = `$${params.length}`;
filters.push(`(item.title ILIKE ${token} OR COALESCE(item.legal_basis,'') ILIKE ${token} OR COALESCE(item.glossary,'') ILIKE ${token})`);
}
const where = filters.join(' AND ');
const [categories, items] = await Promise.all([
this.dataSource.query(`
SELECT DISTINCT category.id,category.code,category.name,category.sort_order AS "sortOrder"
FROM finding_catalog_item_inventory_families mapping
JOIN finding_catalog_items item ON item.id=mapping.catalog_item_id
JOIN finding_categories category ON category.id=item.category_id
LEFT JOIN finding_catalog_item_merges merge_record ON merge_record.source_item_id=item.id
WHERE ${where}
ORDER BY category.sort_order,category.name,category.id
`, params),
this.dataSource.query(`
SELECT item.id,item.category_id AS "categoryId",item.code,
item.source_number AS "sourceNumber",item.title,item.legal_basis AS "legalBasis",
item.glossary,item.suggested_severity AS "suggestedSeverity",item.revision,
category.name AS "categoryName"
FROM finding_catalog_item_inventory_families mapping
JOIN finding_catalog_items item ON item.id=mapping.catalog_item_id
JOIN finding_categories category ON category.id=item.category_id
LEFT JOIN finding_catalog_item_merges merge_record ON merge_record.source_item_id=item.id
WHERE ${where}
ORDER BY category.sort_order,item.source_number,item.code
`, params),
]);
return {
asset: { id: asset.id, code: asset.code, name: asset.name },
inventoryFamily: {
id: asset.familyId,
code: asset.familyCode,
name: asset.familyName,
level: asset.familyLevel,
},
catalogSource: 'INVENTORY_FAMILY' as const,
typeConfigured: true,
configurationReason: `Hallazgos asociados a la clasificación técnica ${asset.familyName ?? asset.familyCode ?? ''}`.trim(),
categories,
items,
other,
};
}
}