fix: require undated drafts for Pending status

This commit is contained in:
Alexandre Brandizzi 2026-09-29 13:04:51 -03:00
parent 4771f6f8eb
commit 7d5d015602
5 changed files with 66 additions and 6 deletions

View file

@ -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

View file

@ -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 };
}

View file

@ -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(
<StatusCell
wo={{ ...incompleteRow, status: "Scheduled", scheduledOn: "2026-06-01" }}
statusOptions={CREATION_INLINE_STATUSES}
onChangeStatus={vi.fn()}
onOpenSlideOver={vi.fn()}
/>,
);
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.",
);
});
});

View file

@ -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(
<WizardStepVendorTime
@ -95,7 +95,13 @@ describe("WizardStepVendorTime creation statuses (AAP)", () => {
);
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();
});
});

View file

@ -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({