import { BadRequestException, Injectable } from '@nestjs/common'; import { DataSource } from 'typeorm'; export interface InspectionPlanningHierarchyItem { id: string; code: string; name: string; } @Injectable() export class InspectionPlanningHierarchyService { constructor(private readonly dataSource: DataSource) {} async departments(): Promise<{ data: InspectionPlanningHierarchyItem[] }> { const data = await this.dataSource.query(` SELECT department.id, department.code, department.name FROM assets department INNER JOIN asset_types type ON type.id=department.asset_type_id WHERE lower(type.code)='departamento' AND type.is_active=true AND department.information_status<>'INACTIVE' AND EXISTS ( SELECT 1 FROM assets area INNER JOIN asset_types area_type ON area_type.id=area.asset_type_id WHERE area.parent_id=department.id AND lower(area_type.code)='area' AND area.information_status<>'INACTIVE' ) ORDER BY department.name, department.code `) as InspectionPlanningHierarchyItem[]; return { data }; } async areasForDepartment(departmentId: string): Promise<{ data: InspectionPlanningHierarchyItem[] }> { await this.requireType(departmentId, 'departamento', 'El Departamento seleccionado no es válido'); const data = await this.dataSource.query(` SELECT area.id, area.code, area.name FROM assets area INNER JOIN asset_types type ON type.id=area.asset_type_id WHERE area.parent_id=$1::uuid AND lower(type.code)='area' AND type.is_active=true AND area.information_status<>'INACTIVE' ORDER BY area.name, area.code `, [departmentId]) as InspectionPlanningHierarchyItem[]; return { data }; } async yacimientosForArea(areaId: string): Promise<{ data: InspectionPlanningHierarchyItem[] }> { await this.requireType(areaId, 'area', 'El Área seleccionada no es válida'); const data = await this.dataSource.query(` SELECT yacimiento.id, yacimiento.code, yacimiento.name FROM assets yacimiento INNER JOIN asset_types type ON type.id=yacimiento.asset_type_id WHERE yacimiento.parent_id=$1::uuid AND lower(type.code)='yacimiento' AND type.is_active=true AND yacimiento.information_status<>'INACTIVE' ORDER BY yacimiento.name, yacimiento.code `, [areaId]) as InspectionPlanningHierarchyItem[]; return { data }; } async operatorsForArea( areaId: string, at?: string, ): Promise<{ data: InspectionPlanningHierarchyItem[] }> { await this.requireType(areaId, 'area', 'El Área seleccionada no es válida'); if (at) { const effectiveAt = new Date(at); if (!Number.isFinite(effectiveAt.getTime())) { throw new BadRequestException({ code: 'INSPECTION_PLANNING_DATE_INVALID', message: 'La fecha de planificación no es válida', }); } } // Modelo autoritativo: la Empresa pertenece al Yacimiento. Para mantener el // selector de planificación por Área, se proyectan las Empresas de todos los // Yacimientos activos que pertenecen a esa Área. const data = await this.dataSource.query(` SELECT DISTINCT company.id, company.code, COALESCE(profile.legal_name,company.name) AS name FROM assets yacimiento INNER JOIN asset_types yacimiento_type ON yacimiento_type.id=yacimiento.asset_type_id INNER JOIN assets company ON company.id=yacimiento.operator_company_id INNER JOIN asset_types company_type ON company_type.id=company.asset_type_id LEFT JOIN organization_profiles profile ON profile.asset_id=company.id WHERE yacimiento.parent_id=$1::uuid AND lower(yacimiento_type.code)='yacimiento' AND yacimiento_type.is_active=true AND yacimiento.information_status<>'INACTIVE' AND company_type.operational_role='COMPANY' AND company_type.is_active=true AND company.information_status<>'INACTIVE' ORDER BY name, company.code `, [areaId]) as InspectionPlanningHierarchyItem[]; return { data }; } private async requireType(id: string, typeCode: string, message: string): Promise { const [row] = await this.dataSource.query(` SELECT 1 FROM assets asset INNER JOIN asset_types type ON type.id=asset.asset_type_id WHERE asset.id=$1::uuid AND lower(type.code)=lower($2) AND type.is_active=true AND asset.information_status<>'INACTIVE' LIMIT 1 `, [id, typeCode]) as Array<{ '?column?': number }>; if (!row) { throw new BadRequestException({ code: 'INSPECTION_PLANNING_HIERARCHY_INVALID', message }); } } }