From 1993cf8a6395d61c7034cc918c4bf779041507db Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:03:04 -0300 Subject: [PATCH 1/3] HUDS : Armar api o controladores para situaciones activas y antecedentes --- initialize.ts | 1 + modules/huds/hudsSituaciones.controller.ts | 133 ++++++++++++++++++ modules/huds/hudsSituaciones.routes.ts | 44 ++++++ modules/huds/index.ts | 1 + .../schemas/carnet-perinatal.schema.ts | 16 +++ 5 files changed, 195 insertions(+) create mode 100644 modules/huds/hudsSituaciones.controller.ts create mode 100644 modules/huds/hudsSituaciones.routes.ts diff --git a/initialize.ts b/initialize.ts index 63bd7a141a..4fcd888b75 100644 --- a/initialize.ts +++ b/initialize.ts @@ -106,6 +106,7 @@ export function initAPI(app: Express) { app.use('/api/modules/gestor-usuarios', require('./modules/gestor-usuarios').PerfilesRouter); app.use('/api/modules/registro-novedades', require('./modules/registro-novedades').NovedadesRouter); app.use('/api/modules/huds', require('./modules/huds').HudsAccesoRouter); + app.use('/api/modules/huds', require('./modules/huds').HudsSituacionesRouter); app.use('/api/modules/webhook', require('./modules/webhook').WebhookRouter); app.use('/api/modules/webhook', require('./modules/webhook/webhooklog').WebhookLogRouter); app.use('/api/modules/seguimiento-paciente', require('./modules/seguimiento-paciente').SeguimientoPacienteRouter); diff --git a/modules/huds/hudsSituaciones.controller.ts b/modules/huds/hudsSituaciones.controller.ts new file mode 100644 index 0000000000..9311ee37c7 --- /dev/null +++ b/modules/huds/hudsSituaciones.controller.ts @@ -0,0 +1,133 @@ +import { PacienteCtr } from '../../core-v2/mpi/paciente/paciente.routes'; +import { SnomedCtr } from '../../core/term/controller/snomed.controller'; +import { Prestacion } from '../rup/schemas/prestacion'; +import { CarnetPerinatal } from '../perinatal/schemas/carnet-perinatal.schema'; +import { buscarEnHuds } from '../rup/controllers/rup'; +import * as moment from 'moment'; + +// SNOMED ECL para antecedentes familiares +const ECL_ANTECEDENTES_FAMILIARES = '<< 57177007'; + +function registrosPorSemanticTag(registros, semanticTag) { + const result = []; + for (const registro of registros) { + if (registro.concepto && registro.concepto.semanticTag === semanticTag) { + result.push(registro); + } + if (registro.registros && registro.registros.length > 0) { + result.push(...registrosPorSemanticTag(registro.registros, semanticTag)); + } + } + return result; +} + +export async function situacionesActivas(pacienteID) { + const paciente = await PacienteCtr.findById(pacienteID); + if (!paciente) { + return null; + } + + const result: any[] = []; + + const prestaciones: any[] = await Prestacion.find({ + 'paciente.id': { $in: paciente.vinculos }, + 'estadoActual.tipo': 'validada' + }); + + for (const prestacion of prestaciones) { + const registros = registrosPorSemanticTag(prestacion.ejecucion.registros || [], 'trastorno'); + for (const registro of registros) { + result.push({ + tipo: 'trastorno', + concepto: registro.concepto, + fecha: prestacion.ejecucion.fecha, + profesional: prestacion.solicitud.profesional, + organizacion: prestacion.ejecucion.organizacion, + idPrestacion: prestacion._id, + tipoPrestacion: prestacion.solicitud.tipoPrestacion + }); + } + } + + // Usar vinculos para cubrir pacientes con mĂșltiples identificadores ANDES + const carnet: any = await CarnetPerinatal.findOne({ + 'paciente.id': { $in: paciente.vinculos }, + fechaFinEmbarazo: null + }); + + if (carnet && carnet.embarazoEnCurso) { + const controles = (carnet.controles || []).sort( + (a, b) => moment(b.fechaControl).valueOf() - moment(a.fechaControl).valueOf() + ); + const ultimoControl = controles.length > 0 ? controles[0] : null; + + if (ultimoControl && moment(ultimoControl.fechaControl).isAfter(moment().subtract(9, 'months'))) { + result.push({ + tipo: 'embarazo', + situacion: 'embarazo en curso', + fechaUltimoControl: ultimoControl.fechaControl, + profesional: ultimoControl.profesional, + idPrestacion: ultimoControl.idPrestacion, + organizacion: ultimoControl.organizacion + }); + } + } + + return result; +} + +/** + * Antecedentes personales: trastornos registrados en prestaciones validadas del paciente. + * Filtra por semanticTag === 'trastorno' en memoria (sin llamada a Snowstorm). + * Incluye registros anidados recursivamente. + */ +export async function antecedentesPersonales(pacienteID) { + const paciente = await PacienteCtr.findById(pacienteID); + if (!paciente) { + return null; + } + + const prestaciones: any[] = await Prestacion.find({ + 'paciente.id': { $in: paciente.vinculos }, + 'estadoActual.tipo': 'validada' + }); + + const result: any[] = []; + + for (const prestacion of prestaciones) { + const registros = registrosPorSemanticTag(prestacion.ejecucion.registros || [], 'trastorno'); + for (const registro of registros) { + result.push({ + concepto: registro.concepto, + fecha: prestacion.ejecucion.fecha, + profesional: prestacion.solicitud.profesional, + organizacion: prestacion.ejecucion.organizacion, + idPrestacion: prestacion._id, + tipoPrestacion: prestacion.solicitud.tipoPrestacion + }); + } + } + + return result; +} + +export async function antecedentesFamiliares(pacienteID) { + const paciente = await PacienteCtr.findById(pacienteID); + if (!paciente) { + return null; + } + + const expression = '<< 57177007'; + const conceptos = await SnomedCtr.getConceptByExpression(expression); + + if (!conceptos || conceptos.length === 0) { + return []; + } + + const prestaciones: any[] = await Prestacion.find({ + 'paciente.id': { $in: paciente.vinculos }, + 'estadoActual.tipo': 'validada' + }); + + return buscarEnHuds(prestaciones, conceptos); +} diff --git a/modules/huds/hudsSituaciones.routes.ts b/modules/huds/hudsSituaciones.routes.ts new file mode 100644 index 0000000000..af0aaf4dc0 --- /dev/null +++ b/modules/huds/hudsSituaciones.routes.ts @@ -0,0 +1,44 @@ +import * as express from 'express'; +import { Types } from 'mongoose'; +import { Auth } from '../../auth/auth.class'; +import { asyncHandler } from '@andes/api-tool'; +import { situacionesActivas, antecedentesPersonales, antecedentesFamiliares } from './hudsSituaciones.controller'; + +const router = express.Router(); + +router.use(Auth.authenticate()); + +router.get('/:idPaciente/situacionesActivas', asyncHandler(async (req: any, res) => { + if (!Types.ObjectId.isValid(req.params.idPaciente)) { + return res.status(404).send('Paciente no encontrado'); + } + const result = await situacionesActivas(req.params.idPaciente); + if (!result) { + return res.status(404).send('Paciente no encontrado'); + } + res.json(result); +})); + +router.get('/:idPaciente/antecedentesPersonales', asyncHandler(async (req: any, res) => { + if (!Types.ObjectId.isValid(req.params.idPaciente)) { + return res.status(404).send('Paciente no encontrado'); + } + const result = await antecedentesPersonales(req.params.idPaciente); + if (!result) { + return res.status(404).send('Paciente no encontrado'); + } + res.json(result); +})); + +router.get('/:idPaciente/AntecedentesFamiliares', asyncHandler(async (req: any, res) => { + if (!Types.ObjectId.isValid(req.params.idPaciente)) { + return res.status(404).send('Paciente no encontrado'); + } + const result = await antecedentesFamiliares(req.params.idPaciente); + if (!result) { + return res.status(404).send('Paciente no encontrado'); + } + res.json(result); +})); + +export const HudsSituacionesRouter = router; diff --git a/modules/huds/index.ts b/modules/huds/index.ts index 68f7974de2..25b272d577 100644 --- a/modules/huds/index.ts +++ b/modules/huds/index.ts @@ -1,2 +1,3 @@ export { HudsAccesosCtr } from './hudsAccesos.controller'; export { HudsAccesoRouter } from './hudsAccesos.routes'; +export { HudsSituacionesRouter } from './hudsSituaciones.routes'; diff --git a/modules/perinatal/schemas/carnet-perinatal.schema.ts b/modules/perinatal/schemas/carnet-perinatal.schema.ts index 988b53594c..92559c085b 100644 --- a/modules/perinatal/schemas/carnet-perinatal.schema.ts +++ b/modules/perinatal/schemas/carnet-perinatal.schema.ts @@ -1,6 +1,7 @@ import { Schema, Types, model } from 'mongoose'; import { AuditPlugin } from '@andes/mongoose-plugin-audit'; import { PacienteSubSchema } from '../../../core-v2/mpi/paciente/paciente.schema'; +import * as moment from 'moment'; export const CarnetPerinatalSchema = new Schema({ fecha: Date, @@ -38,6 +39,21 @@ export const CarnetPerinatalSchema = new Schema({ nota: String }); +CarnetPerinatalSchema.virtual('embarazoEnCurso').get(function () { + if (this.fechaFinEmbarazo) { + return false; + } + + const fechaRef = this.fechaUltimoControl || this.fecha; + + if (!fechaRef) { + return false; + } + + const diezMeses = moment().subtract(10, 'months').toDate(); + return moment(fechaRef).isAfter(diezMeses); +}); + CarnetPerinatalSchema.plugin(AuditPlugin); export const CarnetPerinatal = model('carnet-perinatal', CarnetPerinatalSchema, 'carnet-perinatal'); From c2bf09f0eccc2ab91bad76822610fa14df5278fd Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:53:22 -0300 Subject: [PATCH 2/3] fix - de conceptos harcodeadas a buscar en la base de datos --- modules/huds/hudsSituaciones.controller.ts | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/modules/huds/hudsSituaciones.controller.ts b/modules/huds/hudsSituaciones.controller.ts index 9311ee37c7..1f74a8520e 100644 --- a/modules/huds/hudsSituaciones.controller.ts +++ b/modules/huds/hudsSituaciones.controller.ts @@ -5,8 +5,7 @@ import { CarnetPerinatal } from '../perinatal/schemas/carnet-perinatal.schema'; import { buscarEnHuds } from '../rup/controllers/rup'; import * as moment from 'moment'; -// SNOMED ECL para antecedentes familiares -const ECL_ANTECEDENTES_FAMILIARES = '<< 57177007'; +import { ECLQueries } from '../../core/tm/schemas/eclqueries.schema'; function registrosPorSemanticTag(registros, semanticTag) { const result = []; @@ -87,28 +86,28 @@ export async function antecedentesPersonales(pacienteID) { return null; } + const eclQuery = await ECLQueries.findOne({ key: 'antecedentes_personales' }); + const expression = eclQuery ? eclQuery.valor : '<< 312850006'; + const conceptos = await SnomedCtr.getConceptByExpression(expression); + + if (!conceptos || conceptos.length === 0) { + return []; + } + const prestaciones: any[] = await Prestacion.find({ 'paciente.id': { $in: paciente.vinculos }, 'estadoActual.tipo': 'validada' }); - const result: any[] = []; - - for (const prestacion of prestaciones) { - const registros = registrosPorSemanticTag(prestacion.ejecucion.registros || [], 'trastorno'); - for (const registro of registros) { - result.push({ - concepto: registro.concepto, - fecha: prestacion.ejecucion.fecha, - profesional: prestacion.solicitud.profesional, - organizacion: prestacion.ejecucion.organizacion, - idPrestacion: prestacion._id, - tipoPrestacion: prestacion.solicitud.tipoPrestacion - }); - } - } - - return result; + const results = buscarEnHuds(prestaciones, conceptos); + return results.map(item => ({ + concepto: item.registro.concepto, + fecha: item.fecha, + profesional: item.profesional, + organizacion: item.organizacion, + idPrestacion: item.idPrestacion, + tipoPrestacion: item.tipoPrestacion + })); } export async function antecedentesFamiliares(pacienteID) { @@ -117,7 +116,8 @@ export async function antecedentesFamiliares(pacienteID) { return null; } - const expression = '<< 57177007'; + const eclQuery = await ECLQueries.findOne({ key: 'antecedentes_familiares' }); + const expression = eclQuery ? eclQuery.valor : '<< 57177007'; const conceptos = await SnomedCtr.getConceptByExpression(expression); if (!conceptos || conceptos.length === 0) { From ad57137e2556a00437fc41dd35753ff4023d6fa7 Mon Sep 17 00:00:00 2001 From: MarianoCampetella Date: Mon, 7 Sep 2026 15:08:19 -0300 Subject: [PATCH 3/3] correcciones 07/09 --- modules/huds/hudsSituaciones.controller.ts | 32 ++++++++-------------- modules/huds/hudsSituaciones.routes.ts | 2 +- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/modules/huds/hudsSituaciones.controller.ts b/modules/huds/hudsSituaciones.controller.ts index 1f74a8520e..6e6a3a2db1 100644 --- a/modules/huds/hudsSituaciones.controller.ts +++ b/modules/huds/hudsSituaciones.controller.ts @@ -36,15 +36,17 @@ export async function situacionesActivas(pacienteID) { for (const prestacion of prestaciones) { const registros = registrosPorSemanticTag(prestacion.ejecucion.registros || [], 'trastorno'); for (const registro of registros) { - result.push({ - tipo: 'trastorno', - concepto: registro.concepto, - fecha: prestacion.ejecucion.fecha, - profesional: prestacion.solicitud.profesional, - organizacion: prestacion.ejecucion.organizacion, - idPrestacion: prestacion._id, - tipoPrestacion: prestacion.solicitud.tipoPrestacion - }); + if (registro.valor?.estado === 'activo') { + result.push({ + tipo: 'trastorno', + concepto: registro.concepto, + fecha: prestacion.ejecucion.fecha, + profesional: prestacion.solicitud.profesional, + organizacion: prestacion.ejecucion.organizacion, + idPrestacion: prestacion._id, + tipoPrestacion: prestacion.solicitud.tipoPrestacion + }); + } } } @@ -89,7 +91,6 @@ export async function antecedentesPersonales(pacienteID) { const eclQuery = await ECLQueries.findOne({ key: 'antecedentes_personales' }); const expression = eclQuery ? eclQuery.valor : '<< 312850006'; const conceptos = await SnomedCtr.getConceptByExpression(expression); - if (!conceptos || conceptos.length === 0) { return []; } @@ -99,15 +100,7 @@ export async function antecedentesPersonales(pacienteID) { 'estadoActual.tipo': 'validada' }); - const results = buscarEnHuds(prestaciones, conceptos); - return results.map(item => ({ - concepto: item.registro.concepto, - fecha: item.fecha, - profesional: item.profesional, - organizacion: item.organizacion, - idPrestacion: item.idPrestacion, - tipoPrestacion: item.tipoPrestacion - })); + return buscarEnHuds(prestaciones, conceptos); } export async function antecedentesFamiliares(pacienteID) { @@ -119,7 +112,6 @@ export async function antecedentesFamiliares(pacienteID) { const eclQuery = await ECLQueries.findOne({ key: 'antecedentes_familiares' }); const expression = eclQuery ? eclQuery.valor : '<< 57177007'; const conceptos = await SnomedCtr.getConceptByExpression(expression); - if (!conceptos || conceptos.length === 0) { return []; } diff --git a/modules/huds/hudsSituaciones.routes.ts b/modules/huds/hudsSituaciones.routes.ts index af0aaf4dc0..0c0f298aca 100644 --- a/modules/huds/hudsSituaciones.routes.ts +++ b/modules/huds/hudsSituaciones.routes.ts @@ -30,7 +30,7 @@ router.get('/:idPaciente/antecedentesPersonales', asyncHandler(async (req: any, res.json(result); })); -router.get('/:idPaciente/AntecedentesFamiliares', asyncHandler(async (req: any, res) => { +router.get('/:idPaciente/antecedentesFamiliares', asyncHandler(async (req: any, res) => { if (!Types.ObjectId.isValid(req.params.idPaciente)) { return res.status(404).send('Paciente no encontrado'); }