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/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-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/: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. |

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 { v4: uuidv4 } = require('uuid');
const { getResourceByUrl, processDocumentBundleTransaction } = require('../services/fhir');
const { DOCUMENT_TYPES } = require('../constants/documentTypes');
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 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) {
return resources.filter(r => r.resourceType === resourceType)[0];

View File

@ -3,6 +3,7 @@ const config = require('../config');
const { getBusToken } = require('../utils/busAuth');
const { findPatient } = require('../services/patient');
const { findDocumentReferenceByPatient } = require('../services/documentReference');
const { DOCUMENT_TYPES } = require('../constants/documentTypes');
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;
}
/**
* 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?patient.identifier=:localId
* GET /fhir/DocumentReference?subject=:localId&type=:type
*
* Flow:
* 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.
*
* Required query parameter (one of):
* subject local Patient ID in the Bus.
* 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) {
try {
@ -37,6 +59,7 @@ async function listDocumentReference(req, res, next) {
if (!localPatientIdentifier) {
throw createError(400, 'Missing required query parameter: subject or patient.identifier');
}
const documentType = resolveDocumentType(req.query.type);
const token = await getBusToken(
config.bus.url,
config.bus.jwtSecret,
@ -46,14 +69,15 @@ async function listDocumentReference(req, res, next) {
config.bus.documentRegistryScope
].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 });
if (!patientSearchset) {
throw createError(422, 'Could not resolve national identifier for the given patient');
}
const patientNationalId = patientSearchset.entry[0].fullUrl
// 2. Obtengo el listado de entradas del indice de atenciones asociadada al id de paciente.
const documentReferenceSearchset = await findDocumentReferenceByPatient(token, patientNationalId)
// 2. Obtengo el listado de entradas del indice de atenciones asociadada al id de paciente
// (y, si se pidió, al tipo de documento).
const documentReferenceSearchset = await findDocumentReferenceByPatient(token, patientNationalId, documentType)
res.status(200).json(documentReferenceSearchset);
} catch (err) {

View File

@ -8,15 +8,16 @@ sequenceDiagram
participant IndiceNacion as Indice Documentos
end
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
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>]
FederadorNacion-->>NodoDominio: 200 OK (Patient Searchset)
Note over NodoDominio,IndiceNacion: 2. Busqueda de Metadatos
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>]
Note right of NodoDominio: El Nodo obtiene el identificador nacional del paciente
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)
NodoDominio-->>HIS_A: 200 OK (DocumentReference Searchset)
Note over HIS_A,NodoDominio2: 3. Descarga del documento (ITI-68)
HIS_A->>NodoDominio2: Obtiene el documento IPS <br /> [GET <URL_IPSBundle>]
NodoDominio2-->>HIS_A: 200 OK (IPS Bundle)
HIS_A->>NodoDominio2: Obtiene el documento <br /> [GET <URL_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
* (GET /fhir/DocumentReference?patient=value).
* Searches DocumentReferences in the document registry by patient internal ID,
* 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} token - Bearer access token.
* @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.
*/
async function findDocumentReferenceByPatient(token, patientId) {
async function findDocumentReferenceByPatient(token, patientId, type) {
const request = createBusRequest(token);
const params = { subject: patientId };
if (type) {
params.type = type;
}
const response = await request.get(
URL.parse(INDICE_ATENCION_URL),
{
params: { subject: patientId },
}
{ params }
);
return response.data;
}