Skip to content

Commit

Permalink
BAH-3181 | Enable locale specific concept search and also return FSN …
Browse files Browse the repository at this point in the history
…in defaultLocale (#236)

Updated /bahmnicore/observations API to take in optional locale parameter, so that concepts are searched in the locale.
Observation.conceptFSN returns the FSN in implementation/default locale
  • Loading branch information
angshu authored Dec 7, 2023
1 parent 62dab0f commit 45a3bd4
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class BahmniObservation implements Comparable<BahmniObservation>{
private String interpretation;
private String status;
private String encounterTypeName;
private String conceptFSN;

@JsonIgnore
private Serializable complexData;
Expand Down Expand Up @@ -431,4 +432,12 @@ public String getEncounterTypeName() {
public void setEncounterTypeName(String encounterTypeName) {
this.encounterTypeName = encounterTypeName;
}

public void setConceptFSN(String conceptFSN) {
this.conceptFSN = conceptFSN;
}

public String getConceptFSN() {
return this.conceptFSN;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@

import org.apache.commons.collections.CollectionUtils;
import org.openmrs.Concept;
import org.openmrs.ConceptName;
import org.openmrs.EncounterProvider;
import org.openmrs.Obs;
import org.openmrs.api.ConceptNameType;
import org.openmrs.module.bahmniemrapi.drugorder.mapper.BahmniProviderMapper;
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation;
import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.parameters.AdditionalBahmniObservationFields;
import org.openmrs.module.emrapi.encounter.ObservationMapper;
import org.openmrs.module.emrapi.encounter.matcher.ObservationTypeMatcher;
import org.openmrs.module.emrapi.utils.HibernateLazyLoader;
import org.openmrs.util.LocaleUtility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

@Component(value = "omrsObsToBahmniObsMapper")
public class OMRSObsToBahmniObsMapper {
Expand All @@ -33,9 +38,10 @@ public OMRSObsToBahmniObsMapper(ETObsToBahmniObsMapper etObsToBahmniObsMapper, O

public Collection<BahmniObservation> map(List<Obs> obsList, Collection<Concept> rootConcepts) {
Collection<BahmniObservation> bahmniObservations = new ArrayList<>();
Locale implementationLocale = LocaleUtility.getDefaultLocale();
for (Obs obs : obsList) {
if(observationTypeMatcher.getObservationType(obs).equals(ObservationTypeMatcher.ObservationType.OBSERVATION)){
BahmniObservation bahmniObservation =map(obs);
BahmniObservation bahmniObservation = map(obs, implementationLocale);
if(CollectionUtils.isNotEmpty(rootConcepts )){
bahmniObservation.setConceptSortWeight(ConceptSortWeightUtil.getSortWeightFor(bahmniObservation.getConcept().getName(), rootConcepts));
}
Expand All @@ -45,7 +51,7 @@ public Collection<BahmniObservation> map(List<Obs> obsList, Collection<Concept>
return bahmniObservations;
}

public BahmniObservation map(Obs obs) {
public BahmniObservation map(Obs obs, Locale implementationLocale) {
if(obs == null)
return null;
String obsGroupUuid = obs.getObsGroup() == null? null : obs.getObsGroup().getUuid();
Expand All @@ -61,6 +67,28 @@ public BahmniObservation map(Obs obs) {
for (EncounterProvider encounterProvider : obs.getEncounter().getEncounterProviders()) {
additionalBahmniObservationFields.addProvider(bahmniProviderMapper.map(encounterProvider.getProvider()));
}
return etObsToBahmniObsMapper.map(observationMapper.map(obs), additionalBahmniObservationFields, Collections.singletonList(obs.getConcept()), true);
BahmniObservation bahmniObservation = etObsToBahmniObsMapper.map(observationMapper.map(obs), additionalBahmniObservationFields, Collections.singletonList(obs.getConcept()), true);
bahmniObservation.setConceptFSN(getConceptFSNInDefaultLocale(obs, implementationLocale));
return bahmniObservation;
}

private String getConceptFSNInDefaultLocale(Obs obs, Locale implementationLocale) {
if (obs.getConcept() == null) {
return null;
}
Concept concept = new HibernateLazyLoader().load(obs.getConcept());
if (implementationLocale == null) {
return concept.getName().getName();
}
ConceptName fsn = concept.getName(implementationLocale, ConceptNameType.FULLY_SPECIFIED, null);
if (fsn == null) {
fsn = concept.getNames().stream().filter(name -> !name.getVoided() && name.getLocale().equals(implementationLocale)
&& name.getConceptNameType().equals(ConceptNameType.FULLY_SPECIFIED)).findFirst().orElse(null);
}
if (fsn != null) {
return fsn.getName();
} else {
return concept.getName().getName();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public List<BahmniObservation> map(List<BahmniObservation> bahmniObservations, S
new org.openmrs.module.bahmniemrapi.obsrelation.contract.ObsRelationship();
targetObsRelation.setRelationshipType(obsRelationship.getObsRelationshipType().getName());
targetObsRelation.setUuid(obsRelationship.getUuid());
targetObsRelation.setTargetObs(OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs()));
targetObsRelation.setTargetObs(OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs(), null));
bahmniObservation.setTargetObsRelation(targetObsRelation);
// bahmniObservation.setProviders(providers);
}
Expand All @@ -47,8 +47,8 @@ public List<BahmniObservation> map(List<ObsRelationship> obsRelationships) {
List<BahmniObservation> bahmniObservations = new ArrayList<>();
for (ObsRelationship obsRelationship : obsRelationships) {

BahmniObservation sourceObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getSourceObs());
BahmniObservation targetObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs());
BahmniObservation sourceObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getSourceObs(), null);
BahmniObservation targetObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs(), null);
sourceObservation.setProviders(encounterProviderMapper.convert(obsRelationship.getSourceObs().getEncounter().getEncounterProviders()));

org.openmrs.module.bahmniemrapi.obsrelation.contract.ObsRelationship targetObsRelation =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void shouldMapObsRelationshipForBahmniObservations() {
BahmniObservation sourceObservation = getBahmniObservation(sourceObsUuid);
BahmniObservation targetObservation = getBahmniObservation(targetObsUuid);

when(OMRSObsToBahmniObsMapper.map(targetObs)).thenReturn(targetObservation);
when(OMRSObsToBahmniObsMapper.map(targetObs, null)).thenReturn(targetObservation);

ArrayList<BahmniObservation> bahmniObservations = new ArrayList<>();
bahmniObservations.add(sourceObservation);
Expand All @@ -81,7 +81,7 @@ public void shouldMapObsRelationshipForBahmniObservations() {
List<BahmniObservation> mappedBahmniObservations = obsRelationshipMapper.map(bahmniObservations, "encounter-uuid");

verify(obsrelationService).getRelationsWhereSourceObsInEncounter("encounter-uuid");
verify(OMRSObsToBahmniObsMapper, times(1)).map(targetObs);
verify(OMRSObsToBahmniObsMapper, times(1)).map(targetObs, null);
assertEquals(2, mappedBahmniObservations.size());
assertEquals(sourceObsUuid, mappedBahmniObservations.get(0).getUuid());
assertEquals(targetObsUuid, mappedBahmniObservations.get(0).getTargetObsRelation().getTargetObs().getUuid());
Expand Down Expand Up @@ -112,8 +112,8 @@ public void shouldMapMultipleObsRelationshipForBahmniObservations() {
BahmniObservation targetObservation1 = getBahmniObservation(targetObs1Uuid);
BahmniObservation targetObservation2 = getBahmniObservation(targetObs2Uuid);

when(OMRSObsToBahmniObsMapper.map(targetObs1)).thenReturn(targetObservation1);
when(OMRSObsToBahmniObsMapper.map(targetObs2)).thenReturn(targetObservation2);
when(OMRSObsToBahmniObsMapper.map(targetObs1, null)).thenReturn(targetObservation1);
when(OMRSObsToBahmniObsMapper.map(targetObs2, null)).thenReturn(targetObservation2);

ArrayList<BahmniObservation> bahmniObservations = new ArrayList<>();
bahmniObservations.add(sourceObservation1);
Expand All @@ -124,7 +124,7 @@ public void shouldMapMultipleObsRelationshipForBahmniObservations() {
List<BahmniObservation> mappedBahmniObservations = obsRelationshipMapper.map(bahmniObservations, "encounter-uuid");

verify(obsrelationService).getRelationsWhereSourceObsInEncounter("encounter-uuid");
verify(OMRSObsToBahmniObsMapper, times(2)).map(any(Obs.class));
verify(OMRSObsToBahmniObsMapper, times(2)).map(any(Obs.class), any());
assertEquals(4, mappedBahmniObservations.size());
assertEquals(sourceObs1Uuid, mappedBahmniObservations.get(0).getUuid());
assertEquals(targetObs1Uuid, mappedBahmniObservations.get(0).getTargetObsRelation().getTargetObs().getUuid());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.openmrs.api.context.Context;
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation;
import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.OMRSObsToBahmniObsMapper;
import org.openmrs.module.emrapi.encounter.OrderMapper;
import org.openmrs.module.emrapi.encounter.domain.EncounterTransaction;
import org.openmrs.module.emrapi.encounter.mapper.OrderMapper1_12;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -240,13 +239,13 @@ else if (o1.getDateActivated().after(o2.getDateActivated()))

public BahmniObservation getChildObsFromParentObs(String parentObsGroupUuid, String childConceptName){
Concept childConcept = conceptService.getConceptByName(childConceptName);
return omrsObsToBahmniObsMapper.map(obsDao.getChildObsFromParent(parentObsGroupUuid, childConcept));
return omrsObsToBahmniObsMapper.map(obsDao.getChildObsFromParent(parentObsGroupUuid, childConcept), null);
}

public BahmniObservation getLatestBahmniObservationFor(String conceptName){
Obs obs = latestObs(conceptName);
if(obs != null) {
return omrsObsToBahmniObsMapper.map(obs);
return omrsObsToBahmniObsMapper.map(obs, null);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation;
import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.OMRSObsToBahmniObsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

Expand Down Expand Up @@ -93,7 +91,7 @@ private boolean programDoesNotHaveEncounters(String patientProgramUuid, Collecti
private List<BahmniObservation> convertToBahmniObservation(List<Obs> observations) {
List<BahmniObservation> bahmniObservations = new ArrayList<>();
for (Obs observation : observations) {
BahmniObservation bahmniObservation = omrsObsToBahmniObsMapper.map(observation);
BahmniObservation bahmniObservation = omrsObsToBahmniObsMapper.map(observation, null);
bahmniObservation.setObservationDateTime(observation.getObsDatetime());
bahmniObservations.add(bahmniObservation);
}
Expand Down Expand Up @@ -265,7 +263,7 @@ public Collection<BahmniObservation> getInitialObservationsForPatientProgram(Str
@Override
public BahmniObservation getBahmniObservationByUuid(String observationUuid) {
Obs obs = obsService.getObsByUuid(observationUuid);
return omrsObsToBahmniObsMapper.map(obs);
return omrsObsToBahmniObsMapper.map(obs, null);
}

@Override
Expand All @@ -274,7 +272,7 @@ public BahmniObservation getRevisedBahmniObservationByUuid(String observationUui
if (obs.getVoided()) {
obs = getRevisionObs(obs);
}
return omrsObsToBahmniObsMapper.map(obs);
return omrsObsToBahmniObsMapper.map(obs, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public void shouldGetChildObservationFromParent() throws Exception {
bahmniObs.setUuid("observation uuid");

PowerMockito.when(obsDao.getChildObsFromParent("parent obs uuid", vitalsConcept)).thenReturn(obs);
PowerMockito.when(omrsObsToBahmniObsMapper.map(obs)).thenReturn(bahmniObs);
PowerMockito.when(omrsObsToBahmniObsMapper.map(obs, null)).thenReturn(bahmniObs);
Assert.assertEquals("observation uuid", bahmniBridge.getChildObsFromParentObs("parent obs uuid", "vital concept name").getUuid());

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,12 @@ public void shouldGetBahmniObservationByObservationUuid() throws Exception {
Obs obs = new Obs();
BahmniObservation expectedBahmniObservation = new BahmniObservation();
when(obsService.getObsByUuid(observationUuid)).thenReturn(obs);
when(omrsObsToBahmniObsMapper.map(obs)).thenReturn(expectedBahmniObservation);
when(omrsObsToBahmniObsMapper.map(obs, null)).thenReturn(expectedBahmniObservation);

BahmniObservation actualBahmniObservation = bahmniObsService.getBahmniObservationByUuid(observationUuid);

verify(obsService, times(1)).getObsByUuid(observationUuid);
verify(omrsObsToBahmniObsMapper, times(1)).map(obs);
verify(omrsObsToBahmniObsMapper, times(1)).map(obs, null);
assertNotNull(actualBahmniObservation);
assertEquals(expectedBahmniObservation, actualBahmniObservation);
}
Expand Down Expand Up @@ -262,7 +262,7 @@ public void shouldReturnBahmniObservationWhenGetObsForFormBuilderFormsCalled() {
when(visitDao.getVisitIdsFor(patientUuid, numberOfVisits)).thenReturn(visitIds);
when(obsDao.getObsForFormBuilderForms(patientUuid, formNames, visitIds, encounters, null, null))
.thenReturn(singletonList(observation));
when(omrsObsToBahmniObsMapper.map(observation)).thenReturn(bahmniObservation);
when(omrsObsToBahmniObsMapper.map(observation, null)).thenReturn(bahmniObservation);

Collection<BahmniObservation> bahmniObservations = bahmniObsService.getObsForFormBuilderForms(patientUuid,
formNames, numberOfVisits, null, null, patientProgramUuid);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package org.bahmni.module.bahmnicore.web.v1_0.controller.display.controls;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.bahmni.module.bahmnicore.extensions.BahmniExtensions;
import org.bahmni.module.bahmnicore.obs.ObservationsAdder;
import org.bahmni.module.bahmnicore.service.BahmniObsService;
import org.bahmni.module.bahmnicore.util.MiscUtils;
import org.openmrs.Concept;
import org.openmrs.ConceptSearchResult;
import org.openmrs.Visit;
import org.openmrs.api.APIException;
import org.openmrs.api.ConceptService;
import org.openmrs.api.VisitService;
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation;
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;
Expand All @@ -21,8 +25,15 @@

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Controller
@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/bahmnicore/observations")
Expand All @@ -47,27 +58,52 @@ public BahmniObservationsController(BahmniObsService bahmniObsService, ConceptSe
@ResponseBody
public Collection<BahmniObservation> get(@RequestParam(value = "patientUuid", required = true) String patientUUID,
@RequestParam(value = "concept", required = true) List<String> rootConceptNames,
@RequestParam(value = "locale", required = false) String locale,
@RequestParam(value = "scope", required = false) String scope,
@RequestParam(value = "numberOfVisits", required = false) Integer numberOfVisits,
@RequestParam(value = "obsIgnoreList", required = false) List<String> obsIgnoreList,
@RequestParam(value = "filterObsWithOrders", required = false, defaultValue = "true") Boolean filterObsWithOrders ) throws ParseException {

List<Concept> rootConcepts = MiscUtils.getConceptsForNames(rootConceptNames, conceptService);

List<Concept> conceptList = searchConceptsByName(rootConceptNames, identifyLocale(locale));
Collection<BahmniObservation> observations;
if (ObjectUtils.equals(scope, LATEST)) {
observations = bahmniObsService.getLatest(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null);
observations = bahmniObsService.getLatest(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null);
} else if (ObjectUtils.equals(scope, INITIAL)) {
observations = bahmniObsService.getInitial(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null);
observations = bahmniObsService.getInitial(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null);
} else {
observations = bahmniObsService.observationsFor(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null, null, null);
observations = bahmniObsService.observationsFor(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null, null, null);
}

sendObsToGroovyScript(getConceptNames(rootConcepts), observations);
sendObsToGroovyScript(getConceptNames(conceptList), observations);

return observations;
}

private List<Concept> searchConceptsByName(List<String> conceptNames, Locale searchLocale) {
Set<Concept> conceptSet = new LinkedHashSet<>();
if (CollectionUtils.isNotEmpty(conceptNames)) {
List<Locale> localeList = Collections.singletonList(searchLocale);
for (String name : conceptNames) {
List<ConceptSearchResult> conceptsSearchResult = conceptService.getConcepts(name, localeList, false, null, null, null, null, null, 0, null);
List<Concept> conceptsByName = conceptsSearchResult.stream().map(conceptSearchResult -> conceptSearchResult.getConcept()).collect(Collectors.toList());
conceptSet.addAll(conceptsByName);
}
}
return new ArrayList<>(conceptSet);
}

private Locale identifyLocale(String locale) {
if (locale != null && !locale.isEmpty()) {
Locale searchLocale = LocaleUtility.fromSpecification(locale);
if (searchLocale.getLanguage().isEmpty()) {
throw new APIException("Invalid locale: " + locale);
}
return searchLocale;
} else {
return LocaleUtility.getDefaultLocale();
}
}

@RequestMapping(method = RequestMethod.GET, params = {"visitUuid"})
@ResponseBody
public Collection<BahmniObservation> get(@RequestParam(value = "visitUuid", required = true) String visitUuid,
Expand Down

0 comments on commit 45a3bd4

Please sign in to comment.