From 88115af80e474bca9cae86047ce5043380dee737 Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Fri, 18 Sep 2026 12:10:03 -0300 Subject: [PATCH 1/2] =?UTF-8?q?GDU=20-=20Visualizaci=C3=B3n=20por=20solici?= =?UTF-8?q?tud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth/permisos.ts | 3 ++- modules/recetas/recetas.routes.ts | 1 + modules/recetas/recetasInsumos/receta-insumo.routes.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/auth/permisos.ts b/auth/permisos.ts index ee313d8cf1..553fea44ea 100644 --- a/auth/permisos.ts +++ b/auth/permisos.ts @@ -269,7 +269,8 @@ export default [ child: [ { key: 'laboratorio', title: 'Ver solo laboratorios', type: 'boolean' }, { key: 'vacuna', title: 'Ver solo vacunas', type: 'boolean' }, - { key: 'receta', title: 'Ver solo recetas', type: 'boolean' } + { key: 'receta', title: 'Ver solo recetas', type: 'boolean' }, + { key: 'solicitudes', title: 'Ver solo solicitudes', type: 'boolean' } ] } ] diff --git a/modules/recetas/recetas.routes.ts b/modules/recetas/recetas.routes.ts index 77b23a3aca..f7a847677c 100644 --- a/modules/recetas/recetas.routes.ts +++ b/modules/recetas/recetas.routes.ts @@ -115,6 +115,7 @@ const authorizeByToken = async (req: Request, res: Response, next) => 'huds:visualizacionParcialHuds:laboratorio', 'huds:visualizacionParcialHuds:vacuna', 'huds:visualizacionParcialHuds:receta', + 'huds:visualizacionParcialHuds:solicitudes', 'huds:visualizacionParcialHuds:*', 'recetas:read' ]); diff --git a/modules/recetas/recetasInsumos/receta-insumo.routes.ts b/modules/recetas/recetasInsumos/receta-insumo.routes.ts index 0d15ee3b84..4b4fe13d28 100644 --- a/modules/recetas/recetasInsumos/receta-insumo.routes.ts +++ b/modules/recetas/recetasInsumos/receta-insumo.routes.ts @@ -87,6 +87,7 @@ const authorizeByToken = async (req: Request, res: Response, next) => 'huds:visualizacionParcialHuds:laboratorio', 'huds:visualizacionParcialHuds:vacuna', 'huds:visualizacionParcialHuds:receta', + 'huds:visualizacionParcialHuds:solicitudes', 'huds:visualizacionParcialHuds:*', 'recetas:read' ]); From 11ad428e5bc0c0c928c5c1e457d382762c772f3e Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Fri, 18 Sep 2026 12:10:03 -0300 Subject: [PATCH 2/2] =?UTF-8?q?GDU=20-=20Visualizaci=C3=B3n=20por=20solici?= =?UTF-8?q?tud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth/permisos.ts | 36 ++++++++++++-- modules/rup/routes/prestacion.ts | 81 +++++++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 6 deletions(-) diff --git a/auth/permisos.ts b/auth/permisos.ts index 553fea44ea..f86d6c0f63 100644 --- a/auth/permisos.ts +++ b/auth/permisos.ts @@ -267,10 +267,38 @@ export default [ key: 'visualizacionParcialHuds', title: 'Visualización parcial de la HUDS', child: [ - { key: 'laboratorio', title: 'Ver solo laboratorios', type: 'boolean' }, - { key: 'vacuna', title: 'Ver solo vacunas', type: 'boolean' }, - { key: 'receta', title: 'Ver solo recetas', type: 'boolean' }, - { key: 'solicitudes', title: 'Ver solo solicitudes', type: 'boolean' } + + { + key: 'laboratorio', + title: 'Ver solo laboratorios', + type: 'boolean' + }, + + { + key: 'vacuna', + title: 'Ver solo vacunas', + type: 'boolean' + }, + + { + key: 'receta', + title: 'Ver solo recetas', + type: 'boolean' + }, + + { + key: 'solicitudes', + title: 'Ver solo solicitudes', + type: 'boolean' + }, + + { + key: 'tipoPrestacion', + title: 'Tipo de prestación', + type: 'prestacion', + requires: 'solicitudes' + } + ] } ] diff --git a/modules/rup/routes/prestacion.ts b/modules/rup/routes/prestacion.ts index 8a990b4ee6..9b21a0c79d 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -7,6 +7,7 @@ import { Types } from 'mongoose'; import { AppCache } from '../../../connections'; import { PacienteCtr } from '../../../core-v2/mpi/paciente/paciente.routes'; import { SnomedCtr } from '../../../core/term/controller/snomed.controller'; +import { tipoPrestacion as tipoPrestacionModel } from '../../../core/tm/schemas/tipoPrestacion'; import { getObraSocial } from '../../../modules/obraSocial/controller/obraSocial'; import { removeDiacritics } from '../../../utils/utils'; import { getVisualizadorURL } from '../../pacs'; @@ -26,6 +27,54 @@ import { Agenda } from '../../turnos/schemas/agenda'; const router = express.Router(); +/** + * Indica si corresponde aplicar el filtro de la HUDS parcial por tipo de prestación + * sobre las solicitudes del paciente. + */ +function aplicarFiltroHudsSolicitudes(req: any): boolean { + if (Auth.check(req, 'huds:visualizacionHuds')) { + return false; + } + const parcial = Auth.check(req, 'huds:visualizacionParcialHuds:*') || Auth.check(req, 'huds:visualizacionParcialHuds:solicitudes'); + if (!parcial) { + return false; + } + const hudsTipoPrestaciones = Auth.getPermissions(req, 'huds:visualizacionParcialHuds:tipoPrestacion:?'); + return !!hudsTipoPrestaciones?.length && hudsTipoPrestaciones[0] !== '*'; +} + +async function obtenerConceptosPermitidosHuds(req: any): Promise | null> { + if (!aplicarFiltroHudsSolicitudes(req)) { + return null; + } + const ids = Auth.getPermissions(req, 'huds:visualizacionParcialHuds:tipoPrestacion:?') + .filter(id => Types.ObjectId.isValid(id)) + .map(id => Types.ObjectId(id)); + const prestaciones = await tipoPrestacionModel.find({ _id: { $in: ids } }, { conceptId: 1 }).lean(); + return new Set(prestaciones.map(prestacion => prestacion.conceptId).filter(Boolean)); +} + +function filtrarRegistrosSolicitudHuds(registros: any[], conceptosPermitidos: Set): void { + if (!Array.isArray(registros)) { + return; + } + for (let i = registros.length - 1; i >= 0; i--) { + const registro = registros[i]; + if (registro.esSolicitud) { + const conceptId = registro.valor?.solicitudPrestacion?.prestacionSolicitada?.conceptId; + if (!conceptosPermitidos.has(conceptId)) { + registros.splice(i, 1); + continue; + } + } + filtrarRegistrosSolicitudHuds(registro.registros, conceptosPermitidos); + } +} + +function filtrarSolicitudesHuds(prestacion: any, conceptosPermitidos: Set): void { + filtrarRegistrosSolicitudHuds(prestacion.ejecucion?.registros, conceptosPermitidos); +} + /** * * Buscar un determinado concepto snomed ya sea en una prestación especifica o en la huds completa de un paciente * @@ -212,7 +261,12 @@ router.get('/prestaciones/solicitudes', async (req: any, res, next) => { if (req.query.origen === 'top') { match.$and.push({ inicio: 'top' }); - match.$and.push({ 'solicitud.prestacionOrigen': { $exists: false } }); + // Si se consulta la HUDS de un paciente puntual (idPaciente) no se excluyen + // las solicitudes derivadas (con prestacionOrigen), ya que también son parte + // de su historia. En la bandeja de entrada del TOP (sin idPaciente) sí se excluyen. + if (!req.query.idPaciente) { + match.$and.push({ 'solicitud.prestacionOrigen': { $exists: false } }); + } } if (req.query.tieneTurno !== undefined) { @@ -297,6 +351,14 @@ router.get('/prestaciones/solicitudes', async (req: any, res, next) => { }); } + // HUDS parcial: filtra solicitudes del paciente según el permiso de tipo de prestación de solicitudes + let conceptosPermitidosHuds: Set = null; + if (req.query.idPaciente && aplicarFiltroHudsSolicitudes(req)) { + const hudsTipoPrestaciones = Auth.getPermissions(req, 'huds:visualizacionParcialHuds:tipoPrestacion:?'); + match.$and.push({ 'solicitud.tipoPrestacion.id': { $in: hudsTipoPrestaciones.map(e => Types.ObjectId(e)) } }); + conceptosPermitidosHuds = await obtenerConceptosPermitidosHuds(req); + } + if (req.query.estados) { match.$and.push({ 'estadoActual.tipo': { $in: (typeof req.query.estados === 'string') ? [req.query.estados] : req.query.estados } }); } @@ -414,7 +476,11 @@ router.get('/prestaciones/solicitudes', async (req: any, res, next) => { if (req.query.limit) { pipeline.push({ $limit: parseInt(req.query.limit, 10) }); } - res.json(await Prestacion.aggregate(pipeline).option({ hint: indice }).allowDiskUse(true)); + const resultados = await Prestacion.aggregate(pipeline).option({ hint: indice }).allowDiskUse(true); + if (conceptosPermitidosHuds) { + resultados.forEach(prestacion => filtrarSolicitudesHuds(prestacion, conceptosPermitidosHuds)); + } + res.json(resultados); } catch (err) { return next(err); } @@ -523,6 +589,14 @@ router.get('/prestaciones', async (req: any, res, next) => { query.where({ 'solicitud.tipoPrestacion.conceptId': compare }); } + // HUDS parcial: filtra las prestaciones del paciente según el permiso de tipo de prestación de solicitudes + let conceptosPermitidosHuds: Set = null; + if (req.query.hudsToken && aplicarFiltroHudsSolicitudes(req)) { + const hudsTipoPrestaciones = Auth.getPermissions(req, 'huds:visualizacionParcialHuds:tipoPrestacion:?'); + query.where({ 'solicitud.tipoPrestacion.id': { $in: hudsTipoPrestaciones.map(id => Types.ObjectId(id)) } }); + conceptosPermitidosHuds = await obtenerConceptosPermitidosHuds(req); + } + if (req.query.organizacion) { query.where('solicitud.organizacion.id').equals(req.query.organizacion); } @@ -560,6 +634,9 @@ router.get('/prestaciones', async (req: any, res, next) => { const profesional = Auth.getProfesional(req); const profesionalId = profesional && profesional.id && profesional.id.toString(); for (let i = 0; i < data.length; i++) { + if (conceptosPermitidosHuds) { + filtrarSolicitudesHuds(data[i], conceptosPermitidosHuds); + } let profId = false; if (data[i].solicitud.profesional && data[i].solicitud.profesional.id) { profId = data[i].solicitud.profesional.id.toString();