mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-06 11:12:04 +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 { WorkOrderDetail } from "@/domain/work-orders/types/work-order-detail";
|
||||||
import type { CompletionDocStatus } from "@/domain/work-orders/types/work-order-table-row";
|
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. */
|
/** Fields required to evaluate whether a WO may be marked Completed. */
|
||||||
export type WoClosabilityInput = {
|
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
|
* Map standalone detail DTO onto closability. `problem` is the same service
|
||||||
* expose (service, docStatus, media, type) stay empty so Completed fails closed.
|
* 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 {
|
export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInput {
|
||||||
const vendorName = wo.dispatches.find((dispatch) =>
|
const vendorName = wo.dispatches.find((dispatch) =>
|
||||||
|
|
@ -121,9 +131,9 @@ export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInpu
|
||||||
tech: "",
|
tech: "",
|
||||||
completedDate: wo.completedDate,
|
completedDate: wo.completedDate,
|
||||||
woNumber: wo.workOrderNumber || wo.internalWONumber,
|
woNumber: wo.workOrderNumber || wo.internalWONumber,
|
||||||
pm: "",
|
pm: wo.problem,
|
||||||
docStatus: "",
|
docStatus: "",
|
||||||
mediaCount: 0,
|
mediaCount: 0,
|
||||||
type: "",
|
type: detailSourceToWoType(wo.source),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,12 +161,14 @@ describe("wizardDraftToClosabilityInput", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("detailToClosabilityInput", () => {
|
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 = {
|
const detail = {
|
||||||
assignedTo: "Alice",
|
assignedTo: "Alice",
|
||||||
completedDate: "2026-07-15",
|
completedDate: "2026-07-15",
|
||||||
workOrderNumber: "20260623001",
|
workOrderNumber: "20260623001",
|
||||||
internalWONumber: "SH-1",
|
internalWONumber: "SH-1",
|
||||||
|
problem: "HVAC PM",
|
||||||
|
source: "Add-On",
|
||||||
dispatches: [{ vendorName: "ACME Tech" }],
|
dispatches: [{ vendorName: "ACME Tech" }],
|
||||||
} as WorkOrderDetail;
|
} as WorkOrderDetail;
|
||||||
|
|
||||||
|
|
@ -176,9 +178,28 @@ describe("detailToClosabilityInput", () => {
|
||||||
expect(input.tech).toBe("");
|
expect(input.tech).toBe("");
|
||||||
expect(input.completedDate).toBe("2026-07-15");
|
expect(input.completedDate).toBe("2026-07-15");
|
||||||
expect(input.woNumber).toBe("20260623001");
|
expect(input.woNumber).toBe("20260623001");
|
||||||
expect(input.pm).toBe("");
|
expect(input.pm).toBe("HVAC PM");
|
||||||
expect(getClosabilityGaps(input)).toContain("Service");
|
expect(input.type).toBe("Add-On");
|
||||||
|
expect(getClosabilityGaps(input)).not.toContain("Service");
|
||||||
expect(getClosabilityGaps(input)).not.toContain("Company");
|
expect(getClosabilityGaps(input)).not.toContain("Company");
|
||||||
expect(getClosabilityGaps(input)).not.toContain("Technician");
|
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