mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-01 15:33:12 +00:00
fix(work-orders): map detail problem and source into closability
detailToClosabilityInput now uses WorkOrderDetail.problem as pm and source as WO type so Done is not permanently blocked by a false Service gap. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
55449a9e31
commit
8cd6d92ba7
2 changed files with 39 additions and 8 deletions
|
|
@ -1,6 +1,10 @@
|
|||
import type { WorkOrderDetail } from "@/domain/work-orders/types/work-order-detail";
|
||||
import type { CompletionDocStatus } from "@/domain/work-orders/types/work-order-table-row";
|
||||
import type { WOType, WorkOrderWizardDraft } from "@/domain/work-orders/types/work-order-wizard";
|
||||
import {
|
||||
WO_TYPES,
|
||||
type WOType,
|
||||
type WorkOrderWizardDraft,
|
||||
} from "@/domain/work-orders/types/work-order-wizard";
|
||||
|
||||
/** Fields required to evaluate whether a WO may be marked Completed. */
|
||||
export type WoClosabilityInput = {
|
||||
|
|
@ -106,9 +110,15 @@ export function wizardDraftToClosabilityInput(draft: WorkOrderWizardDraft): WoCl
|
|||
};
|
||||
}
|
||||
|
||||
function detailSourceToWoType(source: string): WOType | "" {
|
||||
return (WO_TYPES as readonly string[]).includes(source) ? (source as WOType) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Map standalone detail DTO onto closability. Fields the detail route does not
|
||||
* expose (service, docStatus, media, type) stay empty so Completed fails closed.
|
||||
* Map standalone detail DTO onto closability. `problem` is the same service
|
||||
* field the board maps into `pm`; `source` carries wizard WO type when set.
|
||||
* docStatus/media stay empty (detail route does not expose them) so those
|
||||
* type-specific gates still fail closed.
|
||||
*/
|
||||
export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInput {
|
||||
const vendorName = wo.dispatches.find((dispatch) =>
|
||||
|
|
@ -121,9 +131,9 @@ export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInpu
|
|||
tech: "",
|
||||
completedDate: wo.completedDate,
|
||||
woNumber: wo.workOrderNumber || wo.internalWONumber,
|
||||
pm: "",
|
||||
pm: wo.problem,
|
||||
docStatus: "",
|
||||
mediaCount: 0,
|
||||
type: "",
|
||||
type: detailSourceToWoType(wo.source),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,12 +161,14 @@ describe("wizardDraftToClosabilityInput", () => {
|
|||
});
|
||||
|
||||
describe("detailToClosabilityInput", () => {
|
||||
it("maps vendorName to company and fails closed on missing service/media fields", () => {
|
||||
it("maps problem/source and vendorName so Done is not permanently blocked", () => {
|
||||
const detail = {
|
||||
assignedTo: "Alice",
|
||||
completedDate: "2026-07-15",
|
||||
workOrderNumber: "20260623001",
|
||||
internalWONumber: "SH-1",
|
||||
problem: "HVAC PM",
|
||||
source: "Add-On",
|
||||
dispatches: [{ vendorName: "ACME Tech" }],
|
||||
} as WorkOrderDetail;
|
||||
|
||||
|
|
@ -176,9 +178,28 @@ describe("detailToClosabilityInput", () => {
|
|||
expect(input.tech).toBe("");
|
||||
expect(input.completedDate).toBe("2026-07-15");
|
||||
expect(input.woNumber).toBe("20260623001");
|
||||
expect(input.pm).toBe("");
|
||||
expect(getClosabilityGaps(input)).toContain("Service");
|
||||
expect(input.pm).toBe("HVAC PM");
|
||||
expect(input.type).toBe("Add-On");
|
||||
expect(getClosabilityGaps(input)).not.toContain("Service");
|
||||
expect(getClosabilityGaps(input)).not.toContain("Company");
|
||||
expect(getClosabilityGaps(input)).not.toContain("Technician");
|
||||
expect(getClosabilityGaps(input)).toEqual([]);
|
||||
});
|
||||
|
||||
it("fails closed on missing service when problem is empty", () => {
|
||||
const detail = {
|
||||
assignedTo: "Alice",
|
||||
completedDate: "2026-07-15",
|
||||
workOrderNumber: "20260623001",
|
||||
internalWONumber: "SH-1",
|
||||
problem: "",
|
||||
source: "Reactive",
|
||||
dispatches: [{ vendorName: "ACME Tech" }],
|
||||
} as WorkOrderDetail;
|
||||
|
||||
const input = detailToClosabilityInput(detail);
|
||||
expect(input.pm).toBe("");
|
||||
expect(input.type).toBe("Reactive");
|
||||
expect(getClosabilityGaps(input)).toContain("Service");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue