shoc-frontend-new/src/test/domain/work-orders/utils/wo-lifecycle-transitions.test.ts
2026-09-29 11:28:26 -03:00

215 lines
6.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { PENDING_UPLIFT_GAP } from "@/domain/work-orders/utils/wo-closability";
import {
AUTOMATIC_LIFECYCLE_STATUSES,
BOARD_INLINE_STATUSES,
COMPLETED_DOC_BLOCK_MSG,
COMPLETED_MEDIA_BLOCK_MSG,
CREATION_INLINE_STATUSES,
SCHEDULED_NEEDS_DATE_MSG,
formatAapCompletedBlockTitle,
getInlineStatusTransitions,
getStatusOptionState,
hasConcreteScheduleDate,
maybeAutoSchedulePatch,
mergeAutoSchedulePatch,
resolveCreationStatus,
withAutoScheduleStatus,
} from "@/domain/work-orders/utils/wo-lifecycle-transitions";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
describe("wo-lifecycle-transitions", () => {
it("lists only manual board statuses: no automatic states and no Canceled (SH-169)", () => {
expect(BOARD_INLINE_STATUSES).toEqual([
"En Route",
"On Site",
"In Progress",
"Completed",
"Rescheduled",
"Pending Quote",
]);
expect(BOARD_INLINE_STATUSES).not.toContain("Canceled");
for (const automatic of AUTOMATIC_LIFECYCLE_STATUSES) {
expect(BOARD_INLINE_STATUSES).not.toContain(automatic);
}
});
it("never offers the current status as a transition (SH-358)", () => {
expect(getInlineStatusTransitions("On Site")).toEqual([
"En Route",
"In Progress",
"Completed",
"Rescheduled",
"Pending Quote",
]);
expect(getInlineStatusTransitions("Incomplete")).toEqual(BOARD_INLINE_STATUSES);
});
it("lists AAP creation statuses only", () => {
expect(CREATION_INLINE_STATUSES).toEqual(["Incomplete", "Pending", "Scheduled"]);
});
it("treats week-only as no concrete schedule date", () => {
expect(hasConcreteScheduleDate({ scheduledOn: "2026-06-01", scheduleWeekOnly: true })).toBe(
false,
);
expect(hasConcreteScheduleDate({ scheduledOn: "2026-06-01", schedMode: "week" })).toBe(false);
expect(hasConcreteScheduleDate({ scheduledOn: "—" })).toBe(false);
expect(hasConcreteScheduleDate({ scheduledOn: "2026-06-01" })).toBe(true);
});
it("disables Scheduled without a concrete date", () => {
expect(getStatusOptionState({ scheduledOn: "" }, "Scheduled", [])).toEqual({
disabled: true,
title: SCHEDULED_NEEDS_DATE_MSG,
});
});
it("promotes Incomplete/Pending when a concrete date exists", () => {
expect(
maybeAutoSchedulePatch({
status: "Incomplete",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
}),
).toEqual({ status: "Scheduled" });
expect(
maybeAutoSchedulePatch({
status: "Pending",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
}),
).toEqual({ status: "Scheduled" });
});
it("reverts Scheduled without a concrete date to Pending", () => {
expect(
maybeAutoSchedulePatch({
status: "Scheduled",
scheduledOn: "",
scheduleWeekOnly: false,
}),
).toEqual({ status: "Pending" });
});
it("does not auto-change In Progress when a date exists", () => {
expect(
maybeAutoSchedulePatch({
status: "In Progress",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
}),
).toEqual({});
});
it("merges auto-schedule onto an existing-row patch", () => {
const row = {
status: "Incomplete",
scheduledOn: "",
scheduleWeekOnly: false,
} as WorkOrderTableRow;
expect(
mergeAutoSchedulePatch(row, { scheduledOn: "2026-06-02", scheduleWeekOnly: false }),
).toEqual({
scheduledOn: "2026-06-02",
scheduleWeekOnly: false,
status: "Scheduled",
});
expect(mergeAutoSchedulePatch(row, { vendorId: "9" })).toEqual({ vendorId: "9" });
expect(
mergeAutoSchedulePatch({ ...row, scheduledOn: "2026-06-01" }, { vendorId: "9" }),
).toEqual({ vendorId: "9" });
});
it("promotes a pre-schedule wizard pick to Scheduled on a dated draft", () => {
const draft = {
status: "Scheduled",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
};
expect(withAutoScheduleStatus(draft, { status: "Pending" })).toEqual({ status: "Scheduled" });
expect(withAutoScheduleStatus(draft, { status: "Incomplete" })).toEqual({
status: "Scheduled",
});
});
it("still derives Scheduled when a concrete date is set on a draft", () => {
const draft = {
status: "Pending",
scheduledOn: "",
scheduleWeekOnly: false,
};
expect(
withAutoScheduleStatus(draft, { scheduledOn: "2026-06-02", scheduleWeekOnly: false }),
).toEqual({
scheduledOn: "2026-06-02",
scheduleWeekOnly: false,
status: "Scheduled",
});
});
it("promotes pre-schedule picks on dated rows", () => {
const row = {
status: "Scheduled",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
} as WorkOrderTableRow;
expect(mergeAutoSchedulePatch(row, { status: "Pending" })).toEqual({ status: "Scheduled" });
expect(mergeAutoSchedulePatch(row, { status: "Incomplete" })).toEqual({
status: "Scheduled",
});
});
it("still demotes Scheduled when the schedule is cleared", () => {
const row = {
status: "Scheduled",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
} as WorkOrderTableRow;
expect(mergeAutoSchedulePatch(row, { scheduledOn: "", scheduleWeekOnly: false })).toEqual({
scheduledOn: "",
scheduleWeekOnly: false,
status: "Pending",
});
});
it("promotes a Pending create pick to Scheduled when the draft is dated", () => {
expect(
resolveCreationStatus({
status: "Pending",
scheduledOn: "2026-06-01",
scheduleWeekOnly: false,
}),
).toBe("Scheduled");
});
it("demotes Scheduled without a concrete date at create", () => {
expect(
resolveCreationStatus({
status: "Scheduled",
scheduledOn: "",
scheduleWeekOnly: false,
}),
).toBe("Pending");
});
it("uses AAP completed tooltip hierarchy", () => {
expect(formatAapCompletedBlockTitle(["Dispatcher", "Company"])).toBe(
"Fill in Assigned To, Vendor before completing this work order.",
);
expect(formatAapCompletedBlockTitle(["Service"])).toBe(
"Select a service before completing this work order.",
);
expect(formatAapCompletedBlockTitle(["WO number"])).toBe(
"Assign a real APM number (not SH) before completing this work order.",
);
expect(formatAapCompletedBlockTitle([PENDING_UPLIFT_GAP])).toBe(
"This work order has an uplift pending approval and cannot be completed.",
);
expect(formatAapCompletedBlockTitle(["Completion document"])).toBe(COMPLETED_DOC_BLOCK_MSG);
expect(formatAapCompletedBlockTitle(["At least 1 photo"])).toBe(COMPLETED_MEDIA_BLOCK_MSG);
expect(formatAapCompletedBlockTitle(["Company", PENDING_UPLIFT_GAP])).toBe(
"Fill in Vendor before completing this work order.",
);
});
});