diff --git a/onprc_ehr/resources/etls/SLAWeaning.xml b/onprc_ehr/resources/etls/SLAWeaning.xml
index b03f7a8c5..b1301e787 100644
--- a/onprc_ehr/resources/etls/SLAWeaning.xml
+++ b/onprc_ehr/resources/etls/SLAWeaning.xml
@@ -20,9 +20,11 @@
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/onprc_ehr/resources/etls/TB_Test_Historical_Process.xml b/onprc_ehr/resources/etls/TB_Test_Historical_Process.xml
new file mode 100644
index 000000000..04c400b0c
--- /dev/null
+++ b/onprc_ehr/resources/etls/TB_Test_Historical_Process.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ TB_Test_Historical_Record_Updates
+
+ Transfer Tb Test temp tables into study Clinical Observation values
+
+
+
+
+
+
+ Transfer to EHR Tasks
+
+
+
+
+
+
+
+
+
+ Transfer temp table data to study clinical observation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/onprc_ehr/resources/queries/study/DVMAlertForAlopeciaCases.sql b/onprc_ehr/resources/queries/study/DVMAlertForAlopeciaCases.sql
new file mode 100644
index 000000000..f248fc189
--- /dev/null
+++ b/onprc_ehr/resources/queries/study/DVMAlertForAlopeciaCases.sql
@@ -0,0 +1,69 @@
+/* Added by Kollil 09/22/2025
+ When BSU creates a case AND scores the alopecia at either 4 or 5 (only those scores)
+ THEN the vet assigned to that animal should receive an alert.
+ Show open cases in last 7 days
+Refer to old tkt # 12523, new ticket # 15401
+*/
+SELECT
+ co.Id,
+ co.date AS AlertObservationDate,
+ co.observation AS AlopeciaScore,
+ co.performedby,
+ CASE
+ WHEN co.enteredSincevetReview = 1 THEN 'true'
+ WHEN co.enteredSincevetReview = 0 THEN 'false'
+ ELSE NULL
+ END AS enteredSincevetReview,
+ co.Id.assignedVet.AssignedVet AS AssignedVet,
+ c.BehaviorCaseOpenDate,
+ TIMESTAMPADD(SQL_TSI_DAY, 7, c.BehaviorCaseOpenDate) AS VetReviewDueDate
+FROM study.clinical_observations co
+ INNER JOIN study.demographics d
+ ON d.Id = co.Id
+ INNER JOIN (
+ SELECT
+ x.Id,
+ MAX(x.date) AS BehaviorCaseOpenDate
+ FROM study.Cases x
+ WHERE x.category = 'Behavior'
+ AND x.allProblemCategories = 'Behavioral: Alopecia'
+ AND x.enddate IS NULL
+ AND x.date >= TIMESTAMPADD(SQL_TSI_DAY, -7, NOW())
+ GROUP BY x.Id
+ ) c
+ ON c.Id = co.Id
+WHERE co.category = 'Alopecia Score'
+ AND co.observation IN ('4', '5')
+ AND d.calculated_status = 'Alive'
+
+ /* Only the first 4/5 in a streak */
+ AND NOT EXISTS (
+ SELECT 1
+ FROM study.clinical_observations prev
+ WHERE prev.Id = co.Id
+ AND prev.category = 'Alopecia Score'
+ AND prev.observation IN ('4', '5')
+ AND prev.date < co.date
+ AND prev.date >
+ COALESCE(
+ (
+ SELECT MAX(reset.date)
+ FROM study.clinical_observations reset
+ WHERE reset.Id = co.Id
+ AND reset.category = 'Alopecia Score'
+ AND reset.observation IN ('0', '1', '2', '3')
+ AND reset.date < co.date
+ ),
+ {ts '1900-01-01 00:00:00'}
+ )
+)
+ /* Remove old streaks that later returned to 0-3 */
+ AND NOT EXISTS (
+ SELECT 1
+ FROM study.clinical_observations laterReset
+ WHERE laterReset.Id = co.Id
+ AND laterReset.category = 'Alopecia Score'
+ AND laterReset.observation IN ('0', '1', '2', '3')
+ AND laterReset.date > co.date
+)
+ORDER BY co.Id ASC
\ No newline at end of file
diff --git a/onprc_ehr/resources/queries/study/DVMAlertforAlopeciaCases.query.xml b/onprc_ehr/resources/queries/study/DVMAlertforAlopeciaCases.query.xml
new file mode 100644
index 000000000..92a6ffd2f
--- /dev/null
+++ b/onprc_ehr/resources/queries/study/DVMAlertforAlopeciaCases.query.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ New severe alopecia cases with a score of 4 or 5 requires Vet review
+
+
+ false
+
+ study
+ animal
+ id
+
+
+
+ false
+ Alert Observation Date
+
+
+ Alopecia Score
+
+
+ Performed By
+
+
+ Entered Since Last Vet Review?
+
+
+ Assigned Vet
+
+
+ Behavior Case Open Date
+
+
+ Vet Review Due Date
+
+
+
+
+
+
\ No newline at end of file
diff --git a/onprc_ehr/resources/schemas/dbscripts/postgresql/onprc_ehr-26.005-26.006.sql b/onprc_ehr/resources/schemas/dbscripts/postgresql/onprc_ehr-26.005-26.006.sql
new file mode 100644
index 000000000..7874237c6
--- /dev/null
+++ b/onprc_ehr/resources/schemas/dbscripts/postgresql/onprc_ehr-26.005-26.006.sql
@@ -0,0 +1,237 @@
+CREATE TABLE onprc_ehr.TB_TestTemp_Historical (
+ rowid integer GENERATED BY DEFAULT AS IDENTITY (START WITH 100 INCREMENT BY 1) NOT NULL,
+ animalid varchar(200) NULL,
+ date timestamp NULL,
+ objectid ENTITYID NOT NULL,
+ created timestamp NULL,
+ createdby integer NULL,
+ performedby varchar(200) NULL,
+ modifiedby integer NULL,
+ date_posted timestamp(0) NULL,
+ CONSTRAINT PK_TB_TestTemp_Historical PRIMARY KEY (rowid)
+);
+
+CREATE TABLE onprc_ehr.Temp_Clinical_Observations_Historical (
+ rowid integer GENERATED BY DEFAULT AS IDENTITY (START WITH 100 INCREMENT BY 1) NOT NULL,
+ Id varchar(200) NULL,
+ date timestamp(0) NULL,
+ category varchar(500) NULL,
+ area varchar(500) NULL,
+ observation varchar(500) NULL,
+ createdby integer NULL,
+ performedby varchar(500) NULL,
+ taskid varchar(4000) NULL,
+ qcstate integer NULL,
+ modifiedby integer NULL,
+ CONSTRAINT PK_Temp_Clinical_Observations_Historical PRIMARY KEY (rowid)
+);
+
+CREATE TABLE onprc_ehr.Temp_Clinical_Observations_Historical_Master (
+ rowid integer GENERATED BY DEFAULT AS IDENTITY (START WITH 100 INCREMENT BY 1) NOT NULL,
+ searchid integer NULL,
+ Id varchar(200) NULL,
+ date timestamp(0) NULL,
+ category varchar(500) NULL,
+ area varchar(500) NULL,
+ observation varchar(500) NULL,
+ createdby integer NULL,
+ performedby varchar(500) NULL,
+ taskid varchar(4000) NULL,
+ qcstate smallint NULL,
+ modifiedby integer NULL, -- smalldatetime on SQL Server is clearly wrong
+ Posted_date timestamp(0) NULL,
+ CONSTRAINT PK_Temp_Clinical_Observations_Historical_Master PRIMARY KEY (rowid)
+);
+
+CREATE TABLE onprc_ehr.Observation_Historical_EHRTasks (
+ rowid integer GENERATED BY DEFAULT AS IDENTITY (START WITH 100 INCREMENT BY 1) NOT NULL,
+ taskid varchar(4000) NULL,
+ description varchar(500) NULL,
+ title varchar(500) NULL,
+ qcstate smallint NULL,
+ formtype varchar(500) NULL,
+ category varchar(500) NULL,
+ assignedto smallint NULL,
+ createdby smallint NULL,
+ modifiedby smallint NULL,
+ CONSTRAINT PK_Observation_Historical_EHRTasks PRIMARY KEY (rowid)
+);
+
+/*
+**
+** Created by
+** R. Blasa 7-31-2026 A Program Process that reviews all TB Test Encounter entries on a current date, and creates a
+** new TB Test Clinical Observation record based on
+** having the same monkey id, date, and then to be assigned to a Data Admin for reviews.
+**
+*/
+
+CREATE OR REPLACE FUNCTION onprc_ehr.p_Create_TB_Observation_Historical_records(
+ Start_Date TIMESTAMP,
+ End_Date TIMESTAMP
+)
+RETURNS integer
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ v_SearchKey integer;
+ v_TempSearchKey integer;
+ v_TaskId varchar(4000);
+ v_AnimalID varchar(100);
+ v_date timestamp(0);
+ v_performedby varchar(500);
+ v_FirstFlag integer;
+BEGIN
+ -- Reset temp tables
+ TRUNCATE TABLE onprc_ehr.TB_TestTemp_Historical RESTART IDENTITY;
+ TRUNCATE TABLE onprc_ehr.Temp_Clinical_Observations_Historical RESTART IDENTITY;
+ TRUNCATE TABLE onprc_ehr.Observation_Historical_EHRTasks RESTART IDENTITY;
+
+ -- Generate a list of TB test monkeys
+ INSERT INTO onprc_ehr.TB_TestTemp_Historical (animalid, date, objectid, created, createdby, performedby, modifiedby, date_posted)
+ SELECT
+ a.participantid,
+ a.date::date,
+ a.objectid,
+ a.created,
+ a.createdBy,
+ a.performedby,
+ a.modifiedby,
+ CURRENT_TIMESTAMP
+ FROM studydataset.c6d214_encounters a
+ WHERE lower(a.type) IN (lower('Procedure'), lower('Surgery'))
+ AND a.qcstate = 18
+ AND a.procedureid = 802 -----'TB Test Intradermal'
+ AND a.date >= Start_Date
+ AND a.date < End_Date + INTERVAL '1 day'
+ AND a.participantid NOT IN (
+ SELECT j.participantid
+ FROM studydataset.c6d171_clinical_observations j
+ WHERE j.participantid = a.participantid
+ AND j.date::date = a.date::date + 3
+ AND lower(j.category) = lower('TB TST Score (72 hr)')
+ AND j.qcstate = 18
+ )
+ ORDER BY a.participantid, a.date DESC;
+
+ IF NOT EXISTS (SELECT 1 FROM onprc_ehr.TB_TestTemp_Historical) THEN
+ RETURN 0;
+ END IF;
+
+ v_TempSearchKey := 0;
+ v_TaskId := NULL;
+ v_FirstFlag := 0;
+
+ SELECT rowid INTO v_SearchKey
+ FROM onprc_ehr.TB_TestTemp_Historical
+ ORDER BY rowid
+ LIMIT 1;
+
+ -- Create a single task for each process run
+ WHILE v_TempSearchKey < v_SearchKey LOOP
+
+ SELECT animalid, date, performedby
+ INTO v_AnimalID, v_date, v_performedby
+ FROM onprc_ehr.TB_TestTemp_Historical
+ WHERE rowid = v_SearchKey;
+
+ IF NOT EXISTS (
+ SELECT 1 FROM studydataset.c6d171_clinical_observations j
+ WHERE j.participantid = v_AnimalID
+ AND j.date::date = v_date::date + 3
+ AND lower(j.category) = lower('TB TST Score (72 hr)')
+ ) THEN
+
+ IF v_FirstFlag != 1 THEN
+ v_TaskId := gen_random_uuid()::text;
+
+ INSERT INTO onprc_ehr.Observation_Historical_EHRTasks (
+ taskid,
+ description,
+ title,
+ qcstate,
+ formtype,
+ category,
+ assignedto,
+ createdby,
+ modifiedby
+ ) VALUES (
+ v_TaskId,
+ 'TB TST Scores ' || COALESCE(v_date::text, ''),
+ 'TB TST Scores',
+ 20, --- Qc State (In Progress)
+ 'TB TST Scores',
+ 'task',
+ 1822, ------- Assigned To Data Admins
+ 1042, -------- Created By IS
+ 1042 ----- Modified by IS
+ );
+
+ v_FirstFlag := 1;
+ END IF;
+
+ -- Add three days from TB Test date
+ v_date := v_date + INTERVAL '3 days';
+
+ INSERT INTO onprc_ehr.Temp_Clinical_Observations_Historical (
+ Id,
+ date,
+ category,
+ area,
+ observation,
+ createdby,
+ performedby,
+ taskid,
+ qcstate,
+ modifiedby
+ ) VALUES (
+ v_AnimalID,
+ v_date,
+ 'TB TST Score (72 hr)',
+ 'Right Eyelid',
+ 'Grade: Negative',
+ 1042,
+ v_performedby,
+ v_TaskId,
+ 20,
+ 1042
+ );
+
+ END IF;
+
+ v_TempSearchKey := v_SearchKey;
+
+ SELECT rowid INTO v_SearchKey
+ FROM onprc_ehr.TB_TestTemp_Historical
+ WHERE rowid > v_TempSearchKey
+ ORDER BY rowid
+ LIMIT 1;
+
+ IF NOT FOUND OR v_SearchKey IS NULL THEN
+ EXIT;
+ END IF;
+
+ END LOOP;
+
+ -- Create a master copy of the completed transaction
+ INSERT INTO onprc_ehr.Temp_Clinical_Observations_Historical_Master (
+ searchid, Id, date, category, area, observation, createdby, performedby, taskid, qcstate, modifiedby, Posted_date
+ )
+ SELECT
+ rowid,
+ Id,
+ date,
+ category,
+ area,
+ observation,
+ createdby,
+ performedby,
+ taskid,
+ qcstate,
+ modifiedby,
+ CURRENT_TIMESTAMP
+ FROM onprc_ehr.Temp_Clinical_Observations_Historical;
+
+ RETURN 0;
+END;
+$$;
diff --git a/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-26.004-26.005.sql b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-26.004-26.005.sql
new file mode 100644
index 000000000..ae836ff71
--- /dev/null
+++ b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-26.004-26.005.sql
@@ -0,0 +1,329 @@
+CREATE TABLE [onprc_ehr].[TB_TestTemp_Historical](
+ rowid [int] IDENTITY(100,1) NOT NULL,
+ animalid varchar(200) NULL,
+ date datetime NULL,
+ objectid ENTITYID NOT NULL,
+ created datetime NULL,
+ createdby integer NULL,
+ performedby varchar(200) NULL,
+ modifiedby integer NULL,
+ date_posted smalldatetime
+ )
+ GO
+
+
+CREATE TABLE [onprc_ehr].[Temp_Clinical_Observations_Historical](
+ rowid [int] IDENTITY(100,1) NOT NULL,
+ Id varchar(200) NULL,
+ date smalldatetime NULL,
+ category varchar(500) NULL,
+ area varchar(500) NULL,
+ observation varchar(500) NULL,
+ createdby integer NULL,
+ performedby varchar(500) NULL,
+ taskid varchar(4000) NULL,
+ qcstate integer NULL,
+ modifiedby integer NULL
+
+ )
+ GO
+
+CREATE TABLE [onprc_ehr].[Temp_Clinical_Observations_Historical_Master](
+ rowid [int] IDENTITY(100,1) NOT NULL,
+ searchid integer NULL,
+ Id varchar(200) NULL,
+ date smalldatetime NULL,
+ category varchar(500) NULL,
+ area varchar(500) NULL,
+ observation varchar(500) NULL,
+ createdby integer NULL,
+ performedby varchar(500) NULL,
+ taskid varchar(4000) NULL,
+ qcstate smallint NULL,
+ modifiedby smalldatetime NULL,
+ Posted_date smalldatetime
+
+ )
+ GO
+
+CREATE TABLE [onprc_ehr].[Observation_Historical_EHRTasks](
+ rowid [int] IDENTITY(100,1) NOT NULL,
+ taskid varchar(4000) NULL,
+ description varchar(500)NULL,
+ title varchar(500)NULL,
+ qcstate smallint NULL,
+ formtype varchar(500) NULL,
+ category varchar(500) NULL,
+ assignedto smallint NULL,
+ createdby smallint NULL,
+ modifiedby smallint NULL
+
+ )
+ GO
+
+
+ EXEC core.fn_dropifexists 'p_Create_TB_Observation_Historical_records', 'onprc_ehr', 'PROCEDURE', NULL;
+GO
+
+
+/*
+**
+** Created by
+** R. Blasa 7-31-2026 A Program Process that reviews all TB Test Encounter entries on a current date, and creates a
+** new TB Test Clinical Observation record based on
+** having the same monkey id, date, and then to be assigned to a Data Admin for reviews.
+**
+
+**
+**
+*/
+
+CREATE Procedure onprc_ehr.p_Create_TB_Observation_Historical_records
+ @Start_Date smalldatetime,
+ @End_Date smalldatetime
+
+
+
+AS
+
+
+
+DECLARE
+@SearchKey Int,
+ @TempsearchKey Int,
+ @TaskId varchar(4000),
+ @AnimalID varchar(100),
+ @date smalldatetime,
+ @createdby integer,
+ @performedby varchar(500),
+ @modifiedby integer,
+ @RunID varchar(4000),
+ @FirstFlag integer,
+ @TestDate smalldatetime
+
+
+
+
+BEGIN
+
+
+ ---- Reset temp table
+
+Truncate table onprc_ehr.TB_TestTemp_Historical
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+ Truncate table [onprc_ehr].[Temp_Clinical_Observations_Historical]
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+ Truncate table [onprc_ehr].[Observation_Historical_EHRTasks]
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+ --- Generate a list TB test monkeys )
+
+ Insert into onprc_ehr.TB_TestTemp_Historical
+
+select
+ a.participantid,
+ cast(a.date as date),
+ a.objectid,
+ a.created,
+ a.createdBy,
+ a.performedby,
+ a.modifiedby,
+ getdate() -----date processed
+
+
+from studydataset.c6d214_encounters a
+Where a.type in ('Procedure','Surgery')
+ And a.qcstate = 18
+ And a.procedureid = 802 -----'TB Test Intradermal'
+ And (a.date >= @Start_Date And a.date < dateadd(day, 1, @End_Date) )
+ AND a.participantid not in (select j.participantid from studydataset.c6d171_clinical_observations j
+ Where j.participantid = a.participantid
+ And cast(j.date as date) = dateadd(day,3,cast(a.date as date) )
+ And j.category = 'TB TST Score (72 hr)'
+ And j.qcstate = 18 )
+
+order by a.participantid, a.date desc
+
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+ ---- When there are no records to process, exit immediately from the program.
+
+ If (Select count(*) from onprc_ehr.TB_TestTemp_Historical) = 0
+ BEGIN
+ GOTO No_Records
+ END
+
+
+ ---- Reset temp variables
+
+ Set @SearchKey = 0
+ Set @TempSearchKey = 0
+ Set @Date = NULL
+ Set @modifiedby = NULL
+ Set @createdby =NULL
+ Set @performedby = NULL
+ Set @TaskID = NULL
+ Set @Animalid = Null
+ Set @RunID = Null
+ Set @FirstFlag = 0
+
+
+
+ ----- extract initial row id
+
+Select Top 1 @Searchkey = rowid from onprc_ehr.TB_TestTemp_Historical
+Order by rowid
+
+
+
+ ----Create a single task for each daily process
+
+
+ While @TempSearchKey < @SearchKey
+BEGIN
+
+ -----Begin entry Tb observation process
+
+Select @Animalid =animalid, @date = date, @modifiedby=modifiedby, @createdby =createdby,@performedby= performedby
+from onprc_ehr.TB_TestTemp_Historical Where rowid = @Searchkey
+
+
+
+
+ If not exists (select * from studydataset.c6d171_clinical_observations j Where j.participantid = @AnimalID
+ And cast(j.date as date) = dateadd(day,3,@date)
+ And j.category = 'TB TST Score (72 hr)' )
+
+
+BEGIN
+
+ If @FirstFlag != 1
+ BEGIN
+ ---- created a new task id
+ Set @TaskID = NEWID()
+
+ ---- Create Clinical Observation entries
+ Insert into onprc_ehr.Observation_Historical_EHRTasks
+ (
+ taskid,
+ description,
+ title,
+ qcstate,
+ formType,
+ category,
+ assignedto,
+ createdby,
+ modifiedby
+
+ )
+
+ Values (
+
+ @TaskID,
+ 'TB TST Scores ' + cast(@Date as varchar(50)) , ------ Title consist of animal id and Clinical procedure date
+ 'TB TST Scores',
+ 20, --- Qc State (In Progress)
+ 'TB TST Scores', ------ FormType
+ 'task', ----- category,
+ 1822, ------- Assigned To Data Admins
+ 1042, -------- Created By IS
+ 1042 ----- Modified by IS
+
+ )
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+ ---Set Task insert process only once per single process
+ Set @FirstFlag = 1
+
+ END ---(@FirstFlag)
+
+
+ ----- Initialize data entries
+ Set @date = dateadd(day, 3,@date) ----- Add three days from TB Test date
+
+
+
+ --- Create a Clinical Observation Record
+
+ Insert into Temp_Clinical_Observations_Historical
+ (
+ Id,
+ date,
+ category,
+ area,
+ observation,
+ createdby,
+ performedby,
+ taskid,
+ qcstate,
+ modifiedby
+
+
+ )
+ values (
+ @animalid,
+ @date,
+ 'TB TST Score (72 hr)',
+ 'Right Eyelid',
+ 'Grade: Negative',
+ 1042, -----created by IS
+ @performedby,
+ @TaskID,
+ 20 , ---- In Progress QCState
+ 1042 -----modified by IS
+
+
+ )
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+
+END --(If not exist)
+
+ ----- Proceed and fetch the next record
+
+ Set @TempSearchKey = @SearchKey
+
+ Select Top 1 @SearchKey = rowid from onprc_ehr.TB_TestTemp_Historical
+ Where rowid > @TempSearchKey
+ Order by rowid
+
+
+END ---- While @TempSearchKey
+
+
+ ----- Create a master copy of the completed transaction
+
+Insert into onprc_ehr.Temp_Clinical_Observations_Master
+Select *, getdate()
+from onprc_ehr.Temp_Clinical_Observations_Historical
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+
+
+ No_Records:
+
+ RETURN 0
+
+
+ Err_Proc:
+ -------Error Generated, program processed stopped
+ RETURN 1
+
+
+END
diff --git a/onprc_ehr/resources/schemas/onprc_ehr.xml b/onprc_ehr/resources/schemas/onprc_ehr.xml
index 26e225c6f..a1c94dffe 100644
--- a/onprc_ehr/resources/schemas/onprc_ehr.xml
+++ b/onprc_ehr/resources/schemas/onprc_ehr.xml
@@ -1517,4 +1517,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/onprc_ehr/resources/web/onprc_ehr/data/sources/ONPRCDefaults.js b/onprc_ehr/resources/web/onprc_ehr/data/sources/ONPRCDefaults.js
index 0188d8b75..4873624de 100644
--- a/onprc_ehr/resources/web/onprc_ehr/data/sources/ONPRCDefaults.js
+++ b/onprc_ehr/resources/web/onprc_ehr/data/sources/ONPRCDefaults.js
@@ -273,13 +273,17 @@ EHR.model.DataModelManager.registerMetadata('Default', {
}
},
//Modified: 9-10-2026 R. Blasa
- 'study.housing': {
+ 'study.Housing': {
room: {
- editorConfig: {
- plugins: [Ext4.create('LDK.plugin.UserEditableCombo', {
- allowChooseOther: false
- })]
- }
+ xtype: 'onprc_ehr.roomfieldsingle',
+ allowBlank: false,
+ }
+ },
+
+ 'study.Birth': {
+ room: {
+ xtype: 'onprc_ehr.roomfieldsingle',
+ allowBlank: false
}
},
diff --git a/onprc_ehr/resources/web/onprc_ehr/form/field/RoomFieldSingle.js b/onprc_ehr/resources/web/onprc_ehr/form/field/RoomFieldSingle.js
new file mode 100644
index 000000000..82a60bba7
--- /dev/null
+++ b/onprc_ehr/resources/web/onprc_ehr/form/field/RoomFieldSingle.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013-2019 LabKey Corporation
+ *
+ * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+ */
+Ext4.define('EHR.form.field.RoomFieldSingle', {
+ extend: 'Ext.form.field.ComboBox',
+ alias: 'widget.onprc_ehr-roomfieldsingle',
+
+ caseSensitive: false,
+ anyMatch: true,
+ displayField: 'room',
+ forceSelection: true,
+ columns: 'room,area',
+
+ initComponent: function(){
+ var ctx = EHR.Utils.getEHRContext();
+
+ Ext4.apply(this, {
+ valueField: 'room',
+ queryMode: 'local',
+ store: {
+ type: 'labkey-store',
+ containerPath: ctx ? ctx['EHRStudyContainer'] : null,
+ schemaName: 'ehr_lookups',
+ queryName: 'rooms',
+ columns: this.columns,
+ sort: 'room_sortValue',
+ filterArray: [LABKEY.Filter.create('datedisabled', null, LABKEY.Filter.Types.ISBLANK)],
+ autoLoad: true
+ },
+ });
+
+ this.callParent(arguments);
+ }
+});
\ No newline at end of file
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/ONPRC_EHRModule.java b/onprc_ehr/src/org/labkey/onprc_ehr/ONPRC_EHRModule.java
index aeeeb29b8..d7642d5a4 100644
--- a/onprc_ehr/src/org/labkey/onprc_ehr/ONPRC_EHRModule.java
+++ b/onprc_ehr/src/org/labkey/onprc_ehr/ONPRC_EHRModule.java
@@ -124,7 +124,7 @@ public String getName()
@Override
public @Nullable Double getSchemaVersion()
{
- return 26.004;
+ return 26.006;
}
@Override
@@ -327,6 +327,8 @@ private void registerEHRResources()
//Added: 10-12-2023 R.Blasa
EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("onprc_ehr/form/field/EnvironmentalField.js"), this);
+ //Added: 9-14-2026 R.Blasa
+ EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("onprc_ehr/form/field/RoomFieldSingle.js"), this);
EHRService.get().registerReportLink(EHRService.REPORT_LINK_TYPE.housing, "List Single Housed Animals", this, DetailsURL.fromString("/query/executeQuery.view?schemaName=study&query.queryName=demographicsPaired&query.viewName=Single Housed"), "Commonly Used Queries");
EHRService.get().registerReportLink(EHRService.REPORT_LINK_TYPE.housing, "Find Animals Housed In A Given Room/Cage At A Specific Time", this, DetailsURL.fromString("/ehr/housingOverlaps.view?groupById=1"), "Commonly Used Queries");
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/VetReviewNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/VetReviewNotification.java
index c84b4d07a..e6f0d23c8 100644
--- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/VetReviewNotification.java
+++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/VetReviewNotification.java
@@ -37,8 +37,10 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Created by bimber on 9/18/2014.
@@ -85,13 +87,76 @@ public String getMessageBodyHTML(Container c, User u)
{
StringBuilder msg = new StringBuilder();
- /* remarksWithoutAssignedVet(c, u, msg);*/
+ /* remarksWithoutAssignedVet(c, u, msg);*/
+ DVMAlopeciaAlert(c,u,msg); //Added by Kolli, March 2026
vetRecordsUnderReview(c, u, msg);
animalsWithoutAssignedVet(c, u, msg);
+
return msg.toString();
}
+ /* Added by Kollil 09/22/2025
+ When BSU creates a case AND scores the alopecia at either 4 or 5 (only those scores)
+ THEN the vet assigned to that animal should receive an alert. Show open cases in last 7 days
+ Refer to old tkt # 12523, new tkt # 15401
+ */
+ private void DVMAlopeciaAlert(final Container c, User u, final StringBuilder msg)
+ {
+ TableInfo ti = getStudySchema(c, u).getTable("DVMAlertforAlopeciaCases");
+
+ TableSelector ts = new TableSelector(ti, null, null);
+ long total = ts.getRowCount();
+
+ if (total > 0)
+ {
+ msg.append(" ALERT: " + total + " animals found with alopecia score of 4 or 5 with open behavioral case for alopecia in the last 7 days. ");
+ msg.append("Click here to view the data in a grid view\n");
+ msg.append(" ");
+
+ //Display the report in the email
+ Set columns = new HashSet<>();
+ columns.add(FieldKey.fromString("Id"));
+ columns.add(FieldKey.fromString("AlertObservationDate"));
+ columns.add(FieldKey.fromString("AlopeciaScore"));
+ columns.add(FieldKey.fromString("performedby"));
+ columns.add(FieldKey.fromString("enteredSincevetReview"));
+ columns.add(FieldKey.fromString("AssignedVet"));
+ columns.add(FieldKey.fromString("BehaviorCaseOpenDate"));
+ columns.add(FieldKey.fromString("VetReviewDueDate"));
+
+ final Map colMap = QueryService.get().getColumns(ti, columns);
+ TableSelector ts2 = new TableSelector(ti, colMap.values(), null, new Sort("date"));
+
+ // Table header
+ msg.append("
");
+ }
+ else
+ {
+ msg.append("WARNING: No animals found with alopecia score of 4 or 5 with open behavioral case for alopecia in last 7 days! \n");
+ }
+
+
+ }
+
public void vetRecordsUnderReview(Container c, User u, final StringBuilder msg)
{
int duration = 7;
@@ -171,4 +236,4 @@ protected void animalsWithoutAssignedVet(final Container c, User u, final String
msg.append("\n");
}
}
-}
+}
\ No newline at end of file
diff --git a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest2.java b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest2.java
index efff00392..fc3e44bf2 100644
--- a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest2.java
+++ b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest2.java
@@ -390,15 +390,6 @@ private void testBirthRecordStatus(String offspringId, boolean birthWasChanged)
SelectRowsCommand weightSelect = new SelectRowsCommand("study", "weight");
weightSelect.addFilter(new Filter("Id", offspringId, Filter.Operator.EQUAL));
-// if (!isAlive)
-// {
-// //if the animal was born dead, we expect these flags to be endded automatically
-// groupSelect.addFilter(new Filter("enddate", null, Filter.Operator.NONBLANK));
-// spfFlagSelect.addFilter(new Filter("enddate", null, Filter.Operator.NONBLANK));
-// conditionSelect.addFilter(new Filter("enddate", null, Filter.Operator.NONBLANK));
-// housingSelect.addFilter(new Filter("enddate", null, Filter.Operator.NONBLANK));
-// }
-
if (isPublic)
{
//we expect demographics record to be present
@@ -412,19 +403,7 @@ private void testBirthRecordStatus(String offspringId, boolean birthWasChanged)
org.junit.Assert.assertEquals(INDIAN, demographicsRow.get("geographic_origin"));
}
- //expect death date
-// if (!isAlive)
-// {
-// //in our test scenario, death date always matches birth
-// org.junit.Assert.assertEquals("demographics death date should match birth", birthDate, demographicsRow.get("death"));
-// }
-// else
-// {
-// //in our test scenario, death date always matches birth
-// Assert.assertNull("demographics death date should be null", demographicsRow.get("death"));
-// }
-
-// org.junit.Assert.assertEquals("demographics birth date not set properly", birthDate, demographicsRow.get("birth"));
+ org.junit.Assert.assertEquals("demographics birth date not set properly", birthDate, demographicsRow.get("birth"));
//always expect condition = Nonrestricted
org.junit.Assert.assertEquals(1, conditionSelect.execute(getApiHelper().getConnection(), getContainerPath()).getRowCount().intValue());
diff --git a/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.query.xml b/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.query.xml
index d018c1309..f9c30eabb 100644
--- a/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.query.xml
+++ b/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.query.xml
@@ -4,6 +4,7 @@
Purchase Order Details
+
diff --git a/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.sql b/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.sql
index c75219c35..26ff7288d 100644
--- a/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.sql
+++ b/sla/resources/queries/sla_public/PurchaseOrderDetailsAdmin.sql
@@ -36,4 +36,4 @@ pd.cancelledby
FROM PublicPurchase p, PublicPurchaseDetails pd
WHERE p.objectid = pd.purchaseid
-
+ORDER BY requestdate DESC
diff --git a/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.query.xml b/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.query.xml
index f5873a642..98c3945f9 100644
--- a/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.query.xml
+++ b/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.query.xml
@@ -3,7 +3,7 @@
- Check Purchase Orders By Requestor
+ Purchase Orders By Requestortrue
diff --git a/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.sql b/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.sql
index ebde278b2..81d38afd2 100644
--- a/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.sql
+++ b/sla/resources/queries/sla_public/PurchaseOrdersByRequestor.sql
@@ -3,9 +3,22 @@
*
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
-SELECT requestorid,
-requestor,
-SUM(CASE WHEN confirmationnum IS NULL AND datecancelled IS NULL THEN 1 ELSE 0 END) AS pendingorders,
-COUNT(rowid) AS numberoforders
+-- Modified by Kollil in Sep, 2026 - Removed any empty requestor data
+SELECT
+ requestorid,
+ requestorid.lastName AS RequestorLastname,
+ SUM(
+ CASE
+ WHEN confirmationnum IS NULL
+ AND datecancelled IS NULL
+ THEN 1
+ ELSE 0
+ END
+ ) AS pendingorders,
+ COUNT(rowid) AS numberoforders
FROM PurchaseOrderDetails
-GROUP By requestorid, requestor
\ No newline at end of file
+WHERE requestor IS NOT NULL
+ AND requestor <> ''
+GROUP BY
+ requestorid,
+ requestorid.lastName
\ No newline at end of file