mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
Compare commits
2 commits
b2d44944ab
...
27c7c8df55
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27c7c8df55 | ||
|
|
96f3daf20c |
7 changed files with 128 additions and 38 deletions
|
|
@ -18,6 +18,7 @@ import {
|
|||
mapUpdateDispatchPayload,
|
||||
mapVendorDropdownItems,
|
||||
mapWorkOrderDetail,
|
||||
mapCompletedDateUpdateFormData,
|
||||
mapWorkOrderFormToCreatePayload,
|
||||
mapWorkOrderFormToUpdateFormData,
|
||||
mapWorkOrderTableRow,
|
||||
|
|
@ -307,6 +308,14 @@ export const workOrdersApi = {
|
|||
);
|
||||
},
|
||||
|
||||
/** Persist only CompletedDate via EditWorkorder — no GetWorkorderById prefetch. */
|
||||
updateCompletedDate: async (id: string | number, completedDate: string): Promise<void> => {
|
||||
await apiPostForm<{ message?: string; status?: string }>(
|
||||
API_PATHS.workOrder.editWorkorder,
|
||||
mapCompletedDateUpdateFormData(id, completedDate),
|
||||
);
|
||||
},
|
||||
|
||||
delete: async (id: string | number): Promise<void> => {
|
||||
await apiDelete(API_PATHS.workOrder.deleteWorkorder, {
|
||||
json: { Id: Number(id) },
|
||||
|
|
|
|||
|
|
@ -405,6 +405,17 @@ export function mapWorkOrderFormToUpdateFormData(
|
|||
return formData;
|
||||
}
|
||||
|
||||
/** Partial EditWorkorder payload — only Id + CompletedDate (avoids legacy GetWorkorderById). */
|
||||
export function mapCompletedDateUpdateFormData(
|
||||
id: string | number,
|
||||
completedDate: string,
|
||||
): FormData {
|
||||
const formData = new FormData();
|
||||
formData.append("Id", String(id));
|
||||
appendIfPresent(formData, "CompletedDate", completedDate);
|
||||
return formData;
|
||||
}
|
||||
|
||||
export function mapLocationOption(raw: unknown): LocationOption {
|
||||
const item = asRecord(raw);
|
||||
const name = readString(item, "name", "Name", "locationName", "LocationName");
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@ import {
|
|||
expandTablePatchToBoardFieldOps,
|
||||
isLocalOnlyTablePatch,
|
||||
} from "@/domain/work-orders/mappers/work-order-board-patch-mapper";
|
||||
import {
|
||||
mapWorkOrderDetailToFormValues,
|
||||
mapWorkOrderTableRow,
|
||||
} from "@/domain/work-orders/mappers/work-order-mapper";
|
||||
import { mapWorkOrderTableRow } from "@/domain/work-orders/mappers/work-order-mapper";
|
||||
import type {
|
||||
WorkOrderTablePatch,
|
||||
WorkOrderTableRow,
|
||||
|
|
@ -37,9 +34,7 @@ type PatchResult =
|
|||
{ kind: "local"; patch: WorkOrderTablePatch } | { kind: "board"; row: WorkOrderTableRow };
|
||||
|
||||
async function persistCompletedDate(id: string | number, completedDate: string): Promise<void> {
|
||||
const detail = await workOrdersApi.getById(id);
|
||||
const values = mapWorkOrderDetailToFormValues(detail);
|
||||
await workOrdersApi.update(id, { ...values, completedDate });
|
||||
await workOrdersApi.updateCompletedDate(id, completedDate);
|
||||
}
|
||||
|
||||
async function applyBoardFieldOps(
|
||||
|
|
@ -85,7 +80,7 @@ async function applyBoardFieldOps(
|
|||
}
|
||||
|
||||
/** CompDoc completedDate uses EditWorkorder; board fields use PATCH …/board. */
|
||||
async function runWorkOrderTablePatch(
|
||||
export async function runWorkOrderTablePatch(
|
||||
id: string | number,
|
||||
patch: WorkOrderTablePatch,
|
||||
getRow: ((id: string | number) => WorkOrderTableRow | undefined) | undefined,
|
||||
|
|
|
|||
|
|
@ -165,6 +165,36 @@ describe("workOrdersApi.update", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("workOrdersApi.updateCompletedDate", () => {
|
||||
beforeEach(() => {
|
||||
apiGet.mockReset();
|
||||
apiPost.mockReset();
|
||||
apiPostForm.mockReset();
|
||||
apiPostForm.mockResolvedValue({ message: "Updated Successfully", status: "200" });
|
||||
});
|
||||
|
||||
it("posts only Id and CompletedDate to EditWorkorder without GetWorkorderById", async () => {
|
||||
await workOrdersApi.updateCompletedDate(55, "2026-07-30");
|
||||
|
||||
expect(apiGet).not.toHaveBeenCalled();
|
||||
expect(apiPost).not.toHaveBeenCalled();
|
||||
expect(apiPostForm).toHaveBeenCalledTimes(1);
|
||||
expect(apiPostForm).toHaveBeenCalledWith(
|
||||
API_PATHS.workOrder.editWorkorder,
|
||||
expect.any(FormData),
|
||||
);
|
||||
expect(API_PATHS.workOrder.editWorkorder).toBe("WorkOrder/EditWorkorder");
|
||||
expect(API_PATHS.workOrder.getById).toBe("WorkOrder/GetWorkorderById");
|
||||
|
||||
const formData = apiPostForm.mock.calls[0]?.[1] as FormData;
|
||||
expect(formData.get("Id")).toBe("55");
|
||||
expect(formData.get("CompletedDate")).toBe("2026-07-30");
|
||||
expect(formData.get("Status")).toBeNull();
|
||||
expect(formData.get("WorkerOrderTitle")).toBeNull();
|
||||
expect(formData.getAll("ContactIds")).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("workOrdersApi.fetchDispatchers", () => {
|
||||
beforeEach(() => {
|
||||
apiGet.mockReset();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
mapCompletedDateUpdateFormData,
|
||||
mapWorkOrderFormToCreatePayload,
|
||||
mapWorkOrderFormToUpdateFormData,
|
||||
} from "@/domain/work-orders/mappers/work-order-mapper";
|
||||
|
|
@ -150,3 +151,24 @@ describe("mapWorkOrderFormToUpdateFormData", () => {
|
|||
expect(formData.has("DocStatus")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mapCompletedDateUpdateFormData", () => {
|
||||
it("builds FormData with only Id and CompletedDate", () => {
|
||||
const formData = mapCompletedDateUpdateFormData(42, "2026-07-30");
|
||||
|
||||
expect(formData.get("Id")).toBe("42");
|
||||
expect(formData.get("CompletedDate")).toBe("2026-07-30");
|
||||
expect(formData.get("Status")).toBeNull();
|
||||
expect(formData.get("WorkerOrderTitle")).toBeNull();
|
||||
expect(formData.get("Description")).toBeNull();
|
||||
expect(formData.getAll("ContactIds")).toEqual([]);
|
||||
expect(formData.getAll("CategoryIds")).toEqual([]);
|
||||
});
|
||||
|
||||
it("omits empty CompletedDate", () => {
|
||||
const formData = mapCompletedDateUpdateFormData(1, " ");
|
||||
|
||||
expect(formData.get("Id")).toBe("1");
|
||||
expect(formData.get("CompletedDate")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const getById = vi.fn();
|
||||
const update = vi.fn();
|
||||
const updateCompletedDate = vi.fn();
|
||||
|
||||
vi.mock("@/domain/work-orders/api/work-orders-api", () => ({
|
||||
workOrdersApi: {
|
||||
getById: (...args: unknown[]) => getById(...args),
|
||||
update: (...args: unknown[]) => update(...args),
|
||||
updateCompletedDate: (...args: unknown[]) => updateCompletedDate(...args),
|
||||
patchBoardField: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
import { runWorkOrderTablePatch } from "@/domain/work-orders/use-cases/use-work-order-table-mutations";
|
||||
|
||||
describe("runWorkOrderTablePatch completedDate", () => {
|
||||
beforeEach(() => {
|
||||
getById.mockReset();
|
||||
update.mockReset();
|
||||
updateCompletedDate.mockReset();
|
||||
updateCompletedDate.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
it("persists completedDate via updateCompletedDate without getById", async () => {
|
||||
const result = await runWorkOrderTablePatch(99, { completedDate: "2026-07-30" }, undefined);
|
||||
|
||||
expect(getById).not.toHaveBeenCalled();
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
expect(updateCompletedDate).toHaveBeenCalledTimes(1);
|
||||
expect(updateCompletedDate).toHaveBeenCalledWith(99, "2026-07-30");
|
||||
expect(result).toEqual({ kind: "local", patch: { completedDate: "2026-07-30" } });
|
||||
});
|
||||
});
|
||||
|
|
@ -2,17 +2,19 @@ import type { ReactNode } from "react";
|
|||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { act, renderHook, waitFor } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { WorkOrderDetail, WorkOrderFormValues } from "@/domain/work-orders/types/work-order";
|
||||
import type { WorkOrderDetail } from "@/domain/work-orders/types/work-order";
|
||||
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
||||
|
||||
const getById = vi.fn();
|
||||
const update = vi.fn();
|
||||
const updateCompletedDate = vi.fn();
|
||||
const patchBoardField = vi.fn();
|
||||
|
||||
vi.mock("@/domain/work-orders/api/work-orders-api", () => ({
|
||||
workOrdersApi: {
|
||||
getById: (...args: unknown[]) => getById(...args),
|
||||
update: (...args: unknown[]) => update(...args),
|
||||
updateCompletedDate: (...args: unknown[]) => updateCompletedDate(...args),
|
||||
patchBoardField: (...args: unknown[]) => patchBoardField(...args),
|
||||
},
|
||||
}));
|
||||
|
|
@ -117,6 +119,7 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
|
|||
beforeEach(() => {
|
||||
getById.mockReset();
|
||||
update.mockReset();
|
||||
updateCompletedDate.mockReset();
|
||||
patchBoardField.mockReset();
|
||||
serverState = { ...BASE_DETAIL };
|
||||
rowState = { ...BASE_ROW };
|
||||
|
|
@ -144,24 +147,11 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
|
|||
},
|
||||
);
|
||||
|
||||
getById.mockImplementation(async () => {
|
||||
events.push("getById:start");
|
||||
await delay(15);
|
||||
events.push("getById:end");
|
||||
return { ...serverState };
|
||||
});
|
||||
|
||||
update.mockImplementation(async (_id: unknown, values: WorkOrderFormValues) => {
|
||||
events.push("update:start");
|
||||
updateCompletedDate.mockImplementation(async (_id: unknown, completedDate: string) => {
|
||||
events.push("updateCompletedDate:start");
|
||||
await delay(5);
|
||||
serverState = {
|
||||
...serverState,
|
||||
scheduledDate: values.scheduledDate,
|
||||
completedDate: values.completedDate,
|
||||
status: values.status,
|
||||
};
|
||||
events.push("update:end");
|
||||
return { ...serverState };
|
||||
serverState = { ...serverState, completedDate };
|
||||
events.push("updateCompletedDate:end");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -189,10 +179,12 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
|
|||
workOrderVersion: "AAAAAAA=",
|
||||
});
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
expect(updateCompletedDate).not.toHaveBeenCalled();
|
||||
expect(getById).not.toHaveBeenCalled();
|
||||
expect(serverState.docStatus).toBe("NN");
|
||||
});
|
||||
|
||||
it("serializes board docStatus and completedDate full-update without racing", async () => {
|
||||
it("serializes board docStatus and completedDate without racing or GetWorkorderById", async () => {
|
||||
const onPatch = vi.fn();
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
|
|
@ -209,27 +201,23 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
|
|||
result.current.patchField(42, { completedDate: "2026-07-20" });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(events).toContain("update:end"));
|
||||
await waitFor(() => expect(events).toContain("updateCompletedDate:end"));
|
||||
await waitFor(() => expect(events).toContain("boardPatch:end"));
|
||||
|
||||
expect(events).toEqual([
|
||||
"boardPatch:start",
|
||||
"boardPatch:end",
|
||||
"getById:start",
|
||||
"getById:end",
|
||||
"update:start",
|
||||
"update:end",
|
||||
"updateCompletedDate:start",
|
||||
"updateCompletedDate:end",
|
||||
]);
|
||||
|
||||
expect(getById).not.toHaveBeenCalled();
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
expect(updateCompletedDate).toHaveBeenCalledWith(42, "2026-07-20");
|
||||
|
||||
expect(serverState.docStatus).toBe("Yes");
|
||||
expect(serverState.completedDate).toBe("2026-07-20");
|
||||
expect(serverState.scheduledDate).toBe(BASE_DETAIL.scheduledDate);
|
||||
expect(serverState.status).toBe(BASE_DETAIL.status);
|
||||
|
||||
for (const call of update.mock.calls) {
|
||||
const values = call[1] as WorkOrderFormValues;
|
||||
expect(values.scheduledDate).toBe(BASE_DETAIL.scheduledDate);
|
||||
expect(values.status).not.toBe("Done");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue