Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public interface DroolsEngineService extends OpenmrsService {
* @param <T> the type of objects to retrieve
* @param session the Drools session to query
* @param tClass the class object representing the type to retrieve
* @return List<T> a list of objects of the specified type from the session
* @return a list of objects of the specified type from the session
* @throws DroolsSessionException if the session does not exist or cannot be
* accessed
*/
Expand All @@ -62,7 +62,7 @@ public interface DroolsEngineService extends OpenmrsService {
* @param session the Drools session to query
* @param tClass the class object representing the type to retrieve
* @param tPredicate the predicate that returned objects must satisfy
* @return List<T> a list of matching objects from the session
* @return a list of matching objects from the session
* @throws DroolsSessionException if the session does not exist or cannot be
* accessed
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public interface DroolsCalculationService {
*
* // Check if most recent diagnosis equals a specific concept
* checkMostRecentObs(patient, "CIEL:1284", Operator.EQUALS, "CIEL:5622");
* }</pre>
*
* @param patient the patient whose observations will be evaluated; must not be null
* @param conceptRef the concept reference (UUID or mapping)
Expand Down
86 changes: 86 additions & 0 deletions api/src/main/java/org/openmrs/module/drools/utils/CommonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@
import org.drools.decisiontable.SpreadsheetCompiler;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.openmrs.Concept;
import org.openmrs.ConceptMap;
import org.openmrs.ConceptMapType;
import org.openmrs.api.context.Context;
import org.openmrs.module.drools.session.ExternalEvaluatorManager;
import org.openmrs.module.drools.session.DroolsSessionConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class CommonUtils {

Expand Down Expand Up @@ -85,4 +92,83 @@ public static void convertExcelRulesToDrl(String excelFilePath, String outputDrl
}

}

/**
* Gets a concept by its SAME-AS mapping to an external source.
* Unlike ConceptService.getConceptByMapping(), this method only considers
* SAME-AS mappings, avoiding the "Multiple non-retired concepts found" error
* that occurs when a concept has both SAME-AS and NARROWER-THAN mappings.
*
* @param code The concept code in the external source
* @param sourceName The name of the concept source (e.g., "CIEL")
* @return The concept with a SAME-AS mapping to the given code, or null if not found
*/
public static Concept getConceptBySameAsMapping(String code, String sourceName) {
if (code == null || sourceName == null) {
return null;
}

List<Concept> concepts = Context.getConceptService().getConceptsByMapping(code, sourceName, false);
if (concepts == null || concepts.isEmpty()) {
return null;
}

// Filter for SAME-AS mapping type only
for (Concept concept : concepts) {
for (ConceptMap mapping : concept.getConceptMappings()) {
if (mapping.getConceptReferenceTerm() != null
&& mapping.getConceptReferenceTerm().getConceptSource() != null
&& sourceName.equals(mapping.getConceptReferenceTerm().getConceptSource().getName())
&& code.equals(mapping.getConceptReferenceTerm().getCode())) {
ConceptMapType mapType = mapping.getConceptMapType();
if (mapType != null && "SAME-AS".equalsIgnoreCase(mapType.getName())) {
return concept;
}
}
}
}

// Fall back to first result if no SAME-AS found (backwards compatibility)
log.warn("No SAME-AS mapping found for code {} from source {}, returning first match", code, sourceName);
return concepts.get(0);
}

/**
* Gets all concepts that have a SAME-AS or NARROWER-THAN mapping to the given code.
* This is useful for finding concepts that represent the same or more specific
* versions of a given terminology code (e.g., SNOMED CT).
*
* @param code The concept code in the external source
* @param sourceName The name of the concept source (e.g., "SNOMED CT")
* @return A set of concepts with SAME-AS or NARROWER-THAN mappings, or empty set if none found
*/
public static Set<Concept> getConceptsBySameAsOrNarrowerThanMapping(String code, String sourceName) {
Set<Concept> result = new HashSet<>();
if (code == null || sourceName == null) {
return result;
}

List<Concept> concepts = Context.getConceptService().getConceptsByMapping(code, sourceName, false);
if (concepts == null || concepts.isEmpty()) {
return result;
}

for (Concept concept : concepts) {
for (ConceptMap mapping : concept.getConceptMappings()) {
if (mapping.getConceptReferenceTerm() != null
&& mapping.getConceptReferenceTerm().getConceptSource() != null
&& sourceName.equals(mapping.getConceptReferenceTerm().getConceptSource().getName())
&& code.equals(mapping.getConceptReferenceTerm().getCode())
&& mapping.getConceptMapType() != null) {
String mapType = mapping.getConceptMapType().getName();
if ("SAME-AS".equalsIgnoreCase(mapType) || "NARROWER-THAN".equalsIgnoreCase(mapType)) {
result.add(concept);
break;
}
}
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static Date daysFromNow(int days) {
}

/**
* Checks if the difference between start and end is >= threshold in given granularity.
* Checks if the difference between start and end is at least the threshold in given granularity.
*
* @param start the start date
* @param end the end date
Expand Down Expand Up @@ -158,7 +158,7 @@ public static Boolean isAtLeast(Date start, Date end, long threshold, Granularit
* @param start the start date
* @param end the end date
* @param granularity the granularity
* @return the difference (end - start) in given units, negative if end < start
* @return the difference (end - start) in given units, negative if end is before start
*/
public static long diff(Date start, Date end, Granularity granularity) {
if (start == null || end == null || granularity == null) {
Expand Down
2 changes: 2 additions & 0 deletions omod/src/main/resources/webModuleApplicationContext.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@
http://www.springframework.org/schema/util/spring-util-3.0.xsd">

<context:component-scan base-package="org.openmrs.module.drools.web.controller" />
<context:component-scan base-package="org.openmrs.module.drools.loader" />
<context:component-scan base-package="org.openmrs.module.drools.provider" />
</beans>