Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions GeneticsCore/resources/etls/MHC_Typing.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@
</alternateKeys>
</destination>
</transform>

<transform id="rc" type="TaskrefTransformStep">
<taskref ref="org.labkey.primeseq.etl.VerifyRowCount">
<settings>
<setting name="sourceRemoteSource" value="PRIMESEQ_MHC"/>
<setting name="sourceSchema" value="geneticscore"/>
<setting name="sourceQuery" value="mhc_data"/>
<setting name="sourceColumn" value="objectId"/>

<setting name="destSchema" value="geneticscore"/>
<setting name="destQuery" value="mhc_data"/>
<setting name="destColumn" value="objectId"/>
</settings>
</taskref>
</transform>
</transforms>

<incrementalFilter className="ModifiedSinceFilterStrategy" timestampColumnName="modified">
Expand Down
365 changes: 180 additions & 185 deletions onprc_billing/resources/queries/onprc_billing/perDiemsByDay.sql

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions onprc_ehr/resources/etls/CageAuditLog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Created by: Kollil, 10/16/2025
Created a new ETL process for the cage audit log data.
This query runs daily at 8:30Pm to capture the snapshot of the cage inventory
-->

<etl xmlns="http://labkey.org/etl/xml">
<name>CageAuditLog</name>
<description>Executes onprc_ehr.p_CageAuditHistoryProcess daily (no load)</description>
<transforms>
<!-- Calls a DB stored procedure that simply executes the query -->
<transform id="RunCageAuditLog" type="StoredProcedure">
<description>Run stored proc p_CageAuditHistoryProcess</description>
<procedure schemaName="onprc_ehr" procedureName="p_CageAuditHistoryProcess" useTransaction="false"/>
</transform>
</transforms>

<schedule>
<!--Runs daily 8:30pm-->
<cron expression="0 30 20 * * ?"/>
</schedule>

</etl>
21 changes: 11 additions & 10 deletions onprc_ehr/resources/queries/study/parentageSummary.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2017 LabKey Corporation
* Copyright (c) 2013-2016 LabKey Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,9 +21,9 @@ SELECT
p.method

FROM study.parentage p
WHERE p.qcstate.publicdata = true and p.enddateCoalesced <= now()
WHERE p.qcstate.publicdata = true and p.enddate is null

UNION ALL
UNION

SELECT
b.Id,
Expand All @@ -34,15 +34,16 @@ SELECT

FROM study.birth b
WHERE b.dam is not null and b.qcstate.publicdata = true

UNION ALL
And 'dam' not in (select k.relationship from study.parentage k where k.Id = b.Id and k.enddate is null)
UNION

SELECT
b.Id,
b.date,
b.sire,
a.Id,
a.date,
a.sire,
'Sire' as relationship,
'Observed' as method

FROM study.birth b
WHERE b.sire is not null and b.qcstate.publicdata = true
FROM study.birth a
WHERE a.sire is not null and a.qcstate.publicdata = true
And 'sire' not in (select k.relationship from study.parentage k where k.Id = a.Id and k.enddate is null)
133 changes: 80 additions & 53 deletions onprc_ehr/resources/scripts/onprc_ehr/onprc_triggers.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,59 +568,6 @@ exports.init = function(EHR){
}
});

EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'assignment', function(helper, scriptErrors, row, oldRow){
// note: if this is automatically generated from death/departure, allow an incomplete record
// alerts will flag these
if (row.enddate && !row.releaseCondition && !helper.isGeneratedByServer()){
EHR.Server.Utils.addError(scriptErrors, 'releaseCondition', 'Must provide the release condition when the release date is set', 'WARN');
}

if (row.enddate && !row.releaseType && !helper.isGeneratedByServer()){
EHR.Server.Utils.addError(scriptErrors, 'releaseType', 'Must provide the release type when the release date is set', 'WARN');
}

//update condition on release
//Modified: 5-13-2019 R.Blasa
if (!helper.isETL() && helper.getEvent() == 'update' && oldRow){
if (EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData && EHR.Server.Security.getQCStateByLabel(oldRow.QCStateLabel).PublicData){
if (row.releaseCondition && row.enddate && row.releaseCondition != 206){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.enddate, row.releaseCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'releaseCondition', msg, 'INFO');
}
else {
triggerHelper.updateAnimalCondition(row.Id, row.enddate, row.releaseCondition);
}
}
}
}

