diff --git a/mcc/package-lock.json b/mcc/package-lock.json index d8baa823b..68c3ae536 100644 --- a/mcc/package-lock.json +++ b/mcc/package-lock.json @@ -11317,12 +11317,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -11510,9 +11507,9 @@ } }, "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dependencies": { "minimist": "^1.2.0" }, @@ -24057,12 +24054,9 @@ "dev": true }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonfile": { "version": "6.1.0", @@ -24217,9 +24211,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "requires": { "minimist": "^1.2.0" } diff --git a/mcc/resources/data/death_cause.tsv b/mcc/resources/data/death_cause.tsv new file mode 100644 index 000000000..a7fe3a6b7 --- /dev/null +++ b/mcc/resources/data/death_cause.tsv @@ -0,0 +1,26 @@ +value title category description sort_order date_disabled +Spontaneous Death 1 +Sudden Infant Death 5 +Accidental Death 13 +Death Due to Fight 14 +Acute Surgical Death 6 +Postoperative Death 7 +Dead On Arrival 15 +Unplanned Experimental Death 8 +Perinatal Death 2 +Postpartum Death 9 +Death in Quarantine 12 +Undetermined Cause 10 +Unclassified Cause 11 +Abortion ( < 130 days gestation ) 17 +Spontaneous Death, Experimental subject 22 +Neonatal death (<28 days of age, breathed once) 28 +Spontaneous Death in quarantine 24 +Stillbirth ( > 130 days gestation, never breathed) 16 +Cause of Death Unknown 99 +EUTHANASIA, EXPERIMENTAL 3 +EUTHANASIA, NONEXPERIMENTAL 4 +EUTHANASIA, QUARANTINE 3 +Medical Termination 30 +Miscarriage 32 +Biochemical Pregnancy 35 diff --git a/mcc/resources/referenceStudy/study/datasets/datasets_manifest.xml b/mcc/resources/referenceStudy/study/datasets/datasets_manifest.xml index b6f22d8d5..bab0de73a 100644 --- a/mcc/resources/referenceStudy/study/datasets/datasets_manifest.xml +++ b/mcc/resources/referenceStudy/study/datasets/datasets_manifest.xml @@ -37,13 +37,13 @@ - + - + diff --git a/mcc/resources/views/populateData.html b/mcc/resources/views/populateData.html index b9628b62e..d9337b2ef 100644 --- a/mcc/resources/views/populateData.html +++ b/mcc/resources/views/populateData.html @@ -178,6 +178,13 @@ schemaName: 'ehr_lookups', queryName: 'conc_units', pk: 'rowid' + },{ + label: 'Death Cause', + populateFn: 'populateFromFile', + moduleName: 'mcc', + schemaName: 'ehr_lookups', + queryName: 'death_cause', + pk: 'rowid' },{ label: 'Dosage Units', populateFn: 'populateFromFile', diff --git a/mcc/resources/web/mcc/panel/MccImportPanel.js b/mcc/resources/web/mcc/panel/MccImportPanel.js index d3a9b20ca..f2a385072 100644 --- a/mcc/resources/web/mcc/panel/MccImportPanel.js +++ b/mcc/resources/web/mcc/panel/MccImportPanel.js @@ -652,6 +652,14 @@ Ext4.define('MCC.panel.MccImportPanel', { parsedRows: parsedRows, panel: this } + },{ + text: 'Process Missing IDs', + action: this.processMissingIds, + rowData: { + colArray: colArray, + parsedRows: parsedRows, + panel: this + } }], columns: columns }); @@ -663,6 +671,302 @@ Ext4.define('MCC.panel.MccImportPanel', { } }, + processMissingIds: function(e, dt, node, config) { + Ext4.Msg.wait('Loading...'); + + var idToColony = {}; + var colonyToId = {}; + config.rowData.parsedRows.forEach(function(row){ + idToColony[row.Id] = row.colony; + + if (!colonyToId[row.colony]) { + colonyToId[row.colony] = []; + } + + colonyToId[row.colony].push(row.Id); + }); + + var missingIds = [] + var multi = new LABKEY.MultiRequest(); + for (var colony in colonyToId) { + multi.add(LABKEY.Query.selectRows, { + schemaName: 'study', + queryName: 'demographics', + columns: 'Id,colony,objectid,lsid,calculated_status', + filterArray: [ + LABKEY.Filter.create('colony', colony, LABKEY.Filter.Types.EQUAL), + LABKEY.Filter.create('calculated_status', 'Alive', LABKEY.Filter.Types.EQUAL), + LABKEY.Filter.create('Id', colonyToId[colony].join(';'), LABKEY.Filter.Types.NOT_IN) + ], + scope: this, + failure: LDK.Utils.getErrorCallback(), + success: function (results) { + if (results.rows.length) { + missingIds = missingIds.concat(results.rows); + } + } + }); + } + + multi.send(function(){ + Ext4.Msg.hide(); + if (missingIds.length) { + Ext4.create('Ext.window.Window', { + bodyStyle: 'padding: 5px;', + width: 600, + modal: true, + title: 'Reconcile Census with Existing IDs', + effectiveDate: config.rowData.panel.IMPORT_DATE, + defaults: { + labelWidth: 200, + width: 575, + }, + items: [{ + html: 'The following IDs are listed for the indicated colony, but were not in your census. Choose any status updates and hit submit:', + border: false, + style: 'padding-bottom: 10px;' + },{ + layout: { + type: 'table', + columns: 4 + }, + border: false, + defaults: { + border: false, + bodyStyle: 'padding: 5px' + }, + items: config.rowData.panel.getAnimalRows(missingIds) + }], + buttons: [{ + text: 'Update IDs', + scope: this, + handler: function(btn) { + var demographicsUpdates = []; + var deathInserts = []; + var departureInserts = []; + var win = btn.up('window'); + + var missingValues = false; + win.query('combo[dataIndex="status_code"]').forEach(function(f){ + if (f.getValue() && f.getValue() !== f.sourceRecord.calculated_status) { + var fields = win.query('field[recordIdx=' + f.recordIdx + ']'); + LDK.Assert.assertEquality('Incorrect number of MccImportPanel fields', 3, fields.length); + + var dateVal = fields[1].getValue(); + var otherVal = fields[2].getValue(); + if (!dateVal || !otherVal) { + missingValues = true; + return false; + } + + if (f.getValue() === 'Dead') { + deathInserts.push({ + Id: f.sourceRecord.Id, + objectId: null, + QCStateLabel: 'Completed', + QCState: null, + date: dateVal, + cause: otherVal + }); + } else if (f.getValue() === 'Shipped') { + departureInserts.push({ + Id: f.sourceRecord.Id, + objectId: null, + QCStateLabel: 'Completed', + QCState: null, + date: dateVal, + destination: otherVal + }); + } else { + // Handle unknown: + demographicsUpdates.push({ + Id: f.sourceRecord.Id, + calculated_status: f.getValue(), + lsid: f.sourceRecord.lsid, + objectid: f.sourceRecord.objectid + }); + } + } + }); + + if (missingValues) { + Ext4.Msg.alert('Error', 'One or more fields is missing a value'); + return; + } + + var commands = []; + if (demographicsUpdates.length) { + commands.push({ + command: 'update', + schemaName: 'study', + queryName: 'demographics', + rows: demographicsUpdates + }); + } + + if (departureInserts.length) { + commands.push({ + type: 'insert', + schemaName: 'study', + queryName: 'departure', + rows: departureInserts + }); + } + + if (deathInserts.length) { + commands.push({ + command: 'insert', + schemaName: 'study', + queryName: 'deaths', + rows: deathInserts + }); + } + + if (!commands.length) { + Ext4.Msg.alert('No updates', 'No changes, nothing to do'); + btn.up('window').close(); + } + else { + Ext4.Msg.wait('Saving rows...'); + LABKEY.Query.saveRows({ + commands: commands, + scope: this, + success: function() { + Ext4.Msg.hide(); + Ext4.Msg.alert('Success', 'Records updated', function(){ + btn.up('window').close(); + }, this); + }, + failure: LDK.Utils.getErrorCallback() + }); + } + } + + },{ + text: 'Cancel', + handler: function(btn) { + btn.up('window').close(); + } + }] + }).show(); + } + else { + Ext4.Msg.alert('No missing IDs', 'All existing IDs from these colonies were present in this census, nothing to do'); + } + }, this); + }, + + getAnimalRows: function(missingIds) { + var ret = [{ + xtype: 'displayfield', + width: 125, + value: 'Animal Id' + }, { + xtype: 'displayfield', + width: 100, + value: 'Status' + }, { + xtype: 'displayfield', + width: 100, + value: 'Date' + },{ + xtype: 'displayfield', + width: 125, + value: 'Destination/Cause' + }]; + + Ext4.Array.forEach(missingIds, function(r, idx){ + ret = ret.concat([{ + xtype: 'displayfield', + width: 125, + value: r.Id + ' / ' + r.colony + }, { + xtype: 'ldk-simplecombo', + storeValues: Ext4.Array.unique([r.calculated_status, 'Alive', 'Dead', 'Shipped', 'Unknown']), + recordIdx: idx, + dataIndex: 'status_code', + forceSelection: true, + sourceRecord: r, + width: 100, + style: 'margin-right: 5px', + value: r.calculated_status, + listeners: { + render: function (f) { + if (f.getValue()) { + f.fireEvent('change', f, f.getValue()); + } + }, + change: function (field, val) { + var target1 = field.up('panel').down('container[recordIdx=' + field.recordIdx + '][areaType="date"]'); + target1.removeAll(); + + var target2 = field.up('panel').down('container[recordIdx=' + field.recordIdx + '][areaType="other"]'); + target2.removeAll(); + + var effectiveDate = field.up('window').effectiveDate; + + if (val === 'Shipped') { + target1.add({ + xtype: 'datefield', + dataIndex: 'date', + labelAlign: 'top', + recordIdx: field.recordIdx, + style: 'margin-right: 5px', + value: effectiveDate + }); + + target2.add({ + xtype: 'ldk-simplelabkeycombo', + dataIndex: 'destination', + labelAlign: 'top', + recordIdx: field.recordIdx, + schemaName: 'ehr_lookups', + queryName: 'source', + valueField: 'code', + displayField: 'code', + forceSelection: true, + plugins: ['ldk-usereditablecombo'] + }); + } + else if (val === 'Dead') { + target1.add({ + xtype: 'datefield', + dataIndex: 'date', + labelAlign: 'top', + recordIdx: field.recordIdx, + style: 'margin-right: 5px', + value: effectiveDate + }); + + target2.add({ + xtype: 'ldk-simplelabkeycombo', + dataIndex: 'cause', + labelAlign: 'top', + recordIdx: field.recordIdx, + schemaName: 'ehr_lookups', + queryName: 'death_cause', + valueField: 'value', + displayField: 'value', + forceSelection: true, + plugins: ['ldk-usereditablecombo'] + }); + } + } + } + },{ + xtype: 'container', + recordIdx: idx, + areaType: 'date' + },{ + xtype: 'container', + recordIdx: idx, + areaType: 'other' + }]); + }); + + return(ret); + }, + onSubmit: function(e, dt, node, config){ Ext4.Msg.wait('Saving...'); var rawData = config.rowData.parsedRows; diff --git a/mcc/resources/web/mcc/window/MarkShippedWindow.js b/mcc/resources/web/mcc/window/MarkShippedWindow.js index 1302f5476..14245b422 100644 --- a/mcc/resources/web/mcc/window/MarkShippedWindow.js +++ b/mcc/resources/web/mcc/window/MarkShippedWindow.js @@ -121,6 +121,7 @@ Ext4.define('MCC.window.MarkShippedWindow', { return; } + var targetFolderId = win.down('#targetFolder').store.findRecord('Path', targetFolder).get('EntityId'); Ext4.Msg.wait('Saving...'); LABKEY.Query.selectRows({ schemaName: 'study', @@ -140,7 +141,9 @@ Ext4.define('MCC.window.MarkShippedWindow', { var newId = win.down('#newId').getValue() || row.Id; var commands = []; - if (!row['Id/MostRecentDeparture/MostRecentDeparture']) { + + var shouldAddDeparture = !row['Id/MostRecentDeparture/MostRecentDeparture'] || row['Id/MostRecentDeparture/MostRecentDeparture'] !== Ext4.Date.format(row.effectiveDate, 'Y-m-d') || row.Id !== newId; + if (shouldAddDeparture) { commands.push({ command: 'insert', schemaName: 'study', @@ -149,6 +152,7 @@ Ext4.define('MCC.window.MarkShippedWindow', { Id: row.Id, date: effectiveDate, destination: centerName, + description: row.colony ? 'Original center: ' + row.colony : null, qcstate: null, objectId: null, QCStateLabel: 'Completed' @@ -156,52 +160,102 @@ Ext4.define('MCC.window.MarkShippedWindow', { }); } - commands.push({ - command: 'insert', - containerPath: targetFolder, - schemaName: 'study', - queryName: 'Demographics', - rows: [{ - Id: newId, - date: effectiveDate, - alternateIds: row.Id !== newId ? row.Id : null, - gender: row.gender, - species: row.species, - birth: row.birth, - death: row.death, - dam: row.dam, - sire: row.sire, - colony: centerName, - source: row.colony, - calculated_status: 'Alive', - skipMccAliasCreation: true, - QCState: null, - QCStateLabel: 'Completed', - objectId: null - }] - }); + // If going to a new LK folder, we're creating a whole new record: + if (targetFolderId.toUpperCase() !== LABKEY.Security.currentContainer.id.toUpperCase() || newId !== row.Id) { + commands.push({ + command: 'insert', + containerPath: targetFolder, + schemaName: 'study', + queryName: 'Demographics', + rows: [{ + Id: newId, + date: effectiveDate, + alternateIds: row.Id !== newId ? row.Id : null, + gender: row.gender, + species: row.species, + birth: row.birth, + death: row.death, + dam: row.dam, + sire: row.sire, + colony: centerName, + source: row.colony, + calculated_status: 'Alive', + skipMccAliasCreation: true, + QCState: null, + QCStateLabel: 'Completed', + objectId: null + }] + }); - commands.push({ - command: 'insert', - containerPath: targetFolder, - schemaName: 'mcc', - queryName: 'animalMapping', - rows: [{ - subjectname: newId, - externalAlias: row['Id/mccAlias/externalAlias'] - }] - }); + commands.push({ + command: 'update', + containerPath: null, //Use current folder + schemaName: 'study', + queryName: 'Demographics', + rows: [{ + Id: newId, + excludeFromCensus: true + }] + }); + } + else { + // Otherwise update the existing: + commands.push({ + command: 'update', + containerPath: targetFolder, + schemaName: 'study', + queryName: 'Demographics', + rows: [{ + Id: newId, + date: effectiveDate, + alternateIds: row.Id !== newId ? row.Id : null, + gender: row.gender, + species: row.species, + birth: row.birth, + death: row.death, + dam: row.dam, + sire: row.sire, + colony: centerName, + source: row.colony, + calculated_status: 'Alive', + skipMccAliasCreation: true, + QCState: null, + QCStateLabel: 'Completed', + objectId: null + }] + }); - commands.push({ - command: 'update', - containerPath: null, //Use current folder - schemaName: 'study', - queryName: 'Demographics', - rows: [{ - Id: newId, - excludeFromCensus: true - }] - }); + // And also add an arrival record. NOTE: set the date after the departure to get status to update properly + var arrivalDate = new Date(effectiveDate).setMinutes(effectiveDate.getMinutes() + 1); + commands.push({ + command: 'insert', + containerPath: targetFolder, + schemaName: 'study', + queryName: 'Arrival', + rows: [{ + Id: newId, + date: arrivalDate, + source: centerName, + QCState: null, + QCStateLabel: 'Completed', + objectId: null + }] + }); + } + + // Do this insert if we're using a new container, or if the animal is being assigned a new ID + if (targetFolderId.toUpperCase() !== LABKEY.Security.currentContainer.id.toUpperCase() || newId !== row.Id) { + commands.push({ + command: 'insert', + containerPath: targetFolder, + schemaName: 'mcc', + queryName: 'animalMapping', + rows: [{ + subjectname: newId, + externalAlias: row['Id/mccAlias/externalAlias'] + }] + }); + } LABKEY.Query.saveRows({ commands: commands, diff --git a/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java b/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java index cf1163020..21beaf35d 100644 --- a/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java +++ b/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java @@ -16,6 +16,7 @@ package org.labkey.test.tests.mcc; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Before; @@ -65,6 +66,15 @@ public void testMccModule() throws Exception testAnimalImportAndTransfer(); } + private static final String ANIMAL_DATA_HEADER = "animal ID\tprevious IDs\tsource\t\"DOB\n(MM/DD/YYYY)\"\tsex\tmaternal ID\tpaternal ID\t\"weight(grams)\"\t\"date of weight\n(MM/DD/YY)\"\tU24 status\tavailalble to transfer\tcurrent housing status\tinfant history\tfertility status\tmedical history\n"; + + private static final String ANIMAL_DATA1 = "Animal1\t\t\t7/10/2011\t0 - male\tDam1\tSire1\t382.8\t5/19/2021\t0 - not assigned to U24 breeding colony\t0 - not available for transfer\t1 - natal family group\t3 - successful rearing of offspring\t2 - successful offspring produced\t0 - naive animal\n"; + + + private static final String ANIMAL_DATA2 = "Animal2\t\t\t6/3/2015\t1 - female\tDam2\tSire2\t361.2\t1/28/2021\t0 - not assigned to U24 breeding colony\t0 - not available for transfer\t2 - active breeding\t3 - successful rearing of offspring\t2 - successful offspring produced\t0 - naive animal\n"; + + private static final String ANIMAL_DATA3 = "Animal3\t\t\t6/4/2015\t1 - female\tDam2\tSire2\t361.2\t1/28/2021\t0 - not assigned to U24 breeding colony\t0 - not available for transfer\t2 - active breeding\t3 - successful rearing of offspring\t2 - successful offspring produced\t0 - naive animal"; + private void testAnimalImportAndTransfer() throws Exception { beginAt(getProjectName() + "/Colonies/SNPRC/project-begin.view"); @@ -72,11 +82,7 @@ private void testAnimalImportAndTransfer() throws Exception waitForElement(Locator.tagWithText("label", "Paste Data Below:")); Ext4FieldRef.getForLabel(this, "Center/Colony Name").setValue("SNPRC"); - Ext4FieldRef.getForLabel(this, "Paste Data Below").setValue( - "animal ID\tprevious IDs\tsource\t\"DOB\n(MM/DD/YYYY)\"\tsex\tmaternal ID\tpaternal ID\t\"weight(grams)\"\t\"date of weight\n(MM/DD/YY)\"\tU24 status\tavailalble to transfer\tcurrent housing status\tinfant history\tfertility status\tmedical history\n" + - "Animal1\t\t\t7/10/2011\t0 - male\tDam1\tSire1\t382.8\t5/19/2021\t0 - not assigned to U24 breeding colony\t0 - not available for transfer\t1 - natal family group\t3 - successful rearing of offspring\t2 - successful offspring produced\t0 - naive animal\n" + - "Animal2\t\t\t6/3/2015\t1 - female\tDam2\tSire2\t361.2\t1/28/2021\t0 - not assigned to U24 breeding colony\t0 - not available for transfer\t2 - active breeding\t3 - successful rearing of offspring\t2 - successful offspring produced\t0 - naive animal" - ); + Ext4FieldRef.getForLabel(this, "Paste Data Below").setValue(ANIMAL_DATA_HEADER + ANIMAL_DATA1 + ANIMAL_DATA2 + ANIMAL_DATA3); waitAndClick(Ext4Helper.Locators.ext4Button("Preview")); waitForElement(Locator.tagWithText("td", "Animal2").withClass("dt-center")); @@ -138,6 +144,90 @@ private void testAnimalImportAndTransfer() throws Exception srr.getRows().forEach(row -> { Assert.assertEquals("Incorrect QCState", "Completed", row.get("QCState/Label")); }); + + // Now try a within-folder transfer: + dr = DataRegionTable.DataRegion(getDriver()).withName("Dataset").waitFor(); + dr.checkCheckbox(0); //Animal2 + dr.clickHeaderMenu("More Actions", false, "Mark Animal Shipped"); + + new Window.WindowFinder(getDriver()).withTitle("Mark ID Shipped").waitFor(); + Ext4FieldRef.getForLabel(this, "Effective Date").setValue(new SimpleDateFormat("MM/dd/yyyy").format(new Date())); + combo = Ext4ComboRef.getForLabel(this, "Destination Center Name"); + combo.clickTrigger(); + waitAndClick(Locator.tagContainingText("li", "Other")); + + dialog = new Window.WindowFinder(getDriver()).withTitle("Enter Value").waitFor(); + dialog.findElement(Locator.tag("input")).sendKeys("TargetColony2"); + waitAndClick(Ext4Helper.Locators.ext4Button("OK")); + sleep(100); + + Ext4ComboRef.getForLabel(this, "Target Folder").setComboByDisplayValue("Other"); + waitAndClick(Ext4Helper.Locators.ext4Button("Submit")); + + new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); + waitAndClickAndWait(Ext4Helper.Locators.ext4Button("OK")); + + dr = DataRegionTable.DataRegion(getDriver()).withName("Dataset").waitFor(); + Assert.assertEquals("Incorrect ID", "Animal2", dr.getDataAsText(0, "Id")); + Assert.assertEquals("Incorrect Alias", mccId, dr.getDataAsText(0, "MCC Alias")); + Assert.assertEquals("Incorrect Status", "", dr.getDataAsText(0, "Status")); + Assert.assertEquals("Incorrect Status", "Dam2", dr.getDataAsText(0, "Dam")); + Assert.assertEquals("Incorrect Status", "Sire2", dr.getDataAsText(0, "Sire")); + Assert.assertNull("Incorrect Value", StringUtils.trimToNull(dr.getDataAsText(0, "Exclude From Census?"))); + Assert.assertEquals("Incorrect Colony", "TargetColony2", dr.getDataAsText(0, "colony")); + Assert.assertEquals("Incorrect Colony", "TargetColony", dr.getDataAsText(0, "source")); + + sr = new SelectRowsCommand("study", "departure"); + sr.setColumns(Arrays.asList("Id", "QCState/Label")); + sr.setFilters(Arrays.asList(new Filter("Id", "Animal2"))); + srr = sr.execute(createDefaultConnection(), getProjectName() + "/Colonies/Other"); + Assert.assertEquals("Incorrect number of departures", 1, srr.getRowCount().intValue()); + srr.getRows().forEach(row -> { + Assert.assertEquals("Incorrect QCState", "Completed", row.get("QCState/Label")); + }); + + // Now check status update: + populateLookups("SNPRC"); //status is needed for this to work + beginAt(getProjectName() + "/Colonies/SNPRC/project-begin.view"); + waitAndClickAndWait(Locator.tagWithText("a", "Import Excel-Based Data")); + waitForElement(Locator.tagWithText("label", "Paste Data Below:")); + Ext4FieldRef.getForLabel(this, "Center/Colony Name").setValue("SNPRC"); + + Ext4FieldRef.getForLabel(this, "Paste Data Below").setValue(ANIMAL_DATA_HEADER + ANIMAL_DATA1); + + waitAndClick(Ext4Helper.Locators.ext4Button("Preview")); + waitForElement(Locator.tagWithText("td", "Animal1").withClass("dt-center")); + + waitAndClick(getButton("Process Missing IDs")); + new Window.WindowFinder(getDriver()).withTitle("Reconcile Census with Existing IDs").waitFor(); + + String comboQuery = "combo[dataIndex='status_code']"; + Ext4ComboRef.waitForComponent(this, comboQuery); + Ext4ComboRef statusCombo = _ext4Helper.queryOne(comboQuery, Ext4ComboRef.class); + statusCombo.setComboByDisplayValue("Dead"); + + String comboQuery2 = "combo[dataIndex='cause']"; + Ext4ComboRef.waitForComponent(this, comboQuery2); + Ext4ComboRef causeCombo = _ext4Helper.queryOne(comboQuery2, Ext4ComboRef.class); + causeCombo.setComboByDisplayValue("Cause of Death Unknown"); + + waitAndClick(Ext4Helper.Locators.ext4Button("Update IDs")); + sleep(100); + new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); + waitAndClick(Ext4Helper.Locators.ext4Button("OK")); + + sr = new SelectRowsCommand("study", "demographics"); + sr.setColumns(Arrays.asList("Id", "calculated_status")); + sr.setFilters(Arrays.asList(new Filter("Id", "Animal3"))); + srr = sr.execute(createDefaultConnection(), getProjectName() + "/Colonies/SNPRC"); + Assert.assertEquals("Incorrect status", "Dead", srr.getRows().get(0).get("calculated_status")); + + sr = new SelectRowsCommand("study", "deaths"); + sr.setColumns(Arrays.asList("Id", "cause")); + sr.setFilters(Arrays.asList(new Filter("Id", "Animal3"))); + srr = sr.execute(createDefaultConnection(), getProjectName() + "/Colonies/SNPRC"); + Assert.assertEquals("No death record", 1, srr.getRowCount().intValue()); + Assert.assertEquals("Incorrect cause", "Cause of Death Unknown", srr.getRows().get(0).get("cause")); } private static class FormElement @@ -678,6 +768,8 @@ private void doRequestFormTestWithFailure() throws Exception assertElementNotPresent(getButton("Save")); assertElementNotPresent(getButton("Submit")); assertElementNotPresent(getButton("Approve Request")); + + stopImpersonating(); } private FormElement getFormElementByName(String name) @@ -767,11 +859,23 @@ private void doSetup() throws Exception } } + private void populateLookups(String name) + { + beginAt(getProjectName() + "/Colonies/" + name + "/project-begin.view"); + waitAndClickAndWait(Locator.tagWithText("a", "Populate Lookups")); + waitAndClick(Ext4Helper.Locators.ext4Button("Populate Lookup Sets")); + waitForElement(Locator.tagWithText("div", "Populating lookup_sets...")); + waitForElement(Locator.tagWithText("div", "Populate Complete")); + + waitAndClick(Ext4Helper.Locators.ext4Button("Populate All")); + waitForElement(Locator.tagWithText("div", "Populate Complete")); + } + private void testInvalidId() { beginAt("/mcc/" + getProjectName() + "/animalRequest.view?requestId=foo"); - assertElementPresent(Locator.tagWithText("div", "There is no request with id: foo")); + waitForElement(Locator.tagWithText("div", "There is no request with id: foo")); } diff --git a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java index d43cfbc7d..d4a798c2b 100644 --- a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java +++ b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java @@ -204,10 +204,10 @@ private void processVloupeFile(JobContext ctx, File perCellTsv, Readset rs, Reco parameters.basename = FileUtil.makeLegalName(rs.getName()); parameters.allowableHtoBarcodes = htosPerReadset; - // If demuxEM used: - if (parameters.methods.contains(CellHashingService.CALLING_METHOD.demuxem) || parameters.consensusMethods.contains(CellHashingService.CALLING_METHOD.demuxem)) + // If demuxEM/demuxmix used: + if (CellHashingService.CALLING_METHOD.requiresH5(parameters.methods) || CellHashingService.CALLING_METHOD.requiresH5(parameters.consensusMethods)) { - ctx.getLogger().debug("demuxEM is used, adding H5 file"); + ctx.getLogger().debug("demuxEM/demuxmix is used, adding H5 file"); if (genomeId == null) { genomeId = ctx.getSequenceSupport().getCachedGenomes().iterator().next().getGenomeId();