From 8036820fae8242b52605fd41530c5bd709a365bb Mon Sep 17 00:00:00 2001 From: kollil Date: Fri, 10 Oct 2025 14:49:27 -0700 Subject: [PATCH 1/8] Made changes to the Weights drop alert. --- .../notification/WeightAlertsNotification.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java index b661a3a64..bd1607f0e 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java @@ -79,13 +79,13 @@ public String getEmailSubject(Container c) @Override public String getCronString() { - return "0 15 9 ? * MON"; + return "0 0 12 ? * THU"; } @Override public String getScheduleDescription() { - return "every Monday, at 9:15 AM"; + return "every Thursday, at 12pm"; } @Override @@ -97,7 +97,7 @@ public String getMessageBodyHTML(Container c, User u) Date now = new Date(); msg.append("This email contains alerts of significant weight changes. It was run on: " + getDateFormat(c).format(now) + " at " + _timeFormat.format(now) + ".

"); - getLivingWithoutWeight(c, u, msg); + //getLivingWithoutWeight(c, u, msg); generateCombinedWeightTable(c, u, msg); @@ -110,7 +110,7 @@ private void generateCombinedWeightTable(final Container c, User u, final String //first weight drops Set dropDistinctIds = new HashSet<>(); - processWeights(c, u, sb, 0, 30, CompareType.LTE, -10, dropDistinctIds); + processWeights(c, u, sb, 0, 100, CompareType.LTE, -10, dropDistinctIds); consecutiveWeightDrops(c, u, sb, dropDistinctIds); if (!dropDistinctIds.isEmpty()) @@ -121,7 +121,7 @@ private void generateCombinedWeightTable(final Container c, User u, final String //also weight gains Set gainDistinctIds = new HashSet<>(); - processWeights(c, u, sb, 0, 30, CompareType.GTE, 10, gainDistinctIds); + processWeights(c, u, sb, 0, 100, CompareType.GTE, 10, gainDistinctIds); if (!gainDistinctIds.isEmpty()) { @@ -180,7 +180,8 @@ private void processWeights(Container c, User u, final StringBuilder msg, int mi final FieldKey ageKey = FieldKey.fromString("Id/age/AgeFriendly"); final FieldKey problemKey = FieldKey.fromString("Id/openProblems/problems"); final FieldKey investKey = FieldKey.fromString("Id/activeAssignments/investigators"); - final FieldKey vetsKey = FieldKey.fromString("Id/activeAssignments/vets"); + //final FieldKey vetsKey = FieldKey.fromString("Id/activeAssignments/vets"); + final FieldKey vetsKey = FieldKey.fromString("Id/assignedVet/AssignedVet"); final FieldKey peKey = FieldKey.fromString("Id/physicalExamHistory/daysSinceExam"); List colKeys = new ArrayList<>(); @@ -206,7 +207,7 @@ private void processWeights(Container c, User u, final StringBuilder msg, int mi filter.addCondition(FieldKey.fromString("IntervalInDays"), max, CompareType.LTE); Calendar date = Calendar.getInstance(); - date.add(Calendar.DATE, -30); + date.add(Calendar.DATE, -100); /// change to last 100 days filter.addCondition(FieldKey.fromString("LatestWeightDate"), getDateFormat(c).format(date.getTime()), CompareType.DATE_GTE); TableSelector ts = new TableSelector(ti, columns.values(), filter, null); From 34222c215b7492d510455afe1f2e748a9b6e8689 Mon Sep 17 00:00:00 2001 From: kollil Date: Tue, 9 Dec 2025 15:10:14 -0800 Subject: [PATCH 2/8] Added query.xml files for the db tables --- .../labkey/onprc_ehr/notification/WeightAlertsNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java index bd1607f0e..2e8135f75 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java @@ -80,7 +80,7 @@ public String getEmailSubject(Container c) public String getCronString() { return "0 0 12 ? * THU"; - } + } //Made changes to the alert by Kollil, Refer to tkt # 13461 @Override public String getScheduleDescription() From 439341f806c376eb9fab2077d2f8c267a4e53ccc Mon Sep 17 00:00:00 2001 From: kollil Date: Fri, 9 Jan 2026 13:31:11 -0800 Subject: [PATCH 3/8] Added new functionality to the weights data --- .../study/Demographics_NotInMMA.query.xml | 9 + .../queries/study/Demographics_NotInMMA.sql | 47 +++ .../study/weightRelChange_NotInMMA.query.xml | 68 ++++ .../study/weightRelChange_NotInMMA.sql | 59 ++++ .../WeightAlertsNotification.java | 296 +++++++++--------- 5 files changed, 336 insertions(+), 143 deletions(-) create mode 100644 onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml create mode 100644 onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql create mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml create mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql diff --git a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml new file mode 100644 index 000000000..d949afe42 --- /dev/null +++ b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml @@ -0,0 +1,9 @@ + + + + + Animals not in weight management regimen +
+
+
+
diff --git a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql new file mode 100644 index 000000000..d3ed0c31f --- /dev/null +++ b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql @@ -0,0 +1,47 @@ +/* + Created by Kollil in Dec 2025 + Tkt # 13461 + Added two filters to the Demographics dataset: + 1. Filter out any animal with the following SNOMED Codes: + Begin active weight management regimen (P-YY961) + However, we would need to include animals that have this additional SNOMED Code if it's entered AFTER the one above + Release from active weight management regimen (P-YY960) + 2. Remove Shelters, Corral and Hospital locations from the lists + */ +Select + d.Id.curlocation.area as Area, + d.Id.curlocation.room as Room, + d.Id.curlocation.cage as Cage, + d.Id, + d.Id.utilization.use as ProjectsAndGroups, + d.species, + d.geographic_origin, + d.gender as Sex, + d.calculated_status, + d.birth, + d.Id.Age.YearAndDays, + d.Id.MostRecentWeight.MostRecentWeight, + d.Id.MostRecentWeight.MostRecentWeightDate, + d.Id.viral_status.viralStatus, + d.history +From Demographics d +Where d.Id Not In ( + SELECT DISTINCT t.Id + FROM study.WeightManagementMMAData t + WHERE NOT EXISTS ( + -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + SELECT 1 + FROM study.WeightManagementMMAData b + WHERE b.Id = t.Id + AND b.code = 'P-YY961' + AND b.date = (SELECT MAX(b2.date) + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = t.Id + AND b2.code = 'P-YY961') + AND NOT EXISTS (SELECT 1 + FROM study.WeightManagementMMAData r + WHERE r.Id = t.Id + AND r.code = 'P-YY960' + AND r.date > b.date)) +) + AND d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml new file mode 100644 index 000000000..4270989c0 --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml @@ -0,0 +1,68 @@ + + + + + Animals(Not in Weight Management Regimen) with Weight Change, Relative to Current Weight + This query shows the percent change of each weight, relative to the current weight + + + true + true + + + true + + study + animal + id + + + + true + Date of Last Weight + + + Old Weight (kg) + + + % Change Relative To Current + + + + + + true + FF0000 + + + + + + true + 458B00 + + + + + Days Since Weight + + + Months Since Weight + + + Latest Weight (kg) + /query/executeQuery.view?schemaName=study& + query.queryName=weight& + query.date~eq=${LatestWeightDate}& + query.sort=-date + + + + Latest Weight Date + + + PctChange +
+
+
+
diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql new file mode 100644 index 000000000..0b5b167d5 --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql @@ -0,0 +1,59 @@ +/* + Created by Kollil in Dec 2025 + Tkt # 13461 + This query is the ONPRC version of the core LK EHR query called, weightRelChange. In addition to the original one, this new query has two filters: + 1. Filter out any animal with the following SNOMED Codes: + Begin active weight management regimen (P-YY961) + However, we would need to include animals that have this additional SNOMED Code if it's entered AFTER the one above + Release from active weight management regimen (P-YY960) + 2. Remove Shelters, Corral and Hospital locations from the lists + */ +SELECT + w.lsid, + w.Id, + w.date, + w.Id.MostRecentWeight.MostRecentWeightDate as LatestWeightDate, + w.Id.MostRecentWeight.MostRecentWeight AS LatestWeight, + + timestampdiff('SQL_TSI_DAY', w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInDays, + age_in_months(w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInMonths, + + w.weight, + CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN + Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1) + ELSE + null + END AS PctChange, + + CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN + Abs(Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1)) + else + null + END AS AbsPctChange, + w.qcstate + +FROM study.weight w +WHERE w.qcstate.publicdata = true + AND w.Id NOT IN + (SELECT DISTINCT t.Id + FROM study.WeightManagementMMAData t + WHERE NOT EXISTS + ( + -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + SELECT 1 + FROM study.WeightManagementMMAData b + WHERE b.Id = t.Id + AND b.code = 'P-YY961' + AND b.date = (SELECT MAX(b2.date) + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = t.Id + AND b2.code = 'P-YY961') + AND NOT EXISTS (SELECT 1 + FROM study.WeightManagementMMAData r + WHERE r.Id = t.Id + AND r.code = 'P-YY960' + AND r.date > b.date) + ) + ) + -- Exclude animals from these locations + AND w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital') \ No newline at end of file diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java index 2e8135f75..c2e65237a 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java @@ -20,6 +20,7 @@ import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerFilter; import org.labkey.api.data.Results; import org.labkey.api.data.ResultsImpl; import org.labkey.api.data.Selector; @@ -97,7 +98,11 @@ public String getMessageBodyHTML(Container c, User u) Date now = new Date(); msg.append("This email contains alerts of significant weight changes. It was run on: " + getDateFormat(c).format(now) + " at " + _timeFormat.format(now) + ".

"); - //getLivingWithoutWeight(c, u, msg); + /* + Changed by Kollil: 1/2026, tkt #13461 + 1. Delete the "animals do not have a weight" since that's captured on the colony management emails already. + */ + //getLivingWithoutWeight(c, u, msg); generateCombinedWeightTable(c, u, msg); @@ -111,11 +116,15 @@ private void generateCombinedWeightTable(final Container c, User u, final String //first weight drops Set dropDistinctIds = new HashSet<>(); processWeights(c, u, sb, 0, 100, CompareType.LTE, -10, dropDistinctIds); - consecutiveWeightDrops(c, u, sb, dropDistinctIds); + /* + Changed by Kollil: 1/2026 + Disabling this section as per ticket #13461 + */ + //consecutiveWeightDrops(c, u, sb, dropDistinctIds); if (!dropDistinctIds.isEmpty()) { - String url = getExecuteQueryUrl(c, "study", "Demographics", "By Location") + "&query.calculated_status~eq=Alive&query.Id~in=" + (StringUtils.join(new ArrayList(dropDistinctIds), ";")); + String url = getExecuteQueryUrl(c, "study", "Demographics_NotInMMA", null ) + "&query.calculated_status~eq=Alive&query.Id~in=" + (StringUtils.join(new ArrayList(dropDistinctIds), ";")); sb.insert(0, "WARNING: There are " + dropDistinctIds.size() + " animals that experienced either a large weight loss, or 3 consecutive weight drops. Click here to view this list, or view the data below.


"); } @@ -125,53 +134,18 @@ private void generateCombinedWeightTable(final Container c, User u, final String if (!gainDistinctIds.isEmpty()) { - String url = getExecuteQueryUrl(c, "study", "Demographics", "By Location") + "&query.calculated_status~eq=Alive&query.Id~in=" + (StringUtils.join(new ArrayList(gainDistinctIds), ";")); + String url = getExecuteQueryUrl(c, "study", "Demographics_NotInMMA", null) + "&query.calculated_status~eq=Alive&query.Id~in=" + (StringUtils.join(new ArrayList(gainDistinctIds), ";")); sb.insert(0, "WARNING: There are " + gainDistinctIds.size() + " animals that experienced large weight gain (>10%). Click here to view this list, or view the data below.


"); } msg.append(sb); } - private void getLivingWithoutWeight(final Container c, User u, final StringBuilder msg) - { - SimpleFilter filter = new SimpleFilter(FieldKey.fromString("calculated_status"), "Alive"); - filter.addCondition(FieldKey.fromString("Id/MostRecentWeight/MostRecentWeightDate"), null, CompareType.ISBLANK); - Sort sort = new Sort(getStudy(c).getSubjectColumnName()); - - TableInfo ti = getStudySchema(c, u).getTable("Demographics"); - List colKeys = new ArrayList<>(); - colKeys.add(FieldKey.fromString(getStudy(c).getSubjectColumnName())); - colKeys.add(FieldKey.fromString("Id/age/AgeFriendly")); - final Map columns = QueryService.get().getColumns(ti, colKeys); - - TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); - if (ts.exists()) - { - msg.append("WARNING: The animals listed below do not have a weight.\n"); - msg.append(" Click here to view these animals

\n"); - - ts.forEach(new TableSelector.ForEachBlock<>() - { - @Override - public void exec(ResultSet rs) throws SQLException - { - Results results = new ResultsImpl(rs, columns); - msg.append(rs.getString(getStudy(c).getSubjectColumnName())); - String age = results.getString(FieldKey.fromString("Id/age/AgeFriendly")); - if (age != null) - msg.append(" (Age: " + age + ")"); - - msg.append("
\n"); - } - }); - - msg.append("
\n"); - } - } - private void processWeights(Container c, User u, final StringBuilder msg, int min, int max, CompareType ct, double pct, @Nullable Set distinctIds) { - TableInfo ti = getStudySchema(c, u).getTable("weightRelChange"); + //Daily transfers query + TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("weightRelChange_NotInMMA", ContainerFilter.Type.AllFolders.create(c, u)); +// TableInfo ti = getStudySchema(c, u).getTable("weightRelChange_NotInMMA"); assert ti != null; final FieldKey areaKey = FieldKey.fromString("Id/curLocation/Area"); @@ -263,14 +237,13 @@ public void exec(ResultSet object) throws SQLException if (!summary.isEmpty()) { - msg.append("

Click here to view these " + distinctAnimals.size() + " animals

\n"); + msg.append("

Click here to view these " + distinctAnimals.size() + " animals

\n"); msg.append(""); for (String area : summary.keySet()) { Map>> areaValue = summary.get(area); - for (String room : areaValue.keySet()) - { + for (String room : areaValue.keySet()) { List> roomValue = areaValue.get(room); for (Map map : roomValue) { @@ -310,109 +283,146 @@ public void exec(ResultSet object) throws SQLException { msg.append("There are no changes during this period.
"); } - if (distinctIds != null && !distinctAnimals.isEmpty()) distinctIds.addAll(distinctAnimals); } - protected void consecutiveWeightDrops(final Container c, User u, final StringBuilder msg, @Nullable Set distinctIds) - { - SimpleFilter filter = new SimpleFilter(FieldKey.fromString("Id/dataset/demographics/calculated_status"), "Alive"); - Calendar date = Calendar.getInstance(); - date.add(Calendar.DATE, -10); - filter.addCondition(FieldKey.fromString("date"), date.getTime(), CompareType.DATE_GTE); - Sort sort = new Sort(); - sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/area"), Sort.SortDirection.ASC)); - sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/room"), Sort.SortDirection.ASC)); - sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/cage"), Sort.SortDirection.ASC)); - - TableInfo ti = getStudySchema(c, u).getTable("weightConsecutiveDrops"); - assert ti != null; - - List colKeys = new ArrayList<>(); - colKeys.add(FieldKey.fromString("Id/curLocation/area")); - colKeys.add(FieldKey.fromString("Id/curLocation/room")); - colKeys.add(FieldKey.fromString("Id/curLocation/cage")); - colKeys.add(FieldKey.fromString("Id/activeAssignments/investigators")); - colKeys.add(FieldKey.fromString("Id/activeAssignments/vets")); - colKeys.add(FieldKey.fromString("Id/physicalExamHistory/daysSinceExam")); - colKeys.add(FieldKey.fromString("Id/openProblems/problems")); - - final Map columns = QueryService.get().getColumns(ti, colKeys); - for (ColumnInfo col : ti.getColumns()) - { - columns.put(col.getFieldKey(), col); - } - - TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); - if (ts.exists()) - { - final Set animalIds = new HashSet<>(); - - msg.append("WARNING: The following animals have a weight entered since " + getDateFormat(c).format(date.getTime()) + " representing 3 consecutive weight drops with a total drop of more than 3%:

\n"); - - final StringBuilder tableMsg = new StringBuilder(); - tableMsg.append("
AreaRoomCageIdInvestigatorsResponsible VetOpen ProblemsDays Since Last PEWeight DatesDays BetweenWeight (kg)Percent Change
"); - ts.forEach(new TableSelector.ForEachBlock<>() - { - @Override - public void exec(ResultSet rs) throws SQLException - { - Results results = new ResultsImpl(rs, columns); - - tableMsg.append(""); - tableMsg.append(""); - tableMsg.append(""); - String subj = getValue(results, getStudy(c).getSubjectColumnName()); - tableMsg.append(""); - - tableMsg.append(""); - tableMsg.append(""); - tableMsg.append(""); - tableMsg.append(""); - - tableMsg.append(""); - - tableMsg.append(""); - - tableMsg.append(""); - - tableMsg.append(""); - - tableMsg.append(""); - - String id = getValue(results, getStudy(c).getSubjectColumnName()); - if (id != null) - animalIds.add(id); - } - }); - - tableMsg.append("
RoomCageIdInvestigator(s)Responsible VetOpen ProblemsDays Since Last PEWeight DateInterval (days)Weight (kg)% Change
").append(getValue(results, "Id/curLocation/room")).append("").append(getValue(results, "Id/curLocation/cage")).append(""); - tableMsg.append(subj).append("").append(getValue(results, "Id/activeAssignments/investigators")).append("").append(getValue(results, "Id/activeAssignments/vets")).append("").append(getValue(results, "Id/openProblems/problems")).append("").append(getValue(results, "Id/physicalExamHistory/daysSinceExam")).append("").append(getDateValue(c, results, "date")).append("
"); - tableMsg.append(getDateValue(c, results, "prevDate1")).append("
"); - tableMsg.append(getDateValue(c, results, "prevDate2")); - tableMsg.append("
"); - tableMsg.append(getNumericValue(results, "interval1")).append("
"); - tableMsg.append(getNumericValue(results, "interval2")).append("
"); - tableMsg.append("
"); - tableMsg.append("
").append(getValue(results, "curWeight")).append("
"); - tableMsg.append(getValue(results, "prevWeight1")).append("
"); - tableMsg.append(getValue(results, "prevWeight2")); - tableMsg.append("
").append(getNumericValue(results, "pctChange1")).append("
"); - tableMsg.append(getNumericValue(results, "pctChange2")).append("
"); - tableMsg.append("
"); - tableMsg.append("
\n"); - - msg.append("

Click here to view these " + animalIds.size() + " animals

\n"); - msg.append(tableMsg); - msg.append("
\n"); - - if (distinctIds != null && !animalIds.isEmpty()) - distinctIds.addAll(animalIds); - } - } +// protected void consecutiveWeightDrops(final Container c, User u, final StringBuilder msg, @Nullable Set distinctIds) +// { +// SimpleFilter filter = new SimpleFilter(FieldKey.fromString("Id/dataset/demographics/calculated_status"), "Alive"); +// Calendar date = Calendar.getInstance(); +// date.add(Calendar.DATE, -10); +// +// filter.addCondition(FieldKey.fromString("date"), date.getTime(), CompareType.DATE_GTE); +// Sort sort = new Sort(); +// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/area"), Sort.SortDirection.ASC)); +// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/room"), Sort.SortDirection.ASC)); +// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/cage"), Sort.SortDirection.ASC)); +// +// TableInfo ti = getStudySchema(c, u).getTable("weightConsecutiveDrops"); +// assert ti != null; +// +// List colKeys = new ArrayList<>(); +// colKeys.add(FieldKey.fromString("Id/curLocation/area")); +// colKeys.add(FieldKey.fromString("Id/curLocation/room")); +// colKeys.add(FieldKey.fromString("Id/curLocation/cage")); +// colKeys.add(FieldKey.fromString("Id/activeAssignments/investigators")); +// colKeys.add(FieldKey.fromString("Id/activeAssignments/vets")); +// colKeys.add(FieldKey.fromString("Id/physicalExamHistory/daysSinceExam")); +// colKeys.add(FieldKey.fromString("Id/openProblems/problems")); +// +// final Map columns = QueryService.get().getColumns(ti, colKeys); +// for (ColumnInfo col : ti.getColumns()) +// { +// columns.put(col.getFieldKey(), col); +// } +// +// TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); +// if (ts.exists()) +// { +// final Set animalIds = new HashSet<>(); +// +// msg.append("WARNING: The following animals have a weight entered since " + getDateFormat(c).format(date.getTime()) + " representing 3 consecutive weight drops with a total drop of more than 3%:

