From bb27300a60d5d56114cb12e7293fb81e53479fce Mon Sep 17 00:00:00 2001 From: mherman22 Date: Tue, 6 Aug 2024 14:51:21 +0300 Subject: [PATCH] Query the CR to retrieve patient data into OpenELIS --- .../provider/PatientSearchRestController.java | 138 +++++++++++++++++- .../dataexchange/fhir/FhirConfig.java | 37 +++-- .../service/FhirTransformServiceImpl.java | 19 +-- .../resources/languages/message_en.properties | 1 + 4 files changed, 161 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java b/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java index 22b1ec4b9c..7592378665 100644 --- a/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java +++ b/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java @@ -1,11 +1,21 @@ package org.openelisglobal.common.rest.provider; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInputAndPartialOutput; +import ca.uhn.fhir.rest.gclient.StringClientParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenParam; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import org.apache.commons.validator.GenericValidator; +import org.hl7.fhir.r4.model.*; import org.openelisglobal.common.provider.query.PatientSearchResults; import org.openelisglobal.common.provider.query.PatientSearchResultsForm; import org.openelisglobal.common.provider.query.workerObjects.PatientSearchLocalAndExternalWorker; @@ -15,12 +25,16 @@ import org.openelisglobal.common.rest.util.PatientSearchResultsPaging; import org.openelisglobal.common.util.ConfigurationProperties; import org.openelisglobal.common.util.ConfigurationProperties.Property; +import org.openelisglobal.common.util.DateUtil; +import org.openelisglobal.dataexchange.fhir.FhirConfig; +import org.openelisglobal.dataexchange.fhir.FhirUtil; import org.openelisglobal.internationalization.MessageUtil; import org.openelisglobal.observationhistory.service.ObservationHistoryService; import org.openelisglobal.observationhistory.service.ObservationHistoryServiceImpl.ObservationType; import org.openelisglobal.patient.service.PatientService; import org.openelisglobal.patient.valueholder.Patient; import org.openelisglobal.person.service.PersonService; +import org.openelisglobal.person.valueholder.Person; import org.openelisglobal.sample.service.SampleService; import org.openelisglobal.sample.valueholder.Sample; import org.openelisglobal.samplehuman.service.SampleHumanService; @@ -37,6 +51,10 @@ @RequestMapping(value = "/rest/") public class PatientSearchRestController extends BaseRestController { + @Autowired + private FhirConfig fhirConfig; + @Autowired + private FhirUtil fhirUtil; @Autowired SampleService sampleService; @Autowired @@ -64,10 +82,10 @@ public PatientSearchResultsForm getPatientResults(HttpServletRequest request, PatientSearchResultsForm form = new PatientSearchResultsForm(); String requestedPage = request.getParameter("page"); + Patient patient = getPatientForLabNumber(labNumber); if (GenericValidator.isBlankOrNull(requestedPage)) { List results = new ArrayList<>(); if (!GenericValidator.isBlankOrNull(labNumber)) { - Patient patient = getPatientForLabNumber(labNumber); if (patient == null || GenericValidator.isBlankOrNull(patient.getId())) { form.setPatientSearchResults(results); return form; @@ -85,6 +103,47 @@ public PatientSearchResultsForm getPatientResults(HttpServletRequest request, form.setPatientSearchResults(results); return form; } + + if (request.getParameter("crResult").contains("true")) { + if (isClientRegistryConfigInvalid()) { + return null; + } + + IGenericClient clientRegistry = fhirUtil.getFhirClient(fhirConfig.getClientRegistryServerUrl(), + fhirConfig.getClientRegistryUserName(), fhirConfig.getClientRegistryPassword()); + + List targetSystems = new ArrayList<>(); + IOperationUntypedWithInputAndPartialOutput identifiersRequest = clientRegistry + .operation().onType("Patient").named("$ihe-pix") + .withSearchParameter(Parameters.class, "sourceIdentifier", + new TokenParam("http://openelis-global.org/pat_uuid", + patient.getFhirUuidAsString())) + .andSearchParameter("targetSystem", new StringParam(String.join(",", targetSystems))); + + Parameters crMatchingParams = identifiersRequest.useHttpGet().execute(); + List crIdentifiers = crMatchingParams.getParameter().stream() + .filter(param -> Objects.equals(param.getName(), "targetId")) + .map(param -> param.getValue().toString()).collect(Collectors.toList()); + + if (crIdentifiers.isEmpty()) { + return null; + } + + Bundle patientBundle = clientRegistry.search().forResource(org.hl7.fhir.r4.model.Patient.class) + .where(new StringClientParam(org.hl7.fhir.r4.model.Patient.SP_RES_ID).matches() + .values(crIdentifiers)) + .returnBundle(Bundle.class).execute(); + + List externalPatients = parseCRPatientSearchResults(patientBundle); + + for (org.hl7.fhir.r4.model.Patient externalPatient : externalPatients) { + Patient openElisPatient = transformFhirPatientObjectToOpenElisPatientObject(patient, + externalPatient); + PatientSearchResults searchResult = getSearchResultsForPatient(openElisPatient, null); + searchResult.setDataSourceName(MessageUtil.getMessage("patient.cr.source")); + results.add(searchResult); + } + } } paging.setDatabaseResults(request, form, results); } else { @@ -94,6 +153,12 @@ public PatientSearchResultsForm getPatientResults(HttpServletRequest request, return form; } + private boolean isClientRegistryConfigInvalid() { + return GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryServerUrl()) + || GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryUserName()) + || GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryPassword()); + } + private Patient getPatientForLabNumber(String labNumber) { Sample sample = sampleService.getSampleByAccessionNumber(labNumber); @@ -138,4 +203,75 @@ private PatientSearchWorker getAppropriateWorker(HttpServletRequest request, boo externalID, patientID, guid, dateOfBirth, gender); } + private List parseCRPatientSearchResults(Bundle patientBundle) { + return patientBundle.getEntry().stream().filter(entry -> entry.hasType("Patient")) + .map(entry -> (org.hl7.fhir.r4.model.Patient) entry.getResource()).collect(Collectors.toList()); + } + + public Patient transformFhirPatientObjectToOpenElisPatientObject(Patient openELISPatient, + org.hl7.fhir.r4.model.Patient fhirPatient) { + for (org.hl7.fhir.r4.model.Identifier identifier : fhirPatient.getIdentifier()) { + String system = identifier.getSystem(); + String value = identifier.getValue(); + if ("http://openelis-global.org/pat_nationalId".equals(system)) { + openELISPatient.setNationalId(value); + } else if ("http://openelis-global.org/pat_guid".equals(system)) { + openELISPatient.setExternalId(value); + } else if ("http://openelis-global.org/pat_uuid".equals(system)) { + openELISPatient.setFhirUuid(UUID.fromString(value)); + } + } + + if (!fhirPatient.getName().isEmpty()) { + HumanName name = fhirPatient.getNameFirstRep(); + openELISPatient.setEpiFirstName(name.getGivenAsSingleString()); + openELISPatient.setEpiLastName(name.getFamily()); + } + + if (!fhirPatient.getTelecom().isEmpty()) { + ContactPoint telecom = fhirPatient.getTelecomFirstRep(); + if (ContactPoint.ContactPointSystem.PHONE.equals(telecom.getSystem())) { + Person person = openELISPatient.getPerson(); + if (person == null) { + person = new Person(); + openELISPatient.setPerson(person); + } + person.setPrimaryPhone(telecom.getValue()); + } + } + + switch (fhirPatient.getGender()) { + case MALE: + openELISPatient.setGender("M"); + break; + case FEMALE: + openELISPatient.setGender("F"); + break; + default: + openELISPatient.setGender(null); + break; + } + + if (fhirPatient.getBirthDate() != null) { + openELISPatient.setBirthDate(new Timestamp(fhirPatient.getBirthDate().getTime())); + openELISPatient.setBirthDateForDisplay( + DateUtil.convertTimestampToStringDate(new Timestamp(fhirPatient.getBirthDate().getTime()))); + } + + if (!fhirPatient.getAddress().isEmpty()) { + Address fhirAddress = fhirPatient.getAddressFirstRep(); + Person person = openELISPatient.getPerson(); + if (person == null) { + person = new Person(); + openELISPatient.setPerson(person); + } + person.setStreetAddress(fhirAddress.getLine().isEmpty() ? null : fhirAddress.getLine().get(0).toString()); + person.setCity(fhirAddress.getCity()); + person.setState(fhirAddress.getState()); + person.setCountry(fhirAddress.getCountry()); + } + + return openELISPatient; + } + } diff --git a/src/main/java/org/openelisglobal/dataexchange/fhir/FhirConfig.java b/src/main/java/org/openelisglobal/dataexchange/fhir/FhirConfig.java index d556ab1ac6..eb4c3b5d55 100644 --- a/src/main/java/org/openelisglobal/dataexchange/fhir/FhirConfig.java +++ b/src/main/java/org/openelisglobal/dataexchange/fhir/FhirConfig.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory; import ca.uhn.fhir.rest.client.api.IRestfulClientFactory; +import lombok.Getter; import org.apache.http.impl.client.CloseableHttpClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -14,28 +15,41 @@ @Configuration public class FhirConfig { + @Getter @Value("${org.openelisglobal.oe.fhir.system:http://openelis-global.org}") private String oeFhirSystem; + @Getter @Value("${org.openelisglobal.fhirstore.uri}") private String localFhirStorePath; + @Getter @Value("${org.openelisglobal.remote.source.uri}") private String[] remoteStorePaths; + @Getter @Value("${org.openelisglobal.fhirstore.username:}") private String username; + @Getter @Value("${org.openelisglobal.fhirstore.password:}") private String password; + @Getter + @Value("${org.openelisglobal.crserver.uri}") + private String clientRegistryServerUrl; + + @Getter + @Value("${org.openelisglobal.crserver.username}") + private String clientRegistryUserName; + + @Getter + @Value("${org.openelisglobal.crserver.password}") + private String clientRegistryPassword; + @Autowired CloseableHttpClient httpClient; - public String getLocalFhirStorePath() { - return localFhirStorePath; - } - @Bean public FhirContext fhirContext() { FhirContext fhirContext = new FhirContext(FhirVersionEnum.R4); @@ -50,19 +64,4 @@ public void configureFhirHttpClient(FhirContext fhirContext) { fhirContext.setRestfulClientFactory(clientFactory); } - public String getOeFhirSystem() { - return oeFhirSystem; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String[] getRemoteStorePaths() { - return remoteStorePaths; - } } diff --git a/src/main/java/org/openelisglobal/dataexchange/fhir/service/FhirTransformServiceImpl.java b/src/main/java/org/openelisglobal/dataexchange/fhir/service/FhirTransformServiceImpl.java index 0d19efcc22..df80a39bd8 100644 --- a/src/main/java/org/openelisglobal/dataexchange/fhir/service/FhirTransformServiceImpl.java +++ b/src/main/java/org/openelisglobal/dataexchange/fhir/service/FhirTransformServiceImpl.java @@ -115,7 +115,6 @@ import org.openelisglobal.typeofsample.valueholder.TypeOfSample; import org.openelisglobal.typeoftestresult.service.TypeOfTestResultServiceImpl; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; @@ -124,13 +123,6 @@ @Service public class FhirTransformServiceImpl implements FhirTransformService { - @Value("${org.openelisglobal.crserver.uri:}") - private String clientRegistryServerUrl; - @Value("${org.openelisglobal.crserver.username:}") - private String clientRegistryUserName; - @Value("${org.openelisglobal.crserver.password:}") - private String clientRegistryPassword; - @Autowired private FhirConfig fhirConfig; @Autowired @@ -173,7 +165,6 @@ public class FhirTransformServiceImpl implements FhirTransformService { private AddressPartService addressPartService; @Autowired private OrganizationService organizationService; - @Autowired private FhirUtil fhirUtil; @@ -396,11 +387,11 @@ public void transformPersistPatient(PatientManagementInfo patientInfo, boolean i org.hl7.fhir.r4.model.Patient patient = transformToFhirPatient(patientInfo.getPatientPK()); this.addToOperations(fhirOperations, tempIdGenerator, patient); - if (!GenericValidator.isBlankOrNull(clientRegistryServerUrl) - && !GenericValidator.isBlankOrNull(clientRegistryUserName) - && !GenericValidator.isBlankOrNull(clientRegistryPassword)) { - IGenericClient clientRegistry = fhirUtil.getFhirClient(clientRegistryServerUrl, clientRegistryUserName, - clientRegistryPassword); + if (!GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryServerUrl()) + && !GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryUserName()) + && !GenericValidator.isBlankOrNull(fhirConfig.getClientRegistryPassword())) { + IGenericClient clientRegistry = fhirUtil.getFhirClient(fhirConfig.getClientRegistryServerUrl(), + fhirConfig.getClientRegistryUserName(), fhirConfig.getClientRegistryPassword()); try { if (isCreate) { clientRegistry.create().resource(patient).execute(); diff --git a/src/main/resources/languages/message_en.properties b/src/main/resources/languages/message_en.properties index e295993aab..88b329f39e 100644 --- a/src/main/resources/languages/message_en.properties +++ b/src/main/resources/languages/message_en.properties @@ -4149,6 +4149,7 @@ patient.information = Patient Information patient.insuranceNumber = Insurance number patient.labno.search = Lab No patient.local.source = OpenElis +patient.cr.source = Open Client Registry patient.management.title = Add/Modify Patient patient.maritialStatus = Marital Status patient.medicaidId = Medicaid