fix(inventory): preserve custom catalog and apply authoritative universal findings
This commit is contained in:
+138
-67
@@ -7,10 +7,12 @@ import {
|
|||||||
} from '../../reference-data/f5-authoritative-inventory-source';
|
} from '../../reference-data/f5-authoritative-inventory-source';
|
||||||
|
|
||||||
type IdRow = { id: string };
|
type IdRow = { id: string };
|
||||||
|
type CountRow = { total: number };
|
||||||
|
|
||||||
const CATALOG_DOCUMENT_NUMBER = 'DH-F5-INVENTORY-CATALOG';
|
const CATALOG_DOCUMENT_NUMBER = 'DH-F5-INVENTORY-CATALOG';
|
||||||
const CATALOG_CATEGORY_CODE = 'F5MODEL';
|
const CATALOG_CATEGORY_CODE = 'F5MODEL';
|
||||||
const CATALOG_SOURCE_NAME = 'final_modelov2.xlsx';
|
const CATALOG_SOURCE_NAME = 'final_modelov2.xlsx';
|
||||||
|
const F5_AUTO_REASON = 'F5 familia técnica: catálogo contextual automático';
|
||||||
|
|
||||||
function findingKey(value: string): string {
|
function findingKey(value: string): string {
|
||||||
return value.normalize('NFD')
|
return value.normalize('NFD')
|
||||||
@@ -52,6 +54,20 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
throw new Error('F5 inventory catalog source contract mismatch');
|
throw new Error('F5 inventory catalog source contract mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source.catalogSource.universalFindings.length !== 3) {
|
||||||
|
throw new Error(`F5 universal finding contract mismatch: ${source.catalogSource.universalFindings.length}`);
|
||||||
|
}
|
||||||
|
const universalKeys = new Set(source.catalogSource.universalFindings.map(findingKey));
|
||||||
|
for (const required of [
|
||||||
|
'ORDEN Y LIMPIEZA',
|
||||||
|
'CARTELERIA PREVENTIVA / INFORMATIVA',
|
||||||
|
'EXTINTORES',
|
||||||
|
]) {
|
||||||
|
if (!universalKeys.has(findingKey(required))) {
|
||||||
|
throw new Error(`F5 missing authoritative universal finding: ${required}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
INSERT INTO source_documents (
|
INSERT INTO source_documents (
|
||||||
document_type,document_number,title,issuer,external_reference,notes
|
document_type,document_number,title,issuer,external_reference,notes
|
||||||
@@ -70,17 +86,13 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
`F5 · catálogo técnico autorizado · hoja ${source.catalogSource.sheet} · 14 Instalaciones · 109 Subinstalaciones`,
|
`F5 · catálogo técnico autorizado · hoja ${source.catalogSource.sheet} · 14 Instalaciones · 109 Subinstalaciones`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const sourceDocumentId = await this.id(
|
// Only the known historical spreadsheet catalog is superseded. Families
|
||||||
queryRunner,
|
// created manually by DH (including source_reference NULL) remain untouched.
|
||||||
`SELECT id FROM source_documents WHERE document_number=$1 AND issuer='Dirección de Hidrocarburos' LIMIT 1`,
|
|
||||||
[CATALOG_DOCUMENT_NUMBER],
|
|
||||||
'catalog source document',
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
UPDATE inventory_families
|
UPDATE inventory_families
|
||||||
SET is_active=false,updated_at=CURRENT_TIMESTAMP
|
SET is_active=false,updated_at=CURRENT_TIMESTAMP
|
||||||
WHERE source_reference IS NULL OR source_reference NOT LIKE 'F5:%'
|
WHERE source_reference LIKE 'APLICACION APP%'
|
||||||
|
OR source_reference LIKE 'SYSTEM:F3.1:%'
|
||||||
`);
|
`);
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
UPDATE finding_categories
|
UPDATE finding_categories
|
||||||
@@ -165,6 +177,7 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
const itemKey = findingKey(clean);
|
const itemKey = findingKey(clean);
|
||||||
if (!titleByKey.has(itemKey)) titleByKey.set(itemKey,clean);
|
if (!titleByKey.has(itemKey)) titleByKey.set(itemKey,clean);
|
||||||
};
|
};
|
||||||
|
for (const title of source.catalogSource.universalFindings) register(title);
|
||||||
for (const family of source.catalogSource.installations) for (const title of family.findings) register(title);
|
for (const family of source.catalogSource.installations) for (const title of family.findings) register(title);
|
||||||
for (const family of source.catalogSource.subinstallations) for (const title of family.findings) register(title);
|
for (const family of source.catalogSource.subinstallations) for (const title of family.findings) register(title);
|
||||||
if (titleByKey.size !== 177) {
|
if (titleByKey.size !== 177) {
|
||||||
@@ -182,17 +195,16 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
[itemCode],
|
[itemCode],
|
||||||
);
|
);
|
||||||
if (!itemId) {
|
if (!itemId) {
|
||||||
const rows = (await queryRunner.query(`
|
const itemRows = (await queryRunner.query(`
|
||||||
INSERT INTO finding_catalog_items (
|
INSERT INTO finding_catalog_items (
|
||||||
category_id,code,source_number,title,import_note,revision,is_active
|
category_id,code,source_number,title,import_note,revision,is_active
|
||||||
)
|
) VALUES ($1::uuid,$2,$3,$4,$5,1,true)
|
||||||
VALUES ($1::uuid,$2,$3,$4,$5,1,true)
|
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`,[
|
`,[
|
||||||
categoryId,itemCode,sourceNumber,title,
|
categoryId,itemCode,sourceNumber,title,
|
||||||
`${CATALOG_SOURCE_NAME} · ${source.catalogSource.sheet} · F5 authoritative catalog`,
|
`${CATALOG_SOURCE_NAME} · ${source.catalogSource.sheet} · F5 authoritative catalog`,
|
||||||
])) as IdRow[];
|
])) as IdRow[];
|
||||||
itemId=rows[0]?.id ?? null;
|
itemId=itemRows[0]?.id ?? null;
|
||||||
} else {
|
} else {
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
UPDATE finding_catalog_items
|
UPDATE finding_catalog_items
|
||||||
@@ -226,36 +238,43 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
sourceNumber+=1;
|
sourceNumber+=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryRunner.query(`DELETE FROM finding_catalog_item_inventory_families`);
|
// Add F5 mappings only. Never delete mappings created by office users or by
|
||||||
|
// historical migrations; inactive historical families simply stop being offered.
|
||||||
for (const family of source.catalogSource.installations) {
|
for (const family of source.catalogSource.installations) {
|
||||||
await this.mapFindings(queryRunner,installationCode(family.name),family,itemIdByKey);
|
await this.mapFindings(
|
||||||
|
queryRunner,
|
||||||
|
installationCode(family.name),
|
||||||
|
family,
|
||||||
|
source.catalogSource.universalFindings,
|
||||||
|
itemIdByKey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (const family of source.catalogSource.subinstallations) {
|
for (const family of source.catalogSource.subinstallations) {
|
||||||
await this.mapFindings(
|
await this.mapFindings(
|
||||||
queryRunner,
|
queryRunner,
|
||||||
subinstallationCode(family.installation,family.name),
|
subinstallationCode(family.installation,family.name),
|
||||||
family,
|
family,
|
||||||
|
source.catalogSource.universalFindings,
|
||||||
itemIdByKey,
|
itemIdByKey,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.installFamilySyncFunctions(queryRunner);
|
await this.installFamilySyncFunctions(queryRunner);
|
||||||
|
|
||||||
|
// Keep pre-existing profile administration untouched. Yacimiento needs a
|
||||||
|
// profile only to expose OTROS because the source does not provide a family.
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
INSERT INTO finding_catalog_asset_type_profiles(asset_type_id,reason)
|
INSERT INTO finding_catalog_asset_type_profiles(asset_type_id,reason)
|
||||||
SELECT id,'F5: catálogo contextual por familia técnica. Yacimiento sin familia usa OTROS.'
|
SELECT id,'F5: Yacimiento admite Hallazgos mediante OTROS; no posee familia precargada en final_modelov2.xlsx.'
|
||||||
FROM asset_types WHERE lower(code) IN ('yacimiento','instalacion','subinstalacion')
|
FROM asset_types WHERE lower(code)='yacimiento'
|
||||||
ON CONFLICT (asset_type_id) DO UPDATE SET
|
ON CONFLICT (asset_type_id) DO NOTHING
|
||||||
reason=EXCLUDED.reason,updated_at=CURRENT_TIMESTAMP
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const [counts] = (await queryRunner.query(`
|
const [counts] = (await queryRunner.query(`
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) FILTER (WHERE level='INSTALLATION' AND source_reference LIKE 'F5:${CATALOG_SOURCE_NAME}%')::integer AS installations,
|
COUNT(*) FILTER (WHERE level='INSTALLATION' AND source_reference LIKE 'F5:${CATALOG_SOURCE_NAME}%')::integer AS installations,
|
||||||
COUNT(*) FILTER (WHERE level='SUBINSTALLATION' AND source_reference LIKE 'F5:${CATALOG_SOURCE_NAME}%')::integer AS subinstallations
|
COUNT(*) FILTER (WHERE level='SUBINSTALLATION' AND source_reference LIKE 'F5:${CATALOG_SOURCE_NAME}%')::integer AS subinstallations
|
||||||
FROM inventory_families
|
FROM inventory_families WHERE is_active=true
|
||||||
WHERE is_active=true
|
|
||||||
`)) as Array<{ installations:number; subinstallations:number }>;
|
`)) as Array<{ installations:number; subinstallations:number }>;
|
||||||
if (Number(counts?.installations ?? 0)!==14 || Number(counts?.subinstallations ?? 0)!==109) {
|
if (Number(counts?.installations ?? 0)!==14 || Number(counts?.subinstallations ?? 0)!==109) {
|
||||||
throw new Error(`F5 family preload verification failed: ${JSON.stringify(counts ?? {})}`);
|
throw new Error(`F5 family preload verification failed: ${JSON.stringify(counts ?? {})}`);
|
||||||
@@ -265,12 +284,28 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
SELECT COUNT(*)::integer AS total
|
SELECT COUNT(*)::integer AS total
|
||||||
FROM finding_catalog_items
|
FROM finding_catalog_items
|
||||||
WHERE category_id=$1::uuid AND is_active=true
|
WHERE category_id=$1::uuid AND is_active=true
|
||||||
`,[categoryId])) as Array<{total:number}>;
|
`,[categoryId])) as CountRow[];
|
||||||
if (Number(itemCount?.total ?? 0)!==177) {
|
if (Number(itemCount?.total ?? 0)!==177) {
|
||||||
throw new Error(`F5 finding preload verification failed: ${itemCount?.total ?? 0}`);
|
throw new Error(`F5 finding preload verification failed: ${itemCount?.total ?? 0}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sourceDocumentId;
|
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}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
@@ -279,6 +314,34 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
`SELECT id FROM finding_categories WHERE lower(code)=lower($1) LIMIT 1`,
|
`SELECT id FROM finding_categories WHERE lower(code)=lower($1) LIMIT 1`,
|
||||||
[CATALOG_CATEGORY_CODE],
|
[CATALOG_CATEGORY_CODE],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (categoryId) {
|
||||||
|
const [usedFinding] = (await queryRunner.query(`
|
||||||
|
SELECT COUNT(*)::integer AS total
|
||||||
|
FROM inspection_findings finding
|
||||||
|
JOIN finding_catalog_items item ON item.id=finding.catalog_item_id
|
||||||
|
WHERE item.category_id=$1::uuid
|
||||||
|
`,[categoryId])) as CountRow[];
|
||||||
|
if (Number(usedFinding?.total ?? 0)>0) {
|
||||||
|
throw new Error('Cannot safely rollback F5 catalog: inspection findings already reference F5 catalog items');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [usedFamily] = (await queryRunner.query(`
|
||||||
|
SELECT COUNT(*)::integer AS total
|
||||||
|
FROM assets asset
|
||||||
|
JOIN inventory_families family ON family.id=asset.inventory_family_id
|
||||||
|
WHERE family.source_reference LIKE 'F5:%'
|
||||||
|
`)) as CountRow[];
|
||||||
|
if (Number(usedFamily?.total ?? 0)>0) {
|
||||||
|
throw new Error('Cannot safely rollback F5 catalog: inventory instances already reference F5 families');
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.query(`
|
||||||
|
DELETE FROM finding_catalog_asset_overrides
|
||||||
|
WHERE reason=$1
|
||||||
|
`,[F5_AUTO_REASON]);
|
||||||
|
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
DELETE FROM finding_catalog_item_inventory_families mapping
|
DELETE FROM finding_catalog_item_inventory_families mapping
|
||||||
@@ -288,45 +351,63 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
DELETE FROM finding_catalog_item_versions version
|
DELETE FROM finding_catalog_item_versions version
|
||||||
USING finding_catalog_items item
|
USING finding_catalog_items item
|
||||||
WHERE item.id=version.item_id
|
WHERE item.id=version.item_id AND item.category_id=$1::uuid
|
||||||
AND item.category_id=$1::uuid
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM inspection_findings finding WHERE finding.catalog_item_id=item.id
|
|
||||||
)
|
|
||||||
`,[categoryId]);
|
|
||||||
await queryRunner.query(`
|
|
||||||
DELETE FROM finding_catalog_items item
|
|
||||||
WHERE item.category_id=$1::uuid
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM inspection_findings finding WHERE finding.catalog_item_id=item.id
|
|
||||||
)
|
|
||||||
`,[categoryId]);
|
|
||||||
await queryRunner.query(`
|
|
||||||
DELETE FROM finding_categories category
|
|
||||||
WHERE category.id=$1::uuid
|
|
||||||
AND NOT EXISTS (SELECT 1 FROM finding_catalog_items item WHERE item.category_id=category.id)
|
|
||||||
`,[categoryId]);
|
`,[categoryId]);
|
||||||
|
await queryRunner.query(`DELETE FROM finding_catalog_items WHERE category_id=$1::uuid`,[categoryId]);
|
||||||
|
await queryRunner.query(`DELETE FROM finding_categories WHERE id=$1::uuid`,[categoryId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
DELETE FROM inventory_families family
|
DELETE FROM inventory_family_parent_rules rule
|
||||||
WHERE family.source_reference LIKE 'F5:%'
|
USING inventory_families child
|
||||||
AND NOT EXISTS (SELECT 1 FROM assets asset WHERE asset.inventory_family_id=family.id)
|
WHERE child.id=rule.child_family_id AND child.source_reference LIKE 'F5:%'
|
||||||
`);
|
`);
|
||||||
|
await queryRunner.query(`DELETE FROM inventory_families WHERE source_reference LIKE 'F5:%'`);
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
UPDATE inventory_families
|
UPDATE inventory_families
|
||||||
SET is_active=true,updated_at=CURRENT_TIMESTAMP
|
SET is_active=true,updated_at=CURRENT_TIMESTAMP
|
||||||
WHERE source_reference LIKE 'APLICACION APP%' OR source_reference LIKE 'SYSTEM:F3.1:%'
|
WHERE source_reference LIKE 'APLICACION APP%'
|
||||||
|
OR source_reference LIKE 'SYSTEM:F3.1:%'
|
||||||
`);
|
`);
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
UPDATE finding_categories SET is_active=true,updated_at=CURRENT_TIMESTAMP
|
UPDATE finding_categories SET is_active=true,updated_at=CURRENT_TIMESTAMP
|
||||||
WHERE lower(code)='app26r2'
|
WHERE lower(code)='app26r2'
|
||||||
`);
|
`);
|
||||||
|
await queryRunner.query(`
|
||||||
|
DELETE FROM finding_catalog_asset_type_profiles profile
|
||||||
|
USING asset_types type
|
||||||
|
WHERE profile.asset_type_id=type.id
|
||||||
|
AND lower(type.code)='yacimiento'
|
||||||
|
AND profile.reason='F5: Yacimiento admite Hallazgos mediante OTROS; no posee familia precargada en final_modelov2.xlsx.'
|
||||||
|
`);
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
DELETE FROM source_documents
|
DELETE FROM source_documents
|
||||||
WHERE document_number=$1 AND issuer='Dirección de Hidrocarburos'
|
WHERE document_number=$1 AND issuer='Dirección de Hidrocarburos'
|
||||||
`,[CATALOG_DOCUMENT_NUMBER]);
|
`,[CATALOG_DOCUMENT_NUMBER]);
|
||||||
await this.restoreF31FamilySyncFunctions(queryRunner);
|
await this.restoreF31FamilySyncFunctions(queryRunner);
|
||||||
|
|
||||||
|
// Rebuild only automatic historical overrides. Manual overrides have never
|
||||||
|
// been touched by this migration.
|
||||||
|
await queryRunner.query(`
|
||||||
|
DELETE FROM finding_catalog_asset_overrides
|
||||||
|
WHERE reason LIKE 'F3.1 familia técnica:%'
|
||||||
|
`);
|
||||||
|
await queryRunner.query(`
|
||||||
|
INSERT INTO finding_catalog_asset_overrides(
|
||||||
|
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
||||||
|
)
|
||||||
|
SELECT asset.id,mapping.catalog_item_id,true,
|
||||||
|
'F3.1 familia técnica: catálogo contextual automático',
|
||||||
|
asset.created_by,asset.updated_by
|
||||||
|
FROM assets asset
|
||||||
|
JOIN finding_catalog_item_inventory_families mapping
|
||||||
|
ON mapping.inventory_family_id=asset.inventory_family_id
|
||||||
|
WHERE asset.inventory_family_id IS NOT NULL
|
||||||
|
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
||||||
|
is_enabled=true,
|
||||||
|
reason='F3.1 familia técnica: catálogo contextual automático',
|
||||||
|
updated_at=CURRENT_TIMESTAMP
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async upsertFamily(
|
private async upsertFamily(
|
||||||
@@ -339,8 +420,7 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
INSERT INTO inventory_families(
|
INSERT INTO inventory_families(
|
||||||
code,name,level,legacy_type_code,information_labels,source_reference,is_active
|
code,name,level,legacy_type_code,information_labels,source_reference,is_active
|
||||||
)
|
) VALUES ($1,$2,$3,NULL,'[]'::jsonb,$4,true)
|
||||||
VALUES ($1,$2,$3,NULL,'[]'::jsonb,$4,true)
|
|
||||||
ON CONFLICT (code) DO UPDATE SET
|
ON CONFLICT (code) DO UPDATE SET
|
||||||
name=EXCLUDED.name,level=EXCLUDED.level,legacy_type_code=NULL,
|
name=EXCLUDED.name,level=EXCLUDED.level,legacy_type_code=NULL,
|
||||||
information_labels='[]'::jsonb,source_reference=EXCLUDED.source_reference,
|
information_labels='[]'::jsonb,source_reference=EXCLUDED.source_reference,
|
||||||
@@ -366,6 +446,7 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
familyCode: string,
|
familyCode: string,
|
||||||
family: F5InstallationCatalogRow|F5SubinstallationCatalogRow,
|
family: F5InstallationCatalogRow|F5SubinstallationCatalogRow,
|
||||||
|
universalFindings: string[],
|
||||||
itemIdByKey: Map<string,string>,
|
itemIdByKey: Map<string,string>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const familyId = await this.id(
|
const familyId = await this.id(
|
||||||
@@ -375,7 +456,7 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
`family ${familyCode}`,
|
`family ${familyCode}`,
|
||||||
);
|
);
|
||||||
const mapped = new Set<string>();
|
const mapped = new Set<string>();
|
||||||
for (const rawTitle of family.findings) {
|
for (const rawTitle of [...family.findings,...universalFindings]) {
|
||||||
const itemKey=findingKey(rawTitle);
|
const itemKey=findingKey(rawTitle);
|
||||||
if (!itemKey || itemKey==='hallazgos' || mapped.has(itemKey)) continue;
|
if (!itemKey || itemKey==='hallazgos' || mapped.has(itemKey)) continue;
|
||||||
mapped.add(itemKey);
|
mapped.add(itemKey);
|
||||||
@@ -395,23 +476,18 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM finding_catalog_asset_overrides
|
DELETE FROM finding_catalog_asset_overrides
|
||||||
WHERE asset_id=NEW.id
|
WHERE asset_id=NEW.id AND reason LIKE 'F% familia técnica:%';
|
||||||
AND reason LIKE 'F% familia técnica:%';
|
|
||||||
|
|
||||||
IF NEW.inventory_family_id IS NOT NULL THEN
|
IF NEW.inventory_family_id IS NOT NULL THEN
|
||||||
INSERT INTO finding_catalog_asset_overrides(
|
INSERT INTO finding_catalog_asset_overrides(
|
||||||
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
||||||
)
|
)
|
||||||
SELECT NEW.id,mapping.catalog_item_id,true,
|
SELECT NEW.id,mapping.catalog_item_id,true,$$${F5_AUTO_REASON}$$,
|
||||||
'F5 familia técnica: catálogo contextual automático',
|
|
||||||
NEW.created_by,NEW.updated_by
|
NEW.created_by,NEW.updated_by
|
||||||
FROM finding_catalog_item_inventory_families mapping
|
FROM finding_catalog_item_inventory_families mapping
|
||||||
WHERE mapping.inventory_family_id=NEW.inventory_family_id
|
WHERE mapping.inventory_family_id=NEW.inventory_family_id
|
||||||
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
||||||
is_enabled=true,
|
is_enabled=true,reason=$$${F5_AUTO_REASON}$$,
|
||||||
reason='F5 familia técnica: catálogo contextual automático',
|
updated_by=NEW.updated_by,updated_at=CURRENT_TIMESTAMP;
|
||||||
updated_by=NEW.updated_by,
|
|
||||||
updated_at=CURRENT_TIMESTAMP;
|
|
||||||
END IF;
|
END IF;
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END $$;
|
END $$;
|
||||||
@@ -432,18 +508,16 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
INSERT INTO finding_catalog_asset_overrides(
|
INSERT INTO finding_catalog_asset_overrides(
|
||||||
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
||||||
)
|
)
|
||||||
SELECT asset.id,NEW.catalog_item_id,true,
|
SELECT asset.id,NEW.catalog_item_id,true,$$${F5_AUTO_REASON}$$,
|
||||||
'F5 familia técnica: catálogo contextual automático',
|
|
||||||
asset.created_by,asset.updated_by
|
asset.created_by,asset.updated_by
|
||||||
FROM assets asset
|
FROM assets asset
|
||||||
WHERE asset.inventory_family_id=NEW.inventory_family_id
|
WHERE asset.inventory_family_id=NEW.inventory_family_id
|
||||||
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
||||||
is_enabled=true,
|
is_enabled=true,reason=$$${F5_AUTO_REASON}$$,updated_at=CURRENT_TIMESTAMP;
|
||||||
reason='F5 familia técnica: catálogo contextual automático',
|
|
||||||
updated_at=CURRENT_TIMESTAMP;
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END $$;
|
END $$;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
DELETE FROM finding_catalog_asset_overrides
|
DELETE FROM finding_catalog_asset_overrides
|
||||||
WHERE reason LIKE 'F% familia técnica:%'
|
WHERE reason LIKE 'F% familia técnica:%'
|
||||||
@@ -452,18 +526,15 @@ export class F5AuthoritativeInventoryCatalog1790087300000 implements MigrationIn
|
|||||||
INSERT INTO finding_catalog_asset_overrides(
|
INSERT INTO finding_catalog_asset_overrides(
|
||||||
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
asset_id,catalog_item_id,is_enabled,reason,created_by,updated_by
|
||||||
)
|
)
|
||||||
SELECT asset.id,mapping.catalog_item_id,true,
|
SELECT asset.id,mapping.catalog_item_id,true,$1,
|
||||||
'F5 familia técnica: catálogo contextual automático',
|
|
||||||
asset.created_by,asset.updated_by
|
asset.created_by,asset.updated_by
|
||||||
FROM assets asset
|
FROM assets asset
|
||||||
JOIN finding_catalog_item_inventory_families mapping
|
JOIN finding_catalog_item_inventory_families mapping
|
||||||
ON mapping.inventory_family_id=asset.inventory_family_id
|
ON mapping.inventory_family_id=asset.inventory_family_id
|
||||||
WHERE asset.inventory_family_id IS NOT NULL
|
WHERE asset.inventory_family_id IS NOT NULL
|
||||||
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
ON CONFLICT (asset_id,catalog_item_id) DO UPDATE SET
|
||||||
is_enabled=true,
|
is_enabled=true,reason=$1,updated_at=CURRENT_TIMESTAMP
|
||||||
reason='F5 familia técnica: catálogo contextual automático',
|
`,[F5_AUTO_REASON]);
|
||||||
updated_at=CURRENT_TIMESTAMP
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async restoreF31FamilySyncFunctions(queryRunner: QueryRunner):Promise<void> {
|
private async restoreF31FamilySyncFunctions(queryRunner: QueryRunner):Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user