\n"); +// +// final StringBuilder tableMsg = new StringBuilder(); +// tableMsg.append(""); +// ts.forEach(new TableSelector.ForEachBlock<>() +// { +// @Override +// public void exec(ResultSet rs) throws SQLException +// { +// Results results = new ResultsImpl(rs, columns); +// +// tableMsg.append(""); +// tableMsg.append(""); +// tableMsg.append(""); +// String subj = getValue(results, getStudy(c).getSubjectColumnName()); +// tableMsg.append(""); +// +// tableMsg.append(""); +// tableMsg.append(""); +// tableMsg.append(""); +// tableMsg.append(""); +// +// tableMsg.append(""); +// +// tableMsg.append(""); +// +// tableMsg.append(""); +// +// tableMsg.append(""); +// +// tableMsg.append(""); +// +// String id = getValue(results, getStudy(c).getSubjectColumnName()); +// if (id != null) +// animalIds.add(id); +// } +// }); +// +// tableMsg.append("
RoomCageIdInvestigator(s)Responsible VetOpen ProblemsDays Since Last PEWeight DateInterval (days)Weight (kg)% Change
").append(getValue(results, "Id/curLocation/room")).append("").append(getValue(results, "Id/curLocation/cage")).append(""); +// tableMsg.append(subj).append("").append(getValue(results, "Id/activeAssignments/investigators")).append("").append(getValue(results, "Id/activeAssignments/vets")).append("").append(getValue(results, "Id/openProblems/problems")).append("").append(getValue(results, "Id/physicalExamHistory/daysSinceExam")).append("").append(getDateValue(c, results, "date")).append("
"); +// tableMsg.append(getDateValue(c, results, "prevDate1")).append("
"); +// tableMsg.append(getDateValue(c, results, "prevDate2")); +// tableMsg.append("
"); +// tableMsg.append(getNumericValue(results, "interval1")).append("
"); +// tableMsg.append(getNumericValue(results, "interval2")).append("
"); +// tableMsg.append("
"); +// tableMsg.append("
").append(getValue(results, "curWeight")).append("
"); +// tableMsg.append(getValue(results, "prevWeight1")).append("
"); +// tableMsg.append(getValue(results, "prevWeight2")); +// tableMsg.append("
").append(getNumericValue(results, "pctChange1")).append("
"); +// tableMsg.append(getNumericValue(results, "pctChange2")).append("
"); +// tableMsg.append("
"); +// tableMsg.append("
\n"); +// +// msg.append("

Click here to view these " + animalIds.size() + " animals

\n"); +// msg.append(tableMsg); +// msg.append("
\n"); +// +// if (distinctIds != null && !animalIds.isEmpty()) +// distinctIds.addAll(animalIds); +// } +// } + + // private void getLivingWithoutWeight(final Container c, User u, final StringBuilder msg) +// { +// SimpleFilter filter = new SimpleFilter(FieldKey.fromString("calculated_status"), "Alive"); +// filter.addCondition(FieldKey.fromString("Id/MostRecentWeight/MostRecentWeightDate"), null, CompareType.ISBLANK); +// Sort sort = new Sort(getStudy(c).getSubjectColumnName()); +// +// TableInfo ti = getStudySchema(c, u).getTable("Demographics"); +// List colKeys = new ArrayList<>(); +// colKeys.add(FieldKey.fromString(getStudy(c).getSubjectColumnName())); +// colKeys.add(FieldKey.fromString("Id/age/AgeFriendly")); +// final Map columns = QueryService.get().getColumns(ti, colKeys); +// +// TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); +// if (ts.exists()) +// { +// msg.append("WARNING: The animals listed below do not have a weight.\n"); +// msg.append(" Click here to view these animals

\n"); +// +// ts.forEach(new TableSelector.ForEachBlock<>() +// { +// @Override +// public void exec(ResultSet rs) throws SQLException +// { +// Results results = new ResultsImpl(rs, columns); +// msg.append(rs.getString(getStudy(c).getSubjectColumnName())); +// String age = results.getString(FieldKey.fromString("Id/age/AgeFriendly")); +// if (age != null) +// msg.append(" (Age: " + age + ")"); +// +// msg.append("
\n"); +// } +// }); +// +// msg.append("
\n"); +// } +// } private String getValue(Results rs, String prop) throws SQLException { From 9811c87ba7619774faedf570ae3d98aeee3c895a Mon Sep 17 00:00:00 2001 From: kollil Date: Fri, 9 Jan 2026 16:17:16 -0800 Subject: [PATCH 4/8] Added new exclusion clauses --- .../queries/study/Demographics_NotInMMA.sql | 22 +++++++++++-------- .../study/weightRelChange_NotInMMA.sql | 8 ++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql index d3ed0c31f..3e6191741 100644 --- a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql +++ b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql @@ -25,7 +25,12 @@ Select d.Id.viral_status.viralStatus, d.history From Demographics d -Where d.Id Not In ( +WHERE d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital') -- Exclude animals from these locations + AND NOT ( -- Exclude females under 5yrs, males under 7yrs + (d.gender.code = 'f' AND d.Id.age.ageInYears < 5) + OR (d.gender.code = 'm' AND d.Id.age.ageInYears < 7) + ) + AND d.Id Not In ( SELECT DISTINCT t.Id FROM study.WeightManagementMMAData t WHERE NOT EXISTS ( @@ -35,13 +40,12 @@ Where d.Id Not In ( WHERE b.Id = t.Id AND b.code = 'P-YY961' AND b.date = (SELECT MAX(b2.date) - FROM study.WeightManagementMMAData b2 - WHERE b2.Id = t.Id - AND b2.code = 'P-YY961') + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = t.Id + AND b2.code = 'P-YY961') AND NOT EXISTS (SELECT 1 - FROM study.WeightManagementMMAData r - WHERE r.Id = t.Id - AND r.code = 'P-YY960' - AND r.date > b.date)) + FROM study.WeightManagementMMAData r + WHERE r.Id = t.Id + AND r.code = 'P-YY960' + AND r.date > b.date)) ) - AND d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql index 0b5b167d5..3149f137e 100644 --- a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql @@ -31,9 +31,13 @@ SELECT null END AS AbsPctChange, w.qcstate - FROM study.weight w WHERE w.qcstate.publicdata = true + AND d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations + AND NOT ( --exclude females under 5yrs, males under 7yrs + (d.gender.code = 'f' AND d.Id.age.ageInYears < 5) + OR (d.gender.code = 'm' AND d.Id.age.ageInYears < 7) + ) AND w.Id NOT IN (SELECT DISTINCT t.Id FROM study.WeightManagementMMAData t @@ -55,5 +59,3 @@ WHERE w.qcstate.publicdata = true AND r.date > b.date) ) ) - -- Exclude animals from these locations - AND w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital') \ No newline at end of file From d49504c6bba2ee524c62d2b2e6f626583ab60bbb Mon Sep 17 00:00:00 2001 From: kollil Date: Sat, 10 Jan 2026 21:11:10 -0800 Subject: [PATCH 5/8] Updated queries with more filters --- .../queries/study/Demographics_NotInMMA.sql | 59 ++++++++-------- .../study/weightRelChange_NotInMMA.query.xml | 68 ------------------- .../study/weightRelChange_NotInMMA.sql | 61 ----------------- .../WeightAlertsNotification.java | 8 ++- 4 files changed, 37 insertions(+), 159 deletions(-) delete mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml delete mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql diff --git a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql index 3e6191741..f197e4ee1 100644 --- a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql +++ b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.sql @@ -8,15 +8,16 @@ Release from active weight management regimen (P-YY960) 2. Remove Shelters, Corral and Hospital locations from the lists */ -Select - d.Id.curlocation.area as Area, - d.Id.curlocation.room as Room, - d.Id.curlocation.cage as Cage, + +SELECT + d.Id.curlocation.area AS Area, + d.Id.curlocation.room AS Room, + d.Id.curlocation.cage AS Cage, d.Id, - d.Id.utilization.use as ProjectsAndGroups, + d.Id.utilization.use AS ProjectsAndGroups, d.species, d.geographic_origin, - d.gender as Sex, + d.gender AS Sex, d.calculated_status, d.birth, d.Id.Age.YearAndDays, @@ -24,28 +25,30 @@ Select d.Id.MostRecentWeight.MostRecentWeightDate, d.Id.viral_status.viralStatus, d.history -From Demographics d -WHERE d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital') -- Exclude animals from these locations - AND NOT ( -- Exclude females under 5yrs, males under 7yrs - (d.gender.code = 'f' AND d.Id.age.ageInYears < 5) - OR (d.gender.code = 'm' AND d.Id.age.ageInYears < 7) +FROM Demographics d +WHERE d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations + AND NOT (-- Exclude females under 5yrs, males under 7yrs + (d.gender.code = 'f' AND d.Id.age.ageInYears < 5) + OR (d.gender.code = 'm' AND d.Id.age.ageInYears < 7) ) - AND d.Id Not In ( - SELECT DISTINCT t.Id - FROM study.WeightManagementMMAData t - WHERE NOT EXISTS ( - -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + AND NOT EXISTS ( + -- -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + SELECT 1 + FROM study.WeightManagementMMAData b + WHERE b.Id = d.Id + AND b.code = 'P-YY961' + AND b.date = ( + SELECT MAX(b2.date) + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = d.Id + AND b2.code = 'P-YY961' + ) + AND NOT EXISTS ( SELECT 1 - FROM study.WeightManagementMMAData b - WHERE b.Id = t.Id - AND b.code = 'P-YY961' - AND b.date = (SELECT MAX(b2.date) - FROM study.WeightManagementMMAData b2 - WHERE b2.Id = t.Id - AND b2.code = 'P-YY961') - AND NOT EXISTS (SELECT 1 - FROM study.WeightManagementMMAData r - WHERE r.Id = t.Id - AND r.code = 'P-YY960' - AND r.date > b.date)) + FROM study.WeightManagementMMAData r + WHERE r.Id = d.Id + AND r.code = 'P-YY960' + AND r.date > b.date + ) ) + diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml deleted file mode 100644 index 4270989c0..000000000 --- a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - Animals(Not in Weight Management Regimen) with Weight Change, Relative to Current Weight - This query shows the percent change of each weight, relative to the current weight - - - true - true - - - true - - study - animal - id - - - - true - Date of Last Weight - - - Old Weight (kg) - - - % Change Relative To Current - - - - - - true - FF0000 - - - - - - true - 458B00 - - - - - Days Since Weight - - - Months Since Weight - - - Latest Weight (kg) - /query/executeQuery.view?schemaName=study& - query.queryName=weight& - query.date~eq=${LatestWeightDate}& - query.sort=-date - - - - Latest Weight Date - - - PctChange -
-
-
-
diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql deleted file mode 100644 index 3149f137e..000000000 --- a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql +++ /dev/null @@ -1,61 +0,0 @@ -/* - Created by Kollil in Dec 2025 - Tkt # 13461 - This query is the ONPRC version of the core LK EHR query called, weightRelChange. In addition to the original one, this new query has two filters: - 1. Filter out any animal with the following SNOMED Codes: - Begin active weight management regimen (P-YY961) - However, we would need to include animals that have this additional SNOMED Code if it's entered AFTER the one above - Release from active weight management regimen (P-YY960) - 2. Remove Shelters, Corral and Hospital locations from the lists - */ -SELECT - w.lsid, - w.Id, - w.date, - w.Id.MostRecentWeight.MostRecentWeightDate as LatestWeightDate, - w.Id.MostRecentWeight.MostRecentWeight AS LatestWeight, - - timestampdiff('SQL_TSI_DAY', w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInDays, - age_in_months(w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInMonths, - - w.weight, - CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN - Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1) - ELSE - null - END AS PctChange, - - CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN - Abs(Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1)) - else - null - END AS AbsPctChange, - w.qcstate -FROM study.weight w -WHERE w.qcstate.publicdata = true - AND d.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations - AND NOT ( --exclude females under 5yrs, males under 7yrs - (d.gender.code = 'f' AND d.Id.age.ageInYears < 5) - OR (d.gender.code = 'm' AND d.Id.age.ageInYears < 7) - ) - AND w.Id NOT IN - (SELECT DISTINCT t.Id - FROM study.WeightManagementMMAData t - WHERE NOT EXISTS - ( - -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' - SELECT 1 - FROM study.WeightManagementMMAData b - WHERE b.Id = t.Id - AND b.code = 'P-YY961' - AND b.date = (SELECT MAX(b2.date) - FROM study.WeightManagementMMAData b2 - WHERE b2.Id = t.Id - AND b2.code = 'P-YY961') - AND NOT EXISTS (SELECT 1 - FROM study.WeightManagementMMAData r - WHERE r.Id = t.Id - AND r.code = 'P-YY960' - AND r.date > b.date) - ) - ) diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java index c2e65237a..24c9d6b6c 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java @@ -51,6 +51,10 @@ * User: bbimber * Date: 7/23/12 * Time: 7:41 PM + * + * Modified by Kollil as per ticket # 13461 + * Date: Jan 2026 + * */ public class WeightAlertsNotification extends AbstractEHRNotification { @@ -144,8 +148,8 @@ private void generateCombinedWeightTable(final Container c, User u, final String private void processWeights(Container c, User u, final StringBuilder msg, int min, int max, CompareType ct, double pct, @Nullable Set distinctIds) { //Daily transfers query - TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("weightRelChange_NotInMMA", ContainerFilter.Type.AllFolders.create(c, u)); -// TableInfo ti = getStudySchema(c, u).getTable("weightRelChange_NotInMMA"); +// TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("weightRelChange_NotInMMA", ContainerFilter.Type.AllFolders.create(c, u)); + TableInfo ti = getStudySchema(c, u).getTable("weightRelChange"); assert ti != null; final FieldKey areaKey = FieldKey.fromString("Id/curLocation/Area"); From 3fae10a008712ce3a16dc0d06974e6ea2d6d80ec Mon Sep 17 00:00:00 2001 From: kollil Date: Thu, 15 Jan 2026 12:56:28 -0800 Subject: [PATCH 6/8] Updated queries --- .../study/Demographics_NotInMMA.query.xml | 2 +- .../weightConsecutiveDrops_NotInMMA.query.xml | 50 +++++ .../study/weightConsecutiveDrops_NotInMMA.sql | 81 +++++++ .../study/weightRelChange_NotInMMA.query.xml | 68 ++++++ .../study/weightRelChange_NotInMMA.sql | 63 ++++++ .../WeightAlertsNotification.java | 208 +++++++++--------- 6 files changed, 366 insertions(+), 106 deletions(-) create mode 100644 onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.query.xml create mode 100644 onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.sql create mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml create mode 100644 onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql diff --git a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml index d949afe42..48f834dca 100644 --- a/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml +++ b/onprc_ehr/resources/queries/study/Demographics_NotInMMA.query.xml @@ -2,7 +2,7 @@ - Animals not in weight management regimen + Demographics (Excluding animals in Weight MMA regimen)
diff --git a/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.query.xml new file mode 100644 index 000000000..c781c7ded --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.query.xml @@ -0,0 +1,50 @@ + + + + + Weight Change, Relative to Previous Weight (Excluding the animals enrolled in MMA) + This query shows the percent change of each weight, relative to the weight immediately prior to it + + + true + true + + + /query/executeQuery.view?schemaName=study& + query.queryName=weight& + query.id~eq=${id}& + query.sort=-date + + + + /query/executeQuery.view?schemaName=study& + query.queryName=weight& + query.date~eq=${PrevDate}& + query.sort=-date + + + + /query/executeQuery.view?schemaName=study& + query.queryName=weight& + query.lsid~eq=${lsid}& + + Percent Change + + + Interval (Days) + + + Current Weight (kg) + + + Weight Date + + + + + + PctChange +
+
+
+
diff --git a/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.sql new file mode 100644 index 000000000..13fbd4571 --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightConsecutiveDrops_NotInMMA.sql @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +--this query contains a handful of calculated fields for the weights table +--it is designed to be joined into weights using lsid + +SELECT + w.lsid, + w.Id, + w.date, + w.weight AS curWeight, + pd1.PrevDate as prevDate1, + pw1.weight AS prevWeight1, + Round(((w.weight - pw1.weight) * 100 / w.weight), 1) AS pctChange1, + timestampdiff('SQL_TSI_DAY', pw1.date, w.date) AS interval1, + pd2.PrevDate as PrevDate2, + pw2.weight AS PrevWeight2, + Round(((pw1.weight - pw2.weight) * 100 / pw1.weight), 1) AS PctChange2, + timestampdiff('SQL_TSI_DAY', pw2.date, pw1.date) AS Interval2 +FROM study.weight w + --Find the next most recent weight date before this one + JOIN + (SELECT T2.Id, T2.date, max(T1.date) as PrevDate + FROM study.weight T1 + JOIN study.weight T2 ON (T1.Id = T2.Id AND T1.date < T2.date) + WHERE t1.qcstate.publicdata = true AND t2.qcstate.publicdata = true + GROUP BY T2.Id, T2.date) pd1 + ON (w.Id = pd1.Id AND w.date = pd1.Date) + + --and the weight associated with that date + JOIN study.weight pw1 + ON (w.Id = pw1.Id AND pw1.date = pd1.prevdate AND pw1.qcstate.publicdata = true) + + --then find the next most recent date + LEFT JOIN + (SELECT T2.Id, T2.date, max(T1.date) as PrevDate + FROM study.weight T1 + JOIN study.weight T2 ON (T1.Id = T2.Id AND T1.date < T2.date) + WHERE t1.qcstate.publicdata = true AND t2.qcstate.publicdata = true + GROUP BY T2.Id, T2.date + ) pd2 + ON (pd1.Id = pd2.Id AND pd1.PrevDate = pd2.date) + + --and the weight associated with that date + JOIN study.weight pw2 + ON (w.Id = pw2.Id AND pw2.date = pd2.prevdate AND pw2.qcstate.publicdata = true) +WHERE + w.qcstate.publicdata = true + AND pd1.date is not null + AND pd2.date is not null + --only include drops + AND w.weight < pw1.weight + AND pw1.weight < pw2.weight + AND ((w.weight - pw2.weight) * 100 / w.weight) < -3.0 + + AND w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations + AND NOT (-- Exclude females under 5yrs, males under 7yrs + (w.Id.demographics.gender.code = 'f' AND w.Id.age.ageInYears < 5) + OR (w.Id.demographics.gender.code = 'm' AND w.Id.age.ageInYears < 7) + ) + AND w.Id NOT IN ( + SELECT 1 -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + FROM study.WeightManagementMMAData b + WHERE b.Id = w.Id + AND b.code = 'P-YY961' + AND b.date = ( + SELECT MAX(b2.date) + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = w.Id + AND b2.code = 'P-YY961' + ) + AND NOT EXISTS ( + SELECT 1 + FROM study.WeightManagementMMAData r + WHERE r.Id = w.Id + AND r.code = 'P-YY960' + AND r.date > b.date + ) + ) diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml new file mode 100644 index 000000000..5b6170eca --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.query.xml @@ -0,0 +1,68 @@ + + + + + Weight Change, Relative to Current Weight (Excluding the animals enrolled in MMA) + This query shows the percent change of each weight, relative to the current weight + + + true + true + + + true + + study + animal + id + + + + true + Date of Last Weight + + + Old Weight (kg) + + + % Change Relative To Current + + + + + + true + FF0000 + + + + + + true + 458B00 + + + + + Days Since Weight + + + Months Since Weight + + + Latest Weight (kg) + /query/executeQuery.view?schemaName=study& + query.queryName=weight& + query.date~eq=${LatestWeightDate}& + query.sort=-date + + + + Latest Weight Date + + + PctChange +
+
+
+
diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql new file mode 100644 index 000000000..341654635 --- /dev/null +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql @@ -0,0 +1,63 @@ +/* + Created by Kollil in Dec 2025 + Tkt # 13461 + Added two filters to the Demographics dataset: + 1. Filter out any animal with the following SNOMED Codes: + Begin active weight management regimen (P-YY961) + However, we would need to include animals that have this additional SNOMED Code if it's entered AFTER the one above + Release from active weight management regimen (P-YY960) + 2. Remove Shelters, Corral and Hospital locations from the lists + */ + +SELECT + w.lsid, + w.Id, + w.date, + w.Id.MostRecentWeight.MostRecentWeightDate as LatestWeightDate, + w.Id.MostRecentWeight.MostRecentWeight AS LatestWeight, + + timestampdiff('SQL_TSI_DAY', w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInDays, + age_in_months(w.date, w.Id.MostRecentWeight.MostRecentWeightDate) AS IntervalInMonths, + + w.weight, + CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN + Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1) + ELSE + null + END AS PctChange, + + CASE WHEN w.date >= timestampadd('SQL_TSI_DAY', -730, w.Id.MostRecentWeight.MostRecentWeightDate) THEN + Abs(Round(((w.Id.MostRecentWeight.MostRecentWeight - w.weight) * 100 / w.weight), 1)) + else + null + END AS AbsPctChange, + w.qcstate +FROM study.weight w +WHERE w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude animals from these locations + AND NOT (-- Exclude females under 5yrs, males under 7yrs + (w.Id.demographics.gender.code = 'f' AND w.Id.age.ageInYears < 5) + OR (w.Id.demographics.gender.code = 'm' AND w.Id.age.ageInYears < 7) + ) + AND w.qcstate.publicdata = true + AND w.Id = '26520' + AND NOT EXISTS ( + -- -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' + SELECT 1 + FROM study.WeightManagementMMAData b + WHERE b.Id = w.Id + AND b.code = 'P-YY961' + AND b.date = ( + SELECT MAX(b2.date) + FROM study.WeightManagementMMAData b2 + WHERE b2.Id = w.Id + AND b2.code = 'P-YY961' + ) + AND NOT EXISTS ( + SELECT 1 + FROM study.WeightManagementMMAData r + WHERE r.Id = w.Id + AND r.code = 'P-YY960' + AND r.date > b.date + ) + ) + diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java index 24c9d6b6c..b16ec0b25 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/WeightAlertsNotification.java @@ -124,7 +124,7 @@ private void generateCombinedWeightTable(final Container c, User u, final String Changed by Kollil: 1/2026 Disabling this section as per ticket #13461 */ - //consecutiveWeightDrops(c, u, sb, dropDistinctIds); +// consecutiveWeightDrops(c, u, sb, dropDistinctIds); if (!dropDistinctIds.isEmpty()) { @@ -147,9 +147,8 @@ private void generateCombinedWeightTable(final Container c, User u, final String private void processWeights(Container c, User u, final StringBuilder msg, int min, int max, CompareType ct, double pct, @Nullable Set distinctIds) { - //Daily transfers query -// TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("weightRelChange_NotInMMA", ContainerFilter.Type.AllFolders.create(c, u)); - TableInfo ti = getStudySchema(c, u).getTable("weightRelChange"); + TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("weightRelChange_NotInMMA", ContainerFilter.Type.AllFolders.create(c, u)); +// TableInfo ti = getStudySchema(c, u).getTable("weightRelChange"); assert ti != null; final FieldKey areaKey = FieldKey.fromString("Id/curLocation/Area"); @@ -158,7 +157,6 @@ private void processWeights(Container c, User u, final StringBuilder msg, int mi final FieldKey ageKey = FieldKey.fromString("Id/age/AgeFriendly"); final FieldKey problemKey = FieldKey.fromString("Id/openProblems/problems"); final FieldKey investKey = FieldKey.fromString("Id/activeAssignments/investigators"); - //final FieldKey vetsKey = FieldKey.fromString("Id/activeAssignments/vets"); final FieldKey vetsKey = FieldKey.fromString("Id/assignedVet/AssignedVet"); final FieldKey peKey = FieldKey.fromString("Id/physicalExamHistory/daysSinceExam"); @@ -283,113 +281,113 @@ public void exec(ResultSet object) throws SQLException msg.append("

\n"); msg.append("


"); } - else - { + else { msg.append("There are no changes during this period.
"); } + if (distinctIds != null && !distinctAnimals.isEmpty()) distinctIds.addAll(distinctAnimals); } -// protected void consecutiveWeightDrops(final Container c, User u, final StringBuilder msg, @Nullable Set distinctIds) -// { -// SimpleFilter filter = new SimpleFilter(FieldKey.fromString("Id/dataset/demographics/calculated_status"), "Alive"); -// Calendar date = Calendar.getInstance(); -// date.add(Calendar.DATE, -10); -// -// filter.addCondition(FieldKey.fromString("date"), date.getTime(), CompareType.DATE_GTE); -// Sort sort = new Sort(); -// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/area"), Sort.SortDirection.ASC)); -// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/room"), Sort.SortDirection.ASC)); -// sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/cage"), Sort.SortDirection.ASC)); -// -// TableInfo ti = getStudySchema(c, u).getTable("weightConsecutiveDrops"); -// assert ti != null; -// -// List colKeys = new ArrayList<>(); -// colKeys.add(FieldKey.fromString("Id/curLocation/area")); -// colKeys.add(FieldKey.fromString("Id/curLocation/room")); -// colKeys.add(FieldKey.fromString("Id/curLocation/cage")); -// colKeys.add(FieldKey.fromString("Id/activeAssignments/investigators")); -// colKeys.add(FieldKey.fromString("Id/activeAssignments/vets")); -// colKeys.add(FieldKey.fromString("Id/physicalExamHistory/daysSinceExam")); -// colKeys.add(FieldKey.fromString("Id/openProblems/problems")); -// -// final Map columns = QueryService.get().getColumns(ti, colKeys); -// for (ColumnInfo col : ti.getColumns()) -// { -// columns.put(col.getFieldKey(), col); -// } -// -// TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); -// if (ts.exists()) -// { -// final Set animalIds = new HashSet<>(); -// -// msg.append("WARNING: The following animals have a weight entered since " + getDateFormat(c).format(date.getTime()) + " representing 3 consecutive weight drops with a total drop of more than 3%:

\n"); -// -// final StringBuilder tableMsg = new StringBuilder(); -// tableMsg.append(""); -// ts.forEach(new TableSelector.ForEachBlock<>() -// { -// @Override -// public void exec(ResultSet rs) throws SQLException -// { -// Results results = new ResultsImpl(rs, columns); -// -// tableMsg.append(""); -// tableMsg.append(""); -// tableMsg.append(""); -// String subj = getValue(results, getStudy(c).getSubjectColumnName()); -// tableMsg.append(""); -// -// tableMsg.append(""); -// tableMsg.append(""); -// tableMsg.append(""); -// tableMsg.append(""); -// -// tableMsg.append(""); -// -// tableMsg.append(""); -// -// tableMsg.append(""); -// -// tableMsg.append(""); -// -// tableMsg.append(""); -// -// String id = getValue(results, getStudy(c).getSubjectColumnName()); -// if (id != null) -// animalIds.add(id); -// } -// }); -// -// tableMsg.append("
RoomCageIdInvestigator(s)Responsible VetOpen ProblemsDays Since Last PEWeight DateInterval (days)Weight (kg)% Change
").append(getValue(results, "Id/curLocation/room")).append("").append(getValue(results, "Id/curLocation/cage")).append(""); -// tableMsg.append(subj).append("").append(getValue(results, "Id/activeAssignments/investigators")).append("").append(getValue(results, "Id/activeAssignments/vets")).append("").append(getValue(results, "Id/openProblems/problems")).append("").append(getValue(results, "Id/physicalExamHistory/daysSinceExam")).append("").append(getDateValue(c, results, "date")).append("
"); -// tableMsg.append(getDateValue(c, results, "prevDate1")).append("
"); -// tableMsg.append(getDateValue(c, results, "prevDate2")); -// tableMsg.append("
"); -// tableMsg.append(getNumericValue(results, "interval1")).append("
"); -// tableMsg.append(getNumericValue(results, "interval2")).append("
"); -// tableMsg.append("
"); -// tableMsg.append("
").append(getValue(results, "curWeight")).append("
"); -// tableMsg.append(getValue(results, "prevWeight1")).append("
"); -// tableMsg.append(getValue(results, "prevWeight2")); -// tableMsg.append("
").append(getNumericValue(results, "pctChange1")).append("
"); -// tableMsg.append(getNumericValue(results, "pctChange2")).append("
"); -// tableMsg.append("
"); -// tableMsg.append("
\n"); -// -// msg.append("

