diff --git a/changes/change_stopped_release.md b/changes/change_stopped_release.md new file mode 100644 index 00000000..24cda65f --- /dev/null +++ b/changes/change_stopped_release.md @@ -0,0 +1 @@ +Release approval and release steps are now required even for stopped cases diff --git a/changes/fix_stopped_overdue.md b/changes/fix_stopped_overdue.md new file mode 100644 index 00000000..668fc321 --- /dev/null +++ b/changes/fix_stopped_overdue.md @@ -0,0 +1 @@ +Steps that were skipped due to the case being stopped could still be shown as overdue diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseFilterKey.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseFilterKey.java index 9e716f58..ff71f7f5 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseFilterKey.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseFilterKey.java @@ -20,7 +20,9 @@ public enum CaseFilterKey { || kase.getDonor().getExternalName().toLowerCase().contains(string.toLowerCase())), PENDING(string -> { PendingState state = getState(string); - Predicate notStoppedOrPaused = kase -> !kase.getRequisition().isStopped() && !kase.getRequisition().isPaused(); + Predicate notStoppedOrPaused = kase -> + (!state.isStoppable() || !kase.getRequisition().isStopped()) + && !kase.getRequisition().isPaused(); return notStoppedOrPaused.and(state.predicate()); }) { @Override diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSort.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSort.java index 0089a639..726fa614 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSort.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSort.java @@ -16,7 +16,7 @@ public enum CaseSort { @Override public Comparator comparator(Map assaysById) { return (a, b) -> { - // If one case is inactive (stopped/paused/complete), the other is more urgent + // If one case is inactive (paused/complete), the other is more urgent // If both cases are inactive, consider them equal if (isInactive(a)) { if (isInactive(b)) { @@ -58,8 +58,7 @@ public Comparator comparator(Map assaysById) { } private static boolean isInactive(Case kase) { - return kase.isStopped() - || kase.getRequisition().isPaused() + return kase.getRequisition().isPaused() || CompletedGate.RELEASE.qualifyCase(kase); } @@ -93,23 +92,28 @@ private static int calculateStepDaysOverdue(Case kase, AssayTargets targets) { } private static boolean isStepBehind(Integer target, Case kase, CompletedGate completedGate) { - return target != null && kase.getCaseDaysSpent() > target && !completedGate.qualifyCase(kase); + return target != null && kase.getCaseDaysSpent() > target + && (!kase.getRequisition().isStopped() || !completedGate.isStoppable()) + && !completedGate.qualifyCase(kase); } private static int calculateStepDaysRemaining(Case kase, AssayTargets targets) { - if (!CompletedGate.RECEIPT.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getReceiptDays()); - } else if (!CompletedGate.EXTRACTION.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getExtractionDays()); - } else if (!CompletedGate.LIBRARY_PREPARATION.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getLibraryPreparationDays()); - } else if (!CompletedGate.LIBRARY_QUALIFICATION.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getLibraryQualificationDays()); - } else if (!CompletedGate.FULL_DEPTH_SEQUENCING.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getFullDepthSequencingDays()); - } else if (!CompletedGate.ANALYSIS_REVIEW.qualifyCase(kase)) { - return calculateDaysRemaining(kase, targets.getAnalysisReviewDays()); - } else if (!CompletedGate.RELEASE_APPROVAL.qualifyCase(kase)) { + if (!kase.getRequisition().isStopped()) { + if (!CompletedGate.RECEIPT.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getReceiptDays()); + } else if (!CompletedGate.EXTRACTION.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getExtractionDays()); + } else if (!CompletedGate.LIBRARY_PREPARATION.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getLibraryPreparationDays()); + } else if (!CompletedGate.LIBRARY_QUALIFICATION.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getLibraryQualificationDays()); + } else if (!CompletedGate.FULL_DEPTH_SEQUENCING.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getFullDepthSequencingDays()); + } else if (!CompletedGate.ANALYSIS_REVIEW.qualifyCase(kase)) { + return calculateDaysRemaining(kase, targets.getAnalysisReviewDays()); + } + } + if (!CompletedGate.RELEASE_APPROVAL.qualifyCase(kase)) { return calculateDaysRemaining(kase, targets.getReleaseApprovalDays()); } else if (!CompletedGate.RELEASE.qualifyCase(kase)) { return calculateDaysRemaining(kase, targets.getReleaseDays()); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CompletedGate.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CompletedGate.java index 8c748948..0edcaca4 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CompletedGate.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/CompletedGate.java @@ -17,7 +17,7 @@ public enum CompletedGate { // @formatter:off - RECEIPT("Receipt") { + RECEIPT("Receipt", true) { @Override public boolean qualifyCase(Case kase) { return Helpers.isReceiptCompleted(kase); @@ -37,7 +37,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - EXTRACTION("Extraction") { + EXTRACTION("Extraction", true) { @Override public boolean qualifyTest(Test test) { return test.isExtractionSkipped() || Helpers.isCompleted(test.getExtractions()); @@ -53,7 +53,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } }, - LIBRARY_PREPARATION("Library Preparation") { + LIBRARY_PREPARATION("Library Preparation", true) { @Override public boolean qualifyTest(Test test) { return test.isLibraryPreparationSkipped() @@ -70,7 +70,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } }, - LIBRARY_QUALIFICATION("Library Qualification") { + LIBRARY_QUALIFICATION("Library Qualification", true) { @Override public boolean qualifyTest(Test test) { return Helpers.isCompleted(test.getLibraryQualifications()); @@ -85,7 +85,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - FULL_DEPTH_SEQUENCING("Full-Depth Sequencing") { + FULL_DEPTH_SEQUENCING("Full-Depth Sequencing", true) { @Override public boolean qualifyTest(Test test) { return Helpers.isCompleted(test.getFullDepthSequencings()); @@ -100,7 +100,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - ANALYSIS_REVIEW("Analysis Review") { + ANALYSIS_REVIEW("Analysis Review", true) { @Override public boolean qualifyCase(Case kase) { return Helpers.isCompletedRequisitionQc(kase.getRequisition(), Requisition::getAnalysisReviews); @@ -113,7 +113,7 @@ public boolean qualifyRequisition(Requisition requisition) { } }, - RELEASE_APPROVAL("Release Approval") { + RELEASE_APPROVAL("Release Approval", false) { @Override public boolean qualifyCase(Case kase) { return Helpers.isCompletedRequisitionQc(kase.getRequisition(), Requisition::getReleaseApprovals); @@ -124,7 +124,7 @@ public boolean qualifyRequisition(Requisition requisition) { return Helpers.isCompletedRequisitionQc(requisition, Requisition::getReleaseApprovals); } }, - RELEASE("Release") { + RELEASE("Release", false) { @Override public boolean qualifyCase(Case kase) { return Helpers.isCompletedRequisitionQc(kase.getRequisition(), Requisition::getReleases); @@ -145,18 +145,24 @@ public static CompletedGate getByLabel(String label) { } private final String label; + private final boolean stoppable; private final Predicate casePredicate = this::qualifyCase; private final Predicate testPredicate = this::qualifyTest; private final Predicate requisitionPredicate = this::qualifyRequisition; - private CompletedGate(String label) { + private CompletedGate(String label, boolean stoppable) { this.label = label; + this.stoppable = stoppable; } public String getLabel() { return label; } + public boolean isStoppable() { + return stoppable; + } + public Predicate predicate() { return casePredicate; } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/PendingState.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/PendingState.java index 3dbc3899..c70b6464 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/PendingState.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/filtering/PendingState.java @@ -44,7 +44,7 @@ public enum PendingState { // @formatter:off - RECEIPT_QC("Receipt QC") { + RECEIPT_QC("Receipt QC", true) { @Override public boolean qualifyCase(Case kase) { return Helpers.isPendingReceiptQc(kase); @@ -64,7 +64,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - EXTRACTION("Extraction") { + EXTRACTION("Extraction", true) { @Override public boolean qualifyCase(Case kase) { return Helpers.isReceiptPassed @@ -86,7 +86,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - EXTRACTION_QC("Extraction QC Sign-Off") { + EXTRACTION_QC("Extraction QC Sign-Off", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingQc(test.getExtractions()); @@ -101,7 +101,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - LIBRARY_PREPARATION("Library Preparation") { + LIBRARY_PREPARATION("Library Preparation", true) { @Override public boolean qualifyTest(Test test) { return !test.isLibraryPreparationSkipped() @@ -119,7 +119,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - LIBRARY_QC("Library QC Sign-Off") { + LIBRARY_QC("Library QC Sign-Off", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingQc(test.getLibraryPreparations()); @@ -134,7 +134,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - LIBRARY_QUALIFICATION("Library Qualification") { + LIBRARY_QUALIFICATION("Library Qualification", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingWork(test.getLibraryQualifications(), test.getLibraryPreparations()); @@ -152,7 +152,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - LIBRARY_QUALIFICATION_QC("Library Qualification QC Sign-Off") { + LIBRARY_QUALIFICATION_QC("Library Qualification QC Sign-Off", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingQc(test.getLibraryQualifications()); @@ -167,7 +167,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - LIBRARY_QUALIFICATION_DATA_REVIEW("Library Qualification Data Review") { + LIBRARY_QUALIFICATION_DATA_REVIEW("Library Qualification Data Review", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingDataReview(test.getLibraryQualifications()); @@ -182,7 +182,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - FULL_DEPTH_SEQUENCING("Full-Depth Sequencing") { + FULL_DEPTH_SEQUENCING("Full-Depth Sequencing", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingWork(test.getFullDepthSequencings(), test.getLibraryQualifications()); @@ -201,7 +201,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - FULL_DEPTH_QC("Full-Depth Sequencing QC Sign-Off") { + FULL_DEPTH_QC("Full-Depth Sequencing QC Sign-Off", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingQc(test.getFullDepthSequencings()); @@ -216,7 +216,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - FULL_DEPTH_DATA_REVIEW("Full-Depth Sequencing Data Review") { + FULL_DEPTH_DATA_REVIEW("Full-Depth Sequencing Data Review", true) { @Override public boolean qualifyTest(Test test) { return Helpers.hasPendingDataReview(test.getFullDepthSequencings()); @@ -231,7 +231,7 @@ public boolean qualifySample(Sample sample, MetricCategory requestCategory) { } } }, - ANALYSIS_REVIEW("Analysis Review") { + ANALYSIS_REVIEW("Analysis Review", true) { @Override public boolean qualifyCase(Case kase) { return kase.getTests().stream().allMatch(Helpers.isCompleted(Test::getFullDepthSequencings)) @@ -243,11 +243,11 @@ public boolean qualifyRequisition(Requisition requisition) { return requisition.getAnalysisReviews().isEmpty(); } }, - RELEASE_APPROVAL("Release Approval") { + RELEASE_APPROVAL("Release Approval", false) { @Override public boolean qualifyCase(Case kase) { - return Helpers.isCompletedRequisitionQc(kase, Requisition::getAnalysisReviews) + return (kase.isStopped() || Helpers.isCompletedRequisitionQc(kase, Requisition::getAnalysisReviews)) && this.qualifyRequisition(kase.getRequisition()); } @@ -256,7 +256,7 @@ public boolean qualifyRequisition(Requisition requisition) { return requisition.getReleaseApprovals().isEmpty(); } }, - RELEASE("Release") { + RELEASE("Release", false) { @Override public boolean qualifyCase(Case kase) { return Helpers.isCompletedRequisitionQc(kase, Requisition::getReleaseApprovals) @@ -278,18 +278,24 @@ public static PendingState getByLabel(String label) { } private final String label; + private final boolean stoppable; private final Predicate casePredicate = this::qualifyCase; private final Predicate testPredicate = this::qualifyTest; private final Predicate requisitionPredicate = this::qualifyRequisition; - private PendingState(String label) { + private PendingState(String label, boolean stoppable) { this.label = label; + this.stoppable = stoppable; } public String getLabel() { return label; } + public boolean isStoppable() { + return stoppable; + } + public Predicate predicate() { return casePredicate; } diff --git a/src/test/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSortTest.java b/src/test/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSortTest.java index 49ea6b28..06f05df5 100644 --- a/src/test/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSortTest.java +++ b/src/test/java/ca/on/oicr/gsi/dimsum/service/filtering/CaseSortTest.java @@ -99,30 +99,6 @@ public void testSortByUrgencyBothCompleted() { testUrgencyComparator(a, b, true); } - @org.junit.jupiter.api.Test - public void testSortByUrgencyBothStopped() { - Case a = mockEmptyCase(1L); - when(a.isStopped()).thenReturn(true); - - Case b = mockEmptyCase(1L); - when(b.isStopped()).thenReturn(true); - - // Both stopped, should be considered equivalent - testUrgencyComparator(a, b, true); - } - - @org.junit.jupiter.api.Test - public void testSortByUrgencyOneCompletedOneStopped() { - Case a = mockEmptyCase(1L); - a.getRequisition().getReleases().add(mockRequisitionQc(true, 2023, 1, 1)); - - Case b = mockEmptyCase(1L); - when(b.isStopped()).thenReturn(true); - - // One completed, one stopped. Should be considered equivalent - testUrgencyComparator(a, b, true); - } - @org.junit.jupiter.api.Test public void testSortByUrgencyOneCompleted() { Case a = mockEmptyCase(1L); @@ -134,17 +110,6 @@ public void testSortByUrgencyOneCompleted() { testUrgencyComparator(a, b); } - @org.junit.jupiter.api.Test - public void testSortByUrgencyOneStopped() { - Case a = mockEmptyCase(1L); - - Case b = mockEmptyCase(1L); - when(b.isStopped()).thenReturn(true); - - // B stopped. A is more urgent - testUrgencyComparator(a, b); - } - @org.junit.jupiter.api.Test public void testSortByUrgencyBothPaused() { Case a = mockEmptyCase(1L); @@ -168,18 +133,6 @@ public void testSortByUrgencyOnePaused() { testUrgencyComparator(a, b); } - @org.junit.jupiter.api.Test - public void testSortByUrgencyOnePausedOneStopped() { - Case a = mockEmptyCase(1L); - when(a.getRequisition().isPaused()).thenReturn(true); - - Case b = mockEmptyCase(1L); - when(b.isStopped()).thenReturn(true); - - // A paused, B stopped. Should be considered equivalent - testUrgencyComparator(a, b, true); - } - @org.junit.jupiter.api.Test public void testSortByUrgencyBothOverdue() { Case a = mockEmptyCase(1L); diff --git a/ts/data/case.ts b/ts/data/case.ts index 3cf7bb74..b8eb8988 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -1,8 +1,6 @@ import { legendAction, TableDefinition } from "../component/table-builder"; import { - addLink, makeIcon, - addMisoIcon, styleText, makeNameDiv, addNaText, @@ -20,11 +18,9 @@ import { RequisitionQc, } from "./requisition"; import { Tooltip } from "../component/tooltip"; -import { caseFilters, latestActivitySort } from "../component/table-components"; +import { caseFilters } from "../component/table-components"; import { AssayTargets } from "./assay"; -const dayMillis = 1000 * 60 * 60 * 24; - export interface Project { name: string; pipeline: string; @@ -243,9 +239,6 @@ export const caseDefinition: TableDefinition = { dateDiv.appendChild(document.createTextNode(kase.startDate)); fragment.appendChild(dateDiv); - if (kase.requisition.stopped) { - return; - } if (caseComplete(kase)) { addTextDiv(`Completed in ${kase.caseDaysSpent} days`, fragment); return; @@ -253,7 +246,8 @@ export const caseDefinition: TableDefinition = { addTextDiv(`${kase.caseDaysSpent}d spent`, fragment); const targets = getTargets(kase); - if (caseOverdue(kase, targets)) { + const overdue = caseOverdue(kase, targets); + if (overdue) { const overdueDiv = makeTextDivWithTooltip( "OVERDUE", `Case target: ${targets.caseDays} days` @@ -267,19 +261,21 @@ export const caseDefinition: TableDefinition = { ); fragment.appendChild(remainingDiv); } - const overdueStep = getOverdueStep(kase, targets); - if (overdueStep) { - const behindDiv = makeTextDivWithTooltip( - "BEHIND SCHEDULE", - `${overdueStep.stepLabel} target: ${overdueStep.targetDays} days` - ); - styleText(behindDiv, "error"); - fragment.appendChild(behindDiv); + if (!overdue) { + const overdueStep = getOverdueStep(kase, targets); + if (overdueStep) { + const behindDiv = makeTextDivWithTooltip( + "BEHIND SCHEDULE", + `${overdueStep.stepLabel} target: ${overdueStep.targetDays} days` + ); + styleText(behindDiv, "error"); + fragment.appendChild(behindDiv); + } } }, getCellHighlight(kase) { - if (kase.requisition.stopped || caseComplete(kase)) { - // Never show overdue/behind warning/error for completed or stopped cases + if (caseComplete(kase)) { + // Never show overdue/behind warning/error for completed cases return null; } const targets = getTargets(kase); @@ -302,12 +298,14 @@ export const caseDefinition: TableDefinition = { ) { addConstructionIcon("receipt", fragment); } - const targets = getTargets(kase); - addTurnAroundTimeInfo( - kase.caseDaysSpent, - targets.receiptDays, - fragment - ); + if (!kase.requisition.stopped) { + const targets = getTargets(kase); + addTurnAroundTimeInfo( + kase.caseDaysSpent, + targets.receiptDays, + fragment + ); + } } }, getCellHighlight(kase) { @@ -356,12 +354,14 @@ export const caseDefinition: TableDefinition = { } addConstructionIcon("extraction", fragment); } - const targets = getTargets(kase); - addTurnAroundTimeInfo( - kase.caseDaysSpent, - targets.extractionDays, - fragment - ); + if (!kase.requisition.stopped) { + const targets = getTargets(kase); + addTurnAroundTimeInfo( + kase.caseDaysSpent, + targets.extractionDays, + fragment + ); + } } } }, @@ -405,12 +405,14 @@ export const caseDefinition: TableDefinition = { } addConstructionIcon("library preparation", fragment); } - const targets = getTargets(kase); - addTurnAroundTimeInfo( - kase.caseDaysSpent, - targets.libraryPreparationDays, - fragment - ); + if (!kase.requisition.stopped) { + const targets = getTargets(kase); + addTurnAroundTimeInfo( + kase.caseDaysSpent, + targets.libraryPreparationDays, + fragment + ); + } } } }, @@ -453,12 +455,14 @@ export const caseDefinition: TableDefinition = { } addConstructionIcon("library qualification", fragment); } - const targets = getTargets(kase); - addTurnAroundTimeInfo( - kase.caseDaysSpent, - targets.libraryQualificationDays, - fragment - ); + if (!kase.requisition.stopped) { + const targets = getTargets(kase); + addTurnAroundTimeInfo( + kase.caseDaysSpent, + targets.libraryQualificationDays, + fragment + ); + } } } }, @@ -495,12 +499,14 @@ export const caseDefinition: TableDefinition = { } addConstructionIcon("full-depth sequencing", fragment); } - const targets = getTargets(kase); - addTurnAroundTimeInfo( - kase.caseDaysSpent, - targets.fullDepthSequencingDays, - fragment - ); + if (!kase.requisition.stopped) { + const targets = getTargets(kase); + addTurnAroundTimeInfo( + kase.caseDaysSpent, + targets.fullDepthSequencingDays, + fragment + ); + } } } }, @@ -528,6 +534,7 @@ export const caseDefinition: TableDefinition = { kase, (requisition) => requisition.analysisReviews, sequencingComplete, + true, targets.analysisReviewDays, fragment ); @@ -535,18 +542,14 @@ export const caseDefinition: TableDefinition = { getCellHighlight(kase) { return getRequisitionPhaseHighlight( kase, - kase.requisition.analysisReviews + kase.requisition.analysisReviews, + true ); }, }, { title: "Release Approval", addParentContents(kase, fragment) { - if ( - handleNaRequisitionPhase(kase, (x) => x.releaseApprovals, fragment) - ) { - return; - } const analysisReviewComplete = requisitionPhaseComplete( kase.requisition.analysisReviews ); @@ -554,7 +557,8 @@ export const caseDefinition: TableDefinition = { addRequisitionIcons( kase, (requisition) => requisition.releaseApprovals, - analysisReviewComplete, + analysisReviewComplete || kase.requisition.stopped, + false, targets.releaseApprovalDays, fragment ); @@ -562,16 +566,14 @@ export const caseDefinition: TableDefinition = { getCellHighlight(kase) { return getRequisitionPhaseHighlight( kase, - kase.requisition.releaseApprovals + kase.requisition.releaseApprovals, + false ); }, }, { title: "Release", addParentContents(kase, fragment) { - if (handleNaRequisitionPhase(kase, (x) => x.releases, fragment)) { - return; - } const draftComplete = requisitionPhaseComplete( kase.requisition.releaseApprovals ); @@ -580,12 +582,17 @@ export const caseDefinition: TableDefinition = { kase, (requisition) => requisition.releases, draftComplete, + false, targets.releaseDays, fragment ); }, getCellHighlight(kase) { - return getRequisitionPhaseHighlight(kase, kase.requisition.releases); + return getRequisitionPhaseHighlight( + kase, + kase.requisition.releases, + false + ); }, }, { @@ -707,10 +714,14 @@ function requisitionPhaseComplete(qcs: RequisitionQc[]): boolean { return !!(qcs.length && getLatestRequisitionQc(qcs).qcPassed); } -function getRequisitionPhaseHighlight(kase: Case, qcs: RequisitionQc[]) { +function getRequisitionPhaseHighlight( + kase: Case, + qcs: RequisitionQc[], + stoppable: boolean +) { if (requisitionPhaseComplete(qcs) || kase.requisition.paused) { return null; - } else if (kase.requisition.stopped) { + } else if (stoppable && kase.requisition.stopped) { return qcs.length ? null : "na"; } else { return "warning"; @@ -820,6 +831,7 @@ function addRequisitionIcons( kase: Case, getQcs: (requisition: Requisition) => RequisitionQc[], previousComplete: boolean, + stoppable: boolean, targetDays: number | null, fragment: DocumentFragment ) { @@ -831,7 +843,11 @@ function addRequisitionIcons( const status = qcStatuses.qc; addRequisitionIcon(kase.requisition, status, fragment); } - if (previousComplete && !requisitionPhaseComplete(qcs)) { + if ( + (!stoppable || !kase.requisition.stopped) && + previousComplete && + !requisitionPhaseComplete(qcs) + ) { addTurnAroundTimeInfo(kase.caseDaysSpent, targetDays, fragment); } } @@ -916,6 +932,9 @@ function getOverdueStep(kase: Case, targets: AssayTargets): OverdueStep | null { stepLabel: "Release approval", targetDays: targets.releaseApprovalDays, }; + } + if (kase.requisition.stopped) { + return null; } else if ( requisitionPhaseBehind( kase.requisition.analysisReviews,