mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 02:22:06 +00:00
fix(work-orders): ignore cancelled dispatches in detail closability (SH-183)
This commit is contained in:
parent
1554cf30d0
commit
a43de20ed4
2 changed files with 62 additions and 4 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { WorkOrderDispatchSummary } from "@/domain/work-orders/types/dispatch";
|
||||||
import type { WorkOrderDetail } from "@/domain/work-orders/types/work-order-detail";
|
import type { WorkOrderDetail } from "@/domain/work-orders/types/work-order-detail";
|
||||||
import type {
|
import type {
|
||||||
CompletionDocStatus,
|
CompletionDocStatus,
|
||||||
|
|
@ -156,16 +157,26 @@ export function wizardDraftToClosabilityInput(draft: WorkOrderWizardDraft): WoCl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Current vendor assignment — cancelled dispatches do not count as company (SH-183). */
|
||||||
|
function currentAssignedDispatch(
|
||||||
|
dispatches: WorkOrderDispatchSummary[],
|
||||||
|
): WorkOrderDispatchSummary | undefined {
|
||||||
|
return dispatches.find((dispatch) => {
|
||||||
|
if (dispatch.status === "Cancelled") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const vendorId = String(dispatch.vendorId ?? "").trim();
|
||||||
|
return Boolean((dispatch.vendorName ?? "").trim() || vendorId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map standalone detail DTO onto closability. Uses authoritative `type` / `docStatus` /
|
* Map standalone detail DTO onto closability. Uses authoritative `type` / `docStatus` /
|
||||||
* `mediaCount` (enriched from board detail on the view route). Never treats `source`
|
* `mediaCount` (enriched from board detail on the view route). Never treats `source`
|
||||||
* as WorkOrderType. `problem` is the same service field the board maps into `pm`.
|
* as WorkOrderType. `problem` is the same service field the board maps into `pm`.
|
||||||
*/
|
*/
|
||||||
export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInput {
|
export function detailToClosabilityInput(wo: WorkOrderDetail): WoClosabilityInput {
|
||||||
const assigned = wo.dispatches.find((dispatch) => {
|
const assigned = currentAssignedDispatch(wo.dispatches);
|
||||||
const vendorId = String(dispatch.vendorId ?? "").trim();
|
|
||||||
return Boolean(dispatch.vendorName.trim() || vendorId);
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
dispatcherId: "",
|
dispatcherId: "",
|
||||||
dispatcherName: wo.assignedTo,
|
dispatcherName: wo.assignedTo,
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,22 @@ describe("getClosabilityGaps", () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each(["PM", "Reactive", "Emergency", "Overdue", ""] as const)(
|
||||||
|
"blocks Completed without a company for type %s (SH-183)",
|
||||||
|
(type) => {
|
||||||
|
const gaps = getClosabilityGaps(
|
||||||
|
makeInput({
|
||||||
|
company: "",
|
||||||
|
vendorId: "",
|
||||||
|
type,
|
||||||
|
docStatus: "Yes",
|
||||||
|
mediaCount: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(gaps).toContain("Company");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it("lists field gaps before uplift and document gaps", () => {
|
it("lists field gaps before uplift and document gaps", () => {
|
||||||
expect(
|
expect(
|
||||||
getClosabilityGaps(
|
getClosabilityGaps(
|
||||||
|
|
@ -310,6 +326,37 @@ describe("detailToClosabilityInput", () => {
|
||||||
expect(input.vendorId).toBe("45");
|
expect(input.vendorId).toBe("45");
|
||||||
expect(getClosabilityGaps(input)).toEqual([]);
|
expect(getClosabilityGaps(input)).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("ignores cancelled dispatches when resolving assigned company (SH-183)", () => {
|
||||||
|
const cancelledOnly = {
|
||||||
|
assignedTo: "Alice",
|
||||||
|
completedDate: "2026-07-15",
|
||||||
|
workOrderNumber: "20260623001",
|
||||||
|
internalWONumber: "SH-1",
|
||||||
|
problem: "HVAC PM",
|
||||||
|
source: "procurement-integration",
|
||||||
|
type: "",
|
||||||
|
docStatus: "",
|
||||||
|
mediaCount: 0,
|
||||||
|
dispatches: [{ vendorName: "", vendorId: 45, status: "Cancelled" }],
|
||||||
|
} as WorkOrderDetail;
|
||||||
|
|
||||||
|
expect(detailToClosabilityInput(cancelledOnly).vendorId).toBe("");
|
||||||
|
expect(getClosabilityGaps(detailToClosabilityInput(cancelledOnly))).toContain("Company");
|
||||||
|
|
||||||
|
const supersededThenCurrent = {
|
||||||
|
...cancelledOnly,
|
||||||
|
dispatches: [
|
||||||
|
{ vendorName: "Old Co", vendorId: 1, status: "Cancelled" },
|
||||||
|
{ vendorName: "ACME Tech", vendorId: 45, status: "Sent" },
|
||||||
|
],
|
||||||
|
} as WorkOrderDetail;
|
||||||
|
|
||||||
|
const input = detailToClosabilityInput(supersededThenCurrent);
|
||||||
|
expect(input.company).toBe("ACME Tech");
|
||||||
|
expect(input.vendorId).toBe("45");
|
||||||
|
expect(getClosabilityGaps(input)).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("readDetailWoType", () => {
|
describe("readDetailWoType", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue