diff --git a/api-v3/src/database/migrations/1790087300000-f5-authoritative-inventory-catalog.ts b/api-v3/src/database/migrations/1790087300000-f5-authoritative-inventory-catalog.ts index 14ebb6c..85de72a 100644 --- a/api-v3/src/database/migrations/1790087300000-f5-authoritative-inventory-catalog.ts +++ b/api-v3/src/database/migrations/1790087300000-f5-authoritative-inventory-catalog.ts @@ -13,6 +13,7 @@ const CATALOG_DOCUMENT_NUMBER = 'DH-F5-INVENTORY-CATALOG'; const CATALOG_CATEGORY_CODE = 'F5MODEL'; const CATALOG_SOURCE_NAME = 'final_modelov2.xlsx'; const F5_AUTO_REASON = 'F5 familia técnica: catálogo contextual automático'; +const F5_SOURCE_FAMILY_COUNT = 123; function findingKey(value: string): string { return value.normalize('NFD') @@ -289,22 +290,23 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn throw new Error(`F5 finding preload verification failed: ${itemCount?.total ?? 0}`); } - const [universalMappingCount] = (await queryRunner.query(` - SELECT COUNT(DISTINCT mapping.inventory_family_id)::integer AS total - FROM finding_catalog_item_inventory_families mapping - JOIN finding_catalog_items item ON item.id=mapping.catalog_item_id - JOIN inventory_families family ON family.id=mapping.inventory_family_id - WHERE item.category_id=$1::uuid - AND lower(regexp_replace(unaccent(item.title),'[^a-zA-Z0-9]+',' ','g')) - IN ( - lower(regexp_replace(unaccent('ORDEN Y LIMPIEZA'),'[^a-zA-Z0-9]+',' ','g')), - lower(regexp_replace(unaccent('CARTELERIA PREVENTIVA / INFORMATIVA'),'[^a-zA-Z0-9]+',' ','g')), - lower(regexp_replace(unaccent('EXTINTORES'),'[^a-zA-Z0-9]+',' ','g')) - ) - AND family.source_reference LIKE 'F5:${CATALOG_SOURCE_NAME}%' - `,[categoryId])) as CountRow[]; - if (Number(universalMappingCount?.total ?? 0)!==123) { - throw new Error(`F5 universal mapping verification failed: ${universalMappingCount?.total ?? 0}`); + // Verify every universal finding is independently attached to every one of + // the 14 + 109 source families. This intentionally avoids optional DB text + // extensions such as unaccent. + for (const universalTitle of source.catalogSource.universalFindings) { + const universalItemId = itemIdByKey.get(findingKey(universalTitle)); + if (!universalItemId) throw new Error(`F5 missing universal catalog item ${universalTitle}`); + const [mappedCount] = (await queryRunner.query(` + SELECT COUNT(DISTINCT mapping.inventory_family_id)::integer AS total + FROM finding_catalog_item_inventory_families mapping + JOIN inventory_families family ON family.id=mapping.inventory_family_id + WHERE mapping.catalog_item_id=$1::uuid + AND family.is_active=true + AND family.source_reference LIKE $2 + `,[universalItemId,`F5:${CATALOG_SOURCE_NAME}%`])) as CountRow[]; + if (Number(mappedCount?.total ?? 0)!==F5_SOURCE_FAMILY_COUNT) { + throw new Error(`F5 universal mapping verification failed for ${universalTitle}: ${mappedCount?.total ?? 0}`); + } } } @@ -481,12 +483,13 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn INSERT INTO finding_catalog_asset_overrides( asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by ) - SELECT NEW.id,mapping.catalog_item_id,true,$$${F5_AUTO_REASON}$$, + SELECT NEW.id,mapping.catalog_item_id,true, + 'F5 familia técnica: catálogo contextual automático', NEW.created_by,NEW.updated_by FROM finding_catalog_item_inventory_families mapping WHERE mapping.inventory_family_id=NEW.inventory_family_id ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET - is_enabled=true,reason=$$${F5_AUTO_REASON}$$, + is_enabled=true,reason='F5 familia técnica: catálogo contextual automático', updated_by=NEW.updated_by,updated_at=CURRENT_TIMESTAMP; END IF; RETURN NEW; @@ -508,12 +511,13 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn INSERT INTO finding_catalog_asset_overrides( asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by ) - SELECT asset.id,NEW.catalog_item_id,true,$$${F5_AUTO_REASON}$$, + SELECT asset.id,NEW.catalog_item_id,true, + 'F5 familia técnica: catálogo contextual automático', asset.created_by,asset.updated_by FROM assets asset WHERE asset.inventory_family_id=NEW.inventory_family_id ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET - is_enabled=true,reason=$$${F5_AUTO_REASON}$$,updated_at=CURRENT_TIMESTAMP; + is_enabled=true,reason='F5 familia técnica: catálogo contextual automático',updated_at=CURRENT_TIMESTAMP; RETURN NEW; END $$; `);