diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java index 474d564a60..15a276bee0 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java @@ -15,6 +15,7 @@ import org.openmrs.Person; import org.openmrs.api.ConceptNameType; import org.openmrs.api.context.Context; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -24,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Locale; import static java.util.Objects.nonNull; @@ -77,7 +79,7 @@ public List getObsByPatientAndVisit(String patientUuid, List concep " where obs.person.uuid = :patientUuid " + " and cn.concept = obs.concept.conceptId " + " and cn.name in (:conceptNames) " + - " and cn.locale = :locale " + + " and cn.locale in (:locale) " + " and cn.conceptNameType = :conceptNameType " + " and cn.voided = false and obs.voided = false "); @@ -106,13 +108,18 @@ public List getObsByPatientAndVisit(String patientUuid, List concep query.append(" order by obs.obsDatetime desc "); } + List localeList = new ArrayList<>(); + localeList.add(Context.getLocale()); + if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + localeList.add(LocaleUtility.getDefaultLocale()); + } Query queryToGetObservations = sessionFactory.getCurrentSession().createQuery(query.toString()); queryToGetObservations.setMaxResults(limit); queryToGetObservations.setString("patientUuid", patientUuid); queryToGetObservations.setParameterList("conceptNames", conceptNames); queryToGetObservations.setParameter("conceptNameType", ConceptNameType.FULLY_SPECIFIED); - queryToGetObservations.setString("locale", Context.getLocale().getLanguage()); + queryToGetObservations.setParameterList("locale", localeList); if (null != obsIgnoreList && obsIgnoreList.size() > 0) { queryToGetObservations.setParameterList("obsIgnoreList", obsIgnoreList); } diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java index 9db4592d01..73042231b6 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java @@ -2,8 +2,11 @@ import org.apache.commons.collections.CollectionUtils; import org.openmrs.Concept; +import org.openmrs.ConceptName; import org.openmrs.api.ConceptService; +import org.openmrs.api.context.Context; import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; +import org.openmrs.util.LocaleUtility; import java.util.ArrayList; import java.util.Collection; @@ -18,6 +21,9 @@ public static List getConceptsForNames(List conceptNames, Conce List rootConcepts = new ArrayList<>(); for (String rootConceptName : conceptNames) { Concept concept = conceptService.getConceptByName(rootConceptName); + if (concept == null) { + concept = getConceptInDefaultLocale(conceptService, rootConceptName); + } if (concept != null) { rootConcepts.add(concept); } @@ -26,6 +32,20 @@ public static List getConceptsForNames(List conceptNames, Conce } return new ArrayList<>(); } + private static Concept getConceptInDefaultLocale(ConceptService conceptService, String rootConceptName) { + if (LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + return null; + } + List conceptsByName = conceptService.getConceptsByName(rootConceptName, LocaleUtility.getDefaultLocale(), false); + for (Concept concept : conceptsByName) { + for (ConceptName conceptname : concept.getNames()) { + if (conceptname.getName().equalsIgnoreCase(rootConceptName) && (conceptname.isPreferred() || conceptname.isFullySpecifiedName())) { + return concept; + } + } + } + return null; + } public static void setUuidsForObservations(Collection bahmniObservations) { for (BahmniObservation bahmniObservation : bahmniObservations) { diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java index 30ae7c0881..d401b7c432 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java @@ -3,8 +3,10 @@ import org.apache.commons.collections.CollectionUtils; import org.openmrs.Concept; import org.openmrs.ConceptName; +import org.openmrs.ConceptSearchResult; import org.openmrs.api.APIException; import org.openmrs.api.ConceptService; +import org.openmrs.api.context.Context; import org.openmrs.module.webservices.rest.web.RequestContext; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.resource.api.PageableResult; @@ -14,6 +16,7 @@ import org.openmrs.module.webservices.rest.web.resource.impl.EmptySearchResult; import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; import org.openmrs.module.webservices.rest.web.response.ResponseException; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -21,6 +24,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; @Component public class BahmniConceptSearchHandler implements SearchHandler { @@ -35,10 +40,22 @@ public SearchConfig getSearchConfig() { return new SearchConfig("byFullySpecifiedName", RestConstants.VERSION_1 + "/concept", Arrays.asList("1.8.* - 2.*"), searchQuery); } + /** + * Searches for concepts by the given parameters. (Currently only supports name and locale (optional)) + * @return a list of concepts matching the given parameters. + * @throws APIException + * Should return concepts in the specified locale if specified. + * Should return concepts in the default locale as well as logged in locale if locale is not specified. + */ + @Override public PageableResult search(RequestContext context) throws ResponseException { String conceptName = context.getParameter("name"); - List conceptsByName = conceptService.getConceptsByName(conceptName); + List localeList = getLocales(context); + + List conceptsSearchResult = conceptService.getConcepts(conceptName, localeList, false, null, null, null, null, null, 0, null); + List conceptsByName = conceptsSearchResult.stream().map(conceptSearchResult -> conceptSearchResult.getConcept()).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(conceptsByName)) { return new EmptySearchResult(); } else { @@ -59,4 +76,27 @@ public PageableResult search(RequestContext context) throws ResponseException { } } + /** + * Returns list of unique locales based on the context.getParameter("locale") parameter + * Should return List of results for locales: If locale is specified, then return results for that locale. + * If locale is not specified, then return results for logged in locale and default locale. + */ + + private List getLocales(RequestContext context) { + String locale = context.getParameter("locale"); + + List localeList = new ArrayList<>(); + + if (locale != null) { + localeList.add(LocaleUtility.fromSpecification(locale)); + } else { + localeList.add(Context.getLocale()); + if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + localeList.add(LocaleUtility.getDefaultLocale()); + } + } + + return localeList; + } + } diff --git a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java new file mode 100644 index 0000000000..5bdbd50bb0 --- /dev/null +++ b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java @@ -0,0 +1,106 @@ +package org.bahmni.module.bahmnicore.web.v1_0.search; + + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.openmrs.Concept; +import org.openmrs.ConceptName; +import org.openmrs.ConceptSearchResult; +import org.openmrs.api.ConceptNameType; +import org.openmrs.api.ConceptService; +import org.openmrs.api.context.UserContext; +import org.openmrs.module.webservices.rest.web.RequestContext; +import org.openmrs.module.webservices.rest.web.resource.api.SearchConfig; +import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; +import org.openmrs.util.LocaleUtility; +import org.springframework.beans.factory.annotation.Qualifier; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class BahmniConceptSearchHandlerTest { + + @Mock + @Qualifier("conceptService") + private ConceptService conceptService; + + @Mock + RequestContext requestContext; + + @Mock + UserContext userContext; + + @InjectMocks + private BahmniConceptSearchHandler bahmniConceptSearchHandler; + + + @Test + public void shouldSearchByQuestion() { + SearchConfig searchConfig = bahmniConceptSearchHandler.getSearchConfig(); + assertEquals(searchConfig.getId(), "byFullySpecifiedName"); + } + + @Test + public void shouldSupportVersions1_8To2() { + SearchConfig searchConfig = bahmniConceptSearchHandler.getSearchConfig(); + assertTrue(searchConfig.getSupportedOpenmrsVersions().contains("1.8.* - 2.*")); + } + + @Test + public void shouldSearchByGivenLocale_whenLocaleIsSpecified() { + List conceptSearchResults = new ArrayList<>(); + ConceptSearchResult result = new ConceptSearchResult(); + Concept concept = new Concept(); + concept.setId(123); + ConceptName conceptNameFullySpecified = new ConceptName(); + conceptNameFullySpecified.setConceptNameType(ConceptNameType.FULLY_SPECIFIED); + conceptNameFullySpecified.setName("Nutritional Values"); + concept.setNames(Collections.singleton(conceptNameFullySpecified)); + result.setConcept(concept); + conceptSearchResults.add(result); + + List localeList = new ArrayList<>(); + localeList.add(Locale.FRENCH); + + when(conceptService.getConcepts(anyString(), anyList(), anyBoolean(), isNull(), isNull(), isNull(), isNull(), isNull(), any(Integer.class), isNull())).thenReturn(conceptSearchResults); + when(requestContext.getLimit()).thenReturn(10); + when(requestContext.getParameter("locale")).thenReturn("fr"); + when(requestContext.getParameter("name")).thenReturn("Nutritional Values"); + + + NeedsPaging searchResults = (NeedsPaging) bahmniConceptSearchHandler.search(requestContext); + + verify(conceptService, times(1)).getConcepts("Nutritional Values", localeList, false, null, null, null, null, null, 0, null); + assertEquals(1, searchResults.getPageOfResults().size()); + assertEquals(1, localeList.size()); + assertEquals(new Integer(123) , searchResults.getPageOfResults().get(0).getId()); + } + + @Test + public void shouldSearchByLoggedInLocaleAndDefaultLocale_whenLocaleIsNotSpecified() { + when(requestContext.getParameter("name")).thenReturn("Nutritional Values"); + + bahmniConceptSearchHandler.search(requestContext); + List localeList = new ArrayList<>(); + localeList.add(LocaleUtility.getDefaultLocale()); + + verify(conceptService, times(1)).getConcepts("Nutritional Values", localeList, false, null, null, null, null, null, 0, null); + } +}