shoc-frontend-new/src/domain/work-orders/mappers/work-order-uplift-mapper.ts

159 lines
4.4 KiB
TypeScript
Raw Normal View History

import type {
UpliftSummary,
WorkOrderUplift,
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;
}
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"),
};
}
export function mapWorkOrderUplifts(rawItems: unknown[]): WorkOrderUplift[] {
return rawItems.map(mapWorkOrderUplift);
}