diff --git a/src/routes/handlers/fetchPatientSummaries.ts b/src/routes/handlers/fetchPatientSummaries.ts index 0adb422..0c0aee6 100644 --- a/src/routes/handlers/fetchPatientSummaries.ts +++ b/src/routes/handlers/fetchPatientSummaries.ts @@ -19,6 +19,9 @@ export const fetchAllPatientSummariesByRefs = async ( patientRefs: string[], queryParams?: object ): Promise => { + // remove duplicates + patientRefs = Array.from(new Set(patientRefs.map(ref => ref?.split('/').pop() || ''))); + const patientExternalRefs = patientRefs.map((ref) => { const params = Object.entries(queryParams ?? {}); let combinedParams = null; @@ -29,7 +32,7 @@ export const fetchAllPatientSummariesByRefs = async ( .join('&'); } - const path = `/fhir/${ref}/$summary${combinedParams ? `?${combinedParams}` : ''}`; + const path = `/fhir/Patient/${ref}/$summary${combinedParams ? `?${combinedParams}` : ''}`; return getData(protocol, host, port, path, { 'Content-Type': 'application/fhir+json', diff --git a/src/routes/index.ts b/src/routes/index.ts index e08c5c0..d68e0e5 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -8,7 +8,7 @@ import { matchAsyncHandler } from './handlers/matchPatientAsync'; import { matchSyncHandler } from './handlers/matchPatientSync'; import { mpiMdmQueryLinksMiddleware } from '../middlewares/mpi-mdm-query-links'; import { validationMiddleware } from '../middlewares/validation'; -import { buildOpenhimResponseObject, getData } from '../utils/utils'; +import { buildOpenhimResponseObject, getData, patientProjector } from '../utils/utils'; import { fetchEverythingByRef } from './handlers/fetchPatientResources'; import { mpiMdmSummaryMiddleware } from '../middlewares/mpi-mdm-summary'; import { fetchPatientSummaryByRef } from './handlers/fetchPatientSummaries'; @@ -125,6 +125,9 @@ routes.get('/fhir/Patient/:patientId', async (req, res) => { const patient = mpiResponse.body as Patient; patient.id = requestedId; + + if (req.query.projection === 'partial') mpiResponse.body = patientProjector(patient); + logger.debug( `Mapped upstream ID ${upstreamId} to requested ID ${requestedId} in response body` ); diff --git a/src/utils/kafkaFhir.ts b/src/utils/kafkaFhir.ts index db69cca..3181be1 100644 --- a/src/utils/kafkaFhir.ts +++ b/src/utils/kafkaFhir.ts @@ -186,16 +186,19 @@ export const processBundle = async (bundle: Bundle): Promise { + let guttedPatient: ResponseObject; + let id: string; + if (patientEntry.fullUrl) { // Check if patient already exists and perform update - const guttedPatient = await sendRequest({ + guttedPatient = await sendRequest({ ...fhirDatastoreRequestDetails, method: 'GET', path: `/fhir/Patient/${patientEntry.fullUrl.split('/').pop()}`, }); if (isHttpStatusOk(guttedPatient.status)) { - const id: string = Object.assign(guttedPatient.body).link[0].other.reference.split('/').pop(); + id = Object.assign(guttedPatient.body).link[0].other.reference.split('/').pop(); let mpiPatient = await sendRequest({ ...clientRegistryRequestDetails, @@ -232,7 +235,12 @@ export const processBundle = async (bundle: Bundle): Promise { + if (isHttpStatusOk(guttedPatient.status)) { + return {status: response.status, body: {...response.body, id}} + } + return response; + }); }); const clientRegistryResponses = await Promise.all(promises); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index efa81e8..b09bbcc 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -233,6 +233,10 @@ export const transformPatientResourceForMPI = (patient: Patient): MpiTransformRe export const restorePatientResource = (patientData: PatientData) => { patientData.restoredPatient = patientData.mpiResponsePatient; + // restore the source uuid of the patient + const id = Object.assign({id: ''}, patientData.mpiTransformResult?.patient).id; + patientData.restoredPatient = Object.assign({}, patientData.restoredPatient, {id}); + if (patientData.mpiTransformResult?.extension?.length) { patientData.restoredPatient = Object.assign({}, patientData.restoredPatient, { extension: patientData.mpiTransformResult.extension, @@ -312,3 +316,14 @@ export const mergeBundles = async ( return bundle; }; + +export const patientProjector = (patient: Patient) : Patient => { + return { + resourceType: patient.resourceType, + id: patient.id, + identifier: patient.identifier, + name: patient.name, + birthDate: patient.birthDate, + gender: patient.gender + } +}; diff --git a/tests/unit/matchPatientSync.ts b/tests/unit/matchPatientSync.ts index 316a16a..8ae482f 100644 --- a/tests/unit/matchPatientSync.ts +++ b/tests/unit/matchPatientSync.ts @@ -408,7 +408,7 @@ describe('Match Patient Synchronously', (): void => { }, }, restoredPatient: { - id: 'testPatient', + id: '12333', resourceType: 'Patient', }, }, diff --git a/tests/unit/utils.ts b/tests/unit/utils.ts index c8666e9..fc99832 100644 --- a/tests/unit/utils.ts +++ b/tests/unit/utils.ts @@ -12,6 +12,7 @@ import { createHandlerResponseObject, mergeBundles, transformPatientResourceForMPI, + patientProjector, } from '../../src/utils/utils'; import { MpiMediatorResponseObject, @@ -592,6 +593,113 @@ describe('Utils', (): void => { }); }); + describe('*patientProjector', (): void => { + it('should project patient', (): void => { + const patient: Patient = { + resourceType: 'Patient', + id: '642b83d3-a43c-41ef-a578-2b730f276bfb', + extension: [ + { + url: 'http://hl7.org/fhir/StructureDefinition/patient-religion', + valueCodeableConcept: { + coding: [ + { + system: 'http://terminology.hl7.org/ValueSet/v3-ReligiousAffiliation', + code: '1036', + display: 'Orthodox', + }, + ], + }, + }, + { + url: 'http://hl7.org/fhir/StructureDefinition/patient-relatedPerson', + valueReference: { + reference: 'RelatedPerson/f8b7dccb-f1ef-4365-9323-29303479d02bRelatedPerson481', + }, + }, + { + url: 'http://cdr.aacahb.gov.et/EducationalLevel', + valueCodeableConcept: { + coding: [ + { + system: 'http://terminology.hl7.org/CodeSystem/v3-EducationLevel', + code: 'ELEM', + display: 'Elementary School', + }, + ], + }, + }, + { + url: 'http://cdr.aacahb.gov.et/Occupation', + valueString: 'Foreman', + }, + ], + identifier: [ + { + system: 'http://cdr.aacahb.gov.et/SmartCareID', + value: '642b83d3-a43c-41ef-a578-2b730f276bfb', + }, + { + system: 'http://cdr.aacahb.gov.et/NationalID', + value: 'MRN-642b83d3-a43c-41ef-a578-2b730f476bf9', + }, + { + system: 'http://cdr.aacahb.gov.et/UAN', + value: 'UAN-642b83d3-a43c-41ef-a578-2b730f276bfb', + }, + ], + name: [ + { + use: 'official', + family: 'Rodrigues', + given: ['Liniee'], + }, + ], + telecom: [ + { + system: 'phone', + value: '+2519000000', + use: 'home', + }, + ], + gender: 'female', + birthDate: '1999-06-19', + address: [ + { + type: 'physical', + text: 'Urban', + state: 'Addis Ababa', + city: 'Cherkos sub city', + district: '10', + line: ['17', '927/5'], + }, + ], + maritalStatus: { + coding: [ + { + system: 'http://terminology.hl7.org/CodeSystem/v3-MaritalStatus', + code: 'M', + display: 'Married', + }, + ], + }, + managingOrganization: { + reference: 'Organization/009a6a861c1b45778c0cbedadefe52a4', + }, + }; + + const result: Patient = patientProjector(patient); + + expect(result).to.haveOwnProperty('birthDate'); + expect(result).to.haveOwnProperty('id'); + expect(result).to.haveOwnProperty('name'); + expect(result).to.haveOwnProperty('resourceType'); + expect(result).to.haveOwnProperty('gender'); + expect(result).to.haveOwnProperty('identifier'); + expect(result).to.not.haveOwnProperty('address') + }); + }); + describe('*mergeBundles', (): void => { it('should merge bundles', async (): Promise => { const clientRegistryPatientRef: string = 'http://client-registry:8080/fhir/Patient/1455';