NINS_CODE/bahmni_config/openmrs/obscalculator/BahmniObsValueCalculator.groovy
travelershot 70dda814aa codepush
2024-12-12 22:37:39 +06:00

300 lines
12 KiB
Groovy

import org.apache.commons.lang.StringUtils
import org.hibernate.Query
import org.hibernate.SessionFactory
import org.openmrs.Obs
import org.openmrs.Patient
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.api.context.Context
import org.openmrs.module.bahmniemrapi.obscalculator.ObsValueCalculator;
import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniEncounterTransaction
import org.openmrs.module.emrapi.encounter.domain.EncounterTransaction;
import org.joda.time.LocalDate;
import org.joda.time.Months;
public class BahmniObsValueCalculator implements ObsValueCalculator {
static Double BMI_VERY_SEVERELY_UNDERWEIGHT = 16.0;
static Double BMI_SEVERELY_UNDERWEIGHT = 17.0;
static Double BMI_UNDERWEIGHT = 18.5;
static Double BMI_NORMAL = 25.0;
static Double BMI_OVERWEIGHT = 30.0;
static Double BMI_OBESE = 35.0;
static Double BMI_SEVERELY_OBESE = 40.0;
static Map<BahmniObservation, BahmniObservation> obsParentMap = new HashMap<BahmniObservation, BahmniObservation>();
public static enum BmiStatus {
VERY_SEVERELY_UNDERWEIGHT("Very Severely Underweight"),
SEVERELY_UNDERWEIGHT("Severely Underweight"),
UNDERWEIGHT("Underweight"),
NORMAL("Normal"),
OVERWEIGHT("Overweight"),
OBESE("Obese"),
SEVERELY_OBESE("Severely Obese"),
VERY_SEVERELY_OBESE("Very Severely Obese");
private String status;
BmiStatus(String status) {
this.status = status
}
@Override
public String toString() {
return status;
}
}
public void run(BahmniEncounterTransaction bahmniEncounterTransaction) {
setBMI(bahmniEncounterTransaction);
}
static def setBMI(BahmniEncounterTransaction bahmniEncounterTransaction) {
Collection<BahmniObservation> observations = bahmniEncounterTransaction.getObservations()
def nowAsOfEncounter = bahmniEncounterTransaction.getEncounterDateTime() != null ? bahmniEncounterTransaction.getEncounterDateTime() : new Date();
BahmniObservation heightObservation = find("Height", observations, null)
BahmniObservation weightObservation = find("Weight", observations, null)
BahmniObservation bmiObservation = find("BMI", observations, null)
BahmniObservation bmiStatusObservation = find("BMI STATUS", observations, null)
BahmniObservation parent = null;
if(heightObservation) {
parent = obsParentMap.get(heightObservation)
} else if(weightObservation) {
parent = obsParentMap.get(weightObservation)
}
System.out.println("Groovy Scripts");
Patient patient = Context.getPatientService().getPatientByUuid(bahmniEncounterTransaction.getPatientUuid());
def patientAgeInMonthsAsOfEncounter = Months.monthsBetween(new LocalDate(patient.getBirthdate()), new LocalDate(nowAsOfEncounter)).getMonths();
if (hasValue(heightObservation) || hasValue(weightObservation)) {
if ((heightObservation && heightObservation.voided) && (weightObservation && weightObservation.voided)) {
voidBmiObs(bmiObservation, bmiStatusObservation)
return
}
def previousHeightValue = fetchLatestValue("Height", bahmniEncounterTransaction.getPatientUuid(), heightObservation, nowAsOfEncounter)
def previousWeightValue = fetchLatestValue("Weight", bahmniEncounterTransaction.getPatientUuid(), weightObservation, nowAsOfEncounter)
Double height = hasValue(heightObservation) && !heightObservation.voided ? heightObservation.getValue() as Double : previousHeightValue
Double weight = hasValue(weightObservation) && !weightObservation.voided ? weightObservation.getValue() as Double : previousWeightValue
Date obsDatetime = getDate(weightObservation) != null ? getDate(weightObservation) : getDate(heightObservation)
if (height == null || weight == null) {
voidBmiObs(bmiObservation, bmiStatusObservation)
return
}
def bmi = bmi(height, weight)
bmiObservation = bmiObservation ?: createObs("BMI", parent, bahmniEncounterTransaction, obsDatetime) as BahmniObservation;
bmiObservation.setValue(bmi);
bmiObservation.setComment([height: height, weight: weight, bmi: bmi].toString())
def bmiStatus = bmiStatus(bmi, patientAgeInMonthsAsOfEncounter, patient.getGender());
bmiStatusObservation = bmiStatusObservation ?: createObs("BMI STATUS", parent, bahmniEncounterTransaction, obsDatetime) as BahmniObservation;
bmiStatusObservation.setValue(bmiStatus);
bmiStatusObservation.setComment([height: height, weight: weight, bmi: bmi, bmiStatus: bmiStatus].toString())
}
}
private static Date getDate(BahmniObservation observation) {
return hasValue(observation) && !observation.voided ? observation.getObservationDateTime() : null;
}
private static boolean hasValue(BahmniObservation observation) {
return observation != null && observation.getValue() != null && !StringUtils.isEmpty(observation.getValue().toString());
}
private static void voidBmiObs(BahmniObservation bmiObservation, BahmniObservation bmiStatusObservation) {
if (hasValue(bmiObservation)) {
bmiObservation.voided = true
}
if (hasValue(bmiStatusObservation)) {
bmiStatusObservation.voided = true
}
}
static BahmniObservation createObs(String conceptName, BahmniObservation parent, BahmniEncounterTransaction encounterTransaction, Date obsDatetime) {
def concept = Context.getConceptService().getConceptByName(conceptName)
BahmniObservation newObservation = new BahmniObservation()
newObservation.setConcept(new EncounterTransaction.Concept(concept.getUuid(), conceptName))
newObservation.setObservationDateTime(obsDatetime);
parent == null ? encounterTransaction.addObservation(newObservation) : parent.addGroupMember(newObservation)
return newObservation
}
static def bmi(Double height, Double weight) {
Double heightInMeters = height * 0.0254;
Double value = weight / (heightInMeters * heightInMeters);
return new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
};
static def bmiStatus(Double bmi, Integer ageInMonth, String gender) {
BMIChart bmiChart = readCSV(OpenmrsUtil.getApplicationDataDirectory() + "obscalculator/BMI_chart.csv");
def bmiChartLine = bmiChart.get(gender, ageInMonth);
if(bmiChartLine != null ) {
return bmiChartLine.getStatus(bmi);
}
if (bmi < BMI_VERY_SEVERELY_UNDERWEIGHT) {
return BmiStatus.VERY_SEVERELY_UNDERWEIGHT;
}
if (bmi < BMI_SEVERELY_UNDERWEIGHT) {
return BmiStatus.SEVERELY_UNDERWEIGHT;
}
if (bmi < BMI_UNDERWEIGHT) {
return BmiStatus.UNDERWEIGHT;
}
if (bmi < BMI_NORMAL) {
return BmiStatus.NORMAL;
}
if (bmi < BMI_OVERWEIGHT) {
return BmiStatus.OVERWEIGHT;
}
if (bmi < BMI_OBESE) {
return BmiStatus.OBESE;
}
if (bmi < BMI_SEVERELY_OBESE) {
return BmiStatus.SEVERELY_OBESE;
}
if (bmi >= BMI_SEVERELY_OBESE) {
return BmiStatus.VERY_SEVERELY_OBESE;
}
return null
};
static Double fetchLatestValue(String conceptName, String patientUuid, BahmniObservation excludeObs, Date tillDate) {
SessionFactory sessionFactory = Context.getRegisteredComponents(SessionFactory.class).get(0)
def excludedObsIsSaved = excludeObs != null && excludeObs.uuid != null
String excludeObsClause = excludedObsIsSaved ? " and obs.uuid != :excludeObsUuid" : ""
Query queryToGetObservations = sessionFactory.getCurrentSession()
.createQuery("select obs " +
" from Obs as obs, ConceptName as cn " +
" where obs.person.uuid = :patientUuid " +
" and cn.concept = obs.concept.conceptId " +
" and cn.name = :conceptName " +
" and obs.voided = false" +
" and obs.obsDatetime <= :till" +
excludeObsClause +
" order by obs.obsDatetime desc");
queryToGetObservations.setString("patientUuid", patientUuid);
queryToGetObservations.setParameterList("conceptName", conceptName);
queryToGetObservations.setDate("till", tillDate);
if (excludedObsIsSaved) {
queryToGetObservations.setString("excludeObsUuid", excludeObs.uuid)
}
queryToGetObservations.setMaxResults(1);
List<Obs> observations = queryToGetObservations.list();
if (observations.size() > 0) {
return observations.get(0).getValueNumeric();
}
return null
}
static BahmniObservation find(String conceptName, Collection<BahmniObservation> observations, BahmniObservation parent) {
for (BahmniObservation observation : observations) {
if (conceptName.equalsIgnoreCase(observation.getConcept().getName())) {
obsParentMap.put(observation, parent);
return observation;
}
BahmniObservation matchingObservation = find(conceptName, observation.getGroupMembers(), observation)
if (matchingObservation) return matchingObservation;
}
return null
}
static BMIChart readCSV(String fileName) {
def chart = new BMIChart();
try {
new File(fileName).withReader { reader ->
def header = reader.readLine();
reader.splitEachLine(",") { tokens ->
chart.add(new BMIChartLine(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]));
}
}
} catch (FileNotFoundException e) {
}
return chart;
}
static class BMIChartLine {
public String gender;
public Integer ageInMonth;
public Double third;
public Double fifteenth;
public Double eightyFifth;
public Double ninetySeventh;
BMIChartLine(String gender, String ageInMonth, String third, String fifteenth, String eightyFifth, String ninetySeventh) {
this.gender = gender
this.ageInMonth = ageInMonth.toInteger();
this.third = third.toDouble();
this.fifteenth = fifteenth.toDouble();
this.eightyFifth = eightyFifth.toDouble();
this.ninetySeventh = ninetySeventh.toDouble();
}
public String getStatus(Double bmi) {
if(bmi < third) {
return BmiStatus.SEVERELY_UNDERWEIGHT
} else if(bmi < fifteenth) {
return BmiStatus.UNDERWEIGHT
} else if(bmi < eightyFifth) {
return BmiStatus.NORMAL
} else if(bmi < ninetySeventh) {
return BmiStatus.OVERWEIGHT
} else {
return BmiStatus.OBESE
}
}
}
static class BMIChart {
List<BMIChartLine> lines;
Map<BMIChartLineKey, BMIChartLine> map = new HashMap<BMIChartLineKey, BMIChartLine>();
public add(BMIChartLine line) {
def key = new BMIChartLineKey(line.gender, line.ageInMonth);
map.put(key, line);
}
public BMIChartLine get(String gender, Integer ageInMonth) {
def key = new BMIChartLineKey(gender, ageInMonth);
return map.get(key);
}
}
static class BMIChartLineKey {
public String gender;
public Integer ageInMonth;
BMIChartLineKey(String gender, Integer ageInMonth) {
this.gender = gender
this.ageInMonth = ageInMonth
}
boolean equals(o) {
if (this.is(o)) return true
if (getClass() != o.class) return false
BMIChartLineKey bmiKey = (BMIChartLineKey) o
if (ageInMonth != bmiKey.ageInMonth) return false
if (gender != bmiKey.gender) return false
return true
}
int hashCode() {
int result
result = (gender != null ? gender.hashCode() : 0)
result = 31 * result + (ageInMonth != null ? ageInMonth.hashCode() : 0)
return result
}
}
}