From 9199146f569417e71e976e5b244203fa27edf716 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/2] 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 66a5d6069e..0eb25777e6 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 48aa2ba07bf527af7c0cc88e4a78bdf9d3d462ba 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/2] 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) {