import { MMReceiveLaborTicket } from "../../services/mm-api-service/types/receive-types.js"; /** * Normalization utilities for labor ticket signatures. * Ensures consistent signatures regardless of API response format variations. */ /** * Normalize timestamps to consistent ISO format (handles Z vs +00:00 variations) */ export function normalizeTimestamp(ts: string | null | undefined): string | null { if (!ts) return null; try { return new Date(ts).toISOString(); } catch { return ts; // If parsing fails, use as-is } } /** * Normalize text values — null/undefined/empty-string all become null. * MM can flip between null and "" across API responses, so we treat them as equivalent. */ export function normalizeString(s: unknown): string | null { if (s === null || s === undefined) return null; const str = String(s); return str.length === 0 ? null : str; } /** * Normalize numbers — coerce strings to numbers, reject non-finite values. */ export function normalizeNumber(n: unknown): number | null { if (n === null || n === undefined || n === "") return null; const num = typeof n === "number" ? n : Number(n); return Number.isFinite(num) ? num : null; } /** * Normalize ID-like values (laborTicketRef, workOrderId, etc.) — always coerce to string. * Ensures "42" and 42 produce the same signature. */ export function normalizeLaborTicketRef(ref: unknown): string | null { if (ref === null || ref === undefined) return null; const s = String(ref); return s.length === 0 ? null : s; } /** * Stable SQLite ledger key for labor tickets written from ERP → MM when `laborTicketRef` * is not yet known. Matches {@link tryLaborTicketLedgerErpImportKey} on the to-ERP path * so the first export cycle can dedupe against the post-import ledger row. */ export function tryLaborTicketLedgerErpImportKey( workOrderId: unknown, laborTicketId: unknown ): string | null { const wo = normalizeLaborTicketRef(workOrderId)?.trim() ?? ""; const id = normalizeLaborTicketRef(laborTicketId)?.trim() ?? ""; if (!wo || !id) return null; return `erp-import:${wo}:${id}`; } /** * Normalize reasons array for consistent signatures */ export function normalizeReasons(reasons: any[] | null | undefined): string[] { return (reasons ?? []) .map((r) => { const reason: any = (r as any)?.reason ?? {}; return ( reason.reasonId ?? reason.code ?? reason.reasonRef ?? reason.rejectReasonRef ?? "" ); }) .filter((v) => v !== "" && v !== null && v !== undefined) .map(String) .sort(); }