diff --git a/e2e/work-orders/pending-status-menu.spec.ts b/e2e/work-orders/pending-status-menu.spec.ts
index 3f2307be..43c86efa 100644
--- a/e2e/work-orders/pending-status-menu.spec.ts
+++ b/e2e/work-orders/pending-status-menu.spec.ts
@@ -247,9 +247,18 @@ test.describe("existing work order status menu", () => {
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("button", { name: "Continue" }).click();
- await expect(
- page.getByRole("dialog").getByRole("button", { name: "Scheduled", exact: true }),
- ).toBeVisible();
+ const wizardDialog = page.getByRole("dialog");
+ const scheduledStatus = wizardDialog.getByRole("button", {
+ name: "Scheduled",
+ exact: true,
+ });
+ await expect(scheduledStatus).toBeVisible();
+ await scheduledStatus.click();
+ const statusMenu = page.locator(".MuiPopover-paper").last();
+ await expect(statusMenu.getByRole("button", { name: "Pending", exact: true })).toBeDisabled();
+ await statusMenu.getByRole("button", { name: "Scheduled", exact: true }).click();
+ await expect(scheduledStatus).toBeVisible();
+
await page.getByRole("button", { name: "Create work order" }).click();
await expect(page.getByRole("heading", { name: "Type & schedule" })).toBeHidden();
await expect
diff --git a/src/domain/work-orders/utils/wo-lifecycle-transitions.ts b/src/domain/work-orders/utils/wo-lifecycle-transitions.ts
index e0351242..bbef896a 100644
--- a/src/domain/work-orders/utils/wo-lifecycle-transitions.ts
+++ b/src/domain/work-orders/utils/wo-lifecycle-transitions.ts
@@ -38,6 +38,8 @@ export const CREATION_INLINE_STATUSES: readonly WizardWOStatus[] = [
export const SCHEDULED_NEEDS_DATE_MSG =
"Set a Schedule On date before marking this work order as Scheduled.";
+export const PENDING_NEEDS_NO_DATE_MSG =
+ "Clear the Schedule On date before marking this work order as Pending.";
export const PAST_DUE_BADGE_TOOLTIP =
"This WO missed its service window. Reschedule to unlock status updates.";
@@ -132,6 +134,9 @@ export function getStatusOptionState(
status: WizardWOStatus,
closabilityGaps: string[],
): StatusOptionState {
+ if (status === "Pending" && hasConcreteScheduleDate(row)) {
+ return { disabled: true, title: PENDING_NEEDS_NO_DATE_MSG };
+ }
if (status === "Scheduled" && !hasConcreteScheduleDate(row)) {
return { disabled: true, title: SCHEDULED_NEEDS_DATE_MSG };
}
diff --git a/src/test/app/(protected)/workorders/status-cell-closability.test.tsx b/src/test/app/(protected)/workorders/status-cell-closability.test.tsx
index 77922f0d..be9a17a6 100644
--- a/src/test/app/(protected)/workorders/status-cell-closability.test.tsx
+++ b/src/test/app/(protected)/workorders/status-cell-closability.test.tsx
@@ -3,6 +3,7 @@ import { describe, expect, it, vi } from "vitest";
import { StatusCell } from "@/app/(protected)/workorders/_components/list/table/cells/status-cell";
import type { WizardWOStatus } from "@/domain/work-orders/types/work-order-wizard";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
+import { CREATION_INLINE_STATUSES } from "@/domain/work-orders/utils/wo-lifecycle-transitions";
const incompleteRow = {
id: "wo-1",
@@ -111,4 +112,23 @@ describe("StatusCell closability gate", () => {
expect(screen.getByRole("button", { name: /^pending$/i })).toBeTruthy();
expect(screen.queryByRole("button", { name: /^en route$/i })).toBeNull();
});
+
+ it("disables Pending for inline creation when Schedule On has a concrete date", () => {
+ render(
+ ,
+ );
+
+ fireEvent.click(screen.getByRole("button", { name: /scheduled/i }));
+ const pending = screen.getByRole("button", { name: /^pending$/i });
+ expect(pending).toBeDisabled();
+ expect(pending).toHaveAttribute(
+ "title",
+ "Clear the Schedule On date before marking this work order as Pending.",
+ );
+ });
});
diff --git a/src/test/app/(protected)/workorders/wizard-step-vendor-time-closability.test.tsx b/src/test/app/(protected)/workorders/wizard-step-vendor-time-closability.test.tsx
index 9280a735..265597e0 100644
--- a/src/test/app/(protected)/workorders/wizard-step-vendor-time-closability.test.tsx
+++ b/src/test/app/(protected)/workorders/wizard-step-vendor-time-closability.test.tsx
@@ -77,7 +77,7 @@ describe("WizardStepVendorTime creation statuses (AAP)", () => {
expect(onPatch).toHaveBeenCalledWith({ status: "Pending" });
});
- it("promotes Pending to Scheduled when picked on a dated draft", () => {
+ it("disables Pending when Schedule On has a concrete date", () => {
const onPatch = vi.fn();
render(
{
);
fireEvent.click(screen.getByRole("button", { name: /scheduled/i }));
- fireEvent.click(screen.getByRole("button", { name: /^pending$/i }));
- expect(onPatch).toHaveBeenCalledWith({ status: "Scheduled" });
+ const pending = screen.getByRole("button", { name: /^pending$/i });
+ expect(pending).toBeDisabled();
+ expect(pending).toHaveAttribute(
+ "title",
+ "Clear the Schedule On date before marking this work order as Pending.",
+ );
+ fireEvent.click(pending);
+ expect(onPatch).not.toHaveBeenCalled();
});
});
diff --git a/src/test/domain/work-orders/utils/wo-lifecycle-transitions.test.ts b/src/test/domain/work-orders/utils/wo-lifecycle-transitions.test.ts
index b22e4357..5d0b4d77 100644
--- a/src/test/domain/work-orders/utils/wo-lifecycle-transitions.test.ts
+++ b/src/test/domain/work-orders/utils/wo-lifecycle-transitions.test.ts
@@ -6,6 +6,7 @@ import {
COMPLETED_DOC_BLOCK_MSG,
COMPLETED_MEDIA_BLOCK_MSG,
CREATION_INLINE_STATUSES,
+ PENDING_NEEDS_NO_DATE_MSG,
SCHEDULED_NEEDS_DATE_MSG,
formatAapCompletedBlockTitle,
getInlineStatusTransitions,
@@ -65,6 +66,25 @@ describe("wo-lifecycle-transitions", () => {
});
});
+ it("disables Pending only when a concrete schedule date exists", () => {
+ expect(getStatusOptionState({ scheduledOn: "2026-06-01" }, "Pending", [])).toEqual({
+ disabled: true,
+ title: PENDING_NEEDS_NO_DATE_MSG,
+ });
+ expect(
+ getStatusOptionState({ scheduledOn: "", scheduleWeekOnly: false }, "Pending", []),
+ ).toEqual({
+ disabled: false,
+ });
+ expect(
+ getStatusOptionState(
+ { scheduledOn: "2026-06-01", scheduleWeekOnly: true, schedMode: "week" },
+ "Pending",
+ [],
+ ),
+ ).toEqual({ disabled: false });
+ });
+
it("promotes Incomplete/Pending when a concrete date exists", () => {
expect(
maybeAutoSchedulePatch({