From 51ca244524eeaf3d62b1e3d2f68e9d208c6e58b6 Mon Sep 17 00:00:00 2001 From: Alexandre Brandizzi Date: Thu, 24 Sep 2026 21:34:24 -0300 Subject: [PATCH] fix(workorders): keep closed undated WOs out of the board page like the search (SH-391) With no range selected, or with Unscheduled, the board search adds only open undated work orders; completed and canceled ones without a date are never unscheduled. The board page kept them. It now applies the same rule, so both return the same rows. --- .../utils/advanced-filter-predicates.ts | 31 ++++++++++++++----- .../utils/table-filter-utils.test.ts | 16 +++++++++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/domain/work-orders/utils/advanced-filter-predicates.ts b/src/domain/work-orders/utils/advanced-filter-predicates.ts index 9fa0b3b4..6b40d48e 100644 --- a/src/domain/work-orders/utils/advanced-filter-predicates.ts +++ b/src/domain/work-orders/utils/advanced-filter-predicates.ts @@ -2,6 +2,11 @@ import type { WorkOrderAdvancedFilters } from "@/domain/work-orders/types/work-o import { ASSIGNEE_FILTER_UNASSIGNED } from "@/domain/work-orders/types/work-order-list"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; import { dateRangeFor } from "@/domain/work-orders/utils/advanced-filters-utils"; +import { + ADVANCED_SEARCH_ALL_WEEKS_FROM, + ADVANCED_SEARCH_ALL_WEEKS_TO, +} from "@/domain/work-orders/utils/board-query-params"; +import { isTerminalCarryOverStatus } from "@/domain/work-orders/utils/carry-over-display"; import { addDaysIso } from "@/domain/work-orders/utils/wizard-date-utils"; type AdvancedFilterPredicate = ( @@ -9,22 +14,32 @@ type AdvancedFilterPredicate = ( filters: WorkOrderAdvancedFilters, ) => boolean; +const isOpenUndated = (row: WorkOrderTableRow): boolean => + !row.scheduledOn && !isTerminalCarryOverStatus(row.status); + +// Mirrors the board search (ApplyDateRangeFilter and ApplyUnscheduledOnlyFilter) +// so the page and /board/search keep the same rows (SH-391): a row is in a range +// when its date is, or when it is week-only and its target week overlaps. With +// no range, every week is searched and open undated rows are added. Closed +// undated rows are never unscheduled. const matchesDateRange: AdvancedFilterPredicate = (row, filters) => { if (filters.unscheduledOnly) { - return !row.scheduledOn; + return isOpenUndated(row); } - const range = dateRangeFor(filters); - if (!range) return true; - const [from, to] = range; + const [from, to] = dateRangeFor(filters) ?? [ + ADVANCED_SEARCH_ALL_WEEKS_FROM, + ADVANCED_SEARCH_ALL_WEEKS_TO, + ]; if (row.scheduledOn && row.scheduledOn >= from && row.scheduledOn <= to) return true; - // Week-only rows also match when their target week overlaps the range, the - // same rule as the board search (SH-391). - return ( + if ( row.scheduleWeekOnly && Boolean(row.targetWeek) && row.targetWeek <= to && addDaysIso(row.targetWeek, 6) >= from - ); + ) { + return true; + } + return filters.dateRange === null && isOpenUndated(row); }; const matchesSite: AdvancedFilterPredicate = (row, filters) => diff --git a/src/test/domain/work-orders/utils/table-filter-utils.test.ts b/src/test/domain/work-orders/utils/table-filter-utils.test.ts index 8471849b..296c7b6d 100644 --- a/src/test/domain/work-orders/utils/table-filter-utils.test.ts +++ b/src/test/domain/work-orders/utils/table-filter-utils.test.ts @@ -488,7 +488,21 @@ describe("matchesAdvancedFilters", () => { expect(matchesAdvancedFilters(weekOnlyOutside, filters)).toBe(false); expect(matchesAdvancedFilters(datedOutsideWithWeek, filters)).toBe(false); expect(matchesAdvancedFilters(undated, filters)).toBe(false); - expect(matchesAdvancedFilters(undated, { ...filters, dateRange: null })).toBe(true); + // No range: every week, plus open undated rows. Closed undated rows are + // never unscheduled, with or without the Unscheduled filter. + const noRange = { ...filters, dateRange: null }; + const unscheduledOnly = { ...filters, unscheduledOnly: true }; + const completedUndated = makeRow({ scheduledOn: "", targetWeek: "", status: "Completed" }); + const canceledUndated = makeRow({ scheduledOn: "", targetWeek: "", status: "Canceled" }); + + expect(matchesAdvancedFilters(undated, noRange)).toBe(true); + expect(matchesAdvancedFilters(datedOutsideWithWeek, noRange)).toBe(true); + expect(matchesAdvancedFilters(weekOnlyOutside, noRange)).toBe(true); + expect(matchesAdvancedFilters(completedUndated, noRange)).toBe(false); + expect(matchesAdvancedFilters(canceledUndated, noRange)).toBe(false); + expect(matchesAdvancedFilters(undated, unscheduledOnly)).toBe(true); + expect(matchesAdvancedFilters(completedUndated, unscheduledOnly)).toBe(false); + expect(matchesAdvancedFilters(canceledUndated, unscheduledOnly)).toBe(false); }); });