Click here to view these " + animalIds.size() + " animals

\n"); -// msg.append(tableMsg); -// msg.append("
\n"); -// -// if (distinctIds != null && !animalIds.isEmpty()) -// distinctIds.addAll(animalIds); -// } -// } + protected void consecutiveWeightDrops(final Container c, User u, final StringBuilder msg, @Nullable Set distinctIds) + { + SimpleFilter filter = new SimpleFilter(FieldKey.fromString("Id/dataset/demographics/calculated_status"), "Alive"); + Calendar date = Calendar.getInstance(); + date.add(Calendar.DATE, -10); + + filter.addCondition(FieldKey.fromString("date"), date.getTime(), CompareType.DATE_GTE); + Sort sort = new Sort(); + sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/area"), Sort.SortDirection.ASC)); + sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/room"), Sort.SortDirection.ASC)); + sort.appendSortColumn(new Sort.SortField(FieldKey.fromString("Id/curLocation/cage"), Sort.SortDirection.ASC)); + + TableInfo ti = getStudySchema(c, u).getTable("weightConsecutiveDrops_NotInMMA"); + assert ti != null; + + List colKeys = new ArrayList<>(); + colKeys.add(FieldKey.fromString("Id/curLocation/area")); + colKeys.add(FieldKey.fromString("Id/curLocation/room")); + colKeys.add(FieldKey.fromString("Id/curLocation/cage")); + colKeys.add(FieldKey.fromString("Id/activeAssignments/investigators")); + colKeys.add(FieldKey.fromString("Id/activeAssignments/vets")); + colKeys.add(FieldKey.fromString("Id/physicalExamHistory/daysSinceExam")); + colKeys.add(FieldKey.fromString("Id/openProblems/problems")); + + final Map columns = QueryService.get().getColumns(ti, colKeys); + for (ColumnInfo col : ti.getColumns()) + { + columns.put(col.getFieldKey(), col); + } + + TableSelector ts = new TableSelector(ti, columns.values(), filter, sort); + if (ts.exists()) + { + final Set animalIds = new HashSet<>(); + + msg.append("WARNING: The following animals have a weight entered since " + getDateFormat(c).format(date.getTime()) + " representing 3 consecutive weight drops with a total drop of more than 3%:

