Skip to content

Commit

Permalink
BS-68 | Create new REST endpoint for Diagnosis Search (#175)
Browse files Browse the repository at this point in the history
* BS-68 | Siva Reddy | Create New Rest End Point for Diagnosis Search

* BS-68 | Siva Reddy | Adding Test Cases for New Rest End Point

* BS-68 | Siva Reddy | Updating Global Proerty Name

* BS-68 | Siva Reddy | Adding terminology services dependency

* BS-68 | Siva Reddy | Updated Rest End Point for Diagnosis Search

* BS-68 | Siva Reddy | Publishing SNOMED specific Bahmnicore OMOD

* BS-68 | Siva Reddy | Updated Dependencies from terminology services module

* Siva Reddy | BS-68 | Updating Rest End Point, TS module dependencies

* Siva Reddy | BS-68 | Update Package of FHIR TS module
  • Loading branch information
sivareddyp committed May 26, 2023
1 parent f5a20a3 commit bf3796b
Show file tree
Hide file tree
Showing 9 changed files with 339 additions and 11 deletions.
2 changes: 1 addition & 1 deletion bahmnicore-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<artifactId>bahmni</artifactId>
<version>1.1.0</version>
</parent>
<artifactId>bahmnicore-api</artifactId>
<artifactId>bahmnicore-ts-api</artifactId>
<packaging>jar</packaging>
<name>Bahmni EMR Core API</name>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package org.bahmni.module.bahmnicore.service;

import org.openmrs.Concept;
import org.openmrs.ConceptSource;
import org.openmrs.module.bahmniemrapi.diagnosis.contract.BahmniDiagnosisRequest;

import java.text.ParseException;
import java.util.Collection;
import java.util.List;

public interface BahmniDiagnosisService {
void delete(String diagnosisObservationUuid);
List<BahmniDiagnosisRequest> getBahmniDiagnosisByPatientAndVisit(String patientUuid,String visitUuid);
List<BahmniDiagnosisRequest> getBahmniDiagnosisByPatientAndDate(String patientUuid, String date) throws ParseException;

boolean isExternalTerminologyServerLookupNeeded();

Collection<Concept> getDiagnosisSets();

List<ConceptSource> getConceptSourcesForDiagnosisSearch();
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.bahmni.module.bahmnicore.service.impl;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.bahmni.module.bahmnicore.service.BahmniDiagnosisService;
import org.openmrs.Concept;
import org.openmrs.ConceptSource;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.Visit;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.ConceptService;
import org.openmrs.api.EncounterService;
import org.openmrs.api.ObsService;
Expand All @@ -21,6 +24,7 @@
import org.openmrs.module.emrapi.encounter.DiagnosisMapper;
import org.openmrs.module.emrapi.encounter.domain.EncounterTransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.text.ParseException;
Expand All @@ -34,6 +38,10 @@

@Component
public class BahmniDiagnosisServiceImpl implements BahmniDiagnosisService {

private static final String BAHMNI_EXTERNAL_TERMINOLOGY_SERVER_LOOKUP_NEEDED = "bahmni.lookupExternalTerminologyServer";
private static final boolean DEFAULT_EXTERNAL_TERMINOLOGY_SERVER_LOOKUP_NEEDED = false;

private EncounterService encounterService;
private ObsService obsService;
private VisitService visitService;
Expand All @@ -42,9 +50,10 @@ public class BahmniDiagnosisServiceImpl implements BahmniDiagnosisService {
private BahmniDiagnosisMetadata bahmniDiagnosisMetadata;
private ConceptService conceptService;
private EmrApiProperties emrApiProperties;
private AdministrationService administrationService;

@Autowired
public BahmniDiagnosisServiceImpl(EncounterService encounterService, ObsService obsService, VisitService visitService, PatientService patientService, DiagnosisMapper diagnosisMapper, BahmniDiagnosisMetadata bahmniDiagnosisMetadata, ConceptService conceptService, EmrApiProperties emrApiProperties) {
public BahmniDiagnosisServiceImpl(EncounterService encounterService, ObsService obsService, VisitService visitService, PatientService patientService, DiagnosisMapper diagnosisMapper, BahmniDiagnosisMetadata bahmniDiagnosisMetadata, ConceptService conceptService, EmrApiProperties emrApiProperties, @Qualifier("adminService") AdministrationService administrationService) {
this.encounterService = encounterService;
this.obsService = obsService;
this.visitService = visitService;
Expand All @@ -53,6 +62,7 @@ public BahmniDiagnosisServiceImpl(EncounterService encounterService, ObsService
this.bahmniDiagnosisMetadata = bahmniDiagnosisMetadata;
this.conceptService = conceptService;
this.emrApiProperties = emrApiProperties;
this.administrationService = administrationService;
}

@Override
Expand Down Expand Up @@ -201,4 +211,20 @@ private void voidObsAndItsChildren(Obs obs) {
voidObsAndItsChildren(childObs);
}
}

@Override
public boolean isExternalTerminologyServerLookupNeeded() {
String externalTSLookupNeeded = administrationService.getGlobalProperty(BAHMNI_EXTERNAL_TERMINOLOGY_SERVER_LOOKUP_NEEDED);
return StringUtils.isNotBlank(externalTSLookupNeeded) ? Boolean.valueOf(externalTSLookupNeeded) : DEFAULT_EXTERNAL_TERMINOLOGY_SERVER_LOOKUP_NEEDED;
}

@Override
public Collection<Concept> getDiagnosisSets() {
return emrApiProperties.getDiagnosisSets();
}

@Override
public List<ConceptSource> getConceptSourcesForDiagnosisSearch() {
return emrApiProperties.getConceptSourcesForDiagnosisSearch();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.openmrs.Concept;
Expand All @@ -18,6 +17,7 @@
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.Visit;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.ConceptService;
import org.openmrs.api.EncounterService;
import org.openmrs.api.ObsService;
Expand All @@ -29,9 +29,9 @@
import org.openmrs.module.emrapi.EmrApiProperties;
import org.openmrs.module.emrapi.diagnosis.Diagnosis;
import org.openmrs.module.emrapi.encounter.DiagnosisMapper;
import org.openmrs.module.emrapi.encounter.domain.EncounterTransaction;
import org.openmrs.util.LocaleUtility;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

Expand All @@ -44,17 +44,17 @@
import java.util.Set;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyList;
import static org.mockito.Mockito.anyListOf;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@PowerMockIgnore("javax.management.*")
@PrepareForTest(LocaleUtility.class)
@RunWith(PowerMockRunner.class)
public class BahmniDiagnosisServiceImplTest {
Expand All @@ -75,8 +75,11 @@ public class BahmniDiagnosisServiceImplTest {
@Mock
private EmrApiProperties emrApiProperties;

@Mock
private AdministrationService administrationService;

@InjectMocks
private BahmniDiagnosisServiceImpl bahmniDiagnosisService = new BahmniDiagnosisServiceImpl(encounterService, obsService, visitService, patientService, diagnosisMapper, bahmniDiagnosisMetadata, conceptService, emrApiProperties);
private BahmniDiagnosisServiceImpl bahmniDiagnosisService = new BahmniDiagnosisServiceImpl(encounterService, obsService, visitService, patientService, diagnosisMapper, bahmniDiagnosisMetadata, conceptService, emrApiProperties, administrationService);

private String initialDiagnosisObsUUID = "initialDiagnosisObsUUID";
private String modifiedDiagnosisObsUUID = "modifiedDiagnosisObsUUID";
Expand All @@ -92,6 +95,7 @@ public void setUp() throws Exception {

PowerMockito.mockStatic(LocaleUtility.class);
PowerMockito.when(LocaleUtility.getLocalesInOrder()).thenReturn(new HashSet<>(Arrays.asList(Locale.getDefault())));
when(administrationService.getGlobalProperty(eq("bahmni.lookupExternalTerminologyServer"))).thenReturn("false");
}

@Test
Expand Down Expand Up @@ -225,6 +229,25 @@ public void shouldReturnEmptyListIfNoVisitFound() throws Exception {
assertEquals(0, bahmniDiagnosisRequests.size());
}

@Test
public void shouldReturnFalseWhenNoExternalTerminologyServerLookupNeeded() {
boolean externalTerminologyServerLookupNeeded = bahmniDiagnosisService.isExternalTerminologyServerLookupNeeded();
assertFalse(externalTerminologyServerLookupNeeded);
}

@Test
public void shouldReturnTrueWhenExternalTerminologyServerLookupNeeded() {
when(administrationService.getGlobalProperty(eq("bahmni.lookupExternalTerminologyServer"))).thenReturn("TRUE");
boolean externalTerminologyServerLookupNeeded = bahmniDiagnosisService.isExternalTerminologyServerLookupNeeded();
assertTrue(externalTerminologyServerLookupNeeded);
}

@Test
public void shouldCallDiagosisSetofSetsInEmrApiWhenNoExternalTerminologyServerLookupNeeded() {
bahmniDiagnosisService.getDiagnosisSets();
verify(emrApiProperties, times(1)).getDiagnosisSets();
}

private Diagnosis getDiagnosis() {
Diagnosis diagnosis = new Diagnosis();
Obs diagnosisObs = new DiagnosisBuilder()
Expand Down
14 changes: 12 additions & 2 deletions bahmnicore-omod/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<artifactId>bahmni</artifactId>
<version>1.1.0</version>
</parent>
<artifactId>bahmnicore-omod</artifactId>
<artifactId>bahmnicore-ts-omod</artifactId>
<packaging>jar</packaging>
<name>Bahmni EMR Core OMOD</name>

Expand Down Expand Up @@ -61,7 +61,17 @@
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>bahmnicore-api</artifactId>
<artifactId>fhir-ts-services-api</artifactId>
<version>${terminologyServices.version}</version>
</dependency>
<dependency>
<groupId>org.openmrs.module</groupId>
<artifactId>fhir2-api</artifactId>
<version>${openmrs.fhir2.version}</version>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>bahmnicore-ts-api</artifactId>
<version>${project.parent.version}</version>
<exclusions>
<exclusion>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.bahmni.module.bahmnicore.web.v1_0.controller;

import org.apache.commons.lang3.LocaleUtils;
import org.bahmni.module.bahmnicore.service.BahmniDiagnosisService;
import org.bahmni.module.fhirterminologyservices.api.TerminologyLookupService;
import org.openmrs.Concept;
import org.openmrs.ConceptMap;
import org.openmrs.ConceptName;
import org.openmrs.ConceptReferenceTerm;
import org.openmrs.ConceptSearchResult;
import org.openmrs.ConceptSource;
import org.openmrs.api.context.Context;
import org.openmrs.module.emrapi.concept.EmrConceptService;
import org.openmrs.module.webservices.rest.SimpleObject;
import org.openmrs.module.webservices.rest.web.RestConstants;
import org.openmrs.module.webservices.rest.web.v1_0.controller.BaseRestController;
import org.openmrs.util.LocaleUtility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import static org.springframework.web.bind.annotation.ValueConstants.DEFAULT_NONE;

@Controller
@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/bahmni/terminologies")
public class BahmniConceptSearchController extends BaseRestController {

private BahmniDiagnosisService bahmniDiagnosisService;

private EmrConceptService emrService;

private TerminologyLookupService terminologyLookupService;

@Autowired
public BahmniConceptSearchController(BahmniDiagnosisService bahmniDiagnosisService, EmrConceptService emrService, TerminologyLookupService terminologyLookupService) {
this.bahmniDiagnosisService = bahmniDiagnosisService;
this.emrService = emrService;
this.terminologyLookupService = terminologyLookupService;
}

@RequestMapping(method = RequestMethod.GET, value = "concepts")
@ResponseBody
public Object search(@RequestParam("term") String query, @RequestParam Integer limit,
@RequestParam(required = false, defaultValue = DEFAULT_NONE) String locale) throws Exception {
boolean externalTerminologyServerLookupNeeded = bahmniDiagnosisService.isExternalTerminologyServerLookupNeeded();
if(externalTerminologyServerLookupNeeded) {
return terminologyLookupService.getResponseList(query, limit, locale);
} else {
return getDiagnosisConcepts(query, limit, locale);
}
}

private List<SimpleObject> getDiagnosisConcepts(String query, Integer limit, String locale) {
Collection<Concept> diagnosisSets = bahmniDiagnosisService.getDiagnosisSets();
List<ConceptSource> conceptSources = bahmniDiagnosisService.getConceptSourcesForDiagnosisSearch();
Locale searchLocale = getSearchLocale(locale);
List<ConceptSearchResult> conceptSearchResults =
emrService.conceptSearch(query, LocaleUtility.getDefaultLocale(), null, diagnosisSets, conceptSources, limit);
ConceptSource conceptSource = conceptSources.isEmpty() ? null: conceptSources.get(0);
return createListResponse(conceptSearchResults, conceptSource, searchLocale);
}

private List<SimpleObject> createListResponse(List<ConceptSearchResult> resultList,
ConceptSource conceptSource, Locale searchLocale) {
List<SimpleObject> allDiagnoses = new ArrayList<>();

for (ConceptSearchResult diagnosis : resultList) {
SimpleObject diagnosisObject = new SimpleObject();
ConceptName conceptName = diagnosis.getConcept().getName(searchLocale);
if (conceptName == null) {
conceptName = diagnosis.getConcept().getName();
}
diagnosisObject.add("conceptName", conceptName.getName());
diagnosisObject.add("conceptUuid", diagnosis.getConcept().getUuid());
if(diagnosis.getConceptName()!=null) {
diagnosisObject.add("matchedName", diagnosis.getConceptName().getName());
}
ConceptReferenceTerm term = getConceptReferenceTermByConceptSource(diagnosis.getConcept(), conceptSource);
if(term != null) {
diagnosisObject.add("code", term.getCode());
}
allDiagnoses.add(diagnosisObject);
}
return allDiagnoses;
}

private ConceptReferenceTerm getConceptReferenceTermByConceptSource(Concept concept, ConceptSource conceptSource) {
Collection<ConceptMap> conceptMappings = concept.getConceptMappings();
if(conceptMappings != null && conceptSource != null) {
for (ConceptMap cm : conceptMappings) {
ConceptReferenceTerm term = cm.getConceptReferenceTerm();
if (conceptSource.equals(term.getConceptSource())) {
return term;
}
}
}
return null;
}

private Locale getSearchLocale(String localeStr) {
if (localeStr == null) {
return Context.getLocale();
}
Locale locale;
try {
locale = LocaleUtils.toLocale(localeStr);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(localeErrorMessage("emrapi.conceptSearch.invalidLocale", localeStr));
}
if (allowedLocale(locale)) {
return locale;
} else {
throw new IllegalArgumentException(localeErrorMessage("emrapi.conceptSearch.unsupportedLocale", localeStr));
}
}

private boolean allowedLocale(Locale locale) {
Set<Locale> allowedLocales = new HashSet<>(Context.getAdministrationService().getAllowedLocales());
return allowedLocales.contains(locale);
}

private String localeErrorMessage(String msgKey, String localeStr) {
return Context.getMessageSourceService().getMessage(msgKey, new Object[] { localeStr }, Context.getLocale());
}

}
11 changes: 9 additions & 2 deletions bahmnicore-omod/src/main/resources/config.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//OpenMRS//DTD OpenMRS Config 1.0//EN" "http://resources.openmrs.org/doctype/config-1.2.dtd">
<!DOCTYPE module PUBLIC "-//OpenMRS//DTD OpenMRS Config 1.0//EN" "http://resources.openmrs.org/doctype/config-1.6.dtd">

<module configVersion="1.2">
<module configVersion="1.6">

<!-- Base Module Properties -->
<id>@MODULE_ID@</id>
Expand Down Expand Up @@ -34,6 +34,7 @@
<require_module>org.openmrs.module.auditlog</require_module>
<require_module>org.bahmni.module.bahmnicommons</require_module>
<require_module>org.bahmni.module.communication</require_module>
<require_module>org.bahmni.module.fhirterminologyservices</require_module>
</require_modules>
<!-- Extensions -->

Expand Down Expand Up @@ -167,6 +168,12 @@
<description>A list of UUIDs indicating extra Patient Identifier Types that should be displayed</description>
</globalProperty>

<globalProperty>
<property>bahmni.lookupExternalTerminologyServer</property>
<defaultValue>false</defaultValue>
<description>Property used to determine whether external terminology server being used or not</description>
</globalProperty>

<globalProperty>
<property>bahmni.enableEmailPrescriptionOption</property>
<defaultValue>false</defaultValue>
Expand Down
Loading

0 comments on commit bf3796b

Please sign in to comment.