fix(work-orders): align detail type mapping with Add-On indicator (SH-114)

Merging dev broke this branch: SH-126/SH-184 made Add-On a backend-authoritative
indicator (isAddOn) and removed it from the WOType union, but
read-detail-closability-fields still accepted "Add-On" and mapped "AddOn" onto
it, so tsc failed on both the mapper and the closability test.

Drop Add-On from the detail type set so a legacy payload normalizes to "", and
cover the normalization directly instead of asserting it through
detailToClosabilityInput, which only forwards the already-typed value.
This commit is contained in:
Codex Review Integration 2026-08-18 17:53:41 -03:00
parent 5ad13d38ca
commit 4449e49149
2 changed files with 24 additions and 6 deletions

View file

@ -5,7 +5,9 @@ import {
import type { CompletionDocStatus } from "@/domain/work-orders/types/work-order-table-row";
import type { WOType } from "@/domain/work-orders/types/work-order-wizard";
const DETAIL_WO_TYPES = new Set(["PM", "Reactive", "Emergency", "Add-On", "Overdue"]);
// SH-126/SH-184: Add-On is a backend-authoritative indicator (`isAddOn`), not a
// selectable business type, so it is no longer part of the WOType union.
const DETAIL_WO_TYPES = new Set(["PM", "Reactive", "Emergency", "Overdue"]);
function asRecord(raw: unknown): Record<string, unknown> {
return typeof raw === "object" && raw !== null ? (raw as Record<string, unknown>) : {};
@ -60,9 +62,6 @@ export function readDetailWoType(record: Record<string, unknown>): WOType | "" {
if (DETAIL_WO_TYPES.has(raw)) {
return raw as WOType;
}
if (raw === "AddOn") {
return "Add-On";
}
return "";
}

View file

@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import type { WorkOrderDetail } from "@/domain/work-orders/types/work-order-detail";
import { readDetailWoType } from "@/domain/work-orders/mappers/read-detail-closability-fields";
import type { WoClosabilityInput } from "@/domain/work-orders/utils/wo-closability";
import {
detailToClosabilityInput,
@ -169,7 +170,10 @@ describe("detailToClosabilityInput", () => {
internalWONumber: "SH-1",
problem: "HVAC PM",
source: "procurement-integration",
type: "Add-On",
// SH-126/SH-184: Add-On is a backend-authoritative indicator (`isAddOn`), not a
// WOType, so it is no longer a valid value here. Normalization of a legacy
// "Add-On"/"AddOn" payload is covered by readDetailWoType.
type: "",
docStatus: "",
mediaCount: 0,
dispatches: [{ vendorName: "ACME Tech" }],
@ -182,7 +186,7 @@ describe("detailToClosabilityInput", () => {
expect(input.completedDate).toBe("2026-07-15");
expect(input.woNumber).toBe("20260623001");
expect(input.pm).toBe("HVAC PM");
expect(input.type).toBe("Add-On");
expect(input.type).toBe("");
expect(input.docStatus).toBe("");
expect(input.mediaCount).toBe(0);
expect(getClosabilityGaps(input)).not.toContain("Service");
@ -299,3 +303,18 @@ describe("detailToClosabilityInput", () => {
expect(getClosabilityGaps(detailToClosabilityInput(detail))).toEqual(["At least 1 photo"]);
});
});
describe("readDetailWoType", () => {
it.each(["PM", "Reactive", "Emergency", "Overdue"])("passes through the business type %s", (type) => {
expect(readDetailWoType({ workOrderType: type })).toBe(type);
});
it.each(["Add-On", "AddOn"])(
"normalizes the legacy Add-On payload %s to empty (SH-126/SH-184)",
(legacy) => {
// Add-On became a backend-authoritative indicator (`isAddOn`) and is no longer a
// selectable business type, so a stale payload must not resolve to a WOType.
expect(readDetailWoType({ workOrderType: legacy })).toBe("");
},
);
});