Agregado filtro por tipo de documento en ITI-67

Find Document References ahora acepta un parametro opcional 'type'
(IPS, MeOW, IT, o un token FHIR system|code) para buscar solo el
tipo de documento pedido. Se extrae el mapa de tipos de documento a
constants/documentTypes.js para compartirlo entre ITI-65 e ITI-67.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gomez Auad 2026-07-15 15:58:32 +00:00
parent df87fc5ee7
commit 7e1b0585e7
6 changed files with 73 additions and 42 deletions

View File

@ -20,7 +20,7 @@ El componente actúa exclusivamente como gateway: no contiene lógica de negocio
| ITI-65 | `POST` | `/fhir/MeOWDocument` | Provide Document Bundle (MeOW - Medication Overview): variante document. | | ITI-65 | `POST` | `/fhir/MeOWDocument` | Provide Document Bundle (MeOW - Medication Overview): variante document. |
| ITI-65 | `POST` | `/fhir/ITTransaction` | Provide Document Bundle (IT - Consultation Note / respuesta de interconsulta): variante transacción. | | ITI-65 | `POST` | `/fhir/ITTransaction` | Provide Document Bundle (IT - Consultation Note / respuesta de interconsulta): variante transacción. |
| ITI-65 | `POST` | `/fhir/ITDocument` | Provide Document Bundle (IT - Consultation Note): variante document. | | ITI-65 | `POST` | `/fhir/ITDocument` | Provide Document Bundle (IT - Consultation Note): variante document. |
| ITI-67 | `GET` | `/fhir/DocumentReference` | Find Document References: busca el paciente por ID local en el MPI para obtener su ID nacional y consulta los DocumentReferences en el Document Registry. | | ITI-67 | `GET` | `/fhir/DocumentReference` | Find Document References: busca el paciente por ID local en el MPI para obtener su ID nacional y consulta los DocumentReferences en el Document Registry. Admite filtrar por tipo de documento con el parámetro opcional `type` (`IPS`, `MeOW`, `IT`, o un token FHIR `system\|code`). |
| ITI-78 | `GET` | `/fhir/Patient` | Patient Demographics Query: búsqueda de pacientes en el MPI. | | ITI-78 | `GET` | `/fhir/Patient` | Patient Demographics Query: búsqueda de pacientes en el MPI. |
| ITI-78 | `GET` | `/fhir/Patient/:id` | Patient Demographics Query: obtención de un paciente por ID en el MPI. | | ITI-78 | `GET` | `/fhir/Patient/:id` | Patient Demographics Query: obtención de un paciente por ID en el MPI. |
| ITI-104 | `POST` | `/fhir/Patient` | Patient Identity Feed: alta de paciente en el MPI. | | ITI-104 | `POST` | `/fhir/Patient` | Patient Identity Feed: alta de paciente en el MPI. |

View File

@ -0,0 +1,27 @@
/**
* Tipos de documento soportados por ITI-65 (Provide Document Bundle) e ITI-67
* (Find Document References), cada uno con su código LOINC para
* DocumentReference.type.
*/
const DOCUMENT_TYPES = {
IPS: {
label: 'IPS',
system: 'http://loinc.org',
code: '60591-5',
display: 'Patient Summary Document',
},
MEOW: {
label: 'MeOW',
system: 'http://loinc.org',
code: '56445-0',
display: 'Medication summary',
},
IT: {
label: 'IT',
system: 'http://loinc.org',
code: '57133-1',
display: 'Referral note',
},
};
module.exports = { DOCUMENT_TYPES };

View File

