mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-05 02:32:08 +00:00
Dispatchers need the design surface from the column and the detail, and an optional evidence file is sent only after the scan passes.
207 lines
6 KiB
TypeScript
207 lines
6 KiB
TypeScript
import type {
|
|
UpliftSummary,
|
|
WorkOrderUplift,
|
|
WorkOrderUpliftAttachment,
|
|
WorkOrderUpliftStatus,
|
|
} from "@/domain/work-orders/types/work-order-uplift";
|
|
import { WORK_ORDER_UPLIFT_STATUSES } from "@/domain/work-orders/types/work-order-uplift";
|
|
|
|
function asRecord(raw: unknown): Record<string, unknown> {
|
|
return typeof raw === "object" && raw !== null ? (raw as Record<string, unknown>) : {};
|
|
}
|
|
|
|
function readString(record: Record<string, unknown>, ...keys: string[]): string {
|
|
for (const key of keys) {
|
|
const value = record[key];
|
|
if (typeof value === "string") {
|
|
return value;
|
|
}
|
|
if (typeof value === "number") {
|
|
return String(value);
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function readNumber(record: Record<string, unknown>, ...keys: string[]): number | null {
|
|
for (const key of keys) {
|
|
const value = record[key];
|
|
if (typeof value === "number") {
|
|
return value;
|
|
}
|
|
if (typeof value === "string" && value !== "") {
|
|
const parsed = Number(value);
|
|
if (!Number.isNaN(parsed)) {
|
|
return parsed;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function readBool(record: Record<string, unknown>, ...keys: string[]): boolean {
|
|
for (const key of keys) {
|
|
const value = record[key];
|
|
if (typeof value === "boolean") {
|
|
return value;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function readId(record: Record<string, unknown>): string | number {
|
|
const value = record.id ?? record.Id;
|
|
if (typeof value === "string" || typeof value === "number") {
|
|
return value;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function readOptionalId(
|
|
record: Record<string, unknown>,
|
|
...keys: string[]
|
|
): string | number | null {
|
|
for (const key of keys) {
|
|
const value = record[key];
|
|
if (typeof value === "string" || typeof value === "number") {
|
|
return value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const STATUS_SET = new Set<string>(WORK_ORDER_UPLIFT_STATUSES);
|
|
|
|
function normalizeUpliftStatus(raw: string): WorkOrderUpliftStatus {
|
|
const normalized = raw.trim().toLowerCase().replace(/\s+/g, "_");
|
|
if (STATUS_SET.has(normalized)) {
|
|
return normalized as WorkOrderUpliftStatus;
|
|
}
|
|
if (normalized === "canceled") {
|
|
return "cancelled";
|
|
}
|
|
if (normalized === "autoapproved") {
|
|
return "auto_approved";
|
|
}
|
|
return "pending";
|
|
}
|
|
|
|
export function mapUpliftSummary(raw: unknown): UpliftSummary {
|
|
const item = asRecord(raw);
|
|
const nested = asRecord(item.upliftSummary ?? item.UpliftSummary);
|
|
const hasNested = Object.keys(nested).length > 0;
|
|
const source = hasNested ? nested : item;
|
|
|
|
const pendingCount =
|
|
readNumber(source, "pendingCount", "PendingCount") ??
|
|
readNumber(item, "pendingUpliftCount", "PendingUpliftCount") ??
|
|
0;
|
|
const hasUplift =
|
|
readBool(source, "hasUplift", "HasUplift") ||
|
|
readBool(item, "hasUplift", "HasUplift") ||
|
|
pendingCount > 0;
|
|
|
|
// Never treat the work-order lifecycle status/Status as uplift primaryStatus.
|
|
const primaryStatusRaw = hasNested
|
|
? readString(source, "primaryStatus", "PrimaryStatus", "status", "Status")
|
|
: readString(item, "primaryStatus", "PrimaryStatus");
|
|
const amount = hasNested
|
|
? readNumber(source, "amount", "Amount")
|
|
: readNumber(item, "amount", "Amount");
|
|
|
|
const summary: UpliftSummary = {
|
|
hasUplift,
|
|
pendingCount,
|
|
};
|
|
|
|
if (primaryStatusRaw) {
|
|
summary.primaryStatus = normalizeUpliftStatus(primaryStatusRaw);
|
|
}
|
|
if (amount != null) {
|
|
summary.amount = amount;
|
|
}
|
|
|
|
return summary;
|
|
}
|
|
|
|
function mapUpliftAttachment(raw: unknown, index: number): WorkOrderUpliftAttachment | null {
|
|
const record = asRecord(raw);
|
|
const name = readString(record, "name", "Name", "fileName", "FileName");
|
|
if (name === "") return null;
|
|
const idValue = record.id ?? record.Id;
|
|
const id =
|
|
typeof idValue === "string" || typeof idValue === "number"
|
|
? String(idValue)
|
|
: `${name}-${index}`;
|
|
return {
|
|
id,
|
|
name,
|
|
url: readString(record, "url", "Url", "fileUrl", "FileUrl"),
|
|
};
|
|
}
|
|
|
|
function mapUpliftAttachments(raw: unknown): WorkOrderUpliftAttachment[] {
|
|
if (!Array.isArray(raw)) return [];
|
|
return raw.flatMap((item, index) => {
|
|
const attachment = mapUpliftAttachment(item, index);
|
|
return attachment == null ? [] : [attachment];
|
|
});
|
|
}
|
|
|
|
function mapEvidenceAttachment(item: Record<string, unknown>): WorkOrderUpliftAttachment[] {
|
|
const listed = mapUpliftAttachments(
|
|
item.attachments ?? item.Attachments ?? item.documents ?? item.Documents,
|
|
);
|
|
if (listed.length > 0) return listed;
|
|
const evidenceId = readOptionalId(item, "evidenceDocumentId", "EvidenceDocumentId");
|
|
const name = readString(
|
|
item,
|
|
"evidenceFileName",
|
|
"EvidenceFileName",
|
|
"originalFileName",
|
|
"OriginalFileName",
|
|
);
|
|
if (evidenceId == null && name === "") return [];
|
|
return [
|
|
{
|
|
id: evidenceId == null ? "evidence" : String(evidenceId),
|
|
name: name === "" ? `Document #${evidenceId}` : name,
|
|
url: "",
|
|
},
|
|
];
|
|
}
|
|
|
|
export function mapWorkOrderUplift(raw: unknown): WorkOrderUplift {
|
|
const item = asRecord(raw);
|
|
const statusRaw = readString(item, "status", "Status");
|
|
|
|
return {
|
|
id: readId(item),
|
|
status: statusRaw ? normalizeUpliftStatus(statusRaw) : "pending",
|
|
amount: readNumber(item, "amount", "Amount", "requestedNTE", "RequestedNTE") ?? 0,
|
|
notes: readString(item, "notes", "Notes", "vendorReason", "VendorReason"),
|
|
requestedAt: readString(item, "requestedAt", "RequestedAt"),
|
|
requestedById: readOptionalId(
|
|
item,
|
|
"requestedById",
|
|
"RequestedById",
|
|
"requesterId",
|
|
"RequesterId",
|
|
),
|
|
requestedByName: readString(
|
|
item,
|
|
"requestedByName",
|
|
"RequestedByName",
|
|
"requestedByVendorName",
|
|
"RequestedByVendorName",
|
|
),
|
|
decidedAt: readString(item, "decidedAt", "DecidedAt"),
|
|
decidedByName: readString(item, "decidedByName", "DecidedByName"),
|
|
decisionNote: readString(item, "decisionNote", "DecisionNote", "revokeReason", "RevokeReason"),
|
|
attachments: mapEvidenceAttachment(item),
|
|
};
|
|
}
|
|
|
|
export function mapWorkOrderUplifts(rawItems: unknown[]): WorkOrderUplift[] {
|
|
return rawItems.map(mapWorkOrderUplift);
|
|
}
|