Skip to content

Commit

Permalink
feat(#114): add endpoints for openmrs and cht
Browse files Browse the repository at this point in the history
  • Loading branch information
witash committed Apr 7, 2024
1 parent 5e4451f commit 4e3de0f
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 3 deletions.
8 changes: 8 additions & 0 deletions mediator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import serviceRequestRoutes from './src/routes/service-request';
import encounterRoutes from './src/routes/encounter';
import organizationRoutes from './src/routes/organization';
import endpointRoutes from './src/routes/endpoint';
import chtRoutes from './src/routes/cht';
import openmrsRoutes from './src/routes/openmrs';
import { registerMediatorCallback } from './src/utils/openhim';
import os from 'os';

Expand All @@ -24,12 +26,18 @@ app.get('*', (_: Request, res: Response) => {
res.send({status: 'success', osuptime: osUptime, processuptime: processUptime});
});

// routes for valid fhir resources
app.use('/patient', patientRoutes);
app.use('/service-request', serviceRequestRoutes);
app.use('/encounter', encounterRoutes);
app.use('/organization', organizationRoutes);
app.use('/endpoint', endpointRoutes);

// routes for cht docs
app.use('/cht', chtRoutes);
// routes for openmrs
app.use('/openmrs', openmrsRoutes);

if (process.env.NODE_ENV !== 'test') {
app.listen(PORT, () => logger.info(`Server listening on port ${PORT}`));

Expand Down
55 changes: 55 additions & 0 deletions mediator/src/utils/cht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CHT } from '../../config';
import { generateBasicAuthUrl } from './url';
import https from 'https';
import path from 'path';
import { logger } from '../../logger';

export async function createChtRecord(patientId: string) {
const record = {
Expand All @@ -22,6 +23,60 @@ export async function createChtRecord(patientId: string) {
return await axios.post(chtApiUrl, record, options);
}

export async function createChtPatient(fhirPatient: fhir4.Patient) {
const options = {
httpsAgent: new https.Agent({
rejectUnauthorized: false,
}),
};

const name = fhirPatient.name?.[0]
const given = name?.given ? name?.given : ''
const tc = fhirPatient.telecom?.[0]
const record = {
_meta: {
form: "N"
},
age_in_years: 22,
patient_phone: tc?.value,
patient_name: `${given} ${name?.family}`,
gender: fhirPatient.gender,
location_id: "65985"
}

const chtApiUrl = generateChtRecordsApiUrl(CHT.url, CHT.username, CHT.password);

return await axios.post(chtApiUrl, record, options);
}

export async function chtRecordFromObservations(patient_id: string, observations: any) {
const options = {
httpsAgent: new https.Agent({
rejectUnauthorized: false,
}),
};

const record: any = {
_meta: {
form: "openmrs_anc"
},
patient_id: patient_id
}

for (const entry of observations.entry) {
const code:string = entry.resource.code.coding[0].code;
if (entry.resource.valueCodeableConcept) {
record[code] = entry.resource.valueCodeableConcept.text;
} else if (entry.resource.valueDateTime) {
record[code] = entry.resource.valueDateTime;
}
}

const chtApiUrl = generateChtRecordsApiUrl(CHT.url, CHT.username, CHT.password);

return await axios.post(chtApiUrl, record, options);
}

export const generateChtRecordsApiUrl = (chtUrl: string, username: string, password: string) => {
const endpoint = generateBasicAuthUrl(chtUrl, username, password);
return path.join(endpoint, '/api/v2/records');
Expand Down
131 changes: 128 additions & 3 deletions mediator/src/utils/openmrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,123 @@ const chtIdentifierType: fhir4.CodeableConcept = {
text: 'CHT ID'
}

const medicIdentifierType: fhir4.CodeableConcept = {
text: 'Medic ID'
}

const noteEncounterType: fhir4.CodeableConcept = {
text: "Visit Note",
coding: [{
system: "http://fhir.openmrs.org/code-system/encounter-type",
code: "d7151f82-c1f3-4152-a605-2f9ea7414a79",
display: "Visit Note"
}]
}

const chwEncounterType: fhir4.CodeableConcept = {
text: "Community Health Worker Visit",
coding: [{
system: "http://fhir.openmrs.org/code-system/visit-type",
code: "479a14c9-fd05-4399-8e3d-fed3f8c654c",
display: "Community Health Worker Visit",
}]
}

const homeEncounterType: fhir4.CodeableConcept = {
text: "Home Visit",
coding: [{
system: "http://fhir.openmrs.org/code-system/visit-type",
code: "d66e9fe0-7d51-4801-a550-5d462ad1c944",
display: "Home Visit",
}]
}

const homeHealthEncounterClass: fhir4.CodeableConcept = {
text: 'HH',
coding : [{
system: "http://terminology.hl7.org/CodeSystem/v3-ActCode",
code: "HH"
}]
}

export function buildOpenMRSVisit(patient_id: string, reported_date: number) : fhir4.Encounter {
const visit = buildOpenMRSEncounter(patient_id, reported_date, homeEncounterType);
return visit;
}

export function buildOpenMRSVisitNote(patient_id: string, reported_date: number, visit_id: string): fhir4.Encounter {
const visitNote = buildOpenMRSEncounter(patient_id, reported_date, noteEncounterType);
const visitRef: fhir4.Reference = {
reference: `Encounter/${visit_id}`,
type: "Encounter"
};
visitNote.partOf = visitRef;
return visitNote;
}

export function buildOpenMRSEncounter(patient_id: string, reported_date: number, visitType: fhir4.CodeableConcept): fhir4.Encounter {
const patientRef: fhir4.Reference = {
reference: `Patient/${patient_id}`,
type: "Patient"
};

const openMRSEncounter: fhir4.Encounter = {
resourceType: 'Encounter',
id: randomUUID(),
status: 'unknown',
class: homeHealthEncounterClass,
type: [visitType],
subject: patientRef,
period: {
start: new Date(reported_date).toISOString(),
end: new Date(reported_date + 1000*60*10).toISOString()
}
}

return openMRSEncounter
}


export function buildOpenMRSObservation(patient_id: string, encounter_id: string, entry: any): fhir4.Observation {
const patientRef: fhir4.Reference = {
reference: `Patient/${patient_id}`,
type: "Patient"
};

const encounterRef: fhir4.Reference = {
reference: `Encounter/${encounter_id}`,
type: "Encounter"
};

const observation: fhir4.Observation = {
resourceType: "Observation",
subject: patientRef,
encounter: encounterRef,
status: "final",
code: {
coding: [{
code: entry.code,
}],
},
effectiveDateTime: "2024-03-31T12:26:27+00:00",
issued: "2024-03-31T12:26:28.000+00:00",
};

if ('valueCode' in entry){
observation.valueCodeableConcept = {
coding: [{
code: entry['valueCode']
}]
};
} else if ('valueDateTime' in entry){
observation.valueDateTime = entry['valueDateTime'];
} else if ('valueString' in entry){
observation.valueString = entry['valueString'];
}

return observation;
}

export function buildOpenMRSPatient(chtPatient: Record<string, any>): fhir4.Patient {
const nameParts = chtPatient.name.split(" ");
const familyName = nameParts.pop() || "";
Expand All @@ -34,10 +151,18 @@ export function buildOpenMRSPatient(chtPatient: Record<string, any>): fhir4.Pati
use: 'usual'
};

const medicIdentifier: OpenMRSIdentifier = {
id: randomUUID(),
type: medicIdentifierType,
value: chtPatient.patient_id,
system: 'cht',
use: 'official'
};

const chtIdentifier: OpenMRSIdentifier = {
id: randomUUID(),
type: chtIdentifierType,
value: chtPatient.id,
value: chtPatient._id,
system: 'cht',
use: 'official'
};
Expand All @@ -46,8 +171,8 @@ export function buildOpenMRSPatient(chtPatient: Record<string, any>): fhir4.Pati
resourceType: 'Patient',
name: [name],
birthDate: chtPatient.birthDate,
id: chtPatient.id,
identifier: [phoneIdentifier, chtIdentifier],
id: chtPatient._id,
identifier: [phoneIdentifier, chtIdentifier, medicIdentifier],
gender: chtPatient.gender
};

Expand Down

0 comments on commit 4e3de0f

Please sign in to comment.