// we want to record the date a record was marked endded, in addition to the actual end itself
// NOTE: we only do this when both enddate and releaseType are entered
if (!row.enddatefinalized && row.enddate && row.releaseCondition && EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData){
//note: if ended in the future, defer to that date
row.enddatefinalized = new Date();
if (row.enddate.getTime() > row.enddatefinalized.getTime()){
row.enddatefinalized = row.enddate;
}
}

//check for condition downgrade for assign condition
if (!helper.isETL() && row.Id && row.assignCondition){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.date, row.assignCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'assignCondition', msg, 'INFO');
}
}

//check for condition downgrade for assign condition
if (!helper.isETL() && row.Id && row.date && row.assignCondition){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.date, row.assignCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'assignCondition', msg, 'INFO');
}
}
});

EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.ON_BECOME_PUBLIC, 'study', 'assignment', function(scriptErrors, helper, row, oldRow){
//Modified: 5-9-2019 R.Blasa Prevent flag enttrie for terminal monkey ids
Expand Down Expand Up @@ -1307,6 +1254,86 @@ exports.init = function(EHR){
}
}
});
// Added 10-17-2025 R. Blasa
EHR.Server.TriggerManager.unregisterAllHandlersForQueryNameAndEvent('study', 'assignment', EHR.Server.TriggerManager.Events.BEFORE_UPSERT);
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'assignment', function(helper, scriptErrors, row, oldRow){
if (!helper.isETL()){
//note: the the date field is handled above by removeTimeFromDate
EHR.Server.Utils.removeTimeFromDate(row, scriptErrors, 'enddate');
EHR.Server.Utils.removeTimeFromDate(row, scriptErrors, 'projectedRelease');
}


//check number of allowed animals at assign/approve time
if (!helper.isETL() && !helper.isQuickValidation() && helper.doStandardProtocolCountValidation() &&
//this is designed to always perform the check on imports, but also updates where the Id was changed
!(oldRow && oldRow.Id && oldRow.Id==row.Id) &&
row.Id && row.project && row.date
){
var assignmentsInTransaction = helper.getProperty('assignmentsInTransaction');
assignmentsInTransaction = assignmentsInTransaction || [];

var msgs = helper.getJavaHelper().verifyProtocolCounts(row.Id, row.project, assignmentsInTransaction);
if (msgs){
msgs = msgs.split("<>");
for (var i=0;i<msgs.length;i++){
EHR.Server.Utils.addError(scriptErrors, 'project', msgs[i], 'WARN');
}
}
}

// note: if this is automatically generated from death/departure, allow an incomplete record
// alerts will flag these
if (row.enddate && !row.releaseCondition && !helper.isGeneratedByServer()){
EHR.Server.Utils.addError(scriptErrors, 'releaseCondition', 'Must provide the release condition when the release date is set', 'WARN');
}

if (row.enddate && !row.releaseType && !helper.isGeneratedByServer()){
EHR.Server.Utils.addError(scriptErrors, 'releaseType', 'Must provide the release type when the release date is set', 'WARN');
}

//update condition on release
//Modified: 5-13-2019 R.Blasa
if (!helper.isETL() && helper.getEvent() == 'update' && oldRow){
if (EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData && EHR.Server.Security.getQCStateByLabel(oldRow.QCStateLabel).PublicData){
if (row.releaseCondition && row.enddate && row.releaseCondition != 206){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.enddate, row.releaseCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'releaseCondition', msg, 'INFO');
}
else {
triggerHelper.updateAnimalCondition(row.Id, row.enddate, row.releaseCondition);
}
}
}
}

