From 96f3daf20cf6317e4ed3c4cee70a2050cb49d4b6 Mon Sep 17 00:00:00 2001 From: Arthur Bassi Date: Fri, 31 Jul 2026 09:37:10 -0300 Subject: [PATCH] fix(work-orders): persist completedDate without legacy GetWorkorderById Save Draft failed on GetWorkorderById (HTTP 400) before EditWorkorder. Post only Id + CompletedDate and cover the EditWorkorder route contract. --- src/domain/work-orders/api/work-orders-api.ts | 9 +++++ .../work-orders/mappers/work-order-mapper.ts | 11 ++++++ .../use-work-order-table-mutations.ts | 11 ++---- .../work-orders/api/work-orders-api.test.ts | 30 ++++++++++++++++ .../mappers/work-order-form-payload.test.ts | 22 ++++++++++++ ...der-table-mutations-completed-date.test.ts | 35 +++++++++++++++++++ 6 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 src/test/domain/work-orders/use-cases/use-work-order-table-mutations-completed-date.test.ts diff --git a/src/domain/work-orders/api/work-orders-api.ts b/src/domain/work-orders/api/work-orders-api.ts index 7b0da992..c68874e7 100644 --- a/src/domain/work-orders/api/work-orders-api.ts +++ b/src/domain/work-orders/api/work-orders-api.ts @@ -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 => { + await apiPostForm<{ message?: string; status?: string }>( + API_PATHS.workOrder.editWorkorder, + mapCompletedDateUpdateFormData(id, completedDate), + ); + }, + delete: async (id: string | number): Promise => { await apiDelete(API_PATHS.workOrder.deleteWorkorder, { json: { Id: Number(id) }, diff --git a/src/domain/work-orders/mappers/work-order-mapper.ts b/src/domain/work-orders/mappers/work-order-mapper.ts index 941494c2..ba3a3691 100644 --- a/src/domain/work-orders/mappers/work-order-mapper.ts +++ b/src/domain/work-orders/mappers/work-order-mapper.ts @@ -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"); diff --git a/src/domain/work-orders/use-cases/use-work-order-table-mutations.ts b/src/domain/work-orders/use-cases/use-work-order-table-mutations.ts index 0f878eb4..bf678231 100644 --- a/src/domain/work-orders/use-cases/use-work-order-table-mutations.ts +++ b/src/domain/work-orders/use-cases/use-work-order-table-mutations.ts @@ -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 { - 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, 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 7d0b91ea..1cc433a1 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 @@ -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(); diff --git a/src/test/domain/work-orders/mappers/work-order-form-payload.test.ts b/src/test/domain/work-orders/mappers/work-order-form-payload.test.ts index 6f7a9378..c7f5936f 100644 --- a/src/test/domain/work-orders/mappers/work-order-form-payload.test.ts +++ b/src/test/domain/work-orders/mappers/work-order-form-payload.test.ts @@ -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(); + }); +}); diff --git a/src/test/domain/work-orders/use-cases/use-work-order-table-mutations-completed-date.test.ts b/src/test/domain/work-orders/use-cases/use-work-order-table-mutations-completed-date.test.ts new file mode 100644 index 00000000..984c03a6 --- /dev/null +++ b/src/test/domain/work-orders/use-cases/use-work-order-table-mutations-completed-date.test.ts @@ -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" } }); + }); +});