\n"); + + final StringBuilder tableMsg = new StringBuilder(); + tableMsg.append(""); + ts.forEach(new TableSelector.ForEachBlock<>() + { + @Override + public void exec(ResultSet rs) throws SQLException + { + Results results = new ResultsImpl(rs, columns); + + tableMsg.append(""); + tableMsg.append(""); + tableMsg.append(""); + String subj = getValue(results, getStudy(c).getSubjectColumnName()); + tableMsg.append(""); + + tableMsg.append(""); + tableMsg.append(""); + tableMsg.append(""); + tableMsg.append(""); + + tableMsg.append(""); + + tableMsg.append(""); + + tableMsg.append(""); + + tableMsg.append(""); + + tableMsg.append(""); + + String id = getValue(results, getStudy(c).getSubjectColumnName()); + if (id != null) + animalIds.add(id); + } + }); + + tableMsg.append("
RoomCageIdInvestigator(s)Responsible VetOpen ProblemsDays Since Last PEWeight DateInterval (days)Weight (kg)% Change
").append(getValue(results, "Id/curLocation/room")).append("").append(getValue(results, "Id/curLocation/cage")).append(""); + tableMsg.append(subj).append("").append(getValue(results, "Id/activeAssignments/investigators")).append("").append(getValue(results, "Id/activeAssignments/vets")).append("").append(getValue(results, "Id/openProblems/problems")).append("").append(getValue(results, "Id/physicalExamHistory/daysSinceExam")).append("").append(getDateValue(c, results, "date")).append("
"); + tableMsg.append(getDateValue(c, results, "prevDate1")).append("
"); + tableMsg.append(getDateValue(c, results, "prevDate2")); + tableMsg.append("
"); + tableMsg.append(getNumericValue(results, "interval1")).append("
"); + tableMsg.append(getNumericValue(results, "interval2")).append("
"); + tableMsg.append("
"); + tableMsg.append("
").append(getValue(results, "curWeight")).append("
"); + tableMsg.append(getValue(results, "prevWeight1")).append("
"); + tableMsg.append(getValue(results, "prevWeight2")); + tableMsg.append("
").append(getNumericValue(results, "pctChange1")).append("
"); + tableMsg.append(getNumericValue(results, "pctChange2")).append("
"); + tableMsg.append("
"); + tableMsg.append("
\n"); + + msg.append("

