diff --git a/api-v3/src/asset-master/asset-operational-relations.service.ts b/api-v3/src/asset-master/asset-operational-relations.service.ts index ae547aa..91aeed3 100644 --- a/api-v3/src/asset-master/asset-operational-relations.service.ts +++ b/api-v3/src/asset-master/asset-operational-relations.service.ts @@ -142,27 +142,8 @@ export class AssetOperationalRelationsService { if (!document) throw new BadRequestException({ code: 'SOURCE_DOCUMENT_NOT_FOUND', message: 'El documento fuente no existe' }); } - if (dto.relationRole === AreaOrganizationRole.OPERATOR) { - const [currentOperator] = (await manager.query(` - SELECT relation.id,company.name AS "companyName" - FROM area_company_relations relation - JOIN assets company ON company.id=relation.company_id - WHERE relation.area_id=$1 - AND relation.relation_role='OPERATOR' - AND relation.valid_until IS NULL - AND relation.company_id<>$2 - ORDER BY relation.valid_from DESC - LIMIT 1 - FOR UPDATE OF relation - `,[dto.areaId,dto.companyId])) as Array<{id:string;companyName:string}>; - if (currentOperator) { - throw new ConflictException({ - code:'AREA_ACTIVE_OPERATOR_MUST_END_FIRST', - message:`El Área ya tiene una Operadora vigente (${currentOperator.companyName}). Finalizá esa relación antes de registrar la nueva Operadora.`, - }); - } - } - + // F7: un Área puede estar explotada por varias Empresas simultáneamente. + // La unicidad válida es Área + Empresa + rol activo; no existe una única Operadora por Área. const [row] = (await manager.query(` INSERT INTO area_company_relations ( area_id, company_id, relation_role, participation_percent, legal_instrument, source_document_id, start_reason, created_by @@ -170,9 +151,6 @@ export class AssetOperationalRelationsService { RETURNING id `, [dto.areaId, dto.companyId, dto.relationRole, dto.participationPercent ?? null, dto.legalInstrument ?? null, dto.sourceDocumentId ?? null, dto.reason, principal.userId])) as Array<{ id: string }>; - // F5/F6: changing the Area operator is a temporal relation event only. - // Existing Inventory keeps its creation/historical operator snapshot and - // physical hierarchy unchanged. Runtime ownership must resolve this row. const created = await this.loadRelation(manager, row.id); await this.audit.record({ ...administrationAuditContext(principal, request), @@ -181,7 +159,7 @@ export class AssetOperationalRelationsService { entityId: row.id, afterData: this.auditView(created), metadata: dto.relationRole === AreaOrganizationRole.OPERATOR - ? { inventoryHierarchyChanged:false, operatorSnapshotPreserved:true } + ? { inventoryHierarchyChanged:false, multipleAreaOperatorsAllowed:true } : undefined, }, manager); return created; @@ -212,8 +190,6 @@ export class AssetOperationalRelationsService { }); } - // F5/F6: physical Inventory belongs to Area/Yacimiento hierarchy, not to Company. - // Ending an operator relation never moves, rewrites or blocks existing Inventory. await manager.query(` UPDATE area_company_relations SET valid_until = CURRENT_TIMESTAMP,