From df87fc5ee788b95ae8cd63536a9fd63f15ea93cb Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Auad Date: Wed, 15 Jul 2026 03:14:32 +0000 Subject: [PATCH] Agregadas variantes de ITI-65 para MeOW e IT ademas de IPS Se generaliza el controller para recibir el tipo de documento (LOINC) en vez de hardcodear el de IPS, y se agregan las rutas y mapeos de nginx para /fhir/MeOWTransaction, /fhir/MeOWDocument, /fhir/ITTransaction y /fhir/ITDocument, siguiendo la misma logica que las rutas IPS existentes. Co-Authored-By: Claude Sonnet 5 --- bus-gateway/README.md | 9 +- bus-gateway/controllers/iti65.js | 151 ++++++---- bus-gateway/docs/iti65.mmd | 9 +- bus-gateway/routes/iti65.js | 21 +- nginx/http.conf | 40 +++ nginx/https.conf | 40 +++ tests/fixtures/iti65/bundle-document-it.json | 121 ++++++++ .../fixtures/iti65/bundle-document-meow.json | 177 ++++++++++++ .../fixtures/iti65/bundle-transaction-it.json | 188 +++++++++++++ .../iti65/bundle-transaction-meow.json | 258 ++++++++++++++++++ 10 files changed, 949 insertions(+), 65 deletions(-) create mode 100644 tests/fixtures/iti65/bundle-document-it.json create mode 100644 tests/fixtures/iti65/bundle-document-meow.json create mode 100644 tests/fixtures/iti65/bundle-transaction-it.json create mode 100644 tests/fixtures/iti65/bundle-transaction-meow.json diff --git a/bus-gateway/README.md b/bus-gateway/README.md index 0183409..f8a750d 100644 --- a/bus-gateway/README.md +++ b/bus-gateway/README.md @@ -14,7 +14,12 @@ El componente actúa exclusivamente como gateway: no contiene lógica de negocio | Transacción | Método | Ruta | Descripción | |---|---|---|---| -| ITI-65 | `POST` | `/fhir/Bundle` | Provide Document Bundle: almacena el Bundle en HAPI FHIR, resuelve el ID nacional del paciente vía `$match` en el Bus y registra el DocumentReference en el Document Registry. | +| ITI-65 | `POST` | `/fhir/IPSTransaction` | Provide Document Bundle (IPS): variante transacción — el cliente envía el Bundle transaction completo (Patient, Bundle document, DocumentReference, List). | +| ITI-65 | `POST` | `/fhir/IPSDocument` | Provide Document Bundle (IPS): variante document — el cliente envía solo el Bundle IPS (`type: document`); el gateway arma la transacción internamente. | +| ITI-65 | `POST` | `/fhir/MeOWTransaction` | Provide Document Bundle (MeOW - Medication Overview): variante transacción. | +| 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-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. | @@ -136,7 +141,7 @@ docker compose logs -f ## Headers requeridos por transacción -### ITI-65 `POST /fhir/Bundle` +### ITI-65 `POST /fhir/IPSTransaction`, `/fhir/IPSDocument`, `/fhir/MeOWTransaction`, `/fhir/MeOWDocument`, `/fhir/ITTransaction`, `/fhir/ITDocument` | Header | Descripción | |---|---| diff --git a/bus-gateway/controllers/iti65.js b/bus-gateway/controllers/iti65.js index e0001f9..8e82e9b 100644 --- a/bus-gateway/controllers/iti65.js +++ b/bus-gateway/controllers/iti65.js @@ -20,6 +20,32 @@ 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]; @@ -31,7 +57,7 @@ function extractLocalIdentifier(patient) { })[0]; } -function generateDocumentReferenceResource(subjectReference, bundleUrl) { +function generateDocumentReferenceResource(subjectReference, bundleUrl, docType) { const documentRefernece = { resourceType: 'DocumentReference', status: 'current', @@ -43,9 +69,9 @@ function generateDocumentReferenceResource(subjectReference, bundleUrl) { type: { coding: [ { - system: 'http://loinc.org', - code: '60591-5', - display: 'Patient Summary Document', + system: docType.system, + code: docType.code, + display: docType.display, }, ], }, @@ -77,19 +103,20 @@ async function getResourcesFromTransactionResponse(transactionResponse) { } /** - * Construye un Bundle de tipo transaction a partir de un Bundle de tipo document (IPS). - * Genera Patient, Bundle (IPS), DocumentReference y List (SubmissionSet MHD). + * Construye un Bundle de tipo transaction a partir de un Bundle de tipo document + * (IPS, MeOW, IT, ...). Genera Patient, Bundle (documento), DocumentReference y + * List (SubmissionSet MHD). * Usa urn:uuid: como fullUrl para que HAPI FHIR resuelva las referencias internas. */ -function buildTransactionFromIPSDocument(ipsBundle) { - if (ipsBundle.type !== 'document') { +function buildTransactionFromDocumentBundle(documentBundle, docType) { + if (documentBundle.type !== 'document') { throw createError(400, 'Bundle must be of type document'); } - const patientEntry = (ipsBundle.entry || []).find( + const patientEntry = (documentBundle.entry || []).find( e => e.resource && e.resource.resourceType === 'Patient' ); if (!patientEntry) { - throw createError(400, 'IPS Bundle must contain a Patient resource'); + throw createError(400, `${docType.label} Bundle must contain a Patient resource`); } const patientFullUrl = `urn:uuid:${uuidv4()}`; @@ -108,9 +135,9 @@ function buildTransactionFromIPSDocument(ipsBundle) { }, type: { coding: [{ - system: 'http://loinc.org', - code: '60591-5', - display: 'Patient Summary Document', + system: docType.system, + code: docType.code, + display: docType.display, }] }, date: now, @@ -158,7 +185,7 @@ function buildTransactionFromIPSDocument(ipsBundle) { }, { fullUrl: bundleFullUrl, - resource: ipsBundle, + resource: documentBundle, request: { method: 'POST', url: 'Bundle' } }, { @@ -178,7 +205,7 @@ function buildTransactionFromIPSDocument(ipsBundle) { * Lógica central de ITI-65: persiste la transacción en HAPI FHIR, resuelve el * paciente en el Bus y registra un DocumentReference apuntando al Bundle guardado. */ -async function executeITI65(transaction, token) { +async function executeITI65(transaction, token, docType) { const transactionResponse = await processDocumentBundleTransaction(transaction); const resources = await getResourcesFromTransactionResponse(transactionResponse); @@ -193,59 +220,73 @@ async function executeITI65(transaction, token) { const nationalPatientId = patientSearchset.entry[0].fullUrl; const bundleReference = `${config.baseURL}/fhir/Bundle/${localIPSDocument.id}`; - const documentReference = generateDocumentReferenceResource(nationalPatientId, bundleReference); + const documentReference = generateDocumentReferenceResource(nationalPatientId, bundleReference, docType); return createDocumentReference(token, documentReference); } +async function acquireToken() { + return getBusToken( + config.bus.url, + config.bus.jwtSecret, + config.bus.issuer, + [config.bus.mpiScope, config.bus.documentRegistryScope].join(',') + ); +} + /** * ITI-65: Provide Document Bundle (MHD) — variante transacción * - * POST /fhir/iti65 - * * Espera un Bundle de tipo transaction construido por el cliente. */ -async function provideIPSTransaction(req, res, next) { - try { - const transaction = req.body; - const token = await getBusToken( - config.bus.url, - config.bus.jwtSecret, - config.bus.issuer, - [config.bus.mpiScope, config.bus.documentRegistryScope].join(',') - ); - const result = await executeITI65(transaction, token); - return res.status(200).json(result); - } catch (err) { - next(err); - } +function provideTransaction(docType) { + return async function (req, res, next) { + try { + const transaction = req.body; + const token = await acquireToken(); + const result = await executeITI65(transaction, token, docType); + return res.status(200).json(result); + } catch (err) { + next(err); + } + }; } /** - * ITI-65: Provide Document Bundle (MHD) — variante IPS document + * ITI-65: Provide Document Bundle (MHD) — variante document * - * POST /fhir/Bundle - * - * Espera un Bundle de tipo document (IPS). Genera internamente el Bundle - * transaction y ejecuta el mismo flujo que provideDocumentBundle. + * Espera un Bundle de tipo document. Genera internamente el Bundle transaction + * (Patient, Bundle, DocumentReference, List) y ejecuta el mismo flujo que + * provideTransaction. */ -async function provideIPSDocumentBundle(req, res, next) { - try { - const ipsBundle = req.body; - if (!ipsBundle || ipsBundle.resourceType !== 'Bundle') { - throw createError(400, 'Request body must be a FHIR Bundle resource'); +function provideDocumentBundle(docType) { + return async function (req, res, next) { + try { + const documentBundle = req.body; + if (!documentBundle || documentBundle.resourceType !== 'Bundle') { + throw createError(400, 'Request body must be a FHIR Bundle resource'); + } + const transaction = buildTransactionFromDocumentBundle(documentBundle, docType); + const token = await acquireToken(); + const result = await executeITI65(transaction, token, docType); + return res.status(200).json(result); + } catch (err) { + next(err); } - const transaction = buildTransactionFromIPSDocument(ipsBundle); - const token = await getBusToken( - config.bus.url, - config.bus.jwtSecret, - config.bus.issuer, - [config.bus.mpiScope, config.bus.documentRegistryScope].join(',') - ); - const result = await executeITI65(transaction, token); - return res.status(200).json(result); - } catch (err) { - next(err); - } + }; } -module.exports = { provideIPSTransaction, provideIPSDocumentBundle }; +const provideIPSTransaction = provideTransaction(DOCUMENT_TYPES.IPS); +const provideIPSDocumentBundle = provideDocumentBundle(DOCUMENT_TYPES.IPS); +const provideMeOWTransaction = provideTransaction(DOCUMENT_TYPES.MEOW); +const provideMeOWDocumentBundle = provideDocumentBundle(DOCUMENT_TYPES.MEOW); +const provideITTransaction = provideTransaction(DOCUMENT_TYPES.IT); +const provideITDocumentBundle = provideDocumentBundle(DOCUMENT_TYPES.IT); + +module.exports = { + provideIPSTransaction, + provideIPSDocumentBundle, + provideMeOWTransaction, + provideMeOWDocumentBundle, + provideITTransaction, + provideITDocumentBundle, +}; diff --git a/bus-gateway/docs/iti65.mmd b/bus-gateway/docs/iti65.mmd index a220e92..fc0a3b8 100644 --- a/bus-gateway/docs/iti65.mmd +++ b/bus-gateway/docs/iti65.mmd @@ -7,14 +7,15 @@ sequenceDiagram participant FederadorNacion as Federador participant IndiceNacion as Indice Documentos end - Note over HIS_A,IndiceNacion: 1. Recepcion Local del Documento Bundle (POST /Bundle) - HIS_A->>NodoDominio: ITI65: Provee un nuevo documento IPS (bundle) + Note over HIS_A,IndiceNacion: Variantes: /IPSTransaction, /IPSDocument, /MeOWTransaction, /MeOWDocument, /ITTransaction, /ITDocument + Note over HIS_A,IndiceNacion: 1. Recepcion Local del Documento Bundle + HIS_A->>NodoDominio: ITI65: Provee un nuevo documento (bundle) Note right of NodoDominio: El Nodo almacena físicamente el documento y extrae la metadata. Note over NodoDominio,FederadorNacion: 2. Resolución de Identidad NodoDominio->>FederadorNacion: Busca al paciente por el su identificador local [GET /Patient?identifier=] FederadorNacion-->>NodoDominio: 200 OK (Patient Searchset) Note over NodoDominio,IndiceNacion: 3. Enrutamiento de la Petición - Note right of NodoDominio: El Nodo genera la referencia al IPS y la asocia al identificador nacional del paciente. - NodoDominio->>IndiceNacion: Guarda la referencia al IPS en el índice de documentos [POST /DocumentReference] + Note right of NodoDominio: El Nodo genera la referencia al documento y la asocia al identificador nacional del paciente. + NodoDominio->>IndiceNacion: Guarda la referencia al documento en el índice de documentos [POST /DocumentReference] IndiceNacion-->>NodoDominio: 201 (Created) NodoDominio-->>HIS_A: 200 OK (DocumentReference) diff --git a/bus-gateway/routes/iti65.js b/bus-gateway/routes/iti65.js index 1215498..90285c0 100644 --- a/bus-gateway/routes/iti65.js +++ b/bus-gateway/routes/iti65.js @@ -1,11 +1,24 @@ const express = require('express'); const router = express.Router(); -const { provideIPSTransaction, provideIPSDocumentBundle } = require('../controllers/iti65'); +const { + provideIPSTransaction, + provideIPSDocumentBundle, + provideMeOWTransaction, + provideMeOWDocumentBundle, + provideITTransaction, + provideITDocumentBundle, +} = require('../controllers/iti65'); -// ITI-65: Provide Document Bundle — variante transaction Bundle +// ITI-65: Provide Document Bundle — IPS router.post('/IPSTransaction', provideIPSTransaction); - -// ITI-65: Provide Document Bundle — variante IPS document Bundle (type: document) router.post('/IPSDocument', provideIPSDocumentBundle); +// ITI-65: Provide Document Bundle — MeOW (Medication Overview) +router.post('/MeOWTransaction', provideMeOWTransaction); +router.post('/MeOWDocument', provideMeOWDocumentBundle); + +// ITI-65: Provide Document Bundle — IT (Consultation Note / respuesta de interconsulta) +router.post('/ITTransaction', provideITTransaction); +router.post('/ITDocument', provideITDocumentBundle); + module.exports = router; diff --git a/nginx/http.conf b/nginx/http.conf index f73d463..d526c8d 100644 --- a/nginx/http.conf +++ b/nginx/http.conf @@ -35,6 +35,46 @@ http { proxy_read_timeout 90s; } + # ITI-65: Provide Document Bundle — MeOW (Medication Overview) transaction Bundle + location /fhir/MeOWTransaction { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — MeOW (Medication Overview) document Bundle + location /fhir/MeOWDocument { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — IT (Consultation Note) transaction Bundle + location /fhir/ITTransaction { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — IT (Consultation Note) document Bundle + location /fhir/ITDocument { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + # ITI-67: Find Document References location /fhir/DocumentReference { proxy_pass http://bus_gateway; diff --git a/nginx/https.conf b/nginx/https.conf index d60efa8..338d8e9 100644 --- a/nginx/https.conf +++ b/nginx/https.conf @@ -51,6 +51,46 @@ http { proxy_read_timeout 90s; } + # ITI-65: Provide Document Bundle — MeOW (Medication Overview) transaction Bundle + location /fhir/MeOWTransaction { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — MeOW (Medication Overview) document Bundle + location /fhir/MeOWDocument { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — IT (Consultation Note) transaction Bundle + location /fhir/ITTransaction { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + + # ITI-65: Provide Document Bundle — IT (Consultation Note) document Bundle + location /fhir/ITDocument { + proxy_pass http://bus_gateway; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90s; + } + # ITI-67: Find Document References location /fhir/DocumentReference { proxy_pass http://bus_gateway; diff --git a/tests/fixtures/iti65/bundle-document-it.json b/tests/fixtures/iti65/bundle-document-it.json new file mode 100644 index 0000000..edee001 --- /dev/null +++ b/tests/fixtures/iti65/bundle-document-it.json @@ -0,0 +1,121 @@ +{ + "resourceType": "Bundle", + "type": "document", + "timestamp": "2026-04-23T07:50:00-03:00", + "entry": [ + { + "fullUrl": "urn:uuid:5ca8da35-efb1-498a-93bc-ed34524a360f", + "resource": { + "resourceType": "Patient", + "identifier": [ + { + "system": "urn:oid:2.16.858.1.858.1.1.1", + "value": "123456789" + } + ], + "active": true, + "name": [ + { + "use": "official", + "family": "Pérez", + "given": [ + "Juan" + ] + } + ] + } + }, + { + "fullUrl": "urn:uuid:4d58cb4f-1f8b-4f94-9877-bb5a0de47955", + "resource": { + "resourceType": "Composition", + "status": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11488-4", + "display": "Consultation note" + } + ] + }, + "subject": { + "reference": "urn:uuid:5ca8da35-efb1-498a-93bc-ed34524a360f" + }, + "date": "2026-04-23T07:50:00-03:00", + "author": [ + { + "display": "Dra. Especialista - Nodo Panamá" + } + ], + "title": "Informe de Contra-referencia Dermatológica", + "section": [ + { + "title": "Motivo de Interconsulta", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "42349-1", + "display": "Reason for referral" + } + ] + }, + "text": { + "status": "generated", + "div": "