Click here to view these " + animalIds.size() + " animals

\n"); + msg.append(tableMsg); + msg.append("
\n"); + + if (distinctIds != null && !animalIds.isEmpty()) + distinctIds.addAll(animalIds); + } + } // private void getLivingWithoutWeight(final Container c, User u, final StringBuilder msg) // { From c64648c4cf11c5b1868217d38d1532e2dad6108b Mon Sep 17 00:00:00 2001 From: kollil Date: Thu, 15 Jan 2026 13:59:38 -0800 Subject: [PATCH 7/8] Updated query: Removed the animalid from the where clause --- onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql index 341654635..5b9cdd8ed 100644 --- a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql @@ -39,7 +39,7 @@ WHERE w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude OR (w.Id.demographics.gender.code = 'm' AND w.Id.age.ageInYears < 7) ) AND w.qcstate.publicdata = true - AND w.Id = '26520' +-- AND w.Id = '26520' AND NOT EXISTS ( -- -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' SELECT 1 From ed95c68c67cbc4dea1dcb6d98a71b4f728896f8a Mon Sep 17 00:00:00 2001 From: kollil Date: Thu, 15 Jan 2026 14:01:07 -0800 Subject: [PATCH 8/8] Updated query: Removed the animalid from the where clause --- onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql index 5b9cdd8ed..884348e4c 100644 --- a/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql +++ b/onprc_ehr/resources/queries/study/weightRelChange_NotInMMA.sql @@ -39,7 +39,6 @@ WHERE w.Id.curlocation.area NOT IN ('Shelters', 'Corral', 'Hospital')-- Exclude OR (w.Id.demographics.gender.code = 'm' AND w.Id.age.ageInYears < 7) ) AND w.qcstate.publicdata = true --- AND w.Id = '26520' AND NOT EXISTS ( -- -- Find animals whose latest 'Weight MMA BEGIN' has no later 'Weight MMA RELEASE' SELECT 1