// we want to record the date a record was marked endded, in addition to the actual end itself
// NOTE: we only do this when both enddate and releaseType are entered
if (!row.enddatefinalized && row.enddate && row.releaseCondition && EHR.Server.Security.getQCStateByLabel(row.QCStateLabel).PublicData){
//note: if ended in the future, defer to that date
row.enddatefinalized = new Date();
if (row.enddate.getTime() > row.enddatefinalized.getTime()){
row.enddatefinalized = row.enddate;
}
}

//check for condition downgrade for assign condition
if (!helper.isETL() && row.Id && row.assignCondition){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.date, row.assignCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'assignCondition', msg, 'INFO');
}
}

//check for condition downgrade for assign condition
if (!helper.isETL() && row.Id && row.date && row.assignCondition){
var msg = triggerHelper.checkForConditionDowngrade(row.Id, row.date, row.assignCondition);
if (msg){
EHR.Server.Utils.addError(scriptErrors, 'assignCondition', msg, 'INFO');
}
}
});

//Added 10-5-2022 R.Blasa
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'matings', function (helper, scriptErrors, row, oldRow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ protected String ensureFlagExists(final String category, final String name, fina
SelectRowsCommand select1 = new SelectRowsCommand("ehr_lookups", "flag_values");
select1.addFilter(new Filter("category", category, Filter.Operator.EQUAL));
select1.addFilter(new Filter("value", name, Filter.Operator.EQUAL));
select1.addFilter(new Filter("datedisabled", null, Filter.Operator.ISBLANK));
SelectRowsResponse resp = select1.execute(getApiHelper().getConnection(), getContainerPath());

String objectid = resp.getRowCount().intValue() == 0 ? null : (String)resp.getRows().get(0).get("objectid");
Expand Down
103 changes: 102 additions & 1 deletion onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.labkey.test.components.BodyWebPart;
import org.labkey.test.pages.ehr.AnimalHistoryPage;
import org.labkey.test.pages.ehr.EnterDataPage;
import org.labkey.test.pages.ehr.NotificationAdminPage;
import org.labkey.test.util.DataRegionTable;
import org.labkey.test.util.Ext4Helper;
import org.labkey.test.util.LogMethod;
Expand Down Expand Up @@ -71,6 +72,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -1975,5 +1977,104 @@ protected String getAnimalHistoryPath()
{
return ANIMAL_HISTORY_URL;
}
}

@Test
public void testNotificationAdminAudits() throws Exception
{
// Ensure notification service is configured
setupNotificationService();

// Navigate to Notification Admin page
goToEHRFolder();
waitAndClickAndWait(Locators.bodyPanel().append(Locator.tagContainingText("a", "EHR Admin Page")));
waitAndClickAndWait(Locator.tagContainingText("a", "Notification Admin"));

// Record start time for audit filtering
LocalDateTime start = LocalDateTime.now().minusMinutes(5);

// Change Notification User and Reply Email, then save
NotificationAdminPage.beginAt(this);
String replyEmail = "ehr-notify@labkey.test";
Ext4FieldRef.getForLabel(this, "Notification User").setValue(PasswordUtil.getUsername());
Ext4FieldRef.getForLabel(this, "Reply Email").setValue(replyEmail);
click(Ext4Helper.Locators.ext4Button("Save"));
waitForElement(Ext4Helper.Locators.window("Success"));
waitAndClickAndWait(Ext4Helper.Locators.ext4Button("OK"));

// Identify two notifications by extracting their keys from the Run Report links
beginAt(WebTestHelper.getBaseURL() + "/ldk/" + getContainerPath() + "/notificationAdmin.view");
Locator links = Locator.tagContainingText("a", "Run Report In Browser");
waitFor(() -> links.findElements(getDriver()).size() >= 2, "Expected at least two notifications to be available", WAIT_FOR_PAGE);
List<WebElement> runLinks = links.findElements(getDriver());

List<String> notifKeys = new ArrayList<>();
for (int i = 0; i < Math.min(2, runLinks.size()); i++)
{
String href = runLinks.get(i).getAttribute("href");
int idx = href.indexOf("key=");
Assert.assertTrue("Could not locate notification key in href: " + href, idx > -1);
String key = href.substring(idx + 4);
notifKeys.add(key);
}

// Disable the two notifications and save
for (String key : notifKeys)
{
_ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithInputNamed("status_" + key), Ext4Helper.TextMatchTechnique.EXACT, "Disabled");
}
click(Ext4Helper.Locators.ext4Button("Save"));
waitForElement(Ext4Helper.Locators.window("Success"));
waitAndClickAndWait(Ext4Helper.Locators.ext4Button("OK"));

// Re-enable the two notifications and save
for (String key : notifKeys)
{
_ext4Helper.selectComboBoxItem(Ext4Helper.Locators.formItemWithInputNamed("status_" + key), Ext4Helper.TextMatchTechnique.EXACT, "Enabled");
}
click(Ext4Helper.Locators.ext4Button("Save"));
waitForElement(Ext4Helper.Locators.window("Success"));
waitAndClickAndWait(Ext4Helper.Locators.ext4Button("OK"));

// Manage subscribed users on the first notification: add two users then remove one
Locator manageLink = Locator.tagContainingText("a", "Manage Subscribed Users/Groups").index(0);
waitAndClick(manageLink);
waitForElement(Ext4Helper.Locators.window("Manage Subscribed Users"));
Ext4ComboRef combo = Ext4ComboRef.getForLabel(this, "Add User Or Group");
combo.waitForStoreLoad();
_ext4Helper.selectComboBoxItem(Locator.id(combo.getId()), Ext4Helper.TextMatchTechnique.CONTAINS, DATA_ADMIN.getEmail());
Ext4FieldRef.waitForComponent(this, "field[fieldLabel^='Add User Or Group']");
combo = Ext4ComboRef.getForLabel(this, "Add User Or Group");
_ext4Helper.selectComboBoxItem(Locator.id(combo.getId()), Ext4Helper.TextMatchTechnique.CONTAINS, BASIC_SUBMITTER.getEmail());
waitAndClick(Ext4Helper.Locators.ext4Button("Close"));

// Re-open and remove one user
waitAndClick(manageLink);
waitForElement(Ext4Helper.Locators.window("Manage Subscribed Users"));
assertElementPresent(Ext4Helper.Locators.ext4Button("Remove"));
waitAndClick(Ext4Helper.Locators.ext4Button("Remove").index(0));
waitAndClick(Ext4Helper.Locators.ext4Button("Close"));

// Verify audit log entries in audit.SiteSettings for this container
sleep(1000);

Function<String, Integer> countAudit = (commentSubstring) -> {
try
{
SelectRowsCommand cmd = new SelectRowsCommand("auditLog", "AppPropsEvent");
cmd.addFilter(new Filter("Created", Date.from(start.atZone(ZoneId.systemDefault()).toInstant()), Filter.Operator.DATE_GTE));
cmd.addFilter(new Filter("Comment", commentSubstring, Filter.Operator.CONTAINS));
SelectRowsResponse resp = cmd.execute(getApiHelper().getConnection(), getContainerPath());
return resp.getRowCount().intValue();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
};

Assert.assertTrue("Expected audit entry for reply-to email update", countAudit.apply("Notification reply-to email updated.") > 0);
Assert.assertTrue("Expected audit entry for service user update", countAudit.apply("Notification service user updated.") > 0);
Assert.assertTrue("Expected audit entry for notification enabled", countAudit.apply("has been enabled.") > 0);
Assert.assertTrue("Expected audit entry for subscription updates", countAudit.apply("Updated notification subscriptions for") > 0);
}
}