diff --git a/onprc_ehr/resources/queries/study/clinremarks/.qview.xml b/onprc_ehr/resources/queries/study/clinremarks/.qview.xml index 9f5ac339e..1196a662a 100644 --- a/onprc_ehr/resources/queries/study/clinremarks/.qview.xml +++ b/onprc_ehr/resources/queries/study/clinremarks/.qview.xml @@ -10,6 +10,8 @@ + + diff --git a/onprc_ehr/resources/web/onprc_ehr/form/field/PlanTextArea.js b/onprc_ehr/resources/web/onprc_ehr/form/field/PlanTextArea.js new file mode 100644 index 000000000..3620e5e9d --- /dev/null +++ b/onprc_ehr/resources/web/onprc_ehr/form/field/PlanTextArea.js @@ -0,0 +1,201 @@ +/** + * Created: R.Blasa on 10/25/2017. + */ +/* + * Copyright (c) 2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +Ext4.define('ONPRC_EHR.form.field.CEG_PlantextArea', { + extend: 'Ext.form.field.TextArea', + alias: 'widget.onprc_ehr-CEG_Plantextarea', + + onAnimalChange: function(){ + this.updateDisplayEl(); + }, + + onRender : function(ct, position){ + this.callParent(arguments); + + this.wrap = this.inputEl.wrap({ + tag: 'div', + cls: 'x4-form-field-wrap' + }); + + this.linkDiv = this.wrap.createChild({ + tag: 'div', + style: 'vertical-align:top;' + }, this.inputEl); + + this.linkEl = this.linkDiv.createChild({ + tag: 'a', + cls: 'labkey-text-link', + html: (this.getValue() ? 'Copy Latest CEG_Plan' : 'Edit CEG_Plan') + }); + + var panel = this.up('ehr-formpanel'); + if (panel){ + this.mon(panel, 'bindrecord', this.onAnimalChange, this, {buffer: 100}); + } + else { + LDK.Utils.logToServer({ + message: 'Unable to find ehr-formpanel in PlanTextArea' + }) + } + + var dataEntryPanel = this.up('ehr-dataentrypanel'); + if (dataEntryPanel){ + this.mon(dataEntryPanel, 'animalchange', this.onAnimalChange, this, {buffer: 100}); + } + else { + LDK.Utils.logToServer({ + message: 'Unable to find ehr-dataentrypanel in PlanTextArea' + }) + } + + this.linkEl.on('click', this.copyMostRecentCEG_Plan, this); + this.setupMask(); + }, + + setupMask: function(){ + if (this.getValue()){ + this.showTextArea(); + return; + } + + this.inputEl.setVisibilityMode(Ext4.dom.AbstractElement.DISPLAY); + this.inputEl.setVisible(false); + + this.displayEl = this.wrap.createChild({ + tag: 'div', + style: 'vertical-align:top;', + html: '' + }); + + this.displayEl.setWidth(this.width - this.labelWidth); + this.displayEl.setHeight(this.getHeight()); + + this.updateDisplayEl(); + }, + + showTextArea: function(){ + if (!this.rendered){ + return; + } + + if (this.displayEl){ + this.displayEl.remove(); + delete this.displayEl; + } + + if (this.linkEl){ + this.linkEl.update('Copy Latest CEG_Plan'); + } + + if (this.inputEl) + this.inputEl.setVisible(true); + }, + + updateDisplayEl: function(){ + if (!this.displayEl){ + return; + } + + var rec = EHR.DataEntryUtils.getBoundRecord(this); + if (rec && rec.get('Id')){ + this.getMostRecentCEG_Plan(rec, function(ret, Id){ + if (!ret || !this.displayEl){ + return; + } + + if (ret.mostRecentCeg_Plan && ret.isActive){ + this.displayEl.update(ret.mostRecentCeg_Plan); + } + else { + this.displayEl.update('Either no active case or no CEG_Plan for ' + (Id || rec.get('Id'))); + } + }); + } + else { + this.displayEl.update('No animal entered'); + } + }, + + copyMostRecentCEG_Plan: function(){ + var rec = EHR.DataEntryUtils.getBoundRecord(this); + if (!rec || !rec.get('Id')){ + Ext4.Msg.alert('Error', 'No Id Entered'); + return; + } + + Ext4.Msg.wait('Loading...'); + this.showTextArea(); + + this.getMostRecentCEG_Plan(rec, function(ret){ + Ext4.Msg.hide(); + + if (ret){ + this.setValue(ret.mostRecentCeg_Plan); + this.linkEl.update('Refresh CEG Plan'); + } + }, true); + }, + + getMostRecentCEG_Plan: function(rec, cb, alwaysUseCallback){ + var date = rec.get('date') || new Date(); + var id = rec.get('Id'); + this.pendingIdRequest = id; + + LABKEY.Query.executeSql({ + schemaName: 'study', + sql: 'SELECT c.Id, c.CEG_Plan as mostRecentCeg_Plan, c.caseid, c.caseid.category as caseCategory, c.caseid.isActive as isActive FROM study.clinRemarks c WHERE (c.category != \'Replaced SOAP\' OR c.category IS NULL) AND c.CEG_Plan IS NOT NULL AND c.Id = \'' + rec.get('Id') + '\' ORDER BY c.date DESC LIMIT 1', + failure: LDK.Utils.getErrorCallback(), + scope: this, + success: function(results){ + if (!alwaysUseCallback && id != this.pendingIdRequest){ + console.log('more recent request, aborting'); + return; + } + + if (results && results.rows && results.rows.length && results.rows[0].mostRecentCeg_Plan){ + cb.call(this, results.rows[0], results.rows[0].Id); + } + else { + cb.call(this, null, id); + } + } + }); + }, + + onDestroy : function(){ + if (this.linkEl){ + this.linkEl.removeAllListeners(); + this.linkEl.remove(); + } + + if (this.linkDiv){ + this.linkDiv.removeAllListeners(); + this.linkDiv.remove(); + } + + if (this.displayEl){ + //NOTE: no listeners were added + //this.displayEl.removeAllListeners(); + this.displayEl.remove(); + } + + if (this.wrap){ + this.wrap.remove(); + } + + this.callParent(this); + }, + + setValue: function(){ + this.callParent(arguments); + + if (this.getValue()){ + this.showTextArea(); + } + } +}); \ No newline at end of file diff --git a/onprc_ehr/resources/web/onprc_ehr/model/sources/SurgicalRounds.js b/onprc_ehr/resources/web/onprc_ehr/model/sources/SurgicalRounds.js new file mode 100644 index 000000000..b80a922ca --- /dev/null +++ b/onprc_ehr/resources/web/onprc_ehr/model/sources/SurgicalRounds.js @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +EHR.model.DataModelManager.registerMetadata('SurgicalRounds', { + allQueries: { + Id: { + editable: false, + columnConfig: { + editable: false + } + } + }, + byQuery: { + 'study.clinremarks': { + category: { + defaultValue: 'Surgery', + hidden: true + }, + hx: { + hidden: true + }, + s: { + hidden: true + }, + o: { + hidden: true + }, + a: { + hidden: true + }, + p: { + hidden: true + }, + CEG_Plan: { + hidden: true + }, + P2: { + header: 'P2', + hidden: false, + height: 75 + } + + }, + 'study.blood': { + reason: { + defaultValue: 'Clinical' + } + } + } +}); \ No newline at end of file diff --git a/onprc_ehr/resources/web/onprc_ehr/panel/ClinicalRemarkPanel.js b/onprc_ehr/resources/web/onprc_ehr/panel/ClinicalRemarkPanel.js new file mode 100644 index 000000000..6ec997600 --- /dev/null +++ b/onprc_ehr/resources/web/onprc_ehr/panel/ClinicalRemarkPanel.js @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +/** + * @cfg remarkFormat + */ +Ext4.define('ONPRC_EHR.panel.ClinicalRemarkPanel', { + extend: 'Ext.form.Panel', + alias: 'widget.onprc_ehr-clinicalremarkpanel', + + initComponent: function(){ + Ext4.apply(this, { + bodyStyle: 'padding: 5px;', + defaults: { + labelWidth: 140, + width: 550 + }, + items: [{ + xtype: 'xdatetime', + itemId: 'dateField', + fieldLabel: 'Date', + allowBlank: false, + name: 'date', + value: new Date() + },{ + xtype: 'combo', + fieldLabel: 'Remark Format', + isFormField: false, + itemId: 'remarkFormat', + displayField: 'label', + valueField: 'label', + store: { + type: 'store', + fields: ['label', 'fields', 'fieldLabels'], + data: [ + {label: 'SOAP', fields: ['s', 'o', 'a', 'p'], fieldLabels: ['S', 'O', 'A', 'P']}, + {label: 'S2', fields: ['p2'], fieldLabels: ['S2']}, + {label: 'Hx', fields: ['hx'], fieldLabels: ['Hx']}, + {label: 'Simple Remark', fields: ['remark'], fieldLabels: ['Remark']} + ] + }, + value: this.remarkFormat, + editable: false, + listeners: { + scope: this, + change: function(field){ + var panel = this.down('#remarkPanel'); + panel.removeAll(); + panel.add(this.getItems(field.store.findRecord('label', field.getValue()))); + }, + beforerender: function(field){ + if (field.getValue()){ + field.fireEvent('change', field, field.getValue()); + } + } + } + },{ + xtype: 'container', + itemId: 'remarkPanel' + }] + }); + + this.store = this.getStoreCfg(); + + this.callParent(); + }, + + getItems: function(rec){ + var fields = rec.get('fields'); + var labels = rec.get('fieldLabels'); + + var toAdd = []; + Ext4.each(fields, function(field, idx){ + toAdd.push({ + xtype: 'textarea', + fieldLabel: labels[idx], + labelWidth: 140, + name: field, + width: 550, + height: 60 + }); + }); + + return toAdd; + }, + + getStoreCfg: function(){ + return { + type: 'labkey-store', + schemaName: 'study', + queryName: 'Clinical Remarks', + filterArray: [LABKEY.Filter.create('caseId/category', 'Surgery', LABKEY.Filter.Types.EQUAL)], + columns: 'Id,date,caseid,s,o,a,p,p2,hx,remark', + maxRows: 0, + autoLoad: true + } + } +}); \ No newline at end of file diff --git a/onprc_ehr/resources/web/onprc_ehr/window/AddSurgicalCasesWindow.js b/onprc_ehr/resources/web/onprc_ehr/window/AddSurgicalCasesWindow.js new file mode 100644 index 000000000..7145bb4eb --- /dev/null +++ b/onprc_ehr/resources/web/onprc_ehr/window/AddSurgicalCasesWindow.js @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2013-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +/** + * This window will allow users to query open cases and add records to a task based on them + */ +Ext4.define('EHR.window.AddSurgicalCasesWindow', { + extend: 'EHR.window.AddClinicalCasesWindow', + caseCategory: 'Surgery', + templateName: 'Surgical Rounds', + + allowNoSelection: true, + allowReviewAnimals: false, + showAssignedVetCombo: false, + caseDisplayField: 'remark', + caseEmptyText: 'No description available', + defaultRemark: 'Surgical rounds performed.', + + initComponent: function(){ + this.callParent(arguments); + + this.obsStore = this.targetStore.storeCollection.getClientStoreByName('Clinical Observations'); + LDK.Assert.assertNotEmpty('Unable to find targetStore in AddSurgicalCasesWindow', this.obsStore); + }, + + getCases: function(button){ + Ext4.Msg.wait("Loading..."); + this.hide(); + + var casesFilterArray = this.getCasesFilterArray(); + var obsFilterArray = this.getBaseFilterArray(); + obsFilterArray.push(LABKEY.Filter.create('caseCategory', this.caseCategory, LABKEY.Filter.Types.EQUAL)); + obsFilterArray.push(LABKEY.Filter.create('caseIsActive', true, LABKEY.Filter.Types.EQUAL)); + + //find distinct animals matching criteria + var multi = new LABKEY.MultiRequest(); + + multi.add(LABKEY.Query.selectRows, { + requiredVersion: 9.1, + schemaName: 'study', + queryName: 'latestObservationsForCase', + columns: 'Id,date,category,area,observation,remark,caseid', + filterArray: obsFilterArray, + scope: this, + success: function(results){ + this.obsResults = results; + }, + failure: LDK.Utils.getErrorCallback() + }); + + multi.add(LABKEY.Query.selectRows, { + requiredVersion: 9.1, + schemaName: 'study', + queryName: 'cases', + sort: 'Id/curLocation/room_sortValue,Id/curLocation/cage_sortValue,Id,remark', + columns: 'Id,objectid,remark,lastP2,Id/curLocation/location', + filterArray: casesFilterArray, + scope: this, + success: function(results){ + this.casesResults = results; + }, + failure: LDK.Utils.getErrorCallback() + }); + + multi.send(this.onSuccess, this); + }, + + onSuccess: function(){ + if (!this.casesResults || !this.casesResults.rows || !this.casesResults.rows.length){ + Ext4.Msg.hide(); + Ext4.Msg.alert('', 'No active cases were found' + (this.down('#excludeToday').getValue() ? ', excluding those reviewed today.' : '.')); + return; + } + + LDK.Assert.assertNotEmpty('Unable to find targetStore in AddSurgicalCasesWindow', this.targetStore); + + var records = []; + var idMap = {}; + this.caseRecordMap = {}; + this.recordData = { + performedby: this.down('#performedBy').getValue(), + date: this.down('#date').getValue() + }; + + Ext4.Array.each(this.casesResults.rows, function(sr){ + var row = new LDK.SelectRowsRow(sr); + idMap[row.getValue('Id')] = row; + this.caseRecordMap[row.getValue('objectid')] = row; + + var obj = { + Id: row.getValue('Id'), + date: this.recordData.date, + category: this.caseCategory, + s: null, + o: null, + a: null, + p: null, + R2: row.getValue('lastP2'), + caseid: row.getValue('objectid'), + remark: this.defaultRemark, + performedby: this.recordData.performedby, + 'Id/curLocation/location': row.getValue('Id/curLocation/location') + }; + + records.push(this.targetStore.createModel(obj)); + }, this); + + //check for dupes + this.addRecords(records); + }, + + doAddRecords: function(records){ + var toAdd = this.checkForExistingCases(records); + this.targetStore.add(toAdd); + if (toAdd.length){ + this.processObservations(records); + } + else { + this.onComplete(); + } + }, + + processObservations: function(records){ + var previousObsMap = {}; + if (this.obsResults && this.obsResults.rows && this.obsResults.rows.length){ + Ext4.Array.forEach(this.obsResults.rows, function(sr){ + var row = new LDK.SelectRowsRow(sr); + + var caseId = row.getValue('caseid'); + if (!previousObsMap[caseId]) + previousObsMap[caseId] = []; + + previousObsMap[caseId].push({ + Id: row.getValue('Id'), + date: this.recordData.date, + performedby: this.recordData.performedby, + caseid: row.getValue('caseid'), + category: row.getValue('category'), + area: row.getValue('area'), + observation: row.getValue('observation'), + remark: row.getValue('remark') + }); + }, this); + } + + var toAdd = []; + var recordsNeedingTemplate = []; + Ext4.Array.forEach(records, function(rec){ + var caseId = rec.get('caseid'); + if (previousObsMap[caseId]){ + Ext4.Array.forEach(previousObsMap[caseId], function(obsRec){ + toAdd.push(this.obsStore.createModel(obsRec)); + }, this); + } + else { + console.log('no existing obs'); + recordsNeedingTemplate.push(rec) + } + }, this); + + if (toAdd.length){ + this.obsStore.add(toAdd); + } + + if (recordsNeedingTemplate.length){ + this.applyObsTemplate(recordsNeedingTemplate); + } + else { + Ext4.Msg.hide(); + this.close(); + } + } +}); + +EHR.DataEntryUtils.registerGridButton('ADDSURGICALCASES_Amended', function(config){ + return Ext4.Object.merge({ + text: 'Add Open Cases', + tooltip: 'Click to automatically add animals with open cases', + handler: function(btn){ + var grid = btn.up('gridpanel'); + if(!grid.store || !grid.store.hasLoaded()){ + console.log('no store or store hasnt loaded'); + return; + } + + var cellEditing = grid.getPlugin('cellediting'); + if(cellEditing) + cellEditing.completeEdit(); + + Ext4.create('EHR.window.AddSurgicalCasesWindow', { + targetStore: grid.store + }).show(); + } + }, config); +}); diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgeryRoundsRemarksFormSection.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgeryRoundsRemarksFormSection.java new file mode 100644 index 000000000..5b2b3792a --- /dev/null +++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgeryRoundsRemarksFormSection.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.onprc_ehr.dataentry; + +import org.json.JSONObject; +import org.labkey.api.ehr.EHRService; +import org.labkey.api.ehr.dataentry.DataEntryFormContext; +import org.labkey.api.ehr.dataentry.SimpleFormSection; +import org.labkey.api.view.template.ClientDependency; + +import java.util.List; + + +public class SurgeryRoundsRemarksFormSection extends SimpleFormSection +{ + public SurgeryRoundsRemarksFormSection(String label, EHRService.FORM_SECTION_LOCATION location) + { + super("study", "Clinical Remarks", label, "ehr-roundsremarksgridpanel", location); + addClientDependency(ClientDependency.supplierFromPath("ehr/plugin/ClinicalObservationsCellEditing.js")); + addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/panel/ClinicalRemarkPanel.js")); + addClientDependency(ClientDependency.supplierFromPath("ehr/grid/RoundsRemarksGridPanel.js")); + addClientDependency(ClientDependency.supplierFromPath("ehr/grid/ObservationsRowEditorGridPanel.js")); + addClientDependency(ClientDependency.supplierFromPath("ehr/plugin/ClinicalRemarksRowEditor.js")); + addClientDependency(ClientDependency.supplierFromPath("ehr/data/ClinicalObservationsClientStore.js")); + addClientDependency(ClientDependency.supplierFromPath("ehr/buttons/roundsButtons.js")); + + + + setTemplateMode(TEMPLATE_MODE.NONE); + } + + @Override + public List getTbarButtons() + { + List defaultButtons = super.getTbarButtons(); + defaultButtons.remove("COPYFROMSECTION"); + defaultButtons.remove("ADDRECORD"); + defaultButtons.remove("ADDANIMALS"); + + if (defaultButtons.contains("DELETERECORD")) + { + int idx = defaultButtons.indexOf("DELETERECORD"); + defaultButtons.remove("DELETERECORD"); + defaultButtons.add(idx, "ROUNDSDELETE"); + } + + defaultButtons.add("MARK_ROUNDS_REVIEWED"); + + return defaultButtons; + } + + @Override + public List getTbarMoreActionButtons() + { + List defaultButtons = super.getTbarMoreActionButtons(); + defaultButtons.remove("DUPLICATE"); + + return defaultButtons; + } + + @Override + public JSONObject toJSON(DataEntryFormContext ctx, boolean includeFormElements) + { + JSONObject ret = super.toJSON(ctx, includeFormElements); + + return ret; + } + + @Override + protected String getServerSort() + { + return "Id/curLocation/room,Id/curLocation/cage,Id"; + } +} diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsFormType.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsFormType.java index 9dd6206d3..0c1f87fed 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsFormType.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsFormType.java @@ -58,7 +58,12 @@ public SurgicalRoundsFormType(DataEntryFormContext ctx, Module owner) } } - addClientDependency(ClientDependency.supplierFromPath("ehr/model/sources/SurgicalRounds.js")); + addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/model/sources/SurgicalRounds.js")); + + // Added: 4-3-2026 R. Blasa + addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/form/field/Surgery_PlantextArea.js")); + + setDisplayReviewRequired(true); } diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsRemarksFormSection.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsRemarksFormSection.java index 68608d813..b02f31179 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsRemarksFormSection.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/SurgicalRoundsRemarksFormSection.java @@ -26,7 +26,7 @@ * Date: 7/7/13 * Time: 10:36 AM */ -public class SurgicalRoundsRemarksFormSection extends RoundsRemarksFormSection +public class SurgicalRoundsRemarksFormSection extends SurgeryRoundsRemarksFormSection { public SurgicalRoundsRemarksFormSection() { @@ -39,7 +39,7 @@ public SurgicalRoundsRemarksFormSection(EHRService.FORM_SECTION_LOCATION locatio setConfigSources(Collections.singletonList("Task")); addClientDependency(ClientDependency.supplierFromPath("ehr/window/AddClinicalCasesWindow.js")); - addClientDependency(ClientDependency.supplierFromPath("ehr/window/AddSurgicalCasesWindow.js")); + addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/window/AddSurgicalCasesWindow.js")); addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/window/BulkChangeCasesWindow.js")); _showLocation = true; @@ -49,7 +49,7 @@ public SurgicalRoundsRemarksFormSection(EHRService.FORM_SECTION_LOCATION locatio public List getTbarButtons() { List defaultButtons = super.getTbarButtons(); - defaultButtons.add(0, "ADDSURGICALCASES"); + defaultButtons.add(0, "ADDSURGICALCASES_Amended"); defaultButtons.add("BULK_CHANGE_CASES"); return defaultButtons; diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/table/ONPRC_EHRCustomizer.java b/onprc_ehr/src/org/labkey/onprc_ehr/table/ONPRC_EHRCustomizer.java index 7f95381d7..9ed8744a6 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/table/ONPRC_EHRCustomizer.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/table/ONPRC_EHRCustomizer.java @@ -1356,6 +1356,17 @@ private void appendLatestHxCol(AbstractTableInfo ti) recentP2.setDisplayWidth("200"); ti.addColumn(recentP2); + //Last recorded p2 specifically designed for Surgery cases + SQLFragment lastp2Sql = new SQLFragment("(SELECT " + prefix + " (" + "r.p2" + ") as _expr FROM " + realTable.getSelectName() + + " r WHERE " + + " r.caseid = " + ExprColumn.STR_TABLE_ALIAS + ".objectid AND " + + " r.participantId = " + ExprColumn.STR_TABLE_ALIAS + ".participantId AND (r.category != ? OR r.category IS NULL) ORDER BY r.date desc " + suffix + ")", ONPRC_EHRManager.REPLACED_SOAP); + ExprColumn lastP2 = new ExprColumn(ti, "lastP2", lastp2Sql, JdbcType.VARCHAR, objectId); + lastP2.setLabel("S2"); + lastP2.setDescription("This column will display the last P2 recorded corresponding to a case for the animal."); + lastP2.setDisplayWidth("200"); + ti.addColumn(lastP2); + //uses caseId. this is a proxy for rounds SQLFragment recentRemarkSql = new SQLFragment("(SELECT " + prefix + " (" + "r.remark" + ") as _expr FROM " + realTable.getSelectName() + " r WHERE "