|
25 | 25 | import java.util.UUID; |
26 | 26 |
|
27 | 27 | import org.apache.commons.beanutils.BeanUtils; |
| 28 | +import org.apache.commons.text.StringEscapeUtils; |
28 | 29 | import org.apache.commons.collections.CollectionUtils; |
29 | 30 | import org.apache.commons.lang3.StringUtils; |
30 | 31 | import org.apache.commons.lang3.math.NumberUtils; |
|
44 | 45 | import org.openmrs.ConceptNumeric; |
45 | 46 | import org.openmrs.ConceptProposal; |
46 | 47 | import org.openmrs.ConceptReferenceRange; |
| 48 | +import org.openmrs.ConceptReferenceRangeContext; |
47 | 49 | import org.openmrs.ConceptReferenceTerm; |
48 | 50 | import org.openmrs.ConceptReferenceTermMap; |
49 | 51 | import org.openmrs.ConceptSearchResult; |
|
65 | 67 | import org.openmrs.api.context.Context; |
66 | 68 | import org.openmrs.api.db.ConceptDAO; |
67 | 69 | import org.openmrs.api.db.DAOException; |
| 70 | +import org.openmrs.api.db.hibernate.HibernateUtil; |
68 | 71 | import org.openmrs.customdatatype.CustomDatatypeUtil; |
| 72 | +import org.openmrs.util.ConceptReferenceRangeUtility; |
69 | 73 | import org.openmrs.util.OpenmrsConstants; |
70 | 74 | import org.openmrs.util.OpenmrsUtil; |
71 | | -import org.openmrs.validator.ObsValidator; |
72 | 75 | import org.openmrs.validator.ValidateUtil; |
73 | 76 | import org.slf4j.Logger; |
74 | 77 | import org.slf4j.LoggerFactory; |
@@ -2089,8 +2092,126 @@ public ConceptReferenceRange getConceptReferenceRangeByUuid(String uuid) { |
2089 | 2092 |
|
2090 | 2093 | @Override |
2091 | 2094 | public ConceptReferenceRange getConceptReferenceRange(Person person, Concept concept) { |
2092 | | - Obs obs = new Obs(person, concept, null, null); |
2093 | | - return new ObsValidator().getReferenceRange(obs); |
| 2095 | + if (person == null || concept == null) { |
| 2096 | + return null; |
| 2097 | + } |
| 2098 | + return Context.getConceptService().getConceptReferenceRange( |
| 2099 | + new ConceptReferenceRangeContext(person, concept, null)); |
| 2100 | + } |
| 2101 | + |
| 2102 | + @Override |
| 2103 | + public ConceptReferenceRange getConceptReferenceRange(ConceptReferenceRangeContext context) { |
| 2104 | + if (context == null) { |
| 2105 | + throw new IllegalArgumentException("ConceptReferenceRangeContext must not be null"); |
| 2106 | + } |
| 2107 | + |
| 2108 | + Concept concept = HibernateUtil.getRealObjectFromProxy(context.getConcept()); |
| 2109 | + if (!(concept instanceof ConceptNumeric) || concept.getDatatype() == null || !concept.getDatatype().isNumeric()) { |
| 2110 | + return null; |
| 2111 | + } |
| 2112 | + ConceptNumeric conceptNumeric = (ConceptNumeric) concept; |
| 2113 | + |
| 2114 | + List<ConceptReferenceRange> referenceRanges = |
| 2115 | + Context.getConceptService().getConceptReferenceRangesByConceptId(concept.getConceptId()); |
| 2116 | + |
| 2117 | + if (referenceRanges.isEmpty()) { |
| 2118 | + return getDefaultReferenceRange(conceptNumeric); |
| 2119 | + } |
| 2120 | + |
| 2121 | + ConceptReferenceRangeUtility referenceRangeUtility = new ConceptReferenceRangeUtility(); |
| 2122 | + List<ConceptReferenceRange> validRanges = new ArrayList<>(); |
| 2123 | + |
| 2124 | + for (ConceptReferenceRange referenceRange : referenceRanges) { |
| 2125 | + if (referenceRangeUtility.evaluateCriteria( |
| 2126 | + StringEscapeUtils.unescapeHtml4(referenceRange.getCriteria()), context)) { |
| 2127 | + validRanges.add(referenceRange); |
| 2128 | + } |
| 2129 | + } |
| 2130 | + |
| 2131 | + if (validRanges.isEmpty()) { |
| 2132 | + ConceptReferenceRange defaultReferenceRange = getDefaultReferenceRange(conceptNumeric); |
| 2133 | + if (defaultReferenceRange != null) { |
| 2134 | + return defaultReferenceRange; |
| 2135 | + } |
| 2136 | + return null; |
| 2137 | + } |
| 2138 | + |
| 2139 | + return findStrictestReferenceRange(validRanges); |
| 2140 | + } |
| 2141 | + |
| 2142 | + /** |
| 2143 | + * Returns a reference range derived from the ConceptNumeric's own range fields. |
| 2144 | + * Used as a fallback when no ConceptReferenceRange records exist or match. |
| 2145 | + */ |
| 2146 | + private static ConceptReferenceRange getDefaultReferenceRange(ConceptNumeric conceptNumeric) { |
| 2147 | + if (conceptNumeric == null || ( |
| 2148 | + conceptNumeric.getHiAbsolute() == null && |
| 2149 | + conceptNumeric.getHiCritical() == null && |
| 2150 | + conceptNumeric.getHiNormal() == null && |
| 2151 | + conceptNumeric.getLowAbsolute() == null && |
| 2152 | + conceptNumeric.getLowCritical() == null && |
| 2153 | + conceptNumeric.getLowNormal() == null |
| 2154 | + )) { |
| 2155 | + return null; |
| 2156 | + } |
| 2157 | + |
| 2158 | + ConceptReferenceRange defaultReferenceRange = new ConceptReferenceRange(); |
| 2159 | + defaultReferenceRange.setConceptNumeric(conceptNumeric); |
| 2160 | + defaultReferenceRange.setHiAbsolute(conceptNumeric.getHiAbsolute()); |
| 2161 | + defaultReferenceRange.setHiCritical(conceptNumeric.getHiCritical()); |
| 2162 | + defaultReferenceRange.setHiNormal(conceptNumeric.getHiNormal()); |
| 2163 | + defaultReferenceRange.setLowAbsolute(conceptNumeric.getLowAbsolute()); |
| 2164 | + defaultReferenceRange.setLowCritical(conceptNumeric.getLowCritical()); |
| 2165 | + defaultReferenceRange.setLowNormal(conceptNumeric.getLowNormal()); |
| 2166 | + return defaultReferenceRange; |
| 2167 | + } |
| 2168 | + |
| 2169 | + /** |
| 2170 | + * Combines multiple matching reference ranges into one by selecting the strictest bound for |
| 2171 | + * each limit. For low bounds, the highest value is strictest; for high bounds, the lowest. |
| 2172 | + * For example, ranges 80-150 and 60-140 combine to 80-140. |
| 2173 | + */ |
| 2174 | + private static ConceptReferenceRange findStrictestReferenceRange(List<ConceptReferenceRange> conceptReferenceRanges) { |
| 2175 | + if (conceptReferenceRanges.size() == 1) { |
| 2176 | + return conceptReferenceRanges.get(0); |
| 2177 | + } |
| 2178 | + |
| 2179 | + ConceptReferenceRange strictestRange = new ConceptReferenceRange(); |
| 2180 | + strictestRange.setConceptNumeric(conceptReferenceRanges.get(0).getConceptNumeric()); |
| 2181 | + |
| 2182 | + for (ConceptReferenceRange conceptReferenceRange : conceptReferenceRanges) { |
| 2183 | + if (conceptReferenceRange.getLowAbsolute() != null && |
| 2184 | + (strictestRange.getLowAbsolute() == null || strictestRange.getLowAbsolute() < conceptReferenceRange.getLowAbsolute())) { |
| 2185 | + strictestRange.setLowAbsolute(conceptReferenceRange.getLowAbsolute()); |
| 2186 | + } |
| 2187 | + |
| 2188 | + if (conceptReferenceRange.getLowCritical() != null && |
| 2189 | + (strictestRange.getLowCritical() == null || strictestRange.getLowCritical() < conceptReferenceRange.getLowCritical())) { |
| 2190 | + strictestRange.setLowCritical(conceptReferenceRange.getLowCritical()); |
| 2191 | + } |
| 2192 | + |
| 2193 | + if (conceptReferenceRange.getLowNormal() != null && |
| 2194 | + (strictestRange.getLowNormal() == null || strictestRange.getLowNormal() < conceptReferenceRange.getLowNormal())) { |
| 2195 | + strictestRange.setLowNormal(conceptReferenceRange.getLowNormal()); |
| 2196 | + } |
| 2197 | + |
| 2198 | + if (conceptReferenceRange.getHiNormal() != null && |
| 2199 | + (strictestRange.getHiNormal() == null || strictestRange.getHiNormal() > conceptReferenceRange.getHiNormal())) { |
| 2200 | + strictestRange.setHiNormal(conceptReferenceRange.getHiNormal()); |
| 2201 | + } |
| 2202 | + |
| 2203 | + if (conceptReferenceRange.getHiCritical() != null && |
| 2204 | + (strictestRange.getHiCritical() == null || strictestRange.getHiCritical() > conceptReferenceRange.getHiCritical())) { |
| 2205 | + strictestRange.setHiCritical(conceptReferenceRange.getHiCritical()); |
| 2206 | + } |
| 2207 | + |
| 2208 | + if (conceptReferenceRange.getHiAbsolute() != null && |
| 2209 | + (strictestRange.getHiAbsolute() == null || strictestRange.getHiAbsolute() > conceptReferenceRange.getHiAbsolute())) { |
| 2210 | + strictestRange.setHiAbsolute(conceptReferenceRange.getHiAbsolute()); |
| 2211 | + } |
| 2212 | + } |
| 2213 | + |
| 2214 | + return strictestRange; |
2094 | 2215 | } |
2095 | 2216 |
|
2096 | 2217 | /*** |
|
0 commit comments