126 lines
4.4 KiB
JavaScript

const axios = require('axios');
const createError = require('http-errors');
const config = require('../config');
const { getBusToken, createBusRequest } = require('../utils/busAuth');
const { findPatient } = require('../services/patient');
const { createDocumentReference, findDocumentReferenceById, findDocumentReferenceByUrl } = require('../services/documentReference');
const { logger } = require('../utils/logger');
const { v4: uuidv4 } = require('uuid');
const { getResourceByUrl } = require('../services/fhir');
const DOCUMENT_REFERENCE_RESOURCE_TYPE = "DocumentReference";
const IPS_DOCUMENT_RESOURCE_TYPE = 'Bundle';
const PATIENT_RESOURCE_TYPE = 'Patient';
const LIST_RESOURCE_TYPE = 'List';
const NATIONAL_ID_SYSTEM = 'https://federador.msal.gob.ar/patient-id';
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'
function extractResource(resources, resourceType) {
return resources.map(r => r.data).filter(r => r.resourceType === resourceType)[0];
}
function extractLocalIdentifier(patient) {
return patient.identifier.filter(i => {
return i.system !== NATIONAL_ID_SYSTEM && ((!!i.use && i.use === 'official') || (!i.use))
})[0];
}
function generateDocumentReferenceResource(subjectReference, bundleUrl) {
const documentRefernece = {
resourceType: 'DocumentReference',
status: 'current',
masterIdentifier: {
use: 'usual',
system: MASTER_ID_SYSTEM,
value: `urn:uuid:${uuidv4()}`
},
type: {
coding: [
{
system: 'http://loinc.org',
code: '60591-5',
display: 'Patient Summary Document',
},
],
},
date: new Date().toISOString(),
subject: {
reference: subjectReference
},
custodian: {
identifier: busCustodianIdentifier,
},
content: [
{
attachment: {
url: bundleUrl,
contentType: 'application/fhir+json'
},
},
],
};
return documentRefernece;
}
/**
* ITI-65: Provide Document Bundle (MHD)
*
* POST /fhir/Bundle
*
* Flow:
* 1. Store the IPS Bundle in HAPI FHIR.
* 2. Resolve the patient national identifier via Bus $match.
* 3. Register a DocumentReference in the Bus pointing to the stored Bundle.
*
* Required header:
* x-custodian-id — Efector identifier value in the Federador MSAL system.
*/
async function provideDocumentBundle(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(',')
);
// Paso 1: Ejecuto la transcción en el servidor hapi subyacente
const transactionResponse = await processTransaction(transaction);
const resources = [];
transactionResponse.entry.map(e => e.response);
transactionResponse.entry.map(e => e.response).foreEach(r => {
const resource = getResourceByUr(r.location);
resources.push(resource);
});
// Paso 2: Obtengo el paciente local (tal como se guardo en la trasnaccion)
const localPatient = extractResource(resources, PATIENT_RESOURCE_TYPE);
// Paso 3: Obtengo el documento IPS local (tal como se guardo en la transacción)
const localIPSDocument = extractResource(resources, IPS_DOCUMENT_RESOURCE_TYPE)
const localPatientIdentifier = extractLocalIdentifier(localPatient);
const patientSearchset = await findPatient(token, { identifier: `${localIdentifier.system}|${localIdentifier.value}` });
if (patientSearchset.total == 0) {
throw createError(404, 'Patient does not exists');
}
const nationalPatientId = patientSearchset.entry[0].fullUrl;
const bundleReference = `${config.baseURL}/fhir/Bundle/${localIPSDocument.id}`;
const createdDocumentReference = await createDocumentReference(token, createdDocumentReference);
return res.status(200).json(createdDocumentReference);
} catch (err) {
next(err);
}
}
module.exports = { provideDocumentBundle };