diff --git a/ONPRC_EHR_ComplianceDB/resources/queries/EmployeeData/ComplianceProcedureRecentTests/.qview.xml b/ONPRC_EHR_ComplianceDB/resources/queries/EmployeeData/ComplianceProcedureRecentTests/.qview.xml
new file mode 100644
index 000000000..c2b48d9ac
--- /dev/null
+++ b/ONPRC_EHR_ComplianceDB/resources/queries/EmployeeData/ComplianceProcedureRecentTests/.qview.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.html b/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.html
new file mode 100644
index 000000000..fd1dbddf8
--- /dev/null
+++ b/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.view.xml b/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.view.xml
new file mode 100644
index 000000000..2d2c973a7
--- /dev/null
+++ b/ONPRC_EHR_ComplianceDB/resources/views/employeeDetailsPublic.view.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/onprc_billing/resources/queries/onprc_billing/leaseFees.sql b/onprc_billing/resources/queries/onprc_billing/leaseFees.sql
index bb5c09ce8..f427f4157 100644
--- a/onprc_billing/resources/queries/onprc_billing/leaseFees.sql
+++ b/onprc_billing/resources/queries/onprc_billing/leaseFees.sql
@@ -56,8 +56,7 @@ When a5.id is not Null
then (Select c.rowid from Site.{substitutePath moduleProperty('ONPRC_Billing','BillingContainer')}.onprc_billing.chargeableItems c where c.itemCode = 'ONR41')
When (a4.id is not null and (TIMESTAMPDIFF('SQL_TSI_Day',a.date,a.projectedRelease)) <=14 and a.endDate is null and a.ageAtTime.AgeAtTimeYearsRounded < 1)
then (Select c.rowid from Site.{substitutePath moduleProperty('ONPRC_Billing','BillingContainer')}.onprc_billing.chargeableItems c where c.itemCode = 'ONR44')
- WHEN (a.duration <= CAST(javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_MAX_DURATION') as INTEGER) AND a.enddate IS NOT NULL AND a.assignCondition = a.releaseCondition) THEN (SELECT rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.active = true AND ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_NAME'))
- WHEN (a.duration <= CAST(javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_MAX_DURATION') as INTEGER) AND a.enddate IS NOT NULL AND a.assignCondition = a.releaseCondition) THEN (SELECT rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.active = true AND ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_NAME'))
+ WHEN (a.duration <= CAST(javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_MAX_DURATION') as INTEGER) AND a.enddate IS NOT NULL AND a.assignCondition = a.releaseCondition) THEN (SELECT rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.active = true AND ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_NAME'))
WHEN a2.id IS NOT NULL THEN (SELECT rowid FROM onprc_billing_public.chargeableItems ci WHERE (ci.startDate <= a.date and ci.endDate >= a.date) AND ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.TMB_LEASE_NAME'))
ELSE lf.chargeId
END as chargeId,
@@ -81,7 +80,8 @@ CASE
where b.id = a.id and a1.project.protocol = a2.project.protocol) > 0 THEN 0
WHEN (a.duration = 0 AND a.enddate IS NOT NULL AND a.assignCondition = a.releaseCondition) THEN 1
- WHEN (fl.id Is Not Null) THEN 0
+ -- Exempt PI-purchased NHPs from lease fees
+ WHEN (fl.id IS NOT NULL) THEN 0
--This will check for infants born to resource moms and will not charge
WHEN (a.duration <= CAST(javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_MAX_DURATION') as INTEGER) AND a.enddate IS NOT NULL AND a.assignCondition = a.releaseCondition) THEN a.duration
@@ -139,21 +139,20 @@ LEFT JOIN onprc_billing.leaseFeeDefinition lf ON (
AND lf.active = true
)
-
-
---adds the reasearch owned animal exemption
-LEFT JOIN study.flags fl on
- (a.id = fl.id
- and fl.flag.code = 4034
- and (a.date >= fl.date and a.date <=COALESCE(fl.enddate,Now()) ))
-
+-- Add PI-purchased NHP flag data
+LEFT JOIN study.flags fl
+ ON (a.id = fl.id
+ AND fl.flag.code = 4034
+ AND a.date BETWEEN CAST(fl.date AS DATE) AND COALESCE(fl.enddate, now())
+ )
WHERE CAST(a.datefinalized AS DATE) >= CAST(STARTDATE as DATE) AND CAST(a.datefinalized AS DATE) <= CAST(ENDDATE as DATE)
AND a.qcstate.publicdata = true --and a.participantID.demographics.species.common not in ('Rabbit','Guinea Pigs')
---add setup fees for all starts, except day leases aznd sla
+-- Add lease setup fees for all lease starts, except day leases, PI-purchased NHPs, and sla
UNION ALL
+
SELECT
a.id,
a.date,
@@ -168,7 +167,7 @@ SELECT
' ' as ESPFAnimal,
'Lease Setup Fees' as category,
(SELECT rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.active = true AND ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.LEASE_SETUP_FEES')) as chargeId,
- 1 as quantity,
+ 1 AS quantity,
cast(null as integer) as leaseCharge1,
cast(null as integer) as leaseCharge2,
a.objectid as sourceRecord,
@@ -179,11 +178,19 @@ SELECT
FROM study.assignment a
+-- Add PI-purchased NHP flag data
+LEFT JOIN study.flags fl
+ ON (a.id = fl.id
+ AND fl.flag.code = 4034
+ AND a.date BETWEEN CAST(fl.date AS DATE) AND COALESCE(fl.enddate, now())
+ )
+
WHERE CAST(a.datefinalized AS DATE) >= CAST(STARTDATE as DATE) AND CAST(a.datefinalized AS DATE) <= CAST(ENDDATE as DATE)
AND a.qcstate.publicdata = true
--only charge setup fee for leases >24H. note: duration assumes today as end, so exclude null enddates
AND ((a.duration > CAST(javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.DAY_LEASE_MAX_DURATION') as INTEGER)) OR ( a.assignCondition != a.releaseCondition AND a.enddate IS NULL))
and a.id.demographics.species Not IN ('Rabbit','Guinea Pigs')
+AND fl.id IS NULL -- Exempt PI-purchased NHPs from lease setup fees
--add released animals that need adjustments
UNION ALL
@@ -208,9 +215,9 @@ a5.id as ESPFAnimal,
--////This selectes the charge ID to be used
(SELECT max(rowid) as rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_billing.ONPRC_BillingManager.LEASE_FEE_ADJUSTMENT') and ci.active = true) as chargeId,
CASE
- when (fl.id Is Not Null) then 0
- else 1
- end as quantity,
+ WHEN (fl.id IS NOT NULL) THEN 0 -- Exempt PI-purchased NHPs from lease fees
+ ELSE 1
+END AS quantity,
lf2.chargeId as leaseCharge1,
lf.chargeId as leaseCharge2,
a.objectid as sourceRecord,
@@ -248,11 +255,12 @@ LEFT join assignment_U42ESPF a5 on
and a5.dateonly <=a.dateOnly
AND a5.endDateCoalesced >= a.dateOnly)
---adds the reasearch owned animal exemption
-LEFT JOIN study.flags fl on
- (a.id = fl.id
- and fl.flag.code = 4034
- and (a.date >= fl.date and a.date <=COALESCE(fl.enddate,Now()) ))
+-- Add PI-purchased NHP flag data
+LEFT JOIN study.flags fl
+ ON (a.id = fl.id
+ AND fl.flag.code = 4034
+ AND a.date BETWEEN CAST(fl.date AS DATE) AND COALESCE(fl.enddate, now())
+ )
WHERE a.releaseCondition != a.projectedReleaseCondition
and (A.id != A5.id or A5.id is Null)
diff --git a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHIndustryRates/.qview.xml b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHIndustryRates/.qview.xml
index a473db037..684af65eb 100644
--- a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHIndustryRates/.qview.xml
+++ b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHIndustryRates/.qview.xml
@@ -6,52 +6,51 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
diff --git a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRateSheet/.qview.xml b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRateSheet/.qview.xml
index dfe378d46..cc9151e73 100644
--- a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRateSheet/.qview.xml
+++ b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRateSheet/.qview.xml
@@ -6,52 +6,51 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
diff --git a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRates_ReducedFA/.qview.xml b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRates_ReducedFA/.qview.xml
index a21a4dfe7..cdd6ab9a0 100644
--- a/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRates_ReducedFA/.qview.xml
+++ b/onprc_billingpublic/resources/queries/onprc_billing_public/NIHRates_ReducedFA/.qview.xml
@@ -6,52 +6,51 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
diff --git a/onprc_ehr/resources/queries/ehr_lookups/cageReview.sql b/onprc_ehr/resources/queries/ehr_lookups/cageReview.sql
index ab21a94d5..38007587f 100644
--- a/onprc_ehr/resources/queries/ehr_lookups/cageReview.sql
+++ b/onprc_ehr/resources/queries/ehr_lookups/cageReview.sql
@@ -42,6 +42,7 @@ SELECT
t.totalWeightExempt,
t.totalHeightExempt
+
FROM (
SELECT
@@ -68,6 +69,8 @@ SELECT
sum(CASE WHEN t0.weightExemption IS NULL THEN 0 ELSE 1 END) as totalWeightExempt,
count(t0.heightExemption) as totalHeightExempt
+
+
FROM (
SELECT
@@ -82,11 +85,14 @@ SELECT
group_concat(c1.height) as heights,
f.heightExemption,
CASE
+ WHEN hf.Id is not null AND c1.height >= pc.cage_type.height THEN 'ERROR: According to the monkeys weight-- it needs a height step taller than required.'
+ WHEN hf.Id is not null AND c1.height < pc.cage_type.height THEN 'NOTE: According to the monkeys weight-- it needs a height step taller than required.'
WHEN (pc.cage_type.height < c1.height AND f.heightExemption IS NULL) THEN ('ERROR: Insufficient height, ' || h.id ||' needs at least: ' || cast(c1.height AS varchar(50)))
WHEN (pc.cage_type.height < c1.height AND f.heightExemption IS NOT NULL) THEN cast(('NOTE: Height Exemption: ' || h.Id) as varchar(500))
ELSE null
END as heightStatus,
- wf.weightExemption
+ wf.weightExemption,
+ hf.height_error
FROM ehr_lookups.connectedCages pc
@@ -98,17 +104,27 @@ LEFT JOIN (
f.id,
min(f.flag.value) as heightExemption
FROM study.flags f
- WHERE f.isActive = true AND f.flag.category = 'Caging Note' and f.flag.description like '%exempt%'
+ WHERE f.isActive = true AND f.flag.category = 'Caging Note' and (f.flag.description like '%height-exempt%' or f.flag.description like '%Medical-exempt%')
GROUP BY f.Id
) f on (f.Id = h.Id)
---weight flags
+ --height flags
+LEFT JOIN (
+ SELECT
+ f.id,
+ min(f.flag.value) as height_error
+ FROM study.flags f
+ WHERE f.isActive = true AND f.flag.category = 'Caging Note' and (f.flag.description like '%height-error%')
+ GROUP BY f.Id
+) hf on (hf.Id = h.Id)
+
+---weight flags
LEFT JOIN (
SELECT
f.id,
min(f.flag.value) as weightExemption
FROM study.flags f
- WHERE f.isActive = true AND f.flag.category = 'Caging Note' and f.flag.description like '%exempt%'
+ WHERE f.isActive = true AND f.flag.category = 'Caging Note' and (f.flag.description like '%weight-exempt%' or f.flag.description like '%Medical-exempt%')
GROUP BY f.Id
) wf on (wf.Id = h.Id)
diff --git a/onprc_ehr/resources/queries/onprc_ehr/ChemistryPanicNotification.sql b/onprc_ehr/resources/queries/onprc_ehr/ChemistryPanicNotification.sql
index 3118aca4a..dfd49abd0 100644
--- a/onprc_ehr/resources/queries/onprc_ehr/ChemistryPanicNotification.sql
+++ b/onprc_ehr/resources/queries/onprc_ehr/ChemistryPanicNotification.sql
@@ -14,6 +14,7 @@ select a.Id,
from study.ClinpathRuns a, study.chemistryResults b
Where a.objectid = b.runid
And a.type = 'biochemistry'
- And b.qualresult like '%panic%'
+ And b.qualresult like '%alert%'
+
And a.qcstate = 18
And b.qcstate = 18
\ No newline at end of file
diff --git a/onprc_ehr/resources/queries/study/Demographics/BCS Score.qview.xml b/onprc_ehr/resources/queries/study/Demographics/BCS Score.qview.xml
new file mode 100644
index 000000000..5e77609ba
--- /dev/null
+++ b/onprc_ehr/resources/queries/study/Demographics/BCS Score.qview.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/onprc_ehr/resources/queries/study/birth.query.xml b/onprc_ehr/resources/queries/study/birth.query.xml
index 727fb0953..478366b3c 100644
--- a/onprc_ehr/resources/queries/study/birth.query.xml
+++ b/onprc_ehr/resources/queries/study/birth.query.xml
@@ -51,13 +51,7 @@
-
- Dam
-
-
-
-
-
+ Birth Record Dam
/ehr/participantView.view?participantId=${dam}
true
diff --git a/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.query.xml b/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.query.xml
new file mode 100644
index 000000000..f6db19819
--- /dev/null
+++ b/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.query.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ true
+ true
+
+
+ Current Weight (kg)
+ /query/executeQuery.view?schemaName=study&
+ query.queryName=Weight&
+ query.id~eq=${id}
+
+ 0.###
+
+
+ DateTime
+ Weight Date
+ /query/executeQuery.view?schemaName=study&
+ query.queryName=Weight&
+ query.id~eq=${id}&
+ query.date~eq=${MostRecentWeightDate}
+
+
+
+ true
+
+
+ MostRecentWeight
+
+
+
+
diff --git a/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.sql b/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.sql
new file mode 100644
index 000000000..cbea5887c
--- /dev/null
+++ b/onprc_ehr/resources/queries/study/demographicsMostRecentWeight.sql
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010-2019 LabKey Corporation
+ *
+ * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+ */
+SELECT
+
+w.id,
+w.MostRecentWeightDate,
+timestampdiff('SQL_TSI_DAY', w.MostRecentWeightDate, now()) AS DaysSinceWeight,
+
+null as weightField,
+--NOTE: we need to be careful in case duplicate weights are entered on the same time
+cast((
+ SELECT round(cast(AVG(w2.weight) as double), 3) AS _expr
+ FROM study.weight w2
+ WHERE w2.qcstate.publicdata = true AND w.id=w2.id AND w.MostRecentWeightDate=w2.date
+) as double) AS MostRecentWeight
+
+FROM (
+SELECT
+ w.Id AS Id,
+ max(w.date) AS MostRecentWeightDate
+
+FROM study.weight w
+WHERE w.qcstate.publicdata = true and w.weight is not null
+GROUP BY w.id
+) w
+
+--NOTE: altered to a subselect to avoid duplicate entries from weights with identical time
+-- --find the most recent weight associated with that date
+-- LEFT JOIN study.weight T2
+-- ON (w.MostRecentWeightDate = t2.date AND w.Id = t2.Id)
+--
+-- WHERE t2.qcstate.publicdata = true
\ No newline at end of file
diff --git a/onprc_ehr/resources/queries/study/demographicsParents.query.xml b/onprc_ehr/resources/queries/study/demographicsParents.query.xml
index e3ef57f38..57a19f315 100644
--- a/onprc_ehr/resources/queries/study/demographicsParents.query.xml
+++ b/onprc_ehr/resources/queries/study/demographicsParents.query.xml
@@ -31,6 +31,17 @@
id
+
+ Surrogate Dam
+
+ study
+ animal
+ id
+
+
+
+ Foster Dam Type
+
Genetic Dam
@@ -39,9 +50,17 @@
id
+
+ Genetic Dam Type
+
Number of Parents Known
+
+
+ Observed Dam
+
+
diff --git a/onprc_ehr/resources/queries/study/demographicsParents.sql b/onprc_ehr/resources/queries/study/demographicsParents.sql
index 91f7029d2..f282b8bd2 100644
--- a/onprc_ehr/resources/queries/study/demographicsParents.sql
+++ b/onprc_ehr/resources/queries/study/demographicsParents.sql
@@ -16,7 +16,7 @@
SELECT
d.id,
- coalesce(p2.parent, b.dam) as dam,
+ coalesce(p2.parent, b.dam, p5.parent) as dam,
CASE
WHEN p2.parent IS NOT NULL THEN p2.method
WHEN b.dam IS NOT NULL THEN 'Observed'
@@ -29,26 +29,31 @@ SELECT
WHEN b.sire IS NOT NULL THEN 'Observed'
ELSE null
END as sireType,
- p3.parent as fosterMom,
- p3.method as fosterType,
+ p2.parent as geneticdam,
+ p2.method as geneticdamtype,
+ p3.parent as fostermom,
+ p3.method as fostertype,
+ p4.parent as surrogatedam,
+ coalesce(b.dam,p5.parent) as observeddam,
(CASE WHEN p3.parent IS NOT NULL THEN 1 ELSE 0 END +
+ CASE WHEN p4.parent IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN coalesce(p2.parent, b.dam) IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN coalesce(p1.parent, b.sire) IS NOT NULL THEN 1 ELSE 0 END) as numParents,
- greatest(d.modified, p1.modified, p2.modified, p3.modified, b.modified) as modified
+ greatest(d.modified, p1.modified, p2.modified, p3.modified, p4.modified,p5.modified, b.modified) as modified
FROM study.demographics d
LEFT JOIN (
select p1.id, min(p1.method) as method, max(p1.parent) as parent, max(p1.modified) as modified
FROM study.parentage p1
- WHERE (p1.method = 'Genetic' OR p1.method = 'Provisional Genetic') AND p1.relationship = 'Sire' AND p1.enddate IS NULL
+ WHERE p1.method in ('Genetic','Provisional Genetic') AND p1.relationship = 'Sire' AND p1.enddate IS NULL
GROUP BY p1.Id
) p1 ON (d.Id = p1.id)
LEFT JOIN (
select p2.id, min(p2.method) as method, max(p2.parent) as parent, max(p2.modified) as modified
FROM study.parentage p2
- WHERE (p2.method = 'Genetic' OR p2.method = 'Provisional Genetic') AND p2.relationship = 'Dam' AND p2.enddate IS NULL
+ WHERE p2.method in ('Genetic','Provisional Genetic') AND p2.relationship = 'Dam' AND p2.enddate IS NULL
GROUP BY p2.Id
) p2 ON (d.Id = p2.id)
@@ -58,5 +63,19 @@ LEFT JOIN (
WHERE p3.relationship = 'Foster Dam' AND p3.enddate IS NULL
GROUP BY p3.Id
) p3 ON (d.Id = p3.id)
+LEFT JOIN (
+ select p4.id, min(p4.method) as method, max(p4.parent) as parent, max(p4.modified) as modified
+ FROM study.parentage p4
+ WHERE p4.relationship = 'Surrogate Dam' AND p4.enddate IS NULL
+ GROUP BY p4.Id
+) p4 ON (d.Id = p4.id)
+
+LEFT JOIN (
+ select p5.id, min(p5.method) as method, max(p5.parent) as parent, max(p5.modified) as modified
+ FROM study.parentage p5
+ WHERE p5.relationship = 'Observed' AND p5.enddate IS NULL
+ GROUP BY p5.Id
+) p5 ON (d.Id = p5.id)
+
LEFT JOIN study.birth b ON (b.id = d.id)
diff --git a/onprc_ehr/resources/queries/study/demographicsParents/.qview.xml b/onprc_ehr/resources/queries/study/demographicsParents/.qview.xml
index 01e76b9af..c55f9e699 100644
--- a/onprc_ehr/resources/queries/study/demographicsParents/.qview.xml
+++ b/onprc_ehr/resources/queries/study/demographicsParents/.qview.xml
@@ -5,9 +5,13 @@
+
+
-
+
+
+
diff --git a/onprc_ehr/resources/queries/study/housingRoommatesDivider/Caged Housing Only.qview.xml b/onprc_ehr/resources/queries/study/housingRoommatesDivider/Caged Housing Only.qview.xml
index 842d92a89..ca53571c1 100644
--- a/onprc_ehr/resources/queries/study/housingRoommatesDivider/Caged Housing Only.qview.xml
+++ b/onprc_ehr/resources/queries/study/housingRoommatesDivider/Caged Housing Only.qview.xml
@@ -1,6 +1,7 @@
+
diff --git a/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.004-25.005.sql b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.004-25.005.sql
new file mode 100644
index 000000000..6176c6581
--- /dev/null
+++ b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.004-25.005.sql
@@ -0,0 +1,126 @@
+
+CREATE TABLE onprc_ehr.Rpt_TempJmacDate(
+ searchid integer IDENTITY(100,1) NOT NULL,
+ animalid varchar(200) NULL,
+ JBGRemovalDate smalldatetime NULL,
+ JBGActualRemovalDate smalldatetime NULL
+
+ ) ON [PRIMARY]
+ GO
+
+CREATE TABLE onprc_ehr.JmacRemovalDate(
+ searchid integer IDENTITY(100,1) NOT NULL,
+ Id varchar(100) NULL,
+ JBGRemovalDate smalldatetime NULL,
+ JBGActualRemovalDate smalldatetime NULL,
+ DaysDiff float NULL,
+ reason varchar(100) NULL
+) ON [PRIMARY]
+GO
+
+
+
+/*
+**
+** Created by Date Comment
+**
+** blasa 4/10/2026 Process to update jmac Removal date
+**
+**
+**
+**/
+
+CREATE Procedure onprc_ehr.s_JmacRemovalDateProcess
+
+
+AS
+
+
+declare
+
+
+ @TempSearchKey Int,
+ @Searchkey Int,
+ @AnimalID varchar(100),
+ @OrgRemovalDate smalldatetime,
+ @ActualRemovalDate smalldatetime
+
+
+Begin
+
+
+ ----- Reset the last two months only
+
+ Delete onprc_ehr.Rpt_TempJmacDate
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+
+
+ Set @Tempsearchkey = 0
+ Set @Searchkey = 0
+ Set @Animalid = ''
+ Set @OrgRemovalDate = null
+ Set @ActualRemovalDate = null
+
+ --- Set initial processing
+
+ Insert into onprc_ehr.Rpt_TempJmacDate
+ select Id, JBGRemovalDate, JBGActualRemovalDate
+ from onprc_ehr.JmacRemovalDate
+
+ Order by searchid
+
+ Select top 1 @SearchKey = searchID from onprc_ehr.Rpt_TempJmacDate
+ Order by searchid
+
+
+ While @Tempsearchkey < @SearchKey
+ Begin
+
+ Set @Animalid = ''
+ Set @OrgRemovalDate = null
+ Set @ActualRemovalDate = null
+
+ select @animalid = animalid, @OrgRemovalDate = JBGRemovalDate, @ActualRemovalDate = JBGActualRemovalDate
+ from onprc_ehr.Rpt_TempJmacDate Where searchid = @Searchkey
+
+ -------Begin updating records
+
+
+ Update JB
+ Set JB.enddate = @ActualRemovalDate
+ From StudyDataset.c6d346_animal_group_members JB
+ Where JB.Participantid = @Animalid
+ And cast(JB.enddate as Date) = cast(@OrgRemovalDate as Date)
+
+
+ If @@Error <> 0
+ GoTo Err_Proc
+
+
+ Set @TempSearchkey = @Searchkey
+
+ Select Top 1 @SearchKey = searchid From onprc_ehr.Rpt_TempJmacDate
+ Where searchid > @Tempsearchkey
+ Order by searchid
+
+
+
+
+ End ------(While @tempsearchkey < @Searchkey)
+
+
+ Return 0
+
+ Err_Proc: Return 1
+
+
+
+
+END
+
+
+
+
diff --git a/onprc_ehr/resources/schemas/onprc_ehr.xml b/onprc_ehr/resources/schemas/onprc_ehr.xml
index 298c65edc..9b4e8a75e 100644
--- a/onprc_ehr/resources/schemas/onprc_ehr.xml
+++ b/onprc_ehr/resources/schemas/onprc_ehr.xml
@@ -1480,4 +1480,25 @@
+
+
+
+
+
diff --git a/onprc_ehr/resources/scripts/onprc_ehr/onprc_triggers.js b/onprc_ehr/resources/scripts/onprc_ehr/onprc_triggers.js
index 7628d6ea3..30a298a30 100644
--- a/onprc_ehr/resources/scripts/onprc_ehr/onprc_triggers.js
+++ b/onprc_ehr/resources/scripts/onprc_ehr/onprc_triggers.js
@@ -1256,85 +1256,118 @@ exports.init = function(EHR){
}
}
});
+
+ //Added by Kollil, April 2026
+ function toDateOnly(val) {
+ if (!val)
+ return null;
+
+ // row.date object
+ if (typeof val === 'object' && val.time) {
+ var d = new Date(val.time);
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
+ }
+
+ // date strings like "2026-04-20 00:00:00.000"
+ var s = String(val).split(' ')[0]; // keep only YYYY-MM-DD
+ var parts = s.split('-');
+ if (parts.length !== 3)
+ return null;
+
+ return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
+ }
+
// 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()){
+ 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) &&
+ !(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){
+ if (msgs) {
msgs = msgs.split("<>");
- for (var i=0;i row.enddatefinalized.getTime()){
- row.enddatefinalized = row.enddate;
- }
+ // 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.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');
- }
+ //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 by Kollil, April 2026. Refer to ticket # 13807
+ if (row.project && row.date) {
+ var projectEndDate = triggerHelper.getProjectEndDate(row.project); //helper.getJavaHelper().getProjectEndDate(row.project);
+ var assignmentDate = toDateOnly(row.date);
+ var endDate = toDateOnly(projectEndDate);
+
+ if (assignmentDate && endDate && assignmentDate.getTime() > endDate.getTime()) {
+ // console.log('4.5 DEBUG assignmentDate=' + assignmentDate);
+ EHR.Server.Utils.addError(scriptErrors, 'project', 'The assignment start date occurs after the end date of the selected center project. Please review the assignment date and confirm!', 'WARN');
+
+ }
+ }
+
});
//Added 10-5-2022 R.Blasa
@@ -1381,8 +1414,10 @@ exports.init = function(EHR){
// Added: 10-6-2025
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.AFTER_UPSERT, 'study', 'chemistryResults', function (helper, scriptErrors, row, oldRow) {
- if (row.Id && row.qualresult && row.qualresult.indexOf('panic') !== -1) {
- console.log("panic values: " + row.qualresult);
+
+ if (row.Id && row.qualresult && row.qualresult.indexOf('alert') !== -1) {
+
+ console.log("alert values: " + row.qualresult);
triggerHelper.sendClinpathPanicEmail(row.Id, row.runid, row.objectid);
}
});
diff --git a/onprc_ehr/resources/views/printRoom.html b/onprc_ehr/resources/views/printRoom.html
index 55f2aa8a8..01211fcf8 100644
--- a/onprc_ehr/resources/views/printRoom.html
+++ b/onprc_ehr/resources/views/printRoom.html
@@ -50,6 +50,7 @@
foundCages = true;
Ext4.create('Ext.panel.Panel', {
border: false,
+ width: 1450,
defaults: {
border: false
},
@@ -63,7 +64,7 @@
}
else {
// Hack to improve printing in Chrome
- if (Ext4.isChrome) { Ext4.get(webpart.wrapperDivId).setStyle({zoom: '150%'}); };
+ if (Ext4.isChrome) { Ext4.get(webpart.wrapperDivId).setStyle({zoom: '110%'}); };
}
}, this);
diff --git a/onprc_ehr/resources/web/onprc_ehr/model/sources/BehaviorDefaults.js b/onprc_ehr/resources/web/onprc_ehr/model/sources/BehaviorDefaults.js
index 5207f3b7b..eada6c102 100644
--- a/onprc_ehr/resources/web/onprc_ehr/model/sources/BehaviorDefaults.js
+++ b/onprc_ehr/resources/web/onprc_ehr/model/sources/BehaviorDefaults.js
@@ -117,7 +117,8 @@ EHR.model.DataModelManager.registerMetadata('BehaviorDefaults', {
},
category: {
lookup: {
- filterArray: [LABKEY.Filter.create('category', 'Behavior')]
+ filterArray: [LABKEY.Filter.create('category', 'Behavior'),
+ LABKEY.Filter.create('value', 'Behaviors',LABKEY.Filter.Types.NEQ)]
}
}
}
diff --git a/onprc_ehr/resources/web/onprc_ehr/model/sources/CaseMgmt.js b/onprc_ehr/resources/web/onprc_ehr/model/sources/CaseMgmt.js
new file mode 100644
index 000000000..7a9eb120b
--- /dev/null
+++ b/onprc_ehr/resources/web/onprc_ehr/model/sources/CaseMgmt.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2025 LabKey Corporation
+ *
+ * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+ */
+EHR.model.DataModelManager.registerMetadata('CaseMgmt', {
+ byQuery: {
+ 'study.clinremarks': {
+ Id: {
+ columnConfig: {
+ getEditor: function(rec){
+ if (rec && rec.get('caseid')){
+ return false;
+ }
+ return {
+ xtype: 'ehr-animalfield',
+ dataIndex: 'Id'
+ };
+ }
+ },
+ formEditorConfig: {
+ listeners: {
+ afterrender: function(field){
+ var TOOLTIP = 'Refresh the form to enter data for a different animal.';
+ var syncDisabledStyle = function(readOnly){
+ var inputEl = field.inputEl;
+ if (inputEl){
+ inputEl.setStyle({
+ 'background-color': readOnly ? '#f0f0f0' : '',
+ color: readOnly ? '#666666' : '',
+ cursor: readOnly ? 'not-allowed' : ''
+ });
+ }
+ };
+ var setTooltip = function(readOnly){
+ var el = field.getEl();
+ if (el){
+ el.set({'data-qtip': readOnly ? TOOLTIP : ''});
+ }
+ };
+ var syncReadOnly = function(){
+ var rec = EHR.DataEntryUtils.getBoundRecord(field);
+ var readOnly = !!(rec && rec.get('caseid'));
+ field.setReadOnly(readOnly);
+ syncDisabledStyle(readOnly);
+ setTooltip(readOnly);
+ };
+ syncReadOnly();
+ var formPanel = field.up('ehr-formpanel');
+ if (formPanel){
+ field.mon(formPanel, 'bindrecord', syncReadOnly, field, {buffer: 50});
+ }
+ if (EHR.DemographicsCache){
+ field.mon(EHR.DemographicsCache, 'casecreated', function(animalId){
+ var rec = EHR.DataEntryUtils.getBoundRecord(field);
+ if (rec && rec.get('Id') === animalId){
+ field.setReadOnly(true);
+ syncDisabledStyle(true);
+ setTooltip(true);
+ }
+ }, field);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+});
diff --git a/onprc_ehr/resources/web/onprc_ehr/model/sources/ClinicalReport.js b/onprc_ehr/resources/web/onprc_ehr/model/sources/ClinicalReport.js
index 5d2f3e1b5..2b4a9191d 100644
--- a/onprc_ehr/resources/web/onprc_ehr/model/sources/ClinicalReport.js
+++ b/onprc_ehr/resources/web/onprc_ehr/model/sources/ClinicalReport.js
@@ -27,9 +27,6 @@ EHR.model.DataModelManager.registerMetadata('ClinicalReport_ONPRC', {
hidden: false,
allowBlank: false
},
- remark: {
- hidden: false
- },
p2: {
formEditorConfig: {
xtype: 'ehr-plantextarea'
diff --git a/onprc_ehr/resources/web/onprc_ehr/panel/RoomLayoutPanel.js b/onprc_ehr/resources/web/onprc_ehr/panel/RoomLayoutPanel.js
index 1dd9304b0..b331c6582 100644
--- a/onprc_ehr/resources/web/onprc_ehr/panel/RoomLayoutPanel.js
+++ b/onprc_ehr/resources/web/onprc_ehr/panel/RoomLayoutPanel.js
@@ -184,15 +184,15 @@ Ext4.define('ONPRC.panel.RoomLayoutPanel', {
var rooms = Ext4.Object.getKeys(roomMap).sort();
var dividerWidth = 3;
- var height = 115;
- var cageWidth = 51; //Modified: 10-15-2020
+ var height = 75;
+ var cageWidth = 60;
var hasCages = false;
Ext4.each(rooms, function(room, roomIdx){
if (roomIdx == 0 && !config.printMode){
toAdd.push(ONPRC.panel.RoomLayoutPanel.getButtonCfgs(config));
toAdd.push({
- style: 'margin-bottom: 20px;',
+ style: 'margin-bottom: 5px;',
border: false
});
}
@@ -244,7 +244,7 @@ Ext4.define('ONPRC.panel.RoomLayoutPanel', {
border: false
});
- //Modified: 8-19-2019 R. Blasa Added Divider Legends Not eeded at this time
+ //Modified: 8-19-2019 R. Blasa Added Divider Legends Not needed at this time
currentSection.push({
//Modified: 4/3/2023 R.Blasa
diff --git a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessing.xlsx b/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessing.xlsx
deleted file mode 100644
index 9979a28d5..000000000
Binary files a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessing.xlsx and /dev/null differ
diff --git a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate.xlsx b/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate.xlsx
old mode 100644
new mode 100755
index bae51e026..66f764b22
Binary files a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate.xlsx and b/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate.xlsx differ
diff --git a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate_TPR_Master.xlsx b/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate_TPR_Master.xlsx
old mode 100644
new mode 100755
index d3affcd46..a3ff5ddee
Binary files a/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate_TPR_Master.xlsx and b/onprc_ehr/resources/web/onprc_ehr/templates/ClinicalProcessingTemplate_TPR_Master.xlsx differ
diff --git a/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing.js b/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing.js
index 74cb01ae1..9633f508b 100644
--- a/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing.js
+++ b/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing.js
@@ -305,6 +305,8 @@ Ext4.define('ONPRC_EHR.window.ClinicalProcessingWindow', {
{snomedcode = 'F-31030'}
if (row[7]== 3 )
{snomedcode = 'F-31040'}
+ if (row[7]== 'No' )
+ {snomedcode = 'F-30980'}
var obj = {
Id: id,
date: this.getTime(date, times, errors, rowIdx),
diff --git a/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing_TPR.js b/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing_TPR.js
index 3c7d37472..f883a9b76 100644
--- a/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing_TPR.js
+++ b/onprc_ehr/resources/web/onprc_ehr/window/ClinicalMassProcessing_TPR.js
@@ -420,6 +420,8 @@ Ext4.define('ONPRC_EHR.window.ClinicalProcessingTPRWindow', {
{snomedcode = 'F-31030'}
if (row[10]== 3 )
{snomedcode = 'F-31040'}
+ if (row[10]== 'No' )
+ {snomedcode = 'F-30980'}
var obj = {
Id: id,
date: this.getTime(date, times, errors, rowIdx),
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 d18c157d4..6e766bdc6 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 25.004;
+ return 25.005;
}
@Override
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/BehaviorExamFormType.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/BehaviorExamFormType.java
index 8f58945e1..843f5e11e 100644
--- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/BehaviorExamFormType.java
+++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/BehaviorExamFormType.java
@@ -58,6 +58,9 @@ public BehaviorExamFormType(DataEntryFormContext ctx, Module owner)
{
s.addConfigSource("BehaviorDefaults");
+ if (s.getName().equals("Clinical Remarks"))
+ s.addConfigSource("CaseMgmt");
+
if (!s.getName().equals("Clinical Remarks"))
s.addConfigSource("ClinicalReportChild");
@@ -78,6 +81,7 @@ public BehaviorExamFormType(DataEntryFormContext ctx, Module owner)
addClientDependency(ClientDependency.supplierFromPath("ehr/model/sources/ClinicalReport.js"));
addClientDependency(ClientDependency.supplierFromPath("ehr/panel/ExamDataEntryPanel.js"));
addClientDependency(ClientDependency.supplierFromPath("ehr/model/sources/ClinicalReportChild.js"));
+ addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/model/sources/CaseMgmt.js"));
setJavascriptClass("EHR.panel.ExamDataEntryPanel");
// //Added: 12-18-2017 R.Blasa
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/CagemateClinicalReportFormType.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/CagemateClinicalReportFormType.java
deleted file mode 100644
index 2040724e2..000000000
--- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/CagemateClinicalReportFormType.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.labkey.onprc_ehr.dataentry;
-
-import org.labkey.api.ehr.dataentry.AbstractFormSection;
-import org.labkey.api.ehr.dataentry.DataEntryFormContext;
-import org.labkey.api.ehr.dataentry.FormSection;
-import org.labkey.api.ehr.dataentry.SimpleGridPanel;
-import org.labkey.api.ehr.dataentry.TaskForm;
-import org.labkey.api.ehr.dataentry.TaskFormSection;
-import org.labkey.api.ehr.security.EHRClinicalEntryPermission;
-import org.labkey.api.module.Module;
-import org.labkey.api.view.template.ClientDependency;
-
-import java.util.Arrays;
-
-//Created: 1-31-2018 R.Blasa
-
-public class CagemateClinicalReportFormType extends TaskForm
-{
- public static final String NAME = "Cagemate Soaps";
-
- public CagemateClinicalReportFormType(DataEntryFormContext ctx, Module owner)
- {
- super(ctx, owner, NAME, "Cagemates Soaps", "Clinical", Arrays.asList(
- new TaskFormSection(),
- new AnimalDetailsFormSection(),
- new SimpleGridPanel("study", "Clinical Remarks", "SOAPs")
-
- ));
-
- setStoreCollectionClass("EHR.data.ClinicalReportStoreCollection");
- addClientDependency(ClientDependency.supplierFromPath("ehr/data/ClinicalReportStoreCollection.js"));
-
- setTemplateMode(AbstractFormSection.TEMPLATE_MODE.NO_ID);
- setDisplayReviewRequired(true);
-
- for (FormSection s : this.getFormSections())
- {
- s.addConfigSource("ClinicalDefaults");
- //Added 6-4-2015 Blasa
- s.addConfigSource("ClinicalProcedures");
- }
-
- addClientDependency(ClientDependency.supplierFromPath("ehr/model/sources/ClinicalDefaults.js"));
-
-
- }
-
-
-
- @Override
- protected boolean canInsert()
- {
- if (!getCtx().getContainer().hasPermission(getCtx().getUser(), EHRClinicalEntryPermission.class))
- return false;
-
- return super.canInsert();
- }
-
-}
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalReportFormType.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalReportFormType.java
index fa7b11c04..9a6f1faf4 100644
--- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalReportFormType.java
+++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalReportFormType.java
@@ -76,6 +76,9 @@ public ClinicalReportFormType(DataEntryFormContext ctx, Module owner)
// s.addConfigSource("ClinicalReport");
s.addConfigSource("ClinicalReport_ONPRC");
+ if (s.getName().equals("Clinical Remarks"))
+ s.addConfigSource("CaseMgmt");
+
if (!s.getName().equals("Clinical Remarks"))
s.addConfigSource("ClinicalReportChild");
@@ -95,6 +98,7 @@ public ClinicalReportFormType(DataEntryFormContext ctx, Module owner)
// Modified: 10-5-2017 R.Blasa reinstalled 2-12-21
addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/model/sources/ClinicalReport.js"));
+ addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/model/sources/CaseMgmt.js"));
// Added: 7-22-2025 R.Blasa
diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/query/ONPRC_EHRTriggerHelper.java b/onprc_ehr/src/org/labkey/onprc_ehr/query/ONPRC_EHRTriggerHelper.java
index fc7964c53..de49e9cc6 100644
--- a/onprc_ehr/src/org/labkey/onprc_ehr/query/ONPRC_EHRTriggerHelper.java
+++ b/onprc_ehr/src/org/labkey/onprc_ehr/query/ONPRC_EHRTriggerHelper.java
@@ -2021,6 +2021,33 @@ public boolean requiresAssistingStaff(Integer procedureId)
return "Surgery".equals(category);
}
+ //Added by Kollil
+ //Date: Apr 2026
+ public Date getProjectEndDate(Object projectId)
+ {
+ if (projectId == null)
+ return null;
+
+ int pid;
+ if (projectId instanceof Number)
+ pid = ((Number) projectId).intValue();
+ else
+ pid = Integer.parseInt(projectId.toString());
+
+ UserSchema ehrSchema = QueryService.get().getUserSchema(_user, _container, "ehr");
+ if (ehrSchema == null)
+ return null;
+
+ TableInfo ti = ehrSchema.getTable("project");
+ if (ti == null)
+ return null;
+
+ SimpleFilter filter = new SimpleFilter(FieldKey.fromString("project"), pid);
+ TableSelector ts = new TableSelector(ti, Collections.singleton("enddate"), filter, null);
+
+ return ts.getObject(Date.class);
+ }
+
public String getSpeciesForDam(String dam)
{
return new TableSelector(getTableInfo("study", "demographics"), PageFlowUtil.set("species"), new SimpleFilter(FieldKey.fromString("Id"), dam), null).getObject(String.class);
@@ -2640,7 +2667,8 @@ public void exec(ResultSet object) throws SQLException
public void sendClinpathPanicEmail(String id, String runid, String objectid)
{
- String subject = "Chemistry Results with Panic values";
+ String subject = "Chemistry Results with alert values";
+
Container c = getContainer();
@@ -2671,7 +2699,7 @@ public void sendClinpathPanicEmail(String id, String runid, String objectid)
if (ts.getRowCount() == 0)
{
- html.append("There are no Chemistry Panlc Values to display");
+ html.append("There are no Chemistry Alert Values to display");
return;
}
diff --git a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest.java b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest.java
index bdf812dd0..b6682a733 100644
--- a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest.java
+++ b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_EHRTest.java
@@ -72,6 +72,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.function.Function;
import static org.junit.Assert.assertEquals;
@@ -557,6 +558,29 @@ public void testArrivalApi() throws Exception
Assert.assertEquals(1, demographicsSelect.execute(getApiHelper().getConnection(), getContainerPath()).getRowCount().intValue());
}
+ @Test
+ public void testSubmitButtonsDisabledDuringValidation() throws Exception
+ {
+ List allIds = createTemporaryValidationAnimals(30);
+
+ try
+ {
+ log("Bulk adding animals in treatment orders for temporary test animals");
+ _helper.goToTaskForm("Medications/Diet", false);
+ Ext4GridRef treatmentGrid = _helper.getExt4GridForFormSection("Medication/Treatment Orders");
+ addBatchIdsToGrid(treatmentGrid, allIds);
+
+ assertActionsDisabledDuringValidation();
+
+ treatmentGrid.waitForRowCount(allIds.size());
+ _helper.discardForm();
+ }
+ finally
+ {
+ deleteTemporaryValidationAnimals(allIds);
+ }
+ }
+
@Test
public void testCustomActions() throws Exception
{
@@ -1103,8 +1127,9 @@ public void testExamEntry() throws Exception
Assert.assertEquals(remark, bloodGrid.getFieldValue(3, "remark"));
Assert.assertEquals(remark, bloodGrid.getFieldValue(4, "remark"));
- waitAndClickAndWait(_helper.getDataEntryButton("Save & Close"));
- waitForElement(Locator.tagWithText("a", "Enter New Data"));
+ waitForDataEntryButtonEnabled("Save & Close", WAIT_FOR_PAGE * 2);
+ waitAndClick(_helper.getDataEntryButton("Save & Close"));
+ waitForElement(Locator.tagWithText("a", "Enter New Data"), WAIT_FOR_PAGE * 2);
}
@Test
@@ -1488,6 +1513,9 @@ public void testPathology()
//test SNOMED codes
_ext4Helper.clickExt4Tab("Histologic Findings");
Ext4GridRef histologyGrid = _helper.getExt4GridForFormSection("Histologic Findings");
+ // The custom "Add Record" handler returns early until the tab's grid store finishes loading.
+ waitFor(() -> (Boolean)histologyGrid.getFnEval("return !!this.store && (!this.store.hasLoaded || this.store.hasLoaded());"),
+ "Histologic Findings grid store did not finish loading", WAIT_FOR_JAVASCRIPT);
_helper.addRecordToGrid(histologyGrid, "Add Record");
scrollIntoView(histologyGrid.getCell(1,7), true);
waitAndClick(histologyGrid.getCell(1, 7));
@@ -1566,7 +1594,9 @@ public void testPathology()
waitForElementToDisappear(deathWindow, 20000); //saving can take longer than default 10 seconds
waitForElementToDisappear(Locator.tagContainingText("div", "Saving Changes...").notHidden());
- waitAndClickAndWait(_helper.getDataEntryButton("Save & Close"));
+ waitForDataEntryButtonEnabled("Save & Close", WAIT_FOR_PAGE * 2);
+ waitAndClick(_helper.getDataEntryButton("Save & Close"));
+ waitForElement(Locator.tagWithText("a", "Enter New Data"), WAIT_FOR_PAGE * 2);
//make new necropsy, copy from previous
_helper.goToTaskForm("Necropsy", false);
@@ -1971,6 +2001,107 @@ private void setNecropsyFormElement(String id, String value)
assertEquals(value, getFormElement(loc));
}
+ private void addBatchIdsToGrid(Ext4GridRef grid, List ids)
+ {
+ grid.clickTbarButton("Add Batch");
+ waitForElement(Ext4Helper.Locators.window("Choose Animals"));
+ Ext4FieldRef.getForLabel(this, "Id(s)").setValue(StringUtils.join(ids, ";"));
+
+ waitAndClick(Ext4Helper.Locators.window("Choose Animals").append(Ext4Helper.Locators.ext4Button("Submit")));
+ grid.waitForRowCount(ids.size());
+ }
+
+ private void assertActionsDisabledDuringValidation()
+ {
+ List buttonTexts = Arrays.asList("Save Draft", "Save & Close", "Submit For Review", "Submit Final");
+ List menuItemTexts = Arrays.asList("Submit And Reload", "Force Submit");
+ Locator.XPathLocator validationIndicator = Locator.tagContainingText("span", "Validating...").notHidden();
+ waitFor(() -> !validationIndicator.findElements(getDriver()).isEmpty(),
+ "Validation indicator never appeared", WAIT_FOR_PAGE);
+
+ for (String buttonText : buttonTexts)
+ {
+ List buttons = _ext4Helper.componentQuery("button[text='" + buttonText + "']", Ext4CmpRef.class);
+ if (!buttons.isEmpty())
+ {
+ waitFor(() -> Boolean.TRUE.equals(buttons.get(0).getEval("isDisabled() == arguments[0]", true)),
+ buttonText + " did not become disabled during validation", WAIT_FOR_PAGE);
+ }
+ }
+
+ waitAndClick(_helper.getDataEntryButton("More Actions"));
+ waitForElement(Ext4Helper.Locators.menu().notHidden());
+ for (String menuItemText : menuItemTexts)
+ {
+ waitForElement(Ext4Helper.Locators.menuItemDisabled(menuItemText).notHidden());
+ }
+ waitAndClick(_helper.getDataEntryButton("More Actions"));
+ waitForElementToDisappear(Ext4Helper.Locators.menu().notHidden());
+
+ waitFor(() -> validationIndicator.findElements(getDriver()).isEmpty(),
+ "Validation indicator did not disappear", WAIT_FOR_PAGE * 2);
+ waitForText(WAIT_FOR_PAGE * 2, "WARN");
+ waitForText(WAIT_FOR_PAGE * 2, "ERROR");
+ }
+
+ private List createTemporaryValidationAnimals(int count) throws Exception
+ {
+ String seed = Long.toString(System.currentTimeMillis());
+ seed = seed.substring(Math.max(0, seed.length() - 6));
+
+ String[] species = {"Rhesus", "Cynomolgus", "Marmoset"};
+ String[] fields = {"Id", "Species", "Birth", "Gender", "date", "calculated_status", "objectid"};
+ Object[][] data = new Object[count][];
+ List ids = new ArrayList<>();
+
+ for (int i = 0; i < count; i++)
+ {
+ String id = "VAL" + seed + String.format("%02d", i + 1);
+ ids.add(id);
+ data[i] = new Object[]{
+ id,
+ species[i % species.length],
+ new Date().toString(),
+ i % 2 == 0 ? getMale() : getFemale(),
+ new Date(),
+ "Alive",
+ UUID.randomUUID().toString()
+ };
+ }
+
+ getApiHelper().deleteAllRecords("study", "demographics", new Filter("Id", StringUtils.join(ids, ";"), Filter.Operator.IN));
+ getApiHelper().doSaveRows(DATA_ADMIN.getEmail(),
+ getApiHelper().prepareInsertCommand("study", "demographics", "lsid", fields, data),
+ getExtraContext());
+ cacheIds(ids);
+
+ return ids;
+ }
+
+ private void deleteTemporaryValidationAnimals(List ids) throws Exception
+ {
+ if (ids.isEmpty())
+ {
+ return;
+ }
+
+ getApiHelper().deleteAllRecords("study", "demographics", new Filter("Id", StringUtils.join(ids, ";"), Filter.Operator.IN));
+ }
+
+ private void waitForDataEntryButtonEnabled(String buttonText, int timeout)
+ {
+ waitFor(() -> {
+ List buttons = _ext4Helper.componentQuery("button[text='" + buttonText + "']", Ext4CmpRef.class);
+ if (buttons.isEmpty())
+ {
+ return false;
+ }
+
+ return Boolean.TRUE.equals(buttons.get(0).getEval("isDisabled() == arguments[0]", false));
+ },
+ "Button did not become enabled: " + buttonText, timeout);
+ }
+
@Override
protected String getAnimalHistoryPath()
{
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 ee9e2602f..7b0c7fffb 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
@@ -1449,6 +1449,145 @@ public void gridErrorsTest()
//TODO: make sure fields turn red as expected
}
+ /**
+ * Verifies the clinremarks Id field read-only + tooltip behavior wired in via the
+ * `CaseMgmt` metadata source (onprc_ehr/model/sources/CaseMgmt.js). The source is
+ * registered against both ClinicalReportFormType and BehaviorExamFormType, so this
+ * test exercises both forms through a shared helper.
+ */
+ @Test
+ public void testClinremarksIdReadOnlyOnCaseCreated() throws Exception
+ {
+ goToEHRFolder();
+
+ // Verify case open and open & immediately close. Test Exams/Cases and BSU Exam forms.
+ verifyClinremarksIdLockOnCaseCreated("Exams/Cases", "Clinical", "Open Case", CaseEntryPath.MANAGE_CASES_LINK);
+ verifyClinremarksIdLockOnCaseCreated("BSU Exam", "Behavior", "Open & Immediately Close", CaseEntryPath.MANAGE_CASES_LINK);
+
+ // Top and bottom buttons
+ verifyClinremarksIdLockOnCaseCreated("Exams/Cases", "Clinical", "Open Case", CaseEntryPath.OPEN_MANAGE_TOP);
+ verifyClinremarksIdLockOnCaseCreated("BSU Exam", "Behavior", "Open Case", CaseEntryPath.OPEN_MANAGE_BOTTOM);
+ }
+
+ /** How the test reaches the "create new case" dialog from the data entry form. */
+ private enum CaseEntryPath
+ {
+ /** [Manage Cases] link → "Open Case" split button → "Open <category> Case" menu item. */
+ MANAGE_CASES_LINK,
+ /** "Open/Manage <category> Case" button in the Instructions panel at the top of the form. */
+ OPEN_MANAGE_TOP,
+ /** "Open/Manage <category> Case" button in the form's docked footer toolbar. */
+ OPEN_MANAGE_BOTTOM
+ }
+
+ private void verifyClinremarksIdLockOnCaseCreated(String formLinkLabel, String caseCategory, String openButtonLabel, CaseEntryPath entryPath)
+ {
+ final String expectedTooltip = "Refresh the form to enter data for a different animal.";
+
+ log("Verifying clinremarks Id read-only on casecreated for form: " + formLinkLabel + " via '" + openButtonLabel + "' (entry: " + entryPath + ")");
+ _helper.goToTaskForm(formLinkLabel, false);
+ _ext4Helper.clickExt4Tab("SOAP");
+
+ Ext4FieldRef idField = _helper.getExt4FieldForFormSection("SOAP", "Id");
+ Assert.assertNotNull("Could not locate Id field in SOAP section of form: " + formLinkLabel, idField);
+
+ idField.setValue(SUBJECTS[0]);
+
+ // Wait for the AnimalDetailsPanel to display the Id
+ Ext4FieldRef detailsId = _ext4Helper.queryOne("displayfield[name=animalId]", Ext4FieldRef.class);
+ Assert.assertNotNull("AnimalDetailsPanel not rendered (form: " + formLinkLabel + ")", detailsId);
+ waitFor(() -> SUBJECTS[0].equals(String.valueOf(detailsId.getValue())),
+ "AnimalDetailsPanel did not display Id " + SUBJECTS[0] + " (form: " + formLinkLabel + ")",
+ WAIT_FOR_JAVASCRIPT);
+
+ Assert.assertNotEquals("Id field should be editable before any case is created (form: " + formLinkLabel + ")",
+ Boolean.TRUE, idField.getEval("readOnly"));
+ Object preQtip = idField.getEval("getEl().dom.getAttribute('data-qtip')");
+ assertEquals("Id field should have no tooltip before any case is created (form: " + formLinkLabel + ")",
+ "", preQtip == null ? "" : preQtip.toString());
+
+ // Open a real case from the data entry form so ManageCasesPanel fires the real casecreated event
+ createCaseFromForm(SUBJECTS[0], caseCategory, openButtonLabel, entryPath);
+
+ waitFor(() -> Boolean.TRUE.equals(idField.getEval("readOnly")),
+ "Id field did not become read-only after case was opened (form: " + formLinkLabel + ")",
+ WAIT_FOR_JAVASCRIPT);
+ Object postQtip = idField.getEval("getEl().dom.getAttribute('data-qtip')");
+ assertEquals("Id field should carry the lock tooltip after case is opened (form: " + formLinkLabel + ")",
+ expectedTooltip, postQtip == null ? "" : postQtip.toString());
+
+ _helper.discardForm();
+ }
+
+ /**
+ * Opens a case for {@code animalId} from the data entry form via the given {@code entryPath}, then
+ * closes the resulting Manage Cases window. {@code openButtonLabel} is one of the OpenCaseWindow submit
+ * buttons: "Open Case" (just open) or "Open & Immediately Close" (open and immediately close permanently).
+ */
+ private void createCaseFromForm(String animalId, String caseCategory, String openButtonLabel, CaseEntryPath entryPath)
+ {
+ Locator.XPathLocator manageCasesWindow = Ext4Helper.Locators.window("Manage Cases: " + animalId);
+ triggerCreateCaseDialog(manageCasesWindow, caseCategory, entryPath);
+
+ // ManageCasesPanel asks "Open New" vs "Edit Existing" first if an active case of this category
+ // already exists for the animal (ManageCasesPanel.js: showCreateWindow). Dismiss with "Open New".
+ Locator.XPathLocator existingCaseDialog = Ext4Helper.Locators.window("Open Case");
+ if (Boolean.TRUE.equals(waitFor(() -> isElementPresent(existingCaseDialog), 2000)))
+ {
+ waitAndClick(existingCaseDialog.append(Ext4Helper.Locators.ext4ButtonEnabled("Open New")));
+ waitForElementToDisappear(existingCaseDialog);
+ }
+
+ Locator.XPathLocator openCaseWindow = Ext4Helper.Locators.window("Open Case: " + animalId);
+ waitForElement(openCaseWindow);
+
+ if ("Clinical".equals(caseCategory))
+ {
+ Ext4ComboRef vetField = Ext4ComboRef.getForLabel(this, "Assigned Vet");
+ vetField.waitForStoreLoad();
+ // Pick whichever vet the store has rather than hardcoding a display name; the test only needs the field populated
+ vetField.eval("setValue(arguments[0])", vetField.getFnEval("return this.store.getAt(0).get(this.valueField)"));
+ Ext4FieldRef.getForLabel(this, "Problem").setValue("Behavioral");
+ }
+ else if ("Behavior".equals(caseCategory))
+ {
+ Ext4FieldRef.getForLabel(this, "Subcategory").setValue("Alopecia");
+ }
+
+ waitAndClick(openCaseWindow.append(Ext4Helper.Locators.ext4ButtonEnabled(openButtonLabel)));
+ if ("Open & Immediately Close".equals(openButtonLabel))
+ {
+ waitAndClick(Ext4Helper.Locators.menuItem("Close Permanently").notHidden());
+ }
+ waitForElementToDisappear(openCaseWindow);
+
+ waitAndClick(manageCasesWindow.append(Ext4Helper.Locators.ext4ButtonEnabled("Close")));
+ waitForElementToDisappear(manageCasesWindow);
+ }
+
+ private void triggerCreateCaseDialog(Locator.XPathLocator manageCasesWindow, String caseCategory, CaseEntryPath entryPath)
+ {
+ switch (entryPath)
+ {
+ case MANAGE_CASES_LINK -> {
+ waitAndClick(Locator.linkWithText("[Manage Cases]"));
+ waitForElement(manageCasesWindow);
+ waitAndClick(manageCasesWindow.append(Ext4Helper.Locators.ext4ButtonEnabled("Open Case")));
+ waitAndClick(Ext4Helper.Locators.menuItem("Open " + caseCategory + " Case").notHidden());
+ }
+ case OPEN_MANAGE_TOP -> {
+ Locator.XPathLocator instructionsPanel = Locator.tagWithClass("div", "x4-panel").withChild(
+ Locator.tagWithClass("div", "x4-panel-header").withDescendant(
+ Locator.tagWithClass("span", "x4-panel-header-text").withText("Instructions")));
+ waitAndClick(instructionsPanel.append(Ext4Helper.Locators.ext4ButtonEnabled("Open/Manage " + caseCategory + " Case")));
+ }
+ case OPEN_MANAGE_BOTTOM -> {
+ Locator.XPathLocator footerToolbar = Locator.tagWithClass("div", "x4-toolbar-footer");
+ waitAndClick(footerToolbar.append(Ext4Helper.Locators.ext4ButtonEnabled("Open/Manage " + caseCategory + " Case")));
+ }
+ }
+ }
+
@Override
protected String getAnimalHistoryPath()
{
diff --git a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java
index 7689b7356..05a537821 100644
--- a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java
+++ b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java
@@ -293,13 +293,16 @@ public void restrictedIssueSearchTest()
// verify that we can return links even if the user doesn't have permission to view a restricted issue
Assert.assertTrue("Number of search results not expected", resultsPage.getResults().size() == 2);
- // verify assigned to users will see both results but shouldn't be able to see details of issues not assigned to them
+ // verify assigned to users will see both results but shouldn't be able to see details of issues not assigned to them,
+ // also verify that there is a warning rendered if a search result is restricted
impersonate(USER1.getEmail());
+ assertTextPresent("Restricted Issue: You do not have access. Contact your administrator for access.");
verifyIssueAccess(ISSUE_1, true);
verifyIssueAccess(ISSUE_2, false);
stopImpersonating(false);
impersonate(USER2.getEmail());
+ assertTextPresent("Restricted Issue: You do not have access. Contact your administrator for access.");
verifyIssueAccess(ISSUE_1, false);
verifyIssueAccess(ISSUE_2, true);
stopImpersonating();