From a5226e016f2f1c12257f2c2272c5cd7f811c58b9 Mon Sep 17 00:00:00 2001 From: Brent Logan Date: Tue, 18 Nov 2025 18:51:52 -0800 Subject: [PATCH 01/10] Create Historical Room Utilization query --- .../ehr_lookups/roomUtilizationHistorical.sql | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql new file mode 100644 index 000000000..a0584d3eb --- /dev/null +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -0,0 +1,262 @@ +PARAMETERS(ReportDate TIMESTAMP) + +/* Get starting date for each room */ +WITH RoomStartData AS ( + SELECT + room, + min(date) AS startingDate + FROM study.housing + GROUP BY room +), +/* Get total cage locations in each room */ +CageLocationData AS ( + SELECT + c.room, + count(c.cage) AS cageSpots + FROM ehr_lookups.cages c + GROUP BY c.room +), +/* Get total animals housed in each room on the report date */ +AnimalHousingData AS ( + SELECT + h.room, + count(h.id) AS totalAnimals + FROM study.housing h + WHERE + coalesce( REPORTDATE , CAST('1900-01-01 00:00:00.0' as timestamp)) < coalesce(h.enddate, now()) + AND coalesce(REPORTDATE, now()) >= coalesce(h.date, now()) + GROUP BY h.room +), +dateRange AS ( + SELECT + i.date, + CAST(i.date as date) as dateOnly, + CAST(dayofyear(i.date) as INTEGER) as DayOfYear, + CAST(dayofmonth(i.date) as INTEGER) as DayOfMonth, + CAST(dayofweek(i.date) as INTEGER) as DayOfWeek, + ceiling(CAST(dayofmonth(i.date) as FLOAT) / 7.0) as WeekOfMonth, + CAST(week(i.date) as INTEGER) as WeekOfYear, + CAST(REPORTDATE AS TIMESTAMP) as ReportDate + + FROM ( + SELECT + timestampadd('SQL_TSI_DAY', i.value, CAST(coalesce(REPORTDATE, curdate()) AS TIMESTAMP)) as date + FROM ldk.integers i + ) i + WHERE i.date <= REPORTDATE +), +/* The following CTE is onprc_billing.perDiemsByDay modified to use CTE dateRange, which uses only a single data parameter: ReportDate */ +PerDiemsEquivByDayData AS ( + SELECT + t.*, + CASE + WHEN t.overlappingProjects IS NULL THEN 1 + -- NOTE: An assignment overlapping with TMB is not charged per diems. If TMB is single-assigned, it pays per diem and will be caught above. + WHEN t.tmbAssignments > 0 then 0 + WHEN t.assignedProject IS NULL AND t.overlappingProjects IS NOT NULL THEN 0 + WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 0 + WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory NOT LIKE '%Research%' THEN (1.0 / NULLIF((t.totalOverlappingProjects + 1), 0)) + WHEN t.ProjectType = 'Research' AND t.overlappingProjectsCategory NOT LIKE '%Research%' THEN 1 + WHEN t.ProjectType = 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN (1.0 / NULLIF((t.totalOverlappingResearchProjects + 1), 0)) + ELSE 1 + END as effectiveDays, + CASE + WHEN (t.assignedProject IS NULL AND t.overlappingProjects IS NULL) THEN 'Base Grant' + WHEN t.overlappingProjects IS NULL then 'Single Project' + WHEN (t.tmbAssignments > 0) THEN 'Exempt By TMB' + WHEN (t.isTMBProject = 1 AND t.overlappingProjects IS NOT NULL) THEN 'Exempt By TMB' + WHEN t.assignedProject IS NULL AND t.overlappingProjects IS NOT NULL THEN 'Paid By Overlapping Project' + WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 'Paid By Overlapping Project' + WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory NOT LIKE '%Research%' THEN 'Multiple Resources' + WHEN t.ProjectType = 'Research' AND t.overlappingProjectsCategory NOT LIKE '%Research%' THEN 'Single Project' + WHEN t.ProjectType = 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 'Multiple Research' + ELSE 'Unknown' + END as category, + CASE + -- Catch duplicate chargeIds + WHEN (t.perDiemFeeCount > 1) THEN NULL + -- Use the treatmentOrder to look for BottleFed + WHEN (t.bottleFedRecordCount > 0 AND t.researchRecordCount > 0) THEN maxPdfChargeId + -- If this item supports infants, charge that + WHEN (pdfChargeInfantCount > 0 AND maxPdfChargeId IS NOT NULL) THEN maxPdfChargeId + -- Otherwise, infants are a special rate + WHEN (perDiemAge < CAST(javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.INFANT_PER_DIEM_AGE') AS INTEGER)) + THEN (SELECT ci.rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.INFANT_PER_DIEM')) + -- Add quarantine flags, which trump housing type + WHEN (quarantineFlagCount > 0) + THEN (SELECT ci.rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.QUARANTINE_PER_DIEM')) + -- Finally, defer to housing condition + ELSE maxPdfChargeId + END as chargeId, + -- Find overlapping tier flags on that day + coalesce(( + SELECT group_concat(DISTINCT f.flag.value) AS tier + FROM study.flags f + -- NOTE: allow flags that ended on this date + WHERE f.Id = t.Id AND f.enddateCoalesced >= t.dateOnly AND f.dateOnly <= t.dateOnly AND f.flag.category = 'Housing Tier' + ), 'Tier 2') AS tier + + FROM ( + SELECT + i2.Id, + CAST(CAST(i2.dateOnly AS DATE) AS TIMESTAMP) AS DATE, + i2.dateOnly @hidden, + coalesce(a.project, (SELECT p.project FROM ehr.project p WHERE p.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.BASE_GRANT_PROJECT'))) AS project, + a.project AS assignedProject, + max(a.duration) AS duration, -- should only have 1 value, no so need to include in grouping + max(timestampdiff('SQL_TSI_DAY', d.birth, i2.dateOnly)) AS ageAtTime, + a.project.use_Category AS ProjectType, + count(*) AS totalAssignmentRecords, + group_concat(DISTINCT a2.project.displayName) AS overlappingProjects, + count(DISTINCT a2.project) AS totalOverlappingProjects, + sum(CASE WHEN a2.project.use_Category = 'Research' THEN 1 ELSE 0 END) as totalOverlappingResearchProjects, + group_concat(DISTINCT a2.project.use_category) AS overlappingProjectsCategory, + group_concat(DISTINCT a2.project.protocol) AS overlappingProtocols, + count(h3.room) AS totalHousingRecords, + group_concat(DISTINCT h3.room) AS rooms, + group_concat(DISTINCT h3.cage) AS cages, + group_concat(DISTINCT h3.objectid) AS housingRecords, + group_concat(DISTINCT a.objectid) AS assignmentRecords, + group_concat(DISTINCT h3.room.housingCondition.value) AS housingConditions, + group_concat(DISTINCT h3.room.housingType.value) AS housingTypes, + max(timestampdiff('SQL_TSI_DAY', d.birth, i2.dateOnly)) AS perDiemAge, + count(DISTINCT pdf.chargeId) AS perDiemFeeCount, + i2.researchRecordCount, + i2.bottleFedRecordCount, + count(CASE WHEN pdf.canChargeInfants = TRUE THEN 1 ELSE NULL END) AS pdfChargeInfantCount, + max(pdf.chargeId) AS maxPdfChargeId, + (SELECT count(*) AS c + FROM study.flags q + WHERE q.Id = i2.Id AND q.flag.value LIKE '%Quarantine%' AND q.dateOnly <= i2.dateOnly AND q.enddateCoalesced >= i2.dateOnly + ) AS quarantineFlagCount, + max(i2.ReportDate) AS ReportDate @hidden, + count(tmb.Id) AS tmbAssignments, + SUM(CASE WHEN a.projectName = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.TMB_PROJECT') THEN 1 ELSE 0 END) AS isTMBProject + + FROM ( + -- Find all distinct animals housed at the Center each day. + -- This is the first dataset to include all animals here, not just assigned animals. + SELECT + h.Id, + i.dateOnly, + max(h.date) AS lastHousingStart, + min(i.ReportDate) AS ReportDate @hidden, + count(a3.project) as researchRecordCount, + count(t1.code) as bottleFedRecordCount + FROM dateRange i + JOIN study.housing h ON (h.dateOnly <= i.dateOnly AND h.enddateCoalesced >= i.dateOnly AND h.qcstate.publicdata = TRUE) + LEFT JOIN study.assignment a3 ON a3.id = h.id AND a3.date <= i.dateOnly AND a3.endDateCoalesced > i.dateOnly AND a3.project.Use_Category LIKE '%Research%' + LEFT JOIN study.treatment_Order t1 ON t1.id = h.id AND t1.code.meaning LIKE '%Bottle%' AND t1.date <= i.dateOnly + GROUP BY h.Id, i.dateOnly + ) i2 + + JOIN study.demographics d ON ( + i2.Id = d.Id + ) + + -- Housing is a little tricky. Using the query above, we want to find the max start date, on or before this day. + -- The housingType from this location is used. + JOIN study.housing h3 ON (h3.Id = i2.Id AND i2.lastHousingStart = h3.date AND h3.qcstate.publicdata = TRUE) + + -- Then join to any assignment record overlapping each day + LEFT JOIN ( + SELECT + a.lsid, + a.id, + a.project, + a.project.name AS projectName, + a.date, + a.assignCondition, + a.releaseCondition, + a.projectedReleaseCondition, + a.duration, + a.enddate, + a.dateOnly, + a.enddateCoalesced, + a.objectid + FROM study.assignment a + WHERE a.qcstate.publicdata = TRUE + -- NOTE: We don't exclude 1-day assignments or treat them differently. + -- AND a.duration > 0 + ) a ON ( + i2.Id = a.id + AND a.dateOnly <= i2.dateOnly + -- Assignments end at midnight, so an assignment doesn't count on the current date if it ends on it. + -- However, we also include 1-day assignments, which *can* have the end date match the start date. + AND (a.enddate IS NULL OR a.enddateCoalesced > i2.dateOnly OR (a.dateOnly = i2.dateOnly AND a.enddateCoalesced = i2.dateOnly)) + ) + + LEFT JOIN ( + -- For each assignment, find the co-assigned projects on that day. + SELECT + a2.lsid, + a2.date, + a2.enddate, + a2.id, + a2.project, + a2.dateOnly, + a2.enddateCoalesced + FROM study.assignment a2 + WHERE a2.qcstate.publicdata = TRUE + -- NOTE: We don't exclude 1-day assignments or treat them differently. + -- AND a2.duration > 1 + ) a2 ON ( + i2.id = a2.id + AND a2.dateOnly <= i2.dateOnly + AND a.project != a2.project + -- Assignments end at midnight, so an assignment doesn't count on the current date if it ends on it. + -- However, we also include 1-day assignments, which *can* have the end date match the start date. + AND (a2.enddate IS NULL OR a2.enddateCoalesced > i2.dateOnly OR (a2.dateOnly = i2.dateOnly AND a2.enddateCoalesced = i2.dateOnly)) + AND a.lsid != a2.lsid + ) + + -- Find overlapping TMB on this date, which overrides the per diem. + LEFT JOIN study.assignment tmb ON ( + a.id = tmb.id + AND tmb.dateOnly <= i2.dateOnly + AND tmb.project != a.project + AND tmb.endDateCoalesced >= i2.dateOnly + AND tmb.project.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.TMB_PROJECT') + ) + + LEFT JOIN onprc_billing.perDiemFeeDefinition pdf ON ( + pdf.housingType = h3.room.housingType + AND pdf.housingDefinition = h3.room.housingCondition + -- Find overlapping tier flags on that day + AND coalesce( + (SELECT group_concat(DISTINCT f.flag.value) as tier + FROM study.flags f + --NOTE: allow flags that ended on this date + WHERE f.Id = i2.Id AND f.enddateCoalesced >= i2.dateOnly AND f.dateOnly <= i2.dateOnly AND f.flag.category = 'Housing Tier'), + 'Tier 2' + ) = pdf.tier + ) + + GROUP BY i2.dateOnly, i2.Id, a.project, a.project.use_Category, i2.researchRecordCount, i2.bottleFedRecordCount + ) t +) + +SELECT + REPORTDATE @title='Report Date', + r.area, + r.room, + r.housingType, + coalesce(cld.cageSpots, 0) AS totalCageSpaces, + coalesce(ahd.totalAnimals, 0) AS totalAnimals, + coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, + coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed @title='% Used' +FROM ehr_lookups.rooms r + JOIN RoomStartData rsd ON rsd.room = r.room + LEFT JOIN AnimalHousingData ahd ON ahd.room = r.room + LEFT JOIN ( + SELECT + pd.rooms, + sum(pd.effectiveDays) AS perDiemsEquiv + FROM PerDiemsEquivByDayData pd + GROUP BY pd.rooms + ) pd ON pd.rooms = r.room + LEFT JOIN CageLocationData cld ON cld.room = r.room +WHERE r.housingType = 205 -- Cage Location + AND r.housingCondition != 490 -- Exclude none|NECROPSY + AND REPORTDATE <= coalesce(r.dateDisabled, now()) + AND (coalesce(rsd.startingDate, now()) <= REPORTDATE OR rsd.startingDate IS NULL) \ No newline at end of file From 53859fcf3c6122f8c31e0c0c61e6b188b321d517 Mon Sep 17 00:00:00 2001 From: Brent Logan Date: Wed, 19 Nov 2025 10:36:05 -0800 Subject: [PATCH 02/10] Create .query.xml --- .../roomUtilizationHistorical.query.xml | 23 +++++++ .../ehr_lookups/roomUtilizationHistorical.sql | 63 ++++++------------- 2 files changed, 41 insertions(+), 45 deletions(-) create mode 100644 onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml new file mode 100644 index 000000000..123b938f9 --- /dev/null +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml @@ -0,0 +1,23 @@ + + + + + Historic Room Utilization + + + + Report Date + MM-dd-yyyy + + + 0.00 + + + % Used + 0.00% + + +
+
+
+
diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index a0584d3eb..840ffcd70 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -27,6 +27,7 @@ AnimalHousingData AS ( AND coalesce(REPORTDATE, now()) >= coalesce(h.date, now()) GROUP BY h.room ), +/* A modified version of ldk.dateRange with a single date parameter ReportDate */ dateRange AS ( SELECT i.date, @@ -45,13 +46,11 @@ dateRange AS ( ) i WHERE i.date <= REPORTDATE ), -/* The following CTE is onprc_billing.perDiemsByDay modified to use CTE dateRange, which uses only a single data parameter: ReportDate */ -PerDiemsEquivByDayData AS ( +PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsByDay modified to use CTE dateRange, which uses only a single data parameter: ReportDate SELECT t.*, CASE - WHEN t.overlappingProjects IS NULL THEN 1 - -- NOTE: An assignment overlapping with TMB is not charged per diems. If TMB is single-assigned, it pays per diem and will be caught above. + WHEN t.overlappingProjects IS NULL THEN 1 -- An assignment overlapping with TMB is not charged per diems. WHEN t.tmbAssignments > 0 then 0 WHEN t.assignedProject IS NULL AND t.overlappingProjects IS NOT NULL THEN 0 WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 0 @@ -73,29 +72,20 @@ PerDiemsEquivByDayData AS ( ELSE 'Unknown' END as category, CASE - -- Catch duplicate chargeIds - WHEN (t.perDiemFeeCount > 1) THEN NULL - -- Use the treatmentOrder to look for BottleFed - WHEN (t.bottleFedRecordCount > 0 AND t.researchRecordCount > 0) THEN maxPdfChargeId - -- If this item supports infants, charge that - WHEN (pdfChargeInfantCount > 0 AND maxPdfChargeId IS NOT NULL) THEN maxPdfChargeId - -- Otherwise, infants are a special rate - WHEN (perDiemAge < CAST(javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.INFANT_PER_DIEM_AGE') AS INTEGER)) + WHEN (t.perDiemFeeCount > 1) THEN NULL -- Catch duplicate chargeIds + WHEN (t.bottleFedRecordCount > 0 AND t.researchRecordCount > 0) THEN maxPdfChargeId -- Use the treatmentOrder to look for BottleFed + WHEN (pdfChargeInfantCount > 0 AND maxPdfChargeId IS NOT NULL) THEN maxPdfChargeId -- If this item supports infants, charge that + WHEN (perDiemAge < CAST(javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.INFANT_PER_DIEM_AGE') AS INTEGER)) -- Otherwise, infants are a special rate THEN (SELECT ci.rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.INFANT_PER_DIEM')) - -- Add quarantine flags, which trump housing type - WHEN (quarantineFlagCount > 0) + WHEN (quarantineFlagCount > 0) -- Add quarantine flags, which trump housing type THEN (SELECT ci.rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.QUARANTINE_PER_DIEM')) - -- Finally, defer to housing condition - ELSE maxPdfChargeId + ELSE maxPdfChargeId -- Finally, defer to housing condition END as chargeId, - -- Find overlapping tier flags on that day - coalesce(( + coalesce(( -- Find overlapping tier flags on that day SELECT group_concat(DISTINCT f.flag.value) AS tier FROM study.flags f - -- NOTE: allow flags that ended on this date - WHERE f.Id = t.Id AND f.enddateCoalesced >= t.dateOnly AND f.dateOnly <= t.dateOnly AND f.flag.category = 'Housing Tier' + WHERE f.Id = t.Id AND f.enddateCoalesced >= t.dateOnly AND f.dateOnly <= t.dateOnly AND f.flag.category = 'Housing Tier' -- NOTE: allow flags that ended on this date ), 'Tier 2') AS tier - FROM ( SELECT i2.Id, @@ -132,10 +122,7 @@ PerDiemsEquivByDayData AS ( max(i2.ReportDate) AS ReportDate @hidden, count(tmb.Id) AS tmbAssignments, SUM(CASE WHEN a.projectName = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.TMB_PROJECT') THEN 1 ELSE 0 END) AS isTMBProject - - FROM ( - -- Find all distinct animals housed at the Center each day. - -- This is the first dataset to include all animals here, not just assigned animals. + FROM ( -- Find all distinct animals housed at the Center each day. This query is first to include all animals, not just assigned animals. SELECT h.Id, i.dateOnly, @@ -149,17 +136,11 @@ PerDiemsEquivByDayData AS ( LEFT JOIN study.treatment_Order t1 ON t1.id = h.id AND t1.code.meaning LIKE '%Bottle%' AND t1.date <= i.dateOnly GROUP BY h.Id, i.dateOnly ) i2 - JOIN study.demographics d ON ( i2.Id = d.Id ) - - -- Housing is a little tricky. Using the query above, we want to find the max start date, on or before this day. - -- The housingType from this location is used. JOIN study.housing h3 ON (h3.Id = i2.Id AND i2.lastHousingStart = h3.date AND h3.qcstate.publicdata = TRUE) - - -- Then join to any assignment record overlapping each day - LEFT JOIN ( + LEFT JOIN ( -- Then join to any assignment record overlapping each day SELECT a.lsid, a.id, @@ -176,18 +157,14 @@ PerDiemsEquivByDayData AS ( a.objectid FROM study.assignment a WHERE a.qcstate.publicdata = TRUE - -- NOTE: We don't exclude 1-day assignments or treat them differently. - -- AND a.duration > 0 - ) a ON ( + ) a ON ( -- NOTE: We don't exclude 1-day assignments or treat them differently. i2.Id = a.id AND a.dateOnly <= i2.dateOnly -- Assignments end at midnight, so an assignment doesn't count on the current date if it ends on it. -- However, we also include 1-day assignments, which *can* have the end date match the start date. AND (a.enddate IS NULL OR a.enddateCoalesced > i2.dateOnly OR (a.dateOnly = i2.dateOnly AND a.enddateCoalesced = i2.dateOnly)) ) - - LEFT JOIN ( - -- For each assignment, find the co-assigned projects on that day. + LEFT JOIN ( -- For each assignment, find the co-assigned projects on that day. SELECT a2.lsid, a2.date, @@ -209,16 +186,13 @@ PerDiemsEquivByDayData AS ( AND (a2.enddate IS NULL OR a2.enddateCoalesced > i2.dateOnly OR (a2.dateOnly = i2.dateOnly AND a2.enddateCoalesced = i2.dateOnly)) AND a.lsid != a2.lsid ) - - -- Find overlapping TMB on this date, which overrides the per diem. - LEFT JOIN study.assignment tmb ON ( + LEFT JOIN study.assignment tmb ON ( -- Find overlapping TMB on this date, which overrides the per diem. a.id = tmb.id AND tmb.dateOnly <= i2.dateOnly AND tmb.project != a.project AND tmb.endDateCoalesced >= i2.dateOnly AND tmb.project.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.TMB_PROJECT') ) - LEFT JOIN onprc_billing.perDiemFeeDefinition pdf ON ( pdf.housingType = h3.room.housingType AND pdf.housingDefinition = h3.room.housingCondition @@ -231,20 +205,19 @@ PerDiemsEquivByDayData AS ( 'Tier 2' ) = pdf.tier ) - GROUP BY i2.dateOnly, i2.Id, a.project, a.project.use_Category, i2.researchRecordCount, i2.bottleFedRecordCount ) t ) SELECT - REPORTDATE @title='Report Date', + REPORTDATE, r.area, r.room, r.housingType, coalesce(cld.cageSpots, 0) AS totalCageSpaces, coalesce(ahd.totalAnimals, 0) AS totalAnimals, coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, - coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed @title='% Used' + coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed FROM ehr_lookups.rooms r JOIN RoomStartData rsd ON rsd.room = r.room LEFT JOIN AnimalHousingData ahd ON ahd.room = r.room From ad5f72cf53763844429fcab4ea09708e1f713918 Mon Sep 17 00:00:00 2001 From: Brent Logan Date: Wed, 19 Nov 2025 12:56:06 -0800 Subject: [PATCH 03/10] Formatting changes --- .../ehr_lookups/roomUtilizationHistorical.sql | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 840ffcd70..47a2ff1fc 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -31,17 +31,15 @@ AnimalHousingData AS ( dateRange AS ( SELECT i.date, - CAST(i.date as date) as dateOnly, + CAST(i.date as DATE) as dateOnly, CAST(dayofyear(i.date) as INTEGER) as DayOfYear, CAST(dayofmonth(i.date) as INTEGER) as DayOfMonth, CAST(dayofweek(i.date) as INTEGER) as DayOfWeek, ceiling(CAST(dayofmonth(i.date) as FLOAT) / 7.0) as WeekOfMonth, CAST(week(i.date) as INTEGER) as WeekOfYear, CAST(REPORTDATE AS TIMESTAMP) as ReportDate - FROM ( - SELECT - timestampadd('SQL_TSI_DAY', i.value, CAST(coalesce(REPORTDATE, curdate()) AS TIMESTAMP)) as date + SELECT timestampadd('SQL_TSI_DAY', i.value, CAST(coalesce(REPORTDATE, curdate()) AS TIMESTAMP)) as date FROM ldk.integers i ) i WHERE i.date <= REPORTDATE @@ -136,9 +134,7 @@ PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsB LEFT JOIN study.treatment_Order t1 ON t1.id = h.id AND t1.code.meaning LIKE '%Bottle%' AND t1.date <= i.dateOnly GROUP BY h.Id, i.dateOnly ) i2 - JOIN study.demographics d ON ( - i2.Id = d.Id - ) + JOIN study.demographics d ON i2.Id = d.Id JOIN study.housing h3 ON (h3.Id = i2.Id AND i2.lastHousingStart = h3.date AND h3.qcstate.publicdata = TRUE) LEFT JOIN ( -- Then join to any assignment record overlapping each day SELECT @@ -175,8 +171,6 @@ PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsB a2.enddateCoalesced FROM study.assignment a2 WHERE a2.qcstate.publicdata = TRUE - -- NOTE: We don't exclude 1-day assignments or treat them differently. - -- AND a2.duration > 1 ) a2 ON ( i2.id = a2.id AND a2.dateOnly <= i2.dateOnly @@ -196,8 +190,7 @@ PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsB LEFT JOIN onprc_billing.perDiemFeeDefinition pdf ON ( pdf.housingType = h3.room.housingType AND pdf.housingDefinition = h3.room.housingCondition - -- Find overlapping tier flags on that day - AND coalesce( + AND coalesce( -- Find overlapping tier flags on that day (SELECT group_concat(DISTINCT f.flag.value) as tier FROM study.flags f --NOTE: allow flags that ended on this date @@ -219,16 +212,16 @@ SELECT coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed FROM ehr_lookups.rooms r - JOIN RoomStartData rsd ON rsd.room = r.room - LEFT JOIN AnimalHousingData ahd ON ahd.room = r.room - LEFT JOIN ( + JOIN RoomStartData rsd ON rsd.room = r.room + LEFT JOIN AnimalHousingData ahd ON ahd.room = r.room + LEFT JOIN ( SELECT pd.rooms, sum(pd.effectiveDays) AS perDiemsEquiv FROM PerDiemsEquivByDayData pd GROUP BY pd.rooms ) pd ON pd.rooms = r.room - LEFT JOIN CageLocationData cld ON cld.room = r.room + LEFT JOIN CageLocationData cld ON cld.room = r.room WHERE r.housingType = 205 -- Cage Location AND r.housingCondition != 490 -- Exclude none|NECROPSY AND REPORTDATE <= coalesce(r.dateDisabled, now()) From 933642593112735ae62d5d3976cef0fce65a01ad Mon Sep 17 00:00:00 2001 From: loganb Date: Thu, 20 Nov 2025 13:05:52 -0800 Subject: [PATCH 04/10] Formatting changes --- .../ehr_lookups/roomUtilizationHistorical.sql | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 47a2ff1fc..9ed8165e8 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -1,34 +1,30 @@ PARAMETERS(ReportDate TIMESTAMP) -/* Get starting date for each room */ -WITH RoomStartData AS ( +WITH RoomFirstUseData AS ( -- Include a room for report dates after a room's first use SELECT room, min(date) AS startingDate FROM study.housing GROUP BY room ), -/* Get total cage locations in each room */ -CageLocationData AS ( +CageCountData AS ( -- Count *current* cage locations in each room SELECT c.room, count(c.cage) AS cageSpots FROM ehr_lookups.cages c GROUP BY c.room ), -/* Get total animals housed in each room on the report date */ -AnimalHousingData AS ( +AnimalCountData AS ( -- Count animals in each room on the report date SELECT h.room, count(h.id) AS totalAnimals FROM study.housing h WHERE - coalesce( REPORTDATE , CAST('1900-01-01 00:00:00.0' as timestamp)) < coalesce(h.enddate, now()) + coalesce(REPORTDATE, CAST('1900-01-01 00:00:00.0' as timestamp)) < coalesce(h.enddate, now()) AND coalesce(REPORTDATE, now()) >= coalesce(h.date, now()) GROUP BY h.room ), -/* A modified version of ldk.dateRange with a single date parameter ReportDate */ -dateRange AS ( +dateRange AS ( -- A modified version of ldk.dateRange that uses a single date parameter: REPORTDATE SELECT i.date, CAST(i.date as DATE) as dateOnly, @@ -44,11 +40,11 @@ dateRange AS ( ) i WHERE i.date <= REPORTDATE ), -PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsByDay modified to use CTE dateRange, which uses only a single data parameter: ReportDate +PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that uses CTE dateRange and a single date parameter: REPORTDATE SELECT t.*, CASE - WHEN t.overlappingProjects IS NULL THEN 1 -- An assignment overlapping with TMB is not charged per diems. + WHEN t.overlappingProjects IS NULL THEN 1 -- An assignment overlapping with TMB is not charged per diems WHEN t.tmbAssignments > 0 then 0 WHEN t.assignedProject IS NULL AND t.overlappingProjects IS NOT NULL THEN 0 WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 0 @@ -153,7 +149,7 @@ PerDiemsEquivByDayData AS ( -- PerDiemsEquivByDayData is onprc_billing.perDiemsB a.objectid FROM study.assignment a WHERE a.qcstate.publicdata = TRUE - ) a ON ( -- NOTE: We don't exclude 1-day assignments or treat them differently. + ) a ON ( i2.Id = a.id AND a.dateOnly <= i2.dateOnly -- Assignments end at midnight, so an assignment doesn't count on the current date if it ends on it. @@ -208,21 +204,20 @@ SELECT r.room, r.housingType, coalesce(cld.cageSpots, 0) AS totalCageSpaces, - coalesce(ahd.totalAnimals, 0) AS totalAnimals, + coalesce(acd.totalAnimals, 0) AS totalAnimals, coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed FROM ehr_lookups.rooms r - JOIN RoomStartData rsd ON rsd.room = r.room - LEFT JOIN AnimalHousingData ahd ON ahd.room = r.room - LEFT JOIN ( - SELECT - pd.rooms, - sum(pd.effectiveDays) AS perDiemsEquiv - FROM PerDiemsEquivByDayData pd - GROUP BY pd.rooms - ) pd ON pd.rooms = r.room - LEFT JOIN CageLocationData cld ON cld.room = r.room -WHERE r.housingType = 205 -- Cage Location - AND r.housingCondition != 490 -- Exclude none|NECROPSY - AND REPORTDATE <= coalesce(r.dateDisabled, now()) - AND (coalesce(rsd.startingDate, now()) <= REPORTDATE OR rsd.startingDate IS NULL) \ No newline at end of file + +JOIN RoomFirstUseData rfud ON rfud.room = r.room -- rooms without a first use won't be included +LEFT JOIN AnimalCountData acd ON acd.room = r.room +LEFT JOIN ( + SELECT + pd.rooms, + sum(pd.effectiveDays) AS perDiemsEquiv + FROM PerDiemsEquivData pd + GROUP BY pd.rooms +) pd ON pd.rooms = r.room +LEFT JOIN CageCountData cld ON cld.room = r.room +WHERE REPORTDATE <= coalesce(r.dateDisabled, now()) + AND rfud.startingDate <= REPORTDATE \ No newline at end of file From 8f03f0931c8a16076e1112dac69c36bde97d4cd8 Mon Sep 17 00:00:00 2001 From: loganb Date: Thu, 20 Nov 2025 19:19:26 -0800 Subject: [PATCH 05/10] Formatting changes --- .../ehr_lookups/roomUtilizationHistorical.sql | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 9ed8165e8..e0e0ba2ce 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -1,20 +1,20 @@ PARAMETERS(ReportDate TIMESTAMP) -WITH RoomFirstUseData AS ( -- Include a room for report dates after a room's first use +WITH RoomFirstUseData AS ( -- Find first use of each room SELECT room, - min(date) AS startingDate + min(date) AS firstUseDate FROM study.housing GROUP BY room ), -CageCountData AS ( -- Count *current* cage locations in each room +CageSpaceCountData AS ( -- Count *current* cage spaces in each room SELECT c.room, - count(c.cage) AS cageSpots + count(c.cage) AS cageSpaces FROM ehr_lookups.cages c GROUP BY c.room ), -AnimalCountData AS ( -- Count animals in each room on the report date +AnimalCountData AS ( -- A modified version of study.HousingOverlapsReports that uses a single date parameter SELECT h.room, count(h.id) AS totalAnimals @@ -24,7 +24,7 @@ AnimalCountData AS ( -- Count animals in each room on the report date AND coalesce(REPORTDATE, now()) >= coalesce(h.date, now()) GROUP BY h.room ), -dateRange AS ( -- A modified version of ldk.dateRange that uses a single date parameter: REPORTDATE +dateRange AS ( -- A modified version of ldk.dateRange that uses a single date parameter SELECT i.date, CAST(i.date as DATE) as dateOnly, @@ -40,7 +40,7 @@ dateRange AS ( -- A modified version of ldk.dateRange that uses a single date pa ) i WHERE i.date <= REPORTDATE ), -PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that uses CTE dateRange and a single date parameter: REPORTDATE +PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that uses CTE dateRange and a single date parameter SELECT t.*, CASE @@ -203,13 +203,13 @@ SELECT r.area, r.room, r.housingType, - coalesce(cld.cageSpots, 0) AS totalCageSpaces, + coalesce(csc.cageSpaces, 0) AS totalCageSpaces, coalesce(acd.totalAnimals, 0) AS totalAnimals, coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, - coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(cld.cageSpots, 0), 0), 0) AS percentUsed + coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(csc.cageSpaces, 0), 0), 0) AS percentUsed FROM ehr_lookups.rooms r -JOIN RoomFirstUseData rfud ON rfud.room = r.room -- rooms without a first use won't be included +JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included LEFT JOIN AnimalCountData acd ON acd.room = r.room LEFT JOIN ( SELECT @@ -218,6 +218,6 @@ LEFT JOIN ( FROM PerDiemsEquivData pd GROUP BY pd.rooms ) pd ON pd.rooms = r.room -LEFT JOIN CageCountData cld ON cld.room = r.room +LEFT JOIN CageSpaceCountData csc ON csc.room = r.room WHERE REPORTDATE <= coalesce(r.dateDisabled, now()) - AND rfud.startingDate <= REPORTDATE \ No newline at end of file + AND rfu.firstUseDate <= REPORTDATE \ No newline at end of file From 5d3837e804714176b704534e41114ef853e9d046 Mon Sep 17 00:00:00 2001 From: loganb Date: Fri, 21 Nov 2025 15:19:46 -0800 Subject: [PATCH 06/10] Formatting changes --- .../resources/queries/ehr_lookups/roomUtilizationHistorical.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index e0e0ba2ce..62f004728 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -200,6 +200,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that SELECT REPORTDATE, + r.building, r.area, r.room, r.housingType, @@ -216,6 +217,7 @@ LEFT JOIN ( pd.rooms, sum(pd.effectiveDays) AS perDiemsEquiv FROM PerDiemsEquivData pd + WHERE pd. GROUP BY pd.rooms ) pd ON pd.rooms = r.room LEFT JOIN CageSpaceCountData csc ON csc.room = r.room From 24cefda1bdfc2c0383a8d673f005e3928a9242f3 Mon Sep 17 00:00:00 2001 From: loganb Date: Mon, 24 Nov 2025 15:17:53 -0800 Subject: [PATCH 07/10] Add projects to exclude --- .../roomUtilizationHistorical.query.xml | 5 +++++ .../ehr_lookups/roomUtilizationHistorical.sql | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml index 123b938f9..a3505c806 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml @@ -16,6 +16,11 @@ % Used 0.00% + + Project IDs + /query/ONPRC/EHR/executeQuery.view?schemaName=ehr&query.queryName=project&query.columns=project%2Cname%2Cprotocol%2Ctitle%2CinvestigatorId%2Cprotocol%2FinvestigatorId%2Caccount%2Caccount%2FfiscalAuthority%2Caccount%2FprojectNumber%2Cstartdate%2Cenddate%2Cuse_category%2Caccount%2FaliasType%2CactiveAssignments%2FactiveAssignments&query.sort=name&query.project~in=${projects} + _blank + diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 62f004728..75139e0dd 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -207,19 +207,21 @@ SELECT coalesce(csc.cageSpaces, 0) AS totalCageSpaces, coalesce(acd.totalAnimals, 0) AS totalAnimals, coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, - coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(csc.cageSpaces, 0), 0), 0) AS percentUsed + coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(csc.cageSpaces, 0), 0), 0) AS percentUsed, + pd.projects FROM ehr_lookups.rooms r -JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included -LEFT JOIN AnimalCountData acd ON acd.room = r.room -LEFT JOIN ( + JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included + LEFT JOIN AnimalCountData acd ON acd.room = r.room + LEFT JOIN ( SELECT pd.rooms, - sum(pd.effectiveDays) AS perDiemsEquiv + sum(pd.effectiveDays) AS perDiemsEquiv, + group_concat(DISTINCT pd.project, ';') as projects FROM PerDiemsEquivData pd - WHERE pd. + WHERE pd.project NOT IN (625, 1106, 2270) -- Exclude projectID for 0492, 0492-02, 0492-45 GROUP BY pd.rooms ) pd ON pd.rooms = r.room -LEFT JOIN CageSpaceCountData csc ON csc.room = r.room + LEFT JOIN CageSpaceCountData csc ON csc.room = r.room WHERE REPORTDATE <= coalesce(r.dateDisabled, now()) - AND rfu.firstUseDate <= REPORTDATE \ No newline at end of file + AND rfu.firstUseDate <= REPORTDATE \ No newline at end of file From d3c64c5eff65a68214476a50303b00a30da5ce8d Mon Sep 17 00:00:00 2001 From: loganb Date: Thu, 11 Dec 2025 21:54:16 -0800 Subject: [PATCH 08/10] Support list of excluded center project names --- .../roomUtilizationHistorical.query.xml | 2 +- .../ehr_lookups/roomUtilizationHistorical.sql | 64 ++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml index a3505c806..6c4d74fd0 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml @@ -18,7 +18,7 @@ Project IDs - /query/ONPRC/EHR/executeQuery.view?schemaName=ehr&query.queryName=project&query.columns=project%2Cname%2Cprotocol%2Ctitle%2CinvestigatorId%2Cprotocol%2FinvestigatorId%2Caccount%2Caccount%2FfiscalAuthority%2Caccount%2FprojectNumber%2Cstartdate%2Cenddate%2Cuse_category%2Caccount%2FaliasType%2CactiveAssignments%2FactiveAssignments&query.sort=name&query.project~in=${projects} + /query/ONPRC/EHR/executeQuery.view?schemaName=ehr&query.queryName=project&query.columns=project%2Cname%2Cprotocol%2Ctitle%2CinvestigatorId%2Cprotocol%2FinvestigatorId%2Caccount%2Caccount%2FfiscalAuthority%2Caccount%2FprojectNumber%2Cstartdate%2Cenddate%2Cuse_category%2Caccount%2FaliasType%2CactiveAssignments%2FactiveAssignments&query.sort=name&query.project~in=${projects} _blank diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 75139e0dd..4c31c7e52 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -3,7 +3,7 @@ PARAMETERS(ReportDate TIMESTAMP) WITH RoomFirstUseData AS ( -- Find first use of each room SELECT room, - min(date) AS firstUseDate + MIN(date) AS firstUseDate FROM study.housing GROUP BY room ), @@ -17,25 +17,25 @@ CageSpaceCountData AS ( -- Count *current* cage spaces in each room AnimalCountData AS ( -- A modified version of study.HousingOverlapsReports that uses a single date parameter SELECT h.room, - count(h.id) AS totalAnimals + COUNT(h.id) AS totalAnimals FROM study.housing h WHERE - coalesce(REPORTDATE, CAST('1900-01-01 00:00:00.0' as timestamp)) < coalesce(h.enddate, now()) - AND coalesce(REPORTDATE, now()) >= coalesce(h.date, now()) + COALESCE(REPORTDATE, CAST('1900-01-01 00:00:00.0' AS timestamp)) < COALESCE(h.enddate, now()) + AND COALESCE(REPORTDATE, now()) >= COALESCE(h.date, now()) GROUP BY h.room ), dateRange AS ( -- A modified version of ldk.dateRange that uses a single date parameter SELECT i.date, - CAST(i.date as DATE) as dateOnly, - CAST(dayofyear(i.date) as INTEGER) as DayOfYear, - CAST(dayofmonth(i.date) as INTEGER) as DayOfMonth, - CAST(dayofweek(i.date) as INTEGER) as DayOfWeek, - ceiling(CAST(dayofmonth(i.date) as FLOAT) / 7.0) as WeekOfMonth, - CAST(week(i.date) as INTEGER) as WeekOfYear, - CAST(REPORTDATE AS TIMESTAMP) as ReportDate + CAST(i.date AS DATE) AS dateOnly, + CAST(dayofyear(i.date) AS INTEGER) AS DayOfYear, + CAST(dayofmonth(i.date) AS INTEGER) AS DayOfMonth, + CAST(dayofweek(i.date) AS INTEGER) AS DayOfWeek, + ceiling(CAST(dayofmonth(i.date) AS FLOAT) / 7.0) AS WeekOfMonth, + CAST(week(i.date) AS INTEGER) AS WeekOfYear, + CAST(REPORTDATE AS TIMESTAMP) AS ReportDate FROM ( - SELECT timestampadd('SQL_TSI_DAY', i.value, CAST(coalesce(REPORTDATE, curdate()) AS TIMESTAMP)) as date + SELECT timestampadd('SQL_TSI_DAY', i.value, CAST(COALESCE(REPORTDATE, curdate()) AS TIMESTAMP)) AS date FROM ldk.integers i ) i WHERE i.date <= REPORTDATE @@ -44,8 +44,8 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that SELECT t.*, CASE - WHEN t.overlappingProjects IS NULL THEN 1 -- An assignment overlapping with TMB is not charged per diems - WHEN t.tmbAssignments > 0 then 0 + WHEN t.overlappingProjects IS NULL THEN 1 + WHEN t.tmbAssignments > 0 then 0 -- An assignment overlapping with TMB is not charged per diems WHEN t.assignedProject IS NULL AND t.overlappingProjects IS NOT NULL THEN 0 WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory LIKE '%Research%' THEN 0 WHEN t.ProjectType != 'Research' AND t.overlappingProjectsCategory NOT LIKE '%Research%' THEN (1.0 / NULLIF((t.totalOverlappingProjects + 1), 0)) @@ -75,7 +75,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that THEN (SELECT ci.rowid FROM onprc_billing_public.chargeableItems ci WHERE ci.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.QUARANTINE_PER_DIEM')) ELSE maxPdfChargeId -- Finally, defer to housing condition END as chargeId, - coalesce(( -- Find overlapping tier flags on that day + COALESCE(( -- Find overlapping tier flags on that day SELECT group_concat(DISTINCT f.flag.value) AS tier FROM study.flags f WHERE f.Id = t.Id AND f.enddateCoalesced >= t.dateOnly AND f.dateOnly <= t.dateOnly AND f.flag.category = 'Housing Tier' -- NOTE: allow flags that ended on this date @@ -85,7 +85,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that i2.Id, CAST(CAST(i2.dateOnly AS DATE) AS TIMESTAMP) AS DATE, i2.dateOnly @hidden, - coalesce(a.project, (SELECT p.project FROM ehr.project p WHERE p.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.BASE_GRANT_PROJECT'))) AS project, + COALESCE(a.project, (SELECT p.project FROM ehr.project p WHERE p.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.BASE_GRANT_PROJECT'))) AS project, a.project AS assignedProject, max(a.duration) AS duration, -- should only have 1 value, no so need to include in grouping max(timestampdiff('SQL_TSI_DAY', d.birth, i2.dateOnly)) AS ageAtTime, @@ -93,7 +93,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that count(*) AS totalAssignmentRecords, group_concat(DISTINCT a2.project.displayName) AS overlappingProjects, count(DISTINCT a2.project) AS totalOverlappingProjects, - sum(CASE WHEN a2.project.use_Category = 'Research' THEN 1 ELSE 0 END) as totalOverlappingResearchProjects, + sum(CASE WHEN a2.project.use_Category = 'Research' THEN 1 ELSE 0 END) AS totalOverlappingResearchProjects, group_concat(DISTINCT a2.project.use_category) AS overlappingProjectsCategory, group_concat(DISTINCT a2.project.protocol) AS overlappingProtocols, count(h3.room) AS totalHousingRecords, @@ -122,8 +122,8 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that i.dateOnly, max(h.date) AS lastHousingStart, min(i.ReportDate) AS ReportDate @hidden, - count(a3.project) as researchRecordCount, - count(t1.code) as bottleFedRecordCount + count(a3.project) AS researchRecordCount, + count(t1.code) AS bottleFedRecordCount FROM dateRange i JOIN study.housing h ON (h.dateOnly <= i.dateOnly AND h.enddateCoalesced >= i.dateOnly AND h.qcstate.publicdata = TRUE) LEFT JOIN study.assignment a3 ON a3.id = h.id AND a3.date <= i.dateOnly AND a3.endDateCoalesced > i.dateOnly AND a3.project.Use_Category LIKE '%Research%' @@ -186,7 +186,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that LEFT JOIN onprc_billing.perDiemFeeDefinition pdf ON ( pdf.housingType = h3.room.housingType AND pdf.housingDefinition = h3.room.housingCondition - AND coalesce( -- Find overlapping tier flags on that day + AND COALESCE( -- Find overlapping tier flags on that day (SELECT group_concat(DISTINCT f.flag.value) as tier FROM study.flags f --NOTE: allow flags that ended on this date @@ -204,24 +204,30 @@ SELECT r.area, r.room, r.housingType, - coalesce(csc.cageSpaces, 0) AS totalCageSpaces, - coalesce(acd.totalAnimals, 0) AS totalAnimals, - coalesce(pd.perDiemsEquiv, 0) AS perDiemsEquiv, - coalesce(coalesce(pd.perDiemsEquiv, 0) / NULLIF(coalesce(csc.cageSpaces, 0), 0), 0) AS percentUsed, + COALESCE(csc.cageSpaces, 0) AS totalCageSpaces, + COALESCE(acd.totalAnimals, 0) AS totalAnimals, + COALESCE(pd.perDiemsEquiv, 0) AS perDiemsEquiv, + COALESCE(COALESCE(pd.perDiemsEquiv, 0) / NULLIF(COALESCE(csc.cageSpaces, 0), 0), 0) AS percentUsed, pd.projects FROM ehr_lookups.rooms r - JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included - LEFT JOIN AnimalCountData acd ON acd.room = r.room - LEFT JOIN ( +JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included +LEFT JOIN AnimalCountData acd ON acd.room = r.room +LEFT JOIN ( SELECT pd.rooms, sum(pd.effectiveDays) AS perDiemsEquiv, group_concat(DISTINCT pd.project, ';') as projects FROM PerDiemsEquivData pd - WHERE pd.project NOT IN (625, 1106, 2270) -- Exclude projectID for 0492, 0492-02, 0492-45 +-- WHERE pd.project NOT IN (625, 1106, 2270) -- Exclude projectID for 0492, 0492-02, 0492-45 + WHERE pd.project NOT IN ( + SELECT + p.project + FROM ehr.project p + JOIN lists.roomUtilizationHistoricalExcludedProjects ep ON ep.name = p.name + ) GROUP BY pd.rooms ) pd ON pd.rooms = r.room LEFT JOIN CageSpaceCountData csc ON csc.room = r.room -WHERE REPORTDATE <= coalesce(r.dateDisabled, now()) +WHERE REPORTDATE <= COALESCE(r.dateDisabled, now()) AND rfu.firstUseDate <= REPORTDATE \ No newline at end of file From bbf31854ba3f38a7963af720f7d46dc6ed980e91 Mon Sep 17 00:00:00 2001 From: loganb Date: Fri, 12 Dec 2025 08:09:15 -0800 Subject: [PATCH 09/10] Disable script --- .../dbscripts/sqlserver/onprc_ehr-25.003-25.003.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.003-25.003.sql diff --git a/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.003-25.003.sql b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.003-25.003.sql new file mode 100644 index 000000000..4430ac397 --- /dev/null +++ b/onprc_ehr/resources/schemas/dbscripts/sqlserver/onprc_ehr-25.003-25.003.sql @@ -0,0 +1,8 @@ +CREATE TABLE ehr_lookups.roomUtilizationHistoricalExcludedProjects ( + rowid [int] IDENTITY(100,1) NOT NULL, + name nvarchar(200), + + CONSTRAINT PK_EHR_LOOKUPS_ROOMTUILIZATIONHISTORYICALEXCLUDEDPROJECTS PRIMARY KEY (rowid), + +); +GO From fd7a068085c7e235d79479100259889aaf3243fe Mon Sep 17 00:00:00 2001 From: loganb Date: Sat, 20 Dec 2025 21:00:41 -0800 Subject: [PATCH 10/10] Add project.name to query --- .../ehr_lookups/roomUtilizationHistorical.query.xml | 4 ++-- .../queries/ehr_lookups/roomUtilizationHistorical.sql | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml index 6c4d74fd0..6daea2a97 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.query.xml @@ -16,8 +16,8 @@ % Used 0.00% - - Project IDs + + Center Project /query/ONPRC/EHR/executeQuery.view?schemaName=ehr&query.queryName=project&query.columns=project%2Cname%2Cprotocol%2Ctitle%2CinvestigatorId%2Cprotocol%2FinvestigatorId%2Caccount%2Caccount%2FfiscalAuthority%2Caccount%2FprojectNumber%2Cstartdate%2Cenddate%2Cuse_category%2Caccount%2FaliasType%2CactiveAssignments%2FactiveAssignments&query.sort=name&query.project~in=${projects} _blank diff --git a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql index 4c31c7e52..44989941f 100644 --- a/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql +++ b/onprc_ehr/resources/queries/ehr_lookups/roomUtilizationHistorical.sql @@ -86,6 +86,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that CAST(CAST(i2.dateOnly AS DATE) AS TIMESTAMP) AS DATE, i2.dateOnly @hidden, COALESCE(a.project, (SELECT p.project FROM ehr.project p WHERE p.name = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.BASE_GRANT_PROJECT'))) AS project, + a.projectName, a.project AS assignedProject, max(a.duration) AS duration, -- should only have 1 value, no so need to include in grouping max(timestampdiff('SQL_TSI_DAY', d.birth, i2.dateOnly)) AS ageAtTime, @@ -194,7 +195,7 @@ PerDiemsEquivData AS ( -- A modified version of onprc_billing.perDiemsByDay that 'Tier 2' ) = pdf.tier ) - GROUP BY i2.dateOnly, i2.Id, a.project, a.project.use_Category, i2.researchRecordCount, i2.bottleFedRecordCount + GROUP BY i2.dateOnly, i2.Id, a.project, a.projectName, a.project.use_Category, i2.researchRecordCount, i2.bottleFedRecordCount ) t ) @@ -207,8 +208,9 @@ SELECT COALESCE(csc.cageSpaces, 0) AS totalCageSpaces, COALESCE(acd.totalAnimals, 0) AS totalAnimals, COALESCE(pd.perDiemsEquiv, 0) AS perDiemsEquiv, - COALESCE(COALESCE(pd.perDiemsEquiv, 0) / NULLIF(COALESCE(csc.cageSpaces, 0), 0), 0) AS percentUsed, - pd.projects + COALESCE(COALESCE(pd.perDiemsEquiv, 0) / NULLIF(COALESCE(csc.cageSpaces*0.85, 0), 0), 0) AS percentUsed, -- 15% flex + pd.projects, + pd.projectNames FROM ehr_lookups.rooms r JOIN RoomFirstUseData rfu ON rfu.room = r.room -- rooms without a first use won't be included @@ -217,7 +219,8 @@ LEFT JOIN ( SELECT pd.rooms, sum(pd.effectiveDays) AS perDiemsEquiv, - group_concat(DISTINCT pd.project, ';') as projects + group_concat(DISTINCT pd.project, ';') as projects, + group_concat(DISTINCT pd.projectName, ', ') as projectNames FROM PerDiemsEquivData pd -- WHERE pd.project NOT IN (625, 1106, 2270) -- Exclude projectID for 0492, 0492-02, 0492-45 WHERE pd.project NOT IN (