fix(inventory): preserve non-hierarchical operator snapshot compatibility
This commit is contained in:
@@ -0,0 +1,131 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* F5 keeps operator_company_id only as a compatibility/current-context snapshot.
|
||||||
|
* It is NOT part of the physical hierarchy; Area↔Company temporal truth lives in
|
||||||
|
* area_company_relations. Runtime membership is resolved by Area ancestry.
|
||||||
|
*/
|
||||||
|
export class F5OperationalContextCompatibility1790087250000 implements MigrationInterface {
|
||||||
|
name = 'F5OperationalContextCompatibility1790087250000';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await this.installCompatibilityGuard(queryRunner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await this.installAreaOwnedGuard(queryRunner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async installCompatibilityGuard(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`
|
||||||
|
CREATE OR REPLACE FUNCTION enforce_asset_operational_context()
|
||||||
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
asset_role asset_type_operational_role;
|
||||||
|
area_role asset_type_operational_role;
|
||||||
|
company_role asset_type_operational_role;
|
||||||
|
active_relation_id uuid;
|
||||||
|
BEGIN
|
||||||
|
IF NEW.operational_area_id IS NULL AND NEW.operator_company_id IS NULL THEN
|
||||||
|
RETURN NEW;
|
||||||
|
END IF;
|
||||||
|
IF NEW.operational_area_id IS NULL OR NEW.operator_company_id IS NULL THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='operational area and organization must be assigned together';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT operational_role INTO asset_role
|
||||||
|
FROM asset_types WHERE id=NEW.asset_type_id;
|
||||||
|
IF asset_role <> 'GENERIC'::asset_type_operational_role THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='area and organization assets cannot receive an operational assignment';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT t.operational_role INTO area_role
|
||||||
|
FROM assets a JOIN asset_types t ON t.id=a.asset_type_id
|
||||||
|
WHERE a.id=NEW.operational_area_id
|
||||||
|
AND a.information_status<>'INACTIVE' AND t.is_active=true;
|
||||||
|
SELECT t.operational_role INTO company_role
|
||||||
|
FROM assets a JOIN asset_types t ON t.id=a.asset_type_id
|
||||||
|
WHERE a.id=NEW.operator_company_id
|
||||||
|
AND a.information_status<>'INACTIVE' AND t.is_active=true;
|
||||||
|
|
||||||
|
IF area_role IS DISTINCT FROM 'AREA'::asset_type_operational_role THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='operational area must be an active AREA asset';
|
||||||
|
END IF;
|
||||||
|
IF company_role IS DISTINCT FROM 'COMPANY'::asset_type_operational_role THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='operator organization must be an active COMPANY-role asset';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT r.id INTO active_relation_id
|
||||||
|
FROM area_company_relations r
|
||||||
|
WHERE r.area_id=NEW.operational_area_id
|
||||||
|
AND r.company_id=NEW.operator_company_id
|
||||||
|
AND r.relation_role='OPERATOR'::area_organization_role
|
||||||
|
AND r.valid_until IS NULL
|
||||||
|
FOR KEY SHARE;
|
||||||
|
IF active_relation_id IS NULL THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='operational area and organization do not have an active OPERATOR relation';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NEW.parent_id IS NULL OR NOT EXISTS (
|
||||||
|
WITH RECURSIVE ancestors AS (
|
||||||
|
SELECT id,parent_id FROM assets WHERE id=NEW.parent_id
|
||||||
|
UNION ALL
|
||||||
|
SELECT p.id,p.parent_id FROM assets p JOIN ancestors c ON p.id=c.parent_id
|
||||||
|
)
|
||||||
|
SELECT 1 FROM ancestors WHERE id=NEW.operational_area_id LIMIT 1
|
||||||
|
) THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',
|
||||||
|
MESSAGE='operational area must be an ancestor in the physical hierarchy';
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END $$;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async installAreaOwnedGuard(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`
|
||||||
|
CREATE OR REPLACE FUNCTION enforce_asset_operational_context()
|
||||||
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
asset_role asset_type_operational_role;
|
||||||
|
area_role asset_type_operational_role;
|
||||||
|
BEGIN
|
||||||
|
SELECT operational_role INTO asset_role FROM asset_types WHERE id=NEW.asset_type_id;
|
||||||
|
IF asset_role <> 'GENERIC'::asset_type_operational_role THEN
|
||||||
|
IF NEW.operational_area_id IS NOT NULL OR NEW.operator_company_id IS NOT NULL THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',MESSAGE='Área y Empresa no reciben contexto operativo';
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END IF;
|
||||||
|
IF NEW.operator_company_id IS NOT NULL THEN
|
||||||
|
IF TG_OP='INSERT' OR OLD.operator_company_id IS NULL OR NEW.operator_company_id IS DISTINCT FROM OLD.operator_company_id THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',MESSAGE='La Empresa pertenece al contexto temporal del Área/Inspección y no al Inventario';
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
IF NEW.operational_area_id IS NULL THEN RETURN NEW; END IF;
|
||||||
|
SELECT t.operational_role INTO area_role
|
||||||
|
FROM assets area JOIN asset_types t ON t.id=area.asset_type_id
|
||||||
|
WHERE area.id=NEW.operational_area_id
|
||||||
|
AND area.information_status<>'INACTIVE' AND t.is_active=true;
|
||||||
|
IF area_role IS DISTINCT FROM 'AREA'::asset_type_operational_role THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',MESSAGE='operational area must be an active AREA asset';
|
||||||
|
END IF;
|
||||||
|
IF NEW.parent_id IS NULL OR NOT EXISTS (
|
||||||
|
WITH RECURSIVE ancestors AS (
|
||||||
|
SELECT id,parent_id FROM assets WHERE id=NEW.parent_id
|
||||||
|
UNION ALL
|
||||||
|
SELECT p.id,p.parent_id FROM assets p JOIN ancestors c ON p.id=c.parent_id
|
||||||
|
) SELECT 1 FROM ancestors WHERE id=NEW.operational_area_id LIMIT 1
|
||||||
|
) THEN
|
||||||
|
RAISE EXCEPTION USING ERRCODE='23514',MESSAGE='operational area must be an ancestor in the physical hierarchy';
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END $$;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user