From e104040456564832fc4189330ba1a3ec029f97da Mon Sep 17 00:00:00 2001 From: Lakshmi Kolli <69940873+kollil@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:51:46 -0800 Subject: [PATCH 1/3] Parentage dam mismatch in Colony alert (#1643) * Added a new report in the Colony alert: Parentage Dam mismatch records * Fixed a few comments and typos --- .../study/ParentageDamMismatch.query.xml | 9 +++ .../queries/study/ParentageDamMismatch.sql | 61 ++++++++++++++++++ .../ColonyAlertsNotification.java | 64 +++++++++++++++++++ .../notification/ColonyMgmtNotification.java | 4 ++ 4 files changed, 138 insertions(+) create mode 100644 onprc_ehr/resources/queries/study/ParentageDamMismatch.query.xml create mode 100644 onprc_ehr/resources/queries/study/ParentageDamMismatch.sql diff --git a/onprc_ehr/resources/queries/study/ParentageDamMismatch.query.xml b/onprc_ehr/resources/queries/study/ParentageDamMismatch.query.xml new file mode 100644 index 000000000..5a237c10e --- /dev/null +++ b/onprc_ehr/resources/queries/study/ParentageDamMismatch.query.xml @@ -0,0 +1,9 @@ + + + + + Mismatched Genetic and Observed Dams +
+
+
+
\ No newline at end of file diff --git a/onprc_ehr/resources/queries/study/ParentageDamMismatch.sql b/onprc_ehr/resources/queries/study/ParentageDamMismatch.sql new file mode 100644 index 000000000..f9e07f467 --- /dev/null +++ b/onprc_ehr/resources/queries/study/ParentageDamMismatch.sql @@ -0,0 +1,61 @@ +/* + Added by Kolli, Feb 2026 + Refer tkt# 14114 for details + Display 4 columns: Animal Id, Area, Genetic dam, Observed dam + + Get genetic and observed dam mismatch data. + Use the following criteria, + * 1. One genetic dam per animal + * 2. Included Alive + Dead animals + * 3. Excludes animals that have a foster dam + * 4. Excludes rows where observedDam or geneticDam IS BLANK + * 5. Keeps only mismatches between observed and genetic dams + * 6. Excludes old parentage entries, enddate IS BLANK +*/ + +SELECT + d.Id, + d.Id.curLocation.area AS Area, + coalesce(p2.parent, '') as geneticDam, + coalesce(b.dam, '') as observedDam +FROM study.demographics d + + LEFT JOIN ( + SELECT + p2.Id, + MAX(p2.parent) AS parent + FROM study.parentage p2 + WHERE (p2.method = 'Genetic' OR p2.method = 'Provisional Genetic') + AND p2.relationship = 'Dam' + AND p2.enddate IS NULL + GROUP BY p2.Id +) p2 ON d.Id = p2.Id + + LEFT JOIN ( + SELECT + p3.Id, + MAX(p3.parent) AS parent + FROM study.parentage p3 + WHERE p3.relationship = 'Foster Dam' + AND p3.enddate IS NULL + GROUP BY p3.Id +) p3 ON d.Id = p3.Id + + LEFT JOIN study.birth b + ON b.Id = d.Id + +WHERE d.calculated_status.code IN ('Alive', 'Dead') AND d.qcstate = 18 + /* exclude foster-dam cases (NULL or blank only) */ + AND COALESCE(RTRIM(LTRIM(CAST(p3.parent AS VARCHAR(50)))), '') = '' + + /* exclude blank observed dam */ + AND COALESCE(RTRIM(LTRIM(CAST(b.dam AS VARCHAR(50)))), '') <> '' + + /* exclude blank genetic dam */ + AND COALESCE(RTRIM(LTRIM(CAST(p2.parent AS VARCHAR(50)))), '') <> '' + + /* mismatch observed vs genetic */ + AND COALESCE(RTRIM(LTRIM(CAST(b.dam AS VARCHAR(50)))), '') <> + COALESCE(RTRIM(LTRIM(CAST(p2.parent AS VARCHAR(50)))), '') + + diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyAlertsNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyAlertsNotification.java index 8a5363df3..3b62bd188 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyAlertsNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyAlertsNotification.java @@ -312,6 +312,70 @@ protected void roomsReportingNegativeCagesAvailable(final Container c, User u, f } } + /** + * Kollil, Jan, 2026 : + * Refer tkt# 14114 for more details + * Alert title: WARNING: There are [x total] mismatches of observed and genetic dam data requiring review + * Format: Table + * 4 columns: Animal Id, Area, Genetic dam, Observed dam + * Alert criteria: + * 1. One genetic dam per animal + * 2. Included Alive + Dead animals + * 3. Excludes animals that have a foster dam + * 4. Excludes rows where observedDam or geneticDam IS BLANK + * 5. Keeps only mismatches between observed and genetic dams + * 6. Excludes old parentage entries, enddate IS BLANK + */ + protected void mismatchedObservedAndGeneticDam(final Container c, User u, final StringBuilder msg) + { + if (QueryService.get().getUserSchema(u, c, "study") == null) { + msg.append("Warning: The study schema has not been enabled in this folder, so the alert cannot run.


"); + return; + } + + //Dam mismatch query + TableInfo ti = QueryService.get().getUserSchema(u, c, "study").getTable("ParentageDamMismatch", ContainerFilter.Type.AllFolders.create(c, u)); + TableSelector ts = new TableSelector(ti, null, null); + long count = ts.getRowCount(); + + //Get num of rows + if (count > 0) { + msg.append(" WARNING: There are " + count + " mismatches of observed and genetic dam data requiring review."); + msg.append(" Click here to view them in a grid\n"); + + //Display the report in the email + Set columns = new HashSet<>(); + columns.add(FieldKey.fromString("Id")); + columns.add(FieldKey.fromString("area")); + columns.add(FieldKey.fromString("geneticdam")); + columns.add(FieldKey.fromString("observeddam")); + + final Map colMap = QueryService.get().getColumns(ti, columns); + TableSelector ts2 = new TableSelector(ti, colMap.values(), null, null); + + msg.append("

\n"); + msg.append(""); + msg.append(""); + msg.append(""); + + ts2.forEach(object -> { + Results rs = new ResultsImpl(object, colMap); + String url = getParticipantURL(c, rs.getString("Id")); + msg.append("\n"); + msg.append(""); + msg.append(""); + msg.append(""); + msg.append(""); + }); + } + else { + msg.append(" There are NO mismatches of observed and genetic dam data. "); + } + msg.append("
Id Area Genetic Dam Observed Dam
" + PageFlowUtil.filter(rs.getString("Id")) + " " + PageFlowUtil.filter(rs.getString("area")) + "" + PageFlowUtil.filter(rs.getString("geneticdam")) + "" + PageFlowUtil.filter(rs.getString("observeddam")) + "
"); + msg.append("
\n"); + } + //End of Dam mismatch report + /** * Finds all rooms with animals of mixed viral status * Modified by Kollil, 2/17/2023 diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyMgmtNotification.java b/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyMgmtNotification.java index c7d35ab92..1ca060cad 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyMgmtNotification.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/notification/ColonyMgmtNotification.java @@ -74,6 +74,10 @@ public String getMessageBodyHTML(Container c, User u) doHousingChecks(c, u, msg); transfersYesterday(c, u, msg); roomsWithMixedViralStatus(c, u, msg); + /*Added by kollil, Jan, 2026 + Refer to tkt # 14114 + */ + mismatchedObservedAndGeneticDam(c, u, msg); livingAnimalsWithoutWeight(c, u, msg); hospitalAnimalsWithoutCase(c, u, msg); From 994dee80c58efc1daa1a2ee8ff4795101e05cafd Mon Sep 17 00:00:00 2001 From: Ohsudev <76500320+Ohsudev@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:15:47 -0700 Subject: [PATCH 2/3] 25.11 fb asb request copy from (#1651) * Modified metadata to allow copy from process to allow program to structurally display data into column order from left to right. * Modified metadata to allow copy from process to allow program to structurally display data into column order from left to right. --- .../onprc_ehr/model/sources/ASB_Services.js | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/onprc_ehr/resources/web/onprc_ehr/model/sources/ASB_Services.js b/onprc_ehr/resources/web/onprc_ehr/model/sources/ASB_Services.js index 45ff89712..b4bdc0be1 100644 --- a/onprc_ehr/resources/web/onprc_ehr/model/sources/ASB_Services.js +++ b/onprc_ehr/resources/web/onprc_ehr/model/sources/ASB_Services.js @@ -29,7 +29,7 @@ EHR.model.DataModelManager.registerMetadata('ASB_Services', { 'study.encounters': { chargetype: { defaultValue: 'DCM: ASB Services', - hidden: true + hidden: false }, date: { xtype: 'xdatetime', @@ -89,7 +89,7 @@ EHR.model.DataModelManager.registerMetadata('ASB_Services', { 'study.blood': { chargetype: { defaultValue: 'DCM: ASB Services', - hidden: true + hidden: false }, performedby: { //defaultValue: LABKEY.Security.currentUser.displayName, @@ -105,7 +105,7 @@ EHR.model.DataModelManager.registerMetadata('ASB_Services', { 'study.drug': { chargetype: { defaultValue: 'DCM: ASB Services', - hidden: true + hidden: false }, date: { xtype: 'xdatetime', @@ -147,33 +147,6 @@ EHR.model.DataModelManager.registerMetadata('ASB_Services', { } } - // Modified: 7-27-2017 R.Blasa not needed for this version - //'study.treatment_order': { - // chargetype: { - // defaultValue: 'DCM: ASB Services', - // hidden: true - // }, - // date: { - // defaultValue: new Date() - // }, - // Billable: { - // defaultValue: 'Yes', - // hidden: true - // }, - // code: { - // header: 'Agent', - // editorConfig: { - // defaultSubset: 'Research' - // } - // }, - // category: { - // defaultValue: 'Research', - // hidden: true - // }, - // remark: { - // header: 'Special Instructions', - // hidden: false - // } - //} + } }); \ No newline at end of file From 1d444b0620a4ed68586a3a07830a41bc4dfe10d9 Mon Sep 17 00:00:00 2001 From: Ohsudev <76500320+Ohsudev@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:16:50 -0700 Subject: [PATCH 3/3] =?UTF-8?q?Modified=20Research=20Procedure=20form=20to?= =?UTF-8?q?=20auto=20load=20Charge=20unit=20when=20select=E2=80=A6=20(#165?= =?UTF-8?q?0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Modified Research Procedure form to auto load Charge unit when selecting "TMB breeding" procedure. * Modified Research Procedure form to auto load Charge unit when selecting "TMB breeding" procedure. --- .../sources/ClinicalEncountersClientStore.js | 122 ++++++++++++++++++ .../ClinicalEncountersFormSection.java | 4 +- 2 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 onprc_ehr/resources/web/onprc_ehr/data/sources/ClinicalEncountersClientStore.js diff --git a/onprc_ehr/resources/web/onprc_ehr/data/sources/ClinicalEncountersClientStore.js b/onprc_ehr/resources/web/onprc_ehr/data/sources/ClinicalEncountersClientStore.js new file mode 100644 index 000000000..9c6d90360 --- /dev/null +++ b/onprc_ehr/resources/web/onprc_ehr/data/sources/ClinicalEncountersClientStore.js @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + */ +Ext4.define('ONPRC_EHR.data.ClinicalEncountersClientStore', { + extend: 'EHR.data.DataEntryClientStore', + + constructor: function(){ + this.callParent(arguments); + + this.on('add', this.onAddRecord, this); + }, + + onAddRecord: function(store, records){ + Ext4.each(records, function(record){ + this.onRecordUpdate(record, ['procedureid']); + }, this); + }, + + afterEdit: function(record, modifiedFieldNames){ + this.onRecordUpdate(record, modifiedFieldNames); + + this.callParent(arguments); + }, + + onRecordUpdate: function(record, modifiedFieldNames){ + if (record.get('procedureid')){ + modifiedFieldNames = modifiedFieldNames || []; + + var lookupRec = this.getProcedureRecord(record.get('procedureid')); + if (!lookupRec) + return; + + if (lookupRec.get('remark')&& record.get('remark')== null){ + record.beginEdit(); + record.set('remark', lookupRec.get('remark')); + record.endEdit(true); + } + + if (lookupRec.get('name')&& lookupRec.get('name')== 'TMB breeding'){ + record.beginEdit(); + record.set('chargetype', 'TMB'); + record.endEdit(true); + } + } + + if (modifiedFieldNames && (modifiedFieldNames.indexOf('Id') > -1 || modifiedFieldNames.indexOf('project') > -1 || modifiedFieldNames.indexOf('chargetype') > -1)){ + if (record.get('objectid')){ + var toApply = { + Id: record.get('Id'), + project: record.get('project'), + chargetype: record.get('chargetype') + }; + + this.storeCollection.clientStores.each(function(cs){ + if (cs.storeId == this.storeCollection.collectionId + '-' + 'encounters'){ + return; + } + + var projectField = cs.getFields().get('project'); + var chargeTypeField = cs.getFields().get('chargetype'); + var hasChanges = false; + + if (cs.getFields().get('parentid')){ + if (cs.getFields().get('Id') || cs.getFields().get('project')){ + cs.each(function(r){ + if (r.get('parentid') === record.get('objectid')){ + var obj = {}; + + if (projectField){ + if (!r.get('project') || (projectField.inheritFromParent && r.get('project') !== record.get('project'))){ + obj.project = record.get('project'); + } + } + + if (chargeTypeField){ + if (!r.get('chargetype') || (chargeTypeField.inheritFromParent && r.get('chargetype') !== record.get('chargetype'))){ + obj.chargetype = record.get('chargetype'); + } + } + + if (r.get('Id') !== record.get('Id')){ + obj.Id = record.get('Id'); + } + + if (!Ext4.Object.isEmpty(obj)){ + r.beginEdit(); + r.set(obj); + r.endEdit(true); + hasChanges = true; + } + } + }, this); + } + } + + if (hasChanges){ + cs.fireEvent('datachanged', cs); + } + }, this); + } + } + }, + + getProcedureRecord: function(procedureId){ + var procedureStore = EHR.DataEntryUtils.getProceduresStore(); + LDK.Assert.assertNotEmpty('Unable to find procedureStore from ClinicalEncountersClientStore', procedureStore); + + // If the store is not loaded this will call again. No need to do a load callback here just return undefined if not loaded. + if (LABKEY.ext4.Util.hasStoreLoaded(procedureStore)) { + var procRecIdx = procedureStore.findExact('rowid', procedureId); + LDK.Assert.assertTrue('Unable to find procedure record in ClinicalEncountersClientStore for procedureId: [' + procedureId + ']', procRecIdx > -1); + + var procedureRec = procedureStore.getAt(procRecIdx); + LDK.Assert.assertNotEmpty('Unable to find procedure record from ClinicalEncountersClientStore. ProcedureId was: [' + procedureId + ']', procedureRec); + + return procedureRec; + } + return undefined; + } +}); \ No newline at end of file diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalEncountersFormSection.java b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalEncountersFormSection.java index 90dafd050..98246d927 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalEncountersFormSection.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/dataentry/ClinicalEncountersFormSection.java @@ -33,8 +33,8 @@ public ClinicalEncountersFormSection() { super("study", "encounters", "Procedures", "ehr-gridpanel", EHRService.FORM_SECTION_LOCATION.Body); addClientDependency(ClientDependency.supplierFromPath("ehr/buttons/encounterButtons.js")); - addClientDependency(ClientDependency.supplierFromPath("ehr/data/ClinicalEncountersClientStore.js")); - setClientStoreClass("EHR.data.ClinicalEncountersClientStore"); + addClientDependency(ClientDependency.supplierFromPath("onprc_ehr/data/sources/ClinicalEncountersClientStore.js")); + setClientStoreClass("ONPRC_EHR.data.ClinicalEncountersClientStore"); //Modified 8-24-2015 Blasa Shows Template menus // setTemplateMode(TEMPLATE_MODE.NONE);