From b226861219db86ae1ae77b97e011620fef357273 Mon Sep 17 00:00:00 2001 From: aschmidt34 Date: Thu, 18 Jul 2024 13:59:02 -0500 Subject: [PATCH 1/4] Added updates requested by the blood draw team. - Blood Draws Today (All): Now sorts draws by incomplete first. Also changed unassigned/incomplete column headers for clarity. - Blood Draw Review Notification (Trigger): Updated this so it only sends when a blood draw is requested for the current day with an issue. - Blood Draw Review Notification (Daily): Now shows any blood draws (today & future) that will be overdrawn. --- .../BloodDrawReviewDailyNotification.java | 49 ++++++++++++++++++- .../BloodDrawReviewTriggerNotification.java | 39 ++++++++++++--- .../notification/BloodDrawsTodayAll.java | 32 ++++++++---- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java index 017e6227f..1fa6a659c 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java @@ -90,7 +90,7 @@ public String getMessageBodyHTML(Container c, User u) { // } } else { - messageBody.append("There are no blood draws (today or future) where animal is not alive."); + messageBody.append("There are no blood draws (today or future) where animal is not alive.
\n"); } // Lists all blood draws (today & future) where animal is not assigned to a project. if (!myBloodDrawReviewObject.unassignedBloodDraws.isEmpty()) { @@ -110,7 +110,20 @@ public String getMessageBodyHTML(Container c, User u) { // } } else { - messageBody.append("There are no blood draws (today or future) where animal is not assigned to a project."); + messageBody.append("There are no blood draws (today or future) where animal is not assigned to a project.
\n"); + } + // Lists all blood draws (today & future) where animal has blood overdrawn. + if (!myBloodDrawReviewObject.bloodOverdraws.isEmpty()) { + messageBody.append("

There are " + myBloodDrawReviewObject.bloodOverdraws.size() + " blood draws (today & future) where animal's blood will be overdrawn:

"); + + // Creates table. + String[] myTableColumns = new String[]{"Id", "Date of Blood Draw", "Available Blood"}; + NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, myBloodDrawReviewObject.bloodOverdraws); + messageBody.append(myTable.createBasicHTMLTable()); + messageBody.append(notificationToolkit.createHyperlink("

Click here to view them
\n", myBloodDrawReviewObject.bloodOverdrawsURLView)); + } + else { + messageBody.append("There are no blood draws (today or future) where the animal's blood will be overdrawn.
\n"); } return messageBody.toString(); @@ -128,6 +141,7 @@ public static class BloodDrawReviewDailyObject { this.u = currentUser; getNonAliveBloodDraws(); getUnassignedBloodDraws(); + getBloodOverdraws(); } ArrayList nonAliveBloodDraws = new ArrayList<>(); @@ -186,5 +200,36 @@ void getUnassignedBloodDraws() { this.unassignedBloodDrawsURLView = viewQueryURL; } + ArrayList bloodOverdraws = new ArrayList<>(); + String bloodOverdrawsURLView; + // Gets all blood draws (today & future) where animal has their blood overdrawn. + void getBloodOverdraws() { + // Creates filter. + Date todayDate = dateToolkit.getDateToday(); +// SimpleFilter myFilter = new SimpleFilter("date", todayDate, CompareType.DATE_GTE); // TODO: Uncomment this when testing is finished. + SimpleFilter myFilter = new SimpleFilter("date", dateToolkit.getDateXDaysFromNow(-40000), CompareType.DATE_GTE); // TODO: Delete this when testing is finished. + + // Creates sort. + Sort mySort = new Sort("date"); + // Creates columns to retrieve. + String[] targetColumns = new String[]{"id", "date", "BloodRemaining/AvailBlood"}; + // Runs query. + ArrayList> unformattedUpcomingBloodDraws = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "BloodSchedule", myFilter, mySort, targetColumns); + + // Converts map to list (for displaying in table). + for (HashMap currentDraw : unformattedUpcomingBloodDraws) { + // Verifies there is data because some older blood draws don't list available blood. + if (!currentDraw.get("BloodRemaining/AvailBlood").isEmpty()) { + if (Double.valueOf(currentDraw.get("BloodRemaining/AvailBlood")) <= 0) { + String[] currentRow = {currentDraw.get("id"), currentDraw.get("date"), currentDraw.get("BloodRemaining/AvailBlood")}; + bloodOverdraws.add(currentRow); + } + } + } + + // Creates URL. + String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "BloodSchedule", myFilter); + this.bloodOverdrawsURLView = viewQueryURL; + } } } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java index 94d467965..7d3abad54 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java @@ -1,5 +1,6 @@ package org.labkey.wnprc_ehr.notification; +import net.sf.cglib.core.Local; import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.SimpleFilter; @@ -8,19 +9,25 @@ import org.labkey.api.security.User; import java.lang.reflect.Array; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.Locale; + +import static org.labkey.api.search.SearchService._log; public class BloodDrawReviewTriggerNotification extends AbstractEHRNotification { //Class Variables NotificationToolkit notificationToolkit = new NotificationToolkit(); NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit(); NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit(); -// String requestIdToCheck; + // String requestIdToCheck; String animalIdToCheck; String projectToCheck; String drawDateToCheck; @@ -87,16 +94,17 @@ public String getMessageBodyHTML(Container c, User u) { // Set up. StringBuilder messageBody = new StringBuilder(); Boolean emptyMessage = true; + Boolean isTesting = false; if (this.animalIdToCheck == null || this.projectToCheck == null || this.drawDateToCheck == null) { // This sets up the values for testing through Notification Manager > Run Report in Browser. + isTesting = true; this.animalIdToCheck = "rh2514"; this.projectToCheck = "20140704"; - this.drawDateToCheck = "2022-01-01 01:01:01.0"; -// this.requestor = null; + this.drawDateToCheck = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString(); } // Begins message info. - messageBody.append("

This email contains warning information for a recently submitted blood draw request. It was run on: " + dateToolkit.getCurrentTime() + "

"); + messageBody.append("

This email contains warning information for a recently submitted blood draw request with a requested draw date of today. It was sent on: " + dateToolkit.getCurrentTime() + "

"); messageBody.append("

Animal ID: " + this.animalIdToCheck + "

"); messageBody.append("

Project: " + this.projectToCheck + "

"); @@ -106,14 +114,31 @@ public String getMessageBodyHTML(Container c, User u) { messageBody.append("

WARNING: This animal is no longer alive.

"); } - //Verifies animal is assigned to a project. - if (!notificationToolkit.checkProjectAssignmentStatusOnDate(c, u,animalIdToCheck, Integer.valueOf(projectToCheck), drawDateToCheck)) { + // Verifies animal is assigned to a project. + if (!notificationToolkit.checkProjectAssignmentStatusOnDate(c, u,animalIdToCheck, Integer.valueOf(projectToCheck), drawDateToCheck) || isTesting) { emptyMessage = false; messageBody.append("

WARNING: This animal is not assigned to a project on the date of the requested blood draw.

"); } + // Verifies there is a warning before sending. if (emptyMessage.equals(false)) { - return messageBody.toString(); + try { + // Verifies this blood draw is for today before sending. + DateFormat format = new SimpleDateFormat("yyyy-M-d", Locale.ENGLISH); + Date formattedDrawDate = format.parse(drawDateToCheck); + LocalDate drawDateWithoutTime = formattedDrawDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate todaysDateWithoutTime = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + if (drawDateWithoutTime.equals(todaysDateWithoutTime)) { + return messageBody.toString(); + } + else { + return null; + } + } + catch(Exception e) { + _log.error("Error executing BloodDrawReviewTriggerNotification->getMessageBodyHTML(). Could not format date of blood draw into Date().", e); + return null; + } } else { return null; diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index 2bf367e59..e0f62e965 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -105,7 +105,7 @@ public static class BloodDrawsTodayObject { NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit(); ArrayList myTableData = new ArrayList<>(); // List of all blood draws as [[id, blood remaining, project assignment, completion status, assigned to]] -// ArrayList myTableRowColors = new ArrayList<>(); // List of all row colors (same length as myTableData). + // ArrayList myTableRowColors = new ArrayList<>(); // List of all row colors (same length as myTableData). HashMap>> resultsByArea = new HashMap<>(); // Area(Room(List of draws)) @@ -118,7 +118,8 @@ public static class BloodDrawsTodayObject { // Creates filter. Date todayDate = dateToolkit.getDateToday(); SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL); - myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); +// myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); //TODO: Uncomment this after testing. + myFilter.addCondition("date", dateToolkit.getDateXDaysFromNow(-800), CompareType.DATE_GTE); //TODO: Delete this after testing. // Creates sort. Sort mySort = new Sort("date"); @@ -204,19 +205,32 @@ else if (availBlood <= bloodThreshold) { // Adds the current row to myTableData (based on group being queried). if (assignmentGroup.equals("animalCare")) { if (result.get("billedby/title").equals("Animal Care")) { - myTableData.add(myCurrentRow); -// myTableRowColors.add(currentRowColor); + if (myCurrentRow[3].equals("INCOMPLETE")) { + myTableData.add(0, myCurrentRow); + } + else { + myTableData.add(myCurrentRow); + } } } else if (assignmentGroup.equals("vetStaff")) { if (result.get("billedby/title").equals("Vet Staff")) { - myTableData.add(myCurrentRow); -// myTableRowColors.add(currentRowColor); + if (myCurrentRow[3].equals("INCOMPLETE")) { + myTableData.add(0, myCurrentRow); + } + else { + myTableData.add(myCurrentRow); + } } } else { - myTableData.add(myCurrentRow); -// myTableRowColors.add(currentRowColor); + // Adds to the beginning of the list if blood draw is incomplete, or the end of the list if the blood draw is completed. + if (myCurrentRow[3].equals("INCOMPLETE")) { + myTableData.add(0, myCurrentRow); + } + else { + myTableData.add(myCurrentRow); + } } } @@ -286,7 +300,7 @@ String printTablesAsHTML() { StringBuilder returnString = new StringBuilder(); // Goes through each room in each area and presents a table showing all blood draws for that room. - String[] myTableColumns = new String[]{"Id", "Blood Remaining", "Project Assignment", "Completion Status", "Group", "Other Groups Drawing Blood Today"}; + String[] myTableColumns = new String[]{"Id", "Blood Remaining", "Unassigned", "Incomplete", "Group", "Other Groups Drawing Blood Today"}; // Iterates through each area (sorted alphabetically). for (String currentArea : notificationToolkit.sortSetWithNulls(this.resultsByArea.keySet())) { returnString.append("AREA: " + currentArea + ":
\n"); From 92a5e2fd6e8a6be9c2515c9930e4f4ca5d5bb909 Mon Sep 17 00:00:00 2001 From: aschmidt34 Date: Thu, 18 Jul 2024 17:29:55 -0500 Subject: [PATCH 2/4] Removed test dates and updated to correct dates. --- .../notification/BloodDrawReviewDailyNotification.java | 3 +-- .../org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java index 1fa6a659c..00f1c001b 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java @@ -206,8 +206,7 @@ void getUnassignedBloodDraws() { void getBloodOverdraws() { // Creates filter. Date todayDate = dateToolkit.getDateToday(); -// SimpleFilter myFilter = new SimpleFilter("date", todayDate, CompareType.DATE_GTE); // TODO: Uncomment this when testing is finished. - SimpleFilter myFilter = new SimpleFilter("date", dateToolkit.getDateXDaysFromNow(-40000), CompareType.DATE_GTE); // TODO: Delete this when testing is finished. + SimpleFilter myFilter = new SimpleFilter("date", todayDate, CompareType.DATE_GTE); // Creates sort. Sort mySort = new Sort("date"); diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index e0f62e965..c91a4f7cd 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -118,8 +118,7 @@ public static class BloodDrawsTodayObject { // Creates filter. Date todayDate = dateToolkit.getDateToday(); SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL); -// myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); //TODO: Uncomment this after testing. - myFilter.addCondition("date", dateToolkit.getDateXDaysFromNow(-800), CompareType.DATE_GTE); //TODO: Delete this after testing. + myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); // Creates sort. Sort mySort = new Sort("date"); From 0e6fe4fee2742c973677820be404ef200f661420 Mon Sep 17 00:00:00 2001 From: aschmidt34 Date: Fri, 19 Jul 2024 16:41:54 -0500 Subject: [PATCH 3/4] Fixed test date updates. --- .../org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java | 1 + 1 file changed, 1 insertion(+) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index c91a4f7cd..7f1f66d03 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -119,6 +119,7 @@ public static class BloodDrawsTodayObject { Date todayDate = dateToolkit.getDateToday(); SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL); myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); + //placeholder // Creates sort. Sort mySort = new Sort("date"); From ee02a0cfabe9ea3870a088580b700eae4353f3d1 Mon Sep 17 00:00:00 2001 From: aschmidt34 Date: Mon, 22 Jul 2024 14:32:57 -0500 Subject: [PATCH 4/4] Removed placeholder text. --- .../org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index 7f1f66d03..c91a4f7cd 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -119,7 +119,6 @@ public static class BloodDrawsTodayObject { Date todayDate = dateToolkit.getDateToday(); SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL); myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL); - //placeholder // Creates sort. Sort mySort = new Sort("date");