From 5968b20de14b022feb76db8d88b94bc1fca69d02 Mon Sep 17 00:00:00 2001 From: aschmidt34 <124093649+aschmidt34@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:59:20 -0600 Subject: [PATCH] 24.3 fb notification revamps (#712) * - 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. * Migrated automated test changes from 23.11 to 24.3. 23.11_notificationRevamps is now ready to be deleted. * Added blood overdraw trigger notification. * Registered new notification. * 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. * 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. * 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. * Reordered messages in BloodDrawReviewDailyNotification.java so overdraws are listed first. * -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. * Removed automated tests that don't aren't finished. * 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. * Adding automated tests for notifications. * - 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. * - 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. * 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. * Moved the automated tests to the end of the list and removed the @Test flag. * Disabled site-wide notifications. Also disable individual notifications. * 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. * Added try/catch for insertValueIntoBloodBilledByDataset due to duplicate data being uploaded. Looks like labkey's loadBloodBilledByLookup() already uploads the same values. * Added try/catch for remaining functions that insert into datasets. * 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. * Removing migrated alerts from ehrcron to Java based notifications * 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. * 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. * - 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. * - 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. * - 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. * - 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). * Removed joda time import statement because it was unused. * ClinpathRefRange.sql - Added units column to table for data retrieval in ClinpathAbnormalResultsAlertsRevamp.java. WNPRC_EHRModule.java - Registered the 2 new notifications. ClinpathAbnormalResultsAlertsRevamp.java - Created new alert. ClinpathAlertsRevamp.java - Created new alert. * ClinpathResultAlertsRevamp.java: Created new revamp notification. WNPRC_EHRModule.java: Registered new notification. * LargeInfantAlertsRevamp.java: Created new revamped notification. WNPRC_EHRModule.java: Registered new LargeInfantAlertwsRevamp notification. * ClinpathAbnormalResultsAlertsRevamp.java: Fixed text display, typos, and filter. ClinpathAlertsRevamp.java: Fixed text display. ClinpathResultAlertsRevamp.java: Fixed filter. ColonyAlertsNotificationRevamp.java: Added Kim's fix (there was an issue where the query retrieved inactive projects. LargeInfantAlertsRevamp.java: Fixed text display. --------- Co-authored-by: F. Daniel Nicolalde --- .../queries/study/ClinpathRefRange.sql | 4 + .../org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 6 +- .../ClinpathAbnormalResultsAlertsRevamp.java | 196 ++++++++++++++++++ .../notification/ClinpathAlertsRevamp.java | 178 ++++++++++++++++ .../ClinpathResultAlertsRevamp.java | 188 +++++++++++++++++ .../ColonyAlertsNotificationRevamp.java | 61 +----- .../notification/LargeInfantAlertsRevamp.java | 110 ++++++++++ 7 files changed, 682 insertions(+), 61 deletions(-) create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAbnormalResultsAlertsRevamp.java create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAlertsRevamp.java create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathResultAlertsRevamp.java create mode 100644 WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/LargeInfantAlertsRevamp.java diff --git a/WNPRC_EHR/resources/queries/study/ClinpathRefRange.sql b/WNPRC_EHR/resources/queries/study/ClinpathRefRange.sql index 9de05477f..16edcf994 100644 --- a/WNPRC_EHR/resources/queries/study/ClinpathRefRange.sql +++ b/WNPRC_EHR/resources/queries/study/ClinpathRefRange.sql @@ -33,6 +33,7 @@ c.taskid, c.qcstate, c.alertOnAbnormal, c.alertOnAny, +c.testId.units, 'Chemistry' as dataset, 'Chemistry_'||c.testid as test_key, from study.chemistryRefRange c @@ -59,6 +60,7 @@ c.taskid, c.qcstate, c.alertOnAbnormal, c.alertOnAny, +c.testId.units, 'Hematology' as dataset, 'Hematology_'||c.testid as test_key, from study.hematologyRefRange c @@ -85,6 +87,7 @@ c.taskid, c.qcstate, c.alertOnAbnormal, c.alertOnAny, +c.testId.units, 'Immunology' as dataset, 'Immunology_'||c.testid as test_key, from study.immunologyRefRange c @@ -111,6 +114,7 @@ c.taskid, c.qcstate, c.alertOnAbnormal, c.alertOnAny, +c.testId.units, 'Urinalysis' as dataset, 'Urinalysis_'||c.testid as test_key, from study.urinalysisRefRange c 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 abdebd68e..b6badf219 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java @@ -393,7 +393,11 @@ public void registerNotifications() { new BloodOverdrawTriggerNotification(this), new EmptyNotificationRevamp(this), new AnimalRequestUpdateNotificationRevamp(this), - new TreatmentAlertsNotificationRevamp(this) + new TreatmentAlertsNotificationRevamp(this), + new ClinpathAbnormalResultsAlertsRevamp(this), + new ClinpathAlertsRevamp(this), + new ClinpathResultAlertsRevamp(this), + new LargeInfantAlertsRevamp(this) ); for (Notification notification : notifications) diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAbnormalResultsAlertsRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAbnormalResultsAlertsRevamp.java new file mode 100644 index 000000000..907663c8b --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAbnormalResultsAlertsRevamp.java @@ -0,0 +1,196 @@ +package org.labkey.wnprc_ehr.notification; + +import org.checkerframework.checker.units.qual.A; +import org.jetbrains.annotations.Nullable; +import org.labkey.api.data.CompareType; +import org.labkey.api.data.Container; +import org.labkey.api.data.SimpleFilter; +import org.labkey.api.ldk.notification.NotificationService; +import org.labkey.api.module.Module; +import org.labkey.api.security.User; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; + +public class ClinpathAbnormalResultsAlertsRevamp 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 ClinpathAbnormalResultsAlertsRevamp(Module owner) {super(owner);} + + + + + + // Notification Details + @Override + public String getName() { + return "Clinpath Abnormal Results Alerts Notification Revamp"; + } + @Override + public String getDescription() { + return "This report is designed to identify potential problems related to clinpath."; + } + @Override + public String getEmailSubject(Container c) { + return "Abnormal Clinpath Results: " + dateToolkit.getCurrentTime(); + } + @Override + public String getScheduleDescription() { + return "Daily every hour from 7:05AM - 5:05PM"; + } + @Override + public String getCronString() { + return notificationToolkit.createCronString("5", "7,8,9,10,11,12,13,14,15,16,17", "*"); + } + @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(); + + // Creates CSS. + messageBody.append(styleToolkit.beginStyle()); + messageBody.append(styleToolkit.setBasicTableStyle()); + messageBody.append(styleToolkit.setHeaderRowBackgroundColor("#d9d9d9")); + messageBody.append(styleToolkit.endStyle()); + + // Sets up variables. + HashMap>>> filteredResults = new HashMap<>(); // Areas > Rooms > Results List > Result + Date lastRunDate = new Date(NotificationService.get().getLastRun(this)); + Calendar cal = Calendar.getInstance(); + cal.setTime(lastRunDate); + cal.add(Calendar.DATE, -7); + Date lastRunMinusWeek = cal.getTime(); + + // Creates filter. + SimpleFilter myFilter = new SimpleFilter("qcstate/PublicData", true, CompareType.EQUAL); + myFilter.addCondition("taskid/datecompleted", lastRunDate, CompareType.DATE_GTE); + myFilter.addCondition("taskid/datecompleted", "", CompareType.NONBLANK); + myFilter.addCondition("date", lastRunMinusWeek, CompareType.DATE_GTE); + // Creates columns to retrieve. + String[] targetColumns = new String[]{"Id", "date", "Id/curLocation/area", "Id/curLocation/room", "Id/curLocation/cage", "alertStatus", "taskid/datecompleted", "testid", "result", "units", "status", "ref_range_min", "ref_range_max", "ageAtTime"}; + // Runs query. + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "ClinpathRefRange", myFilter, null, targetColumns); + // Creates URL. + String clinpathTasksUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "ClinpathRefRange", myFilter); + + // Organizes results into a list filtered by [Area > Room > Task]. + for (HashMap result : returnArray) { + // Verifies 'alert status' exists before adding results. + if (!result.get("alertStatus").isEmpty()) { + // Updates current location. + if (result.get("Id/curLocation/area").isEmpty()) { + result.put("Id/curLocation/area", "No Active Housing"); + } + // Updates current room. + if (result.get("Id/curLocation/room").isEmpty()) { + result.put("Id/curLocation/room", "No Room"); + } + + // Adds to list if area does not exist yet. + if (!filteredResults.containsKey(result.get("Id/curLocation/area"))) { + // Creates new room results list. + ArrayList> newRoomList = new ArrayList<>(); + newRoomList.add(result); + // Creates new room map. + HashMap>> newRoom = new HashMap<>(); + newRoom.put(result.get("Id/curLocation/room"), newRoomList); + // Creates new area map and adds to the filtered results. + filteredResults.put(result.get("Id/curLocation/area"), newRoom); + } + // Adds to list if room does not exist yet. + else if (!filteredResults.get(result.get("Id/curLocation/area")).containsKey(result.get("Id/curLocation/room"))) { + // Creates new room results list. + ArrayList> newRoomList = new ArrayList<>(); + newRoomList.add(result); + // Creates new room map and adds to the areas list. + filteredResults.get(result.get("Id/curLocation/area")).put(result.get("Id/curLocation/room"), newRoomList); + } + // Adds to list if area and room exist already. + else { + filteredResults.get(result.get("Id/curLocation/area")).get(result.get("Id/curLocation/room")).add(result); + } + } + } + + // Prints text. + messageBody.append("There have been " + returnArray.size() + " clinpath tasks completed since " + lastRunDate + "
"); + messageBody.append(notificationToolkit.createHyperlink("Click here to view them", clinpathTasksUrlView) + "

\n"); + messageBody.append("

Listed below are the abnormal records.

\n"); + + // Prints table with all records. + String[] tableColumns = new String[]{"Id", "Collect Date", "Date Completed", "Test ID", "Result", "Units", "Status", "Ref Range Min", "Ref Range Max", "Age At Time"}; + for (String currentArea : notificationToolkit.sortSetWithNulls(filteredResults.keySet())) { + messageBody.append("" + currentArea + ":
\n"); + for (String currentRoom : notificationToolkit.sortSetWithNulls(filteredResults.get(currentArea).keySet())) { + messageBody.append(currentRoom + ":
\n"); + // Reformats the hashmap into a String[] List (to be compatible with the table creation function). + ArrayList currentTableData = new ArrayList<>(); + ArrayList rowColorsList = new ArrayList<>(); + for (HashMap currentRow : filteredResults.get(currentArea).get(currentRoom)) { + String[] newTableRow = new String[] { + currentRow.get("Id"), + currentRow.get("date"), + currentRow.get("taskid/datecompleted"), + currentRow.get("testid"), + currentRow.get("result"), + currentRow.get("units"), + currentRow.get("status"), + currentRow.get("ref_range_min"), + currentRow.get("ref_range_max"), + currentRow.get("ageAtTime"), + }; + currentTableData.add(newTableRow); + + if (!currentRow.get("ref_range_min").isBlank() && !currentRow.get("result").isBlank()) { + if (Double.parseDouble(currentRow.get("result")) < Double.parseDouble(currentRow.get("ref_range_min"))) { + rowColorsList.add("yellow"); + } + } + if (!currentRow.get("ref_range_max").isBlank() && !currentRow.get("result").isBlank()) { + if (Double.parseDouble(currentRow.get("result")) > Double.parseDouble(currentRow.get("ref_range_max"))) { + rowColorsList.add("red"); + } + } + + if (currentTableData.size() > rowColorsList.size()) { + rowColorsList.add("white"); + } + } + + // Displays table. + NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(tableColumns, currentTableData); + myTable.rowColors = rowColorsList; + messageBody.append(myTable.createBasicHTMLTable()); + } + } + + // Returns message. + return messageBody.toString(); + } + +} diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAlertsRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAlertsRevamp.java new file mode 100644 index 000000000..04326efc5 --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathAlertsRevamp.java @@ -0,0 +1,178 @@ +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.ldk.notification.NotificationService; +import org.labkey.api.module.Module; +import org.labkey.api.security.User; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; + +public class ClinpathAlertsRevamp extends AbstractEHRNotification { + // Class Variables + NotificationToolkit notificationToolkit = new NotificationToolkit(); + NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit(); + + + + + + // Constructors + /** + * This constructor is used to register the notification in WNPRC_EHRModule.java. + * @param owner + */ + public ClinpathAlertsRevamp(Module owner) {super(owner);} + + + + + + // Notification Details + @Override + public String getName() { + return "Clinpath Alerts Notification Revamp"; + } + @Override + public String getDescription() { + return "This report is designed to identify potential problems related to clinpath."; + } + @Override + public String getEmailSubject(Container c) { + return "Daily Clinpath Alerts: " + dateToolkit.getCurrentTime(); + } + @Override + public String getScheduleDescription() { + return "Daily at 11:00am, 1:00pm, and 4:00pm"; + } + @Override + public String getCronString() { + return notificationToolkit.createCronString("0", "11,13,16", "*"); + } + @Override + public String getCategory() { + return "Revamped Notifications"; + } + + // Message Creation + @Override + public String getMessageBodyHTML(Container c, User u) { + // Creates variables & retrieves data. + Date lastRunDate = new Date(NotificationService.get().getLastRun(this)); + ClinpathAlertsObject myClinpathAlertsObject = new ClinpathAlertsObject(c, u, lastRunDate); + final StringBuilder messageBody = new StringBuilder(); + + // Begins message info. + messageBody.append("This email contains reports on Clinpath Requests. It was run on: " + dateToolkit.getDateToday() + ".

"); + + // Displays requests created since the last time this email was sent. + messageBody.append("Clinpath requests created since the last time this email was sent (" + lastRunDate + "):
\n"); + if (!myClinpathAlertsObject.recordsRequestedSinceLastEmail.isEmpty()) { + messageBody.append("There are " + myClinpathAlertsObject.recordsRequestedSinceLastEmail.size() + " requests.
"); + messageBody.append("

" + notificationToolkit.createHyperlink("Click here to view them", myClinpathAlertsObject.recordsRequestedSinceLastEmailUrlView) + "
\n"); + } + else { + messageBody.append("No requests have been entered.
"); + } + messageBody.append("


\n"); + + // Displays clinpath requests that have not been approved or denied yet. + messageBody.append("Clinpath requests that have not been approved or denied yet:
\n"); + if (!myClinpathAlertsObject.recordsNotYetApproved.isEmpty()) { + messageBody.append("WARNING: There are " + myClinpathAlertsObject.recordsNotYetApproved.size() + " requests that have not been approved or denied yet.
"); + messageBody.append("

" + notificationToolkit.createHyperlink("Click here to view them", myClinpathAlertsObject.recordsNotYetApprovedUrlView) + "
\n"); + } + else { + messageBody.append("There are no requests that have not been approved or denied yet.
"); + } + messageBody.append("


\n"); + + // Displays records not completed where the date requested is today. + if (!myClinpathAlertsObject.incompleteRecordsRequestedToday.isEmpty()) { + messageBody.append("WARNING: There are " + myClinpathAlertsObject.incompleteRecordsRequestedToday.size() + " requests that were requested for today or earlier, but have not been marked complete.
"); + messageBody.append("

" + notificationToolkit.createHyperlink("Click here to view them", myClinpathAlertsObject.incompleteRecordsRequestedTodayUrlView) + "
\n"); + messageBody.append("


\n"); + } + + return messageBody.toString(); + } + + public static class ClinpathAlertsObject { + // Set up. + Container c; + User u; + Date dateLastRun; + NotificationToolkit notificationToolkit = new NotificationToolkit(); + NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit(); + + + + // Constructor. + public ClinpathAlertsObject(Container currentContainer, User currentUser, Date lastRun) { + // Sets variables. + this.c = currentContainer; + this.u = currentUser; + this.dateLastRun = lastRun; + + // Retrieves data. + getRecordsRequestedSinceLastEmail(); + getRecordsNotYetApproved(); + getIncompleteRecordsRequestedToday(); + } + + + + // Gets any record requested since the last email. + ArrayList> recordsRequestedSinceLastEmail; + String recordsRequestedSinceLastEmailUrlView; + private void getRecordsRequestedSinceLastEmail() { + // Creates filter. + SimpleFilter myFilter = new SimpleFilter("qcstate/label", "Request: Pending", CompareType.EQUAL); + myFilter.addCondition("created", dateLastRun, CompareType.DATE_GTE); + // Creates columns to retrieve. + String[] targetColumns = new String[]{"created"}; + // Runs query. + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Clinpath Runs", myFilter, null, targetColumns); + + // Assigns data. + this.recordsRequestedSinceLastEmail = returnArray; + this.recordsRequestedSinceLastEmailUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "Clinpath Runs", myFilter); + } + + // Gets any requests not yet approved. + ArrayList> recordsNotYetApproved; + String recordsNotYetApprovedUrlView; + private void getRecordsNotYetApproved() { + // Creates filter. + SimpleFilter myFilter = new SimpleFilter("qcstate/label", "Request: Pending", CompareType.EQUAL); + myFilter.addCondition("date", dateToolkit.getDateToday(), CompareType.DATE_GTE); + // Creates columns to retrieve. + String[] targetColumns = new String[]{"id"}; + // Runs query. + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Clinpath Runs", myFilter, null, targetColumns); + + // Assigns data. + this.recordsNotYetApproved = returnArray; + this.recordsNotYetApprovedUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "Clinpath Runs", myFilter); + } + + // Gets any record not completed where the date requested is today. + ArrayList> incompleteRecordsRequestedToday; + String incompleteRecordsRequestedTodayUrlView; + private void getIncompleteRecordsRequestedToday() { + // Creates filter. + SimpleFilter myFilter = new SimpleFilter("qcstate/label", "Completed", CompareType.NEQ); + myFilter.addCondition("date", dateToolkit.getDateToday(), CompareType.DATE_LTE); + String[] targetColumns = new String[]{"id"}; + // Runs query. + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Clinpath Runs", myFilter, null, targetColumns); + + // Assigns data. + this.incompleteRecordsRequestedToday = returnArray; + this.incompleteRecordsRequestedTodayUrlView = notificationToolkit.createQueryURL(c, "execute", "study", "Clinpath Runs", myFilter); + } + } +} diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathResultAlertsRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathResultAlertsRevamp.java new file mode 100644 index 000000000..97dea6e8f --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ClinpathResultAlertsRevamp.java @@ -0,0 +1,188 @@ +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.util.ArrayList; +import java.util.Date; +import java.util.HashMap; + +public class ClinpathResultAlertsRevamp 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 ClinpathResultAlertsRevamp(Module owner) {super(owner);} + + + + + + // Notification Details + @Override + public String getName() { + return "Clinpath Result Alerts Revamp"; + } + @Override + public String getDescription() { + return "This report is designed to identify potential problems related to clinpath."; + } + @Override + public String getEmailSubject(Container c) { + return "New Clinpath Results: " + dateToolkit.getCurrentTime(); + } + @Override + public String getScheduleDescription() { + return "Daily at 10:00am"; + } + @Override + public String getCronString() { + return notificationToolkit.createCronString("0", "10", "*"); + } + @Override + public String getCategory() { + return "Revamped Notifications"; + } + + + + + + // Message Creation + @Override + public String getMessageBodyHTML(Container c, User u) { + // Creates variables & retrieves data. + final StringBuilder messageBody = new StringBuilder(); + + // Creates CSS. + messageBody.append(styleToolkit.beginStyle()); + messageBody.append(styleToolkit.setBasicTableStyle()); + messageBody.append(styleToolkit.setHeaderRowBackgroundColor("#d9d9d9")); + messageBody.append(styleToolkit.endStyle()); + + // Creates filter. + SimpleFilter myFilter = new SimpleFilter("qcstate/PublicData", true, CompareType.EQUAL); + myFilter.addCondition("taskid/datecompleted", dateToolkit.getDateXDaysFromNow(-1), CompareType.DATE_GTE); + myFilter.addCondition("taskid/datecompleted", "", CompareType.NONBLANK); + // Creates sort. + Sort mySort = new Sort("Id,date"); + // Creates columns to retrieve. + String[] targetColumns = new String[]{"Id", "date", "Id/curLocation/area", "Id/curLocation/room", "Id/curLocation/cage", "serviceRequested", "requestid/description", "reviewedBy", "dateReviewed"}; + // Runs query. + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "Clinpath Runs", myFilter, mySort, targetColumns); + // Creates URL. + String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Clinpath Runs", myFilter); + + // Creates filtered list. + HashMap>>> filteredResults = new HashMap<>(); // Areas > Rooms > Results List > Result + + // Begins message info. + messageBody.append("This email contains clinpath results entered since: " + dateToolkit.getDateXDaysFromNow(-1) + ".

