From e31e32bcfa6e17a02d3b1de1f23475924d3ec27c Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Fri, 6 Sep 2024 14:19:04 -0500 Subject: [PATCH 01/13] Add blood graph along with queries to support it, as well as new column for blood avail including thirty days in the future --- .../BloodSchedule/Blood Schedule.qview.xml | 1 + .../queries/study/Current Blood.query.xml | 3 + .../resources/queries/study/Current Blood.sql | 18 +- .../queries/study/Current Blood/.qview.xml | 2 + .../queries/study/bloodDrawChanges.sql | 66 ++ .../queries/study/bloodSummary.query.xml | 3 + .../resources/queries/study/bloodSummary.sql | 39 +- .../queries/study/currentBloodDraws.sql | 85 +++ .../web/wnprc_ehr/panel/BloodSummaryPanel.js | 570 ++++++++++++++++++ .../resources/web/wnprc_ehr/wnprcReports.js | 30 + .../org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 1 + 11 files changed, 781 insertions(+), 37 deletions(-) create mode 100644 WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql create mode 100644 WNPRC_EHR/resources/queries/study/currentBloodDraws.sql create mode 100644 WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js diff --git a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml index a889616dc..04e7ac58e 100644 --- a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml +++ b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml @@ -56,6 +56,7 @@ + diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml index a37953f2a..f5116e3eb 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml @@ -62,6 +62,9 @@ Volume Remaining After Draw (mL) + + /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + BloodLast30 diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.sql b/WNPRC_EHR/resources/queries/study/Current Blood.sql index 6187c80ed..54195ace4 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.sql +++ b/WNPRC_EHR/resources/queries/study/Current Blood.sql @@ -5,23 +5,14 @@ */ SELECT bq.*, - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round(bq.weight*0.15*60, 1) - ELSE - round(bq.weight*0.2*60, 1) - END as numeric) AS MaxBlood, - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round((bq.weight*0.15*60) - bq.BloodLast30, 1) - ELSE - round((bq.weight*0.2*60) - bq.BloodLast30, 1) - END AS numeric) AS AvailBlood + cast(round(bq.weight*species.max_draw_pct*species.blood_per_kg, 1) as numeric) AS MaxBlood, + cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - bq.BloodLast30, 1) AS numeric) AS AvailBlood, + cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - (bq.BloodLast30 + bq.BloodNext30), 1) AS numeric) AS BloodAvailPlusThirty FROM ( SELECT b.*, - (select species from study.demographics d where d.id = b.id) as species, + (d.species) as species, ( CONVERT ( (SELECT AVG(w.weight) AS _expr @@ -109,5 +100,6 @@ FROM --WHERE b.id.status.status = 'Alive' ) bi ) b + JOIN study.demographics d ON d.id=b.id ) bq diff --git a/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml b/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml index 33013bb26..f75cd0a18 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml @@ -23,6 +23,8 @@ + + diff --git a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql new file mode 100644 index 000000000..d358fe95e --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql @@ -0,0 +1,66 @@ +/* + * Copyright (c) 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. + */ +--this query is designed to return any dates when allowable blood draw volume changes +--this includes dates of blood draws, plus the date those draws drop off +PARAMETERS(DATE_INTERVAL INTEGER) + +SELECT + b2.id, + b2.dateOnly, + b2.quantity, + DATE_INTERVAL as blood_draw_interval, + TIMESTAMPADD('SQL_TSI_DAY', (-1 * DATE_INTERVAL), b2.dateOnly) as minDate, + TIMESTAMPADD('SQL_TSI_DAY', DATE_INTERVAL, b2.dateOnly) as maxDate, + +FROM ( + SELECT + b.id, + b.dateOnly, + sum(b.quantity) as quantity + + FROM ( + --find all blood draws within the interval, looking backwards + SELECT + b.id, + b.dateOnly, + b.quantity, + FROM study.blood b + WHERE b.dateOnly > timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) AND b.project.research = TRUE + + UNION ALL + + --join 1 row for the current date + SELECT + d1.id, + curdate() as dateOnly, + 0 as quantity, + FROM study.demographics d1 + WHERE d1.calculated_status = 'Alive' + + UNION ALL + + --add one row for each date when the draw drops off the record + SELECT + b.id, + timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly), + 0 as quantity, + FROM study.blood b + WHERE timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly) >= timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) AND b.project.research = TRUE + + ) b + + GROUP BY b.id, b.dateOnly +) b2 \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml index b8a667e34..7d3c1c2a2 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml @@ -28,6 +28,9 @@ query.sort=-Date& + + /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + BloodLast30 diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql index 29754e3f8..c38ff59ff 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.sql +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.sql @@ -12,26 +12,15 @@ SELECT bq.weight, bq.lastWeighDate, cast(bq.BloodLast30 as numeric) as BloodLast30, --- bq.BloodNext30, --- round(bq.weight*0.2*60, 1) AS MaxBlood, --- round((bq.weight*0.2*60) - bq.BloodLast30, 1) AS AvailBlood - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round(bq.weight*0.15*60, 1) - ELSE - round(bq.weight*0.2*60, 1) - END as numeric) AS MaxBlood, - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round((bq.weight*0.15*60) - bq.BloodLast30, 1) - ELSE - round((bq.weight*0.2*60) - bq.BloodLast30, 1) - END AS numeric) AS AvailBlood + bq.BloodNext30, + cast(round(bq.weight*species.max_draw_pct*species.blood_per_kg, 1) as numeric) AS MaxBlood, + cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - bq.BloodLast30, 1) AS numeric) AS AvailBlood, + cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - (bq.BloodLast30 + bq.BloodNext30), 1) AS numeric) AS BloodAvailNowPlusThirtyDays FROM ( SELECT b.*, - (select species from study.demographics d where d.id = b.id) as species, + (d.species) as species, ( CONVERT ( (SELECT AVG(w.weight) AS _expr @@ -65,16 +54,18 @@ FROM --AND draws.qcstate.publicdata = true ), 0 ) ) AS BloodLast30 --- , ( COALESCE ( --- (SELECT SUM(draws.quantity) AS _expr --- FROM study."Blood Draws" draws --- WHERE draws.id=bi.id --- AND draws.date BETWEEN TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) AND bi.date --- AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) --- ), 0 ) --- ) AS BloodNext30 + , ( COALESCE ( + (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id=bi.id + AND (cast(draws.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) as date) AND cast(draws.date as date) <= cast(bi.date as date)) + AND cast(draws.date as date) >= bi.date + AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) + ), 0 ) + ) AS BloodNext30 FROM study.blood bi --WHERE (bi.qcstate.metadata.DraftData = true OR bi.qcstate.publicdata = true) ) b + JOIN study.demographics d ON d.id=b.id ) bq diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql new file mode 100644 index 000000000..feda25ea5 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +SELECT + t.id, + t.date, + cast(t.quantity as double) as quantity, + t.species, + t.max_draw_pct, + t.blood_draw_interval, + t.blood_per_kg, + t.mostRecentWeight, + t.mostRecentWeightDate, + t.death, + cast(t.allowableBlood as double) as maxAllowableBlood, + cast(t.bloodPrevious as double) as bloodPrevious, + cast((t.allowableBlood - t.bloodPrevious) as double) as allowablePrevious, + + cast(t.bloodFuture as double) as bloodFuture, + cast((t.allowableBlood - t.bloodFuture) as double) as allowableFuture, + + --if the draw is historic, always consider previous draws only. + --otherwise, look both forward and backwards, then take the interval with the highest volume + cast(case + WHEN t.date < curdate() THEN (t.allowableBlood - t.bloodPrevious) + WHEN t.bloodPrevious < t.bloodFuture THEN (t.allowableBlood - t.bloodFuture) + ELSE (t.allowableBlood - t.bloodPrevious) + end as double) as allowableBlood, + t.minDate, + t.maxDate + +FROM ( + +SELECT + bd.id, + bd.dateOnly as date, + bd.quantity, + d.species, + d.death, + d.id.mostRecentWeight.MostRecentWeight, + d.id.mostRecentWeight.MostRecentWeightDate, + d.species.blood_per_kg, + d.species.max_draw_pct, + bd.blood_draw_interval, +(d.id.mostRecentWeight.MostRecentWeight * d.species.blood_per_kg * d.species.max_draw_pct) + as allowableBlood, + bd.minDate, + bd.maxDate, + COALESCE( + (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id = bd.id AND draws.project.research = true + AND draws.dateOnly > bd.minDate + AND draws.dateOnly <= bd.dateOnly + --NOTE: this has been changed to include pending/non-approved draws + AND draws.countsAgainstVolume = true + ), 0) AS BloodPrevious, + + COALESCE( + (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id = bd.id AND draws.project.research = true + AND draws.dateOnly < bd.maxDate + AND draws.dateOnly >= bd.dateOnly + --NOTE: this has been changed to include pending/non-approved draws + AND draws.countsAgainstVolume = true + ), 0) AS BloodFuture + +FROM study.bloodDrawChanges bd +JOIN study.demographics d ON (d.id = bd.id) + +) t \ No newline at end of file diff --git a/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js b/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js new file mode 100644 index 000000000..c4c298ee8 --- /dev/null +++ b/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2016-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +/* + * Title: BloodSummaryPanel + * Description: This will generate the blood report plot for each subject ID passed in. Provides a hook to add + * additional items in the report. + * Config: { + * subjects: Array of animal IDs, + * getSubjectItems(optional): Function returning an array of items to add for each subject ID after the plot + * } + */ + +Ext4.define('WNPRC.panel.BloodSummaryPanel', { + extend: 'Ext.panel.Panel', + alias: 'widget.wnprc-bloodsummarypanel', + intervals: {}, + plotHeight: 400, + + bloodPerKgCol: 'species/blood_per_kg', + bloodMaxDrawPctCol: 'species/max_draw_pct', + bloodDrawIntervalCol: 'species/blood_draw_interval', + + initComponent: function(){ + Ext4.apply(this, { + border: false, + defaults: { + border: false + }, + items: [{ + html: 'Loading...' + }] + }); + + this.callParent(); + + if(!Ext4.isDefined(this.subjects) || !Ext4.isArray(this.subjects)) + console.log("Must pass in an array of animal IDs as subjects.") + else + this.loadData(); + }, + + loadData: function(){ + var demoCols = 'id,species,id/MostRecentWeight/mostRecentWeight,id/MostRecentWeight/mostRecentWeightDate,Id/demographics/calculated_status,Id/demographics/calculated_status/meaning' + + ',' + this.bloodPerKgCol + ',' + this.bloodMaxDrawPctCol + ',' + this.bloodDrawIntervalCol; + + LABKEY.Query.selectRows({ + schemaName: 'study', + queryName: 'demographics', + filterArray: [LABKEY.Filter.create('id', this.subjects.join(';'), LABKEY.Filter.Types.EQUALS_ONE_OF)], + columns: demoCols, + requiredVersion: 9.1, + sort: 'id', + scope: this, + failure: LDK.Utils.getErrorCallback(), + success: function(results){ + this.demographicsMap = {}; + this.intervals = {}; + + Ext4.each(results.rows, function(row){ + var map = new LDK.SelectRowsRow(row); + var interval = row[this.bloodDrawIntervalCol].value; + this.demographicsMap[map.getValue('id')] = map; + + if(!interval) { + interval = 42; + } + if( this.intervals.hasOwnProperty(interval) ) { + this.intervals[interval].push(row.Id.value) + } else { + this.intervals[interval] = [row.Id.value]; + } + + }, this); + + this.loadBloodData(); + } + }); + }, + + loadBloodData: function() { + var multi = new LABKEY.MultiRequest(); + + for(var interval in this.intervals) { + if (this.intervals.hasOwnProperty(interval)) { + + multi.add(LABKEY.Ajax.request, { + url: LABKEY.ActionURL.buildURL("ehr", "bloodPlotData"), + params: { + ids: this.intervals[interval], + interval: interval + }, + method : 'POST', + requiredVersion: 9.1, + scope: this, + failure: LDK.Utils.getErrorCallback(), + success: function (response) + { + var results = JSON.parse(response.responseText); + console.log(results); + + var meta = results.metaData.fields; + for(var i = 0; i dDate) { + return; + } + } + //End TODO + if (rDate && Ext4.Date.format(rDate, LABKEY.extDefaultDateFormat) == Ext4.Date.format(new Date(), LABKEY.extDefaultDateFormat)) { + row.isToday = {value: true}; + } + } + + if (!this.currentBloodMap[id]) + this.currentBloodMap[id] = []; + + this.currentBloodMap[id].push(row); + }, this); + + if(this.bloodDrawResults) { + this.bloodDrawResults.rows = this.bloodDrawResults.rows.concat(results.rows); + } else { + this.bloodDrawResults = results; + } + } + }); + } + } + + multi.send(this.onLoad, this); + }, + + onLoad: function(results){ + var toAdd = []; + Ext4.each(this.subjects, function(subject){ + var dd = this.demographicsMap[subject]; + var bds = this.currentBloodMap[subject]; + + var cfg = { + xtype: 'ldk-webpartpanel', + style: 'margin-bottom: 20px;', + title: 'Blood Summary: ' + subject, + defaults: { + border: false + }, + items: [] + }; + + if (!dd){ + cfg.items.push({ + html: 'Either species or weight information is missing for this animal' + }); + } + else { + var status = dd.getValue('Id/demographics/calculated_status/meaning') || dd.getValue('Id/demographics/calculated_status'); + cfg.items.push({ + html: 'Id: ' + dd.getValue('Id') + (status ? ' (' + status + ')' : '') + '' + }); + + cfg.items.push({ + html: '
' + }); + + if(status != null && status.toLowerCase() === "dead") { + cfg.items.push({ + html: 'No current blood draw information for dead animal.', + border: false + }); + } + else if (!bds || bds.length === 1) { + var maxDraw = dd.getValue(this.bloodPerKgCol) * dd.getValue(this.bloodMaxDrawPctCol) * dd.getValue('id/MostRecentWeight/mostRecentWeight'); + cfg.items.push({ + html: 'There are no previous blood draws within the relevant time frame. A maximum amount of ' + Ext4.util.Format.round(maxDraw, 2) + ' mL can be drawn.', + border: false + }); + } + else { + cfg.items = cfg.items.concat(this.getGraphCfg(dd, bds)); + } + } + + toAdd.push(cfg); + }, this); + + this.removeAll(); + if (toAdd.length){ + this.add(toAdd); + } + else { + this.add({ + html: 'No records found' + }); + } + + this.addAdditionalGraphOptions(); + }, + + addAdditionalGraphOptions: function() { + var svgs = d3.selectAll('svg'); + var patternHeight = 8; + + // Add shading pattern + var defs = svgs.selectAll('defs') + .append('pattern') + .attr('id', 'diag-pattern') + .attr('patternUnits', 'userSpaceOnUse') + .attr('x', 0) + .attr('y', 0) + .attr('width', 3) + .attr('height', patternHeight) + .attr('patternTransform', 'rotate(30)') + .append('rect') + .attr('x', 0) + .attr('y', 0) + .attr('width',.5) + .attr('height', patternHeight) + .attr('style', 'stroke:none;') + .attr('fill', 'red'); + + + // Add under zero shading + Ext4.each(svgs[0], function(svg) { + var ticks = svg.getElementsByClassName('axis')[1].getElementsByClassName('tick-text')[0].getElementsByTagName('g'); + Ext4.each(ticks, function(tick) { + if(tick.getElementsByTagName('text')[0].textContent === '0') { + var axis = d3.select(tick.parentElement.parentElement); + var tickText = d3.select(tick.parentElement); + axis.append('rect') + .attr('x', tick.getBBox().x + 16) + .attr('y', tick.getBBox().y + 11) + .attr('width', axis[0][0].getBBox().width - tickText[0][0].getBBox().width - 10) + .attr('height', this.plotHeight - tick.getBBox().y - 60) + .attr('fill-opacity',.5) + .attr('fill', 'url(#diag-pattern)'); + } + },this) + },this); + + var points = d3.selectAll('a.point'); + var todayPoints = points.filter(function(d) { + return (d.isToday && d.isToday == true); + }); + + // Add Today line and text + todayPoints.append(function(d,i) { + + // Hijack the loop to setup line + var yAxis = d3.selectAll('svg').select('g.grid-line path')[0][i]; + var path = yAxis.getAttribute('d'); + var bottom = Number(path.substring(path.indexOf(',')+1, path.indexOf('L'))); + var top = Number(path.substring(path.indexOf(',', path.indexOf(',')+1)+1, path.indexOf('Z'))); + var ht = bottom - top; + this.getElementsByTagName('path')[0] + .setAttribute('d', "M0 " + (ht + 68 - this.getBBox().y) + " l0 -" + (ht-1)); + + var text = document.createElementNS(d3.ns.prefix.svg, 'text'); + text.setAttribute("x", this.getBBox().x - 18); + text.setAttribute("y", this.getBBox().y - 3); + text.setAttribute("style", "font-weight:bold;font-family:Arial;font-size:11px;"); + text.setAttribute("fill", "black"); + text.setAttribute("visibility", "visible"); + text.textContent = "Today"; + + return text; + }); + }, + getMaxBloodAvailValue: function(rows){ + + var allowableBloodVals = []; + for (var i = 0; i < rows.length; i++){ + allowableBloodVals.push(rows[i].allowableDisplay.value); + } + + return Math.round(allowableBloodVals.reduce((a, b) => Math.max(a, b), -Infinity)) + 10; + }, + + getTickValues: function(rows){ + var ticks = [], msPerDay = 86400000, totalTicks = 10; + var minDate = Date.parse(rows[0].date.value); + var minDateGmt = Date.parse(rows[0].date.value.concat(" GMT")); + var maxDate = Date.parse(rows[rows.length - 1].date.value); + var diff = maxDate - minDate; + var daysTotal = diff/msPerDay; + var daysPerTick = Math.ceil(daysTotal/totalTicks); + var newTotal = Math.ceil(daysTotal/daysPerTick); + + ticks[0] = (Math.ceil(minDate/msPerDay) * msPerDay) + - (msPerDay - (minDate - minDateGmt)); // Offset timezone + for(var i=1; iTotal volume of blood collected in the past ' + currentRow.blood_draw_interval.value + ' days: ' + + Ext4.util.Format.round(currentRow.bloodPrevious.value, 1) + ' mL. ' + + 'The amount of blood available if drawn today is: ' + Ext4.util.Format.round(currentRow.allowableDisplay.value, 1) + ' mL.

' + + '

The graph below shows how the amount of blood available will change over time, including when previous draws will drop off. Hover over the timepoints for more information.

', + border: false, + style: 'margin-bottom: 20px' + }); + } + + var layerName = "Volume"; + toAdd.push({ + xtype: 'container', + items: [{ + xtype: 'ldk-graphpanel', + margin: '0 0 0 0', + plotConfig: { + results: results, + title: 'Blood Available To Be Drawn: ' + subject, + height: this.plotHeight, + width: this.getWidth() - 50, + yLabel: 'Available Blood (mL)', + xLabel: 'Date', + xField: 'date', + grouping: ['seriesId'], + scales: { + shape: { + scaleType: 'discrete', + range: [LABKEY.vis.Scale.Shape()[1], LABKEY.vis.Scale.Shape()[0], + LABKEY.vis.Scale.Shape()[4], LABKEY.vis.Scale.Shape()[0]], + domain: ["0 " + layerName, "1 " + layerName, "2 " + layerName, "3 " + layerName] + }, + color: { + scaleType: 'discrete', + range: [LABKEY.vis.Scale.ColorDiscrete()[1], LABKEY.vis.Scale.ColorDiscrete()[0], "#2fad24", "red", "black"], + domain: ["0 " + layerName, "1 " + layerName, "2 " + layerName, "3 " + layerName] + } + , + size: { + scaleType: 'discrete', + range: [5, 7], + domain: ["0 " + layerName, "1 " + layerName] + }, + x: { + tickValues: this.getTickValues(results.rows) + }, + y: { + domain: [0, this.getMaxBloodAvailValue(results.rows)], + } + }, + layers: [{ + y: 'allowableBlood', + hoverText: function(row){ + var lines = []; + + if(row.isDeath) { + lines.push('DEATH'); + } + lines.push('Date: ' + Ext4.Date.format(row.date, LABKEY.extDefaultDateFormat)); + lines.push('Drawn on this Date: ' + row.quantity); + lines.push('Volume Available on this Date: ' + LABKEY.Utils.roundNumber(row.allowableDisplay, 1) + ' mL'); + + lines.push('Current Weight: ' + row.mostRecentWeight + ' kg (' + Ext4.Date.format(row.mostRecentWeightDate, LABKEY.extDefaultDateFormat) + ')'); + + lines.push('Drawn in Previous ' + row.blood_draw_interval + ' days: ' + LABKEY.Utils.roundNumber(row.bloodPrevious, 1)); + + if (new Date(row.date) < new Date() && !row.isToday) + lines.push('Drawn in Next ' + row.blood_draw_interval + ' days: ' + LABKEY.Utils.roundNumber(row.bloodFuture, 1)); + + + return lines.join('\n'); + }, + name: layerName + }] + }, + getPlotConfig: function(){ + var cfg = LDK.panel.GraphPanel.prototype.getPlotConfig.call(this); + cfg.legendData = [ + { + color:'#FC8D62', + text:'Scheduled Blood Draw Status', + shape: LABKEY.vis.Scale.Shape()[1] + }, + { + color:'#66C2A5', + text:'Non-scheduled Blood Draw Status', + shape: LABKEY.vis.Scale.Shape()[0] + } + ] + cfg.aes.color = null; + cfg.aes.shape = null; + + return cfg; + }, + + //@Override + appendLayer: function(plot, layerConfig){ + var meta = this.findMetadata(layerConfig.y); + plot.addLayer(new LABKEY.vis.Layer({ + geom: new LABKEY.vis.Geom.Point({size: 5}), + name: layerConfig.name || meta.caption, + aes: { + y: function(row){ + if (row.isHidden) + return null; + + return row[layerConfig.y] + }, + hoverText: layerConfig.hoverText, + shape: function(row){ + if(row.isDeath) + return 2; + if(row.isToday) + return 3; + if(row.quantity > 0) { + return 0; + } + return 1; + }, + color: function(row){ + if(row.isToday) + return 4; + if(row.isDeath) + return 4; + + if(row.quantity > 0) { + return 0; + } + + return 1; + }, + size: function(row) { + if(row.isToday) + return 1; + if(row.isDeath) + return 1; + + return 0; + } + } + })); + + //now add segments. this is an odd way to accomplish grouping, but + //otherwise Vis will give each segment a different color + Ext4.each(seriesIds, function(seriesId){ + plot.addLayer(new LABKEY.vis.Layer({ + geom: new LABKEY.vis.Geom.Path({size: 5, opacity: 2}), + name: layerConfig.name || meta.caption, + aes: { + y: function(row){ + if (row.seriesId != seriesId) + return null; + + return row[layerConfig.y]; + }, + group: 'none' + } + })); + }, this); + } + }] + }); + + // If defined, add additional items below plot + if(Ext4.isDefined(this.getSubjectItems) && Ext4.isFunction(this.getSubjectItems)) { + toAdd = toAdd.concat(this.getSubjectItems(subject, dd)); + } + else if(Ext4.isDefined(this.getSubjectItems) && !Ext4.isFunction(this.getSubjectItems)) { + console.log("getSubjectItems must be a function returning an array of items to append after the plot") + } + + + return toAdd; + } + + +}); \ No newline at end of file diff --git a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js index b9e718175..003e278f0 100644 --- a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js +++ b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js @@ -1247,6 +1247,36 @@ EHR.reports['abstract'] = function(panel, tab){ EHR.reports.weightGraph(panel, tab); }; +EHR.reports.BloodSummary = function(panel, tab){ + var filterArray = panel.getFilterArray(tab); + var title = panel.getTitleSuffix(); + + tab.add({ + html: 'This report summarizes the blood available for the animals below. ' + + '

If there have been recent blood draws for the animal, a graph will show the available blood over time. On the graph, dots indicate dates when either blood was drawn or a previous blood draw fell off. The horizontal lines indicate the maximum allowable blood that can be drawn on that date.', + border: false, + style: 'padding-bottom: 20px;' + }); + + var subjects = tab.filters.subjects || []; + + if (subjects.length){ + tab.add({ + xtype: 'wnprc-bloodsummarypanel', + subjects: subjects + }); + } + else + { + panel.resolveSubjectsFromHousing(tab, function(subjects, tab){ + tab.add({ + xtype: 'wnprc-bloodsummarypanel', + subjects: subjects + }); + }, this); + } +}; + (function() { var abstractReport = EHR.reports['abstract']; diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java index 215aac420..e9bb96249 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java @@ -233,6 +233,7 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/AfternoonTreatmentsReport.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/EveningTreatmentsReport.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/MasterTreatmentsReport.js"), this); + EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/panel/BloodSummaryPanel.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/Inroom.js"), this); EHRService.get().registerReportLink(EHRService.REPORT_LINK_TYPE.housing, "List Single-housed Animals", this, DetailsURL.fromString("/query/executeQuery.view?schemaName=study&query.queryName=Demographics&query.viewName=Single%20Housed"), "Commonly Used Queries"); From f9f9e93026a92a5955fd990b141761ea8f53d775 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Wed, 11 Sep 2024 11:34:25 -0500 Subject: [PATCH 02/13] exclude today for next 30 days calculation of blood, fix blood summary calc, adjust labels --- .../queries/study/BloodSchedule/Blood Schedule.qview.xml | 6 +++++- WNPRC_EHR/resources/queries/study/Current Blood.query.xml | 3 ++- WNPRC_EHR/resources/queries/study/Current Blood.sql | 2 +- WNPRC_EHR/resources/queries/study/bloodSummary.sql | 5 +++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml index 04e7ac58e..3e8dccc9f 100644 --- a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml +++ b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml @@ -56,7 +56,11 @@ - + + + + + diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml index f5116e3eb..34ccca609 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/Current Blood.query.xml @@ -26,7 +26,7 @@ - Next 30 Days (inclusive) + Next 30 Days (excluding today) /query/executeQuery.view?schemaName=study& query.queryName=Blood Draws& query.viewName=Blood Summary& @@ -63,6 +63,7 @@ Volume Remaining After Draw (mL) + Volume Remaining Over Next 30 Days /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.sql b/WNPRC_EHR/resources/queries/study/Current Blood.sql index 54195ace4..c99ee0b0f 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.sql +++ b/WNPRC_EHR/resources/queries/study/Current Blood.sql @@ -51,7 +51,7 @@ FROM FROM study."Blood Draws" draws WHERE draws.id=bi.id AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) - AND cast(draws.date as date) >= bi.date + AND cast(draws.date as date) > bi.date --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) --when counting forwards, dont include this date diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql index c38ff59ff..bf8e1eb85 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.sql +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.sql @@ -58,8 +58,9 @@ FROM (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws WHERE draws.id=bi.id - AND (cast(draws.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) as date) AND cast(draws.date as date) <= cast(bi.date as date)) - AND cast(draws.date as date) >= bi.date + AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) + AND cast(draws.date as date) > bi.date + --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) ), 0 ) ) AS BloodNext30 From 9c273ab051ff9aa671d6a8ff52017ad23846c225 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Wed, 11 Sep 2024 12:06:19 -0500 Subject: [PATCH 03/13] use next 30 days since it does not include today --- WNPRC_EHR/resources/queries/study/Current Blood.sql | 2 +- WNPRC_EHR/resources/queries/study/bloodSummary.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.sql b/WNPRC_EHR/resources/queries/study/Current Blood.sql index c99ee0b0f..1baa7d91a 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.sql +++ b/WNPRC_EHR/resources/queries/study/Current Blood.sql @@ -50,7 +50,7 @@ FROM (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws WHERE draws.id=bi.id - AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) + AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) AND cast(draws.date as date) > bi.date --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql index bf8e1eb85..337ff9d5f 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.sql +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.sql @@ -58,7 +58,7 @@ FROM (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws WHERE draws.id=bi.id - AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) + AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) AND cast(draws.date as date) > bi.date --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) From 201d2f9f04c86cb79774d0378f0f3496f231b549 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Mon, 23 Sep 2024 10:15:09 -0500 Subject: [PATCH 04/13] use ehr version --- WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js index 003e278f0..3cdaf8aad 100644 --- a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js +++ b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js @@ -1248,9 +1248,6 @@ EHR.reports['abstract'] = function(panel, tab){ }; EHR.reports.BloodSummary = function(panel, tab){ - var filterArray = panel.getFilterArray(tab); - var title = panel.getTitleSuffix(); - tab.add({ html: 'This report summarizes the blood available for the animals below. ' + '

If there have been recent blood draws for the animal, a graph will show the available blood over time. On the graph, dots indicate dates when either blood was drawn or a previous blood draw fell off. The horizontal lines indicate the maximum allowable blood that can be drawn on that date.', @@ -1262,7 +1259,7 @@ EHR.reports.BloodSummary = function(panel, tab){ if (subjects.length){ tab.add({ - xtype: 'wnprc-bloodsummarypanel', + xtype: 'ehr-bloodsummarypanel', subjects: subjects }); } @@ -1270,7 +1267,7 @@ EHR.reports.BloodSummary = function(panel, tab){ { panel.resolveSubjectsFromHousing(tab, function(subjects, tab){ tab.add({ - xtype: 'wnprc-bloodsummarypanel', + xtype: 'ehr-bloodsummarypanel', subjects: subjects }); }, this); From f93b0116b6a0e772f433be5ee00335c36a6786f6 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 24 Sep 2024 11:34:54 -0500 Subject: [PATCH 05/13] remove wnprc blood graph to use ehr instead --- .../web/wnprc_ehr/panel/BloodSummaryPanel.js | 570 ------------------ .../org/labkey/wnprc_ehr/WNPRC_EHRModule.java | 1 - 2 files changed, 571 deletions(-) delete mode 100644 WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js diff --git a/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js b/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js deleted file mode 100644 index c4c298ee8..000000000 --- a/WNPRC_EHR/resources/web/wnprc_ehr/panel/BloodSummaryPanel.js +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 2016-2019 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -/* - * Title: BloodSummaryPanel - * Description: This will generate the blood report plot for each subject ID passed in. Provides a hook to add - * additional items in the report. - * Config: { - * subjects: Array of animal IDs, - * getSubjectItems(optional): Function returning an array of items to add for each subject ID after the plot - * } - */ - -Ext4.define('WNPRC.panel.BloodSummaryPanel', { - extend: 'Ext.panel.Panel', - alias: 'widget.wnprc-bloodsummarypanel', - intervals: {}, - plotHeight: 400, - - bloodPerKgCol: 'species/blood_per_kg', - bloodMaxDrawPctCol: 'species/max_draw_pct', - bloodDrawIntervalCol: 'species/blood_draw_interval', - - initComponent: function(){ - Ext4.apply(this, { - border: false, - defaults: { - border: false - }, - items: [{ - html: 'Loading...' - }] - }); - - this.callParent(); - - if(!Ext4.isDefined(this.subjects) || !Ext4.isArray(this.subjects)) - console.log("Must pass in an array of animal IDs as subjects.") - else - this.loadData(); - }, - - loadData: function(){ - var demoCols = 'id,species,id/MostRecentWeight/mostRecentWeight,id/MostRecentWeight/mostRecentWeightDate,Id/demographics/calculated_status,Id/demographics/calculated_status/meaning' - + ',' + this.bloodPerKgCol + ',' + this.bloodMaxDrawPctCol + ',' + this.bloodDrawIntervalCol; - - LABKEY.Query.selectRows({ - schemaName: 'study', - queryName: 'demographics', - filterArray: [LABKEY.Filter.create('id', this.subjects.join(';'), LABKEY.Filter.Types.EQUALS_ONE_OF)], - columns: demoCols, - requiredVersion: 9.1, - sort: 'id', - scope: this, - failure: LDK.Utils.getErrorCallback(), - success: function(results){ - this.demographicsMap = {}; - this.intervals = {}; - - Ext4.each(results.rows, function(row){ - var map = new LDK.SelectRowsRow(row); - var interval = row[this.bloodDrawIntervalCol].value; - this.demographicsMap[map.getValue('id')] = map; - - if(!interval) { - interval = 42; - } - if( this.intervals.hasOwnProperty(interval) ) { - this.intervals[interval].push(row.Id.value) - } else { - this.intervals[interval] = [row.Id.value]; - } - - }, this); - - this.loadBloodData(); - } - }); - }, - - loadBloodData: function() { - var multi = new LABKEY.MultiRequest(); - - for(var interval in this.intervals) { - if (this.intervals.hasOwnProperty(interval)) { - - multi.add(LABKEY.Ajax.request, { - url: LABKEY.ActionURL.buildURL("ehr", "bloodPlotData"), - params: { - ids: this.intervals[interval], - interval: interval - }, - method : 'POST', - requiredVersion: 9.1, - scope: this, - failure: LDK.Utils.getErrorCallback(), - success: function (response) - { - var results = JSON.parse(response.responseText); - console.log(results); - - var meta = results.metaData.fields; - for(var i = 0; i dDate) { - return; - } - } - //End TODO - if (rDate && Ext4.Date.format(rDate, LABKEY.extDefaultDateFormat) == Ext4.Date.format(new Date(), LABKEY.extDefaultDateFormat)) { - row.isToday = {value: true}; - } - } - - if (!this.currentBloodMap[id]) - this.currentBloodMap[id] = []; - - this.currentBloodMap[id].push(row); - }, this); - - if(this.bloodDrawResults) { - this.bloodDrawResults.rows = this.bloodDrawResults.rows.concat(results.rows); - } else { - this.bloodDrawResults = results; - } - } - }); - } - } - - multi.send(this.onLoad, this); - }, - - onLoad: function(results){ - var toAdd = []; - Ext4.each(this.subjects, function(subject){ - var dd = this.demographicsMap[subject]; - var bds = this.currentBloodMap[subject]; - - var cfg = { - xtype: 'ldk-webpartpanel', - style: 'margin-bottom: 20px;', - title: 'Blood Summary: ' + subject, - defaults: { - border: false - }, - items: [] - }; - - if (!dd){ - cfg.items.push({ - html: 'Either species or weight information is missing for this animal' - }); - } - else { - var status = dd.getValue('Id/demographics/calculated_status/meaning') || dd.getValue('Id/demographics/calculated_status'); - cfg.items.push({ - html: 'Id: ' + dd.getValue('Id') + (status ? ' (' + status + ')' : '') + '' - }); - - cfg.items.push({ - html: '
' - }); - - if(status != null && status.toLowerCase() === "dead") { - cfg.items.push({ - html: 'No current blood draw information for dead animal.', - border: false - }); - } - else if (!bds || bds.length === 1) { - var maxDraw = dd.getValue(this.bloodPerKgCol) * dd.getValue(this.bloodMaxDrawPctCol) * dd.getValue('id/MostRecentWeight/mostRecentWeight'); - cfg.items.push({ - html: 'There are no previous blood draws within the relevant time frame. A maximum amount of ' + Ext4.util.Format.round(maxDraw, 2) + ' mL can be drawn.', - border: false - }); - } - else { - cfg.items = cfg.items.concat(this.getGraphCfg(dd, bds)); - } - } - - toAdd.push(cfg); - }, this); - - this.removeAll(); - if (toAdd.length){ - this.add(toAdd); - } - else { - this.add({ - html: 'No records found' - }); - } - - this.addAdditionalGraphOptions(); - }, - - addAdditionalGraphOptions: function() { - var svgs = d3.selectAll('svg'); - var patternHeight = 8; - - // Add shading pattern - var defs = svgs.selectAll('defs') - .append('pattern') - .attr('id', 'diag-pattern') - .attr('patternUnits', 'userSpaceOnUse') - .attr('x', 0) - .attr('y', 0) - .attr('width', 3) - .attr('height', patternHeight) - .attr('patternTransform', 'rotate(30)') - .append('rect') - .attr('x', 0) - .attr('y', 0) - .attr('width',.5) - .attr('height', patternHeight) - .attr('style', 'stroke:none;') - .attr('fill', 'red'); - - - // Add under zero shading - Ext4.each(svgs[0], function(svg) { - var ticks = svg.getElementsByClassName('axis')[1].getElementsByClassName('tick-text')[0].getElementsByTagName('g'); - Ext4.each(ticks, function(tick) { - if(tick.getElementsByTagName('text')[0].textContent === '0') { - var axis = d3.select(tick.parentElement.parentElement); - var tickText = d3.select(tick.parentElement); - axis.append('rect') - .attr('x', tick.getBBox().x + 16) - .attr('y', tick.getBBox().y + 11) - .attr('width', axis[0][0].getBBox().width - tickText[0][0].getBBox().width - 10) - .attr('height', this.plotHeight - tick.getBBox().y - 60) - .attr('fill-opacity',.5) - .attr('fill', 'url(#diag-pattern)'); - } - },this) - },this); - - var points = d3.selectAll('a.point'); - var todayPoints = points.filter(function(d) { - return (d.isToday && d.isToday == true); - }); - - // Add Today line and text - todayPoints.append(function(d,i) { - - // Hijack the loop to setup line - var yAxis = d3.selectAll('svg').select('g.grid-line path')[0][i]; - var path = yAxis.getAttribute('d'); - var bottom = Number(path.substring(path.indexOf(',')+1, path.indexOf('L'))); - var top = Number(path.substring(path.indexOf(',', path.indexOf(',')+1)+1, path.indexOf('Z'))); - var ht = bottom - top; - this.getElementsByTagName('path')[0] - .setAttribute('d', "M0 " + (ht + 68 - this.getBBox().y) + " l0 -" + (ht-1)); - - var text = document.createElementNS(d3.ns.prefix.svg, 'text'); - text.setAttribute("x", this.getBBox().x - 18); - text.setAttribute("y", this.getBBox().y - 3); - text.setAttribute("style", "font-weight:bold;font-family:Arial;font-size:11px;"); - text.setAttribute("fill", "black"); - text.setAttribute("visibility", "visible"); - text.textContent = "Today"; - - return text; - }); - }, - getMaxBloodAvailValue: function(rows){ - - var allowableBloodVals = []; - for (var i = 0; i < rows.length; i++){ - allowableBloodVals.push(rows[i].allowableDisplay.value); - } - - return Math.round(allowableBloodVals.reduce((a, b) => Math.max(a, b), -Infinity)) + 10; - }, - - getTickValues: function(rows){ - var ticks = [], msPerDay = 86400000, totalTicks = 10; - var minDate = Date.parse(rows[0].date.value); - var minDateGmt = Date.parse(rows[0].date.value.concat(" GMT")); - var maxDate = Date.parse(rows[rows.length - 1].date.value); - var diff = maxDate - minDate; - var daysTotal = diff/msPerDay; - var daysPerTick = Math.ceil(daysTotal/totalTicks); - var newTotal = Math.ceil(daysTotal/daysPerTick); - - ticks[0] = (Math.ceil(minDate/msPerDay) * msPerDay) - - (msPerDay - (minDate - minDateGmt)); // Offset timezone - for(var i=1; iTotal volume of blood collected in the past ' + currentRow.blood_draw_interval.value + ' days: ' - + Ext4.util.Format.round(currentRow.bloodPrevious.value, 1) + ' mL. ' - + 'The amount of blood available if drawn today is: ' + Ext4.util.Format.round(currentRow.allowableDisplay.value, 1) + ' mL.

' - + '

The graph below shows how the amount of blood available will change over time, including when previous draws will drop off. Hover over the timepoints for more information.

', - border: false, - style: 'margin-bottom: 20px' - }); - } - - var layerName = "Volume"; - toAdd.push({ - xtype: 'container', - items: [{ - xtype: 'ldk-graphpanel', - margin: '0 0 0 0', - plotConfig: { - results: results, - title: 'Blood Available To Be Drawn: ' + subject, - height: this.plotHeight, - width: this.getWidth() - 50, - yLabel: 'Available Blood (mL)', - xLabel: 'Date', - xField: 'date', - grouping: ['seriesId'], - scales: { - shape: { - scaleType: 'discrete', - range: [LABKEY.vis.Scale.Shape()[1], LABKEY.vis.Scale.Shape()[0], - LABKEY.vis.Scale.Shape()[4], LABKEY.vis.Scale.Shape()[0]], - domain: ["0 " + layerName, "1 " + layerName, "2 " + layerName, "3 " + layerName] - }, - color: { - scaleType: 'discrete', - range: [LABKEY.vis.Scale.ColorDiscrete()[1], LABKEY.vis.Scale.ColorDiscrete()[0], "#2fad24", "red", "black"], - domain: ["0 " + layerName, "1 " + layerName, "2 " + layerName, "3 " + layerName] - } - , - size: { - scaleType: 'discrete', - range: [5, 7], - domain: ["0 " + layerName, "1 " + layerName] - }, - x: { - tickValues: this.getTickValues(results.rows) - }, - y: { - domain: [0, this.getMaxBloodAvailValue(results.rows)], - } - }, - layers: [{ - y: 'allowableBlood', - hoverText: function(row){ - var lines = []; - - if(row.isDeath) { - lines.push('DEATH'); - } - lines.push('Date: ' + Ext4.Date.format(row.date, LABKEY.extDefaultDateFormat)); - lines.push('Drawn on this Date: ' + row.quantity); - lines.push('Volume Available on this Date: ' + LABKEY.Utils.roundNumber(row.allowableDisplay, 1) + ' mL'); - - lines.push('Current Weight: ' + row.mostRecentWeight + ' kg (' + Ext4.Date.format(row.mostRecentWeightDate, LABKEY.extDefaultDateFormat) + ')'); - - lines.push('Drawn in Previous ' + row.blood_draw_interval + ' days: ' + LABKEY.Utils.roundNumber(row.bloodPrevious, 1)); - - if (new Date(row.date) < new Date() && !row.isToday) - lines.push('Drawn in Next ' + row.blood_draw_interval + ' days: ' + LABKEY.Utils.roundNumber(row.bloodFuture, 1)); - - - return lines.join('\n'); - }, - name: layerName - }] - }, - getPlotConfig: function(){ - var cfg = LDK.panel.GraphPanel.prototype.getPlotConfig.call(this); - cfg.legendData = [ - { - color:'#FC8D62', - text:'Scheduled Blood Draw Status', - shape: LABKEY.vis.Scale.Shape()[1] - }, - { - color:'#66C2A5', - text:'Non-scheduled Blood Draw Status', - shape: LABKEY.vis.Scale.Shape()[0] - } - ] - cfg.aes.color = null; - cfg.aes.shape = null; - - return cfg; - }, - - //@Override - appendLayer: function(plot, layerConfig){ - var meta = this.findMetadata(layerConfig.y); - plot.addLayer(new LABKEY.vis.Layer({ - geom: new LABKEY.vis.Geom.Point({size: 5}), - name: layerConfig.name || meta.caption, - aes: { - y: function(row){ - if (row.isHidden) - return null; - - return row[layerConfig.y] - }, - hoverText: layerConfig.hoverText, - shape: function(row){ - if(row.isDeath) - return 2; - if(row.isToday) - return 3; - if(row.quantity > 0) { - return 0; - } - return 1; - }, - color: function(row){ - if(row.isToday) - return 4; - if(row.isDeath) - return 4; - - if(row.quantity > 0) { - return 0; - } - - return 1; - }, - size: function(row) { - if(row.isToday) - return 1; - if(row.isDeath) - return 1; - - return 0; - } - } - })); - - //now add segments. this is an odd way to accomplish grouping, but - //otherwise Vis will give each segment a different color - Ext4.each(seriesIds, function(seriesId){ - plot.addLayer(new LABKEY.vis.Layer({ - geom: new LABKEY.vis.Geom.Path({size: 5, opacity: 2}), - name: layerConfig.name || meta.caption, - aes: { - y: function(row){ - if (row.seriesId != seriesId) - return null; - - return row[layerConfig.y]; - }, - group: 'none' - } - })); - }, this); - } - }] - }); - - // If defined, add additional items below plot - if(Ext4.isDefined(this.getSubjectItems) && Ext4.isFunction(this.getSubjectItems)) { - toAdd = toAdd.concat(this.getSubjectItems(subject, dd)); - } - else if(Ext4.isDefined(this.getSubjectItems) && !Ext4.isFunction(this.getSubjectItems)) { - console.log("getSubjectItems must be a function returning an array of items to append after the plot") - } - - - return toAdd; - } - - -}); \ No newline at end of file diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java index e9bb96249..215aac420 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRModule.java @@ -233,7 +233,6 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/AfternoonTreatmentsReport.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/EveningTreatmentsReport.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/reports/MasterTreatmentsReport.js"), this); - EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/panel/BloodSummaryPanel.js"), this); EHRService.get().registerClientDependency(ClientDependency.supplierFromPath("wnprc_ehr/Inroom.js"), this); EHRService.get().registerReportLink(EHRService.REPORT_LINK_TYPE.housing, "List Single-housed Animals", this, DetailsURL.fromString("/query/executeQuery.view?schemaName=study&query.queryName=Demographics&query.viewName=Single%20Housed"), "Commonly Used Queries"); From 4c100ddf54d88a972169f38b69f090b191fffbba Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Wed, 2 Oct 2024 16:37:28 -0500 Subject: [PATCH 06/13] Consolidate blood draw reports into currentBloodDraws.sql, adjust references --- .../resources/queries/study/Current Blood.sql | 105 ------------ .../queries/study/Current Blood/.qview.xml | 44 ----- .../study/DailyOverDrawsWithThreshold.sql | 4 +- .../resources/queries/study/blood.query.xml | 2 +- .../study/blood/Blood Summary.qview.xml | 2 +- .../queries/study/bloodDrawChanges.sql | 7 +- .../queries/study/bloodSummary.query.xml | 39 ----- .../resources/queries/study/bloodSummary.sql | 72 --------- ....query.xml => currentBloodDraws.query.xml} | 153 +++++++++--------- .../queries/study/currentBloodDraws.sql | 55 ++++++- .../study/currentBloodDraws/.qview.xml | 42 +++++ .../demographics/Blood Draw Info.qview.xml | 10 +- .../study/demographicsBloodSummary.query.xml | 63 -------- .../study/demographicsBloodSummary.sql | 87 ---------- .../resources/web/wnprc_ehr/wnprcReports.js | 20 +++ .../BloodDrawReviewDailyNotification.java | 8 +- .../notification/BloodDrawsTodayAll.java | 20 +-- .../notification/NotificationToolkit.java | 6 +- .../wnprc_ehr/table/WNPRC_EHRCustomizer.java | 2 +- .../test/tests/wnprc_ehr/WNPRC_EHRTest.java | 4 +- 20 files changed, 225 insertions(+), 520 deletions(-) delete mode 100644 WNPRC_EHR/resources/queries/study/Current Blood.sql delete mode 100644 WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml delete mode 100644 WNPRC_EHR/resources/queries/study/bloodSummary.query.xml delete mode 100644 WNPRC_EHR/resources/queries/study/bloodSummary.sql rename WNPRC_EHR/resources/queries/study/{Current Blood.query.xml => currentBloodDraws.query.xml} (74%) create mode 100644 WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml delete mode 100644 WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml delete mode 100644 WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.sql b/WNPRC_EHR/resources/queries/study/Current Blood.sql deleted file mode 100644 index 1baa7d91a..000000000 --- a/WNPRC_EHR/resources/queries/study/Current Blood.sql +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2010-2013 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - bq.*, - cast(round(bq.weight*species.max_draw_pct*species.blood_per_kg, 1) as numeric) AS MaxBlood, - cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - bq.BloodLast30, 1) AS numeric) AS AvailBlood, - cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - (bq.BloodLast30 + bq.BloodNext30), 1) AS numeric) AS BloodAvailPlusThirty -FROM -( - SELECT - b.*, - (d.species) as species, - ( - CONVERT ( - (SELECT AVG(w.weight) AS _expr - FROM study.weight w - WHERE w.id=b.id AND w.date=b.lastWeighDate - AND w.qcstate.publicdata = true - ), double ) - ) AS weight - FROM - ( - SELECT bi.* - ,timestampadd('SQL_TSI_DAY', -29, bi.date) as minDate - ,timestampadd('SQL_TSI_DAY', 29, bi.date) as maxDate - ,( CONVERT( - (SELECT MAX(w.date) as _expr - FROM study.weight w - WHERE w.id = bi.id - --AND w.date <= bi.date - AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bi.date - AND w.qcstate.publicdata = true - ), timestamp ) - ) AS lastWeighDate - , ( COALESCE ( - (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr - FROM study."Blood Draws" draws - WHERE draws.id=bi.id - AND draws.date >= TIMESTAMPADD('SQL_TSI_DAY', -29, bi.date) - AND cast(draws.date as date) <= bi.date - AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) - --when counting backwards, dont include this date - --AND (draws.date != bi.date and draws.qcstate.label != bi.status) - ), 0 ) - ) AS BloodLast30 - , ( COALESCE ( - (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr - FROM study."Blood Draws" draws - WHERE draws.id=bi.id - AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) - AND cast(draws.date as date) > bi.date - --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) - AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) - --when counting forwards, dont include this date - --AND (draws.date != bi.date and draws.qcstate.label != bi.status) - ), 0 ) - ) AS BloodNext30 - from ( - SELECT - b.id, - --b.id.dataset.demographics.species as species, - cast(b.date as date) as date, - --b.lsid, - --b.qcstate, - b.qcstate.label as status, - SUM(coalesce(b.quantity, 0)) as quantity - FROM study.blood b - WHERE cast(b.date as date) >= TIMESTAMPADD('SQL_TSI_DAY', -29, now()) - AND (b.qcstate.metadata.DraftData = true OR b.qcstate.publicdata = true) - group by b.id, cast(b.date as date), b.qcstate.label - - UNION ALL - SELECT - b.id, - --b.id.dataset.demographics.species as species, - TIMESTAMPADD('SQL_TSI_DAY', 30, cast(cast(b.date as date) as timestamp)) as date, - --null as lsid, - --null as qcstate, - null as status, - 0 as quantity - FROM study.blood b - WHERE cast(b.date as date) >= TIMESTAMPADD('SQL_TSI_DAY', -29, now()) - AND (b.qcstate.metadata.DraftData = true OR b.qcstate.publicdata = true) - GROUP BY b.id, cast(b.date as date) - - --add one row per animal, showing todays date - UNION ALL - SELECT - b.id, - --b.species, - curdate() as date, - --null as lsid, - --null as qcstate, - null as status, - 0 as quantity - FROM study.demographics b - --WHERE b.id.status.status = 'Alive' - ) bi - ) b - JOIN study.demographics d ON d.id=b.id - ) bq - diff --git a/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml b/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml deleted file mode 100644 index f75cd0a18..000000000 --- a/WNPRC_EHR/resources/queries/study/Current Blood/.qview.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql b/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql index 9e0ef9abd..e87e21f4b 100644 --- a/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql +++ b/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql @@ -17,9 +17,9 @@ SELECT b.Id, b.restraintTime, b.instructions, b.restraintDuration, - b.BloodRemaining.AvailBlood, + b.BloodRemaining.allowableBlood, b.QCState, b.QCState.label FROM "Blood Draws" b LEFT JOIN ehr_lookups.species e ON e.common = b.Id.Demographics.species -WHERE b.BloodRemaining.AvailBlood < e.blood_threshold_warning AND b.date > curdate() AND b.date < cast(TIMESTAMPADD('SQL_TSI_DAY', 1, curdate()) as date) AND b.QCState.label <> 'Request: Denied' \ No newline at end of file +WHERE b.BloodRemaining.allowableBlood < e.blood_threshold_warning AND b.date > curdate() AND b.date < cast(TIMESTAMPADD('SQL_TSI_DAY', 1, curdate()) as date) AND b.QCState.label <> 'Request: Denied' \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/blood.query.xml b/WNPRC_EHR/resources/queries/study/blood.query.xml index 0d4c76bd8..ebb431ad8 100644 --- a/WNPRC_EHR/resources/queries/study/blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/blood.query.xml @@ -106,7 +106,7 @@ true study - bloodSummary + currentBloodDraws lsid
diff --git a/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml b/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml index 04a6f204a..2e70880c8 100644 --- a/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml +++ b/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml @@ -38,7 +38,7 @@
- + diff --git a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql index d358fe95e..d58fd6410 100644 --- a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql +++ b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql @@ -15,10 +15,11 @@ */ --this query is designed to return any dates when allowable blood draw volume changes --this includes dates of blood draws, plus the date those draws drop off -PARAMETERS(DATE_INTERVAL INTEGER) +PARAMETERS(DATE_INTERVAL INTEGER DEFAULT 30) SELECT b2.id, + b2.status, b2.dateOnly, b2.quantity, DATE_INTERVAL as blood_draw_interval, @@ -29,12 +30,14 @@ FROM ( SELECT b.id, b.dateOnly, + GROUP_CONCAT(b.status,'') as status, sum(b.quantity) as quantity FROM ( --find all blood draws within the interval, looking backwards SELECT b.id, + b.qcstate as status, b.dateOnly, b.quantity, FROM study.blood b @@ -45,6 +48,7 @@ FROM ( --join 1 row for the current date SELECT d1.id, + null as status, curdate() as dateOnly, 0 as quantity, FROM study.demographics d1 @@ -55,6 +59,7 @@ FROM ( --add one row for each date when the draw drops off the record SELECT b.id, + null as status, timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly), 0 as quantity, FROM study.blood b diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml deleted file mode 100644 index 7d3c1c2a2..000000000 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - true - - - - Drawn in Previous 30 Days (inclusive) - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~lte=${Date}& - query.Date~gte=${minDate}& - query.sort=-Date& - - - - Scheduled in Next 30 Days (inclusive) - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~gt=${Date}& - query.sort=-Date& - - - - /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary - - - BloodLast30 -
-
-
-
diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql deleted file mode 100644 index 337ff9d5f..000000000 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.sql +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2010-2013 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - bq.lsid, - bq.id, - bq.date, - bq.minDate, --- bq.maxDate, - bq.weight, - bq.lastWeighDate, - cast(bq.BloodLast30 as numeric) as BloodLast30, - bq.BloodNext30, - cast(round(bq.weight*species.max_draw_pct*species.blood_per_kg, 1) as numeric) AS MaxBlood, - cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - bq.BloodLast30, 1) AS numeric) AS AvailBlood, - cast(round((bq.weight*species.max_draw_pct*species.blood_per_kg) - (bq.BloodLast30 + bq.BloodNext30), 1) AS numeric) AS BloodAvailNowPlusThirtyDays -FROM -( - SELECT - b.*, - (d.species) as species, - ( - CONVERT ( - (SELECT AVG(w.weight) AS _expr - FROM study.weight w - WHERE w.id=b.id AND w.date=b.lastWeighDate - AND w.qcstate.publicdata = true - ), double ) - ) AS weight - FROM - ( - SELECT bi.* - ,timestampadd('SQL_TSI_DAY', -29, bi.date) as minDate --- ,timestampadd('SQL_TSI_DAY', 29, bi.date) as maxDate - , ( CONVERT( - (SELECT MAX(w.date) as _expr - FROM study.weight w - WHERE w.id = bi.id - --NOTE: we are doing this comparison such that it considers date only, not datetime - --AND w.date <= bi.date - AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bi.date - AND w.qcstate.publicdata = true - ), timestamp ) - ) AS lastWeighDate - , ( COALESCE ( - (SELECT SUM(draws.quantity) AS _expr - FROM study."Blood Draws" draws - WHERE draws.id=bi.id - --AND draws.date BETWEEN TIMESTAMPADD('SQL_TSI_DAY', -30, bi.date) AND bi.date - AND (cast(draws.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', -29, bi.date) as date) AND cast(draws.date as date) <= cast(bi.date as date)) - AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) - --AND draws.qcstate.publicdata = true - ), 0 ) - ) AS BloodLast30 - , ( COALESCE ( - (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr - FROM study."Blood Draws" draws - WHERE draws.id=bi.id - AND draws.date <= TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) - AND cast(draws.date as date) > bi.date - --AND draws.date BETWEEN bi.date AND TIMESTAMPADD('SQL_TSI_DAY', 29, bi.date) - AND (draws.qcstate.metadata.DraftData = true OR draws.qcstate.publicdata = true) - ), 0 ) - ) AS BloodNext30 - FROM study.blood bi - --WHERE (bi.qcstate.metadata.DraftData = true OR bi.qcstate.publicdata = true) - ) b - JOIN study.demographics d ON d.id=b.id - ) bq - diff --git a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml b/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml similarity index 74% rename from WNPRC_EHR/resources/queries/study/Current Blood.query.xml rename to WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml index 34ccca609..ec7039ef0 100644 --- a/WNPRC_EHR/resources/queries/study/Current Blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml @@ -1,74 +1,79 @@ - - - - - - - true - - - - - study - Animal - Id - - - - Previous 30 Days (inclusive) - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~datelte=${Date}& - query.Date~dategte=${minDate}& - query.sort=-Date& - - - - Next 30 Days (excluding today) - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~dategte=${Date}& - query.sort=-Date& - - - - Latest Weight (kg) - /query/executeQuery.view?schemaName=study& - query.queryName=Weight& - query.Id~eq=${Id}& - query.wDate~gt=${wDate}& - query.sort=-Date& - - - - yyyy-MM-dd - - - yyyy-MM-dd - - - yyyy-MM-dd - - - yyyy-MM-dd HH:mm - - - 20% Volume By Weight - - - Volume Remaining After Draw (mL) - - - Volume Remaining Over Next 30 Days - /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary - - - BloodLast30 -
-
-
-
+ + + + + + + true + + + + + study + Animal + Id + + + + Status + + core + qcstate + rowid + + + + Previous 30 Days (inclusive) + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~datelte=${Date}& + query.Date~dategte=${minDate}& + query.sort=-Date& + + + + Next 30 Days (inclusive) + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~dategte=${Date}& + query.sort=-Date& + + + + Latest Weight (kg) + /query/executeQuery.view?schemaName=study& + query.queryName=Weight& + query.Id~eq=${Id}& + query.wDate~gt=${wDate}& + query.sort=-Date& + + + + yyyy-MM-dd + + + yyyy-MM-dd + + + yyyy-MM-dd + + + 20% Volume By Weight + + + Volume Remaining After Draw (mL) + /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + + + Volume Remaining Over Next 30 Days + /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + + +
+
+
+
diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql index feda25ea5..cacb6129e 100644 --- a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql @@ -17,6 +17,7 @@ SELECT t.id, t.date, + t.status, cast(t.quantity as double) as quantity, t.species, t.max_draw_pct, @@ -25,7 +26,7 @@ SELECT t.mostRecentWeight, t.mostRecentWeightDate, t.death, - cast(t.allowableBlood as double) as maxAllowableBlood, + cast(round(t.allowableBlood,1) as numeric) as maxAllowableBlood, cast(t.bloodPrevious as double) as bloodPrevious, cast((t.allowableBlood - t.bloodPrevious) as double) as allowablePrevious, @@ -34,11 +35,12 @@ SELECT --if the draw is historic, always consider previous draws only. --otherwise, look both forward and backwards, then take the interval with the highest volume - cast(case + cast(round(case WHEN t.date < curdate() THEN (t.allowableBlood - t.bloodPrevious) WHEN t.bloodPrevious < t.bloodFuture THEN (t.allowableBlood - t.bloodFuture) ELSE (t.allowableBlood - t.bloodPrevious) - end as double) as allowableBlood, + end , 1) as numeric) as allowableBlood, + cast( round(t.allowableBlood - ((t.bloodPrevious + t.bloodFuture) - t.bloodToday), 1) as numeric) as BloodAvailPlusThirty, t.minDate, t.maxDate @@ -46,17 +48,49 @@ FROM ( SELECT bd.id, + bd.status, bd.dateOnly as date, bd.quantity, d.species, d.death, + ( + CONVERT ( + (SELECT AVG(w.weight) AS _expr + FROM study.weight w + WHERE w.id=bd.id AND w.date= + ( CONVERT( + (SELECT MAX(w.date) as _expr + FROM study.weight w + WHERE w.id = bd.id + --AND w.date <= bi.date + AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bd.dateOnly + AND w.qcstate.publicdata = true + ), timestamp ) + ) + AND w.qcstate.publicdata = true + ), double ) + ) * d.species.max_draw_pct * d.species.blood_per_kg AS allowableBlood, + + (CONVERT ( + (SELECT AVG(w.weight) AS _expr + FROM study.weight w + WHERE w.id=bd.id AND w.date= + (CONVERT( + (SELECT MAX(w.date) as _expr + FROM study.weight w + WHERE w.id = bd.id + --AND w.date <= bi.date + AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bd.dateOnly + AND w.qcstate.publicdata = true + ), timestamp ) + ) + AND w.qcstate.publicdata = true + ), double ) ) as weight, d.id.mostRecentWeight.MostRecentWeight, d.id.mostRecentWeight.MostRecentWeightDate, d.species.blood_per_kg, d.species.max_draw_pct, bd.blood_draw_interval, -(d.id.mostRecentWeight.MostRecentWeight * d.species.blood_per_kg * d.species.max_draw_pct) - as allowableBlood, bd.minDate, bd.maxDate, COALESCE( @@ -77,7 +111,16 @@ SELECT AND draws.dateOnly >= bd.dateOnly --NOTE: this has been changed to include pending/non-approved draws AND draws.countsAgainstVolume = true - ), 0) AS BloodFuture + ), 0) AS BloodFuture, + +COALESCE( + (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id = bd.id AND draws.project.research = true + AND draws.dateOnly = curdate() + --NOTE: this has been changed to include pending/non-approved draws + AND draws.countsAgainstVolume = true + ), 0) AS BloodToday FROM study.bloodDrawChanges bd JOIN study.demographics d ON (d.id = bd.id) diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml b/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml new file mode 100644 index 000000000..f72ca56dd --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml b/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml index 7315e444b..96fe4b9e5 100644 --- a/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml +++ b/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml @@ -34,7 +34,7 @@
- + @@ -45,22 +45,22 @@ - + - + - + - + diff --git a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml deleted file mode 100644 index e680dda90..000000000 --- a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - true - true - - - true - - - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~lte=${Date}& - query.sort=-Date& - - Blood Drawn In Previous 30 Days - - - Scheduled in Next 30 Days - /query/executeQuery.view?schemaName=study& - query.queryName=Blood Draws& - query.viewName=Blood Summary& - query.Id~eq=${Id}& - query.Date~gt=${Date}& - query.sort=-Date& - - - - Max Blood Per 30 Days (mL) - - - Available Blood (mL) - - - - - - FF0000 - - - - - Current Blood (mL) - - - - - - FBEC5D - - - - - AvailBlood -
-
-
-
diff --git a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql deleted file mode 100644 index dcf9fd08c..000000000 --- a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql +++ /dev/null @@ -1,87 +0,0 @@ - - -/* - * Copyright (c) 2010-2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 - */ -SELECT - b.lsid, - b.id, - --b.date, - b.wdate as MostRecentWeightDate, - b.weight as MostRecentWeight, - convert(BloodLast30, float) as BloodLast30, - convert(BloodNext30, float) as BloodNext30, - convert(CASE - WHEN (b.species = 'Marmoset') - THEN (b.weight*0.15*60) - ELSE - (b.weight*0.2*60) - END, float) AS MaxBlood, - - convert(case - when (b.species = 'Marmoset') - THEN ((b.weight*0.15*60) - b.BloodLast30) - else - ((b.weight*0.2*60) - b.BloodLast30) - end, float) as CurrentBlood, - - TRUNCATE(ROUND(CAST(case - when (b.BloodLast30 > b.BloodNext30 and b.species = 'Marmoset') - THEN ((b.weight*0.15*60) - b.BloodLast30) - when (b.BloodLast30 > b.BloodNext30 and b.species != 'Marmoset') - THEN ((b.weight*0.2*60) - b.BloodLast30 -b.BloodNext30) - when (b.BloodLast30 <= b.BloodNext30 and b.species = 'Marmoset') - THEN ((b.weight*0.15*60) - b.BloodNext30) - else - ((b.weight*0.2*60) - b.BloodNext30 - b.BloodLast30) - end AS NUMERIC),2),2) as AvailBlood -from ( -SELECT - d.lsid, - d.id, - d.species, --- d.weight, --- d.wdate, - lastWeight.date as wdate, - ( - SELECT AVG(w.weight) AS _expr - FROM study.weight w - WHERE w.id=d.id AND w.date=lastWeight.date - AND w.qcstate.publicdata = true - ) AS weight, - COALESCE (( - SELECT - SUM(bd.quantity) AS _expr - FROM study."Blood Draws" bd - WHERE bd.id=d.id AND - bd.qcstate.publicdata = true AND - --bd.date BETWEEN TIMESTAMPADD('SQL_TSI_DAY', -30, now()) AND now() - (cast(bd.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', -30, now()) as date) AND cast(bd.date as date) <= cast(curdate() as date)) - - ), 0) AS BloodLast30, - COALESCE (( - SELECT - SUM(bd.quantity) AS _expr - FROM study."Blood Draws" bd - WHERE bd.id=d.id AND - (bd.qcstate.publicdata = true OR bd.qcstate.metadata.DraftData = true) AND - --bd.date BETWEEN now() AND TIMESTAMPADD('SQL_TSI_DAY', 30, now()) - (cast(bd.date as date) >= cast(curdate() as date) AND cast(bd.date as date) <= cast(TIMESTAMPADD('SQL_TSI_DAY', 30, now()) as date)) - - ), 0) AS BloodNext30 - -FROM - study.demographics d - LEFT OUTER JOIN - (SELECT w.id, MAX(date) as date FROM study.weight w - WHERE w.qcstate.publicdata = true - GROUP BY w.id) lastWeight ON d.id = lastWeight.id - --- WHERE b.date >= TIMESTAMPADD('SQL_TSI_DAY', -30, now()) -WHERE - -d.calculated_status = 'Alive' - -) b \ No newline at end of file diff --git a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js index 3cdaf8aad..2bebd2370 100644 --- a/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js +++ b/WNPRC_EHR/resources/web/wnprc_ehr/wnprcReports.js @@ -661,6 +661,26 @@ EHR.reports.diagnostics = function(panel, tab){ }); }; +EHR.reports.currentBloodDraws = function(panel, tab) { + var filterArray = panel.getFilterArray(tab); + var title = panel.getTitleSuffix(); + + var config = panel.getQWPConfig({ + schemaName: 'study', + queryName: 'currentBloodDraws', + title: "Current Blood " + title, + parameters: {'interval': '30'}, + filters: filterArray.nonRemovable, + removeableFilters: filterArray.removable + }); + + tab.add({ + xtype: 'ldk-querycmp', + style: 'margin-bottom:20px;', + queryConfig: config + }); +} + EHR.reports.bloodChemistry = function(panel, tab){ var filterArray = panel.getFilterArray(tab); var title = panel.getTitleSuffix(); diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java index 85e38961b..ce0ca3cce 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java @@ -229,16 +229,16 @@ void getBloodOverdraws() { // Creates sort. Sort mySort = new Sort("date"); // Creates columns to retrieve. - String[] targetColumns = new String[]{"id", "date", "BloodRemaining/AvailBlood"}; + String[] targetColumns = new String[]{"id", "date", "BloodRemaining/allowableBlood"}; // Runs query. ArrayList> unformattedUpcomingBloodDraws = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "BloodSchedule", myFilter, mySort, targetColumns); // Converts map to list (for displaying in table). for (HashMap currentDraw : unformattedUpcomingBloodDraws) { // Verifies there is data because some older blood draws don't list available blood. - if (!currentDraw.get("BloodRemaining/AvailBlood").isEmpty()) { - if (Double.valueOf(currentDraw.get("BloodRemaining/AvailBlood")) <= 0) { - String[] currentRow = {currentDraw.get("id"), currentDraw.get("date"), currentDraw.get("BloodRemaining/AvailBlood")}; + if (!currentDraw.get("BloodRemaining/allowableBlood").isEmpty()) { + if (Double.valueOf(currentDraw.get("BloodRemaining/allowableBlood")) <= 0) { + String[] currentRow = {currentDraw.get("id"), currentDraw.get("date"), currentDraw.get("BloodRemaining/allowableBlood")}; bloodOverdraws.add(currentRow); } } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index 8030b9204..b7b7d82fa 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -123,7 +123,7 @@ public static class BloodDrawsTodayObject { // Creates sort. Sort mySort = new Sort("date"); // Creates columns to retrieve. - String[] targetColumns = new String[]{"id", "qcstate/label", "projectStatus", "BloodRemaining/AvailBlood", "billedby/title", "Id/curLocation/room", "Id/curLocation/area"}; + String[] targetColumns = new String[]{"id", "qcstate/label", "projectStatus", "BloodRemaining/allowableBlood", "billedby/title", "Id/curLocation/room", "Id/curLocation/area"}; //Runs query. ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "BloodSchedule", myFilter, mySort, targetColumns); @@ -146,7 +146,7 @@ public static class BloodDrawsTodayObject { // Updates id. myCurrentRow[0] = result.get("id"); // Updates blood remaining. - myCurrentRow[1] = result.get("BloodRemaining/AvailBlood"); + myCurrentRow[1] = result.get("BloodRemaining/allowableBlood"); // Updates project status (this checks if animal is assigned to a project). if (!result.get("qcstate/label").equals("Request: Denied") && !result.get("projectStatus").isEmpty()) { myCurrentRow[2] = "UNASSIGNED"; @@ -180,25 +180,25 @@ public static class BloodDrawsTodayObject { //Updates row colors. myCurrentRow[8] = "white"; - if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { - Float availBlood = Float.parseFloat(result.get("BloodRemaining/AvailBlood")); - if (availBlood <= 0) { + if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { + Float allowableBlood = Float.parseFloat(result.get("BloodRemaining/allowableBlood")); + if (allowableBlood <= 0) { // If blood draw is over limit, color it red. myCurrentRow[8] = "red"; } - else if (availBlood <= bloodThreshold) { + else if (allowableBlood <= bloodThreshold) { // If blood draw is over threshold limit, color it orange. myCurrentRow[8] = "orange"; } } // String currentRowColor = "white"; -// if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { -// Float availBlood = Float.parseFloat(result.get("BloodRemaining/AvailBlood")); -// if (availBlood <= 0) { +// if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { +// Float allowableBlood = Float.parseFloat(result.get("BloodRemaining/allowableBlood")); +// if (allowableBlood <= 0) { // // If blood draw is over limit, color it red. // currentRowColor = "red"; // } -// else if (availBlood <= bloodThreshold) { +// else if (allowableBlood <= bloodThreshold) { // // If blood draw is over threshold limit, color it orange. // currentRowColor = "orange"; // } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java index 34912b9f8..66d1f1d4b 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java @@ -1035,14 +1035,14 @@ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck, SimpleFilter myFilter = new SimpleFilter("Id", idToCheck, CompareType.EQUAL); myFilter.addCondition("date", dateToCheck, CompareType.DATE_EQUAL); // Runs query. - String[] targetColumns = new String[]{"BloodRemaining/AvailBlood"}; + String[] targetColumns = new String[]{"BloodRemaining/allowableBlood"}; ArrayList> returnArray = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "blood", myFilter, null, targetColumns); // Checks results. if (!returnArray.isEmpty()) { for (HashMap result : returnArray) { - if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { - Double availableBlood = Double.valueOf(result.get("BloodRemaining/AvailBlood")); + if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { + Double availableBlood = Double.valueOf(result.get("BloodRemaining/allowableBlood")); if (availableBlood <=0) { return availableBlood; } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java index 606830674..d9bd8c220 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java @@ -364,7 +364,7 @@ private void customizeAnimalTable(AbstractTableInfo ds) col10.setDescription("Calculates the total number of days each animal has been single housed, if applicable."); ds.addColumn(col10); - BaseColumnInfo bloodCol = getWrappedIdCol(us, ds, "AvailBlood", "demographicsBloodSummary"); + BaseColumnInfo bloodCol = getWrappedIdCol(us, ds, "allowableBlood", "currentBloodDraws"); bloodCol.setLabel("Blood Remaining"); bloodCol.setDescription("Calculates the total blood draw and remaining, which is determine by weight and blood drawn in the past 30 days."); ds.addColumn(bloodCol); diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java index f1711acd2..a29b64ce1 100644 --- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java +++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java @@ -4181,7 +4181,7 @@ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, Str /** * This function inserts data into the 'study/BloodSchedule' dataset. - * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/AvailBlood, billedby/title, and Id/DataSet/Demographics/calculated_status. + * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/allowableBlood, billedby/title, and Id/DataSet/Demographics/calculated_status. * This function updates the following tables: study/demographics, study/weight, study/blood. * @param billingGroupRealName * @param animalID @@ -4211,7 +4211,7 @@ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, Str HashMap demographicInfoTestData1 = new HashMap<>(); demographicInfoTestData1.put("id", animalID); demographicInfoTestData1.put("calculated_status", livingStatus); - // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood'). + // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/allowableBlood'). HashMap weightTestData1 = new HashMap<>(); weightTestData1.put("id", animalID); weightTestData1.put("date", new Date()); From da350df09436a137d4c2d586c2e64f7bc1711ae2 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Fri, 4 Oct 2024 11:31:16 -0500 Subject: [PATCH 07/13] ignore project type --- WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql | 4 ++-- WNPRC_EHR/resources/queries/study/currentBloodDraws.sql | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql index d58fd6410..efb9c28f4 100644 --- a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql +++ b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql @@ -41,7 +41,7 @@ FROM ( b.dateOnly, b.quantity, FROM study.blood b - WHERE b.dateOnly > timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) AND b.project.research = TRUE + WHERE b.dateOnly > timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) UNION ALL @@ -63,7 +63,7 @@ FROM ( timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly), 0 as quantity, FROM study.blood b - WHERE timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly) >= timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) AND b.project.research = TRUE + WHERE timestampadd('SQL_TSI_DAY', DATE_INTERVAL, b.dateOnly) >= timestampadd('SQL_TSI_DAY', -1 * DATE_INTERVAL, curdate()) ) b diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql index cacb6129e..76fcad98a 100644 --- a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql @@ -96,7 +96,7 @@ SELECT COALESCE( (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws - WHERE draws.id = bd.id AND draws.project.research = true + WHERE draws.id = bd.id AND draws.dateOnly > bd.minDate AND draws.dateOnly <= bd.dateOnly --NOTE: this has been changed to include pending/non-approved draws @@ -106,7 +106,7 @@ SELECT COALESCE( (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws - WHERE draws.id = bd.id AND draws.project.research = true + WHERE draws.id = bd.id AND draws.dateOnly < bd.maxDate AND draws.dateOnly >= bd.dateOnly --NOTE: this has been changed to include pending/non-approved draws @@ -116,7 +116,7 @@ SELECT COALESCE( (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws - WHERE draws.id = bd.id AND draws.project.research = true + WHERE draws.id = bd.id AND draws.dateOnly = curdate() --NOTE: this has been changed to include pending/non-approved draws AND draws.countsAgainstVolume = true From cb610f31e162f8196238d7dd4ca8a9479f6638e8 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 12 Nov 2024 14:40:32 -0600 Subject: [PATCH 08/13] group up the blood draws if they are done at the same time --- .../wnprc_billing/bloodDrawsAllTubesSPI.sql | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql b/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql index fb5d7bec8..ea4fed321 100644 --- a/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql +++ b/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql @@ -2,15 +2,17 @@ SELECT Id, date, project, - coalesce(account, project.account.alias) AS debitedAccount, + coalesce(account, project.account.alias) as debitedAccount, coalesce(a.tier_rate.tierRate, project.account.tier_rate.tierRate) as otherRate, - objectid AS sourceRecord, - ('Blood Draws ' || Id) AS comment, - CAST(1 as DOUBLE) AS quantity, - taskId, - performedby + group_concat(objectid,';') as objectids, + ('Blood Draws ' || Id || ' x' || COUNT(*)) as comment, + CAST(1 AS DOUBLE) AS quantity, + group_concat(taskid, ';') as taskids, + group_concat(performedby, ';') as performedby FROM studyLinked.BloodSchedule bloodSch LEFT JOIN ehr_billing.aliases a ON bloodSch.account = a.alias WHERE billedBy.value = 'c' AND - qcstate.publicdata = true \ No newline at end of file + qcstate.publicdata = true + +GROUP BY id, date, project, coalesce(account, project.account.alias), coalesce(a.tier_rate.tierRate, project.account.tier_rate.tierRate); From 4aa99c6bf1f942842a83763ebbd19e0f6ca20533 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 19 Nov 2024 15:55:43 -0600 Subject: [PATCH 09/13] Revert back to original AvailBlood calculation, add new calc for future draws in the new current blood report, fix ehr blood store so all records in transaction are used --- .../BloodSchedule/Blood Schedule.qview.xml | 5 -- .../study/DailyOverDrawsWithThreshold.sql | 4 +- .../resources/queries/study/blood.query.xml | 2 +- .../study/blood/Blood Summary.qview.xml | 2 +- .../queries/study/bloodDrawChanges.sql | 4 +- .../queries/study/bloodSummary.query.xml | 36 ++++++++ .../resources/queries/study/bloodSummary.sql | 76 ++++++++++++++++ .../queries/study/currentBloodDraws.query.xml | 16 ++-- .../queries/study/currentBloodDraws.sql | 86 +++++++------------ .../study/currentBloodDraws/.qview.xml | 3 +- .../demographics/Blood Draw Info.qview.xml | 12 +-- .../study/demographicsBloodSummary.sql | 72 ++++++++++++++++ WNPRC_EHR/resources/web/ehr/ext3/ehrStore.js | 2 +- .../BloodDrawReviewDailyNotification.java | 8 +- .../notification/BloodDrawsTodayAll.java | 20 ++--- .../wnprc_ehr/table/WNPRC_EHRCustomizer.java | 2 +- 16 files changed, 255 insertions(+), 95 deletions(-) create mode 100644 WNPRC_EHR/resources/queries/study/bloodSummary.query.xml create mode 100644 WNPRC_EHR/resources/queries/study/bloodSummary.sql create mode 100644 WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql diff --git a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml index 3e8dccc9f..a889616dc 100644 --- a/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml +++ b/WNPRC_EHR/resources/queries/study/BloodSchedule/Blood Schedule.qview.xml @@ -56,11 +56,6 @@ - - - - - diff --git a/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql b/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql index e87e21f4b..9e0ef9abd 100644 --- a/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql +++ b/WNPRC_EHR/resources/queries/study/DailyOverDrawsWithThreshold.sql @@ -17,9 +17,9 @@ SELECT b.Id, b.restraintTime, b.instructions, b.restraintDuration, - b.BloodRemaining.allowableBlood, + b.BloodRemaining.AvailBlood, b.QCState, b.QCState.label FROM "Blood Draws" b LEFT JOIN ehr_lookups.species e ON e.common = b.Id.Demographics.species -WHERE b.BloodRemaining.allowableBlood < e.blood_threshold_warning AND b.date > curdate() AND b.date < cast(TIMESTAMPADD('SQL_TSI_DAY', 1, curdate()) as date) AND b.QCState.label <> 'Request: Denied' \ No newline at end of file +WHERE b.BloodRemaining.AvailBlood < e.blood_threshold_warning AND b.date > curdate() AND b.date < cast(TIMESTAMPADD('SQL_TSI_DAY', 1, curdate()) as date) AND b.QCState.label <> 'Request: Denied' \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/blood.query.xml b/WNPRC_EHR/resources/queries/study/blood.query.xml index ebb431ad8..0d4c76bd8 100644 --- a/WNPRC_EHR/resources/queries/study/blood.query.xml +++ b/WNPRC_EHR/resources/queries/study/blood.query.xml @@ -106,7 +106,7 @@ true study - currentBloodDraws + bloodSummary lsid diff --git a/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml b/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml index 2e70880c8..04a6f204a 100644 --- a/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml +++ b/WNPRC_EHR/resources/queries/study/blood/Blood Summary.qview.xml @@ -38,7 +38,7 @@ - + diff --git a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql index efb9c28f4..f91415d21 100644 --- a/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql +++ b/WNPRC_EHR/resources/queries/study/bloodDrawChanges.sql @@ -30,7 +30,7 @@ FROM ( SELECT b.id, b.dateOnly, - GROUP_CONCAT(b.status,'') as status, + b.status, sum(b.quantity) as quantity FROM ( @@ -67,5 +67,5 @@ FROM ( ) b - GROUP BY b.id, b.dateOnly + GROUP BY b.id, b.dateOnly, b.status ) b2 \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml new file mode 100644 index 000000000..2149003c5 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml @@ -0,0 +1,36 @@ + + + + + + + true + + + + Drawn in Previous 30 Days (inclusive) + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~lte=${Date}& + query.Date~gte=${minDate}& + query.sort=-Date& + + + + Scheduled in Next 30 Days (inclusive) + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~gt=${Date}& + query.sort=-Date& + + + + BloodLast30 +
+
+
+
diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql new file mode 100644 index 000000000..8661b0e72 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.sql @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010-2013 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + bq.lsid, + bq.id, + bq.date, + bq.minDate, +-- bq.maxDate, + bq.weight, + bq.lastWeighDate, + cast(bq.BloodLast30 as numeric) as BloodLast30, + bq.BloodNext30, +-- round(bq.weight*0.2*60, 1) AS MaxBlood, +-- round((bq.weight*0.2*60) - bq.BloodLast30, 1) AS AvailBlood + cast(CASE + WHEN bq.species = 'Marmoset' + THEN round(bq.weight*0.15*60, 1) + ELSE + round(bq.weight*0.2*60, 1) + END as numeric) AS MaxBlood, + cast(CASE + WHEN bq.species = 'Marmoset' + THEN round((bq.weight*0.15*60) - bq.BloodLast30, 1) + ELSE + round((bq.weight*0.2*60) - bq.BloodLast30, 1) + END AS numeric) AS AvailBlood +FROM +( + SELECT + b.*, + (select species from study.demographics d where d.id = b.id) as species, + ( + CONVERT ( + (SELECT AVG(w.weight) AS _expr + FROM study.weight w + WHERE w.id=b.id AND w.date=b.lastWeighDate + ), double ) + ) AS weight + FROM + ( + SELECT bi.* + ,timestampadd('SQL_TSI_DAY', -30, bi.date) as minDate +-- ,timestampadd('SQL_TSI_DAY', 29, bi.date) as maxDate + , ( CONVERT( + (SELECT MAX(w.date) as _expr + FROM study.weight w + WHERE w.id = bi.id + --NOTE: we are doing this comparison such that it considers date only, not datetime + --AND w.date <= bi.date + AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bi.date + ), timestamp ) + ) AS lastWeighDate + , ( COALESCE ( + (SELECT SUM(draws.quantity) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id=bi.id + AND (cast(draws.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', -30, bi.date) as date) AND cast(draws.date as date) <= cast(bi.date as date)) + --AND draws.qcstate.publicdata = true + ), 0 ) + ) AS BloodLast30, + COALESCE (( + SELECT + SUM(draws.quantity) AS _expr + FROM study."Blood Draws" draws + WHERE draws.id=bi.id AND + (cast(draws.date as date) <= cast(TIMESTAMPADD('SQL_TSI_DAY', 30, bi.date) as date) AND cast(draws.date as date) > cast(bi.date as date) ) + + ), 0) AS BloodNext30 + FROM study.blood bi + --WHERE (bi.qcstate.metadata.DraftData = true OR bi.qcstate.publicdata = true) + ) b + ) bq + diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml b/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml index ec7039ef0..cf0b8081c 100644 --- a/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.query.xml @@ -23,7 +23,7 @@
- Previous 30 Days (inclusive) + Previous 30 Days (including today) /query/executeQuery.view?schemaName=study& query.queryName=Blood Draws& query.viewName=Blood Summary& @@ -32,9 +32,10 @@ query.Date~dategte=${minDate}& query.sort=-Date& + This shows the amount of blood draws taken in the past, including today. - Next 30 Days (inclusive) + Next 30 Days (excluding today) /query/executeQuery.view?schemaName=study& query.queryName=Blood Draws& query.viewName=Blood Summary& @@ -42,6 +43,7 @@ query.Date~dategte=${Date}& query.sort=-Date& + This shows the amount of blood draws scheduled in the next 30 days after the given date. Latest Weight (kg) @@ -63,14 +65,16 @@ 20% Volume By Weight + This shows the maximum blood an animal can get drawn based on their weight. - Volume Remaining After Draw (mL) - /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + Volume Available Today (mL) + This shows the amount of blood remaining today. It includes blood draws that happened 30 days in the past up to today. - - Volume Remaining Over Next 30 Days + + Volume Remaining After All Draws (mL) /WNPRC/EHR/ehr-animalHistory.view#subjects:${Id}&inputType:singleSubject&showReport:1&activeReport:BloodSummary + This column shows the amount of blood remaining for the animal while considering future draws. It includes approved blood draws 30 days into the future and past blood draws 30 days in the past. diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql index 76fcad98a..f90605794 100644 --- a/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws.sql @@ -15,41 +15,35 @@ */ SELECT - t.id, - t.date, - t.status, - cast(t.quantity as double) as quantity, - t.species, - t.max_draw_pct, - t.blood_draw_interval, - t.blood_per_kg, - t.mostRecentWeight, - t.mostRecentWeightDate, - t.death, - cast(round(t.allowableBlood,1) as numeric) as maxAllowableBlood, - cast(t.bloodPrevious as double) as bloodPrevious, - cast((t.allowableBlood - t.bloodPrevious) as double) as allowablePrevious, + t.id, + t.date, + t.status, + cast(t.quantity as double) as quantity, + t.species, + t.max_draw_pct, + t.blood_draw_interval, + t.blood_per_kg, + t.mostRecentWeight, + t.mostRecentWeightDate, + t.death, + cast(round(t.allowableBlood,1) as numeric) as maxAllowableBlood, + cast(t.bloodPrevious as double) as bloodPrevious, + cast((t.allowableBlood - t.bloodPrevious) as double) as allowablePrevious, - cast(t.bloodFuture as double) as bloodFuture, - cast((t.allowableBlood - t.bloodFuture) as double) as allowableFuture, + cast(t.bloodFuture as double) as bloodFuture, + cast((t.allowableBlood - t.bloodFuture) as double) as allowableFuture, - --if the draw is historic, always consider previous draws only. - --otherwise, look both forward and backwards, then take the interval with the highest volume - cast(round(case - WHEN t.date < curdate() THEN (t.allowableBlood - t.bloodPrevious) - WHEN t.bloodPrevious < t.bloodFuture THEN (t.allowableBlood - t.bloodFuture) - ELSE (t.allowableBlood - t.bloodPrevious) - end , 1) as numeric) as allowableBlood, - cast( round(t.allowableBlood - ((t.bloodPrevious + t.bloodFuture) - t.bloodToday), 1) as numeric) as BloodAvailPlusThirty, - t.minDate, - t.maxDate + ROUND(CAST((t.allowableBlood - t.bloodPrevious) AS double),1) as allowableBlood, + ROUND(CAST((t.allowableBlood - t.bloodPrevious - t.bloodFuture) AS double),1) as allowableBloodIncludingFutureDraws, + t.minDate, + t.maxDate FROM ( -SELECT - bd.id, - bd.status, - bd.dateOnly as date, + SELECT + bd.id, + bd.status, + bd.dateOnly as date, bd.quantity, d.species, d.death, @@ -57,16 +51,7 @@ SELECT CONVERT ( (SELECT AVG(w.weight) AS _expr FROM study.weight w - WHERE w.id=bd.id AND w.date= - ( CONVERT( - (SELECT MAX(w.date) as _expr - FROM study.weight w - WHERE w.id = bd.id - --AND w.date <= bi.date - AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bd.dateOnly - AND w.qcstate.publicdata = true - ), timestamp ) - ) + WHERE w.id=bd.id AND w.date=d.id.mostRecentWeight.MostRecentWeightDate AND w.qcstate.publicdata = true ), double ) ) * d.species.max_draw_pct * d.species.blood_per_kg AS allowableBlood, @@ -74,16 +59,7 @@ SELECT (CONVERT ( (SELECT AVG(w.weight) AS _expr FROM study.weight w - WHERE w.id=bd.id AND w.date= - (CONVERT( - (SELECT MAX(w.date) as _expr - FROM study.weight w - WHERE w.id = bd.id - --AND w.date <= bi.date - AND CAST(CAST(w.date AS DATE) AS TIMESTAMP) <= bd.dateOnly - AND w.qcstate.publicdata = true - ), timestamp ) - ) + WHERE w.id=bd.id AND w.date=d.id.mostRecentWeight.MostRecentWeightDate AND w.qcstate.publicdata = true ), double ) ) as weight, d.id.mostRecentWeight.MostRecentWeight, @@ -108,7 +84,7 @@ SELECT FROM study."Blood Draws" draws WHERE draws.id = bd.id AND draws.dateOnly < bd.maxDate - AND draws.dateOnly >= bd.dateOnly + AND draws.dateOnly > bd.dateOnly --NOTE: this has been changed to include pending/non-approved draws AND draws.countsAgainstVolume = true ), 0) AS BloodFuture, @@ -116,13 +92,13 @@ SELECT COALESCE( (SELECT SUM(coalesce(draws.quantity, 0)) AS _expr FROM study."Blood Draws" draws - WHERE draws.id = bd.id + WHERE draws.id = bd.id AND draws.dateOnly = curdate() --NOTE: this has been changed to include pending/non-approved draws AND draws.countsAgainstVolume = true ), 0) AS BloodToday -FROM study.bloodDrawChanges bd -JOIN study.demographics d ON (d.id = bd.id) + FROM study.bloodDrawChanges bd + JOIN study.demographics d ON (d.id = bd.id) -) t \ No newline at end of file + ) t \ No newline at end of file diff --git a/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml b/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml index f72ca56dd..22719345e 100644 --- a/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml +++ b/WNPRC_EHR/resources/queries/study/currentBloodDraws/.qview.xml @@ -17,11 +17,12 @@ + + - diff --git a/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml b/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml index 96fe4b9e5..6b6dd23f8 100644 --- a/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml +++ b/WNPRC_EHR/resources/queries/study/demographics/Blood Draw Info.qview.xml @@ -34,7 +34,7 @@ - + @@ -45,24 +45,24 @@ - + - + - + - + - + diff --git a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql new file mode 100644 index 000000000..e07e90ead --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql @@ -0,0 +1,72 @@ + + +/* + * Copyright (c) 2010-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +SELECT + b.lsid, + b.id, + --b.date, + b.wdate as MostRecentWeightDate, + b.weight as MostRecentWeight, + convert(BloodLast30, float) as BloodLast30, + convert(BloodNext30, float) as BloodNext30, + convert(CASE + WHEN (b.species = 'Marmoset') + THEN (b.weight*0.15*60) + ELSE + (b.weight*0.2*60) + END, float) AS MaxBlood, + + TRUNCATE(ROUND(CAST(case + when (b.species = 'Marmoset') + THEN ((b.weight*0.15*60) - b.BloodLast30) + else + ((b.weight*0.2*60) - b.BloodNext30) + end AS NUMERIC),2),2) as AvailBlood +from ( +SELECT + d.lsid, + d.id, + d.species, +-- d.weight, +-- d.wdate, + lastWeight.date as wdate, + ( + SELECT AVG(w.weight) AS _expr + FROM study.weight w + WHERE w.id=d.id AND w.date=lastWeight.date + ) AS weight, + COALESCE (( + SELECT + SUM(bd.quantity) AS _expr + FROM study."Blood Draws" bd + WHERE bd.id=d.id AND + --bd.date BETWEEN TIMESTAMPADD('SQL_TSI_DAY', -30, now()) AND now() + (cast(bd.date as date) >= cast(TIMESTAMPADD('SQL_TSI_DAY', -30, now()) as date) AND cast(bd.date as date) <= cast(curdate() as date)) + + ), 0) AS BloodLast30, + COALESCE (( + SELECT + SUM(bd.quantity) AS _expr + FROM study."Blood Draws" bd + WHERE bd.id=d.id AND + --bd.date BETWEEN now() AND TIMESTAMPADD('SQL_TSI_DAY', 30, now()) + (cast(bd.date as date) >= cast(curdate() as date) AND cast(bd.date as date) <= cast(TIMESTAMPADD('SQL_TSI_DAY', 30, now()) as date)) + + ), 0) AS BloodNext30 + +FROM + study.demographics d + LEFT OUTER JOIN + (SELECT w.id, MAX(date) as date FROM study.weight w + GROUP BY w.id) lastWeight ON d.id = lastWeight.id + +-- WHERE b.date >= TIMESTAMPADD('SQL_TSI_DAY', -30, now()) +WHERE + +d.calculated_status = 'Alive' + +) b \ No newline at end of file diff --git a/WNPRC_EHR/resources/web/ehr/ext3/ehrStore.js b/WNPRC_EHR/resources/web/ehr/ext3/ehrStore.js index 4ce13bc69..708226c66 100644 --- a/WNPRC_EHR/resources/web/ehr/ext3/ehrStore.js +++ b/WNPRC_EHR/resources/web/ehr/ext3/ehrStore.js @@ -667,7 +667,7 @@ EHR.ext.AdvancedStore = Ext.extend(LABKEY.ext.Store, { // top-level request, rather than only per-blood. in this instance only Blood Draws.js // is using the data, but weights are a good example of something that might be // globally useful. - if (this.queryName == 'Blood Draws'){ + if (this.queryName == 'blood'){ var bloodDrawMap = {}; var allRecords = this.getAllRecords(); for (var idx = 0; idx < allRecords.length; ++idx){ diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java index ce0ca3cce..85e38961b 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawReviewDailyNotification.java @@ -229,16 +229,16 @@ void getBloodOverdraws() { // Creates sort. Sort mySort = new Sort("date"); // Creates columns to retrieve. - String[] targetColumns = new String[]{"id", "date", "BloodRemaining/allowableBlood"}; + String[] targetColumns = new String[]{"id", "date", "BloodRemaining/AvailBlood"}; // Runs query. ArrayList> unformattedUpcomingBloodDraws = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "BloodSchedule", myFilter, mySort, targetColumns); // Converts map to list (for displaying in table). for (HashMap currentDraw : unformattedUpcomingBloodDraws) { // Verifies there is data because some older blood draws don't list available blood. - if (!currentDraw.get("BloodRemaining/allowableBlood").isEmpty()) { - if (Double.valueOf(currentDraw.get("BloodRemaining/allowableBlood")) <= 0) { - String[] currentRow = {currentDraw.get("id"), currentDraw.get("date"), currentDraw.get("BloodRemaining/allowableBlood")}; + if (!currentDraw.get("BloodRemaining/AvailBlood").isEmpty()) { + if (Double.valueOf(currentDraw.get("BloodRemaining/AvailBlood")) <= 0) { + String[] currentRow = {currentDraw.get("id"), currentDraw.get("date"), currentDraw.get("BloodRemaining/AvailBlood")}; bloodOverdraws.add(currentRow); } } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java index b7b7d82fa..8030b9204 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/BloodDrawsTodayAll.java @@ -123,7 +123,7 @@ public static class BloodDrawsTodayObject { // Creates sort. Sort mySort = new Sort("date"); // Creates columns to retrieve. - String[] targetColumns = new String[]{"id", "qcstate/label", "projectStatus", "BloodRemaining/allowableBlood", "billedby/title", "Id/curLocation/room", "Id/curLocation/area"}; + String[] targetColumns = new String[]{"id", "qcstate/label", "projectStatus", "BloodRemaining/AvailBlood", "billedby/title", "Id/curLocation/room", "Id/curLocation/area"}; //Runs query. ArrayList> returnArray = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "BloodSchedule", myFilter, mySort, targetColumns); @@ -146,7 +146,7 @@ public static class BloodDrawsTodayObject { // Updates id. myCurrentRow[0] = result.get("id"); // Updates blood remaining. - myCurrentRow[1] = result.get("BloodRemaining/allowableBlood"); + myCurrentRow[1] = result.get("BloodRemaining/AvailBlood"); // Updates project status (this checks if animal is assigned to a project). if (!result.get("qcstate/label").equals("Request: Denied") && !result.get("projectStatus").isEmpty()) { myCurrentRow[2] = "UNASSIGNED"; @@ -180,25 +180,25 @@ public static class BloodDrawsTodayObject { //Updates row colors. myCurrentRow[8] = "white"; - if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { - Float allowableBlood = Float.parseFloat(result.get("BloodRemaining/allowableBlood")); - if (allowableBlood <= 0) { + if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { + Float availBlood = Float.parseFloat(result.get("BloodRemaining/AvailBlood")); + if (availBlood <= 0) { // If blood draw is over limit, color it red. myCurrentRow[8] = "red"; } - else if (allowableBlood <= bloodThreshold) { + else if (availBlood <= bloodThreshold) { // If blood draw is over threshold limit, color it orange. myCurrentRow[8] = "orange"; } } // String currentRowColor = "white"; -// if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { -// Float allowableBlood = Float.parseFloat(result.get("BloodRemaining/allowableBlood")); -// if (allowableBlood <= 0) { +// if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { +// Float availBlood = Float.parseFloat(result.get("BloodRemaining/AvailBlood")); +// if (availBlood <= 0) { // // If blood draw is over limit, color it red. // currentRowColor = "red"; // } -// else if (allowableBlood <= bloodThreshold) { +// else if (availBlood <= bloodThreshold) { // // If blood draw is over threshold limit, color it orange. // currentRowColor = "orange"; // } diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java index d9bd8c220..606830674 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/table/WNPRC_EHRCustomizer.java @@ -364,7 +364,7 @@ private void customizeAnimalTable(AbstractTableInfo ds) col10.setDescription("Calculates the total number of days each animal has been single housed, if applicable."); ds.addColumn(col10); - BaseColumnInfo bloodCol = getWrappedIdCol(us, ds, "allowableBlood", "currentBloodDraws"); + BaseColumnInfo bloodCol = getWrappedIdCol(us, ds, "AvailBlood", "demographicsBloodSummary"); bloodCol.setLabel("Blood Remaining"); bloodCol.setDescription("Calculates the total blood draw and remaining, which is determine by weight and blood drawn in the past 30 days."); ds.addColumn(bloodCol); From e977c611d54911b95f736c8d18371dd98d7b299d Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 3 Dec 2024 10:41:29 -0600 Subject: [PATCH 10/13] update notification to revert to old blood avail name, use species as lookups for blood queries --- .../queries/study/bloodSummary.query.xml | 4 ++-- .../resources/queries/study/bloodSummary.sql | 19 ++++++------------- .../study/demographicsBloodSummary.sql | 17 +++-------------- .../notification/NotificationToolkit.java | 6 +++--- 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml index 2149003c5..c5163f487 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.query.xml @@ -8,7 +8,7 @@ - Drawn in Previous 30 Days (inclusive) + Drawn in Previous 30 Days (including today) /query/executeQuery.view?schemaName=study& query.queryName=Blood Draws& query.viewName=Blood Summary& @@ -19,7 +19,7 @@ - Scheduled in Next 30 Days (inclusive) + Scheduled in Next 30 Days (excluding today) /query/executeQuery.view?schemaName=study& query.queryName=Blood Draws& query.viewName=Blood Summary& diff --git a/WNPRC_EHR/resources/queries/study/bloodSummary.sql b/WNPRC_EHR/resources/queries/study/bloodSummary.sql index 8661b0e72..1e486d444 100644 --- a/WNPRC_EHR/resources/queries/study/bloodSummary.sql +++ b/WNPRC_EHR/resources/queries/study/bloodSummary.sql @@ -15,23 +15,13 @@ SELECT bq.BloodNext30, -- round(bq.weight*0.2*60, 1) AS MaxBlood, -- round((bq.weight*0.2*60) - bq.BloodLast30, 1) AS AvailBlood - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round(bq.weight*0.15*60, 1) - ELSE - round(bq.weight*0.2*60, 1) - END as numeric) AS MaxBlood, - cast(CASE - WHEN bq.species = 'Marmoset' - THEN round((bq.weight*0.15*60) - bq.BloodLast30, 1) - ELSE - round((bq.weight*0.2*60) - bq.BloodLast30, 1) - END AS numeric) AS AvailBlood + cast(round((bq.weight*(species.max_draw_pct)*(species.blood_per_kg)), 1) as numeric) AS MaxBlood, + cast(round((bq.weight*(species.max_draw_pct)*(species.blood_per_kg)) - bq.BloodLast30, 1) AS numeric) AS AvailBlood FROM ( SELECT b.*, - (select species from study.demographics d where d.id = b.id) as species, + d.species as species, ( CONVERT ( (SELECT AVG(w.weight) AS _expr @@ -70,7 +60,10 @@ FROM ), 0) AS BloodNext30 FROM study.blood bi + --WHERE (bi.qcstate.metadata.DraftData = true OR bi.qcstate.publicdata = true) ) b + + JOIN study.demographics d ON b.id = d.id ) bq diff --git a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql index e07e90ead..fad214145 100644 --- a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql +++ b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.sql @@ -13,19 +13,8 @@ SELECT b.weight as MostRecentWeight, convert(BloodLast30, float) as BloodLast30, convert(BloodNext30, float) as BloodNext30, - convert(CASE - WHEN (b.species = 'Marmoset') - THEN (b.weight*0.15*60) - ELSE - (b.weight*0.2*60) - END, float) AS MaxBlood, - - TRUNCATE(ROUND(CAST(case - when (b.species = 'Marmoset') - THEN ((b.weight*0.15*60) - b.BloodLast30) - else - ((b.weight*0.2*60) - b.BloodNext30) - end AS NUMERIC),2),2) as AvailBlood + convert((b.weight*(b.species.max_draw_pct)*(b.species.blood_per_kg)), float) AS MaxBlood, + TRUNCATE(ROUND(CAST(((b.weight*(b.species.max_draw_pct)*(b.species.blood_per_kg)) - b.BloodLast30) AS NUMERIC),2),2) as AvailBlood from ( SELECT d.lsid, @@ -54,7 +43,7 @@ SELECT FROM study."Blood Draws" bd WHERE bd.id=d.id AND --bd.date BETWEEN now() AND TIMESTAMPADD('SQL_TSI_DAY', 30, now()) - (cast(bd.date as date) >= cast(curdate() as date) AND cast(bd.date as date) <= cast(TIMESTAMPADD('SQL_TSI_DAY', 30, now()) as date)) + (cast(bd.date as date) > cast(curdate() as date) AND cast(bd.date as date) <= cast(TIMESTAMPADD('SQL_TSI_DAY', 30, now()) as date)) ), 0) AS BloodNext30 diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java index 66d1f1d4b..34912b9f8 100644 --- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java +++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/notification/NotificationToolkit.java @@ -1035,14 +1035,14 @@ public Double checkIfBloodDrawIsOverdraw(Container c, User u, String idToCheck, SimpleFilter myFilter = new SimpleFilter("Id", idToCheck, CompareType.EQUAL); myFilter.addCondition("date", dateToCheck, CompareType.DATE_EQUAL); // Runs query. - String[] targetColumns = new String[]{"BloodRemaining/allowableBlood"}; + String[] targetColumns = new String[]{"BloodRemaining/AvailBlood"}; ArrayList> returnArray = getTableMultiRowMultiColumnWithFieldKeys(c, u, "study", "blood", myFilter, null, targetColumns); // Checks results. if (!returnArray.isEmpty()) { for (HashMap result : returnArray) { - if (!result.get("BloodRemaining/allowableBlood").isEmpty()) { - Double availableBlood = Double.valueOf(result.get("BloodRemaining/allowableBlood")); + if (!result.get("BloodRemaining/AvailBlood").isEmpty()) { + Double availableBlood = Double.valueOf(result.get("BloodRemaining/AvailBlood")); if (availableBlood <=0) { return availableBlood; } From bb19d3449d5ce0480cf26914cfa1f198c54255e5 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 3 Dec 2024 10:51:42 -0600 Subject: [PATCH 11/13] restore demographicsBloodSummary query file --- .../study/demographicsBloodSummary.query.xml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml diff --git a/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml new file mode 100644 index 000000000..d90021b23 --- /dev/null +++ b/WNPRC_EHR/resources/queries/study/demographicsBloodSummary.query.xml @@ -0,0 +1,52 @@ + + + + + + + true + true + + + true + + + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~lte=${Date}& + query.sort=-Date& + + Blood Drawn In Previous 30 Days + + + Scheduled in Next 30 Days + /query/executeQuery.view?schemaName=study& + query.queryName=Blood Draws& + query.viewName=Blood Summary& + query.Id~eq=${Id}& + query.Date~gt=${Date}& + query.sort=-Date& + + + + Max Blood Per 30 Days (mL) + + + Available Blood (mL) + + + + + + FF0000 + + + + + AvailBlood +
+
+
+
\ No newline at end of file From e2883c6eb59c55ac3d915ff5b7e73140c1426a8b Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Tue, 3 Dec 2024 10:58:50 -0600 Subject: [PATCH 12/13] update test comments --- .../src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java index 05346477c..da85269de 100644 --- a/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java +++ b/WNPRC_EHR/test/src/org/labkey/test/tests/wnprc_ehr/WNPRC_EHRTest.java @@ -4170,7 +4170,7 @@ public void insertValueIntoBloodBilledByDataset(String billingGroupRealName, Str /** * This function inserts data into the 'study/BloodSchedule' dataset. - * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/allowableBlood, billedby/title, and Id/DataSet/Demographics/calculated_status. + * This function creates the following fields in 'study/BloodSchedule': id, date, projectStatus, BloodRemaining/AvailBlood, billedby/title, and Id/DataSet/Demographics/calculated_status. * This function updates the following tables: study/demographics, study/weight, study/blood. * @param billingGroupRealName * @param animalID @@ -4200,7 +4200,7 @@ public void insertValueIntoBloodScheduleDataset(String billingGroupRealName, Str HashMap demographicInfoTestData1 = new HashMap<>(); demographicInfoTestData1.put("id", animalID); demographicInfoTestData1.put("calculated_status", livingStatus); - // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/allowableBlood'). + // Creates weight info (this updates the bloodSchedule field: 'BloodRemaining/AvailBlood'). HashMap weightTestData1 = new HashMap<>(); weightTestData1.put("id", animalID); weightTestData1.put("date", new Date()); From 636721ca34af10a2357c6737f3ef1d58376e6d55 Mon Sep 17 00:00:00 2001 From: Chad Sebranek Date: Wed, 4 Dec 2024 09:57:12 -0600 Subject: [PATCH 13/13] restore old blood draw query --- .../wnprc_billing/bloodDrawsAllTubesSPI.sql | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql b/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql index ea4fed321..fb5d7bec8 100644 --- a/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql +++ b/wnprc_billing/resources/queries/wnprc_billing/bloodDrawsAllTubesSPI.sql @@ -2,17 +2,15 @@ SELECT Id, date, project, - coalesce(account, project.account.alias) as debitedAccount, + coalesce(account, project.account.alias) AS debitedAccount, coalesce(a.tier_rate.tierRate, project.account.tier_rate.tierRate) as otherRate, - group_concat(objectid,';') as objectids, - ('Blood Draws ' || Id || ' x' || COUNT(*)) as comment, - CAST(1 AS DOUBLE) AS quantity, - group_concat(taskid, ';') as taskids, - group_concat(performedby, ';') as performedby + objectid AS sourceRecord, + ('Blood Draws ' || Id) AS comment, + CAST(1 as DOUBLE) AS quantity, + taskId, + performedby FROM studyLinked.BloodSchedule bloodSch LEFT JOIN ehr_billing.aliases a ON bloodSch.account = a.alias WHERE billedBy.value = 'c' AND - qcstate.publicdata = true - -GROUP BY id, date, project, coalesce(account, project.account.alias), coalesce(a.tier_rate.tierRate, project.account.tier_rate.tierRate); + qcstate.publicdata = true \ No newline at end of file