(null);
- const siteCellMissing = missing.some((f) => f === "site" || f === "pocName" || f === "pocPhone");
+ const siteCellMissing = missing.some(
+ (f) => f === "customer" || f === "site" || f === "pocName" || f === "pocPhone",
+ );
const siteShowError = showErrors && siteCellMissing;
const woShowError = showErrors && missing.includes("woNumber");
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-sidebar-summary-rows.ts b/src/app/(protected)/workorders/_components/wizard/wizard-sidebar-summary-rows.ts
index e49e267a..3cd23c7d 100644
--- a/src/app/(protected)/workorders/_components/wizard/wizard-sidebar-summary-rows.ts
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-sidebar-summary-rows.ts
@@ -46,6 +46,7 @@ export function buildWizardSidebarSummaryRows(draft: WorkOrderWizardDraft): [str
["Schedule on", scheduleOnLabel(draft)],
["Due date", fmtDate(draft.dueDate) || "—"],
["Assigned to", draft.assigneeName || "—"],
+ ["Account", draft.customer.trim() || "—"],
["Site", draft.siteCode || draft.locationName || "—"],
["POC", pocLabel(draft)],
["Additional POCs", formatAdditionalPocSummary(draft)],
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-step-location-account-select.tsx b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-account-select.tsx
new file mode 100644
index 00000000..5ab5a3e1
--- /dev/null
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-account-select.tsx
@@ -0,0 +1,49 @@
+import { Building2, Info } from "lucide-react";
+import { Text } from "@/components/ui/text";
+import { WizardFieldSelect } from "@/app/(protected)/workorders/_components/wizard/wizard-field-select";
+import { WizLabel } from "@/app/(protected)/workorders/_components/wizard/wizard-labels";
+import { useAccountsList } from "@/domain/accounts/use-cases/use-accounts-list";
+
+type WizardStepLocationAccountSelectProps = {
+ customer: string;
+ onCustomerChange: (customer: string) => void;
+ showError?: boolean;
+};
+
+export function WizardStepLocationAccountSelect({
+ customer,
+ onCustomerChange,
+ showError = false,
+}: WizardStepLocationAccountSelectProps) {
+ const { data } = useAccountsList({ page: 1, pageSize: 100, search: "" });
+ const accounts = data?.items ?? [];
+ const options = accounts
+ .map((account) => account.name.trim())
+ .filter(Boolean)
+ .map((name) => ({ key: name, label: name }));
+
+ return (
+
+ Account
+
+ }
+ searchPlaceholder="Search account name…"
+ options={options}
+ onPick={onCustomerChange}
+ />
+
+ Account is required to create a work order.
+
+
+ );
+}
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx
index 950ca5c8..17425052 100644
--- a/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx
@@ -2,6 +2,7 @@ import { Text } from "@/components/ui/text";
import type { LocationOption } from "@/domain/work-orders/types/work-order";
import type { Location } from "@/domain/locations/types/location";
import type { WorkOrderWizardDraft } from "@/domain/work-orders/types/work-order-wizard";
+import { WizardStepLocationAccountSelect } from "@/app/(protected)/workorders/_components/wizard/wizard-step-location-account-select";
import { WizardStepLocationPocFields } from "@/app/(protected)/workorders/_components/wizard/wizard-step-location-poc-fields";
import { WizardStepLocationServiceSelect } from "@/app/(protected)/workorders/_components/wizard/wizard-step-location-service-select";
import { WizardStepLocationSiteDetails } from "@/app/(protected)/workorders/_components/wizard/wizard-step-location-site-details";
@@ -44,6 +45,11 @@ export function WizardStepLocationService({
return (
+ onPatch({ customer })}
+ />
= {
+ customer: "Account",
site: "Site",
woNumber: "WO #",
pocName: "POC name",
@@ -9,6 +10,7 @@ export const INLINE_CREATE_REQ_LABELS: Record = {
};
export type InlineCreateDraftFields = {
+ customer?: string;
site?: string;
locationId?: string | number;
woNumber?: string;
@@ -18,6 +20,9 @@ export type InlineCreateDraftFields = {
export function getInlineCreateMissing(d: InlineCreateDraftFields): InlineCreateReqField[] {
const miss: InlineCreateReqField[] = [];
+ if (!d.customer?.trim()) {
+ miss.push("customer");
+ }
const hasSite = Boolean(d.site?.trim()) || Boolean(String(d.locationId ?? "").trim());
if (!hasSite) {
miss.push("site");
@@ -43,6 +48,9 @@ export function inlineCreateSaveHint(miss: InlineCreateReqField[]): string {
}
export function inlineCreateSiteError(miss: InlineCreateReqField[]): string {
+ if (miss.includes("customer")) {
+ return "Account is required";
+ }
if (miss.includes("site")) {
return "Site is required";
}
diff --git a/src/test/app/(protected)/workorders/build-inline-draft-create-input.test.ts b/src/test/app/(protected)/workorders/build-inline-draft-create-input.test.ts
index ccccd7d3..16b30ee8 100644
--- a/src/test/app/(protected)/workorders/build-inline-draft-create-input.test.ts
+++ b/src/test/app/(protected)/workorders/build-inline-draft-create-input.test.ts
@@ -8,6 +8,7 @@ describe("buildInlineDraftCreateInput", () => {
const draft = {
...EMPTY_TABLE_DRAFT,
site: "BK5",
+ customer: "Amazon",
locationId: "9",
woNumber: "25001",
pocName: "Jane",
@@ -30,6 +31,8 @@ describe("buildInlineDraftCreateInput", () => {
expect(payload.scheduleWeekOnly).toBeUndefined();
expect(payload.woNumber).toBe("25001");
expect(payload.pocName).toBe("Jane");
+ expect(payload.customer).toBe("Amazon");
+ expect(input.customer).toBe("Amazon");
});
it("keeps week-only schedule when targetWeek is set", () => {
diff --git a/src/test/app/(protected)/workorders/wizard-step-location-account-select.test.tsx b/src/test/app/(protected)/workorders/wizard-step-location-account-select.test.tsx
new file mode 100644
index 00000000..d0bc6a2c
--- /dev/null
+++ b/src/test/app/(protected)/workorders/wizard-step-location-account-select.test.tsx
@@ -0,0 +1,48 @@
+import { fireEvent, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import { WizardStepLocationAccountSelect } from "@/app/(protected)/workorders/_components/wizard/wizard-step-location-account-select";
+import { renderWithProviders } from "@/test/test-utils";
+
+vi.mock("@/domain/accounts/use-cases/use-accounts-list", () => ({
+ useAccountsList: () => ({
+ data: {
+ items: [
+ {
+ id: 1,
+ name: "Amazon",
+ number: "",
+ industry: "",
+ website: "",
+ primaryContact: "",
+ phoneNumber: "",
+ owner: "",
+ },
+ {
+ id: 2,
+ name: "Sea Haven",
+ number: "",
+ industry: "",
+ website: "",
+ primaryContact: "",
+ phoneNumber: "",
+ owner: "",
+ },
+ ],
+ },
+ }),
+}));
+
+describe("WizardStepLocationAccountSelect", () => {
+ it("sets draft.customer to the exact account name on pick", () => {
+ const onCustomerChange = vi.fn();
+ renderWithProviders(
+ ,
+ { withAuth: false },
+ );
+
+ fireEvent.click(screen.getByRole("button", { name: /select account/i }));
+ fireEvent.click(screen.getByRole("button", { name: "Amazon" }));
+
+ expect(onCustomerChange).toHaveBeenCalledWith("Amazon");
+ });
+});
diff --git a/src/test/domain/work-orders/api/work-orders-api.test.ts b/src/test/domain/work-orders/api/work-orders-api.test.ts
index 388ad617..fabf80af 100644
--- a/src/test/domain/work-orders/api/work-orders-api.test.ts
+++ b/src/test/domain/work-orders/api/work-orders-api.test.ts
@@ -114,6 +114,7 @@ describe("workOrdersApi.createFromBoard", () => {
type: "PM",
siteCode: "BK5",
woNumber: "12345",
+ customer: "Amazon",
});
expect(apiPost).toHaveBeenCalledWith(API_PATHS.workOrder.boardCreate, {
@@ -122,6 +123,7 @@ describe("workOrdersApi.createFromBoard", () => {
lifecycleStatus: 1,
woNumber: "12345",
isAddOn: false,
+ customer: "Amazon",
});
});
});
diff --git a/src/test/domain/work-orders/mappers/wizard-draft-mapper.test.ts b/src/test/domain/work-orders/mappers/wizard-draft-mapper.test.ts
index 3c128e93..fe70bd74 100644
--- a/src/test/domain/work-orders/mappers/wizard-draft-mapper.test.ts
+++ b/src/test/domain/work-orders/mappers/wizard-draft-mapper.test.ts
@@ -123,7 +123,7 @@ describe("wizard step validation", () => {
expect(isWizardStepValid(2, draft)).toBe(false);
});
- it("allows step 2 when site and POC are set", () => {
+ it("blocks step 2 without customer", () => {
const draft = {
...EMPTY_WIZARD_DRAFT,
type: "PM" as const,
@@ -133,6 +133,21 @@ describe("wizard step validation", () => {
pocName: "Jordan",
pocPhone: "555-0100",
};
+ expect(canContinueWizardStep2(draft)).toBe(false);
+ expect(isWizardStepValid(2, draft)).toBe(false);
+ });
+
+ it("allows step 2 when site, account, and POC are set", () => {
+ const draft = {
+ ...EMPTY_WIZARD_DRAFT,
+ type: "PM" as const,
+ woNumber: "12345",
+ locationId: "99",
+ siteCode: "BK5",
+ customer: "Amazon",
+ pocName: "Jordan",
+ pocPhone: "555-0100",
+ };
expect(canContinueWizardStep2(draft)).toBe(true);
expect(isWizardStepValid(2, draft)).toBe(true);
});
@@ -148,13 +163,14 @@ describe("wizard step validation", () => {
expect(isWizardStepValid(2, draft)).toBe(false);
});
- it("allows create when type, woNumber, site, and POC are set", () => {
+ it("allows create when type, woNumber, site, account, and POC are set", () => {
const draft = {
...EMPTY_WIZARD_DRAFT,
type: "PM" as const,
woNumber: "12345678901234567890",
locationId: "99",
siteCode: "BK5",
+ customer: "Amazon",
pocName: "Jordan",
pocPhone: "555-0100",
};
diff --git a/src/test/domain/work-orders/mappers/work-order-board-mapper.test.ts b/src/test/domain/work-orders/mappers/work-order-board-mapper.test.ts
index b9b1511d..ee3d5c27 100644
--- a/src/test/domain/work-orders/mappers/work-order-board-mapper.test.ts
+++ b/src/test/domain/work-orders/mappers/work-order-board-mapper.test.ts
@@ -60,6 +60,28 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
});
});
+ it("includes customer when the draft has an account name", () => {
+ const payload = mapWizardDraftToBoardCreatePayload({
+ ...EMPTY_WIZARD_DRAFT,
+ type: "PM",
+ siteCode: "BK5",
+ customer: " Amazon ",
+ });
+
+ expect(payload.customer).toBe("Amazon");
+ });
+
+ it("omits customer when the draft account is blank", () => {
+ const payload = mapWizardDraftToBoardCreatePayload({
+ ...EMPTY_WIZARD_DRAFT,
+ type: "PM",
+ siteCode: "BK5",
+ customer: " ",
+ });
+
+ expect(payload.customer).toBeUndefined();
+ });
+
it("sets isAddOn from cutoff preview when scheduled (create hint; not frozen)", () => {
const payload = mapWizardDraftToBoardCreatePayload({
...EMPTY_WIZARD_DRAFT,
diff --git a/src/test/domain/work-orders/utils/get-inline-create-missing.test.ts b/src/test/domain/work-orders/utils/get-inline-create-missing.test.ts
index 3ddd8dca..6d2204df 100644
--- a/src/test/domain/work-orders/utils/get-inline-create-missing.test.ts
+++ b/src/test/domain/work-orders/utils/get-inline-create-missing.test.ts
@@ -7,9 +7,10 @@ import {
} from "@/domain/work-orders/utils/get-inline-create-missing";
describe("getInlineCreateMissing", () => {
- it("returns empty when Site, WO#, and POC are filled even without schedule", () => {
+ it("returns empty when Account, Site, WO#, and POC are filled even without schedule", () => {
expect(
getInlineCreateMissing({
+ customer: "Amazon",
site: "BK5",
locationId: "12",
woNumber: "25001",
@@ -22,6 +23,7 @@ describe("getInlineCreateMissing", () => {
it("accepts locationId alone as site presence", () => {
expect(
getInlineCreateMissing({
+ customer: "Amazon",
site: "",
locationId: 42,
woNumber: "25001",
@@ -34,6 +36,7 @@ describe("getInlineCreateMissing", () => {
it("lists missing POC fields without requiring schedule", () => {
expect(
getInlineCreateMissing({
+ customer: "Amazon",
site: "BK5",
woNumber: "25001",
pocName: "",
@@ -42,8 +45,14 @@ describe("getInlineCreateMissing", () => {
).toEqual(["pocName", "pocPhone"]);
});
- it("lists site and woNumber when empty", () => {
- expect(getInlineCreateMissing({})).toEqual(["site", "woNumber", "pocName", "pocPhone"]);
+ it("lists account, site, and woNumber when empty", () => {
+ expect(getInlineCreateMissing({})).toEqual([
+ "customer",
+ "site",
+ "woNumber",
+ "pocName",
+ "pocPhone",
+ ]);
});
});
@@ -58,6 +67,10 @@ describe("inlineCreateSaveHint", () => {
});
describe("inlineCreateSiteError", () => {
+ it("prefers account-required message when account is missing", () => {
+ expect(inlineCreateSiteError(["customer", "site"])).toBe("Account is required");
+ });
+
it("prefers site-required message when site is missing", () => {
expect(inlineCreateSiteError(["site", "pocName"])).toBe("Site is required");
});