"); + + // Displays if there is no data. + if (returnArray.isEmpty()) { + messageBody.append("No requests have been completed.


\n"); + } + // Displays if there IS data. + else { + // Updates message info. + messageBody.append("There are " + returnArray.size() + " completed requests since " + dateToolkit.getDateXDaysFromNow(-1) + ". "); + messageBody.append("Below is a summary. Click the animal ID for more detail.
"); + messageBody.append(notificationToolkit.createHyperlink("Click here to view them.", viewQueryURL) + "

\n"); + + // Sorts results into a list filtered by room & area. + for (HashMap result : returnArray) { + // Updates current area if empty. + if (result.get("Id/curLocation/area").isEmpty()) { + result.put("Id/curLocation/area", "No Active Housing"); + } + // Updates current room if empty. + if (result.get("Id/curLocation/room").isEmpty()) { + result.put("Id/curLocation/room", "No Room"); + } + // Adds line separators when there are multiple values. + if (!result.get("requestid/description").isEmpty()) { + String rawDescription = result.get("requestid/description"); + String parsedDescription = rawDescription.replace(",", ",
\n"); + result.put("requestid/description", parsedDescription); + } + + // Adds to list if area does not exist yet. + if (!filteredResults.containsKey(result.get("Id/curLocation/area"))) { + // Creates new room results list. + ArrayList> newRoomList = new ArrayList<>(); + newRoomList.add(result); + // Creates new room map. + HashMap>> newRoom = new HashMap<>(); + newRoom.put(result.get("Id/curLocation/room"), newRoomList); + // Creates new area map and adds to the filtered results. + filteredResults.put(result.get("Id/curLocation/area"), newRoom); + } + // Adds to list if room does not exist yet. + else if (!filteredResults.get(result.get("Id/curLocation/area")).containsKey(result.get("Id/curLocation/room"))) { + // Creates new room results list. + ArrayList> newRoomList = new ArrayList<>(); + newRoomList.add(result); + // Creates new room map and adds to the areas list. + filteredResults.get(result.get("Id/curLocation/area")).put(result.get("Id/curLocation/room"), newRoomList); + } + // Adds to list if area and room exist already. + else { + filteredResults.get(result.get("Id/curLocation/area")).get(result.get("Id/curLocation/room")).add(result); + } + } + + // Creates a table from the data. + String[] tableColumns = new String[]{"Id", "Collect Date", "Service Requested", "Requestor", "Date Reviewed", "Reviewed By"}; + for (String currentArea : notificationToolkit.sortSetWithNulls(filteredResults.keySet())) { + messageBody.append("" + currentArea + ":
\n"); + for (String currentRoom : notificationToolkit.sortSetWithNulls(filteredResults.get(currentArea).keySet())) { + messageBody.append(currentRoom + ":
\n"); + // Reformats the hashmap into a String[] List (to be compatible with the table creation function). + ArrayList currentTableData = new ArrayList<>(); + ArrayList rowColorsList = new ArrayList<>(); + for (HashMap currentRow : filteredResults.get(currentArea).get(currentRoom)) { + String[] newTableRow = new String[] { + currentRow.get("Id"), + currentRow.get("date"), + currentRow.get("serviceRequested"), + currentRow.get("requestid/description"), + currentRow.get("dateReviewed"), + currentRow.get("reviewedBy"), + }; + currentTableData.add(newTableRow); + + if (currentRow.get("reviewedBy").isBlank()) { + rowColorsList.add("red"); + } + else { + rowColorsList.add("white"); + } + } + + // Displays table. + NotificationToolkit.NotificationRevampTable myTable = new NotificationToolkit.NotificationRevampTable(tableColumns, currentTableData); + myTable.rowColors = rowColorsList; + messageBody.append(myTable.createBasicHTMLTable()); + } + } + } + + return messageBody.toString(); + } + +} 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 872a428e8..5dc8ca3a1 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/ColonyAlertsNotificationRevamp.java @@ -559,7 +559,6 @@ private void getLivingAnimalsWithoutWeight() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.calculated_status~eq=Alive&query.Id/MostRecentWeight/MostRecentWeightDate~isblank"); //Returns data. this.livingAnimalsWithoutWeight = returnArray; @@ -577,8 +576,6 @@ private void getOccupiedCagesWithoutDimensions() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "ehr", "missingCages", null); String editQueryURL = notificationToolkit.createQueryURL(c, "update", "ehr", "missingCages", null); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=ehr&query.queryName=missingCages"); -// Path editQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=ehr_lookups&query.queryName=cage"); //Returns data. this.occupiedCagesWithoutDimensions = returnArray; @@ -634,7 +631,6 @@ private void getLivingAnimalsInProtectedContact() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Housing", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Housing&query.cond~eq=pc&query.enddate~isblank="); //Returns data. this.livingAnimalsInProtectedContact = returnArray; @@ -653,7 +649,6 @@ private void getLivingAnimalsWithMultipleActiveHousingRecords() { //Creates 'view query' URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "housingProblems", null); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=housingProblems"); //Creates 'edit query' URL. StringBuilder idsToCheck = new StringBuilder(); for (String id : returnArray) { @@ -662,7 +657,6 @@ private void getLivingAnimalsWithMultipleActiveHousingRecords() { SimpleFilter myFilter = new SimpleFilter("Id", idsToCheck.toString(), CompareType.IN); myFilter.addCondition("enddate", "", CompareType.ISBLANK); String editQueryURL = notificationToolkit.createQueryURL(c, "update", "study", "Housing", myFilter); -// Path editQueryURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "updateQuery.view?schemaName=study&query.queryName=Housing&query.Id~in=" + idsToCheck + "&query.enddate~isblank"); //Returns data. this.livingAnimalsWithMultipleActiveHousingRecords = returnArray; @@ -671,37 +665,14 @@ private void getLivingAnimalsWithMultipleActiveHousingRecords() { } // Find all animals where the housing snapshot doesn't match the housing table. - //TODO: Need to update snapshot. ArrayList livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTable; //id String livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTableURLView; //url string (view) private void getLivingAnimalsWhereHousingSnapshotDoesNotMatchHousingTable() { //Runs query. ArrayList returnArray = notificationToolkit.getTableMultiRowSingleColumn(c, u, "study", "ValidateHousingSnapshot", null, null, "Id", null); -// //Update snapshot. -// if (!returnArray.isEmpty()) { -// -// ScriptEngine engine = null; -// String ext = FileUtil.getExtension("/usr/local/labkey/tools/uupdateSnapshot.pl"); -// if (ext != null) { -// engine = LabKeyScriptEngineManager.get().getEngineByExtension(c, ext, LabKeyScriptEngineManager.EngineContext.pipeline); -// } -// if (engine != null) { -// File scriptDir = null; -// Context myContext = null; //TODO: Add context here. -// try (SecurityManager.TransformSession session = SecurityManager.createTransformSession(myContext)) { -// scriptDir = getScriptDirectory -// } -// } -// -// //TODO: Update snapshot (line 210 in colonyAlerts.pl). -// // The following line is how it's done in the perl script. -//// system("/usr/local/labkey/tools/updateSnapshot.pl"); -// } - //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "ValidateHousingSnapshot", null); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=ValidateHousingSnapshot"); //Returns data. this.livingAnimalsWhereHousingSnapshotDoesNotMatchHousingTable = returnArray; @@ -722,7 +693,6 @@ private void getAllRecordsWithPotentialHousingConditionProblems() { //Creates 'view query' URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "housingConditionProblems", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=housingConditionProblems&query.viewName=Problems"); //Creates 'edit query' URL. StringBuilder idsToCheck = new StringBuilder(); for (String id : returnArray) { @@ -731,7 +701,6 @@ private void getAllRecordsWithPotentialHousingConditionProblems() { myFilter.addCondition("Id", idsToCheck.toString(), CompareType.IN); myFilter.addCondition("enddate", "", CompareType.ISBLANK); String editQueryURL = notificationToolkit.createQueryURL(c, "update", "study", "Housing", myFilter); -// Path editQueryURL = new Path(ActionURL.getBaseServerURL(), "ehr", c.getPath(), "updateQuery.view?schemaName=study&query.queryName=Housing&query.Id~in=" + idsToCheck + "&query.enddate~isblank"); //Returns data. this.recordsWithPotentialHousingConditionProblems = returnArray; @@ -753,7 +722,6 @@ private void getOpenHousingRecordsWhereAnimalIsNotAlive() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Housing", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Housing&query.enddate~isblank&query.Id/Dataset/Demographics/calculated_status~neqornull=Alive"); //Returns data. this.openHousingRecordsWhereAnimalIsNotAlive = returnArray; @@ -774,7 +742,6 @@ private void getLivingAnimalsWithoutActiveHousingRecord() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.Id/curLocation/room~isblank&query.calculated_status~eq=Alive"); //Returns data. this.livingAnimalsWithoutActiveHousingRecord = returnArray; @@ -791,7 +758,6 @@ private void getAllRecordsWithCalculatedStatusFieldProblems() { //Creates 'view query' URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Validate_status", null); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Validate_status"); //Creates 'edit query' URL. StringBuilder idsToCheck = new StringBuilder(); for (String id : returnArray) { @@ -821,7 +787,6 @@ private void getAnimalsLackingAssignments() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.viewName=No Active Assigns"); //Returns data. this.animalsLackingAssignments = returnArray; @@ -840,7 +805,6 @@ private void getActiveAssignmentsWhereAnimalIsNotAlive() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Assignment", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Assignment&query.enddate~isblank&query.Id/Dataset/Demographics/calculated_status~neqornull=Alive"); //Returns data. this.activeAssignmentsWhereAnimalIsNotAlive = returnArray; @@ -861,7 +825,6 @@ private void getActiveAssignmentsWhereProjectLacksValidProtocol() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Assignment", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Assignment&query.enddate~isblank&query.Id/Dataset/Demographics/calculated_status~neqornull=Alive&query.project/protocol~isblank"); //Returns data. this.activeAssignmentsWhereProjectLacksValidProtocol = returnArray; @@ -877,7 +840,6 @@ private void getDuplicateActiveAssignments() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "duplicateAssignments", null); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=duplicateAssignments"); //Returns data. this.duplicateActiveAssignments = returnArray; @@ -897,7 +859,6 @@ private void getLivingSivPosAnimalsNotExemptFromPairHousing() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.viewName=Alive%2C%20at%20WNPRC&query.medical~contains=siv&query.Id%2FassignmentSummary%2FActiveVetAssignments~doesnotcontain=20060202"); //Returns data. this.livingSivPosAnimalsNotExemptFromPairHousing = returnArray; @@ -917,7 +878,6 @@ private void getLivingShivPosAnimalsNotExemptFromPairHousing() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.viewName=Alive%2C%20at%20WNPRC&query.medical~contains=shiv&query.Id%2FassignmentSummary%2FActiveVetAssignments~doesnotcontain=20060202"); //Returns data. this.livingShivPosAnimalsNotExemptFromPairHousing = returnArray; @@ -936,7 +896,6 @@ private void getOpenEndedTreatmentsWhereAnimalIsNotAlive() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Treatment Orders", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Treatment Orders&query.enddate~isblank&query.Id/Dataset/Demographics/calculated_status~neqornull=Alive"); //Returns data. this.openEndedTreatmentsWhereAnimalIsNotAlive = returnArray; @@ -955,7 +914,6 @@ private void getOpenEndedProblemsWhereAnimalIsNotAlive() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Problem List", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Problem List&query.enddate~isblank&query.Id/Dataset/Demographics/calculated_status~neqornull=Alive"); //Returns data. this.openEndedProblemsWhereAnimalIsNotAlive = returnArray; @@ -979,7 +937,6 @@ private void getNonContiguousHousingRecords() { queryURL.addParameter("query.queryName", "HousingCheck"); queryURL.addParameter("query.param.MINDATE", todayCalendarDate); String viewQueryURL = (new Path(new ActionURL().getBaseServerURI(), queryURL.toString())).toString(); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=HousingCheck&query.param.MINDATE=" + todayCalendarDate); //Returns data. this.nonContiguousHousingRecords = returnArray; @@ -998,7 +955,6 @@ private void getBirthRecordsMissingGender() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Birth", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Birth&query.gender~isblank=&query.date~dategte=-90d"); //Returns data. this.birthRecordsMissingGender = returnArray; @@ -1019,7 +975,6 @@ private void getDemographicsMissingGender() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.gender~isblank=&query.created~dategte=-90d"); //Returns data. this.demographicsMissingGender = returnArray; @@ -1040,7 +995,6 @@ private void getPrenatalRecordsMissingGender() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Prenatal Deaths", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Prenatal Deaths&query.gender~isblank=&query.date~dategte=-90d"); //Returns data. this.prenatalRecordsMissingGender = returnArray; @@ -1061,7 +1015,6 @@ private void getPrenatalRecordsMissingSpecies() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Prenatal Deaths", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Prenatal Deaths&query.species~isblank=&query.date~dategte=-90d"); //Returns data. this.prenatalRecordsMissingSpecies = returnArray; @@ -1081,7 +1034,6 @@ private void getAnimalsThatDiedWithoutWeight() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "validateFinalWeights", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=validateFinalWeights&query.death~dategte=-90d"); //Returns data. this.animalsThatDiedWithoutWeight = returnArray; @@ -1101,7 +1053,6 @@ private void getTbRecordsLackingResult() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "TB Tests", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=TB Tests&query.date~datelte=-10d&query.date~dategte=-90d&query.missingresults~eq=true"); //Returns data. this.tbRecordsLackingResult = returnArray; @@ -1125,7 +1076,6 @@ private void getProtocolsExpiringSoon() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "ehr", "protocol", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=ehr&query.queryName=protocol&query.Approve~datelte=-" + expirationValue + "d"); //Returns data. this.protocolsExpiringSoon = returnArray; @@ -1145,7 +1095,6 @@ private void getBirthRecordsWithoutDemographicsRecord() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Birth", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Birth&query.Id/Dataset/Demographics/Id~isblank"); //Returns data. this.birthRecordsWithoutDemographicsRecord = returnArray; @@ -1166,7 +1115,6 @@ private void getDeathRecordsWithoutDemographicsRecord() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Deaths", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Deaths&query.Id/Dataset/Demographics/Id~isblank&query.notAtCenter~neqornull=true"); //Returns data. this.deathRecordsWithoutDemographicsRecord = returnArray; @@ -1187,7 +1135,6 @@ private void getAnimalsWithHoldCodesNotPending() { ArrayList returnArray = notificationToolkit.getTableMultiRowMultiColumn(c, u, "study", "Demographics", myFilter, mySort, new String[]{"Id", "hold"}); //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Demographics", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Demographics&query.hold~isnonblank&query.Id/assignmentSummary/NumPendingAssignments~eq=0"); //Returns data. this.animalsWithHoldCodesNotPending = returnArray; @@ -1210,7 +1157,6 @@ private void getAssignmentsWithProjectedReleasesToday() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Assignment", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Assignment&query.projectedRelease~dateeq="+ currentDate + "&query.enddate~isnonblank="); //Returns data. this.assignmentsWithProjectedReleasesToday = returnArray; @@ -1230,7 +1176,6 @@ private void getAssignmentsWithProjectedReleasesTomorrow() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c,"execute", "study", "Assignment", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Assignment&query.projectedRelease~dateeq=" + tomorrowDate); //Returns data. this.assignmentsWithProjectedReleasesTomorrow = returnArray; @@ -1252,7 +1197,6 @@ private void getBirthsInLastFiveDays() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Birth", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Birth&query.date~dategte=" + fiveDaysAgoDate); //Returns data. this.birthsInLastFiveDays = returnArray; @@ -1274,7 +1218,6 @@ private void getDeathsInLastFiveDays() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Deaths", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Deaths&query.date~dategte=" + fiveDaysAgoDate); //Returns data. this.deathsInLastFiveDays = returnArray; @@ -1296,7 +1239,6 @@ private void getPrenatalDeathsInLastFiveDays() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "Prenatal Deaths", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=Prenatal Deaths&query.date~dategte=" + fiveDaysAgoDate); //Returns data. this.prenatalDeathsInLastFiveDays = returnArray; @@ -1319,7 +1261,6 @@ private void getTotalFinalizedRecordsWithFutureDates() { //Creates URL. String viewQueryURL = notificationToolkit.createQueryURL(c, "execute", "study", "StudyData", myFilter); -// Path viewQueryURL = new Path(ActionURL.getBaseServerURL(), "query", c.getPath(), "executeQuery.view?schemaName=study&query.queryName=StudyData&query.date~dategt=" + todayDate + "&query.Id/Dataset/Demographics/QCState/PublicData~eq=1&query.dataset/label~neq=Treatment Orders&query.dataset/label~neq=Assignment"); //Returns data. this.totalFinalizedRecordsWithFutureDates = returnArray; @@ -1388,7 +1329,7 @@ private void getProtocolsNearingAnimalLimitPercentage() { private void getAnimalsWithInvalidProjectOrProtocol() { // Creates filter. SimpleFilter myFilter = new SimpleFilter("Id/Dataset/Demographics/calculated_status", "Alive", CompareType.EQUAL); -// myFilter.addCondition("project/protocol", "", CompareType.NONBLANK); + myFilter.addCondition("enddate", dateToolkit.getDateXDaysFromNow(1), CompareType.DATE_GTE); // Gets columns to retrieve. String[] targetColumns = new String[]{"id", "project", "project/protocol", "project/enddate", "project/protocol/enddate"}; // Runs query. diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/LargeInfantAlertsRevamp.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/LargeInfantAlertsRevamp.java new file mode 100644 index 000000000..476dadb8d --- /dev/null +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/LargeInfantAlertsRevamp.java @@ -0,0 +1,110 @@ +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.ldk.notification.NotificationService; +import org.labkey.api.module.Module; +import org.labkey.api.security.User; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; + +public class LargeInfantAlertsRevamp extends AbstractEHRNotification { + // Class Variables + NotificationToolkit notificationToolkit = new NotificationToolkit(); + NotificationToolkit.DateToolkit dateToolkit = new NotificationToolkit.DateToolkit(); + + + + + + // Constructors + /** + * This constructor is used to register the notification in WNPRC_EHRModule.java. + * @param owner + */ + public LargeInfantAlertsRevamp(Module owner) {super(owner);} + + + + + + // Notification Details + @Override + public String getName() { + return "Large Infant Alerts Revamp"; + } + @Override + public String getDescription() { + return "This email lists orphans assigned to cages that do not meet minimum size requirements as of: " + dateToolkit.getCurrentTime(); + } + @Override + public String getEmailSubject(Container c) { + return "Orphans Not in Compliant Cage Alert on " + dateToolkit.getCurrentTime(); + } + @Override + public String getScheduleDescription() { + return "Daily at 6:12am"; + } + @Override + public String getCronString() { + return notificationToolkit.createCronString("12", "6", "*"); + } + @Override + public String getCategory() { + return "Revamped Notifications"; + } + + + + + + // Message Creation + @Override + public String getMessageBodyHTML(Container c, User u) { + // Creates variables. + final StringBuilder messageBody = new StringBuilder(); + + // Retrieves data. + String[] targetColumns = new String[]{"id"}; + ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "InfantsWithExcessWeight", null, null, targetColumns); + + if (!returnArray.isEmpty()) { + // Begins message info. + messageBody.append("This email lists orphans assigned to cages that do not meet minimum size requirements as of: " + dateToolkit.getDateToday() + ".

"); + + // Prints number of results. + if (returnArray.size() > 1) { + messageBody.append("WARNING: There are " + returnArray.size() + " orphans under the age of 6 months residing in cages that do not accommodate the animal's size.
"); + } + else { + messageBody.append("WARNING: There is " + returnArray.size() + " orphan under the age of 6 months residing in a cage that does not accommodate the animal's size.
"); + } + + // Prints results. + messageBody.append("

"); + messageBody.append("Animal
"); + for (HashMap result : returnArray) { + if (!result.get("id").isEmpty()) { + messageBody.append(result.get("id")); + messageBody.append("
"); + } + } + messageBody.append("

"); + + // Prints URL. + String queryURL = notificationToolkit.createQueryURL(c, "execute", "study", "InfantsWithExcessWeight", null); + messageBody.append(notificationToolkit.createHyperlink("

Click here to view them

", queryURL)); + messageBody.append("
"); + + // Returns message. + return messageBody.toString(); + } + else { + notificationToolkit.sendEmptyNotificationRevamp(c, u, "Large Infant Alerts Revamp"); + return null; + } + } +}