Se solicita segunda opinión para evaluación de lesión pigmentada en región escapular, con el fin de descartar malignidad tras hallazgos clínicos iniciales en Uruguay.

" + } + }, + { + "title": "Revisión de Evidencia", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "30954-2", + "display": "Relevant diagnostic tests" + } + ] + }, + "text": { + "status": "generated", + "div": "

Se re-evaluaron los resultados del IPS (Bundle/2313), específicamente el DiagnosticReport/biopsia-001 y las imágenes dermatoscópicas adjuntas.

" + } + }, + { + "title": "Juicio Clínico", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "51848-0", + "display": "Assessment note" + } + ] + }, + "text": { + "status": "generated", + "div": "

Tras el análisis de la evidencia, se concluye que la morfología de la lesión es compatible con un Nevus Displásico. No se identifican criterios histológicos de melanoma.

" + } + }, + { + "title": "Recomendaciones", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18776-5", + "display": "Plan of care" + } + ] + }, + "text": { + "status": "generated", + "div": "
  • Control dermatoscópico cada 6 meses.
  • Uso de fotoprotección (FPS 50+).
  • No se requiere intervención quirúrgica inmediata.
" + } + } + ] + } + } + ] +} diff --git a/tests/fixtures/iti65/bundle-document-meow.json b/tests/fixtures/iti65/bundle-document-meow.json new file mode 100644 index 0000000..920f27d --- /dev/null +++ b/tests/fixtures/iti65/bundle-document-meow.json @@ -0,0 +1,177 @@ +{ + "resourceType": "Bundle", + "id": "medication-overview-example", + "meta": { + "profile": [ + "http://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverview" + ] + }, + "identifier": { + "system": "urn:ietf:rfc:3986", + "value": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a71" + }, + "type": "document", + "timestamp": "2025-06-17T18:36:18+00:00", + "entry": [ + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a72", + "resource": { + "resourceType": "Composition", + "id": "composition-example", + "meta": { + "profile": [ + "http://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverviewComposition" + ] + }, + "status": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "56445-0", + "display": "Medication summary" + } + ] + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "date": "2025-06-17T18:36:18+00:00", + "author": [ + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + } + ], + "title": "Medication Overview", + "section": [ + { + "title": "Medicamentos", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "55112-7", + "display": "Document summary" + } + ] + }, + "text": { + "status": "generated", + "div": "

Resumen de medicamentos

" + }, + "entry": [ + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a74" + }, + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a75" + } + ] + } + ] + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73", + "resource": { + "resourceType": "Patient", + "id": "patient-example", + "identifier": [ + { + "system": "http://hospital.example.org", + "value": "12345" + } + ], + "name": [ + { + "family": "Doe", + "given": [ + "John" + ] + } + ], + "gender": "male", + "birthDate": "1970-01-01" + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a74", + "resource": { + "resourceType": "MedicationStatement", + "id": "medication-statement-1", + "status": "active", + "medicationCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1222004", + "display": "Metronidazole-containing product" + } + ], + "text": "Metronidazole-containing product" + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "effectiveDateTime": "2025-01-01", + "effectivePeriod": { + "start": "2025-01-01", + "end": "2025-12-31" + }, + "dateAsserted": "2025-06-17T18:36:18+00:00", + "dosage": [ + { + "text": "500 mg daily", + "route": { + "text": "Oral" + } + } + ], + "reasonCode": [ + { + "text": "Infection" + } + ] + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a75", + "resource": { + "resourceType": "MedicationStatement", + "id": "medication-statement-2", + "status": "active", + "medicationCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "796001", + "display": "Digoxin-containing product" + } + ], + "text": "Digoxin-containing product" + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "effectiveDateTime": "2025-01-01", + "effectivePeriod": { + "start": "2025-01-01" + }, + "dateAsserted": "2025-06-17T18:36:18+00:00", + "dosage": [ + { + "text": "0.125 mg daily", + "route": { + "text": "Oral" + } + } + ], + "reasonCode": [ + { + "text": "Heart failure" + } + ] + } + } + ] +} diff --git a/tests/fixtures/iti65/bundle-transaction-it.json b/tests/fixtures/iti65/bundle-transaction-it.json new file mode 100644 index 0000000..0eda098 --- /dev/null +++ b/tests/fixtures/iti65/bundle-transaction-it.json @@ -0,0 +1,188 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ + { + "fullUrl": "urn:uuid:5ca8da35-efb1-498a-93bc-ed34524a360f", + "resource": { + "resourceType": "Patient", + "identifier": [ + { + "system": "urn:oid:2.16.858.1.858.1.1.1", + "value": "123456789" + } + ], + "active": true, + "name": [ + { + "use": "official", + "family": "Pérez", + "given": [ + "Juan" + ] + } + ] + }, + "request": { + "method": "POST", + "url": "Patient" + } + }, + { + "fullUrl": "urn:uuid:15f62e6b-f4d9-43d8-91f5-ee963a34339c", + "resource": { + "resourceType": "DocumentReference", + "status": "current", + "docStatus": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "57133-1", + "display": "Referral note" + } + ], + "text": "Informe de Contra-referencia Dermatológica" + }, + "subject": { + "reference": "urn:uuid:5ca8da35-efb1-498a-93bc-ed34524a360f" + }, + "date": "2026-04-23T07:50:00-03:00", + "author": [ + { + "display": "Dra. Especialista - Nodo Panamá" + } + ], + "description": "Respuesta a interconsulta - Caso Dermatología", + "content": [ + { + "attachment": { + "contentType": "application/fhir+json", + "url": "urn:uuid:03e4a890-b152-481a-9ca5-685e03550a08" + } + } + ], + "context": { + "related": [ + { + "identifier": { + "system": "https://salud.gub.uy/interconsultas", + "value": "UY-PA-2026-998877" + } + } + ] + } + }, + "request": { + "method": "POST", + "url": "DocumentReference" + } + }, + { + "fullUrl": "urn:uuid:03e4a890-b152-481a-9ca5-685e03550a08", + "resource": { + "resourceType": "Bundle", + "type": "document", + "timestamp": "2026-04-23T07:50:00-03:00", + "entry": [ + { + "fullUrl": "urn:uuid:4d58cb4f-1f8b-4f94-9877-bb5a0de47955", + "resource": { + "resourceType": "Composition", + "status": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11488-4", + "display": "Consultation note" + } + ] + }, + "subject": { + "reference": "urn:uuid:5ca8da35-efb1-498a-93bc-ed34524a360f" + }, + "date": "2026-04-23T07:50:00-03:00", + "author": [ + { + "display": "Dra. Especialista - Nodo Panamá" + } + ], + "title": "Informe de Contra-referencia Dermatológica", + "section": [ + { + "title": "Motivo de Interconsulta", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "42349-1", + "display": "Reason for referral" + } + ] + }, + "text": { + "status": "generated", + "div": "

Se solicita segunda opinión para evaluación de lesión pigmentada en región escapular, con el fin de descartar malignidad tras hallazgos clínicos iniciales en Uruguay.

" + } + }, + { + "title": "Revisión de Evidencia", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "30954-2", + "display": "Relevant diagnostic tests" + } + ] + }, + "text": { + "status": "generated", + "div": "

Se re-evaluaron los resultados del IPS (Bundle/2313), específicamente el DiagnosticReport/biopsia-001 y las imágenes dermatoscópicas adjuntas.

" + } + }, + { + "title": "Juicio Clínico", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "51848-0", + "display": "Assessment note" + } + ] + }, + "text": { + "status": "generated", + "div": "

Tras el análisis de la evidencia, se concluye que la morfología de la lesión es compatible con un Nevus Displásico. No se identifican criterios histológicos de melanoma.

" + } + }, + { + "title": "Recomendaciones", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18776-5", + "display": "Plan of care" + } + ] + }, + "text": { + "status": "generated", + "div": "
  • Control dermatoscópico cada 6 meses.
  • Uso de fotoprotección (FPS 50+).
  • No se requiere intervención quirúrgica inmediata.
" + } + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Bundle" + } + } + ] +} diff --git a/tests/fixtures/iti65/bundle-transaction-meow.json b/tests/fixtures/iti65/bundle-transaction-meow.json new file mode 100644 index 0000000..25f69d1 --- /dev/null +++ b/tests/fixtures/iti65/bundle-transaction-meow.json @@ -0,0 +1,258 @@ +{ + "resourceType": "Bundle", + "id": "iti65-transaction-medication", + "type": "transaction", + "entry": [ + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73", + "resource": { + "resourceType": "Patient", + "id": "patient-example", + "identifier": [ + { + "system": "http://hospital.example.org", + "value": "12345" + } + ], + "name": [ + { + "family": "Doe", + "given": [ + "John" + ] + } + ], + "gender": "male", + "birthDate": "1970-01-01" + }, + "request": { + "method": "POST", + "url": "Patient" + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a80", + "resource": { + "resourceType": "DocumentReference", + "status": "current", + "docStatus": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "56445-0", + "display": "Medication summary" + } + ], + "text": "Medication Overview" + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "date": "2025-06-17T18:36:18+00:00", + "author": [ + { + "display": "Dra. Especialista" + } + ], + "description": "Medication Overview - Patient Medication Summary", + "content": [ + { + "attachment": { + "contentType": "application/fhir+json", + "url": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a71" + } + } + ] + }, + "request": { + "method": "POST", + "url": "DocumentReference" + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a71", + "resource": { + "resourceType": "Bundle", + "id": "medication-overview-example", + "meta": { + "profile": [ + "http://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverview" + ] + }, + "identifier": { + "system": "urn:ietf:rfc:3986", + "value": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a71" + }, + "type": "document", + "timestamp": "2025-06-17T18:36:18+00:00", + "entry": [ + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a72", + "resource": { + "resourceType": "Composition", + "id": "composition-example", + "meta": { + "profile": [ + "http://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverviewComposition" + ] + }, + "status": "final", + "type": { + "coding": [ + { + "system": "http://loinc.org", + "code": "56445-0", + "display": "Medication summary" + } + ] + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "date": "2025-06-17T18:36:18+00:00", + "author": [ + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + } + ], + "title": "Medication Overview", + "section": [ + { + "title": "Medicamentos", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "55112-7", + "display": "Document summary" + } + ] + }, + "text": { + "status": "generated", + "div": "

Resumen de medicamentos

" + }, + "entry": [ + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a74" + }, + { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a75" + } + ] + } + ] + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73", + "resource": { + "resourceType": "Patient", + "id": "patient-example", + "identifier": [ + { + "system": "http://hospital.example.org", + "value": "12345" + } + ], + "name": [ + { + "family": "Doe", + "given": [ + "John" + ] + } + ], + "gender": "male", + "birthDate": "1970-01-01" + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a74", + "resource": { + "resourceType": "MedicationStatement", + "id": "medication-statement-1", + "status": "active", + "medicationCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1222004", + "display": "Metronidazole-containing product" + } + ], + "text": "Metronidazole-containing product" + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "effectiveDateTime": "2025-01-01", + "effectivePeriod": { + "start": "2025-01-01", + "end": "2025-12-31" + }, + "dateAsserted": "2025-06-17T18:36:18+00:00", + "dosage": [ + { + "text": "500 mg daily", + "route": { + "text": "Oral" + } + } + ], + "reasonCode": [ + { + "text": "Infection" + } + ] + } + }, + { + "fullUrl": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a75", + "resource": { + "resourceType": "MedicationStatement", + "id": "medication-statement-2", + "status": "active", + "medicationCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "796001", + "display": "Digoxin-containing product" + } + ], + "text": "Digoxin-containing product" + }, + "subject": { + "reference": "urn:uuid:68c15694-52f1-4171-bc01-e63d666d2a73" + }, + "effectiveDateTime": "2025-01-01", + "effectivePeriod": { + "start": "2025-01-01" + }, + "dateAsserted": "2025-06-17T18:36:18+00:00", + "dosage": [ + { + "text": "0.125 mg daily", + "route": { + "text": "Oral" + } + } + ], + "reasonCode": [ + { + "text": "Heart failure" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Bundle" + } + } + ] +}