From 4ca39499d51a4275c110ddf8fefb7bdf8fdd1a4a Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 11 Jul 2024 17:46:12 -0500
Subject: [PATCH 01/29] - In Blood Draws Today (All, Animal Care, and Vet
Staff), I changed 'Assignment Status' column header to 'Unassigned' and
'Completion Status' to 'Incomplete'. I also sorted all results so Incomplete
draws show up first. - In BloodDrawReviewTriggerNotification, I made it so
warnings only send when the draw has a date of today. - In
BloodDrawReviewDailyNotification, I added a check to verify that there are no
upcoming blood draws that will overdraw.
- TODO: After testing this on test servers, make sure to remove test dates in BloodDrawsTodayAll and BloodDrawReviewDailyNotification.
---
.../BloodDrawReviewDailyNotification.java | 49 ++++++++++++++++++-
.../BloodDrawReviewTriggerNotification.java | 37 +++++++++++---
.../notification/BloodDrawsTodayAll.java | 30 +++++++++---
3 files changed, 100 insertions(+), 16 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..a2608faaf 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,12 +9,18 @@
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
@@ -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..261d1a274 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java
@@ -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 cef7f29e17560854832fd7ca00174e3686c27881 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 18 Jul 2024 11:08:56 -0500
Subject: [PATCH 02/29] Migrated automated test changes from 23.11 to 24.3.
23.11_notificationRevamps is now ready to be deleted.
---
.../notification/NotificationToolkit.java | 4 +-
.../wnprc_ehr/wnprcEhrTestStudyPolicy.xml | 12 +
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 306 +++++++++++++++++-
3 files changed, 319 insertions(+), 3 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index 05b8d6747..d8b287ea8 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -1511,8 +1511,8 @@ public Date getDateToday() {
public Date getDateXDaysFromNow(Integer numDaysFromNow) {
Calendar todayCalendar = Calendar.getInstance();
todayCalendar.add(Calendar.DATE, numDaysFromNow);
- Date fiveDaysAgoDate = todayCalendar.getTime();
- return fiveDaysAgoDate;
+ Date dateToReturn = todayCalendar.getTime();
+ return dateToReturn;
}
//Returns today's date as String (ex: "03/06/2024").
diff --git a/WNPRC_EHR/test/sampledata/wnprc_ehr/wnprcEhrTestStudyPolicy.xml b/WNPRC_EHR/test/sampledata/wnprc_ehr/wnprcEhrTestStudyPolicy.xml
index 4c206edd0..69867afde 100644
--- a/WNPRC_EHR/test/sampledata/wnprc_ehr/wnprcEhrTestStudyPolicy.xml
+++ b/WNPRC_EHR/test/sampledata/wnprc_ehr/wnprcEhrTestStudyPolicy.xml
@@ -214,6 +214,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index b095a3254..a134ac854 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -259,6 +259,8 @@ public static void doSetup() throws Exception
initTest.populateInitialData();
initTest.createEHRLookupsLinkedSchemaQueryValidation();
+// initTest.notificationRevampSetup();
+
initTest.initCreatedProject();
initTest.uploadBillingDataAndVerify();
@@ -275,7 +277,7 @@ public static void doSetup() throws Exception
initTest.checkUpdateProgramIncomeAccount();
- initTest.deathNotificationSetup();
+// initTest.notificationRevampSetup();
}
private void billingSetup() throws Exception
@@ -3771,4 +3773,306 @@ public void testBloodDrawAPI() throws Exception
}
+ // NOTIFICATION REVAMP: NEW FUNCTIONS
+
+ @Test
+ public void notificationRevampTestBloodDrawsTodayAll() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (All)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId1", true, new Date(), true, Double.valueOf(-1), true); // Testing for available blood OVER the limit.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId2", true, new Date(), true, 0.1, true); // Testing for available blood NEAR the limit.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId3", true, new Date(), false, 2.0, true); // Testing for "NOT ASSIGNED" project status.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId4", true, new Date(), true, 2.0, false); // Testing for "INCOMPLETE" draw status.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAll").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId1' has a red colored cell.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId2' has an orange colored cell.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId3' has the text 'NOT ASSIGNED' present in the row.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId4' has the text 'INCOMPLETE' present in the row.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (All)");
+
+// assertTextPresent("Animal ID:", necropsyID);
+// assertTextPresent("Necropsy Case Number:", necropsyCaseNumber);
+// assertTextPresent("Date of Necropsy:", necropsyDate);
+// assertTextPresent("Grant #:", necropsyAccount);
+// log("Completed testJavaDeathNotification.");
+ }
+
+ public void notificationRevampTestBloodDrawsTodayAnimalCare() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (Animal Care)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("animalCare", "bloodDrawsTodayAnimalCareId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Animal Care.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAnimalCare").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayAnimalCareId1' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (Animal Care)");
+ }
+
+ public void notificationRevampTestBloodDrawsTodayVetStaff() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (Vet Staff)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawsTodayVetStaffId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Vet Staff.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayVetStaff").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayVetStaffId1' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (Vet Staff)");
+ }
+
+ public void notificationRevampTestBloodDrawReviewDailyNotification() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draw Review (Daily)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+ // Creates tomorrow's date.
+ Calendar todayCalendar = Calendar.getInstance();
+ todayCalendar.add(Calendar.DATE, 1);
+ Date dateTomorrow = todayCalendar.getTime();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId1", false, new Date(), true, Double.valueOf(2.0), false); // Testing for blood scheduled for today with a dead anima.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId2", true, dateTomorrow, false, Double.valueOf(2.0), false); // Testing for blood scheduled for tomorrow with an animal not assigned to a project.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawReviewDailyNotification").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawReviewDailyId1' exists.
+ // TODO: Assert ID: 'bloodDrawReviewDailyId2' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draw Review (Daily)");
+ }
+
+ public void notificationRevampTestBloodDrawReviewTriggerNotification() throws UnhandledAlertException, IOException, CommandException {
+ // TODO. For this one, check what the id is for the 'run in browser - testing id', then update the DB with this info. Or should I send it and try using dumbster?
+ }
+
+ @Test
+ public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
+ // Set up.
+ log("Starting notificationRevampSetup()");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Navigates to admin notifications page.
+ EHRAdminPage ehrAdminPage = EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
+ // Updates the notification user and reply email.
+ notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
+ // Enables all notification that we will be testing.
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll"); //TODO: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
+ // Adds notification recipients.
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
+ // Enables dumbster.
+ _containerHelper.enableModules(Arrays.asList("Dumbster"));
+ // Enable LDK Site Notification
+ beginAt(buildURL("ldk", "notificationSiteAdmin"));
+ waitForText("Notification Site Admin");
+ click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
+ click(Locator.tagWithText("li", "Enabled"));
+ click(Locator.tagWithText("span", "Save"));
+ waitForText("Success");
+ clickButtonContainingText("OK");
+ waitForText("Notification Site Admin");
+
+ // Creates billing groups for testing.
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("animalCare", "Animal Care");
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("vetStaff", "Vet Staff");
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("spi", "SPI");
+
+ // Logs completion.
+ log("Completed notificationRevampSetup()");
+
+ // Runs tests.
+ notificationRevampTestBloodDrawsTodayAll();
+ notificationRevampTestBloodDrawsTodayAnimalCare();
+ notificationRevampTestBloodDrawsTodayVetStaff();
+ notificationRevampTestBloodDrawReviewDailyNotification();
+ notificationRevampTestBloodDrawReviewTriggerNotification();
+
+
+
+
+
+ // Uploads data for notification: Admin Alerts
+
+ // Uploads data for notification: Animal Request
+
+ // Uploads data for notification: Blood Draws Today (All)
+
+ // Uploads data for notification: Blood Draws Today (Animal Care)
+
+ // Uploads data for notification: Blood Draws Today (Vet Staff)
+
+ // Uploads data for notification: Blood Draw Review (Daily)
+
+ // Uploads data for notification: Blood Draw Review (Trigger)
+
+ // Uploads data for notification: Colony Alerts
+
+ // Uploads data for notification: Colony Alerts (Lite)
+
+ // Uploads data for notification: Colony Management
+
+ // Uploads data for notification: Death
+
+ // Uploads data for notification: Prenatal Death
+ }
+
+ public class ReusableTestFunctions {
+
+ public void goHome() {
+ beginAt(buildURL("project", getContainerPath(), "begin"));
+ }
+
+ public void insertValueIntoDataset(String schemaName, String queryName, HashMap valuesToInsert) throws IOException, CommandException {
+ log("Inserting values into dataset.\n" +
+ "Schema Name: " + schemaName + "\n" +
+ "Query Name: " + queryName + "\n" +
+ "Values: " + valuesToInsert);
+
+ //TODO: Which one to use?
+ Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
+// Connection cn = WebTestHelper.getRemoteApiConnection();
+
+ // Gets dataset to update.
+ InsertRowsCommand insertCmd = new InsertRowsCommand(schemaName, queryName);
+
+ // Creates values to insert.
+ insertCmd.addRow(valuesToInsert);
+
+ // Inserts rows into dataset.
+ insertCmd.execute(cn, EHR_FOLDER_PATH);
+
+ }
+
+ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, String billingGroupDisplayName) throws IOException, CommandException
+ {
+ HashMap billingGroupTestData = new HashMap<>();
+ billingGroupTestData.put("value", billingGroupRealName);
+ billingGroupTestData.put("title", billingGroupDisplayName);
+ insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
+ }
+
+ /**
+ * This function inserts data into the 'study/BloodSchedule' dataset.
+ * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/AvailBlood, billedby/title, and Id/DataSet/Demographics/calculated_status.
+ * This function updates the following tables: study/demographics, study/weight, study/blood.
+ * @param billingGroupRealName
+ * @param animalID
+ * @param animalAlive
+ * @param projectAssigned
+ * @param animalWeight
+ * @throws IOException
+ * @throws CommandException
+ */
+ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, String animalID, Boolean animalAlive, Date drawDate, Boolean projectAssigned, Double animalWeight, Boolean drawCompleted) throws IOException, CommandException {
+ // Creates data to pass in.
+ String livingStatus = "Dead";
+ if (animalAlive) {
+ livingStatus = "Alive";
+ }
+ Integer assignmentStatus = null;
+ if (projectAssigned) {
+ assignmentStatus = 300901;
+ }
+ Integer completionStatus = getQCStateRowID("In Progress");
+ if (drawCompleted) {
+ completionStatus = getQCStateRowID("Completed");
+ }
+
+ // Creates demographic info (this updates the bloodSchedule field: 'Id/DataSet/Demographics/calculated_status').
+ HashMap demographicInfoTestData1 = new HashMap<>();
+ demographicInfoTestData1.put("id", animalID);
+ demographicInfoTestData1.put("calculated_status", livingStatus);
+ // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood').
+ HashMap weightTestData1 = new HashMap<>();
+ weightTestData1.put("id", animalID);
+ weightTestData1.put("date", new Date());
+ weightTestData1.put("weight", animalWeight);
+ // Creates blood info (this updates the bloodSchedule fields: 'id', 'date', 'projectStatus', 'billedby/title', and QCState/label).
+ HashMap bloodTestData1 = new HashMap<>();
+ bloodTestData1.put("id", animalID);
+ bloodTestData1.put("date", drawDate);
+ bloodTestData1.put("project", assignmentStatus);
+ bloodTestData1.put("billedBy", billingGroupRealName);
+ bloodTestData1.put("QCState", completionStatus);
+
+ // Inserts data.
+ insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
+ insertValueIntoDataset("study", "blood", bloodTestData1);
+ insertValueIntoDataset("study", "weight", weightTestData1);
+
+ // TODO: The following fields are not included. Make sure test still runs correctly.
+ // Id/curLocation/room
+ // Id/curLocation/area
+ }
+
+ public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
+ // Retrieves QCState table.
+ Connection cn = createDefaultConnection();
+ SelectRowsCommand cmd = new SelectRowsCommand("core", "QCState");
+ cmd.setRequiredVersion(9.1); // Not sure what this does, but it was used in 'fetchWeightData()'.
+ cmd.setColumns(Arrays.asList("RowId", "Label"));
+ cmd.setMaxRows(100);
+ SelectRowsResponse r = cmd.execute(cn, EHR_FOLDER_PATH);
+
+ // Goes through each QCState in the table and returns the rowID of the row matching the passed-in QCState.
+ for (Map currentRow : r.getRows()) {
+ String rowLabel = ((HashMap) currentRow.get("Label")).get("value").toString();
+ Integer rowID = Integer.valueOf(((HashMap) currentRow.get("RowId")).get("value").toString());
+ if (rowLabel.equals(qcStateLabel)) {
+ return rowID;
+ }
+ }
+ return null;
+ }
+
+ }
+
}
\ No newline at end of file
From 223ac8829489155a8b6aa7ac22a228aa336d7e5f Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 24 Jul 2024 17:20:50 -0500
Subject: [PATCH 03/29] Added blood overdraw trigger notification.
---
.../scripts/wnprc_ehr/wnprc_triggers.js | 6 +
.../labkey/wnprc_ehr/TriggerScriptHelper.java | 21 ++++
.../BloodOverdrawTriggerNotification.java | 104 ++++++++++++++++++
3 files changed, 131 insertions(+)
create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
diff --git a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
index 51124a6ab..c94f8220f 100644
--- a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
+++ b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
@@ -630,6 +630,12 @@ exports.init = function (EHR) {
}
})
+ EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.AFTER_UPSERT, 'study', 'bloodSummary', function (helper, scriptErrors, row) {
+ if (row.AvailBlood <= 0) {
+ WNPRC.Utils.getJavaHelper().sendBloodOverdrawTriggerNotification(row.Id, row.AvailBlood, row.date);
+ }
+ })
+
function getHousingSQL(row) {
var date = row.Date;
date = EHR.Server.Utils.normalizeDate(date);
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
index 3198126ee..eec2b8a3b 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
@@ -55,6 +55,7 @@
import org.labkey.wnprc_ehr.notification.AnimalRequestNotificationRevamp;
import org.labkey.wnprc_ehr.notification.AnimalRequestNotificationUpdate;
import org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification;
+import org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification;
import org.labkey.wnprc_ehr.notification.DeathNotification;
import org.labkey.wnprc_ehr.notification.DeathNotificationRevamp;
import org.labkey.wnprc_ehr.notification.ProjectRequestNotification;
@@ -246,6 +247,26 @@ else if (!NotificationService.get().isServiceEnabled()) {
}
}
+ // TODO: Should availBlood be a type: Double?
+ public void sendBloodOverdrawTriggerNotification(String animalID, String availBlood, String drawDate) {
+ Module ehr = ModuleLoader.getInstance().getModule("EHR");
+ // Verifies 'Notification Service' is enabled before sending notification.
+ if (NotificationService.get().isServiceEnabled()) {
+ // Sends Overdraw Trigger Notification.
+ if (NotificationService.get().isActive(new BloodOverdrawTriggerNotification(ehr), container)) {
+ _log.info("Using java helper to send email for Blood Overdraw Trigger Notification (animalID: " + animalID + ").");
+ BloodOverdrawTriggerNotification notification = new BloodOverdrawTriggerNotification(ehr, animalID, availBlood, drawDate);
+ notification.sendManually(container, user);
+ }
+ else {
+ _log.info("Blood Overdraw Trigger Notification is not enabled, will not send Blood Overdraw Trigger Notification");
+ }
+ }
+ else if (!NotificationService.get().isServiceEnabled()) {
+ _log.info("Notification service is not enabled, will not send Blood Overdraw Trigger Notification");
+ }
+ }
+
public void sendPregnancyNotification(final List ids, final List objectids) {
// if (!NotificationService.get().isServiceEnabled() && NotificationService.get().isActive(new PregnancyNotification(), container)){
// _log.info("Notification service is not enabled, will not send pregnancy notification");
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
new file mode 100644
index 000000000..54868f3ca
--- /dev/null
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
@@ -0,0 +1,104 @@
+package org.labkey.wnprc_ehr.notification;
+
+import org.labkey.api.data.Container;
+import org.labkey.api.module.Module;
+import org.labkey.api.security.User;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Locale;
+
+import static org.labkey.api.search.SearchService._log;
+
+public class BloodOverdrawTriggerNotification extends AbstractEHRNotification {
+ //Class Variables
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
+ NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
+ String animalID;
+ String availableBlood;
+ String drawDate;
+
+
+ //Constructors
+ /**
+ * This constructor is used to register the notification in WNPRC_EHRModule.java.
+ * @param owner
+ */
+ public BloodOverdrawTriggerNotification(Module owner) {super(owner);}
+
+ //This constructor is used to actually send the notification via the "TriggerScriptHelper.java" class.
+ public BloodOverdrawTriggerNotification(Module owner, String drawAnimalID, String availBlood, String dateOfDraw) {
+ super(owner);
+// this.requestIdToCheck = requestID;
+ this.animalID = drawAnimalID;
+ this.availableBlood = availBlood;
+ this.drawDate = dateOfDraw;
+ }
+
+
+
+ //Notification Details
+ @Override
+ public String getName() {
+ return "Blood Overdraw Trigger Notification";
+ }
+ @Override
+ public String getDescription() {
+ return "This email warns users if an animal had their blood overdrawn.";
+ }
+ @Override
+ public String getEmailSubject(Container c) {
+ String subject = "Blood Overdraw Notification";
+ if (animalID != null) {
+ subject += ": " + animalID;
+ }
+ return subject;
+ }
+ @Override
+ public String getScheduleDescription() {
+ return "Triggered when an animal's blood is overdrawn.";
+ }
+ @Override
+ public String getCategory() {
+ return "Revamped Notifications - Blood Draws Update";
+ }
+
+
+
+ //Sending Options
+ public void sendManually (Container container, User user){
+ notificationToolkit.sendNotification(this, user, container, null);
+ }
+
+
+
+ // Message Creation
+ @Override
+ public String getMessageBodyHTML(Container c, User u) {
+ // Set up.
+ StringBuilder messageBody = new StringBuilder();
+
+// TODO: Set this up for testing.
+ if (this.animalID == null || this.availableBlood == null || this.drawDate == null) {
+ // This sets up the values for testing through Notification Manager > Run Report in Browser.
+ this.animalID = "testID";
+ this.availableBlood = "testAvailBlood";
+ this.drawDate = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString();
+ }
+ else {
+ // Begins message info.
+ messageBody.append("This email contains warning information for an animal who just had their blood overdrawn. It was sent on: " + dateToolkit.getCurrentTime() + "
");
+ messageBody.append("Animal ID: " + this.animalID + "
");
+ messageBody.append("Available Blood: " + this.availableBlood + "
");
+ }
+
+ // Returns message info.
+ return messageBody.toString();
+ }
+
+}
From c51cd235ab8dc900ad5ad8af842875354c4e7040 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 25 Jul 2024 16:35:49 -0500
Subject: [PATCH 04/29] Registered new notification.
---
WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
index 6507a3fe6..215aac420 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
@@ -389,7 +389,8 @@ public void registerNotifications() {
new BloodDrawReviewTriggerNotification(this),
new AdminAlertsNotificationRevamp(this),
new ColonyManagementNotificationRevamp(this),
- new ColonyAlertsLiteNotificationRevamp(this)
+ new ColonyAlertsLiteNotificationRevamp(this),
+ new BloodOverdrawTriggerNotification(this)
);
for (Notification notification : notifications)
From 503747b35cc6816cfe1b31a6462b2cfe662f2ce1 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 26 Jul 2024 16:49:27 -0500
Subject: [PATCH 05/29] Updated code so message sends when testing/running in
browser. Updated log for wnprc_triggers.js for when function is run to help
debug until issue with webpack generation is fixed.
---
.../scripts/wnprc_ehr/wnprc_triggers.js | 2 ++
.../BloodOverdrawTriggerNotification.java | 20 +++++++++----------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
index c94f8220f..5d4e23f1b 100644
--- a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
+++ b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
@@ -631,6 +631,8 @@ exports.init = function (EHR) {
})
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.AFTER_UPSERT, 'study', 'bloodSummary', function (helper, scriptErrors, row) {
+ console.log("Attempting to run sendBloodOverdrawTriggerNotification.");
+ console.log("sendBloodOverdrawTriggerNotification - row.AvailBlood = " + row.AvailBlood);
if (row.AvailBlood <= 0) {
WNPRC.Utils.getJavaHelper().sendBloodOverdrawTriggerNotification(row.Id, row.AvailBlood, row.date);
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
index 54868f3ca..d6e7bbf04 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
@@ -19,9 +19,9 @@ public class BloodOverdrawTriggerNotification extends AbstractEHRNotification {
NotificationToolkit notificationToolkit = new NotificationToolkit();
NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
- String animalID;
- String availableBlood;
- String drawDate;
+ String animalID = null;
+ String availableBlood = null;
+ String drawDate = null;
//Constructors
@@ -83,19 +83,17 @@ public String getMessageBodyHTML(Container c, User u) {
// Set up.
StringBuilder messageBody = new StringBuilder();
-// TODO: Set this up for testing.
+ // This sets up the values for testing through Notification Manager > Run Report in Browser.
if (this.animalID == null || this.availableBlood == null || this.drawDate == null) {
- // This sets up the values for testing through Notification Manager > Run Report in Browser.
this.animalID = "testID";
this.availableBlood = "testAvailBlood";
this.drawDate = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString();
}
- else {
- // Begins message info.
- messageBody.append("This email contains warning information for an animal who just had their blood overdrawn. It was sent on: " + dateToolkit.getCurrentTime() + "
");
- messageBody.append("Animal ID: " + this.animalID + "
");
- messageBody.append("Available Blood: " + this.availableBlood + "
");
- }
+
+ // Begins message info.
+ messageBody.append("This email contains warning information for an animal who just had their blood overdrawn. It was sent on: " + dateToolkit.getCurrentTime() + "
");
+ messageBody.append("Animal ID: " + this.animalID + "
");
+ messageBody.append("Available Blood: " + this.availableBlood + "
");
// Returns message info.
return messageBody.toString();
From 8c02d59d341110ce7f0ac786a2d12bfde09d1ba0 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 31 Jul 2024 16:59:53 -0500
Subject: [PATCH 06/29] Updated overdraw notification. Notification is now
created everytime blood is updated. Logic is run inside notification to
determine if current draw is an overdraw. If it is an overdraw, the message
is sent.
---
.../scripts/wnprc_ehr/wnprc_triggers.js | 11 ++----
.../labkey/wnprc_ehr/TriggerScriptHelper.java | 4 +--
.../BloodOverdrawTriggerNotification.java | 36 ++++++++++++-------
.../notification/NotificationToolkit.java | 20 +++++++++++
4 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
index 5d4e23f1b..ab07c4312 100644
--- a/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
+++ b/WNPRC_EHR/resources/scripts/wnprc_ehr/wnprc_triggers.js
@@ -625,17 +625,12 @@ exports.init = function (EHR) {
var tube_types = {}
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.AFTER_UPSERT, 'study', 'Blood', function (helper, scriptErrors, row) {
+ // Triggers wnprc_triggers.js to send BloodDrawReviewTriggerNotification.java.
if (row.QCStateLabel === 'Request: Approved') {
WNPRC.Utils.getJavaHelper().sendBloodDrawReviewNotification(row.Id, row.project, row.date, row.requestor);
}
- })
-
- EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.AFTER_UPSERT, 'study', 'bloodSummary', function (helper, scriptErrors, row) {
- console.log("Attempting to run sendBloodOverdrawTriggerNotification.");
- console.log("sendBloodOverdrawTriggerNotification - row.AvailBlood = " + row.AvailBlood);
- if (row.AvailBlood <= 0) {
- WNPRC.Utils.getJavaHelper().sendBloodOverdrawTriggerNotification(row.Id, row.AvailBlood, row.date);
- }
+ // Triggers wnprc_triggers.js to send BloodOverdrawTriggerNotification.java.
+ WNPRC.Utils.getJavaHelper().sendBloodOverdrawTriggerNotification(row.Id, row.date);
})
function getHousingSQL(row) {
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
index eec2b8a3b..ba444a72a 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
@@ -248,14 +248,14 @@ else if (!NotificationService.get().isServiceEnabled()) {
}
// TODO: Should availBlood be a type: Double?
- public void sendBloodOverdrawTriggerNotification(String animalID, String availBlood, String drawDate) {
+ public void sendBloodOverdrawTriggerNotification(String animalID, String drawDate) {
Module ehr = ModuleLoader.getInstance().getModule("EHR");
// Verifies 'Notification Service' is enabled before sending notification.
if (NotificationService.get().isServiceEnabled()) {
// Sends Overdraw Trigger Notification.
if (NotificationService.get().isActive(new BloodOverdrawTriggerNotification(ehr), container)) {
_log.info("Using java helper to send email for Blood Overdraw Trigger Notification (animalID: " + animalID + ").");
- BloodOverdrawTriggerNotification notification = new BloodOverdrawTriggerNotification(ehr, animalID, availBlood, drawDate);
+ BloodOverdrawTriggerNotification notification = new BloodOverdrawTriggerNotification(ehr, animalID, drawDate);
notification.sendManually(container, user);
}
else {
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
index d6e7bbf04..823d59ce4 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
@@ -20,7 +20,6 @@ public class BloodOverdrawTriggerNotification extends AbstractEHRNotification {
NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
String animalID = null;
- String availableBlood = null;
String drawDate = null;
@@ -32,11 +31,9 @@ public class BloodOverdrawTriggerNotification extends AbstractEHRNotification {
public BloodOverdrawTriggerNotification(Module owner) {super(owner);}
//This constructor is used to actually send the notification via the "TriggerScriptHelper.java" class.
- public BloodOverdrawTriggerNotification(Module owner, String drawAnimalID, String availBlood, String dateOfDraw) {
+ public BloodOverdrawTriggerNotification(Module owner, String drawAnimalID, String dateOfDraw) {
super(owner);
-// this.requestIdToCheck = requestID;
this.animalID = drawAnimalID;
- this.availableBlood = availBlood;
this.drawDate = dateOfDraw;
}
@@ -82,21 +79,36 @@ public void sendManually (Container container, User user){
public String getMessageBodyHTML(Container c, User u) {
// Set up.
StringBuilder messageBody = new StringBuilder();
+ Double overdrawAmount = null;
// This sets up the values for testing through Notification Manager > Run Report in Browser.
- if (this.animalID == null || this.availableBlood == null || this.drawDate == null) {
+ if (this.animalID == null || this.drawDate == null) {
this.animalID = "testID";
- this.availableBlood = "testAvailBlood";
this.drawDate = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString();
+ overdrawAmount = Double.valueOf(-100);
}
+ else {
+ overdrawAmount = notificationToolkit.checkIfBloodDrawIsOverdraw(c, u, this.animalID, this.drawDate);
+ }
+
+ // Verifies blood is an overdraw.
+ if (overdrawAmount != null) {
+ // Begins message info.
+ messageBody.append("This email contains warning information for an animal who just had their blood overdrawn. It was sent on: " + dateToolkit.getCurrentTime() + "
");
+ messageBody.append("Animal ID: " + this.animalID + "
");
+ messageBody.append("Date of overdraw: " + this.drawDate + "
");
+ messageBody.append("Available blood: " + overdrawAmount + "
");
- // Begins message info.
- messageBody.append("This email contains warning information for an animal who just had their blood overdrawn. It was sent on: " + dateToolkit.getCurrentTime() + "
");
- messageBody.append("Animal ID: " + this.animalID + "
");
- messageBody.append("Available Blood: " + this.availableBlood + "
");
+ // Returns message info.
+ return messageBody.toString();
+ }
+ // Sends no message if there is no overdraw.
+ else {
+ return null;
+ }
- // Returns message info.
- return messageBody.toString();
}
+
+
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index d8b287ea8..371fde31d 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -890,6 +890,26 @@ public Boolean checkProjectAssignmentStatusOnDate(Container c, User u, String id
return animalAssigned;
}
+ // TODO: Comment. Returns null if there is no overdraw, or overdraw amount if there is an overdraw.
+ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck, String dateToCheck) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id", idToCheck, CompareType.EQUAL);
+ myFilter.addCondition("date", dateToCheck, CompareType.DATE_EQUAL);
+ // Runs query.
+ String[] targetColumns = new String[]{"BloodRemaining/AvailBlood"};
+ ArrayList> returnArray = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "blood", myFilter, null, targetColumns);
+
+ // Checks results.
+ if (!returnArray.isEmpty()) {
+ for (HashMap result : returnArray) {
+ Double availableBlood = Double.valueOf(result.get("BloodRemaining/AvailBlood"));
+ if (availableBlood <=0) {
+ return availableBlood;
+ }
+ }
+ }
+ return null;
+ }
From 1940d474a61c51efae93a43313cea34760f5ec5e Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 2 Aug 2024 17:10:59 -0500
Subject: [PATCH 07/29] Fixed issue where 'Animal Replacement Fee' showed
incorrectly in the revamped Death Notification. This occurred when the Type
of Death resulted in a fee in the table 'ehr_lookups' > 'death_cause', but
the 'prepaid' field was empty in the table 'study' > 'demographics'. This
was due to labkeys table lookup resulting in a string 'null' instead of a
real null when using the TableSelector. My new notifications use a new query
function i wrote, but this Death Notification used the old TableSelector
method.
---
.../wnprc_ehr/notification/NotificationToolkit.java | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index 371fde31d..077aa3f01 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -372,13 +372,18 @@ public void exec(ResultSet rs) throws SQLException {
feeTable.forEach(new Selector.ForEachBlock() {
@Override
public void exec(ResultSet rs) throws SQLException {
- updatedFee.append(rs.getString("prepaid"));
+ updatedFee.append(rs.getString("prepaid")); // When value is null, this returns "null" as a string. This is why we need to check for "null" in the next if statement.
}
});
}
}
if (!updatedFee.isEmpty()) {
- return updatedFee.toString();
+ if (!updatedFee.toString().equals("null")) {
+ return updatedFee.toString();
+ }
+ else {
+ return ("Animal replacement fee to be paid (" + causeOfDeath + " death)");
+ }
}
else {
return ("Animal replacement fee to be paid (" + causeOfDeath + " death)");
From f43ccc2f30180b211dffc9ff8bf0ca424a2f91e5 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 2 Aug 2024 17:29:33 -0500
Subject: [PATCH 08/29] Reordered messages in
BloodDrawReviewDailyNotification.java so overdraws are listed first.
---
.../BloodDrawReviewDailyNotification.java | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 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 00f1c001b..1450c29da 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java
@@ -73,6 +73,19 @@ public String getMessageBodyHTML(Container c, User u) {
//Begins message info.
messageBody.append("This email contains any scheduled blood draws (today & future) where animals are either unassigned to a project or no longer alive. It was run on: " + dateToolkit.getCurrentTime() + "
");
+ // 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");
+ }
// Lists all blood draws (today & future) where animal is not alive.
if (!myBloodDrawReviewObject.nonAliveBloodDraws.isEmpty()) {
messageBody.append("
There are " + myBloodDrawReviewObject.nonAliveBloodDraws.size() + " blood draws (today & future) where animal is not alive:
");
@@ -112,19 +125,6 @@ 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.
\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();
}
From 27e89738b8b6ca5e9813d29b55ec3019ba4eb882 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 8 Aug 2024 02:45:08 -0500
Subject: [PATCH 09/29] -NotificationToolkit.java: Updated
getWeightFromAnimalID() and getSexFromAnimalID() so they use new query
function getTableMultiRowMultiColumnWithFieldKeys() instead of old function
getTableRowAsList(). Also moved DeathNecropsyObject and
DeathDemographicObject to DeathNotificationRevamp.java. -
DeathNotificationRevamp.java: Moved DeathNecropsyObject and
DeathDemographicObject here from NotificationToolkit.java. Also cleaned up
these objects and updated these them to use the new query
getTableMultiRowMultiColumnWithFieldKeys.
---
.../notification/DeathNotificationRevamp.java | 289 +++++++++++++++-
.../notification/NotificationToolkit.java | 324 ++++++------------
2 files changed, 392 insertions(+), 221 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
index c4a5e3f36..0e56bd63c 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
@@ -1,10 +1,16 @@
package org.labkey.wnprc_ehr.notification;
+import org.labkey.api.data.CompareType;
import org.labkey.api.data.Container;
+import org.labkey.api.data.SimpleFilter;
+import org.labkey.api.data.Sort;
import org.labkey.api.module.Module;
import org.labkey.api.security.User;
+import org.labkey.api.util.Path;
+import org.labkey.api.view.ActionURL;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* Created by Alex Schmidt on
@@ -14,9 +20,9 @@ public class DeathNotificationRevamp extends AbstractEHRNotification {
//Class Variables
NotificationToolkit notificationToolkit = new NotificationToolkit();
NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
- public String deathID;
- public User currentUser;
- public String hostName;
+ String deathID = null;
+ User currentUser = null;
+ String hostName = null;
//Constructors
@@ -35,9 +41,9 @@ public class DeathNotificationRevamp extends AbstractEHRNotification {
*/
public DeathNotificationRevamp(Module owner, String deathid, User currentuser, String hostname) {
super(owner);
- deathID = deathid;
- currentUser = currentuser;
- hostName = hostname;
+ this.deathID = deathid;
+ this.currentUser = currentuser;
+ this.hostName = hostname;
}
@@ -98,11 +104,14 @@ public String getMessageBodyHTML(Container c, User u) {
final StringBuilder messageBody = new StringBuilder();
if (deathID == null) {
//If no ID exists (testing purposes), this gets the most recent necropsy animal id.
- ArrayList necropsiesInOrder = notificationToolkit.getTableAsList(c, u, "necropsy", "mostRecentNecropsy");
- deathID = necropsiesInOrder.get(0)[0].toString();
+ Sort mySort = new Sort("-date");
+ String[] targetColumns = new String[]{"id"};
+ ArrayList> necropsyList = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "necropsy", null, mySort, targetColumns);
+ deathID = necropsyList.get(0).get("id");
}
- NotificationToolkit.DeathDemographicObject deathDemographicObject = new NotificationToolkit.DeathDemographicObject(c, u, deathID, true);
- NotificationToolkit.DeathNecropsyObject deathNecropsyObject = new NotificationToolkit.DeathNecropsyObject(c, u, deathID, hostName, true);
+ DeathDemographicObject deathDemographicObject = new DeathDemographicObject(c, u, deathID, true);
+// DeathNecropsyObject deathNecropsyObject = new DeathNecropsyObject(c, u, deathID, hostName, true);
+ DeathNecropsyObject deathNecropsyObject = new DeathNecropsyObject(c, u, deathID, true);
//Creates CSS.
messageBody.append(styleToolkit.beginStyle());
@@ -141,7 +150,267 @@ public String getMessageBodyHTML(Container c, User u) {
messageBody.append("Manner of Death: " + deathNecropsyObject.necropsyMannerOfDeath + "
");
}
+ // Resets data. This is necessary to get 'this.deathID' to reset everytime it's run in the browser.
+ this.deathID = null;
+
//Returns string.
return messageBody.toString();
}
+
+
+
+
+
+ /**
+ * This is an object used in the WNPRC DeathNotification.java file that defines all the info presented for a dead animal's necropsy.
+ * It contains the following data (returning blank strings for non-existent data):
+ * If necropsy exists (true/false).
+ * Necropsy case number.
+ * Necropsy task id hyperlink.
+ * Necropsy date.
+ * Necropsy time of death.
+ * Necropsy type of death.
+ * Necropsy grant number.
+ * Necropsy manner of death.
+ * Necropsy animal weight.
+ * Necropsy animal replacement fee.
+ */
+ public static class DeathNecropsyObject {
+ Boolean necropsyExists = false;
+ String necropsyCaseNumber = "";
+ String necropsyTaskIdHyperlink = "";
+ String necropsyDate = "";
+ String necropsyTimeOfDeath = "";
+ String necropsyTypeOfDeath = "";
+ String necropsyGrantNumber = "";
+ String necropsyMannerOfDeath = "";
+ String animalWeight = "";
+ String animalReplacementFee = "";
+
+ public DeathNecropsyObject(Container c, User u, String animalID, Boolean withHtmlPlaceHolders) {
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", animalID, CompareType.EQUAL);
+ String[] targetColumns = new String[]{"caseno", "taskid", "date", "timeofdeath", "causeofdeath", "account", "mannerofdeath"};
+ // Runs query.
+ ArrayList> animalNecropsy = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "necropsy", myFilter, null, targetColumns);
+
+ // Assigns values to object variables.
+ if (!animalNecropsy.isEmpty()) {
+ this.necropsyExists = true;
+ //Gets necropsy data.
+ this.necropsyCaseNumber = animalNecropsy.get(0).get("caseno");
+ this.necropsyDate = animalNecropsy.get(0).get("date");
+ this.necropsyTimeOfDeath = animalNecropsy.get(0).get("timeofdeath");
+ this.necropsyTypeOfDeath = animalNecropsy.get(0).get("causeofdeath");
+ this.necropsyGrantNumber = animalNecropsy.get(0).get("account");
+ this.necropsyMannerOfDeath = animalNecropsy.get(0).get("mannerofdeath");
+ this.animalWeight = notificationToolkit.getWeightFromAnimalID(c, u, animalID);
+ this.animalReplacementFee = notificationToolkit.getAnimalReplacementFee(c, u, this.necropsyTypeOfDeath, animalID);
+
+ //Creates task id with hyperlink. // TODO: Don't use hardcoded URL here.
+ String necropsyTaskID = animalNecropsy.get(0).get("taskid");
+ Path taskURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "taskDetails.view");
+ String taskUrlAsString = taskURL.toString() + "?formtype=Necropsy&taskid=" + necropsyTaskID;
+
+ // Creates filter.
+ SimpleFilter myTaskFilter = new SimpleFilter("taskid", necropsyTaskID, CompareType.EQUAL);
+ String[] targetTaskColumns = new String[]{"rowid"};
+ // Runs query.
+ ArrayList> necropsyTask = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "ehr", "tasks", myTaskFilter, null, targetTaskColumns);
+ String taskRowID = necropsyTask.get(0).get("rowid");
+ this.necropsyTaskIdHyperlink = notificationToolkit.createHyperlink(taskRowID, taskUrlAsString);
+ }
+
+ // Assigns 'Not Specified' placeholders for blank values.
+ if (withHtmlPlaceHolders) {
+ String placeholderText = "Not Specified";
+ if (this.necropsyCaseNumber.isEmpty()) {
+ this.necropsyCaseNumber = placeholderText;
+ }
+ if (this.necropsyTaskIdHyperlink.isEmpty()) {
+ this.necropsyTaskIdHyperlink = placeholderText;
+ }
+ if (this.necropsyDate.isEmpty()) {
+ this.necropsyDate = placeholderText;
+ }
+ if (this.necropsyTimeOfDeath.isEmpty()) {
+ this.necropsyTimeOfDeath = placeholderText;
+ }
+ if (this.necropsyTypeOfDeath.isEmpty()) {
+ this.necropsyTypeOfDeath = placeholderText;
+ }
+ if (this.necropsyGrantNumber.isEmpty()) {
+ this.necropsyGrantNumber = placeholderText;
+ }
+ if (this.necropsyMannerOfDeath.isEmpty()) {
+ this.necropsyMannerOfDeath = placeholderText;
+ }
+ if (this.animalWeight.isEmpty()) {
+ this.animalWeight = placeholderText;
+ }
+ if (this.animalReplacementFee.isEmpty()) {
+ this.animalReplacementFee = placeholderText;
+ }
+ }
+ }
+
+// public DeathNecropsyObject(Container c, User u, String animalID, String hostName, Boolean withHtmlPlaceHolders) {
+// NotificationToolkit notificationToolkit = new NotificationToolkit();
+//
+// if (notificationToolkit.getTableRowCount(c, u, "study", "Necropsy", "notificationView") > 0) { //Added this if/else check to getTableRowAsList(), I can remove this after testing.
+// String[] targetColumns = {"caseno", "taskid", "date", "timeofdeath", "causeofdeath", "account", "mannerofdeath"};
+//
+// ArrayList necropsyTableRow = notificationToolkit.getTableRowAsList(c, u, "study", "necropsy", null, "id", animalID, targetColumns);
+//
+// //Necropsy does exist.
+// if (!necropsyTableRow.isEmpty()) {
+// this.necropsyExists = true;
+// //Gets necropsy data.
+// this.necropsyCaseNumber = necropsyTableRow.get(0);
+// this.necropsyDate = necropsyTableRow.get(2);
+// this.necropsyTimeOfDeath = necropsyTableRow.get(3);
+// this.necropsyTypeOfDeath = necropsyTableRow.get(4);
+// this.necropsyGrantNumber = necropsyTableRow.get(5);
+// this.necropsyMannerOfDeath = necropsyTableRow.get(6);
+// this.animalWeight = notificationToolkit.getWeightFromAnimalID(c, u, animalID);
+// this.animalReplacementFee = notificationToolkit.getAnimalReplacementFee(c, u, this.necropsyTypeOfDeath, animalID);
+//
+// //Creates task id with hyperlink.
+// String necropsyTaskID = necropsyTableRow.get(1);
+// Path taskURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "taskDetails.view");
+// String taskUrlAsString = taskURL.toString() + "?formtype=Necropsy&taskid=" + necropsyTaskID;
+// String taskRowID = "";
+// if (notificationToolkit.getTableRowCount(c, u, "ehr", "tasks", "") > 0) { //Added this if/else check to getTableRowAsList(), I can remove this after testing.
+// ArrayList taskRow = notificationToolkit.getTableRowAsList(c, u, "ehr", "tasks", null, "taskid", necropsyTaskID, new String[]{"rowid"});
+// if (!taskRow.isEmpty()) {
+// taskRowID = taskRow.get(0);
+// }
+// this.necropsyTaskIdHyperlink = notificationToolkit.createHyperlink(taskRowID, taskUrlAsString);
+// }
+// }
+// }
+// if (withHtmlPlaceHolders) {
+// String placeholderText = "Not Specified";
+// if (this.necropsyCaseNumber == null) {
+// this.necropsyCaseNumber = placeholderText;
+// }
+// else if (this.necropsyCaseNumber.equals("") || this.necropsyCaseNumber.equals("null")) {
+// this.necropsyCaseNumber = placeholderText;
+// }
+// if (this.necropsyTaskIdHyperlink == null) {
+// this.necropsyTaskIdHyperlink = placeholderText;
+// }
+// else if (this.necropsyTaskIdHyperlink.equals("") || this.necropsyTaskIdHyperlink.equals("null")) {
+// this.necropsyTaskIdHyperlink = placeholderText;
+// }
+// if (this.necropsyDate == null) {
+// this.necropsyDate = placeholderText;
+// }
+// else if (this.necropsyDate.equals("") || this.necropsyDate.equals("null")) {
+// this.necropsyDate = placeholderText;
+// }
+// if (this.necropsyTimeOfDeath == null) {
+// this.necropsyTimeOfDeath = placeholderText;
+// }
+// else if (this.necropsyTimeOfDeath.equals("") || this.necropsyTimeOfDeath.equals("null")) {
+// this.necropsyTimeOfDeath = placeholderText;
+// }
+// if (this.necropsyTypeOfDeath == null) {
+// this.necropsyTypeOfDeath = placeholderText;
+// }
+// else if (this.necropsyTypeOfDeath.equals("") || this.necropsyTypeOfDeath.equals("null")) {
+// this.necropsyTypeOfDeath = placeholderText;
+// }
+// if (this.necropsyGrantNumber == null) {
+// this.necropsyGrantNumber = placeholderText;
+// }
+// else if (this.necropsyGrantNumber.equals("") || this.necropsyGrantNumber.equals("null")) {
+// this.necropsyGrantNumber = placeholderText;
+// }
+// if (this.necropsyMannerOfDeath == null) {
+// this.necropsyMannerOfDeath = placeholderText;
+// }
+// else if (this.necropsyMannerOfDeath.equals("") || this.necropsyMannerOfDeath.equals("null")) {
+// this.necropsyMannerOfDeath = placeholderText;
+// }
+// if (this.animalWeight == null) {
+// this.animalWeight = placeholderText;
+// }
+// else if (this.animalWeight.equals("") || this.animalWeight.equals("null")) {
+// this.animalWeight = placeholderText;
+// }
+// if (this.animalReplacementFee == null) {
+// this.animalReplacementFee = placeholderText;
+// }
+// else if (this.animalReplacementFee.equals("") || this.animalReplacementFee.equals("null")) {
+// this.animalReplacementFee = placeholderText;
+// }
+// }
+// }
+ }
+
+ /**
+ * This is an object used in the WNPRC DeathNotification.java file that defines all the info presented for a dead animal's demographics.
+ * It contains the following data (returning blank strings for non-existent data):
+ * Animal ID hyperlink.
+ * Animal sex.
+ */
+ public static class DeathDemographicObject {
+ String animalIdHyperlink = "";
+ String animalSex = "";
+ String animalDam = "";
+ String animalSire = "";
+ String animalConception = "";
+ public DeathDemographicObject(Container c, User u, String animalID, Boolean withHtmlPlaceHolders) {
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+
+ // TODO: Update this to remove hardcoded url.
+ //Gets hyperlink for animal id in animal history abstract.
+ Path animalAbstractURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "animalHistory.view");
+ String animalAbstractUrlAsString = animalAbstractURL.toString() + "?#subjects:" + animalID + "&inputType:singleSubject&showReport:1&activeReport:abstract";
+ this.animalIdHyperlink = notificationToolkit.createHyperlink(animalID, animalAbstractUrlAsString);
+
+ //Gets animal sex.
+ String animalSex = notificationToolkit.getSexFromAnimalID(c, u, animalID);
+ this.animalSex = animalSex;
+
+ //Gets prenatal information if necessary.
+ if (notificationToolkit.checkIfPrenatalID(animalID)) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", animalID, CompareType.EQUAL);
+ String[] targetColumns = new String[]{"dam", "sire", "conception"};
+ // Runs query.
+ ArrayList> prenatalDeathRow = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "prenatal", myFilter, null, targetColumns);
+
+ // Checks return data.
+ if (!prenatalDeathRow.isEmpty()) {
+ this.animalDam = prenatalDeathRow.get(0).get("dam");
+ this.animalSire = prenatalDeathRow.get(0).get("sire");
+ this.animalConception = prenatalDeathRow.get(0).get("conception");
+ }
+ }
+
+ //Adds HTML placeholders for empty fields.
+ if (withHtmlPlaceHolders) {
+ String placeholderText = "Not Specified";
+ if (this.animalIdHyperlink.isEmpty()) {
+ this.animalIdHyperlink = placeholderText;
+ }
+ if (this.animalSex.isEmpty()) {
+ this.animalSex = placeholderText;
+ }
+ if (this.animalDam.isEmpty()) {
+ this.animalDam = placeholderText;
+ }
+ if (this.animalSire.isEmpty()) {
+ this.animalSire = placeholderText;
+ }
+ if (this.animalConception.isEmpty()) {
+ this.animalConception = placeholderText;
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index 077aa3f01..5bcb3611d 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -299,6 +299,36 @@ public String createHyperlink(String displayText, String url) {
return("" + displayText + "");
}
+// /**
+// * Gets an animal's weight as a 9-digit number with trailing zeroes removed.
+// * @param currentContainer The current container.
+// * @param currentUser The current user.
+// * @param animalID The animal ID to check the weight for.
+// * @return A string representing the animal's weight.
+// */
+// public String getWeightFromAnimalID(Container currentContainer, User currentUser, String animalID) {
+// //Gets the full animal weight.
+// ArrayList weightRow = getTableRowAsList(currentContainer, currentUser, "study", "weight", new Sort("-date"), "id", animalID, new String[]{"weight"});
+// if (!weightRow.isEmpty()) {
+// String fullWeight = weightRow.get(0);
+// if (fullWeight != null) {
+// //Gets animal weight rounded to 9 digits.
+// String nineDigitWeight = StringUtils.substring(fullWeight, 0, 9);
+// //Removes any trailing zeroes.
+// BigDecimal strippedValue = new BigDecimal(nineDigitWeight).stripTrailingZeros();
+// //Adds weight symbol.
+// String returnWeight = "" + strippedValue + "kg";
+// return returnWeight;
+// }
+// else {
+// return "";
+// }
+// }
+// else {
+// return "";
+// }
+// }
+
/**
* Gets an animal's weight as a 9-digit number with trailing zeroes removed.
* @param currentContainer The current container.
@@ -307,26 +337,31 @@ public String createHyperlink(String displayText, String url) {
* @return A string representing the animal's weight.
*/
public String getWeightFromAnimalID(Container currentContainer, User currentUser, String animalID) {
- //Gets the full animal weight.
- ArrayList weightRow = getTableRowAsList(currentContainer, currentUser, "study", "weight", new Sort("-date"), "id", animalID, new String[]{"weight"});
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", animalID, CompareType.EQUAL);
+ String[] myColumns = new String[]{"weight"};
+ // Runs query.
+ ArrayList> weightRow = getTableMultiRowMultiColumnWithFieldKeys(currentContainer, currentUser, "study", "weight", new SimpleFilter("id", animalID, CompareType.EQUAL), new Sort("-date"), new String[]{"weight"});
+
+ // Gets the full animal weight.
if (!weightRow.isEmpty()) {
- String fullWeight = weightRow.get(0);
+ String fullWeight = weightRow.get(0).get("weight");
if (fullWeight != null) {
//Gets animal weight rounded to 9 digits.
String nineDigitWeight = StringUtils.substring(fullWeight, 0, 9);
- //Removes any trailing zeroes.
- BigDecimal strippedValue = new BigDecimal(nineDigitWeight).stripTrailingZeros();
- //Adds weight symbol.
- String returnWeight = "" + strippedValue + "kg";
- return returnWeight;
- }
- else {
- return "";
+ if (!fullWeight.isEmpty()) {
+ //Removes any trailing zeroes.
+ BigDecimal strippedValue = new BigDecimal(nineDigitWeight).stripTrailingZeros();
+ //Adds weight symbol.
+ String returnWeight = "" + strippedValue + "kg";
+ return returnWeight;
+ }
+ else {
+ return "";
+ }
}
}
- else {
- return "";
- }
+ return "";
}
/**
@@ -425,6 +460,46 @@ public Boolean checkIfPrenatalID(String idToCheck) {
}
}
+// /**
+// * Gets an animal's sex from their id.
+// * @param c The current container.
+// * @param u The current user.
+// * @param animalID The animal ID to check.
+// * @return A string representing the animal's sex.
+// */
+// public String getSexFromAnimalID(Container c, User u, String animalID) {
+// String animalSexCode = "";
+// String animalSexMeaning = "";
+//
+// //Gets sex from prenatal id.
+// if (checkIfPrenatalID(animalID)) {
+// ArrayList prenatalDeathRow = getTableRowAsList(c, u, "study", "prenatal", null, "id", animalID, new String[]{"gender"});
+// if (!prenatalDeathRow.isEmpty()) {
+// animalSexCode = prenatalDeathRow.get(0);
+// }
+// }
+// //Gets sex from non-prenatal id.
+// else {
+// ArrayList demographicTableRow = getTableRowAsList(c, u, "study", "demographics", null, "id", animalID, new String[]{"gender"});
+// if (!demographicTableRow.isEmpty()) {
+// animalSexCode = demographicTableRow.get(0);
+// }
+// }
+//
+// //Gets the gender meaning from the gender code.
+// if (animalSexCode != null) {
+// if (!animalSexCode.equals("") && !animalSexCode.equals("null")) {
+// ArrayList genderTableRow = getTableRowAsList(c, u, "ehr_lookups", "gender_codes", null, "code", animalSexCode, new String[]{"meaning"});
+// if (!genderTableRow.isEmpty()) {
+// animalSexMeaning = genderTableRow.get(0);
+// }
+// }
+// }
+//
+// //Returns animal sex.
+// return animalSexMeaning;
+// }
+
/**
* Gets an animal's sex from their id.
* @param c The current container.
@@ -438,25 +513,43 @@ public String getSexFromAnimalID(Container c, User u, String animalID) {
//Gets sex from prenatal id.
if (checkIfPrenatalID(animalID)) {
- ArrayList prenatalDeathRow = getTableRowAsList(c, u, "study", "prenatal", null, "id", animalID, new String[]{"gender"});
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", animalID, CompareType.EQUAL);
+ String[] targetColumn = new String[]{"gender"};
+ // Runs query.
+ ArrayList> prenatalDeathRow = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "prenatal", myFilter, null, targetColumn);
+
+ // Checks return data.
if (!prenatalDeathRow.isEmpty()) {
- animalSexCode = prenatalDeathRow.get(0);
+ animalSexCode = prenatalDeathRow.get(0).get("gender");
}
}
//Gets sex from non-prenatal id.
else {
- ArrayList demographicTableRow = getTableRowAsList(c, u, "study", "demographics", null, "id", animalID, new String[]{"gender"});
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", animalID, CompareType.EQUAL);
+ String[] targetColumn = new String[]{"gender"};
+ // Runs query.
+ ArrayList> demographicTableRow = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "demographics", myFilter, null, targetColumn);
+
+ // Checks return data.
if (!demographicTableRow.isEmpty()) {
- animalSexCode = demographicTableRow.get(0);
+ animalSexCode = demographicTableRow.get(0).get("gender");
}
}
//Gets the gender meaning from the gender code.
if (animalSexCode != null) {
if (!animalSexCode.equals("") && !animalSexCode.equals("null")) {
- ArrayList genderTableRow = getTableRowAsList(c, u, "ehr_lookups", "gender_codes", null, "code", animalSexCode, new String[]{"meaning"});
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("code", animalSexCode, CompareType.EQUAL);
+ String[] targetColumn = new String[]{"meaning"};
+ // Runs query.
+ ArrayList> genderTableRow = getTableMultiRowMultiColumnWithFieldKeys(c, u, "ehr_lookups", "gender_codes", myFilter, null, targetColumn);
+
+ // Checks return data.
if (!genderTableRow.isEmpty()) {
- animalSexMeaning = genderTableRow.get(0);
+ animalSexMeaning = genderTableRow.get(0).get("meaning");
}
}
}
@@ -919,198 +1012,7 @@ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck,
- //TODO: Move this to DeathNotificationRevamp.java
- /**
- * This is an object used in the WNPRC DeathNotification.java file that defines all the info presented for a dead animal's necropsy.
- * It contains the following data (returning blank strings for non-existent data):
- * If necropsy exists (true/false).
- * Necropsy case number.
- * Necropsy task id hyperlink.
- * Necropsy date.
- * Necropsy time of death.
- * Necropsy type of death.
- * Necropsy grant number.
- * Necropsy manner of death.
- * Necropsy animal weight.
- * Necropsy animal replacement fee.
- */
- public static class DeathNecropsyObject {
- Boolean necropsyExists = false;
- String necropsyCaseNumber = "";
- String necropsyTaskIdHyperlink = "";
- String necropsyDate = "";
- String necropsyTimeOfDeath = "";
- String necropsyTypeOfDeath = "";
- String necropsyGrantNumber = "";
- String necropsyMannerOfDeath = "";
- String animalWeight = "";
- String animalReplacementFee = "";
-
- public DeathNecropsyObject(Container c, User u, String animalID, String hostName, Boolean withHtmlPlaceHolders) {
- NotificationToolkit notificationToolkit = new NotificationToolkit();
- if (notificationToolkit.getTableRowCount(c, u, "study", "Necropsy", "notificationView") > 0) { //Added this if/else check to getTableRowAsList(), I can remove this after testing.
- String[] targetColumns = {"caseno", "taskid", "date", "timeofdeath", "causeofdeath", "account", "mannerofdeath"};
-
- ArrayList necropsyTableRow = notificationToolkit.getTableRowAsList(c, u, "study", "necropsy", null, "id", animalID, targetColumns);
-
- //Necropsy does exist.
- if (!necropsyTableRow.isEmpty()) {
- this.necropsyExists = true;
- //Gets necropsy data.
- this.necropsyCaseNumber = necropsyTableRow.get(0);
- this.necropsyDate = necropsyTableRow.get(2);
- this.necropsyTimeOfDeath = necropsyTableRow.get(3);
- this.necropsyTypeOfDeath = necropsyTableRow.get(4);
- this.necropsyGrantNumber = necropsyTableRow.get(5);
- this.necropsyMannerOfDeath = necropsyTableRow.get(6);
- this.animalWeight = notificationToolkit.getWeightFromAnimalID(c, u, animalID);
- this.animalReplacementFee = notificationToolkit.getAnimalReplacementFee(c, u, this.necropsyTypeOfDeath, animalID);
-
- //Creates task id with hyperlink.
- String necropsyTaskID = necropsyTableRow.get(1);
- Path taskURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "taskDetails.view");
- String taskUrlAsString = taskURL.toString() + "?formtype=Necropsy&taskid=" + necropsyTaskID;
- String taskRowID = "";
- if (notificationToolkit.getTableRowCount(c, u, "ehr", "tasks", "") > 0) { //Added this if/else check to getTableRowAsList(), I can remove this after testing.
- ArrayList taskRow = notificationToolkit.getTableRowAsList(c, u, "ehr", "tasks", null, "taskid", necropsyTaskID, new String[]{"rowid"});
- if (!taskRow.isEmpty()) {
- taskRowID = taskRow.get(0);
- }
- this.necropsyTaskIdHyperlink = notificationToolkit.createHyperlink(taskRowID, taskUrlAsString);
- }
- }
- }
- if (withHtmlPlaceHolders) {
- String placeholderText = "Not Specified";
- if (this.necropsyCaseNumber == null) {
- this.necropsyCaseNumber = placeholderText;
- }
- else if (this.necropsyCaseNumber.equals("") || this.necropsyCaseNumber.equals("null")) {
- this.necropsyCaseNumber = placeholderText;
- }
- if (this.necropsyTaskIdHyperlink == null) {
- this.necropsyTaskIdHyperlink = placeholderText;
- }
- else if (this.necropsyTaskIdHyperlink.equals("") || this.necropsyTaskIdHyperlink.equals("null")) {
- this.necropsyTaskIdHyperlink = placeholderText;
- }
- if (this.necropsyDate == null) {
- this.necropsyDate = placeholderText;
- }
- else if (this.necropsyDate.equals("") || this.necropsyDate.equals("null")) {
- this.necropsyDate = placeholderText;
- }
- if (this.necropsyTimeOfDeath == null) {
- this.necropsyTimeOfDeath = placeholderText;
- }
- else if (this.necropsyTimeOfDeath.equals("") || this.necropsyTimeOfDeath.equals("null")) {
- this.necropsyTimeOfDeath = placeholderText;
- }
- if (this.necropsyTypeOfDeath == null) {
- this.necropsyTypeOfDeath = placeholderText;
- }
- else if (this.necropsyTypeOfDeath.equals("") || this.necropsyTypeOfDeath.equals("null")) {
- this.necropsyTypeOfDeath = placeholderText;
- }
- if (this.necropsyGrantNumber == null) {
- this.necropsyGrantNumber = placeholderText;
- }
- else if (this.necropsyGrantNumber.equals("") || this.necropsyGrantNumber.equals("null")) {
- this.necropsyGrantNumber = placeholderText;
- }
- if (this.necropsyMannerOfDeath == null) {
- this.necropsyMannerOfDeath = placeholderText;
- }
- else if (this.necropsyMannerOfDeath.equals("") || this.necropsyMannerOfDeath.equals("null")) {
- this.necropsyMannerOfDeath = placeholderText;
- }
- if (this.animalWeight == null) {
- this.animalWeight = placeholderText;
- }
- else if (this.animalWeight.equals("") || this.animalWeight.equals("null")) {
- this.animalWeight = placeholderText;
- }
- if (this.animalReplacementFee == null) {
- this.animalReplacementFee = placeholderText;
- }
- else if (this.animalReplacementFee.equals("") || this.animalReplacementFee.equals("null")) {
- this.animalReplacementFee = placeholderText;
- }
- }
- }
- }
- //TODO: Move this to DeathNotificationRevamp.java
- /**
- * This is an object used in the WNPRC DeathNotification.java file that defines all the info presented for a dead animal's demographics.
- * It contains the following data (returning blank strings for non-existent data):
- * Animal ID hyperlink.
- * Animal sex.
- */
- public static class DeathDemographicObject {
- String animalIdHyperlink = "";
- String animalSex = "";
- String animalDam = "";
- String animalSire = "";
- String animalConception = "";
- public DeathDemographicObject(Container c, User u, String animalID, Boolean withHtmlPlaceHolders) {
- NotificationToolkit notificationToolkit = new NotificationToolkit();
- //Gets hyperlink for animal id in animal history abstract.
- Path animalAbstractURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "animalHistory.view");
- String animalAbstractUrlAsString = animalAbstractURL.toString() + "?#subjects:" + animalID + "&inputType:singleSubject&showReport:1&activeReport:abstract";
- this.animalIdHyperlink = notificationToolkit.createHyperlink(animalID, animalAbstractUrlAsString);
-
- //Gets animal sex.
- String animalsex = notificationToolkit.getSexFromAnimalID(c, u, animalID);
- this.animalSex = animalsex;
-
- //Gets prenatal information if necessary.
- if (notificationToolkit.checkIfPrenatalID(animalID)) {
- ArrayList prenatalDeathRow = notificationToolkit.getTableRowAsList(c, u, "study", "prenatal", null, "id", animalID, new String[]{"dam", "sire", "conception"});
- if (!prenatalDeathRow.isEmpty())
- {
- this.animalDam = prenatalDeathRow.get(0);
- this.animalSire = prenatalDeathRow.get(1);
- this.animalConception = prenatalDeathRow.get(2);
- }
- }
-
- //Adds HTML placeholders for empty fields.
- if (withHtmlPlaceHolders) {
- String placeholderText = "Not Specified";
- if (this.animalIdHyperlink == null) {
- this.animalIdHyperlink = placeholderText;
- }
- else if (this.animalIdHyperlink.equals("") || this.animalIdHyperlink.equals("null")) {
- this.animalIdHyperlink = placeholderText;
- }
- if (this.animalSex == null) {
- this.animalSex = placeholderText;
- }
- else if (this.animalSex.equals("") || this.animalSex.equals("null")) {
- this.animalSex = placeholderText;
- }
- if (this.animalDam == null) {
- this.animalDam = placeholderText;
- }
- else if (this.animalDam.equals("") || this.animalDam.equals("null")) {
- this.animalDam = placeholderText;
- }
- if (this.animalSire == null) {
- this.animalSire = placeholderText;
- }
- else if (this.animalSire.equals("") || this.animalSire.equals("null")) {
- this.animalSire = placeholderText;
- }
- if (this.animalConception == null) {
- this.animalConception = placeholderText;
- }
- else if (this.animalConception.equals("") || this.animalConception.equals("null")) {
- this.animalConception = placeholderText;
- }
- }
- }
- }
/**
* This is an object representation of a custom QView file.
From cb1aa1aaa85a3238af68d18a0f50f50dd2fd19f0 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 8 Aug 2024 10:26:35 -0500
Subject: [PATCH 10/29] Removed automated tests that don't aren't finished.
---
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 396 ------------------
1 file changed, 396 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index b84a83477..093511b0f 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -266,8 +266,6 @@ public static void doSetup() throws Exception
initTest.populateInitialData();
initTest.createEHRLookupsLinkedSchemaQueryValidation();
-// initTest.notificationRevampSetup();
-
initTest.initCreatedProject();
initTest.uploadBillingDataAndVerify();
@@ -284,7 +282,6 @@ public static void doSetup() throws Exception
initTest.checkUpdateProgramIncomeAccount();
-// initTest.deathNotificationSetup();
}
private void billingSetup() throws Exception
@@ -3462,97 +3459,6 @@ private void checkUpdateProgramIncomeAccount() throws UnhandledAlertException
log("Completed updateProgramIncomeAccountWithValidPermissions.");
}
-// @Test
-// public void testJavaDeathNotification() throws UnhandledAlertException {
-// log("Started testJavaDeathNotification.");
-// //Navigates to the Necropsies table.
-// beginAt(buildURL("project", getContainerPath(), "begin"));
-// beginAt("/ehr/" + getContainerPath() + "/datasets.view");
-// waitForText("Necropsies");
-// waitAndClickAndWait(LabModuleHelper.getNavPanelItem("Necropsies:", VIEW_TEXT));
-//
-// //Views data from the most recent necropsy.
-// DataRegionTable dr = new DataRegionTable("query", getDriver());
-// dr.clickRowDetails(0);
-//
-// //Saves data from most recent necropsy.
-// String necropsyIDHyperlink = Ext4FieldRef.getForLabel(this, "Id").getValue().toString();
-// int idFrom = necropsyIDHyperlink.indexOf("new\">") + "new\">".length();
-// int idTo = necropsyIDHyperlink.lastIndexOf("");
-// String necropsyID = necropsyIDHyperlink.substring(idFrom, idTo);
-// String necropsyDate = Ext4FieldRef.getForLabel(this, "Necropsy Date").getValue().toString();
-// String necropsyCaseNumber = Ext4FieldRef.getForLabel(this, "Case Number").getValue().toString();
-// String necropsyAccount = Ext4FieldRef.getForLabel(this, "Account").getValue().toString();
-//
-// //Runs death notification in the browser.
-// EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
-// EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
-// waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.DeathNotificationRevamp").withText("Run Report In Browser"));
-//
-// //Validates necessary info.
-// assertTextPresent("Animal ID:", necropsyID);
-// assertTextPresent("Necropsy Case Number:", necropsyCaseNumber);
-// assertTextPresent("Date of Necropsy:", necropsyDate);
-// assertTextPresent("Grant #:", necropsyAccount);
-// log("Completed testJavaDeathNotification.");
-// }
-
-// @Test
-// public void testJavaPrenatalDeathNotification() throws UnhandledAlertException {
-// log("Started testJavaPrenatalDeathNotification.");
-// //Navigates to the "Enter Prenatal Death" page.
-// beginAt(buildURL("project", getContainerPath(), "begin"));
-// waitAndClickAndWait(Locator.tagContainingText("a", "Enter Data"));
-// waitAndClickAndWait(Locator.tagContainingText("a", "Enter Prenatal Death"));
-//
-// //Enters Prenatal Death record.
-// _helper.setDataEntryField("Id", "pd9876");
-// log("Attempting to select combo box item: female");
-// _extHelper.selectComboBoxItem("Gender:", "female" + "\u00A0");
-// log("Successfully selected combo box item: female");
-// click(Locator.buttonContainingText("Force Submit"));
-// clickAndWait(Locator.buttonContainingText("Yes"));
-//
-// //Navigates to dumbster.
-// goToModule("Dumbster");
-// assertTextPresent("Prenatal Death Notification: pd9876");
-// log("Completed testJavaPrenatalDeathNotification.");
-// }
-
- private void deathNotificationSetup() throws UnhandledAlertException {
- log("Starting deathNotificationSetup.");
- //Navigates to home to get a fresh start.
- beginAt(buildURL("project", getContainerPath(), "begin"));
-
- //Navigates to admin notifications page.
- EHRAdminPage ehrAdminPage = EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
-
- //Updates the notification user and reply email.
- notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
-
- //Enables all notification that we will be testing.
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.DeathNotificationRevamp");
-
- //Adds notification recipients.
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.DeathNotification", "EHR Administrators");
-
- //Enables dumbster.
- _containerHelper.enableModules(Arrays.asList("Dumbster"));
-
- //Enable LDK Site Notification
- beginAt(buildURL("ldk", "notificationSiteAdmin"));
- waitForText("Notification Site Admin");
- click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
- click(Locator.tagWithText("li", "Enabled"));
- click(Locator.tagWithText("span", "Save"));
- waitForText("Success");
- clickButtonContainingText("OK");
- waitForText("Notification Site Admin");
-
- log("Completed deathNotificationSetup.");
- }
-
@Test
public void testReactGridPanel() throws UnhandledAlertException {
log("Starting testReactGridPanel.");
@@ -3945,306 +3851,4 @@ public void testAssignmentApi() throws Exception
}
- // NOTIFICATION REVAMP: NEW FUNCTIONS
-
- @Test
- public void notificationRevampTestBloodDrawsTodayAll() throws UnhandledAlertException, IOException, CommandException {
- // Setup
- log("Starting notification revamp test: Blood Draws Today (All)");
- ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
-
- // Navigates to home to get a fresh start.
- myReusableFunctions.goHome();
-
- // Creates test data.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId1", true, new Date(), true, Double.valueOf(-1), true); // Testing for available blood OVER the limit.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId2", true, new Date(), true, 0.1, true); // Testing for available blood NEAR the limit.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId3", true, new Date(), false, 2.0, true); // Testing for "NOT ASSIGNED" project status.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId4", true, new Date(), true, 2.0, false); // Testing for "INCOMPLETE" draw status.
-
- // Runs test email in the browser.
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
- waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAll").withText("Run Report In Browser"));
-
- // Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayAllId1' has a red colored cell.
- // TODO: Assert ID: 'bloodDrawsTodayAllId2' has an orange colored cell.
- // TODO: Assert ID: 'bloodDrawsTodayAllId3' has the text 'NOT ASSIGNED' present in the row.
- // TODO: Assert ID: 'bloodDrawsTodayAllId4' has the text 'INCOMPLETE' present in the row.
-
- // Finishes test.
- log("Completed notification revamp test: Blood Draws Today (All)");
-
-// assertTextPresent("Animal ID:", necropsyID);
-// assertTextPresent("Necropsy Case Number:", necropsyCaseNumber);
-// assertTextPresent("Date of Necropsy:", necropsyDate);
-// assertTextPresent("Grant #:", necropsyAccount);
-// log("Completed testJavaDeathNotification.");
- }
-
- public void notificationRevampTestBloodDrawsTodayAnimalCare() throws UnhandledAlertException, IOException, CommandException {
- // Setup
- log("Starting notification revamp test: Blood Draws Today (Animal Care)");
- ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
-
- // Navigates to home to get a fresh start.
- myReusableFunctions.goHome();
-
- // Creates test data.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("animalCare", "bloodDrawsTodayAnimalCareId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Animal Care.
-
- // Runs test email in the browser.
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
- waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAnimalCare").withText("Run Report In Browser"));
-
- // Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayAnimalCareId1' exists.
-
- // Finishes test.
- log("Completed notification revamp test: Blood Draws Today (Animal Care)");
- }
-
- public void notificationRevampTestBloodDrawsTodayVetStaff() throws UnhandledAlertException, IOException, CommandException {
- // Setup
- log("Starting notification revamp test: Blood Draws Today (Vet Staff)");
- ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
-
- // Navigates to home to get a fresh start.
- myReusableFunctions.goHome();
-
- // Creates test data.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawsTodayVetStaffId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Vet Staff.
-
- // Runs test email in the browser.
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
- waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayVetStaff").withText("Run Report In Browser"));
-
- // Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayVetStaffId1' exists.
-
- // Finishes test.
- log("Completed notification revamp test: Blood Draws Today (Vet Staff)");
- }
-
- public void notificationRevampTestBloodDrawReviewDailyNotification() throws UnhandledAlertException, IOException, CommandException {
- // Setup
- log("Starting notification revamp test: Blood Draw Review (Daily)");
- ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
- // Creates tomorrow's date.
- Calendar todayCalendar = Calendar.getInstance();
- todayCalendar.add(Calendar.DATE, 1);
- Date dateTomorrow = todayCalendar.getTime();
-
- // Navigates to home to get a fresh start.
- myReusableFunctions.goHome();
-
- // Creates test data.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId1", false, new Date(), true, Double.valueOf(2.0), false); // Testing for blood scheduled for today with a dead anima.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId2", true, dateTomorrow, false, Double.valueOf(2.0), false); // Testing for blood scheduled for tomorrow with an animal not assigned to a project.
-
- // Runs test email in the browser.
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
- waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawReviewDailyNotification").withText("Run Report In Browser"));
-
- // Validates necessary info.
- // TODO: Assert ID: 'bloodDrawReviewDailyId1' exists.
- // TODO: Assert ID: 'bloodDrawReviewDailyId2' exists.
-
- // Finishes test.
- log("Completed notification revamp test: Blood Draw Review (Daily)");
- }
-
- public void notificationRevampTestBloodDrawReviewTriggerNotification() throws UnhandledAlertException, IOException, CommandException {
- // TODO. For this one, check what the id is for the 'run in browser - testing id', then update the DB with this info. Or should I send it and try using dumbster?
- }
-
- @Test
- public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
- // Set up.
- log("Starting notificationRevampSetup()");
- ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
-
- // Navigates to home to get a fresh start.
- myReusableFunctions.goHome();
-
- // Navigates to admin notifications page.
- EHRAdminPage ehrAdminPage = EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
- NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
- // Updates the notification user and reply email.
- notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
- // Enables all notification that we will be testing.
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll"); //TODO: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
- // Adds notification recipients.
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
- // Enables dumbster.
- _containerHelper.enableModules(Arrays.asList("Dumbster"));
- // Enable LDK Site Notification
- beginAt(buildURL("ldk", "notificationSiteAdmin"));
- waitForText("Notification Site Admin");
- click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
- click(Locator.tagWithText("li", "Enabled"));
- click(Locator.tagWithText("span", "Save"));
- waitForText("Success");
- clickButtonContainingText("OK");
- waitForText("Notification Site Admin");
-
- // Creates billing groups for testing.
- myReusableFunctions.insertValueIntoBloodBilledByDataset("animalCare", "Animal Care");
- myReusableFunctions.insertValueIntoBloodBilledByDataset("vetStaff", "Vet Staff");
- myReusableFunctions.insertValueIntoBloodBilledByDataset("spi", "SPI");
-
- // Logs completion.
- log("Completed notificationRevampSetup()");
-
- // Runs tests.
- notificationRevampTestBloodDrawsTodayAll();
- notificationRevampTestBloodDrawsTodayAnimalCare();
- notificationRevampTestBloodDrawsTodayVetStaff();
- notificationRevampTestBloodDrawReviewDailyNotification();
- notificationRevampTestBloodDrawReviewTriggerNotification();
-
-
-
-
-
- // Uploads data for notification: Admin Alerts
-
- // Uploads data for notification: Animal Request
-
- // Uploads data for notification: Blood Draws Today (All)
-
- // Uploads data for notification: Blood Draws Today (Animal Care)
-
- // Uploads data for notification: Blood Draws Today (Vet Staff)
-
- // Uploads data for notification: Blood Draw Review (Daily)
-
- // Uploads data for notification: Blood Draw Review (Trigger)
-
- // Uploads data for notification: Colony Alerts
-
- // Uploads data for notification: Colony Alerts (Lite)
-
- // Uploads data for notification: Colony Management
-
- // Uploads data for notification: Death
-
- // Uploads data for notification: Prenatal Death
- }
-
- public class ReusableTestFunctions {
-
- public void goHome() {
- beginAt(buildURL("project", getContainerPath(), "begin"));
- }
-
- public void insertValueIntoDataset(String schemaName, String queryName, HashMap valuesToInsert) throws IOException, CommandException {
- log("Inserting values into dataset.\n" +
- "Schema Name: " + schemaName + "\n" +
- "Query Name: " + queryName + "\n" +
- "Values: " + valuesToInsert);
-
- //TODO: Which one to use?
- Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
-// Connection cn = WebTestHelper.getRemoteApiConnection();
-
- // Gets dataset to update.
- InsertRowsCommand insertCmd = new InsertRowsCommand(schemaName, queryName);
-
- // Creates values to insert.
- insertCmd.addRow(valuesToInsert);
-
- // Inserts rows into dataset.
- insertCmd.execute(cn, EHR_FOLDER_PATH);
-
- }
-
- public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, String billingGroupDisplayName) throws IOException, CommandException
- {
- HashMap billingGroupTestData = new HashMap<>();
- billingGroupTestData.put("value", billingGroupRealName);
- billingGroupTestData.put("title", billingGroupDisplayName);
- insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
- }
-
- /**
- * This function inserts data into the 'study/BloodSchedule' dataset.
- * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/AvailBlood, billedby/title, and Id/DataSet/Demographics/calculated_status.
- * This function updates the following tables: study/demographics, study/weight, study/blood.
- * @param billingGroupRealName
- * @param animalID
- * @param animalAlive
- * @param projectAssigned
- * @param animalWeight
- * @throws IOException
- * @throws CommandException
- */
- public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, String animalID, Boolean animalAlive, Date drawDate, Boolean projectAssigned, Double animalWeight, Boolean drawCompleted) throws IOException, CommandException {
- // Creates data to pass in.
- String livingStatus = "Dead";
- if (animalAlive) {
- livingStatus = "Alive";
- }
- Integer assignmentStatus = null;
- if (projectAssigned) {
- assignmentStatus = 300901;
- }
- Integer completionStatus = getQCStateRowID("In Progress");
- if (drawCompleted) {
- completionStatus = getQCStateRowID("Completed");
- }
-
- // Creates demographic info (this updates the bloodSchedule field: 'Id/DataSet/Demographics/calculated_status').
- HashMap demographicInfoTestData1 = new HashMap<>();
- demographicInfoTestData1.put("id", animalID);
- demographicInfoTestData1.put("calculated_status", livingStatus);
- // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood').
- HashMap weightTestData1 = new HashMap<>();
- weightTestData1.put("id", animalID);
- weightTestData1.put("date", new Date());
- weightTestData1.put("weight", animalWeight);
- // Creates blood info (this updates the bloodSchedule fields: 'id', 'date', 'projectStatus', 'billedby/title', and QCState/label).
- HashMap bloodTestData1 = new HashMap<>();
- bloodTestData1.put("id", animalID);
- bloodTestData1.put("date", drawDate);
- bloodTestData1.put("project", assignmentStatus);
- bloodTestData1.put("billedBy", billingGroupRealName);
- bloodTestData1.put("QCState", completionStatus);
-
- // Inserts data.
- insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
- insertValueIntoDataset("study", "blood", bloodTestData1);
- insertValueIntoDataset("study", "weight", weightTestData1);
-
- // TODO: The following fields are not included. Make sure test still runs correctly.
- // Id/curLocation/room
- // Id/curLocation/area
- }
-
- public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
- // Retrieves QCState table.
- Connection cn = createDefaultConnection();
- SelectRowsCommand cmd = new SelectRowsCommand("core", "QCState");
- cmd.setRequiredVersion(9.1); // Not sure what this does, but it was used in 'fetchWeightData()'.
- cmd.setColumns(Arrays.asList("RowId", "Label"));
- cmd.setMaxRows(100);
- SelectRowsResponse r = cmd.execute(cn, EHR_FOLDER_PATH);
-
- // Goes through each QCState in the table and returns the rowID of the row matching the passed-in QCState.
- for (Map currentRow : r.getRows()) {
- String rowLabel = ((HashMap) currentRow.get("Label")).get("value").toString();
- Integer rowID = Integer.valueOf(((HashMap) currentRow.get("RowId")).get("value").toString());
- if (rowLabel.equals(qcStateLabel)) {
- return rowID;
- }
- }
- return null;
- }
-
- }
-
}
\ No newline at end of file
From 12e34ee8040c79c66bb1515e0596b1055f3f2e30 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 8 Aug 2024 17:04:01 -0500
Subject: [PATCH 11/29] Added 2 new functions to NotificationToolkit for
creating URL's. This is to avoid hardcoding URL's per new LabKey policy.
Implimented these 2 new functions in DeathNotificationRevamp.java for getting
the necropsy and animal abstract URL's.
---
.../notification/DeathNotificationRevamp.java | 9 ++----
.../notification/NotificationToolkit.java | 32 +++++++++++++++++++
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
index 0e56bd63c..40d5c50d0 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
@@ -209,10 +209,9 @@ public DeathNecropsyObject(Container c, User u, String animalID, Boolean withHtm
this.animalWeight = notificationToolkit.getWeightFromAnimalID(c, u, animalID);
this.animalReplacementFee = notificationToolkit.getAnimalReplacementFee(c, u, this.necropsyTypeOfDeath, animalID);
- //Creates task id with hyperlink. // TODO: Don't use hardcoded URL here.
+ //Creates task id with hyperlink.
String necropsyTaskID = animalNecropsy.get(0).get("taskid");
- Path taskURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "taskDetails.view");
- String taskUrlAsString = taskURL.toString() + "?formtype=Necropsy&taskid=" + necropsyTaskID;
+ String taskUrlAsString = notificationToolkit.createFormURL(c, "necropsy", necropsyTaskID);
// Creates filter.
SimpleFilter myTaskFilter = new SimpleFilter("taskid", necropsyTaskID, CompareType.EQUAL);
@@ -366,10 +365,8 @@ public static class DeathDemographicObject {
public DeathDemographicObject(Container c, User u, String animalID, Boolean withHtmlPlaceHolders) {
NotificationToolkit notificationToolkit = new NotificationToolkit();
- // TODO: Update this to remove hardcoded url.
//Gets hyperlink for animal id in animal history abstract.
- Path animalAbstractURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "animalHistory.view");
- String animalAbstractUrlAsString = animalAbstractURL.toString() + "?#subjects:" + animalID + "&inputType:singleSubject&showReport:1&activeReport:abstract";
+ String animalAbstractUrlAsString = notificationToolkit.createAnimalHistoryURL(c, animalID);
this.animalIdHyperlink = notificationToolkit.createHyperlink(animalID, animalAbstractUrlAsString);
//Gets animal sex.
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index 5bcb3611d..159891a21 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -920,6 +920,38 @@ else if (currentClause instanceof SimpleFilter.InClause) {
return returnURL.toString();
}
+ public String createFormURL(Container c, String formType, String taskID) {
+ // Creates URL.
+ ActionURL formURL = new ActionURL();
+ formURL = new ActionURL("ehr", "taskDetails.view", c);
+ formURL.addParameter("formType", formType);
+ formURL.addParameter("taskid", taskID);
+
+ // Creates path.
+ Path returnURL = new Path(new ActionURL().getBaseServerURI(), formURL.toString());
+
+ // Returns URL.
+ return returnURL.toString();
+ }
+
+ public String createAnimalHistoryURL(Container c, String subject) {
+ // Creates URL.
+ ActionURL animalHistoryURL = new ActionURL();
+ animalHistoryURL = new ActionURL("ehr", "animalHistory.view", c);
+ String animalHistoryURLWithID = animalHistoryURL.toString() + "#subjects:" + subject; // TODO: Try and get commented code below to work instaed of hardcoding this. For some reason, adding parameter gives me '#subjects=' instead of '#subjects:'.
+
+// animalHistoryURL.addParameter("#subjects", subject);
+// animalHistoryURL.addParameter("inputType", "singleSubject");
+// animalHistoryURL.addParameter("showReport", "0");
+// animalHistoryURL.addParameter("activeReport", "abstract");
+
+ // Creates path.
+ Path returnURL = new Path(new ActionURL().getBaseServerURI(), animalHistoryURLWithID);
+
+ // Returns URL.
+ return returnURL.toString();
+ }
+
// TODO: COMMENT!!!
public Boolean checkIfAnimalIsAlive(Container c, User u, String idToCheck) {
try {
From 90a923bc9bfb983fe9e60f3212186410b6d58b2a Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 16 Aug 2024 12:01:28 -0500
Subject: [PATCH 12/29] Adding automated tests for notifications.
---
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 308 +++++++++++++++++-
1 file changed, 304 insertions(+), 4 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 093511b0f..3de243834 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -268,6 +268,8 @@ public static void doSetup() throws Exception
initTest.initCreatedProject();
+ initTest.notificationRevampSetup();
+
initTest.uploadBillingDataAndVerify();
// Blood triggers are dependent on weights, so the blood sample data has to be imported after weights. Doing this after
@@ -3378,7 +3380,6 @@ protected String getAnimalHistoryPath()
}
- @Test
public void navigateToBillingContainerWithInvalidPermissions() {
//This test verifies a user cannot access the Finance>Internal page without proper permissions.
@@ -3394,7 +3395,6 @@ public void navigateToBillingContainerWithInvalidPermissions() {
stopImpersonating();
}
- @Test
public void updateProgramIncomeAccountWithInvalidPermissions() throws UnhandledAlertException {
//This test verifies a user cannot update the CreditToAccount module property without proper permissions.
@@ -3413,7 +3413,6 @@ public void updateProgramIncomeAccountWithInvalidPermissions() throws UnhandledA
stopImpersonating();
}
- @Test
public void updateProgramIncomeAccountWithValidPermissions() throws UnhandledAlertException {
//This test verifies a user can update the CreditToAccount module property with proper permissions.
@@ -3445,7 +3444,8 @@ public void updateProgramIncomeAccountWithValidPermissions() throws UnhandledAle
}
- private void checkUpdateProgramIncomeAccount() throws UnhandledAlertException
+ @Test
+ public void checkUpdateProgramIncomeAccount() throws UnhandledAlertException
{
log("Starting checkUpdateProgramIncomeAccount.");
@@ -3851,4 +3851,304 @@ public void testAssignmentApi() throws Exception
}
+ // NOTIFICATION REVAMP: NEW FUNCTIONS START
+ public void notificationRevampTestBloodDrawsTodayAll() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (All)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId1", true, new Date(), true, Double.valueOf(-1), true); // Testing for available blood OVER the limit.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId2", true, new Date(), true, 0.1, true); // Testing for available blood NEAR the limit.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId3", true, new Date(), false, 2.0, true); // Testing for "NOT ASSIGNED" project status.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "bloodDrawsTodayAllId4", true, new Date(), true, 2.0, false); // Testing for "INCOMPLETE" draw status.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAll").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId1' has a red colored cell.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId2' has an orange colored cell.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId3' has the text 'NOT ASSIGNED' present in the row.
+ // TODO: Assert ID: 'bloodDrawsTodayAllId4' has the text 'INCOMPLETE' present in the row.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (All)");
+
+// assertTextPresent("Animal ID:", necropsyID);
+// assertTextPresent("Necropsy Case Number:", necropsyCaseNumber);
+// assertTextPresent("Date of Necropsy:", necropsyDate);
+// assertTextPresent("Grant #:", necropsyAccount);
+// log("Completed testJavaDeathNotification.");
+ }
+
+ public void notificationRevampTestBloodDrawsTodayAnimalCare() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (Animal Care)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("animalCare", "bloodDrawsTodayAnimalCareId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Animal Care.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAnimalCare").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayAnimalCareId1' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (Animal Care)");
+ }
+
+ public void notificationRevampTestBloodDrawsTodayVetStaff() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draws Today (Vet Staff)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawsTodayVetStaffId1", true, new Date(), true, Double.valueOf(2.0), true); // Testing for blood draw assigned to Vet Staff.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayVetStaff").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawsTodayVetStaffId1' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draws Today (Vet Staff)");
+ }
+
+ public void notificationRevampTestBloodDrawReviewDailyNotification() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Blood Draw Review (Daily)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+ // Creates tomorrow's date.
+ Calendar todayCalendar = Calendar.getInstance();
+ todayCalendar.add(Calendar.DATE, 1);
+ Date dateTomorrow = todayCalendar.getTime();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId1", false, new Date(), true, Double.valueOf(2.0), false); // Testing for blood scheduled for today with a dead anima.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId2", true, dateTomorrow, false, Double.valueOf(2.0), false); // Testing for blood scheduled for tomorrow with an animal not assigned to a project.
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawReviewDailyNotification").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // TODO: Assert ID: 'bloodDrawReviewDailyId1' exists.
+ // TODO: Assert ID: 'bloodDrawReviewDailyId2' exists.
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draw Review (Daily)");
+ }
+
+ public void notificationRevampTestBloodDrawReviewTriggerNotification() throws UnhandledAlertException, IOException, CommandException {
+ // TODO. For this one, check what the id is for the 'run in browser - testing id', then update the DB with this info. Or should I send it and try using dumbster?
+ }
+
+ @Test
+ public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
+ // Set up.
+ log("Starting notificationRevampSetup()");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Navigates to admin notifications page.
+ EHRAdminPage ehrAdminPage = EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
+ // Updates the notification user and reply email.
+ notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
+ // Enables all notification that we will be testing.
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll"); //TODO: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
+ // Adds notification recipients.
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
+ // Enables dumbster.
+ _containerHelper.enableModules(Arrays.asList("Dumbster"));
+ // Enable LDK Site Notification
+ beginAt(buildURL("ldk", "notificationSiteAdmin"));
+ waitForText("Notification Site Admin");
+ click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
+ click(Locator.tagWithText("li", "Enabled"));
+ click(Locator.tagWithText("span", "Save"));
+ waitForText("Success");
+ clickButtonContainingText("OK");
+ waitForText("Notification Site Admin");
+
+ // Creates billing groups for testing.
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("animalCare", "Animal Care");
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("vetStaff", "Vet Staff");
+ myReusableFunctions.insertValueIntoBloodBilledByDataset("spi", "SPI");
+
+ // Logs completion.
+ log("Completed notificationRevampSetup()");
+
+ // Runs tests.
+ notificationRevampTestBloodDrawsTodayAll();
+ notificationRevampTestBloodDrawsTodayAnimalCare();
+ notificationRevampTestBloodDrawsTodayVetStaff();
+ notificationRevampTestBloodDrawReviewDailyNotification();
+ notificationRevampTestBloodDrawReviewTriggerNotification();
+
+
+
+
+
+ // Uploads data for notification: Admin Alerts
+
+ // Uploads data for notification: Animal Request
+
+ // Uploads data for notification: Blood Draws Today (All)
+
+ // Uploads data for notification: Blood Draws Today (Animal Care)
+
+ // Uploads data for notification: Blood Draws Today (Vet Staff)
+
+ // Uploads data for notification: Blood Draw Review (Daily)
+
+ // Uploads data for notification: Blood Draw Review (Trigger)
+
+ // Uploads data for notification: Colony Alerts
+
+ // Uploads data for notification: Colony Alerts (Lite)
+
+ // Uploads data for notification: Colony Management
+
+ // Uploads data for notification: Death
+
+ // Uploads data for notification: Prenatal Death
+ }
+
+ public class ReusableTestFunctions {
+
+ public void goHome() {
+ beginAt(buildURL("project", getContainerPath(), "begin"));
+ }
+
+ public void insertValueIntoDataset(String schemaName, String queryName, HashMap valuesToInsert) throws IOException, CommandException {
+ log("Inserting values into dataset.\n" +
+ "Schema Name: " + schemaName + "\n" +
+ "Query Name: " + queryName + "\n" +
+ "Values: " + valuesToInsert);
+
+ //TODO: Which one to use?
+ Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
+// Connection cn = WebTestHelper.getRemoteApiConnection();
+
+ // Gets dataset to update.
+ InsertRowsCommand insertCmd = new InsertRowsCommand(schemaName, queryName);
+
+ // Creates values to insert.
+ insertCmd.addRow(valuesToInsert);
+
+ // Inserts rows into dataset.
+ insertCmd.execute(cn, EHR_FOLDER_PATH);
+
+ }
+
+ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, String billingGroupDisplayName) throws IOException, CommandException
+ {
+ HashMap billingGroupTestData = new HashMap<>();
+ billingGroupTestData.put("value", billingGroupRealName);
+ billingGroupTestData.put("title", billingGroupDisplayName);
+ insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
+ }
+
+ /**
+ * This function inserts data into the 'study/BloodSchedule' dataset.
+ * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/AvailBlood, billedby/title, and Id/DataSet/Demographics/calculated_status.
+ * This function updates the following tables: study/demographics, study/weight, study/blood.
+ * @param billingGroupRealName
+ * @param animalID
+ * @param animalAlive
+ * @param projectAssigned
+ * @param animalWeight
+ * @throws IOException
+ * @throws CommandException
+ */
+ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, String animalID, Boolean animalAlive, Date drawDate, Boolean projectAssigned, Double animalWeight, Boolean drawCompleted) throws IOException, CommandException {
+ // Creates data to pass in.
+ String livingStatus = "Dead";
+ if (animalAlive) {
+ livingStatus = "Alive";
+ }
+ Integer assignmentStatus = null;
+ if (projectAssigned) {
+ assignmentStatus = 300901;
+ }
+ Integer completionStatus = getQCStateRowID("In Progress");
+ if (drawCompleted) {
+ completionStatus = getQCStateRowID("Completed");
+ }
+
+ // Creates demographic info (this updates the bloodSchedule field: 'Id/DataSet/Demographics/calculated_status').
+ HashMap demographicInfoTestData1 = new HashMap<>();
+ demographicInfoTestData1.put("id", animalID);
+ demographicInfoTestData1.put("calculated_status", livingStatus);
+ // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood').
+ HashMap weightTestData1 = new HashMap<>();
+ weightTestData1.put("id", animalID);
+ weightTestData1.put("date", new Date());
+ weightTestData1.put("weight", animalWeight);
+ // Creates blood info (this updates the bloodSchedule fields: 'id', 'date', 'projectStatus', 'billedby/title', and QCState/label).
+ HashMap bloodTestData1 = new HashMap<>();
+ bloodTestData1.put("id", animalID);
+ bloodTestData1.put("date", drawDate);
+ bloodTestData1.put("project", assignmentStatus);
+ bloodTestData1.put("billedBy", billingGroupRealName);
+ bloodTestData1.put("QCState", completionStatus);
+
+ // Inserts data.
+ insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
+ insertValueIntoDataset("study", "blood", bloodTestData1);
+ insertValueIntoDataset("study", "weight", weightTestData1);
+
+ // TODO: The following fields are not included. Make sure test still runs correctly.
+ // Id/curLocation/room
+ // Id/curLocation/area
+ }
+
+ public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
+ // Retrieves QCState table.
+ Connection cn = createDefaultConnection();
+ SelectRowsCommand cmd = new SelectRowsCommand("core", "QCState");
+ cmd.setRequiredVersion(9.1); // Not sure what this does, but it was used in 'fetchWeightData()'.
+ cmd.setColumns(Arrays.asList("RowId", "Label"));
+ cmd.setMaxRows(100);
+ SelectRowsResponse r = cmd.execute(cn, EHR_FOLDER_PATH);
+
+ // Goes through each QCState in the table and returns the rowID of the row matching the passed-in QCState.
+ for (Map currentRow : r.getRows()) {
+ String rowLabel = ((HashMap) currentRow.get("Label")).get("value").toString();
+ Integer rowID = Integer.valueOf(((HashMap) currentRow.get("RowId")).get("value").toString());
+ if (rowLabel.equals(qcStateLabel)) {
+ return rowID;
+ }
+ }
+ return null;
+ }
+
+ }
+
}
\ No newline at end of file
From feb43b84e1d205dd4bc043e34dc71da137d5a384 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 28 Aug 2024 15:18:07 -0500
Subject: [PATCH 13/29] - WNPRC_EHRTest.java: Added notification setup
function, multiple notification check functions, and a toolkit object
containing reusable test functions that are commonly used when writing
different tests. - BloodOverdrawTriggerNotification.java &
BloodDrawReviewTriggerNotification.java: Added a reset function to clear the
data after notification is triggered. This is because there are null checks
that don't work when artifacts are left over from previous instances. -
NotificationToolkit.java: Added null check to checkIfBloodDrawIsOverdraw()
because empty data was crashing the function.
---
.../BloodDrawReviewTriggerNotification.java | 10 ++
.../BloodOverdrawTriggerNotification.java | 7 +-
.../notification/NotificationToolkit.java | 8 +-
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 140 +++++++++++-------
4 files changed, 109 insertions(+), 56 deletions(-)
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 7d3abad54..ac69ed8c7 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewTriggerNotification.java
@@ -129,20 +129,30 @@ public String getMessageBodyHTML(Container c, User u) {
LocalDate drawDateWithoutTime = formattedDrawDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate todaysDateWithoutTime = dateToolkit.getDateToday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
if (drawDateWithoutTime.equals(todaysDateWithoutTime)) {
+ this.resetClass();
return messageBody.toString();
}
else {
+ this.resetClass();
return null;
}
}
catch(Exception e) {
_log.error("Error executing BloodDrawReviewTriggerNotification->getMessageBodyHTML(). Could not format date of blood draw into Date().", e);
+ this.resetClass();
return null;
}
}
else {
+ this.resetClass();
return null;
}
}
+ public void resetClass() {
+ this.animalIdToCheck = null;
+ this.projectToCheck = null;
+ this.drawDateToCheck = null;
+ }
+
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
index 823d59ce4..5321e8f67 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodOverdrawTriggerNotification.java
@@ -100,15 +100,20 @@ public String getMessageBodyHTML(Container c, User u) {
messageBody.append("Available blood: " + overdrawAmount + "
");
// Returns message info.
+ this.resetClass();
return messageBody.toString();
}
// Sends no message if there is no overdraw.
else {
+ this.resetClass();
return null;
}
}
-
+ public void resetClass() {
+ this.animalID = null;
+ this.drawDate = null;
+ }
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index 159891a21..a2882634a 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -1032,9 +1032,11 @@ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck,
// Checks results.
if (!returnArray.isEmpty()) {
for (HashMap result : returnArray) {
- Double availableBlood = Double.valueOf(result.get("BloodRemaining/AvailBlood"));
- if (availableBlood <=0) {
- return availableBlood;
+ if (!result.get("BloodRemaining/AvailBlood").isEmpty()) {
+ Double availableBlood = Double.valueOf(result.get("BloodRemaining/AvailBlood"));
+ if (availableBlood <=0) {
+ return availableBlood;
+ }
}
}
}
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 3de243834..5becdcffd 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -3872,19 +3872,17 @@ public void notificationRevampTestBloodDrawsTodayAll() throws UnhandledAlertExce
waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAll").withText("Run Report In Browser"));
// Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayAllId1' has a red colored cell.
- // TODO: Assert ID: 'bloodDrawsTodayAllId2' has an orange colored cell.
- // TODO: Assert ID: 'bloodDrawsTodayAllId3' has the text 'NOT ASSIGNED' present in the row.
- // TODO: Assert ID: 'bloodDrawsTodayAllId4' has the text 'INCOMPLETE' present in the row.
+ // Verifies a red cell exists (for blood remaining < 0).
+ assertElementVisible(Locator.tagWithAttributeContaining("td", "bgcolor", "red"));
+ // Verifies an orange cell exists (for blood remaining < bloodDrawLimit).
+ assertElementVisible(Locator.tagWithAttributeContaining("td", "bgcolor", "orange"));
+ // Verifies an incomplete cell exists (for blood not yet drawn).
+ assertElementVisible(Locator.tagContainingText("td", "INCOMPLETE"));
+ // Verifies an unassigned cell exists (for blood not yet assigned to a project).
+ assertElementVisible(Locator.tagContainingText("td", "UNASSIGNED"));
// Finishes test.
log("Completed notification revamp test: Blood Draws Today (All)");
-
-// assertTextPresent("Animal ID:", necropsyID);
-// assertTextPresent("Necropsy Case Number:", necropsyCaseNumber);
-// assertTextPresent("Date of Necropsy:", necropsyDate);
-// assertTextPresent("Grant #:", necropsyAccount);
-// log("Completed testJavaDeathNotification.");
}
public void notificationRevampTestBloodDrawsTodayAnimalCare() throws UnhandledAlertException, IOException, CommandException {
@@ -3904,7 +3902,8 @@ public void notificationRevampTestBloodDrawsTodayAnimalCare() throws UnhandledAl
waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayAnimalCare").withText("Run Report In Browser"));
// Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayAnimalCareId1' exists.
+ // Verifies a blood draw shows up here when assigned to Animal Care.
+ assertTextPresent("bloodDrawsTodayAnimalCareId1");
// Finishes test.
log("Completed notification revamp test: Blood Draws Today (Animal Care)");
@@ -3927,7 +3926,8 @@ public void notificationRevampTestBloodDrawsTodayVetStaff() throws UnhandledAler
waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawsTodayVetStaff").withText("Run Report In Browser"));
// Validates necessary info.
- // TODO: Assert ID: 'bloodDrawsTodayVetStaffId1' exists.
+ // Verifies a blood draw shows up here when assigned to Vet Staff.
+ assertTextPresent("bloodDrawsTodayVetStaffId1");
// Finishes test.
log("Completed notification revamp test: Blood Draws Today (Vet Staff)");
@@ -3946,7 +3946,7 @@ public void notificationRevampTestBloodDrawReviewDailyNotification() throws Unha
myReusableFunctions.goHome();
// Creates test data.
- myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId1", false, new Date(), true, Double.valueOf(2.0), false); // Testing for blood scheduled for today with a dead anima.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId1", false, new Date(), true, Double.valueOf(2.0), false); // Testing for blood scheduled for today with a dead animal.
myReusableFunctions.insertValueIntoBloodScheduleDataset("vetStaff", "bloodDrawReviewDailyId2", true, dateTomorrow, false, Double.valueOf(2.0), false); // Testing for blood scheduled for tomorrow with an animal not assigned to a project.
// Runs test email in the browser.
@@ -3955,15 +3955,61 @@ public void notificationRevampTestBloodDrawReviewDailyNotification() throws Unha
waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawReviewDailyNotification").withText("Run Report In Browser"));
// Validates necessary info.
- // TODO: Assert ID: 'bloodDrawReviewDailyId1' exists.
- // TODO: Assert ID: 'bloodDrawReviewDailyId2' exists.
+ // Verifies the notification shows that there is a draw scheduled for a dead animal.
+ assertTextPresent("bloodDrawReviewDailyId1");
+ // Verifies the notification shows that there is a draw scheduled for an animal who is unassigned to a project.
+ assertTextPresent("bloodDrawReviewDailyId2");
// Finishes test.
log("Completed notification revamp test: Blood Draw Review (Daily)");
}
public void notificationRevampTestBloodDrawReviewTriggerNotification() throws UnhandledAlertException, IOException, CommandException {
- // TODO. For this one, check what the id is for the 'run in browser - testing id', then update the DB with this info. Or should I send it and try using dumbster?
+ // Setup
+ log("Starting notification revamp test: Blood Draw Review (Trigger)");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodDrawReviewTriggerNotification").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // Verifies the notification states that there is a dead animal with a blood draw scheduled. This is normally triggered, but here we are just testing to make sure the notification is formatted correctly and created properly.
+ assertTextPresent("This animal is no longer alive.");
+ // Verifies the notification states that there is an unassigned animal with a blood draw scheduled. This is normally triggered, but here we are just testing to make sure the notification is formatted correctly and created properly.
+ assertTextPresent("This animal is not assigned to a project on the date of the requested blood draw.");
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Draw Review (Trigger)");
+ }
+
+ public void notificationRevampTestBloodOverdrawTriggerNotification() throws UnhandledAlertException, IOException, CommandException
+ {
+ // Setup
+ log("Starting notification revamp test: Blood Overdraw Trigger");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoBloodScheduleDataset("spi", "testID", true, new Date(), true, Double.valueOf(-1), true);
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.BloodOverdrawTriggerNotification").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ // Verifies the notification states that there is an unassigned animal with a blood draw scheduled today. This is normally triggered, but here we are just testing to make sure the notification is formatted correctly and created properly.
+ assertTextPresent("This email contains warning information for an animal who just had their blood overdrawn.");
+
+ // Finishes test.
+ log("Completed notification revamp test: Blood Overdraw Trigger");
}
@Test
@@ -3980,15 +4026,27 @@ public void notificationRevampSetup() throws UnhandledAlertException, IOExceptio
NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
// Updates the notification user and reply email.
notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
- // Enables all notification that we will be testing.
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll"); //TODO: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
- // Adds notification recipients.
+ // Enables all notification that we will be testing. //TODO a34: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll");
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare");
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff");
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification");
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification");
+ notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification");
+ // Adds recipients for all notifications we will be testing.
+ waitForText("Blood Draws Today (All)");
notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare", "EHR Administrators");
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff", "EHR Administrators");
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification", "EHR Administrators");
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification", "EHR Administrators");
+ notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification", "EHR Administrators");
// Enables dumbster.
_containerHelper.enableModules(Arrays.asList("Dumbster"));
// Enable LDK Site Notification
beginAt(buildURL("ldk", "notificationSiteAdmin"));
waitForText("Notification Site Admin");
+ waitForElement(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
click(Locator.tagWithText("li", "Enabled"));
click(Locator.tagWithText("span", "Save"));
@@ -4001,43 +4059,25 @@ public void notificationRevampSetup() throws UnhandledAlertException, IOExceptio
myReusableFunctions.insertValueIntoBloodBilledByDataset("vetStaff", "Vet Staff");
myReusableFunctions.insertValueIntoBloodBilledByDataset("spi", "SPI");
- // Logs completion.
- log("Completed notificationRevampSetup()");
-
// Runs tests.
notificationRevampTestBloodDrawsTodayAll();
notificationRevampTestBloodDrawsTodayAnimalCare();
notificationRevampTestBloodDrawsTodayVetStaff();
notificationRevampTestBloodDrawReviewDailyNotification();
notificationRevampTestBloodDrawReviewTriggerNotification();
+ notificationRevampTestBloodOverdrawTriggerNotification();
+ // TODO: Run test for: Admin Alerts
+ // TODO: Run test for: Animal Request
+ // TODO: Run test for: Colony Alerts
+ // TODO: Run test for: Colony Alerts (Lite)
+ // TODO: Run test for: Colony Management
+ // TODO: Run test for: Death
+ // TODO: Run test for: Prenatal Death
+ // Logs completion.
+ log("Completed notificationRevampSetup(). All revamped notifications have been checked.");
-
-
- // Uploads data for notification: Admin Alerts
-
- // Uploads data for notification: Animal Request
-
- // Uploads data for notification: Blood Draws Today (All)
-
- // Uploads data for notification: Blood Draws Today (Animal Care)
-
- // Uploads data for notification: Blood Draws Today (Vet Staff)
-
- // Uploads data for notification: Blood Draw Review (Daily)
-
- // Uploads data for notification: Blood Draw Review (Trigger)
-
- // Uploads data for notification: Colony Alerts
-
- // Uploads data for notification: Colony Alerts (Lite)
-
- // Uploads data for notification: Colony Management
-
- // Uploads data for notification: Death
-
- // Uploads data for notification: Prenatal Death
}
public class ReusableTestFunctions {
@@ -4052,7 +4092,7 @@ public void insertValueIntoDataset(String schemaName, String queryName, HashMap<
"Query Name: " + queryName + "\n" +
"Values: " + valuesToInsert);
- //TODO: Which one to use?
+ //TODO a34: Which one to use?
Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
// Connection cn = WebTestHelper.getRemoteApiConnection();
@@ -4123,10 +4163,6 @@ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, Str
insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
insertValueIntoDataset("study", "blood", bloodTestData1);
insertValueIntoDataset("study", "weight", weightTestData1);
-
- // TODO: The following fields are not included. Make sure test still runs correctly.
- // Id/curLocation/room
- // Id/curLocation/area
}
public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
From 162b1990771cfa51d49a2b5f187d0020f1965103 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 28 Aug 2024 17:00:08 -0500
Subject: [PATCH 14/29] - DeathNotificationRevamp.java: Added a null check to
make sure class doesn't cause a failure if there's no taskID in the row
returned from the query. - WNPRC_EHRTest.java: Added a check for death
notification and prenatal death notification.
---
.../notification/DeathNotificationRevamp.java | 6 +-
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 63 +++++++++++++++++--
2 files changed, 62 insertions(+), 7 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
index 40d5c50d0..690293a64 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/DeathNotificationRevamp.java
@@ -218,8 +218,10 @@ public DeathNecropsyObject(Container c, User u, String animalID, Boolean withHtm
String[] targetTaskColumns = new String[]{"rowid"};
// Runs query.
ArrayList> necropsyTask = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "ehr", "tasks", myTaskFilter, null, targetTaskColumns);
- String taskRowID = necropsyTask.get(0).get("rowid");
- this.necropsyTaskIdHyperlink = notificationToolkit.createHyperlink(taskRowID, taskUrlAsString);
+ if (!necropsyTask.isEmpty()) {
+ String taskRowID = necropsyTask.get(0).get("rowid");
+ this.necropsyTaskIdHyperlink = notificationToolkit.createHyperlink(taskRowID, taskUrlAsString);
+ }
}
// Assigns 'Not Specified' placeholders for blank values.
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 5becdcffd..2f60b648b 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -22,6 +22,7 @@
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import org.labkey.remoteapi.Command;
import org.labkey.remoteapi.CommandException;
import org.labkey.remoteapi.CommandResponse;
import org.labkey.remoteapi.Connection;
@@ -3987,8 +3988,7 @@ public void notificationRevampTestBloodDrawReviewTriggerNotification() throws Un
log("Completed notification revamp test: Blood Draw Review (Trigger)");
}
- public void notificationRevampTestBloodOverdrawTriggerNotification() throws UnhandledAlertException, IOException, CommandException
- {
+ public void notificationRevampTestBloodOverdrawTriggerNotification() throws UnhandledAlertException, IOException, CommandException {
// Setup
log("Starting notification revamp test: Blood Overdraw Trigger");
ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
@@ -4012,6 +4012,53 @@ public void notificationRevampTestBloodOverdrawTriggerNotification() throws Unha
log("Completed notification revamp test: Blood Overdraw Trigger");
}
+ public void notificationRevampTestDeathNotificationRevamp() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Death Notification Revamp");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoNecropsyDataset("necropsyTestId1", new Date());
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.DeathNotificationRevamp").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ assertTextPresent("necropsyTestId1 has been marked as dead.");
+
+ // Finishes test.
+ log("Completed notification revamp test: Death Notification Revamp");
+ }
+
+ public void notificationRevampTestPrenatalDeathNotificationRevamp() throws UnhandledAlertException, IOException, CommandException {
+ // Setup
+ log("Starting notification revamp test: Prenatal Death Notification Revamp");
+ ReusableTestFunctions myReusableFunctions = new ReusableTestFunctions();
+
+ // Navigates to home to get a fresh start.
+ myReusableFunctions.goHome();
+
+ // Creates test data.
+ myReusableFunctions.insertValueIntoNecropsyDataset("pdNecropsyTestId2", new Date());
+
+ // Runs test email in the browser.
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath());
+ EHRAdminPage.beginAt(this, "/ehr/" + getContainerPath()).clickNotificationService(this);
+ waitAndClickAndWait(Locator.tagWithAttributeContaining("a", "href", "wnprc_ehr.notification.DeathNotificationRevamp").withText("Run Report In Browser"));
+
+ // Validates necessary info.
+ assertTextPresent("pdNecropsyTestId2 has been marked as dead.");
+ assertTextPresent("Dam");
+
+ // Finishes test.
+ log("Completed notification revamp test: Prenatal Death Notification Revamp");
+ }
+
@Test
public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
// Set up.
@@ -4066,18 +4113,17 @@ public void notificationRevampSetup() throws UnhandledAlertException, IOExceptio
notificationRevampTestBloodDrawReviewDailyNotification();
notificationRevampTestBloodDrawReviewTriggerNotification();
notificationRevampTestBloodOverdrawTriggerNotification();
+ notificationRevampTestDeathNotificationRevamp();
+ notificationRevampTestPrenatalDeathNotificationRevamp();
// TODO: Run test for: Admin Alerts
// TODO: Run test for: Animal Request
// TODO: Run test for: Colony Alerts
// TODO: Run test for: Colony Alerts (Lite)
// TODO: Run test for: Colony Management
- // TODO: Run test for: Death
- // TODO: Run test for: Prenatal Death
// Logs completion.
log("Completed notificationRevampSetup(). All revamped notifications have been checked.");
-
}
public class ReusableTestFunctions {
@@ -4165,6 +4211,13 @@ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, Str
insertValueIntoDataset("study", "weight", weightTestData1);
}
+ public void insertValueIntoNecropsyDataset(String animalID, Date necropsyDate) throws IOException, CommandException {
+ HashMap necropsyTestData = new HashMap<>();
+ necropsyTestData.put("id", animalID);
+ necropsyTestData.put("date", necropsyDate);
+ insertValueIntoDataset("study", "necropsies", necropsyTestData);
+ }
+
public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
// Retrieves QCState table.
Connection cn = createDefaultConnection();
From 06a322de405d6508feaa39b5351e35bbc1b37af6 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 29 Aug 2024 16:19:07 -0500
Subject: [PATCH 15/29] Added null check before sending blood overdraw trigger
manually. The built in labkey notification setup just doesn't send a
notification if there's a null body, but for my trigger notifications where I
send it manually, I should check for null.
---
WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
index ba444a72a..069b55809 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
@@ -256,7 +256,9 @@ public void sendBloodOverdrawTriggerNotification(String animalID, String drawDat
if (NotificationService.get().isActive(new BloodOverdrawTriggerNotification(ehr), container)) {
_log.info("Using java helper to send email for Blood Overdraw Trigger Notification (animalID: " + animalID + ").");
BloodOverdrawTriggerNotification notification = new BloodOverdrawTriggerNotification(ehr, animalID, drawDate);
- notification.sendManually(container, user);
+ if (notification != null) {
+ notification.sendManually(container, user);
+ }
}
else {
_log.info("Blood Overdraw Trigger Notification is not enabled, will not send Blood Overdraw Trigger Notification");
From 5394f7da6e478e106df6cf9f0629cf1f4396168f Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 30 Aug 2024 11:25:01 -0500
Subject: [PATCH 16/29] Moved the automated tests to the end of the list and
removed the @Test flag.
---
.../src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 2f60b648b..562c49abf 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -269,8 +269,6 @@ public static void doSetup() throws Exception
initTest.initCreatedProject();
- initTest.notificationRevampSetup();
-
initTest.uploadBillingDataAndVerify();
// Blood triggers are dependent on weights, so the blood sample data has to be imported after weights. Doing this after
@@ -285,6 +283,8 @@ public static void doSetup() throws Exception
initTest.checkUpdateProgramIncomeAccount();
+ initTest.notificationRevampSetup();
+
}
private void billingSetup() throws Exception
@@ -4059,7 +4059,6 @@ public void notificationRevampTestPrenatalDeathNotificationRevamp() throws Unhan
log("Completed notification revamp test: Prenatal Death Notification Revamp");
}
- @Test
public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
// Set up.
log("Starting notificationRevampSetup()");
From acb6cc745471c7561d9e5d6a9156dbf9c7c9fd7a Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 30 Aug 2024 16:03:00 -0500
Subject: [PATCH 17/29] Disabled site-wide notifications. Also disable
individual notifications.
---
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 48 +++++++++----------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 562c49abf..62b54f301 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -4073,32 +4073,32 @@ public void notificationRevampSetup() throws UnhandledAlertException, IOExceptio
// Updates the notification user and reply email.
notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
// Enables all notification that we will be testing. //TODO a34: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll");
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare");
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff");
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification");
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification");
- notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification");
- // Adds recipients for all notifications we will be testing.
- waitForText("Blood Draws Today (All)");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare", "EHR Administrators");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff", "EHR Administrators");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification", "EHR Administrators");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification", "EHR Administrators");
- notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification", "EHR Administrators");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification");
+// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification");
+// // Adds recipients for all notifications we will be testing.
+// waitForText("Blood Draws Today (All)");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll", "EHR Administrators");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare", "EHR Administrators");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawsTodayVetStaff", "EHR Administrators");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewDailyNotification", "EHR Administrators");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification", "EHR Administrators");
+// notificationAdminPage.addManageUsers("org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification", "EHR Administrators");
// Enables dumbster.
- _containerHelper.enableModules(Arrays.asList("Dumbster"));
+// _containerHelper.enableModules(Arrays.asList("Dumbster"));
// Enable LDK Site Notification
- beginAt(buildURL("ldk", "notificationSiteAdmin"));
- waitForText("Notification Site Admin");
- waitForElement(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
- click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
- click(Locator.tagWithText("li", "Enabled"));
- click(Locator.tagWithText("span", "Save"));
- waitForText("Success");
- clickButtonContainingText("OK");
- waitForText("Notification Site Admin");
+// beginAt(buildURL("ldk", "notificationSiteAdmin"));
+// waitForText("Notification Site Admin");
+// waitForElement(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
+// click(Locator.tagWithClass("div", "x4-form-arrow-trigger"));
+// click(Locator.tagWithText("li", "Enabled"));
+// click(Locator.tagWithText("span", "Save"));
+// waitForText("Success");
+// clickButtonContainingText("OK");
+// waitForText("Notification Site Admin");
// Creates billing groups for testing.
myReusableFunctions.insertValueIntoBloodBilledByDataset("animalCare", "Animal Care");
From 2fcd5f15127c7808857cb93e254369d0fece6014 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 30 Aug 2024 18:01:04 -0500
Subject: [PATCH 18/29] Re-added 'test' tag before function. Originally
removed this because Marty said it was not necessary if I called the function
in doSetup(), but it's not showing up in the console log anymore. Trying to
re-add this.
---
.../test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 62b54f301..4d3e91e40 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -4059,6 +4059,7 @@ public void notificationRevampTestPrenatalDeathNotificationRevamp() throws Unhan
log("Completed notification revamp test: Prenatal Death Notification Revamp");
}
+ @Test
public void notificationRevampSetup() throws UnhandledAlertException, IOException, CommandException {
// Set up.
log("Starting notificationRevampSetup()");
From ecc9f769adeb11148b55d6a0cc735eb5086e9882 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Tue, 3 Sep 2024 12:56:13 -0500
Subject: [PATCH 19/29] Added try/catch for insertValueIntoBloodBilledByDataset
due to duplicate data being uploaded. Looks like labkey's
loadBloodBilledByLookup() already uploads the same values.
---
.../labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 4d3e91e40..df302f64f 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -4155,10 +4155,15 @@ public void insertValueIntoDataset(String schemaName, String queryName, HashMap<
public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, String billingGroupDisplayName) throws IOException, CommandException
{
- HashMap billingGroupTestData = new HashMap<>();
- billingGroupTestData.put("value", billingGroupRealName);
- billingGroupTestData.put("title", billingGroupDisplayName);
- insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
+ try {
+ HashMap billingGroupTestData = new HashMap<>();
+ billingGroupTestData.put("value", billingGroupRealName);
+ billingGroupTestData.put("title", billingGroupDisplayName);
+ insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
+ }
+ catch (Exception e) {
+ log("Error executing insertValueIntoBloodBilledByDataset(), value already exists in this dataset.");
+ }
}
/**
From 44ba184aba0187a066999c78bb93f28170d939d9 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Tue, 3 Sep 2024 14:32:34 -0500
Subject: [PATCH 20/29] Added try/catch for remaining functions that insert
into datasets.
---
.../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 116 ++++++++++--------
1 file changed, 65 insertions(+), 51 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index df302f64f..227336fb1 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -4133,24 +4133,28 @@ public void goHome() {
}
public void insertValueIntoDataset(String schemaName, String queryName, HashMap valuesToInsert) throws IOException, CommandException {
- log("Inserting values into dataset.\n" +
- "Schema Name: " + schemaName + "\n" +
- "Query Name: " + queryName + "\n" +
- "Values: " + valuesToInsert);
-
- //TODO a34: Which one to use?
- Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
+ try {
+ //TODO a34: Which one to use?
+ Connection cn = new Connection(WebTestHelper.getBaseURL(), PasswordUtil.getUsername(), PasswordUtil.getPassword());
// Connection cn = WebTestHelper.getRemoteApiConnection();
- // Gets dataset to update.
- InsertRowsCommand insertCmd = new InsertRowsCommand(schemaName, queryName);
+ // Gets dataset to update.
+ InsertRowsCommand insertCmd = new InsertRowsCommand(schemaName, queryName);
- // Creates values to insert.
- insertCmd.addRow(valuesToInsert);
+ // Creates values to insert.
+ insertCmd.addRow(valuesToInsert);
- // Inserts rows into dataset.
- insertCmd.execute(cn, EHR_FOLDER_PATH);
+ // Inserts rows into dataset.
+ insertCmd.execute(cn, EHR_FOLDER_PATH);
+ log("Inserting values into dataset.\n" +
+ "Schema Name: " + schemaName + "\n" +
+ "Query Name: " + queryName + "\n" +
+ "Values: " + valuesToInsert);
+ }
+ catch (Exception e) {
+ log("Error executing insertValueIntoDataset(), value most likely already exists in this dataset.");
+ }
}
public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, String billingGroupDisplayName) throws IOException, CommandException
@@ -4162,7 +4166,7 @@ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, Str
insertValueIntoDataset("ehr_lookups", "blood_billed_by", billingGroupTestData);
}
catch (Exception e) {
- log("Error executing insertValueIntoBloodBilledByDataset(), value already exists in this dataset.");
+ log("Error executing insertValueIntoBloodBilledByDataset(), value most likely already exists in this dataset.");
}
}
@@ -4179,48 +4183,58 @@ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, Str
* @throws CommandException
*/
public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, String animalID, Boolean animalAlive, Date drawDate, Boolean projectAssigned, Double animalWeight, Boolean drawCompleted) throws IOException, CommandException {
- // Creates data to pass in.
- String livingStatus = "Dead";
- if (animalAlive) {
- livingStatus = "Alive";
- }
- Integer assignmentStatus = null;
- if (projectAssigned) {
- assignmentStatus = 300901;
+ try {
+ // Creates data to pass in.
+ String livingStatus = "Dead";
+ if (animalAlive) {
+ livingStatus = "Alive";
+ }
+ Integer assignmentStatus = null;
+ if (projectAssigned) {
+ assignmentStatus = 300901;
+ }
+ Integer completionStatus = getQCStateRowID("In Progress");
+ if (drawCompleted) {
+ completionStatus = getQCStateRowID("Completed");
+ }
+
+ // Creates demographic info (this updates the bloodSchedule field: 'Id/DataSet/Demographics/calculated_status').
+ HashMap demographicInfoTestData1 = new HashMap<>();
+ demographicInfoTestData1.put("id", animalID);
+ demographicInfoTestData1.put("calculated_status", livingStatus);
+ // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood').
+ HashMap weightTestData1 = new HashMap<>();
+ weightTestData1.put("id", animalID);
+ weightTestData1.put("date", new Date());
+ weightTestData1.put("weight", animalWeight);
+ // Creates blood info (this updates the bloodSchedule fields: 'id', 'date', 'projectStatus', 'billedby/title', and QCState/label).
+ HashMap bloodTestData1 = new HashMap<>();
+ bloodTestData1.put("id", animalID);
+ bloodTestData1.put("date", drawDate);
+ bloodTestData1.put("project", assignmentStatus);
+ bloodTestData1.put("billedBy", billingGroupRealName);
+ bloodTestData1.put("QCState", completionStatus);
+
+ // Inserts data.
+ insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
+ insertValueIntoDataset("study", "blood", bloodTestData1);
+ insertValueIntoDataset("study", "weight", weightTestData1);
}
- Integer completionStatus = getQCStateRowID("In Progress");
- if (drawCompleted) {
- completionStatus = getQCStateRowID("Completed");
+ catch (Exception e) {
+ log("Error executing insertValueIntoBloodScheduleDataset(), value most likely already exists in this dataset.");
}
-
- // Creates demographic info (this updates the bloodSchedule field: 'Id/DataSet/Demographics/calculated_status').
- HashMap demographicInfoTestData1 = new HashMap<>();
- demographicInfoTestData1.put("id", animalID);
- demographicInfoTestData1.put("calculated_status", livingStatus);
- // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood').
- HashMap weightTestData1 = new HashMap<>();
- weightTestData1.put("id", animalID);
- weightTestData1.put("date", new Date());
- weightTestData1.put("weight", animalWeight);
- // Creates blood info (this updates the bloodSchedule fields: 'id', 'date', 'projectStatus', 'billedby/title', and QCState/label).
- HashMap bloodTestData1 = new HashMap<>();
- bloodTestData1.put("id", animalID);
- bloodTestData1.put("date", drawDate);
- bloodTestData1.put("project", assignmentStatus);
- bloodTestData1.put("billedBy", billingGroupRealName);
- bloodTestData1.put("QCState", completionStatus);
-
- // Inserts data.
- insertValueIntoDataset("study", "demographics", demographicInfoTestData1);
- insertValueIntoDataset("study", "blood", bloodTestData1);
- insertValueIntoDataset("study", "weight", weightTestData1);
}
public void insertValueIntoNecropsyDataset(String animalID, Date necropsyDate) throws IOException, CommandException {
- HashMap necropsyTestData = new HashMap<>();
- necropsyTestData.put("id", animalID);
- necropsyTestData.put("date", necropsyDate);
- insertValueIntoDataset("study", "necropsies", necropsyTestData);
+ try {
+ HashMap necropsyTestData = new HashMap<>();
+ necropsyTestData.put("id", animalID);
+ necropsyTestData.put("date", necropsyDate);
+ insertValueIntoDataset("study", "necropsies", necropsyTestData);
+ }
+ catch (Exception e) {
+ log("Error executing insertValueIntoNecropsyDataset(), value most likely already exists in this dataset.");
+ }
}
public Integer getQCStateRowID(String qcStateLabel) throws IOException, CommandException {
From 4768468900caf4d5d50a15d5575d81b687829b04 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Tue, 3 Sep 2024 16:55:29 -0500
Subject: [PATCH 21/29] Changed a query function in checkIfAnimalIsAlive() so
it no longer references my functions that use QviewObject. Need to
evenutally phase out all these functions as my new query functions work much
better.
---
.../notification/NotificationToolkit.java | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index a2882634a..cc650a5d8 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -956,15 +956,23 @@ public String createAnimalHistoryURL(Container c, String subject) {
public Boolean checkIfAnimalIsAlive(Container c, User u, String idToCheck) {
try {
//Runs query.
- ArrayList animalDemographicRow = getTableRowAsList(c, u, "study", "Demographics", null, "id", idToCheck, new String[]{"calculated_status"});
+// ArrayList animalDemographicRow = getTableRowAsList(c, u, "study", "Demographics", null, "id", idToCheck, new String[]{"calculated_status"});
- //Checks alive status.
- if (animalDemographicRow.get(0).equals("Alive")) {
- return true;
- }
- else {
- return false;
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("id", idToCheck, CompareType.EQUAL);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"calculated_status"};
+ //Runs query.
+ ArrayList> returnArray = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Demographics", myFilter, null, targetColumns);
+
+ if (!returnArray.isEmpty()) {
+ if (returnArray.get(0).get("calculated_status") != null) {
+ if (returnArray.get(0).get("calculated_status").equals("Alive")) {
+ return true;
+ }
+ }
}
+ return false;
}
catch (IndexOutOfBoundsException e) {
// TODO: Log exception.
From 22939c71ad54682bd0e1470a2b7dfa4766933ca8 Mon Sep 17 00:00:00 2001
From: "F. Daniel Nicolalde"
Date: Tue, 3 Sep 2024 17:02:42 -0500
Subject: [PATCH 22/29] Removing migrated alerts from ehrcron to Java based
notifications
---
.../automaticAlerts/automaticAlerts.cron | 5 -
.../automaticAlerts/bloodAdminAlerts.pl | 336 ------
.../scripts/automaticAlerts/bloodAlerts.pl | 385 ------
.../scripts/automaticAlerts/colonyAlerts.pl | 1039 -----------------
.../automaticAlerts/colonyAlertsLite.pl | 381 ------
.../automaticAlerts/colonyMgmtAlerts.pl | 429 -------
6 files changed, 2575 deletions(-)
delete mode 100644 docker/ehrcron/scripts/automaticAlerts/bloodAdminAlerts.pl
delete mode 100644 docker/ehrcron/scripts/automaticAlerts/bloodAlerts.pl
delete mode 100644 docker/ehrcron/scripts/automaticAlerts/colonyAlerts.pl
delete mode 100644 docker/ehrcron/scripts/automaticAlerts/colonyAlertsLite.pl
delete mode 100644 docker/ehrcron/scripts/automaticAlerts/colonyMgmtAlerts.pl
diff --git a/docker/ehrcron/scripts/automaticAlerts/automaticAlerts.cron b/docker/ehrcron/scripts/automaticAlerts/automaticAlerts.cron
index ea4c94b34..141d6be49 100644
--- a/docker/ehrcron/scripts/automaticAlerts/automaticAlerts.cron
+++ b/docker/ehrcron/scripts/automaticAlerts/automaticAlerts.cron
@@ -20,14 +20,9 @@ MAIL_SERVER=mailserver
#Min Hour Day Month Weekday User Command
#---------------------------------------------------------------------------------------
0 10 * * * root $ALERT_DIR/adminAlerts.pl > /dev/null
-30 5,10,14 * * * root $ALERT_DIR/bloodAdminAlerts.pl > /dev/null
-15 5,8,9,12,14 * * * root $ALERT_DIR/bloodAlerts.pl > /dev/null
5 7-17 * * * root $ALERT_DIR/clinpathAbnormalResultAlerts.pl > /dev/null
0 11,13,16 * * * root $ALERT_DIR/clinpathAlerts.pl > /dev/null
00 10 * * * root $ALERT_DIR/clinpathResultAlerts.pl > /dev/null
-0 5 * * * root $ALERT_DIR/colonyAlerts.pl > /dev/null
-0 9-17 * * * root $ALERT_DIR/colonyAlertsLite.pl > /dev/null
-15 5 * * * root $ALERT_DIR/colonyMgmtAlerts.pl > /dev/null
12 6 * * * root $ALERT_DIR/largeInfantAlerts.pl > /dev/null
15 9 * * * root $ALERT_DIR/overdueWeightAlerts.pl > /dev/null
25 7-17 * * * root $ALERT_DIR/siteErrorAlerts.pl > /dev/null
diff --git a/docker/ehrcron/scripts/automaticAlerts/bloodAdminAlerts.pl b/docker/ehrcron/scripts/automaticAlerts/bloodAdminAlerts.pl
deleted file mode 100644
index 3d6faa8f4..000000000
--- a/docker/ehrcron/scripts/automaticAlerts/bloodAdminAlerts.pl
+++ /dev/null
@@ -1,336 +0,0 @@
-#!/usr/bin/env perl
-
-=head1 DESCRIPTION
-
-This script is designed to run as a cron job. It will query a number of tables and email a report.
-The report is designed to identify potential problems related to blood draws.
-
-
-=head1 LICENSE
-
-This package and its accompanying libraries are free software; you can
-redistribute it and/or modify it under the terms of the GPL (either
-version 1, or at your option, any later version) or the Artistic
-License 2.0.
-
-=head1 AUTHOR
-
-Ben Bimber
-
-=cut
-
-#config options:
-my $baseUrl = $ENV{'LK_BASE_URL'};
-my $printableUrl = $ENV{'PERL_LINK_URL'};
-
-my $studyContainer = 'WNPRC/EHR/';
-
-my $notificationtypes = 'Blood Admin Alerts';
-my $mail_server = $ENV{'MAIL_SERVER'};
-
-#emails will be sent from this address
-my $from = 'ehr-no-not-reply@primate.wisc.edu';
-
-
-############Do not edit below this line
-use strict;
-use warnings;
-use LabKey::Query;
-use Net::SMTP;
-use MIME::Lite;
-use Data::Dumper;
-use Time::localtime;
-use File::Touch;
-use File::Spec;
-use File::Basename;
-use Cwd 'abs_path';
-use List::MoreUtils qw/ uniq /;
-
-# Find today's date
-my $tm = localtime;
-my $datetimestr=sprintf("%04d-%02d-%02d at %02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min);
-my $datestr=sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
-
-my $timestr = sprintf("%02d:%02d", $tm->hour, $tm->min);
-
-my $email_html = "This email contains any scheduled blood draws not marked as completed. It was run on: $datetimestr.";
-my $results;
-
-
-#we find any current or future blood draws where the animal is not alive
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--containerPath => $studyContainer,
--schemaName => 'study',
--queryName => 'Blood Draws',
--filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['date', 'dategte', $datestr],
-],
--requiredVersion => 8.3,
-#-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." current or scheduled blood draws for animals not currently at WNPRC.
";
- $email_html .= "
Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find any blood draws over the allowable limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'FutureOverDraws',
-# -filterArray => [
-# ['Id/Dataset/Demographics/calculated_status', 'eq', 'Alive'],
-# ['qcstate/label', 'neq', 'Request: Denied'],
-# ['date', 'dategte', $datestr],
-# ['BloodRemaining/AvailBlood', 'lt', 0],
-#],
- -requiredVersion => 8.3,
- -debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." scheduled blood draws exceeding the allowable volume.
";
-foreach my $row (@{$results->{rows}}){
-$email_html .= $row->{'Id'}."
";
-};
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "There are no future blood draws exceeding the allowable amount based on current weights.
";
- $email_html .= "
\n";
-}
-#$email_html .= "
\n";
-#$email_html .= " Click here to see animals with blood less than 10ml of blood available.
\n";
-#$email_html .= "
\n";
-
-#we find any blood draws where the animal is not assigned to that project
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--containerPath => $studyContainer,
--schemaName => 'study',
--queryName => 'BloodSchedule',
--filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['projectStatus', 'isnonblank', ''],
- ['date', 'dategte', $datestr],
-],
--requiredVersion => 8.3,
-#-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws scheduled today or in the future where the animal is not assigned to the project.
";
-foreach my $row (@{$results->{rows}}){
-$email_html .= $row->{'Id'}."
";
-};
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "All blood draws today and in the future have a valid project for the animal.
";
- $email_html .= "
\n";
-}
-
-#we find any blood draws not yet approved
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--containerPath => $studyContainer,
--schemaName => 'study',
--queryName => 'Blood Draws',
--filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['qcstate/label', 'eq', 'Request: Pending'],
- ['date', 'dategte', $datestr],
-],
--requiredVersion => 8.3,
-#-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws requested that have not been approved or denied yet.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "All requested blood draws have been either approved or denied.
";
- $email_html .= "
\n";
-}
-
-#we find any blood draws not yet assigned to either SPI or animal care
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--containerPath => $studyContainer,
--schemaName => 'study',
--queryName => 'Blood Draws',
--filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['billedby', 'isblank', ''],
- ['date', 'dategte', $datestr],
-],
--requiredVersion => 8.3,
-#-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws requested that have not been assigned to SPI or Animal Care.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "All requested blood draws have been assigned to either SPI or Animal Care.
";
- $email_html .= "
\n";
-}
-
-#we find any current blood draws with clinpath, but lacking a request
-#$results = LabKey::Query::selectRows(
-#-baseUrl => $baseUrl,
-#-containerPath => $studyContainer,
-#-schemaName => 'study',
-#-queryName => 'ValidateBloodDrawClinpath',
-#-viewName => 'Lacking Clinpath Request',
-#-filterArray => [
-# ['date', 'dateeq', $datestr],
-#],
-#-requiredVersion => 8.3,
-#-debug => 1,
-#);
-
-#if(@{$results->{rows}}){
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws scheduled today that request clinpath, but lack a corresponding clinpath request.
";
-# $email_html .= "Click here to view them
\n";
-# $email_html .= "
\n";
-#}
-
-
-
-#we find any incomplete blood draws scheduled today, by area
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--containerPath => $studyContainer,
--schemaName => 'study',
--queryName => 'BloodSchedule',
--columns => 'drawStatus,daterequested,project,date,project/protocol,taskid,projectStatus,tube_vol,tube_type,billedby,billedby/title,num_tubes,Id/curLocation/area,Id/curLocation/room,Id/curLocation/cage,additionalServices,remark,Id,quantity,qcstate,qcstate/Label,requestid',
--filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['date', 'dateeq', $datestr],
- ['qcstate', 'ne', 'Completed'],
-],
--sort => 'daterequested',
--requiredVersion => 8.3,
-#-debug => 1,
-);
-
-
-if(!@{$results->{rows}}){
- $email_html .= "There are no blood draws scheduled for $datestr.
";
-}
-else {
- my $complete = 0;
- my $incomplete = 0;
- my $summary = {};
-foreach my $row (@{$results->{rows}}){
- if($row->{'qcstate/Label'} && $row->{'qcstate/Label'} eq 'Completed'){
- $complete++;
- }
- else {
- if(!$$summary{$row->{'Id/curLocation/area'}}){
- $$summary{$row->{'Id/curLocation/area'}} = {};
- }
- if(!$$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}){
- $$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}} = {complete=>0,incomplete=>0,incompleteRecords=>[]};
- }
-
- $$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}{incomplete}++;
- push(@{$$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}{incompleteRecords}}, $row);
-
- $incomplete++;
- }
-};
-
- my $url = "Click here to view them
\n";
- $email_html .= "There are ".@{$results->{rows}}." scheduled blood draws for $datestr. $complete have been completed. $url\n";
-
- if(!$incomplete){
- $email_html .= "All scheduled blood draws have been marked complete as of $datetimestr.
\n";
- }
- else {
- $email_html .= "The following blood draws have not been marked complete as of $datetimestr:
\n";
-
- my $prevRoom = '';
- foreach my $area (sort(keys %$summary)){
- my $rooms = $$summary{$area};
- $email_html .= "$area:
\n";
- foreach my $room (sort(keys %$rooms)){
- if($$rooms{$room}{incomplete}){
- $email_html .= "$room: ".$$rooms{$room}{incomplete}."
\n";
- $email_html .= "
| Time Requested | Id | Tube Vol | Tube Type | # Tubes | Total Quantity | Additional Services | Assigned To |
\n";
-
- foreach my $rec (@{$$rooms{$room}{incompleteRecords}}){
- $email_html .= "| ".$$rec{daterequested}." | ".$$rec{Id}." | ".($$rec{tube_vol} ? $$rec{tube_vol}.' mL' : '')." | ".($$rec{tube_type} ? $$rec{tube_type} : '')." | ".($$rec{num_tubes} ? $$rec{num_tubes} : '')." | ".($$rec{quantity} ? $$rec{quantity}.' mL' : '')." | ".($$rec{additionalServices} ? $$rec{additionalServices} : '')." | ".($$rec{'billedby/title'} ? $$rec{'billedby/title'} : '')." |
\n";
- }
-
- $email_html .= "
\n";
- }
-
- }
- $email_html .= "
\n";
- }
- }
-
- $email_html .= "
\n";
-}
-
-
-
-#open(HTML, ">", "C:\\Users\\Admin\\Desktop\\test.html");
-#print HTML $email_html;
-#close HTML;
-#die;
-
-$results = LabKey::Query::selectRows(
--baseUrl => $baseUrl,
--requiredVersion => 8.3,
--containerPath => $studyContainer,
--schemaName => 'ehr',
--queryName => 'NotificationRecipientsExpanded',
--filterArray => [
- ['notificationtype', 'in', $notificationtypes],
-],
-#-debug => 1,
-);
-if(@{$results->{rows}}){
- my @email_recipients;
- foreach my $row (@{$results->{rows}}){
- push(@email_recipients, $$row{email})
-}
-
- if(@email_recipients){
- @email_recipients = uniq @email_recipients;
-
- my $smtp = MIME::Lite->new(
- To =>join(", ", @email_recipients),
- From =>$from,
- Subject =>"Subject: Daily Blood Draw Schedule Alerts: $datestr",
- Type =>'multipart/alternative'
- );
- $smtp->attach(Type => 'text/html',
- Encoding => 'quoted-printable',
- Data => $email_html
- );
- $smtp->send() || die;
- }
-}
-
-touch(File::Spec->catfile(dirname(abs_path($0)), '.bloodAdminAlertsLastRun'));
diff --git a/docker/ehrcron/scripts/automaticAlerts/bloodAlerts.pl b/docker/ehrcron/scripts/automaticAlerts/bloodAlerts.pl
deleted file mode 100644
index 3700bfbd1..000000000
--- a/docker/ehrcron/scripts/automaticAlerts/bloodAlerts.pl
+++ /dev/null
@@ -1,385 +0,0 @@
-#!/usr/bin/env perl
-
-=head1 DESCRIPTION
-
-This script is designed to run as a cron job. It will query a number of tables and email a report.
-The report is designed to identify potential problems related to blood draws.
-
-
-=head1 LICENSE
-
-This package and its accompanying libraries are free software; you can
-redistribute it and/or modify it under the terms of the GPL (either
-version 1, or at your option, any later version) or the Artistic
-License 2.0.
-
-=head1 AUTHOR
-
-Ben Bimber
-
-=cut
-
-#config options:
-my $baseUrl = $ENV{'LK_BASE_URL'};
-my $printableUrl = $ENV{'PERL_LINK_URL'};
-
-my $studyContainer = 'WNPRC/EHR/';
-
-my $notificationtypes = 'Blood Alerts';
-my $mail_server = $ENV{'MAIL_SERVER'};
-
-#emails will be sent from this address
-my $from = 'ehr-no-not-reply@primate.wisc.edu';
-
-
-############Do not edit below this line
-use strict;
-use warnings;
-use LabKey::Query;
-use Net::SMTP;
-use MIME::Lite;
-use Data::Dumper;
-use Time::localtime;
-use File::Touch;
-use File::Spec;
-use File::Basename;
-use Cwd 'abs_path';
-use List::MoreUtils qw/ uniq /;
-
-# Find today's date
-my $tm = localtime;
-my $datetimestr=sprintf("%04d-%02d-%02d at %02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min);
-my $datestr=sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
-my $timestr = sprintf("%02d:%02d", $tm->hour, $tm->min);
-
-my $email_html = "This email contains any scheduled blood draws not marked as completed. It was run on: $datetimestr.";
-my $results;
-
-
-#we find any current or future blood draws where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Blood Draws',
- -filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['date', 'dategte', $datestr],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." current or scheduled blood draws for animals not currently at WNPRC.
";
- $email_html .= "
Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find any blood draws over the allowable limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'DailyOverDraws',
-# -filterArray => [
-# ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
-# ['qcstate/label', 'neq', 'Request: Denied'],
-# ['date', 'dategte', $datestr],
-# ['BloodRemaining/AvailBlood', 'lt', 0],
-# ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." scheduled blood draws exceeding the allowable volume.
";
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "There are no future blood draws exceeding the allowable amount based on current weights.
";
- $email_html .= "
\n";
-}
-
-#$email_html .= "
\n";
-#$email_html .= "
-#Click here to see animals with less than 10ml of blood available.
\n";
-#$email_html .= "
\n";
-
-#we find any blood draws over the allowable limit
-#$results = LabKey::Query::selectRows(
-# -baseUrl => $baseUrl,
-# -containerPath => $studyContainer,
-# -schemaName => 'study',
-# -queryName => 'Blood Draws',
-# -filterArray => [
-# ['Id/DataSet/Demographics/calculated_status', 'neqornull', 'Alive'],
-# ['qcstate/label', 'neq', 'Request: Denied'],
-# ['date', 'dategte', $datestr],
-# ['BloodRemaining/AvailBlood', 'lt', 0],
-# ],
-# -requiredVersion => 8.3,
-# #-debug => 1,
-#);
-#
-#if(@{$results->{rows}}){
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." scheduled blood draws exceeding the allowable volume.
";
-# foreach my $row (@{$results->{rows}}){
-# $email_html .= $row->{'Id'}."
";
-# };
-#
-# $email_html .= "Click here to view them
\n";
-# $email_html .= "
\n";
-#}
-
-#we find any blood draws where the animal is not assigned to that project
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'BloodSchedule',
- -filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['projectStatus', 'isnonblank', ''],
- ['date', 'dategte', $datestr],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws scheduled today or in the future where the animal is not assigned to the project.
";
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-else {
- $email_html .= "All blood draws today and in the future have a valid project for the animal.
";
- $email_html .= "
\n";
-}
-
-#we find any blood draws where the animal is not assigned to that project
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'BloodSchedule',
- -filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['qcstate/label', 'neq', 'Request: Denied'],
- ['projectStatus', 'isnonblank', ''],
- ['date', 'dateeq', $datestr],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws scheduled today where the animal is not assigned to the project. DO NOT DRAW FROM THESE ANIMALS UNTIL FIXED.
";
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find any blood draws not yet approved
-#$results = LabKey::Query::selectRows(
-# -baseUrl => $baseUrl,
-# -containerPath => $studyContainer,
-# -schemaName => 'study',
-# -queryName => 'Blood Draws',
-# -filterArray => [
-# ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
-# ['qcstate/label', 'eq', 'Request: Pending'],
-# ['date', 'dategte', $datestr],
-# ],
-# -requiredVersion => 8.3,
-# #-debug => 1,
-#);
-#
-#if(@{$results->{rows}}){
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws requested that have not been approved or denied yet.
";
-# $email_html .= "Click here to view them
\n";
-# $email_html .= "
\n";
-#}
-
-#we find any blood draws not yet assigned to either SPI or animal care
-#$results = LabKey::Query::selectRows(
-# -baseUrl => $baseUrl,
-# -containerPath => $studyContainer,
-# -schemaName => 'study',
-# -queryName => 'Blood Draws',
-# -filterArray => [
-# ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
-# ['qcstate/label', 'neq', 'Request: Denied'],
-# ['billedby', 'isblank', ''],
-# ['date', 'dategte', $datestr],
-# ],
-# -requiredVersion => 8.3,
-# #-debug => 1,
-#);
-#
-#if(@{$results->{rows}}){
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." blood draws requested that have not been assigned to SPI or Animal Care.
";
-# $email_html .= "Click here to view them
\n";
-# $email_html .= "
\n";
-#}
-
-#we find any incomplete blood draws scheduled today, by area
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'BloodSchedule',
- -columns => 'drawStatus,project,date,project/protocol,taskid,projectStatus,tube_vol,tube_type,billedby,billedby/title,num_tubes,Id/curLocation/area,Id/curLocation/room,Id/curLocation/cage,additionalServices,remark,Id,quantity,qcstate,qcstate/Label,requestid',
- -filterArray => [
- ['Id/DataSet/Demographics/calculated_status', 'eq', 'Alive'],
- ['date', 'dateeq', $datestr],
- ['qcstate', 'ne', 'Completed'],
- ],
- -sort => 'date',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(!@{$results->{rows}}){
- $email_html .= "There are no blood draws scheduled for $datestr.
";
-}
-else {
- my $complete = 0;
- my $incomplete = 0;
- my $summary = {};
- my $counts = {};
- foreach my $row (@{$results->{rows}}){
- if($row->{'qcstate/Label'} && $row->{'qcstate/Label'} eq 'Completed'){
- $complete++;
- }
- else {
- if(!$$summary{$row->{'Id/curLocation/area'}}){
- $$summary{$row->{'Id/curLocation/area'}} = {};
- $$counts{$row->{'Id/curLocation/area'}} = {};
- }
- if(!$$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}){
- $$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}} = {complete=>0,incomplete=>0,incompleteRecords=>[]};
- }
-
- if(!$$counts{$row->{'Id/curLocation/area'}}{$row->{'billedby/title'} || 'Not Assigned'}){
- $$counts{$row->{'Id/curLocation/area'}}{$row->{'billedby/title'} || 'Not Assigned'} = 0;
- }
- $$counts{$row->{'Id/curLocation/area'}}{$row->{'billedby/title'} || 'Not Assigned'}++;
-
- $$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}{incomplete}++;
- push(@{$$summary{$row->{'Id/curLocation/area'}}{$row->{'Id/curLocation/room'}}{incompleteRecords}}, $row);
-
- $incomplete++;
- }
- };
-
- my $url = "Click here to view them
\n";
- $email_html .= "There are ".@{$results->{rows}}." scheduled blood draws for $datestr. $complete have been completed. $url\n";
-
- if(!$incomplete){
- $email_html .= "All scheduled blood draws have been marked complete as of $datetimestr.
\n";
- }
- else {
- $email_html .= "The following blood draws have not been marked complete as of $datetimestr:
\n";
-
- $email_html .= "Totals by Area:
\n";
-
- foreach my $area (sort(keys %$counts)){
- my $types = $$counts{$area};
- $email_html .= $area.":
\n";
- foreach my $type (sort(keys %$types)){
- $email_html .= "$type: ".$$types{$type}."
\n";
- }
- }
-
- $email_html .= "
\n";
- $email_html .= "Individual Draws:
\n";
-
- my $prevRoom = '';
- foreach my $area (sort(keys %$summary)){
- my $rooms = $$summary{$area};
- $email_html .= "$area:
\n";
- foreach my $room (sort(keys %$rooms)){
- if($$rooms{$room}{incomplete}){
- $email_html .= "$room: ".$$rooms{$room}{incomplete}."
\n";
- $email_html .= "
| Time Requested | Id | Tube Vol | Tube Type | # Tubes | Total Quantity | Additional Services | Assigned To |
\n";
-
- foreach my $rec (@{$$rooms{$room}{incompleteRecords}}){
- $$rec{date} =~ m/([0-9]{2}):([0-9]{2}):[0-9]{2}/;
-
- my $color;
- if($tm->hour >= int($1) || ($tm->hour == int($1) && ($tm->min + 15) >= int($2))){
- $color = 'yellow';
- }
-
- $email_html .= "| ".$$rec{date}." | ".$$rec{Id}." | ".($$rec{tube_vol} ? $$rec{tube_vol}.' mL' : '')." | ".($$rec{tube_type} ? $$rec{tube_type} : '')." | ".($$rec{num_tubes} ? $$rec{num_tubes} : '')." | ".($$rec{quantity} ? $$rec{quantity}.' mL' : '')." | ".($$rec{additionalServices} ? $$rec{additionalServices} : '')." | ".($$rec{"billedby/title"} ? $$rec{"billedby/title"} : '')." |
\n";
- }
-
- $email_html .= "
\n";
- }
-
- }
- $email_html .= "
\n";
- }
- }
-
- $email_html .= "
\n";
-}
-
-
-
-#open(HTML, ">", "C:\\Users\\Admin\\Desktop\\test.html");
-#print HTML $email_html;
-#close HTML;
-
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -requiredVersion => 8.3,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'NotificationRecipientsExpanded',
- -filterArray => [
- ['notificationtype', 'in', $notificationtypes],
- ],
- #-debug => 1,
-);
-if(@{$results->{rows}}){
- my @email_recipients;
- foreach my $row (@{$results->{rows}}){
- push(@email_recipients, $$row{email})
- }
-
- if(@email_recipients){
- #print (@email_recipients);die;
- @email_recipients = uniq @email_recipients;
- my $smtp = MIME::Lite->new(
- To =>join(", ", @email_recipients),
- From =>$from,
- Subject =>"Subject: Daily Blood Draw Alerts: $datestr",
- Type =>'multipart/alternative'
- );
- $smtp->attach(Type => 'text/html',
- Encoding => 'quoted-printable',
- Data => $email_html
- );
- $smtp->send() || die;
- }
-}
-
-touch(File::Spec->catfile(dirname(abs_path($0)), '.bloodAlertsLastRun'));
diff --git a/docker/ehrcron/scripts/automaticAlerts/colonyAlerts.pl b/docker/ehrcron/scripts/automaticAlerts/colonyAlerts.pl
deleted file mode 100644
index 0a500ad0a..000000000
--- a/docker/ehrcron/scripts/automaticAlerts/colonyAlerts.pl
+++ /dev/null
@@ -1,1039 +0,0 @@
-#!/usr/bin/env perl
-
-=head1 DESCRIPTION
-
-This script is designed to run as a cron job. It will query a number of tables an email a report.
-The report is designed to identify potential problems with the colony, primarily related to weights, housing
-and assignments.
-
-
-=head1 LICENSE
-
-This package and its accompanying libraries are free software; you can
-redistribute it and/or modify it under the terms of the GPL (either
-version 1, or at your option, any later version) or the Artistic
-License 2.0.
-
-=head1 AUTHOR
-
-Ben Bimber
-
-=cut
-
-#config options:
-my $baseUrl = $ENV{'LK_BASE_URL'};
-my $printableUrl = $ENV{'PERL_LINK_URL'};
-my $studyContainer = 'WNPRC/EHR/';
-
-my $notificationtypes = 'Colony Alerts';
-my $mail_server = $ENV{'MAIL_SERVER'};
-
-#emails will be sent from this address
-my $from = 'ehr-do-not-reply@primate.wisc.edu';
-
-
-############Do not edit below this line
-use strict;
-use warnings;
-use LabKey::Query;
-use Net::SMTP;
-use MIME::Lite;
-use Data::Dumper;
-use Time::localtime;
-use File::Touch;
-use File::Spec;
-use File::Basename;
-use Cwd 'abs_path';
-use List::MoreUtils qw/ uniq /;
-
-# Find today's date
-my $tm = localtime;
-my $datetimestr=sprintf("%04d-%02d-%02d at %02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min);
-my $datestr=sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
-
-my $yesterday = localtime( ( time() - ( 24 * 60 * 60 ) ) );
-$yesterday = sprintf("%04d-%02d-%02d", $yesterday->year+1900, ($yesterday->mon)+1, $yesterday->mday);
-
-my $tomorrow = localtime( ( time() + ( 24 * 60 * 60 ) ) );
-$tomorrow = sprintf("%04d-%02d-%02d", $tomorrow->year+1900, ($tomorrow->mon)+1, $tomorrow->mday);
-
-
-my $email_html = "This email contains a series of automatic alerts about the WNPRC colony. It was run on: $datetimestr.";
-my $results;
-
-#first we find all living animals without a weight:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -sort => 'Id',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['Id/MostRecentWeight/MostRecentWeightDate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following animals do not have a weight:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "
Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-
-#then we find all occupied cages without dimensions:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'missingCages',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following cages have animals, but do not have known dimensions:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'room'}."/".$row->{'cage'}."
";
- };
-
- $email_html .= "Click here to view the problem cages
\n";
- $email_html .= "Click here to edit the cage list and fix the problem
\n";
-
- $email_html .= '
';
-}
-
-#then we list all animals in pc:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Housing',
- -sort => 'Id',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'eq', 'Alive'],
- ['cond', 'eq', 'pc'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- my $map = {};
- my $tempHTML = '';
-
- foreach my $row (@{$results->{rows}}){
-
- if(!$$map{$row->{'room'}}){
- $$map{$row->{'room'}} = {};
- }
-
- my $cage = $row->{'cage'};
- if ($cage =~ /^\d+$/ ){
- $cage = $cage + 0; #convert to number
- $$map{$row->{'room'}}{$cage} = [] unless $$map{$row->{'room'}}{$cage};
- push(@{$$map{$row->{'room'}}{$cage}}, $row->{'Id'});
- }
- };
-
- foreach my $room (sort keys %$map){
- my $roommap = $$map{$room};
- foreach my $cage (sort keys %$roommap){
- if(!$$roommap{$cage - 1} && !$$roommap{$cage + 1}){
- $tempHTML .= join(';', @{$$roommap{$cage}}).': '.$room."/".$cage."
";
- }
- }
- }
-
- if($tempHTML){
- $email_html .= "WARNING: The following animals are listed in protected contact, but do not appear to have an adjacent pc animal:
".$tempHTML;
- $email_html .= "Click here to view all pc animals
\n";
- $email_html .= '
';
- }
-}
-
-
-#then we find all living animals with multiple active housing records:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'housingProblems',
- -sort => 'Id',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with multiple active housing records:
";
-
- my @ids;
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= "Click here to edit housing to fix the problems";
- $email_html .= '
';
-}
-
-#then we find all living animals with multiple active housing records:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'ValidateHousingSnapshot',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals where the housing snapshot doesnt match the housing table. The snapshot has been automatically refreshed:
";
- $email_html .= "Click here to view the report again
\n";
- $email_html .= '
';
-
- system("/usr/local/labkey/tools/updateSnapshot.pl");
-}
-
-#then we find all records with potential housing condition problems
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'housingConditionProblems',
- -sort => 'Id',
- -viewName => 'Problems',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records with potential condition problems:
";
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "Click here to view these records
\n";
- $email_html .= "Click here to edit housing to fix the problems";
-
- #$email_html .= join('
', @ids);
- $email_html .= '
';
-}
-
-#we find open housing records where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Housing',
- -sort => 'Id',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active housing records where the animal is not alive:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- #$email_html .= "WARNING: There are ".@{$results->{rows}}." housing records for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find living animals without an active housing record
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -sort => 'Id',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['Id/curLocation/room/room', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." living animals without an active housing record:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#then we find all records with problems in the calculated_status field
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Validate_status',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with problems in the status field:
";
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "Click here to view these records
\n";
- $email_html .= "When you see these problems, it usually happens because the automatic process of calculating this field, which is triggered by births, deaths, departures or arrivals, didnt work right. To force it to re-calculate, just edit the animal's record on one of these tables, maybe no changes, then hit submit. That should force a re-calculation of the status field.";
- $email_html .= "
";
-}
-
-#NOTE: deprecated
-##then we find all records with problems in the calculated_status field
-#$results = LabKey::Query::selectRows(
-# -baseUrl => $baseUrl,
-# -containerPath => $studyContainer,
-# -schemaName => 'study',
-# -queryName => 'Validate_status_mysql',
-# -requiredVersion => 8.3,
-# #-debug => 1,
-#);
-#
-#if(@{$results->{rows}}){
-# my @ids;
-#
-# foreach my $row (@{$results->{rows}}){
-# push(@ids, $row->{'id'});
-# $email_html .= $row->{'id'}."
";
-# };
-#
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with potential problems in the status field (based on old system).
";
-# $email_html .= "Click here to view these records
\n";
-# $email_html .= "When you see these problems, it usually happens because the automatic process of calculating this field, which is triggered by births, deaths, departures or arrivals, didnt work right. To force it to re-calculate, just edit the animal's record on one of these tables, maybe no changes, then hit submit. That should force a re-calculation of the status field.";
-# $email_html .= "
";
-#}
-
-#then we find all animals lacking any assignments
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -viewName => 'No Active Assigns',
- -sort => 'Id',
- -requiredVersion => 8.3,
- -debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." living animals without any active assignments:
";
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'Id'});
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-
-#we find any active assignment where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find any active assignment where the project lacks a valid protocol
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ['project/protocol', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments to a project without a valid protocol.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find any duplicate active assignments
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'duplicateAssignments',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals double assigned to the same project.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#then we find all living siv+ animals not exempt from pair housing (20060202)
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['medical', 'contains', 'siv'],
- ['Id/assignmentSummary/ActiveVetAssignments', 'doesnotcontain', '20060202'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with SIV in the medical field, but not actively assigned to exempt from paired housing (20060202):
";
- $email_html .= "Click here to view them
\n";
- $email_html .= '
';
-}
-
-#then we find all living shiv+ animals not exempt from pair housing (20060202)
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['medical', 'contains', 'shiv'],
- ['Id/assignmentSummary/ActiveVetAssignments', 'doesnotcontain', '20060202'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with SHIV in the medical field, but not actively assigned to exempt from paired housing (20060202):
";
- $email_html .= "Click here to view them
\n";
- $email_html .= '
';
-}
-
-#we find open ended treatments where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Treatment Orders',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active treatments for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find open ended problems where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Problem List',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." unresolved problems for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find open assignments where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find non-continguous housing records
-my $paramVal=sprintf("%02d/%02d/%04d", ($tm->mon)+1, $tm->mday, $tm->year+1900-1);
-
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'HousingCheck',
- -parameters => [
- ['MINDATE', $paramVal]
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records since $paramVal that do not have a contiguous previous or next record.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find birth records in the past 90 days missing a gender
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Birth',
- -filterArray => [
- ['gender', 'isblank', ''],
- ['date', 'dategte', '-90d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following birth records were entered in the last 90 days, but are missing a gender:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}.' ('.$row->{'date'}.")
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-#we find demographics records in the past 90 days missing a gender
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -sort => 'Id',
- -filterArray => [
- ['gender', 'isblank', ''],
- ['created', 'dategte', '-90d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following demographics records were entered in the last 90 days, but are missing a gender:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}.($row->{'birth'} ? ' ('.$row->{'birth'}.')' : '')."
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-#we find prenatal records in the past 90 days missing a gender
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Prenatal Deaths',
- -sort => 'Id',
- -filterArray => [
- ['gender', 'isblank', ''],
- ['date', 'dategte', '-90d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following prenatal death records were entered in the last 90 days, but are missing a gender:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}.' ('.$row->{'date'}.")
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-#we find prenatal records in the past 90 days missing species
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Prenatal Deaths',
- -sort => 'Id',
- -filterArray => [
- ['species', 'isblank', ''],
- ['date', 'dategte', '-90d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following prenatal death records were entered in the last 90 days, but are missing the species:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}.' ('.$row->{'date'}.")
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-
-#we find all animals that died in the past 90 days where there isnt a weight within 7 days of death:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -sort => 'Id',
- -queryName => 'validateFinalWeights',
- -filterArray => [
- ['death', 'dategte', '-90d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals that are dead, but do not have a weight within the previous 7 days:
";
-
- $email_html .= "Click here to view them
\n";
- $email_html .= '
';
-}
-
-#we find TB records lacking a results more than 30 days old, but less than 90
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'TB Tests',
- -filterArray => [
- ['missingresults', 'eq', 'true'],
- ['date', 'dategte', '-90d'],
- ['date', 'datelte', '-10d'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." TB Tests in the past 10-90 days that are missing results.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-
-#we find protocols nearing the animal limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'protocolTotalAnimalsBySpecies',
- -filterArray => [
- ['TotalRemaining', 'lt', '5'],
- ['allowed', 'neq', '0'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." protocols with fewer than 5 remaining animals.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find protocols nearing the animal limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'protocolTotalAnimalsBySpecies',
- -filterArray => [
- ['PercentUsed', 'gte', '95'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." protocols with fewer than 5% of their animals remaining.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find protocols expiring soon
-my $days = 14;
-my $day_value = (365 * 3 - $days);
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'protocol',
- -filterArray => [
- ['Approve', 'datelte', '-' . $day_value . 'd'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." protocols that will expire within the next $days days.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find birth records without a corresponding demographics record
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Birth',
- -sort => 'Id',
- -filterArray => [
- ['Id/Dataset/Demographics/Id', 'isblank', '']
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." WNPRC birth records without a corresponding demographics record.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find death records without a corresponding demographics record
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Deaths',
- -sort => 'Id',
- -filterArray => [
- ['Id/Dataset/Demographics/Id', 'isblank', ''],
- ['notAtCenter', 'neqornull', 'true']
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." WNPRC death records without a corresponding demographics record.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find animals with hold codes, but not on pending
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -sort => 'Id',
- -filterArray => [
- ['hold', 'isnonblank', ''],
- ['Id/assignmentSummary/NumPendingAssignments', 'eq', 0],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with a hold code, but not on the pending project.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find assignments with projected releases today
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -sort => 'Id',
- -filterArray => [
- ['projectedRelease', 'dateeq', $datestr],
- ['enddate', 'isnonblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "ALERT: There are ".@{$results->{rows}}." assignments with a projected release date for today that have not already been ended.
";
-
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find assignments with projected releases tomorrow
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['projectedRelease', 'dateeq', $tomorrow],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "ALERT: There are ".@{$results->{rows}}." assignments with a projected release date for tomorrow.
";
-
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-
-#summarize events in last 5 days:
-my $mindate = localtime( ( time() - ( 5 * 24 * 60 * 60 ) ) );
-$mindate = sprintf("%04d-%02d-%02d", $mindate->year+1900, ($mindate->mon)+1, $mindate->mday);
-$email_html .= "Colony events in the past 5 days:";
-
-
-#births in the last 5 days:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Birth',
- -sort => 'Id',
- -filterArray => [
- ['date', 'dategte', $mindate]
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "Births since $mindate:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "
Click here to view them
\n";
-# $email_html .= '
';
-}
-
-
-#deaths in the last 5 days:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Deaths',
- -sort => 'Id',
- -filterArray => [
- ['date', 'dategte', $mindate]
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "Deaths since $mindate:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- #$email_html .= '
';
-}
-
-#prenatal deaths in the last 5 days:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Prenatal Deaths',
- -sort => 'Id',
- -filterArray => [
- ['date', 'dategte', $mindate]
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "Prenatal Deaths since $mindate:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view them
\n";
- #$email_html .= '
';
-}
-
-$email_html .= '
';
-
-
-
-#find the total finalized records with future dates
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'StudyData',
- -filterArray => [
- ['qcstate/PublicData', 'eq', 'true'],
- ['date', 'dategt', $datestr],
- ['dataset/label', 'neq', 'Treatment Orders'],
- ['dataset/label', 'neq', 'Assignment'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." finalized records with future dates.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-
-#open(HTML, ">", "C:\\Users\\Admin\\Desktop\\test.html");
-#print HTML $email_html;
-#close HTML;
-#die;
-
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -requiredVersion => 8.3,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'NotificationRecipientsExpanded',
- -filterArray => [
- ['notificationtype', 'in', $notificationtypes],
- ],
- #-debug => 1,
-);
-if(@{$results->{rows}}){
- my @email_recipients;
- foreach my $row (@{$results->{rows}}){
- push(@email_recipients, $$row{email})
- }
-
- if(@email_recipients){
- #print (@email_recipients);die;
- @email_recipients = uniq @email_recipients;
- my $smtp = MIME::Lite->new(
- To =>join(", ", @email_recipients),
- From =>$from,
- Subject =>"Subject: Daily Colony Alerts: $datestr",
- Type =>'multipart/alternative'
- );
- $smtp->attach(Type => 'text/html',
- Encoding => 'quoted-printable',
- Data => $email_html
- );
- $smtp->send() || die;
- }
-}
-
-touch(File::Spec->catfile(dirname(abs_path($0)), '.colonyAlertsLastRun'));
diff --git a/docker/ehrcron/scripts/automaticAlerts/colonyAlertsLite.pl b/docker/ehrcron/scripts/automaticAlerts/colonyAlertsLite.pl
deleted file mode 100644
index 5f143d0ac..000000000
--- a/docker/ehrcron/scripts/automaticAlerts/colonyAlertsLite.pl
+++ /dev/null
@@ -1,381 +0,0 @@
-#!/usr/bin/env perl
-
-=head1 DESCRIPTION
-
-This script is designed to run as a cron job. It will query a number of tables an email a report.
-The report is designed to identify potential problems with the colony, primarily related to weights, housing
-and assignments.
-
-
-=head1 LICENSE
-
-This package and its accompanying libraries are free software; you can
-redistribute it and/or modify it under the terms of the GPL (either
-version 1, or at your option, any later version) or the Artistic
-License 2.0.
-
-=head1 AUTHOR
-
-Ben Bimber
-
-=cut
-
-#config options:
-my $baseUrl = $ENV{'LK_BASE_URL'};
-my $printableUrl = $ENV{'PERL_LINK_URL'};
-my $studyContainer = 'WNPRC/EHR/';
-
-my $notificationtypes = 'Colony Alerts Lite';
-my $mail_server = $ENV{'MAIL_SERVER'};
-
-#emails will be sent from this address
-my $from = 'ehr-no-not-reply@primate.wisc.edu';
-
-
-############Do not edit below this line
-use strict;
-use warnings;
-use LabKey::Query;
-use Net::SMTP;
-use MIME::Lite;
-use Data::Dumper;
-use Time::localtime;
-use File::Touch;
-use File::Spec;
-use File::Basename;
-use Cwd 'abs_path';
-use List::MoreUtils qw/ uniq /;
-
-# Find today's date
-my $tm = localtime;
-my $datetimestr=sprintf("%04d-%02d-%02d at %02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min);
-my $datestr=sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
-
-my $yesterday = localtime( ( time() - ( 24 * 60 * 60 ) ) );
-$yesterday = sprintf("%04d-%02d-%02d", $yesterday->year+1900, ($yesterday->mon)+1, $yesterday->mday);
-
-my $email_html = "This email contains a series of automatic alerts about the WNPRC colony. It was run on: $datetimestr.";
-my $results;
-my $doSend = 0;
-
-
-#then we find all living animals with multiple active housing records:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'housingProblems',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with multiple active housing records.
";
- $email_html .= "
Click here to view these animals
\n";
- $email_html .= "Click here to edit housing to fix the problems";
- $email_html .= '
';
-}
-
-#then we find all living animals with multiple active housing records:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'ValidateHousingSnapshot',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals where the housing snapshot doesnt match the housing table. The snapshot has been automatically refreshed:
";
- $email_html .= "Click here to view the report again
\n";
- $email_html .= '
';
-
- system("/usr/local/labkey/automaticAlerts/updateSnapshot.pl");
-}
-
-
-#then we find all records with potential housing condition problems
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'housingConditionProblems',
- -viewName => 'Problems',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records with potential problems in the condition field.
";
- $email_html .= "Click here to view these records
\n";
- $email_html .= "Click here to edit housing to fix the problems";
-
- #$email_html .= join('
', @ids);
- $email_html .= '
';
-}
-
-#we find non-continguous housing records
-my $paramVal = localtime( ( time() - ( 7 * 24 * 60 * 60 ) ) );
-$paramVal=sprintf("%02d/%02d/%04d", ($paramVal->mon)+1, $paramVal->mday, $paramVal->year+1900);
-
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'HousingCheck',
- -parameters => [
- ['MINDATE', $paramVal]
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records since $paramVal that do not have a contiguous previous or next record.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find open housing records where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Housing',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find living animals without an active housing record
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['Id/curLocation/room/room', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." living animals that lack an active housing record.
";
- $email_html .= "Click here to view them
\n";#
- $email_html .= "
\n";
-}
-
-
-#then we find all records with problems in the calculated_status field
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Validate_status',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with potential problems in the status field.
";
- $email_html .= "Click here to view these records
\n";
- $email_html .= "Click here to edit demographics to fix the problems";
- $email_html .= "
";
-}
-
-#then we find all records with problems in the calculated_status field
-#$results = LabKey::Query::selectRows(
-# -baseUrl => $baseUrl,
-# -containerPath => $studyContainer,
-# -schemaName => 'study',
-# -queryName => 'Validate_status_mysql',
-# -requiredVersion => 8.3,
-# #-debug => 1,
-#);
-
-#if(@{$results->{rows}}){
-# $doSend = 1;
-#
-# my @ids;
-#
-# foreach my $row (@{$results->{rows}}){
-# push(@ids, $row->{'id'});
-# $email_html .= $row->{'id'}."
";
-# };
-#
-# $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with potential problems in the status field (based on old system).
";
-# $email_html .= "Click here to view these records
\n";
-# $email_html .= "Click here to edit demographics to fix the problems";
-# $email_html .= "
";
-#}
-
-
-#we find any active assignment where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find any active assignment where the project lacks a valid protocol
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ['protocol/protocol', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments to a project without a valid protocol.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find any duplicate active assignments
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'duplicateAssignments',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $doSend = 1;
-
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals double assigned to the same project.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-
-
-#open(HTML, ">", "C:\\Users\\Admin\\Desktop\\test.html");
-#print HTML $email_html;
-#close HTML;
-#die;
-
-if($doSend){
- $results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -requiredVersion => 8.3,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'NotificationRecipientsExpanded',
- -filterArray => [
- ['notificationtype', 'in', $notificationtypes],
- ],
- #-debug => 1,
- );
- if(@{$results->{rows}}){
- my @email_recipients;
- foreach my $row (@{$results->{rows}}){
- push(@email_recipients, $$row{email})
- }
-
- if(@email_recipients){
- #print (@email_recipients);die;
- @email_recipients = uniq @email_recipients;
- my $smtp = MIME::Lite->new(
- To =>join(", ", @email_recipients),
- From =>$from,
- Subject =>"Subject: Colony Alerts: $datestr",
- Type =>'multipart/alternative'
- );
- $smtp->attach(Type => 'text/html',
- Encoding => 'quoted-printable',
- Data => $email_html
- );
- $smtp->send() || die;
- }
- }
-}
-
-
-touch(File::Spec->catfile(dirname(abs_path($0)), '.colonyAlertsLiteLastRun'));
diff --git a/docker/ehrcron/scripts/automaticAlerts/colonyMgmtAlerts.pl b/docker/ehrcron/scripts/automaticAlerts/colonyMgmtAlerts.pl
deleted file mode 100644
index 3f25cb2ef..000000000
--- a/docker/ehrcron/scripts/automaticAlerts/colonyMgmtAlerts.pl
+++ /dev/null
@@ -1,429 +0,0 @@
-#!/usr/bin/env perl
-
-=head1 DESCRIPTION
-
-This script is designed to run as a cron job. It will query a number of tables an email a report.
-The report is designed to identify potential problems with the colony, primarily related to weights, housing
-and assignments.
-
-
-=head1 LICENSE
-
-This package and its accompanying libraries are free software; you can
-redistribute it and/or modify it under the terms of the GPL (either
-version 1, or at your option, any later version) or the Artistic
-License 2.0.
-
-=head1 AUTHOR
-
-Ben Bimber
-
-=cut
-
-#config options:
-my $baseUrl = $ENV{'LK_BASE_URL'};
-my $printableUrl = $ENV{'PERL_LINK_URL'};
-my $studyContainer = 'WNPRC/EHR/';
-
-my $notificationtypes = 'Colony Management Alerts';
-my $mail_server = $ENV{'MAIL_SERVER'};
-
-#emails will be sent from this address
-my $from = 'ehr-no-not-reply@primate.wisc.edu';
-
-
-############Do not edit below this line
-use strict;
-use warnings;
-use LabKey::Query;
-use Net::SMTP;
-use MIME::Lite;
-use Data::Dumper;
-use Time::localtime;
-use File::Touch;
-use File::Spec;
-use File::Basename;
-use Cwd 'abs_path';
-use List::MoreUtils qw/ uniq /;
-
-# Find today's date
-my $tm = localtime;
-my $datetimestr=sprintf("%04d-%02d-%02d at %02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min);
-my $datestr=sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
-
-my $yesterday = localtime( ( time() - ( 24 * 60 * 60 ) ) );
-$yesterday = sprintf("%04d-%02d-%02d", $yesterday->year+1900, ($yesterday->mon)+1, $yesterday->mday);
-
-my $tomorrow = localtime( ( time() + ( 24 * 60 * 60 ) ) );
-$tomorrow = sprintf("%04d-%02d-%02d", $tomorrow->year+1900, ($tomorrow->mon)+1, $tomorrow->mday);
-
-
-my $email_html = "This email contains a series of automatic alerts about the WNPRC colony. It was run on: $datetimestr.";
-my $results;
-
-#first we find all living animals without a weight:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -filterArray => [
- ['calculated_status', 'eq', 'Alive'],
- ['Id/MostRecentWeight/MostRecentWeightDate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following animals do not have a weight:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "
Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-
-#then we find all occupied cages without dimensions:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'missingCages',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following cages have animals, but do not have known dimensions:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'room'}."/".$row->{'cage'}."
";
- };
-
- $email_html .= "Click here to view the problem cages
\n";
- $email_html .= "Click here to edit the cage list and fix the problem\n";
-
- $email_html .= '
';
-}
-
-#then we list all animals in pc:
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Housing',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'eq', 'Alive'],
- ['cond', 'eq', 'pc'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- my $map = {};
- my $tempHTML = '';
-
- foreach my $row (@{$results->{rows}}){
-
- if(!$$map{$row->{'room'}}){
- $$map{$row->{'room'}} = {};
- }
-
- my $cage = $row->{'cage'};
- if ($cage =~ /^\d+$/ ){
- $cage = $cage + 0; #convert to number
- $$map{$row->{'room'}}{$cage} = [] unless $$map{$row->{'room'}}{$cage};
- push(@{$$map{$row->{'room'}}{$cage}}, $row->{'Id'});
- }
- };
-
- foreach my $room (sort keys %$map){
- my $roommap = $$map{$room};
- foreach my $cage (sort keys %$roommap){
- if(!$$roommap{$cage - 1} && !$$roommap{$cage + 1}){
- $tempHTML .= join(';', @{$$roommap{$cage}}).': '.$room."/".$cage."
";
- }
- }
- }
-
- if($tempHTML){
- $email_html .= "WARNING: The following animals are listed in protected contact, but do not appear to have an adjacent pc animal:
".$tempHTML;
- $email_html .= "Click here to view all pc animals
\n";
- $email_html .= '
';
- }
-}
-
-
-#then we find all records with potential housing condition problems
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'housingConditionProblems',
- -viewName => 'Problems',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." housing records with potential condition problems:
";
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'id'});
- $email_html .= $row->{'id'}."
";
- };
-
- $email_html .= "Click here to view these records
\n";
- $email_html .= "Click here to edit housing to fix the problems";
-
- #$email_html .= join('
', @ids);
- $email_html .= '
';
-}
-
-
-#then we find all animals with cage size problems
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'CageReview',
- -viewName => 'Problem Cages',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: The following cages are too small for the animals currently in them:
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Location'}."
";
- };
-
- $email_html .= "Click here to view these cages
\n";
- $email_html .= '
';
-}
-
-#then we find all animals lacking any assignments
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -viewName => 'No Active Assigns',
- -requiredVersion => 8.3,
- -debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." living animals without any active assignments:
";
-
- my @ids;
-
- foreach my $row (@{$results->{rows}}){
- push(@ids, $row->{'Id'});
- $email_html .= $row->{'Id'}."
";
- };
-
- $email_html .= "Click here to view these animals
\n";
- $email_html .= '
';
-}
-
-
-#we find any active assignment where the animal is not alive
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments for animals not currently at WNPRC.
";
- $email_html .= "Click here to view and update them
\n";
- $email_html .= "
\n";
-}
-
-#we find any active assignment where the project lacks a valid protocol
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Assignment',
- -filterArray => [
- ['Id/Dataset/Demographics/calculated_status', 'neqornull', 'Alive'],
- ['enddate', 'isblank', ''],
- ['protocol/protocol', 'isblank', ''],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." active assignments to a project without a valid protocol.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find any duplicate active assignments
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'duplicateAssignments',
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals double assigned to the same project.
";
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-
-#we find animals with hold codes, but not on pending
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'study',
- -queryName => 'Demographics',
- -filterArray => [
- ['hold', 'isnonblank', ''],
- ['Id/AssignmentSummary/NumPendingAssignments', 'eq', 0],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." animals with a hold code, but not on the pending project.
";
-
- foreach my $row (@{$results->{rows}}){
- $email_html .= $row->{'Id'}." (".$row->{'hold'}.")
";
- };
- $email_html .= "Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-#we find protocols nearing the animal limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'protocolTotalAnimalsBySpecies',
- -columns=>'protocol,allowed,PercentUsed,TotalRemaining,Species,protocol/inves',
- -filterArray => [
- ['TotalRemaining', 'lt', '5'],
- ['allowed', 'neq', '0'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." protocols with fewer than 5 remaining animals.
";
-
- $email_html .= "| Protocol | PI | Species | # Allowed | # Remaining | % Used |
";
- foreach my $rec (@{$results->{rows}}){
- $email_html .= "| ".$$rec{protocol}." | ".$$rec{'protocol/inves'}." | ".$$rec{'Species'}." | ".$$rec{'allowed'}." | ".$$rec{'TotalRemaining'}." | ".$$rec{'PercentUsed'}." |
";
- }
- $email_html .= "
\n";
-
-
- $email_html .= "
Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-#we find protocols nearing the animal limit
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'protocolTotalAnimalsBySpecies',
- -columns=>'protocol,allowed,PercentUsed,TotalRemaining,Species,protocol/inves',
- -filterArray => [
- ['PercentUsed', 'gte', '95'],
- ],
- -requiredVersion => 8.3,
- #-debug => 1,
-);
-
-
-if(@{$results->{rows}}){
- $email_html .= "WARNING: There are ".@{$results->{rows}}." protocols with fewer than 5% of their animals remaining.
";
-
- $email_html .= "| Protocol | PI | Species | # Allowed | # Remaining | % Used |
";
- foreach my $rec (@{$results->{rows}}){
- $email_html .= "| ".$$rec{protocol}." | ".$$rec{'protocol/inves'}." | ".$$rec{'Species'}." | ".$$rec{'allowed'}." | ".$$rec{'TotalRemaining'}." | ".$$rec{'PercentUsed'}." |
";
- }
- $email_html .= "
\n";
-
- $email_html .= "
Click here to view them
\n";
- $email_html .= "
\n";
-}
-
-
-
-
-#open(HTML, ">", "C:\\Users\\Admin\\Desktop\\test.html");
-#print HTML $email_html;
-#close HTML;
-#die;
-
-$results = LabKey::Query::selectRows(
- -baseUrl => $baseUrl,
- -requiredVersion => 8.3,
- -containerPath => $studyContainer,
- -schemaName => 'ehr',
- -queryName => 'NotificationRecipientsExpanded',
- -filterArray => [
- ['notificationtype', 'in', $notificationtypes],
- ],
- #-debug => 1,
-);
-if(@{$results->{rows}}){
- my @email_recipients;
- foreach my $row (@{$results->{rows}}){
- push(@email_recipients, $$row{email})
- }
-
- if(@email_recipients){
- #print (@email_recipients);die;
- @email_recipients = uniq @email_recipients;
- my $smtp = MIME::Lite->new(
- To =>join(", ", @email_recipients),
- From =>$from,
- Subject =>"Subject: Daily Colony Management Alerts: $datestr",
- Type =>'multipart/alternative'
- );
- $smtp->attach(Type => 'text/html',
- Encoding => 'quoted-printable',
- Data => $email_html
- );
- $smtp->send() || die;
- }
-}
-
-touch(File::Spec->catfile(dirname(abs_path($0)), '.colonyMgmtAlertsLastRun'));
From 051bb94831fe9790ad75a111576fa9682fc74d88 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 5 Sep 2024 16:50:10 -0500
Subject: [PATCH 23/29] Added comment to leave commented-out code block alone.
This will be used for future notifications, and it's very tough coding this
correctly in the right order. Please do not delete.
---
.../src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 9848cc66a..6af04e8eb 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -4072,6 +4072,9 @@ public void notificationRevampSetup() throws UnhandledAlertException, IOExceptio
NotificationAdminPage notificationAdminPage = ehrAdminPage.clickNotificationService(this);
// Updates the notification user and reply email.
notificationAdminPage.setNotificationUserAndReplyEmail(DATA_ADMIN_USER);
+
+ // ***PLEASE LEAVE THE FOLLOWING CODE BLOCK COMMENTED OUT - DO NOT DELETE***
+ // ***THIS WILL BE USED TO ENABLE DUMBSTER IN FUTURE NOTIFICATIONS***
// Enables all notification that we will be testing. //TODO a34: Can we remake a function with an appropriate name for this? Something like "enableNotification" maybe.
// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAll");
// notificationAdminPage.enableDeathNotification("status_org.labkey.wnprc_ehr.notification.BloodDrawsTodayAnimalCare");
From 8690123532ee06f140df44bb925558bfdcd916c1 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Mon, 16 Sep 2024 17:32:12 -0500
Subject: [PATCH 24/29] Removed function call for notification tests in
doSetup(). This was recommended by Binal via a LabKey ticket; it caused my
test to run twice since the @test annotation already exists.
---
.../src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
index 6af04e8eb..4633afeb2 100644
--- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
+++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java
@@ -284,9 +284,6 @@ public static void doSetup() throws Exception
initTest.setupAnimalRequests();
initTest.checkUpdateProgramIncomeAccount();
-
- initTest.notificationRevampSetup();
-
}
private void billingSetup() throws Exception
From 47084a53dc448d76755111b845e015333a234104 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 25 Sep 2024 17:24:30 -0500
Subject: [PATCH 25/29] - TriggerScriptHelper.java: Added trigger call for new
AnimalRequestUpdateNotificationRevamp notification. Also moved call for old
notification inside if/else statement so 'on/off' status is checked before
sending. Will delete the old call after vefifying new version works well.
- WNPRC_EHRModule.java: Registered new EmptyNotificationRevamp and AnimalRequestUpdateNotificationRevamp notifications.
- AdminAlertsNotificationRevamp.java: Updated this notification so the days of the week are displayed in the correct order. Also fixed an error with the wrong results being queried (needed to update the filter).
- AnimalRequestNotificationRevamp.java: Added test data to be set when notification is triggered from 'Run Report in Browser'. Also added a resetClass function.
- AnimalRequestUpdateNotificationRevamp.java: Created this new revamped notification.
- ColonyAlertsLiteNotificationRevamp.java: Updated this notification to use the new EmptyNotificationRevamp notification. This is sent instead of the original notification if there is no data to be sent.
- EmptyNotificationRevamp.java: Created this new revamped notification. This is sent when certain notifications have no data to send. This is to prevent users from receiving empty emails, but allows Daniel and I to see that the notifications are still being sent.
- NotificationToolkit.java: Added function to send the new EmptyNotificationRevamp.java notification.
---
.../labkey/wnprc_ehr/TriggerScriptHelper.java | 29 ++-
.../org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 4 +-
.../AdminAlertsNotificationRevamp.java | 13 +-
.../AnimalRequestNotificationRevamp.java | 26 +++
...AnimalRequestUpdateNotificationRevamp.java | 192 ++++++++++++++++++
.../ColonyAlertsLiteNotificationRevamp.java | 20 +-
.../notification/EmptyNotificationRevamp.java | 88 ++++++++
.../notification/NotificationToolkit.java | 9 +
8 files changed, 372 insertions(+), 9 deletions(-)
create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestUpdateNotificationRevamp.java
create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/EmptyNotificationRevamp.java
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
index 069b55809..f6e81b7cb 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
@@ -54,6 +54,7 @@
import org.labkey.wnprc_ehr.notification.AnimalRequestNotification;
import org.labkey.wnprc_ehr.notification.AnimalRequestNotificationRevamp;
import org.labkey.wnprc_ehr.notification.AnimalRequestNotificationUpdate;
+import org.labkey.wnprc_ehr.notification.AnimalRequestUpdateNotificationRevamp;
import org.labkey.wnprc_ehr.notification.BloodDrawReviewTriggerNotification;
import org.labkey.wnprc_ehr.notification.BloodOverdrawTriggerNotification;
import org.labkey.wnprc_ehr.notification.DeathNotification;
@@ -870,7 +871,7 @@ public void sendAnimalRequestNotification(Integer rowid, String hostName){
//Verifies 'Notification Service' is enabled before sending notification.
if (NotificationService.get().isServiceEnabled()){
//Sends original Animal Request Notification.
- //Remove this if-else when new notification is approved.
+ //TODO: Remove this if-else when new notification is approved.
if (NotificationService.get().isActive(new AnimalRequestNotification(ehr), container)) {
_log.info("Using java helper to send email for animal request record: "+rowid);
AnimalRequestNotification notification = new AnimalRequestNotification(ehr, rowid, user, hostName);
@@ -895,10 +896,30 @@ else if (!NotificationService.get().isServiceEnabled()) {
}
}
public void sendAnimalRequestNotificationUpdate(Integer rowid, Map row, Map oldRow, String hostName){
- _log.info("Using java helper to send email for animal request record: "+rowid);
Module ehr = ModuleLoader.getInstance().getModule("EHR");
- AnimalRequestNotificationUpdate notification = new AnimalRequestNotificationUpdate(ehr, rowid, row, oldRow, user, hostName);
- notification.sendManually(container, user);
+
+ // Verifies 'Notification Service' is enabled before sending notification.
+ if (NotificationService.get().isServiceEnabled()) {
+ // Sends original Animal Request Update Notification.
+ // TODO: Remove this if-else when new notification is approved.
+ if (NotificationService.get().isActive(new AnimalRequestNotificationUpdate(ehr), container)) {
+ _log.info("Using java helper to send email for animal request record: "+rowid);
+ AnimalRequestNotificationUpdate notification = new AnimalRequestNotificationUpdate(ehr, rowid, row, oldRow, user, hostName);
+ notification.sendManually(container, user);
+ }
+ else {
+ _log.info("Animal Request Update Notification is not enabled, will not send animal request notification.");
+ }
+
+ // Sends revamped Animal Request Notification.
+ if (NotificationService.get().isActive(new AnimalRequestUpdateNotificationRevamp(ehr), container)) {
+ _log.info("Using java helper to send animal request update notification revamp for animal request record: " + rowid);
+ AnimalRequestUpdateNotificationRevamp notification = new AnimalRequestUpdateNotificationRevamp(ehr, rowid, user, container, hostName, row, oldRow);
+ }
+ }
+ else if (!NotificationService.get().isServiceEnabled()) {
+ _log.info("Notification service is not enabled, will not send animal request update notification.");
+ }
}
public void sendProjectNotification(Integer key, String hostName){
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
index 215aac420..7c9832694 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
@@ -390,7 +390,9 @@ public void registerNotifications() {
new AdminAlertsNotificationRevamp(this),
new ColonyManagementNotificationRevamp(this),
new ColonyAlertsLiteNotificationRevamp(this),
- new BloodOverdrawTriggerNotification(this)
+ new BloodOverdrawTriggerNotification(this),
+ new EmptyNotificationRevamp(this),
+ new AnimalRequestUpdateNotificationRevamp(this)
);
for (Notification notification : notifications)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AdminAlertsNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AdminAlertsNotificationRevamp.java
index fe0d81268..00782608f 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AdminAlertsNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AdminAlertsNotificationRevamp.java
@@ -3,7 +3,9 @@
import org.labkey.api.data.CompareType;
import org.labkey.api.data.Container;
import org.labkey.api.data.SimpleFilter;
+import org.labkey.api.data.Sort;
import org.labkey.api.module.Module;
+import org.labkey.api.query.FieldKey;
import org.labkey.api.security.User;
import java.lang.reflect.Array;
@@ -61,6 +63,7 @@ public String getCategory() {
public String getMessageBodyHTML(Container c, User u) {
// Gets AdminAlertsNotificationRevampObject.
AdminAlertsNotificationObject myAdminAlertsNotificationObject = new AdminAlertsNotificationObject(c, u);
+ Boolean messageIsEmpty = true;
// Begins message body.
StringBuilder messageBody = new StringBuilder();
@@ -116,12 +119,14 @@ public static class AdminAlertsNotificationObject {
// 1. Summarizes site usage in the past 7 days (gets list of logins).
void getSiteUsageSummaryLastSevenDays() {
// Creates filter.
- Date dateSevenDaysAgo = dateToolkit.getDateXDaysFromNow(-7);
+ Date dateSevenDaysAgo = dateToolkit.getDateXDaysFromNow(-50);
SimpleFilter myFilter = new SimpleFilter("date", dateSevenDaysAgo, CompareType.DATE_GTE);
+ // Creates sort.
+ Sort mySort = new Sort("+date");
// Creates columns to retrieve.
String[] targetColumns = new String[]{"dayOfWeek", "date", "Logins"};
// Runs query.
- ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(currentContainer, currentUser, "core", "SiteUsageByDay", myFilter, null, targetColumns);
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(currentContainer, currentUser, "core", "SiteUsageByDay", myFilter, mySort, targetColumns);
// Formats return data into ArrayList to pass in as table data.
for (HashMap currentSiteUsage : returnArray) {
String currentDayOfWeek = currentSiteUsage.get("dayOfWeek");
@@ -137,7 +142,9 @@ void getNumClientErrorsSinceYesterday() {
// Creates filter.
Date dateYesterday = dateToolkit.getDateXDaysFromNow(-1);
SimpleFilter myFilter = new SimpleFilter("date", dateYesterday, CompareType.DATE_GTE);
- myFilter.addCondition("key1", "LabKey Server Backup", CompareType.NEQ);
+ myFilter.addCondition("key1", "LabKey Server Backup", CompareType.NEQ_OR_NULL);
+ myFilter.addCondition("EventType", "Client API Actions", CompareType.EQUAL);
+
// Runs query.
ArrayList returnArray = notificationToolkit.getTableMultiRowSingleColumn(currentContainer, currentUser, "auditlog", "audit", myFilter, null, "RowId", null);
this.numClientErrorsSinceYesterday = Long.valueOf(returnArray.size());
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestNotificationRevamp.java
index 4cb6886c9..a75e5ef15 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestNotificationRevamp.java
@@ -1,12 +1,16 @@
package org.labkey.wnprc_ehr.notification;
import org.labkey.api.data.Container;
+import org.labkey.api.data.SimpleFilter;
+import org.labkey.api.data.Sort;
import org.labkey.api.module.Module;
import org.labkey.api.security.User;
import org.labkey.api.util.Path;
import org.labkey.api.view.ActionURL;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
public class AnimalRequestNotificationRevamp extends AbstractEHRNotification
{
@@ -87,6 +91,21 @@ public String getMessageBodyHTML(Container c, User u)
final StringBuilder msg = new StringBuilder();
Date now = new Date();
+ // Assigns data if none exists. This is used for testing with the 'Run Report in Browser' option.
+ if (rowId == null) {
+ // Creates filter.
+ Sort mySort = new Sort("-date");
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"rowid"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "wnprc", "animal_requests", null, mySort, targetColumns);
+
+ // Assigns most recent rowID to class 'rowId' variable.
+ if (!returnArray.isEmpty()) {
+ this.rowId = Integer.valueOf(returnArray.get(0).get("rowid"));
+ }
+ }
+
//Sets data.
String currentDate = AbstractEHRNotification._dateFormat.format(now);
String currentTime = AbstractEHRNotification._timeFormat.format(now);
@@ -105,7 +124,14 @@ public String getMessageBodyHTML(Container c, User u)
msg.append("View all of the animal requests " + allRequestsHyperlink + ".
");
//Returns string.
+ this.resetClass();
return msg.toString();
}
+ public void resetClass() {
+ this.rowId = null;
+ this.currentUser = null;
+ this.hostName = null;
+ }
+
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestUpdateNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestUpdateNotificationRevamp.java
new file mode 100644
index 000000000..a060204b4
--- /dev/null
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/AnimalRequestUpdateNotificationRevamp.java
@@ -0,0 +1,192 @@
+package org.labkey.wnprc_ehr.notification;
+
+import org.labkey.api.data.CompareType;
+import org.labkey.api.data.Container;
+import org.labkey.api.data.SimpleFilter;
+import org.labkey.api.data.Sort;
+import org.labkey.api.data.TableInfo;
+import org.labkey.api.data.queryprofiler.Query;
+import org.labkey.api.module.Module;
+import org.labkey.api.query.QueryService;
+import org.labkey.api.security.User;
+import org.labkey.api.util.Path;
+import org.labkey.api.view.ActionURL;
+import org.labkey.wnprc_ehr.TriggerScriptHelper;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AnimalRequestUpdateNotificationRevamp extends AbstractEHRNotification
+{
+ //Class Variables
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
+ NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
+ public User currentUser;
+ public Container currentContainer;
+ public String hostName;
+ public Map newRow;
+ public Map oldRow;
+ public Integer rowID;
+
+ //Constructors
+ /**
+ * This constructor is used to register the notification in WNPRC_EHRModule.java.
+ * @param owner
+ */
+ public AnimalRequestUpdateNotificationRevamp(Module owner)
+ {
+ super(owner);
+ }
+ /**
+ * This constructor is used to actually send the notification via the "TriggerScriptHelper.java" class.
+ * @param owner
+ * @param myRowID
+ * @param myCurrentUser
+ * @param myHostName
+ * @param myNewRow
+ * @param myOldRow
+ */
+ public AnimalRequestUpdateNotificationRevamp(Module owner, Integer myRowID, User myCurrentUser, Container myCurrentContainer, String myHostName, Map myNewRow, Map myOldRow)
+ {
+ super(owner);
+ this.currentUser = myCurrentUser;
+ this.rowID = myRowID;
+ this.currentContainer = myCurrentContainer;
+ this.hostName = myHostName;
+ this.newRow = myNewRow;
+ this.oldRow = myOldRow;
+ }
+
+
+
+ //Notification Details
+ public String getName()
+ {
+ return "Animal Request Update Notification Revamp";
+ }
+ public String getDescription() {
+ return "This notification gets sent every time there is an Animal Request that gets updated.";
+ }
+ @Override
+ public String getEmailSubject(Container c)
+ {
+ return "[EHR Services] (Revamp) Animal Request Updated on " + dateToolkit.getCurrentTime();
+ }
+ public String getScheduleDescription()
+ {
+ return "As soon as Animal Request is updated.";
+ }
+ @Override
+ public String getCategory()
+ {
+ return "Revamped Notifications";
+ }
+
+
+
+ //Sending Options
+ public void sendManually (Container container, User user)
+ {
+ notificationToolkit.sendNotification(this, user, container, null);
+ }
+
+
+
+ //Message Creation
+ @Override
+ public String getMessageBodyHTML(Container c, User u)
+ {
+ // Assigns data if none exists. This is used for testing with the 'Run Report in Browser' option. This compares the two most recent rows.
+ if ((this.newRow == null) || (this.oldRow == null)) {
+ // Creates filters. For testing, we retrieve the most recent entry for 1 animal, and the most recent entry for 2 animals.
+ SimpleFilter myFilter1 = new SimpleFilter("numberofanimals", 1, CompareType.EQUAL);
+ SimpleFilter myFilter2 = new SimpleFilter("numberofanimals", 2, CompareType.EQUAL);
+ // Creates sort.
+ Sort mySort = new Sort("-date");
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"rowid", "numberofanimals"};
+ // Runs query.
+ ArrayList> returnArray1 = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "wnprc", "animal_requests", myFilter1, mySort, targetColumns);
+ ArrayList> returnArray2 = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "wnprc", "animal_requests", myFilter2, mySort, targetColumns);
+
+ // Assigns most recent row to this.newRow and the second most recent row to this.oldRow.
+ if ((!returnArray1.isEmpty()) && (!returnArray2.isEmpty())) {
+ // Assigns new row id.
+ this.rowID = Integer.valueOf(returnArray1.get(0).get("rowid"));
+ // Assigns new row.
+ this.newRow = new HashMap<>() {{
+ put("numberOfAnimals", returnArray1.get(0).get("numberofanimals"));
+ }};
+ // Assigns old row.
+ this.oldRow = new HashMap<>() {{
+ put("numberOfAnimals", returnArray2.get(0).get("numberofanimals"));
+ }};
+ }
+ }
+
+ //Creates 'single request' URL.
+ Path singleRequestURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "");
+ String singleRequestUrlAsString = singleRequestURL.toString() + "manageRecord.view?schemaName=wnprc&queryName=animal_requests&title=Animal%20Requests&keyField=rowid&key=" + this.rowID;
+ //Creates 'all requests' URL.
+ Path allRequestsURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "");
+ String allRequestsUrlAsString = allRequestsURL.toString() + "dataEntry.view?#topTab:Requests&activeReport:AnimalRequests\"";
+
+ // Creates variables.
+ final StringBuilder msg = new StringBuilder();
+ String updaterName = "";
+ // Gets the name of the user updating this Animal Request.
+ if (u != null) {
+ if (!u.getFullName().isEmpty()) {
+ updaterName = u.getFullName();
+ }
+ else if (!u.getDisplayName(u).isEmpty()) {
+ updaterName = u.getDisplayName(u);
+ }
+ }
+ // Gets the row differences.
+ TableInfo rowDifferencesTable = QueryService.get().getUserSchema(u, c, "wnprc").getTable("animal_requests");
+ Map> rowDifferences = TriggerScriptHelper.buildDifferencesMap(rowDifferencesTable, this.oldRow, this.newRow);
+ // Gets the table.
+ String[] myTableColumns = new String[]{"Field Changed", "Old Value", "New Value"};
+ List myTableData = new ArrayList<>();
+ for (Map.Entry> change : rowDifferences.entrySet()) {
+ String[] newTableRow = new String[] {
+ change.getKey(),
+ change.getValue().get(0),
+ change.getValue().get(1)
+ };
+ myTableData.add(newTableRow);
+ }
+ NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, (ArrayList) myTableData);
+
+ // Creates CSS.
+ msg.append(styleToolkit.beginStyle());
+ msg.append(styleToolkit.setBasicTableStyle());
+ msg.append(styleToolkit.setHeaderRowBackgroundColor("#d9d9d9"));
+ msg.append(styleToolkit.endStyle());
+
+ // Begins message info.
+ msg.append("" + updaterName + " updated an animal request entry on: " + dateToolkit.getDateXDaysFromNow(0) + ".
");
+ msg.append(" The following changes were made:
");
+ msg.append(myTable.createBasicHTMLTable());
+ msg.append("
Click " + notificationToolkit.createHyperlink("here", singleRequestUrlAsString) + " to review the request.
");
+ msg.append("View all of the animal requests " + notificationToolkit.createHyperlink("here", allRequestsUrlAsString) + ".
");
+
+ //Returns string.
+ this.resetClass();
+ return msg.toString();
+ }
+
+ public void resetClass() {
+ this.currentUser = null;
+ this.currentContainer = null;
+ this.oldRow = null;
+ this.newRow = null;
+ this.hostName = null;
+ }
+}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsLiteNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsLiteNotificationRevamp.java
index 656372e90..6851a7a23 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsLiteNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsLiteNotificationRevamp.java
@@ -56,6 +56,7 @@ public String getMessageBodyHTML(Container c, User u)
// Creates variables & gets data.
StringBuilder messageBody = new StringBuilder();
ColonyAlertsNotificationRevamp.ColonyInformationObject myColonyInformationObject = new ColonyAlertsNotificationRevamp.ColonyInformationObject(c, u, "colonyAlertLite");
+ Boolean emptyMessage = true;
// Begins message info.
messageBody.append("This email contains a series of automatic alerts about the WNPRC colony. It was run on: " + dateToolkit.getCurrentTime() + ".
");
@@ -63,6 +64,7 @@ public String getMessageBodyHTML(Container c, User u)
// Creates message.
// 1. Find all living animals with multiple active housing records.
if (!myColonyInformationObject.livingAnimalsWithMultipleActiveHousingRecords.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.livingAnimalsWithMultipleActiveHousingRecords.size() + " animals with multiple active housing records:
");
for (String result : myColonyInformationObject.livingAnimalsWithMultipleActiveHousingRecords) {
messageBody.append(result + "
");
@@ -73,12 +75,14 @@ public String getMessageBodyHTML(Container c, User u)
}
// 2. Find all animals where the housing snapshot doesn't match the housing table.
if (!myColonyInformationObject.livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTable.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTable.size() + " animals where the housing snapshot doesn't match the housing table. The snapshot has been automatically refreshed:
");
messageBody.append(notificationToolkit.createHyperlink("
Click here to view the report again
\n", myColonyInformationObject.livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTableURLView));
messageBody.append("
");
}
// 3. Find all records with potential housing condition problems.
if (!myColonyInformationObject.recordsWithPotentialHousingConditionProblems.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.recordsWithPotentialHousingConditionProblems.size() + " housing records with potential condition problems:
");
for (String result : myColonyInformationObject.recordsWithPotentialHousingConditionProblems) {
messageBody.append(result + "
");
@@ -89,12 +93,14 @@ public String getMessageBodyHTML(Container c, User u)
}
// 4. Find non-continguous housing records.
if (!myColonyInformationObject.nonContiguousHousingRecords.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.nonContiguousHousingRecords.size() + " housing records since " + dateToolkit.getCalendarDateToday() + " that do not have a contiguous previous or next record.
");
messageBody.append(notificationToolkit.createHyperlink("Click here to view and update them
\n", myColonyInformationObject.nonContiguousHousingRecordsURLView));
messageBody.append("
\n");
}
// 5. Find open housing records where the animal is not alive.
if (!myColonyInformationObject.openHousingRecordsWhereAnimalIsNotAlive.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.openHousingRecordsWhereAnimalIsNotAlive.size() + " active housing records where the animal is not alive:
");
for (String result : myColonyInformationObject.openHousingRecordsWhereAnimalIsNotAlive) {
messageBody.append(result + "
");
@@ -104,6 +110,7 @@ public String getMessageBodyHTML(Container c, User u)
}
// 6. Find living animals without an active housing record.
if (!myColonyInformationObject.livingAnimalsWithoutActiveHousingRecord.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.livingAnimalsWithoutActiveHousingRecord.size() + " living animals without an active housing record:
");
for (String result : myColonyInformationObject.livingAnimalsWithoutActiveHousingRecord) {
messageBody.append(result + "
");
@@ -113,6 +120,7 @@ public String getMessageBodyHTML(Container c, User u)
}
// 7. Find all records with problems in the calculated_status field.
if (!myColonyInformationObject.recordsWithCalculatedStatusFieldProblems.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.recordsWithCalculatedStatusFieldProblems.size() + " animals with problems in the status field:
");
for (String result : myColonyInformationObject.recordsWithCalculatedStatusFieldProblems) {
messageBody.append(result + "
");
@@ -124,24 +132,34 @@ public String getMessageBodyHTML(Container c, User u)
}
// 8. Find any active assignment where the animal is not alive.
if (!myColonyInformationObject.activeAssignmentsWhereAnimalIsNotAlive.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.activeAssignmentsWhereAnimalIsNotAlive.size() + " active assignments for animals not currently at WNPRC.
");
messageBody.append(notificationToolkit.createHyperlink("Click here to view and update them
\n", myColonyInformationObject.activeAssignmentsWhereAnimalIsNotAliveURLView));
messageBody.append("
\n");
}
// 9. Find any active assignment where the project lacks a valid protocol.
if (!myColonyInformationObject.activeAssignmentsWhereProjectLacksValidProtocol.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.activeAssignmentsWhereProjectLacksValidProtocol.size() + " active assignments to a project without a valid protocol.
");
messageBody.append(notificationToolkit.createHyperlink("Click here to view them
\n", myColonyInformationObject.activeAssignmentsWhereProjectLacksValidProtocolURLView));
messageBody.append("
\n");
}
// 10. Find any duplicate active assignments.
if (!myColonyInformationObject.duplicateActiveAssignments.isEmpty()) {
+ emptyMessage = false;
messageBody.append("WARNING: There are " + myColonyInformationObject.duplicateActiveAssignments.size() + " animals double assigned to the same project.
");
messageBody.append(notificationToolkit.createHyperlink("Click here to view them
\n", myColonyInformationObject.duplicateActiveAssignmentsURLView));
messageBody.append("
\n");
}
//Returns string.
- return messageBody.toString();
+ if (emptyMessage == false) {
+ return messageBody.toString();
+ }
+ else {
+ notificationToolkit.sendEmptyNotificationRevamp(c, u, "Colony Alerts Lite");
+ return null;
+ }
+
}
}
\ No newline at end of file
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/EmptyNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/EmptyNotificationRevamp.java
new file mode 100644
index 000000000..58b188d85
--- /dev/null
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/EmptyNotificationRevamp.java
@@ -0,0 +1,88 @@
+package org.labkey.wnprc_ehr.notification;
+
+import org.labkey.api.data.Container;
+import org.labkey.api.module.Module;
+import org.labkey.api.security.User;
+import org.labkey.wnprc_ehr.notification.AbstractEHRNotification;
+import org.labkey.wnprc_ehr.notification.NotificationToolkit;
+
+public class EmptyNotificationRevamp extends AbstractEHRNotification {
+ //Class Variables
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ String notificationType = null;
+
+
+ // Constructors
+ /**
+ * This constructor is used to register the notification in WNPRC_EHRModule.java.
+ * @param owner
+ */
+ public EmptyNotificationRevamp(Module owner) {super(owner);}
+
+ //This constructor is used to actually send the notification via the "TriggerScriptHelper.java" class.
+ public EmptyNotificationRevamp(Module owner, String emptyNotificationType) {
+ super(owner);
+ this.notificationType = emptyNotificationType;
+ }
+
+
+
+ // Notification Details
+ @Override
+ public String getName() {
+ return "Empty Notification";
+ }
+ @Override
+ public String getDescription() {
+ return "This email sends when any of the revamped notifications are triggered but do not contain data.";
+ }
+ @Override
+ public String getEmailSubject(Container c) {
+ String subject = "Empty Notification";
+ if (notificationType != null) {
+ subject += ": " + notificationType;
+ }
+ return subject;
+ }
+ @Override
+ public String getScheduleDescription() {
+ return "Triggered when an empty notification is sent.";
+ }
+ @Override
+ public String getCategory() {
+ return "Revamped Notifications";
+ }
+
+
+
+ // Sending Options
+ public void sendManually (Container container, User user){
+ notificationToolkit.sendNotification(this, user, container, null);
+ }
+
+
+
+ // Message Creation
+ @Override
+ public String getMessageBodyHTML(Container c, User u) {
+ // Set up.
+ StringBuilder messageBody = new StringBuilder();
+
+ // Begins message info.
+ messageBody.append("A revamped notification was triggered, but the message body contained no data.
");
+ if (notificationType != null) {
+ messageBody.append("Notification Type: " + notificationType + "
");
+ }
+ else {
+ messageBody.append("ERROR: Could not retrieve notification type.
");
+ }
+
+ // Returns message info.
+ this.resetClass();
+ return messageBody.toString();
+ }
+
+ public void resetClass() {
+ this.notificationType = null;
+ }
+}
\ No newline at end of file
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
index cc650a5d8..f22abc21e 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java
@@ -1051,6 +1051,15 @@ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck,
return null;
}
+ public void sendEmptyNotificationRevamp(Container c, User u, String notificationType) {
+ Module ehr = ModuleLoader.getInstance().getModule("EHR");
+ _log.info("Using NotificationToolkit to send email for Empty Notification Revamp (notificationType: " + notificationType + ").");
+ EmptyNotificationRevamp notification = new EmptyNotificationRevamp(ehr, notificationType);
+ if (notification != null) {
+ notification.sendManually(c, u);
+ }
+ }
+
From de299acfddaef2078628271c7f860822d64b0948 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Thu, 26 Sep 2024 13:31:42 -0500
Subject: [PATCH 26/29] - TriggerScriptHelper.java: Added 'sendManually'
function call that I had forgotten. - BloodDrawReviewDailyNotification.java:
Added 2 extra checks requested by blood draw team. -
BloodDrawsTodayAnimalCare.java: Updated this to use the new dummy
notification when there is no data to be sent.
---
.../labkey/wnprc_ehr/TriggerScriptHelper.java | 1 +
.../BloodDrawReviewDailyNotification.java | 61 +++++++++++++++++++
.../BloodDrawsTodayAnimalCare.java | 11 +---
3 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
index f6e81b7cb..b2929a3c0 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/TriggerScriptHelper.java
@@ -915,6 +915,7 @@ public void sendAnimalRequestNotificationUpdate(Integer rowid, MapThere are no blood draws (today or future) where animal is not assigned to a project.
\n");
}
+ // Lists all blood draws (today & future) not yet approved.
+ if (!myBloodDrawReviewObject.bloodDrawsNotApproved.isEmpty()) {
+ messageBody.append("WARNING: There are " + myBloodDrawReviewObject.bloodDrawsNotApproved.size() + " blood draws requested that have not been approved or denied yet.
");
+ messageBody.append(notificationToolkit.createHyperlink("Click here to view them
\n", myBloodDrawReviewObject.bloodDrawsNotApprovedURLView));
+ }
+ else {
+ messageBody.append("There are no blood draws (today or future) where blood draw is not yet approved.
\n");
+ }
+ // Lists all blood draws (today & future) not yet assigned to a group (i.e. SPI, Animal Care, Vet Staff).
+ if (!myBloodDrawReviewObject.bloodDrawsNotAssignedToGroup.isEmpty()) {
+ messageBody.append("
WARNING: There are " + myBloodDrawReviewObject.bloodDrawsNotAssignedToGroup.size() + " blood draws requested that have not been assigned to a group.
");
+ messageBody.append(notificationToolkit.createHyperlink("Click here to view them
\n", myBloodDrawReviewObject.bloodDrawsNotAssignedToGroupURLView));
+ }
+ else {
+ messageBody.append("There are no blood draws (today or future) where blood draw is not yet assigned to a group.
\n");
+ }
return messageBody.toString();
}
@@ -142,6 +158,8 @@ public static class BloodDrawReviewDailyObject {
getNonAliveBloodDraws();
getUnassignedBloodDraws();
getBloodOverdraws();
+ getBloodDrawsNotApproved();
+ getBloodDrawsNotAssignedToGroup();
}
ArrayList nonAliveBloodDraws = new ArrayList<>();
@@ -230,5 +248,48 @@ void getBloodOverdraws() {
String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "BloodSchedule", myFilter);
this.bloodOverdrawsURLView = viewQueryURL;
}
+
+ ArrayList> bloodDrawsNotApproved = new ArrayList<>();
+ String bloodDrawsNotApprovedURLView;
+ void getBloodDrawsNotApproved() {
+ // Creates filter.
+ Date todayDate = dateToolkit.getDateToday();
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL);
+ myFilter.addCondition("qcstate/label", "Request: Pending", CompareType.EQUAL);
+ myFilter.addCondition("date", todayDate, CompareType.DATE_GTE);
+
+ // Creates sort.
+ Sort mySort = new Sort("date");
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"id"};
+ // Runs query.
+ bloodDrawsNotApproved = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Blood Draws", myFilter, mySort, targetColumns);
+
+ // Creates URL.
+ String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Blood Draws", myFilter);
+ this.bloodDrawsNotApprovedURLView = viewQueryURL;
+ }
+
+ ArrayList> bloodDrawsNotAssignedToGroup = new ArrayList<>();
+ String bloodDrawsNotAssignedToGroupURLView;
+ void getBloodDrawsNotAssignedToGroup() {
+ Date todayDate = dateToolkit.getDateToday();
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL);
+ myFilter.addCondition("qcstate/label", "Request: Denied", CompareType.NEQ);
+ myFilter.addCondition("billedby", "", CompareType.ISBLANK);
+ myFilter.addCondition("date", todayDate, CompareType.DATE_GTE);
+
+ // Creates sort.
+ Sort mySort = new Sort("date");
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"id"};
+ // Runs query.
+ bloodDrawsNotAssignedToGroup = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Blood Draws", myFilter, mySort, targetColumns);
+
+ // Creates URL.
+ String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Blood Draws", myFilter);
+ this.bloodDrawsNotAssignedToGroupURLView = viewQueryURL;
+ }
+
}
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAnimalCare.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAnimalCare.java
index b32bc742c..64970a6ba 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAnimalCare.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAnimalCare.java
@@ -69,17 +69,12 @@ public String getMessageBodyHTML(Container c, User u) {
// Creates table.
if (myBloodDrawNotificationObject.resultsByArea.isEmpty()) {
- messageBody.append("There are no scheduled blood draws for this group today.");
+ notificationToolkit.sendEmptyNotificationRevamp(c, u, "Blood Draws Today (Animal Care)");
+ return null;
}
else {
messageBody.append(myBloodDrawNotificationObject.printTablesAsHTML());
+ return messageBody.toString();
}
-
-// String[] myTableColumns = new String[]{"Id", "Blood Remaining", "Project Assignment", "Completion Status", "Group", "Other Groups Drawing Blood Today"};
-// NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, myBloodDrawNotificationObject.myTableData);
-// myTable.rowColors = myBloodDrawNotificationObject.myTableRowColors;
-// messageBody.append(myTable.createBasicHTMLTable());
-
- return messageBody.toString();
}
}
From dd4be9ee10d81757ebe1c35ffbe0ca46904480d0 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Mon, 7 Oct 2024 18:10:51 -0500
Subject: [PATCH 27/29] - animal_requests.js: Added fix for fatal issue with
qcstatus being different in dataset and form. -
ColonyAlertsNotificationRevamp.java: Added extra query requested by Kim.
This query checks all animals in the 'Assignments' dataset and returns any
where the project has expired or the protocol has deactivated.
---
.../queries/wnprc/animal_requests.js | 20 +++-
.../ColonyAlertsNotificationRevamp.java | 104 ++++++++++++++++++
2 files changed, 123 insertions(+), 1 deletion(-)
diff --git a/WNPRC_EHR/resources/queries/wnprc/animal_requests.js b/WNPRC_EHR/resources/queries/wnprc/animal_requests.js
index 2c9cfa381..81cac97da 100644
--- a/WNPRC_EHR/resources/queries/wnprc/animal_requests.js
+++ b/WNPRC_EHR/resources/queries/wnprc/animal_requests.js
@@ -90,6 +90,24 @@ function onAfterInsert(helper,errors,row){
function onAfterUpdate(helper,errors,row,oldRow){
var rowid = row.rowId;
var hostName = 'https://' + LABKEY.serverName;
- console.log ("animal_requests.js: New request updated, rowid: "+ rowid);
+ console.log("animal_requests.js: New request updated, rowid: "+ rowid);
+
+ if ("QCStateLabel" in row) {
+ delete row.QCState;
+ row["qcstate"] = row["QCStateLabel"];
+ delete row.QCStateLabel;
+ }
+ if ("QCStateLabel" in oldRow) {
+ oldRow["qcstate"] = oldRow["QCStateLabel"];
+ delete oldRow.QCStateLabel;
+ }
+
+ if ("_publicData" in row) {
+ delete row._publicData;
+ }
+ if ("_publicData" in oldRow) {
+ delete oldRow._publicData;
+ }
+
WNPRC.Utils.getJavaHelper().sendAnimalRequestNotificationUpdate(rowid, row, oldRow, hostName);
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
index bda4861a3..9efef875e 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
@@ -1,6 +1,8 @@
package org.labkey.wnprc_ehr.notification;
import org.checkerframework.checker.units.qual.A;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
import org.labkey.api.action.Action;
import org.labkey.api.data.ColumnInfo;
import org.labkey.api.data.CompareType;
@@ -27,6 +29,8 @@
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -41,6 +45,8 @@
import javax.script.ScriptEngine;
+import static org.labkey.api.search.SearchService._log;
+
/**
* Created by Alex Schmidt on 12/27/23.
@@ -97,6 +103,12 @@ public String getMessageBodyHTML(Container c, User u) {
final StringBuilder messageBody = new StringBuilder();
ColonyInformationObject myColonyAlertObject = new ColonyInformationObject(c, u, "colonyAlert");
+ // Creates CSS.
+ messageBody.append(styleToolkit.beginStyle());
+ messageBody.append(styleToolkit.setBasicTableStyle());
+ messageBody.append(styleToolkit.setHeaderRowBackgroundColor("#d9d9d9"));
+ messageBody.append(styleToolkit.endStyle());
+
//Begins message info.
messageBody.append(" This email contains a series of automatic alerts about the colony. It was run on: " + dateToolkit.getCurrentTime() + ".
");
@@ -373,6 +385,19 @@ public String getMessageBodyHTML(Container c, User u) {
messageBody.append(notificationToolkit.createHyperlink("Click here to view them
\n", myColonyAlertObject.totalFinalizedRecordsWithFutureDatesURLView));
messageBody.append("
\n");
}
+ //38. Find any animals assigned to an inactivated project or deactivated protocol.
+ if (!myColonyAlertObject.animalsWithInvalidProjectOrProtocol.isEmpty()) {
+ // Creates HTML table to return.
+ String[] myTableColumns = new String[]{"Id", "Project", "Project End Date", "Protocol", "Protocol End Date"};
+ NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, myColonyAlertObject.animalsWithInvalidProjectOrProtocol);
+
+ // Displays message.
+ messageBody.append("WARNING: There are " + myColonyAlertObject.animalsWithInvalidProjectOrProtocol.size() + " living animals with inactivated projects or deactivated protocols.
");
+ messageBody.append(myTable.createBasicHTMLTable());
+ messageBody.append(notificationToolkit.createHyperlink("Click here to view all Assignments.
\n", myColonyAlertObject.animalsWithInvalidProjectOrProtocolURLView));
+ messageBody.append("
\n");
+
+ }
//Returns string.
return messageBody.toString();
@@ -469,6 +494,8 @@ public ColonyInformationObject(Container currentContainer, User currentUser, Str
getPrenatalDeathsInLastFiveDays();
//37. Find the total finalized records with future dates.
getTotalFinalizedRecordsWithFutureDates();
+ //38. Find any animals assigned to an inactivated project or deactivated protocol.
+ getAnimalsWithInvalidProjectOrProtocol();
}
else if (alertType.equals("colonyManagement")) {
// 1. Find all living animals without a weight.
@@ -1356,6 +1383,83 @@ private void getProtocolsNearingAnimalLimitPercentage() {
this.protocolsNearingAnimalLimitPercentage = returnArray;
this.protocolsNearingAnimalLimitPercentageURLView = viewQueryURL;
}
+
+ // Find any animals assigned to an inactivated project or deactivated protocol.
+ ArrayList animalsWithInvalidProjectOrProtocol = new ArrayList<>(); //
+ String animalsWithInvalidProjectOrProtocolURLView;
+ private void getAnimalsWithInvalidProjectOrProtocol() {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id/Dataset/Demographics/calculated_status", "Alive", CompareType.EQUAL);
+// myFilter.addCondition("project/protocol", "", CompareType.NONBLANK);
+ // Gets columns to retrieve.
+ String[] targetColumns = new String[]{"id", "project", "project/protocol", "project/enddate", "project/protocol/enddate"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Assignment", myFilter, null, targetColumns);
+
+ // Sets up a Try/Catch block to catch date parsing errors.
+ try {
+ // Sets variables.
+ SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
+ Date formattedCurrentDate = myFormat.parse(dateToolkit.getCurrentTime());
+
+ for (HashMap result : returnArray) {
+ // 0: ID
+ // 1: Project
+ // 2: Project End Date
+ // 3: Protocol
+ // 4: Protocol End Date
+ String[] myCurrentRow = new String[5];
+ myCurrentRow[1] = "";
+ myCurrentRow[2] = "";
+ myCurrentRow[3] = "";
+ myCurrentRow[4] = "";
+
+ // Retrieves row data.
+ String currentID = result.get("id");
+ String currentProject = result.get("project");
+ String currentProtocol = result.get("project/protocol");
+ String currentProjectEnd = result.get("project/enddate");
+ String currentProtocolEnd = result.get("project/protocol/enddate");
+ Boolean projectOrProtocolExpired = false;
+
+ // Adds id.
+ myCurrentRow[0] = currentID;
+ // Checks project.
+ if (currentProject != null && currentProjectEnd != null) {
+ if (!currentProject.isEmpty() && !currentProjectEnd.isEmpty()) {
+ Date formattedProjectEnd = myFormat.parse(currentProjectEnd);
+ if (formattedCurrentDate.compareTo(formattedProjectEnd) > 0) {
+ myCurrentRow[1] = currentProject;
+ myCurrentRow[2] = currentProjectEnd;
+ projectOrProtocolExpired = true;
+ }
+ }
+ }
+ // Checks protocol.
+ if (currentProtocol != null && currentProtocolEnd != null) {
+ if (!currentProtocol.isEmpty() && !currentProtocolEnd.isEmpty()) {
+ Date formattedProtocolEnd = myFormat.parse(currentProtocolEnd);
+ if (formattedCurrentDate.compareTo(formattedProtocolEnd) > 0) {
+ myCurrentRow[3] = currentProtocol;
+ myCurrentRow[4] = currentProtocolEnd;
+ projectOrProtocolExpired = true;
+ }
+ }
+ }
+
+ // Adds row to return list if there is an expired project or protocol.
+ if (projectOrProtocolExpired) {
+ animalsWithInvalidProjectOrProtocol.add(myCurrentRow);
+ }
+ }
+ }
+ catch (ParseException e) {
+ _log.error("There was a parsing exception for: ColonyAlertsNotificationRevamp->getAnimalsWithInvalidProjectOrProtocol", e);
+ }
+
+ // Creates url link to the assignments table.
+ this.animalsWithInvalidProjectOrProtocolURLView = notificationToolkit.createQueryURL(c, "execute", "study", "Assignment", null);
+ }
}
}
From 1bc7ea8a78c6545bf090ceaf0aff72c9faa4d622 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Wed, 30 Oct 2024 16:01:49 -0500
Subject: [PATCH 28/29] - WNPRC_EHRModule.java: Registered new notification. -
TreatmentAlertsNotificationRevamp.java: Created new notification. -
BloodDrawsTodayAll.java: Added 'incomplete count' to the notification (as
requested by blood draw team). - BloodDrawsTodayVetStaff.java: Added
functionality so message does not send when there is no data (as requested by
blood draw team).
---
.../org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 3 +-
.../notification/BloodDrawsTodayAll.java | 54 ++-
.../notification/BloodDrawsTodayVetStaff.java | 10 +-
.../TreatmentAlertsNotificationRevamp.java | 438 ++++++++++++++++++
4 files changed, 477 insertions(+), 28 deletions(-)
create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/TreatmentAlertsNotificationRevamp.java
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
index 7c9832694..abdebd68e 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java
@@ -392,7 +392,8 @@ public void registerNotifications() {
new ColonyAlertsLiteNotificationRevamp(this),
new BloodOverdrawTriggerNotification(this),
new EmptyNotificationRevamp(this),
- new AnimalRequestUpdateNotificationRevamp(this)
+ new AnimalRequestUpdateNotificationRevamp(this),
+ new TreatmentAlertsNotificationRevamp(this)
);
for (Notification notification : notifications)
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 8030b9204..e143099c2 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java
@@ -81,18 +81,17 @@ public String getMessageBodyHTML(Container c, User u) {
// Prints all tables.
if (myBloodDrawNotificationObject.resultsByArea.isEmpty()) {
- messageBody.append("There are no scheduled blood draws for this group today.");
+ messageBody.append("There are no scheduled blood draws today.");
}
else {
+ messageBody.append("REMAINING INCOMPLETE TOTALS:
\n");
+ messageBody.append("Animal Care: " + myBloodDrawNotificationObject.numIncompleteAnimalCare + "\n");
+ messageBody.append("Research Staff: " + myBloodDrawNotificationObject.numIncompleteResearchStaff + "\n");
+ messageBody.append("SPI: " + myBloodDrawNotificationObject.numIncompleteSPI + "\n");
+ messageBody.append("Vet Staff: " + myBloodDrawNotificationObject.numIncompleteVetStaff + "
");
messageBody.append(myBloodDrawNotificationObject.printTablesAsHTML());
}
-// // Creates table.
-// String[] myTableColumns = new String[]{"Id", "Blood Remaining", "Project Assignment", "Completion Status", "Group", "Other Groups Drawing Blood Today"};
-// NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, myBloodDrawNotificationObject.myTableData);
-// myTable.rowColors = myBloodDrawNotificationObject.myTableRowColors;
-// messageBody.append(myTable.createBasicHTMLTable());
-
return messageBody.toString();
}
@@ -105,8 +104,11 @@ 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).
HashMap>> resultsByArea = new HashMap<>(); // Area(Room(List of draws))
+ Integer numIncompleteSPI = 0;
+ Integer numIncompleteAnimalCare = 0;
+ Integer numIncompleteVetStaff = 0;
+ Integer numIncompleteResearchStaff = 0;
//Gets all info for the BloodDrawNotificationObject.
@@ -145,8 +147,10 @@ public static class BloodDrawsTodayObject {
// Updates id.
myCurrentRow[0] = result.get("id");
+
// Updates blood remaining.
myCurrentRow[1] = result.get("BloodRemaining/AvailBlood");
+
// Updates project status (this checks if animal is assigned to a project).
if (!result.get("qcstate/label").equals("Request: Denied") && !result.get("projectStatus").isEmpty()) {
myCurrentRow[2] = "UNASSIGNED";
@@ -154,6 +158,7 @@ public static class BloodDrawsTodayObject {
else {
myCurrentRow[2] = "";
}
+
// Updates completion status (this checks if blood draw has been completed).
if (!result.get("qcstate/label").equals("Completed")) {
myCurrentRow[3] = "INCOMPLETE";
@@ -161,8 +166,10 @@ public static class BloodDrawsTodayObject {
else {
myCurrentRow[3] = "";
}
+
// Updates the current group assigned to this animal.
myCurrentRow[4] = result.get("billedby/title");
+
// Updates the current area.
if (!result.get("Id/curLocation/area").isEmpty()) {
myCurrentRow[6] = result.get("Id/curLocation/area");
@@ -170,6 +177,7 @@ public static class BloodDrawsTodayObject {
else {
myCurrentRow[6] = "Unknown Area";
}
+
// Updates the current room.
if (!result.get("Id/curLocation/room").isEmpty()) {
myCurrentRow[7] = result.get("Id/curLocation/room");
@@ -191,18 +199,6 @@ else if (availBlood <= bloodThreshold) {
myCurrentRow[8] = "orange";
}
}
-// String currentRowColor = "white";
-// if (!result.get("BloodRemaining/AvailBlood").isEmpty()) {
-// Float availBlood = Float.parseFloat(result.get("BloodRemaining/AvailBlood"));
-// if (availBlood <= 0) {
-// // If blood draw is over limit, color it red.
-// currentRowColor = "red";
-// }
-// else if (availBlood <= bloodThreshold) {
-// // If blood draw is over threshold limit, color it orange.
-// currentRowColor = "orange";
-// }
-// }
// Adds the current row to myTableData (based on group being queried).
if (assignmentGroup.equals("animalCare")) {
@@ -234,6 +230,24 @@ else if (assignmentGroup.equals("vetStaff")) {
myTableData.add(myCurrentRow);
}
}
+
+ // Updates number of incomplete draws.
+ if (assignmentGroup.equals("all")) {
+ if (myCurrentRow[3].equals("INCOMPLETE")) {
+ if (result.get("billedby/title").equals("SPI")) {
+ numIncompleteSPI++;
+ }
+ else if (result.get("billedby/title").equals("Animal Care")) {
+ numIncompleteAnimalCare++;
+ }
+ else if (result.get("billedby/title").equals("Research Staff")) {
+ numIncompleteResearchStaff++;
+ }
+ else if (result.get("billedby/title").equals("Vet Staff")) {
+ numIncompleteVetStaff++;
+ }
+ }
+ }
}
//Goes through each draw to find draws scheduled for more than one group, then updates myTableData with information.
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayVetStaff.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayVetStaff.java
index 35de535fd..a4ebcd972 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayVetStaff.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayVetStaff.java
@@ -69,17 +69,13 @@ public String getMessageBodyHTML(Container c, User u) {
// Creates table.
if (myBloodDrawNotificationObject.resultsByArea.isEmpty()) {
- messageBody.append("There are no scheduled blood draws for this group today.");
+ notificationToolkit.sendEmptyNotificationRevamp(c, u, "Blood Draws Today (Vet Staff)");
+ return null;
}
else {
messageBody.append(myBloodDrawNotificationObject.printTablesAsHTML());
+ return messageBody.toString();
}
-// String[] myTableColumns = new String[]{"Id", "Blood Remaining", "Project Assignment", "Completion Status", "Group", "Other Groups Drawing Blood Today"};
-// NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(myTableColumns, myBloodDrawNotificationObject.myTableData);
-// myTable.rowColors = myBloodDrawNotificationObject.myTableRowColors;
-// messageBody.append(myTable.createBasicHTMLTable());
-
- return messageBody.toString();
}
}
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/TreatmentAlertsNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/TreatmentAlertsNotificationRevamp.java
new file mode 100644
index 000000000..13412570a
--- /dev/null
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/TreatmentAlertsNotificationRevamp.java
@@ -0,0 +1,438 @@
+package org.labkey.wnprc_ehr.notification;
+
+import org.labkey.api.data.CompareType;
+import org.labkey.api.data.Container;
+import org.labkey.api.data.SimpleFilter;
+import org.labkey.api.data.Sort;
+import org.labkey.api.module.Module;
+import org.labkey.api.security.User;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+public class TreatmentAlertsNotificationRevamp extends AbstractEHRNotification {
+ //Class Variables
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
+ NotificationToolkit.StyleToolkit styleToolkit = new NotificationToolkit.StyleToolkit();
+
+
+
+
+
+ // Constructors
+ /**
+ * This constructor is used to register the notification in WNPRC_EHRModule.java.
+ * @param owner
+ */
+ public TreatmentAlertsNotificationRevamp(Module owner) {super(owner);}
+
+
+
+
+
+ // Notification Details
+ @Override
+ public String getName() {
+ return "Treatment Alerts Notification Revamp";
+ }
+ @Override
+ public String getDescription() {
+ return "This email contains any scheduled treatments not marked as completed.";
+ }
+ @Override
+ public String getEmailSubject(Container c) {
+ return "Treatment Alerts: " + dateToolkit.getCurrentTime();
+ }
+ @Override
+ public String getScheduleDescription() {
+ return "Daily at 6:00AM, 10:00AM, 1:00PM, 3:00PM, 5:00PM, 7:00PM";
+ }
+ @Override
+ public String getCronString() {
+ return notificationToolkit.createCronString("0", "6,10,13,15,17,19", "*");
+ }
+ @Override
+ public String getCategory() {
+ return "Revamped Notifications";
+ }
+
+
+
+
+
+ //Message Creation
+ @Override
+ public String getMessageBodyHTML(Container c, User u) {
+
+ // Creates variables & gets data.
+ final StringBuilder messageBody = new StringBuilder();
+ TreatmentAlertsObject myTreatmentAlertsObject = new TreatmentAlertsObject(c, u);
+
+ // Creates CSS.
+ messageBody.append(styleToolkit.beginStyle());
+ messageBody.append(styleToolkit.setBasicTableStyle());
+ messageBody.append(styleToolkit.setHeaderRowBackgroundColor("#d9d9d9"));
+ messageBody.append(styleToolkit.endStyle());
+
+ // Begins message info.
+ messageBody.append("This email contains any scheduled treatments not marked as completed. It was run on: " + dateToolkit.getCurrentTime() + ".");
+
+ // Creates message.
+ // 1. Shows all rooms lacking observations today.
+ if (!myTreatmentAlertsObject.roomsLackingObservationsToday.isEmpty()) {
+ messageBody.append("WARNING: The following rooms do not have any obs for today as of: " + dateToolkit.getCurrentTime() + ".");
+ messageBody.append("" + notificationToolkit.createHyperlink("Click here to view them.
\n", myTreatmentAlertsObject.roomsLackingObservationsTodayUrlView));
+ for (HashMap result : myTreatmentAlertsObject.roomsLackingObservationsToday) {
+ messageBody.append(result.get("room") + "
");
+ }
+ messageBody.append("
\n");
+ }
+ // 2. Shows all treatments where the animal is not assigned to that project.
+ if (!myTreatmentAlertsObject.treatmentsWithAnimalNotAssignedToProject.isEmpty()) {
+ messageBody.append("WARNING: There are " + myTreatmentAlertsObject.treatmentsWithAnimalNotAssignedToProject.size() + " scheduled treatments where the animal is not assigned to the project.
");
+ messageBody.append("" + notificationToolkit.createHyperlink("Click here to view them.
\n", myTreatmentAlertsObject.treatmentsWithAnimalNotAssignedToProjectUrlView));
+ messageBody.append("
\n");
+ }
+ // 3. Shows treatments for each time of day.
+ String[] timesOfDay = {"AM", "Noon", "PM", "Any Time", "Night"};
+ String[] treatmentColumns = new String[]{"ID", "Treatment", "Route", "Concentration", "Amount To Give", "Volume", "Instructions", "Ordered By"};
+
+ for (String timeOfDay : timesOfDay) {
+ // Verifies there are treatments scheduled.
+ Integer totalTreatments = myTreatmentAlertsObject.incompleteTreatmentsForEachTimeOfDay.get(timeOfDay).size() + myTreatmentAlertsObject.completedTreatmentCountsForEachTimeOfDay.get(timeOfDay);
+ if (totalTreatments > 0) {
+ messageBody.append("There are " + totalTreatments + " scheduled " + timeOfDay + " treatments. " + myTreatmentAlertsObject.completedTreatmentCountsForEachTimeOfDay.get(timeOfDay) + " have been completed. ");
+ messageBody.append("" + notificationToolkit.createHyperlink("Click here to view them.
\n", myTreatmentAlertsObject.treatmentsForEachTimeOfDayUrlView.get(timeOfDay)));
+
+ // Creates the current timeOfDay results sorted by (area --> room --> result).
+ HashMap>>> resultsByArea = new HashMap<>();
+
+ for (HashMap result : myTreatmentAlertsObject.incompleteTreatmentsForEachTimeOfDay.get(timeOfDay)) {
+ String currentArea = result.get("CurrentArea");
+ String currentRoom = result.get("CurrentRoom");
+ // Adds result if area does not yet exist.
+ if (!resultsByArea.containsKey(currentArea)) {
+ // Creates new treatments list.
+ ArrayList> roomTreatments = new ArrayList<>();
+ roomTreatments.add(result);
+ // Adds new treatments list to new room.
+ HashMap>> newRoom = new HashMap<>();
+ newRoom.put(currentRoom, roomTreatments);
+ // Adds new room to new area.
+ resultsByArea.put(currentArea, newRoom);
+ }
+ // Adds result if area exists but room does not yet exist.
+ else if (!resultsByArea.get(currentArea).containsKey(currentRoom)) {
+ // Creates new treatments list.
+ ArrayList> roomTreatments = new ArrayList<>();
+ roomTreatments.add(result);
+ // Adds new room to new area.
+ resultsByArea.get(currentArea).put(currentRoom, roomTreatments);
+ }
+ // Adds result if area and room both exist.
+ else {
+ resultsByArea.get(currentArea).get(currentRoom).add(result);
+ }
+ }
+
+ // Iterates through each area (sorted alphabetically).
+ for (String currentArea : notificationToolkit.sortSetWithNulls(resultsByArea.keySet())) {
+ messageBody.append("" + currentArea + ":
\n");
+ // Iterates through each room (sorted alphabetically)
+ for (String currentRoom : notificationToolkit.sortSetWithNulls(resultsByArea.get(currentArea).keySet())) {
+ messageBody.append(currentRoom + ": " + resultsByArea.get(currentArea).get(currentRoom).size() + "
\n");
+ // Reformats the treatment hashmap into a String[] List (to be compatible with the table creation function).
+ ArrayList formattedResults = new ArrayList<>();
+ for (HashMap currentTreatment : resultsByArea.get(currentArea).get(currentRoom)) {
+ String[] newTableRow = new String[]{
+ currentTreatment.get("Id"),
+ currentTreatment.get("meaning"),
+ currentTreatment.get("route"),
+ currentTreatment.get("conc2"),
+ currentTreatment.get("amount2"),
+ currentTreatment.get("volume2"),
+ currentTreatment.get("remark"),
+ currentTreatment.get("performedby")
+ };
+ formattedResults.add(newTableRow);
+ }
+ // Displays table with results.
+ NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(treatmentColumns, formattedResults);
+ messageBody.append(myTable.createBasicHTMLTable());
+ }
+ }
+
+ }
+ else {
+ messageBody.append("There are no scheduled " + timeOfDay + " treatments as of " + dateToolkit.getCurrentTime() + ". Treatments could be added after this email was sent, so please check online closer to the time.");
+ }
+ messageBody.append("
\n");
+ }
+ // 4. Shows any treatments from today that differ from the order.
+ if (!myTreatmentAlertsObject.differentOrderTreatments.isEmpty()) {
+ // Reformats the String List into a String[] List (to be compatible with the table creation function).
+ ArrayList formattedResults = new ArrayList<>();
+ for (String result : myTreatmentAlertsObject.differentOrderTreatments) {
+ formattedResults.add(new String[]{result});
+ }
+ // Creates the necessary table.
+ String[] diffTableColumns = new String[]{"DIFFERING TREATMENTS"};
+ NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(diffTableColumns, formattedResults);
+ messageBody.append(myTable.createBasicHTMLTable());
+ messageBody.append("
\n");
+ }
+ // 5. Shows any treatments where the animal is not alive.
+ if (!myTreatmentAlertsObject.treatmentsWhereAnimalIsNotAlive.isEmpty()) {
+ messageBody.append("WARNING: There are " + myTreatmentAlertsObject.treatmentsWhereAnimalIsNotAlive.size() + " active treatments for animals not currently at WNPRC.");
+ messageBody.append("" + notificationToolkit.createHyperlink("Click here to view and update them.
\n", myTreatmentAlertsObject.treatmentsWhereAnimalIsNotAliveURLView));
+ messageBody.append("
\n");
+ }
+ // 6. Find any problems where the animal is not alive.
+ if (!myTreatmentAlertsObject.problemsWhereAnimalIsNotAlive.isEmpty()) {
+ messageBody.append("WARNING: There are " + myTreatmentAlertsObject.problemsWhereAnimalIsNotAlive.size() + " unresolved problems for animals not currently at WNPRC.");
+ messageBody.append("" + notificationToolkit.createHyperlink("Click here to view and update them.
\n", myTreatmentAlertsObject.problemsWhereAnimalIsNotAliveUrlView));
+ messageBody.append("
\n");
+ }
+ // 7. Checks for missing In Rooms after 2:30pm, as specified in the SOP.
+ if (!myTreatmentAlertsObject.missingInRoomsAfterTwoThirty.isEmpty()) {
+ messageBody.append("WARNING: There are " + myTreatmentAlertsObject.missingInRoomsAfterTwoThirty.size() + " " + notificationToolkit.createHyperlink("animals without In Rooms", myTreatmentAlertsObject.missingInRoomsAfterTwoThirtyUrlView) + ".");
+ }
+
+
+ return messageBody.toString();
+ }
+
+ // Gets all info for Treatment Alerts.
+ public static class TreatmentAlertsObject {
+ //Set up.
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit();
+ Date todayDate = dateToolkit.getDateToday();
+
+ TreatmentAlertsObject(Container c, User u) {
+ getRoomsLackingObservationsToday(c, u);
+ getTreatmentsWithAnimalNotAssignedToProject(c, u);
+ getIncompleteTreatmentsForEachTimeOfDay(c, u);
+ getDifferentOrderTreatments(c, u);
+ getTreatmentsWhereAnimalIsNotAlive(c, u);
+ getProblemsWhereAnimalIsNotAlive(c, u);
+ getMissingInRoomsAfterTwoThirty(c, u);
+ }
+
+ // Gets any rooms lacking observations for today.
+ ArrayList> roomsLackingObservationsToday;
+ String roomsLackingObservationsTodayUrlView;
+ private void getRoomsLackingObservationsToday(Container c, User u) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("hasObs", "N", CompareType.EQUAL);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"room"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "ehr", "RoomsWithoutObsToday", myFilter, null, targetColumns);
+
+ // Assigns data.
+ this.roomsLackingObservationsToday = returnArray;
+ this.roomsLackingObservationsTodayUrlView = notificationToolkit.createQueryURL(c, "execute", "ehr", "RoomsWithoutObsToday", myFilter);
+ }
+
+ // Gets all treatments (today) where the animal is not assigned to that project.
+ ArrayList> treatmentsWithAnimalNotAssignedToProject;
+ String treatmentsWithAnimalNotAssignedToProjectUrlView;
+ private void getTreatmentsWithAnimalNotAssignedToProject(Container c, User u) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL);
+ myFilter.addCondition("projectStatus", "", CompareType.NONBLANK);
+ myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"Id"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "treatmentSchedule", myFilter, null, targetColumns);
+
+ // Assigns data.
+ this.treatmentsWithAnimalNotAssignedToProject = returnArray;
+ this.treatmentsWithAnimalNotAssignedToProjectUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", myFilter);
+ }
+
+ // Gets all treatments (today) for each time of the day (AM, Noon, PM, Any Time, Night).
+ HashMap>> incompleteTreatmentsForEachTimeOfDay = new HashMap<>() {{
+ put("AM", new ArrayList());
+ put("Noon", new ArrayList());
+ put("PM", new ArrayList());
+ put("Any Time", new ArrayList());
+ put("Night", new ArrayList());
+ }};
+ HashMap completedTreatmentCountsForEachTimeOfDay = new HashMap<>() {{
+ put("AM", 0);
+ put("Noon", 0);
+ put("PM", 0);
+ put("Any Time", 0);
+ put("Night", 0);
+ }};
+ HashMap treatmentsForEachTimeOfDayUrlView = new HashMap<>();
+ private void getIncompleteTreatmentsForEachTimeOfDay(Container c, User u) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.EQUAL);
+ myFilter.addCondition("date", todayDate, CompareType.DATE_EQUAL);
+ // Creates sort.
+ Sort mySort = new Sort("CurrentArea,CurrentRoom");
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"timeofday", "Id", "CurrentArea", "CurrentRoom", "CurrentCage", "projectStatus", "treatmentStatus", "treatmentStatus/Label", "meaning", "code", "volume2", "conc2", "route", "amount2", "remark", "performedby"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "treatmentSchedule", myFilter, mySort, targetColumns);
+
+ if (!returnArray.isEmpty()) {
+ // Sorts data for each time of day.
+ for (HashMap currentTreatment : returnArray) {
+ String treatmentTime = currentTreatment.get("timeofday");
+ // Verifies time of day is one of the 5 supported times.
+ if (treatmentTime != null) {
+ if (treatmentTime.equals("AM") || treatmentTime.equals("Noon") || treatmentTime.equals("PM") || treatmentTime.equals("Any Time") || treatmentTime.equals("Night")) {
+ if (currentTreatment.get("treatmentStatus/Label").equals("Completed")) {
+ Integer currentCount = completedTreatmentCountsForEachTimeOfDay.get(treatmentTime);
+ completedTreatmentCountsForEachTimeOfDay.put(treatmentTime, currentCount + 1);
+ }
+ else {
+ incompleteTreatmentsForEachTimeOfDay.get(treatmentTime).add(currentTreatment);
+ }
+ }
+ }
+ }
+ // Updates official class variable for each time of day's URL view.
+ SimpleFilter amFilter = new SimpleFilter(myFilter);
+ SimpleFilter noonFilter = new SimpleFilter(myFilter);
+ SimpleFilter pmFilter = new SimpleFilter(myFilter);
+ SimpleFilter anytimeFilter = new SimpleFilter(myFilter);
+ SimpleFilter nightFilter = new SimpleFilter(myFilter);
+ amFilter.addCondition("timeofday", "AM", CompareType.EQUAL);
+ noonFilter.addCondition("timeofday", "Noon", CompareType.EQUAL);
+ pmFilter.addCondition("timeofday", "PM", CompareType.EQUAL);
+ anytimeFilter.addCondition("timeofday", "Any Time", CompareType.EQUAL);
+ nightFilter.addCondition("timeofday", "Night", CompareType.EQUAL);
+ this.treatmentsForEachTimeOfDayUrlView.put("AM", notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", amFilter));
+ this.treatmentsForEachTimeOfDayUrlView.put("Noon", notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", noonFilter));
+ this.treatmentsForEachTimeOfDayUrlView.put("PM", notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", pmFilter));
+ this.treatmentsForEachTimeOfDayUrlView.put("Any Time", notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", anytimeFilter));
+ this.treatmentsForEachTimeOfDayUrlView.put("Night", notificationToolkit.createQueryURL(c, "execute", "study", "treatmentSchedule", nightFilter));
+ }
+ }
+
+ // Gets all treatments (today) that differ from the order.
+ List differentOrderTreatments;
+ String differentOrderTreatmentsUrlView;
+ private void getDifferentOrderTreatments(Container c, User u) {
+ // Creates variable.
+ List resultsAsTableEntries = new ArrayList<>();
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("date", todayDate, CompareType.DATE_EQUAL);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"CurrentArea", "CurrentRoom", "id", "date", "meaning", "performedby", "drug_performedby", "route", "drug_route", "concentration", "drug_concentration", "conc_units", "drug_conc_units", "dosage", "drug_dosage", "dosage_units", "drug_dosage_units", "amount", "drug_amount", "amount_units", "drug_amount_units", "volume", "drug_volume", "vol_units", "drug_vol_units"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "TreatmentsThatDiffer", myFilter, null, targetColumns);
+
+ for (HashMap currentTreatment : returnArray) {
+ // Creates variable.
+ StringBuilder currentTableEntry = new StringBuilder();
+
+ // Displays the basic info for the current treatment.
+ currentTableEntry.append("Id: " + currentTreatment.get("id") + "
\n");
+ currentTableEntry.append("Date: " + currentTreatment.get("date") + "
\n");
+ currentTableEntry.append("Treatment: " + currentTreatment.get("meaning") + "
\n");
+ currentTableEntry.append("Ordered By: " + currentTreatment.get("performedby") + "
\n");
+ currentTableEntry.append("Performed By: " + currentTreatment.get("drug_performedby") + "
\n");
+
+ // Displays which order/entry field in the treatment does not match.
+ // Compares the route.
+ if (!currentTreatment.get("route").equals(currentTreatment.get("drug_route"))) {
+ currentTableEntry.append("Route Ordered: " + currentTreatment.get("route") + "
\n");
+ currentTableEntry.append("Route Entered: " + currentTreatment.get("drug_route") + "
\n");
+ }
+ // Compares the concentration & concentration units.
+ if (!currentTreatment.get("concentration").equals(currentTreatment.get("drug_concentration")) || !currentTreatment.get("conc_units").equals(currentTreatment.get("drug_conc_units"))) {
+ currentTableEntry.append("Concentration Ordered: " + currentTreatment.get("concentration") + " " + currentTreatment.get("conc_units") + "
\n");
+ currentTableEntry.append("Concentration Entered: " + currentTreatment.get("drug_concentration") + " " + currentTreatment.get("drug_conc_units") + "
\n");
+ }
+ // Compares the dosage & dosage units.
+ if (!currentTreatment.get("dosage").equals(currentTreatment.get("drug_dosage")) || !currentTreatment.get("dosage_units").equals(currentTreatment.get("drug_dosage_units"))) {
+ currentTableEntry.append("Dosage Ordered: " + currentTreatment.get("dosage") + " " + currentTreatment.get("dosage_units") + "
\n");
+ currentTableEntry.append("Dosage Entered: " + currentTreatment.get("drug_dosage") + " " + currentTreatment.get("drug_dosage_units") + "
\n");
+ }
+ // Compares the amount & amount units.
+ if (!currentTreatment.get("amount").equals(currentTreatment.get("drug_amount")) || !currentTreatment.get("amount_units").equals(currentTreatment.get("drug_amount_units"))) {
+ currentTableEntry.append("Amount Ordered: " + currentTreatment.get("amount") + " " + currentTreatment.get("amount_units") + "
\n");
+ currentTableEntry.append("Amount Entered: " + currentTreatment.get("drug_amount") + " " + currentTreatment.get("drug_amount_units") + "
\n");
+ }
+ // Compares the volume & volume units.
+ if (!currentTreatment.get("volume").equals(currentTreatment.get("drug_volume")) || !currentTreatment.get("vol_units").equals(currentTreatment.get("drug_vol_units"))) {
+ currentTableEntry.append("Volume Ordered: " + currentTreatment.get("volume") + " " + currentTreatment.get("vol_units") + "
\n");
+ currentTableEntry.append("Volume Entered: " + currentTreatment.get("drug_volume") + " " + currentTreatment.get("drug_vol_units") + "
\n");
+ }
+
+ // Adds treatment to table row list.
+ resultsAsTableEntries.add(currentTableEntry.toString());
+ }
+
+ // Assigns data.
+ this.differentOrderTreatments = resultsAsTableEntries;
+ this.differentOrderTreatmentsUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "TreatmentsThatDiffer", myFilter);
+ }
+
+ // Gets all treatments (today & future) where the animal is not alive.
+ ArrayList> treatmentsWhereAnimalIsNotAlive;
+ String treatmentsWhereAnimalIsNotAliveURLView;
+ private void getTreatmentsWhereAnimalIsNotAlive(Container c, User u) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.NEQ_OR_NULL);
+ myFilter.addCondition("enddate", "", CompareType.ISBLANK);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"Id"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Treatment Orders", myFilter, null, targetColumns);
+
+ // Assigns data.
+ this.treatmentsWhereAnimalIsNotAlive = returnArray;
+ this.treatmentsWhereAnimalIsNotAliveURLView = notificationToolkit.createQueryURL(c, "execute", "study", "Treatment Orders", myFilter);
+ }
+
+ // Gets any problems (today & future) where the animal is not alive.
+ ArrayList> problemsWhereAnimalIsNotAlive;
+ String problemsWhereAnimalIsNotAliveUrlView;
+ private void getProblemsWhereAnimalIsNotAlive(Container c, User u) {
+ // Creates filter.
+ SimpleFilter myFilter = new SimpleFilter("Id/DataSet/Demographics/calculated_status", "Alive", CompareType.NEQ_OR_NULL);
+ myFilter.addCondition("enddate", "", CompareType.ISBLANK);
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"Id"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Problem List", myFilter, null, targetColumns);
+
+ // Assigns data.
+ this.problemsWhereAnimalIsNotAlive = returnArray;
+ this.problemsWhereAnimalIsNotAliveUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "Problem List", myFilter);
+ }
+
+ // Checks for missing-in-rooms after 2:30pm, as specified in the SOP.
+ ArrayList> missingInRoomsAfterTwoThirty;
+ String missingInRoomsAfterTwoThirtyUrlView;
+ private void getMissingInRoomsAfterTwoThirty(Container c, User u) {
+ // Creates columns to retrieve.
+ String[] targetColumns = new String[]{"Id"};
+ // Runs query.
+ ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "inRoomNotSubmitted", null, null, targetColumns);
+
+ // Assigns data.
+ this.missingInRoomsAfterTwoThirty = returnArray;
+ this.missingInRoomsAfterTwoThirtyUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "inRoomNotSubmitted", null);
+ }
+
+
+
+
+
+
+ }
+
+}
From 64c61a31ce54627ab84c63a7458e9b9d3a8f5760 Mon Sep 17 00:00:00 2001
From: aschmidt34
Date: Fri, 22 Nov 2024 12:15:59 -0600
Subject: [PATCH 29/29] Removed joda time import statement because it was
unused.
---
.../wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
index 9efef875e..872a428e8 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java
@@ -1,8 +1,6 @@
package org.labkey.wnprc_ehr.notification;
import org.checkerframework.checker.units.qual.A;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
import org.labkey.api.action.Action;
import org.labkey.api.data.ColumnInfo;
import org.labkey.api.data.CompareType;