@ -7,6 +7,7 @@ const { createDocumentReference, findDocumentReferenceById } = require('../servi
const { logger } = require('../utils/logger'); const { logger } = require('../utils/logger');
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid');
const { getResourceByUrl, processDocumentBundleTransaction } = require('../services/fhir'); const { getResourceByUrl, processDocumentBundleTransaction } = require('../services/fhir');
const { DOCUMENT_TYPES } = require('../constants/documentTypes');
const DOCUMENT_REFERENCE_RESOURCE_TYPE = "DocumentReference"; const DOCUMENT_REFERENCE_RESOURCE_TYPE = "DocumentReference";
@ -20,32 +21,6 @@ const DNI_SYSTEM = 'http://www.renaper.gob.ar/dni';
const CUSTODIAN_ID_SYSTEM = 'http://federador.msal.gob.ar/uri'; const CUSTODIAN_ID_SYSTEM = 'http://federador.msal.gob.ar/uri';
const MASTER_ID_SYSTEM = 'urn:ietf:rfc:3986' const MASTER_ID_SYSTEM = 'urn:ietf:rfc:3986'
/**
* Tipos de documento soportados por ITI-65, cada uno con su código LOINC
* para DocumentReference.type (y, en la variante "document", también para
* el DocumentReference local generado dentro de la transacción).
*/
const DOCUMENT_TYPES = {
IPS: {
label: 'IPS',
system: 'http://loinc.org',
code: '60591-5',
display: 'Patient Summary Document',
},
MEOW: {
label: 'MeOW',
system: 'http://loinc.org',
code: '56445-0',
display: 'Medication summary',
},
IT: {
label: 'IT',
system: 'http://loinc.org',
code: '57133-1',
display: 'Referral note',
},
};
function extractResource(resources, resourceType) { function extractResource(resources, resourceType) {
return resources.filter(r => r.resourceType === resourceType)[0]; return resources.filter(r => r.resourceType === resourceType)[0];

View File

@ -3,6 +3,7 @@ const config = require('../config');
const { getBusToken } = require('../utils/busAuth'); const { getBusToken } = require('../utils/busAuth');
const { findPatient } = require('../services/patient'); const { findPatient } = require('../services/patient');
const { findDocumentReferenceByPatient } = require('../services/documentReference'); const { findDocumentReferenceByPatient } = require('../services/documentReference');
const { DOCUMENT_TYPES } = require('../constants/documentTypes');
const NATIONAL_ID_SYSTEM = 'https://federador.msal.gob.ar/patient-id'; const NATIONAL_ID_SYSTEM = 'https://federador.msal.gob.ar/patient-id';
@ -14,6 +15,20 @@ function extractNationalIdentifier(patient) {
return identifiers.find(id => id.system === NATIONAL_ID_SYSTEM) || null; return identifiers.find(id => id.system === NATIONAL_ID_SYSTEM) || null;
} }
/**
* Resuelve el parámetro de búsqueda `type` a un token FHIR (`system|code`).
* Acepta tanto las etiquetas conocidas (IPS, MeOW, IT case-insensitive)
* como un token FHIR ya armado (`system|code` o `code`), que se pasa tal cual
* para no acoplar la búsqueda a los tipos de documento ya conocidos.
*/
function resolveDocumentType(rawType) {
if (!rawType) return undefined;
const knownType = Object.values(DOCUMENT_TYPES).find(
t => t.label.toLowerCase() === rawType.toLowerCase()
);
return knownType ? `${knownType.system}|${knownType.code}` : rawType;
}
/** /**
@ -21,15 +36,22 @@ function extractNationalIdentifier(patient) {
* *
* GET /fhir/DocumentReference?subject=:localId * GET /fhir/DocumentReference?subject=:localId
* GET /fhir/DocumentReference?patient.identifier=:localId * GET /fhir/DocumentReference?patient.identifier=:localId
* GET /fhir/DocumentReference?subject=:localId&type=:type
* *
* Flow: * Flow:
* 1. Fetch the Patient from the Bus by local ID to obtain the national identifier. * 1. Fetch the Patient from the Bus by local ID to obtain the national identifier.
* 2. Search DocumentReferences in the Bus by that national identifier. * 2. Search DocumentReferences in the Bus by that national identifier
* (opcionalmente filtrando por tipo de documento).
* 3. Return the resulting Bundle. * 3. Return the resulting Bundle.
* *
* Required query parameter (one of): * Required query parameter (one of):
* subject local Patient ID in the Bus. * subject local Patient ID in the Bus.
* patient.identifier same semantics, alternate FHIR parameter name. * patient.identifier same semantics, alternate FHIR parameter name.
*
* Optional query parameter:
* type tipo de documento a buscar. Acepta las etiquetas conocidas
* (IPS, MeOW, IT) o un token FHIR (`system|code`, ej: `http://loinc.org|60591-5`).
* Si se omite, devuelve documentos de cualquier tipo.
*/ */
async function listDocumentReference(req, res, next) { async function listDocumentReference(req, res, next) {
try { try {
@ -37,6 +59,7 @@ async function listDocumentReference(req, res, next) {
if (!localPatientIdentifier) { if (!localPatientIdentifier) {
throw createError(400, 'Missing required query parameter: subject or patient.identifier'); throw createError(400, 'Missing required query parameter: subject or patient.identifier');
} }
const documentType = resolveDocumentType(req.query.type);
const token = await getBusToken( const token = await getBusToken(
config.bus.url, config.bus.url,
config.bus.jwtSecret, config.bus.jwtSecret,
@ -46,14 +69,15 @@ async function listDocumentReference(req, res, next) {
config.bus.documentRegistryScope config.bus.documentRegistryScope
].join(',') ].join(',')
); );
// 1. Obtengo el identificador nacional del paciente en forma de referencia // 1. Obtengo el identificador nacional del paciente en forma de referencia
const patientSearchset = await findPatient(token, { identifier: localPatientIdentifier }); const patientSearchset = await findPatient(token, { identifier: localPatientIdentifier });
if (!patientSearchset) { if (!patientSearchset) {
throw createError(422, 'Could not resolve national identifier for the given patient'); throw createError(422, 'Could not resolve national identifier for the given patient');
} }
const patientNationalId = patientSearchset.entry[0].fullUrl const patientNationalId = patientSearchset.entry[0].fullUrl
// 2. Obtengo el listado de entradas del indice de atenciones asociadada al id de paciente. // 2. Obtengo el listado de entradas del indice de atenciones asociadada al id de paciente
const documentReferenceSearchset = await findDocumentReferenceByPatient(token, patientNationalId) // (y, si se pidió, al tipo de documento).
const documentReferenceSearchset = await findDocumentReferenceByPatient(token, patientNationalId, documentType)
res.status(200).json(documentReferenceSearchset); res.status(200).json(documentReferenceSearchset);
} catch (err) { } catch (err) {

View File

@ -8,15 +8,16 @@ sequenceDiagram
participant IndiceNacion as Indice Documentos participant IndiceNacion as Indice Documentos
end end
participant NodoDominio2 as Nodo B participant NodoDominio2 as Nodo B
Note over HIS_A,FederadorNacion: Tipos soportados: IPS, MeOW, IT (parámetro opcional type)
Note over HIS_A,FederadorNacion: 1. Busqueda y resolución de Identidad Note over HIS_A,FederadorNacion: 1. Busqueda y resolución de Identidad
HIS_A->>NodoDominio: ITI67: Solicita los IPS asociados al paciente por su identificador local <br /> [GET /DocumentReference?patient.identifier=<ID_Local>] HIS_A->>NodoDominio: ITI67: Solicita los documentos asociados al paciente por su identificador local, opcionalmente filtrando por tipo <br /> [GET /DocumentReference?patient.identifier=<ID_Local>&type=<IPS|MeOW|IT>]
NodoDominio->>FederadorNacion: Busca el paciente por su identificador local <br /> [GET /Patient?identifier=<ID_Local>] NodoDominio->>FederadorNacion: Busca el paciente por su identificador local <br /> [GET /Patient?identifier=<ID_Local>]
FederadorNacion-->>NodoDominio: 200 OK (Patient Searchset) FederadorNacion-->>NodoDominio: 200 OK (Patient Searchset)
Note over NodoDominio,IndiceNacion: 2. Busqueda de Metadatos Note over NodoDominio,IndiceNacion: 2. Busqueda de Metadatos
Note right of NodoDominio: El Nodo obtiene el identificador nacional del paciente Note right of NodoDominio: El Nodo obtiene el identificador nacional del paciente
NodoDominio->>IndiceNacion: Busca los IPS asociados al paciente por su identificador nacional <br /> [GET /DocumentReference?patient=<ID_Nacional>] NodoDominio->>IndiceNacion: Busca los documentos asociados al paciente por su identificador nacional (y tipo, si se pidió) <br /> [GET /DocumentReference?patient=<ID_Nacional>&type=<system|code>]
IndiceNacion-->>NodoDominio: 200 OK (DocumentReference Searchset) IndiceNacion-->>NodoDominio: 200 OK (DocumentReference Searchset)
NodoDominio-->>HIS_A: 200 OK (DocumentReference Searchset) NodoDominio-->>HIS_A: 200 OK (DocumentReference Searchset)
Note over HIS_A,NodoDominio2: 3. Descarga del documento (ITI-68) Note over HIS_A,NodoDominio2: 3. Descarga del documento (ITI-68)
HIS_A->>NodoDominio2: Obtiene el documento IPS <br /> [GET <URL_IPSBundle>] HIS_A->>NodoDominio2: Obtiene el documento <br /> [GET <URL_Bundle>]
NodoDominio2-->>HIS_A: 200 OK (IPS Bundle) NodoDominio2-->>HIS_A: 200 OK (Bundle)

View File

@ -69,20 +69,24 @@ async function findDocumentReferenceBySubject(token, subjectSystem, subjectValue
} }
/** /**
* Searches DocumentReferences in the document registry by patient internal ID * Searches DocumentReferences in the document registry by patient internal ID,
* (GET /fhir/DocumentReference?patient=value). * opcionalmente filtrando por tipo de documento
* (GET /fhir/DocumentReference?patient=value[&type=system|code]).
* @param {string} documentRegistryUrl - Base URL of the document registry service. * @param {string} documentRegistryUrl - Base URL of the document registry service.
* @param {string} token - Bearer access token. * @param {string} token - Bearer access token.
* @param {string} patientId - Internal patient ID in the document registry. * @param {string} patientId - Internal patient ID in the document registry.
* @param {string} [type] - Token FHIR (`system|code` o `code`) de DocumentReference.type, ej: `http://loinc.org|60591-5`.
* @returns {Promise<object>} FHIR Bundle (searchset) with matching DocumentReferences. * @returns {Promise<object>} FHIR Bundle (searchset) with matching DocumentReferences.
*/ */
async function findDocumentReferenceByPatient(token, patientId) { async function findDocumentReferenceByPatient(token, patientId, type) {
const request = createBusRequest(token); const request = createBusRequest(token);
const params = { subject: patientId };
if (type) {
params.type = type;
}
const response = await request.get( const response = await request.get(
URL.parse(INDICE_ATENCION_URL), URL.parse(INDICE_ATENCION_URL),
{ { params }
params: { subject: patientId },
}
); );
return response.data; return response.data;
} }