fix(f6): gate mobile findings by area ancestry and temporal operator

This commit is contained in:
2026-09-09 10:42:03 -03:00
parent 792b115449
commit 5c5e5de26b
@@ -138,8 +138,31 @@ export class FieldFindingsService {
asset.id AS "assetId",
asset_type.code AS "assetTypeCode",
asset.inventory_family_id AS "inventoryFamilyId",
asset.operational_area_id AS "assetAreaId",
asset.operator_company_id AS "assetCompanyId",
(
asset.operational_area_id=visit.operational_area_id
OR asset.id=visit.operational_area_id
OR EXISTS (
WITH RECURSIVE ancestors AS (
SELECT id,parent_id FROM assets WHERE id=asset.parent_id
UNION ALL
SELECT parent.id,parent.parent_id
FROM assets parent JOIN ancestors child ON parent.id=child.parent_id
)
SELECT 1 FROM ancestors WHERE id=visit.operational_area_id LIMIT 1
)
) AS "insideArea",
EXISTS (
SELECT 1
FROM area_company_relations relation
WHERE relation.area_id=visit.operational_area_id
AND relation.company_id=visit.operator_company_id
AND relation.relation_role='OPERATOR'
AND relation.valid_from <= COALESCE(visit.actual_started_at,visit.planned_start_at,visit.created_at)
AND (
relation.valid_until IS NULL
OR relation.valid_until >= COALESCE(visit.actual_started_at,visit.planned_start_at,visit.created_at)
)
) AS "operatorRelationValid",
EXISTS (
SELECT 1
FROM inspection_visit_members member
@@ -199,8 +222,8 @@ export class FieldFindingsService {
assetId: string | null;
assetTypeCode: string | null;
inventoryFamilyId: string | null;
assetAreaId: string | null;
assetCompanyId: string | null;
insideArea: boolean;
operatorRelationValid: boolean;
assigned: boolean;
selected: boolean;
captureRequired: boolean;
@@ -230,6 +253,12 @@ export class FieldFindingsService {
message: 'La inspección no tiene Área y Operadora definidas',
});
}
if (!row.operatorRelationValid) {
throw new ConflictException({
code: 'FIELD_FINDING_OPERATOR_RELATION_INVALID',
message: 'La Operadora seleccionada no estaba vinculada al Área para la fecha de esta inspección',
});
}
if (!row.assetId) {
throw new NotFoundException({
code: 'FIELD_FINDING_INVENTORY_NOT_FOUND',
@@ -245,13 +274,13 @@ export class FieldFindingsService {
if (!row.inventoryFamilyId) {
throw new ConflictException({
code: 'FIELD_FINDING_FAMILY_REQUIRED',
message: 'La Instalación/Subinstalación debe tener una familia técnica u Otro antes de registrar Hallazgos',
message: 'La Instalación/Subinstalación debe tener una clasificación técnica antes de registrar Hallazgos',
});
}
if (row.assetAreaId !== row.areaId || row.assetCompanyId !== row.companyId) {
if (!row.insideArea) {
throw new BadRequestException({
code: 'FIELD_FINDING_INVENTORY_OUTSIDE_CONTEXT',
message: 'El Inventario no pertenece al Área y Operadora de esta inspección',
message: 'El Inventario no pertenece al Área de esta inspección',
});
}
if (!row.selected) {