import type { ItemLotTraceLocationBlock, ItemLotTraceResponse, } from "@/app/api/itemTracing"; import { blockWarehouseCode } from "./buildLocationBlockGraphNodes"; export type ScopedRow = T & { scopeWarehouseCode: string; inventoryLotId: number; }; export const primaryWarehouseLabel = (data: ItemLotTraceResponse): string => data.warehouseLines .map((w) => w.warehouseCode) .filter(Boolean) .join(" / ") || "—"; const sortByTimestampDesc = ( rows: T[], ): T[] => [...rows].sort((a, b) => (b.timestamp ?? "").localeCompare(a.timestamp ?? ""), ); const sortByReceiptDateDesc = ( rows: T[], ): T[] => [...rows].sort((a, b) => (b.receiptDate ?? "").localeCompare(a.receiptDate ?? ""), ); export const mergeScopedOrigins = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.origins.map((o) => ({ ...o, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.origins.map((o) => ({ ...o, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, })); }); return sortByReceiptDateDesc([...primary, ...fromBlocks]); }; export const mergeScopedQcResults = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.qcResults.map((q, i) => ({ ...q, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-${q.stockInLineId}-${i}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.qcResults.map((q, i) => ({ ...q, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-${q.stockInLineId}-${i}`, })); }); return [...primary, ...fromBlocks].sort((a, b) => (b.created ?? "").localeCompare(a.created ?? ""), ); }; export const mergeScopedOutboundUsage = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.outboundUsage.map((u) => ({ ...u, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.outboundUsage.map((u) => ({ ...u, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedStockTakeEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.stockTakeEvents.map((e, i) => ({ ...e, scopeWarehouseCode: e.warehouseCode?.trim() || primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-${e.stockTakeCode}-${i}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.stockTakeEvents.map((e, i) => ({ ...e, scopeWarehouseCode: e.warehouseCode?.trim() || wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-${e.stockTakeCode}-${i}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedAdjustments = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.adjustments.map((a, i) => ({ ...a, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-${a.refCode}-${i}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.adjustments.map((a, i) => ({ ...a, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-${a.refCode}-${i}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedTransfers = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.transfers.map((tr, i) => ({ ...tr, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-${tr.transferCode}-${i}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.transfers.map((tr, i) => ({ ...tr, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-${tr.transferCode}-${i}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedMovements = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.movements.map((m, i) => ({ ...m, scopeWarehouseCode: m.warehouseCode?.trim() || primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-mov-${i}-${m.refCode}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.movements.map((m, i) => ({ ...m, scopeWarehouseCode: m.warehouseCode?.trim() || wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-mov-${i}-${m.refCode}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedPutawayEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.putawayEvents.map((p, i) => ({ ...p, scopeWarehouseCode: p.warehouseCode?.trim() || primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-putaway-${i}-${p.refCode}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.putawayEvents.map((p, i) => ({ ...p, scopeWarehouseCode: p.warehouseCode?.trim() || wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-putaway-${i}-${p.refCode}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedPurchaseEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = (data.purchaseEvents ?? []).map((p, i) => ({ ...p, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-po-${i}-${p.purchaseOrderLineId}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return (block.purchaseEvents ?? []).map((p, i) => ({ ...p, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-po-${i}-${p.purchaseOrderLineId}`, })); }); return [...primary, ...fromBlocks].sort((a, b) => (b.orderDate ?? "").localeCompare(a.orderDate ?? ""), ); }; export const mergeScopedDoDeliveries = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.doDeliveries.map((d, i) => ({ ...d, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-do-${i}-${d.stockOutLineId}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.doDeliveries.map((d, i) => ({ ...d, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-do-${i}-${d.stockOutLineId}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedFailEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.failEvents.map((f, i) => ({ ...f, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-fail-${i}-${f.failId}`, timestamp: f.recordDate, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.failEvents.map((f, i) => ({ ...f, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-fail-${i}-${f.failId}`, timestamp: f.recordDate, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedReturnEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.returnEvents.map((r, i) => ({ ...r, scopeWarehouseCode: r.warehouseCode?.trim() || primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-return-${i}-${r.stockOutLineId}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.returnEvents.map((r, i) => ({ ...r, scopeWarehouseCode: r.warehouseCode?.trim() || wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-return-${i}-${r.stockOutLineId}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedOpenMovements = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = data.openMovements.map((o, i) => ({ ...o, scopeWarehouseCode: o.warehouseCode?.trim() || primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-open-${i}-${o.stockInLineId}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return block.openMovements.map((o, i) => ({ ...o, scopeWarehouseCode: o.warehouseCode?.trim() || wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-open-${i}-${o.stockInLineId}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const mergeScopedReplenishmentEvents = (data: ItemLotTraceResponse) => { const primaryWh = primaryWarehouseLabel(data); const primary = (data.replenishmentEvents ?? []).map((r, i) => ({ ...r, scopeWarehouseCode: primaryWh, inventoryLotId: data.lot.inventoryLotId, rowKey: `primary-replenish-${i}-${r.replenishmentId}`, })); const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => { const wh = blockWarehouseCode(block); return (block.replenishmentEvents ?? []).map((r, i) => ({ ...r, scopeWarehouseCode: wh, inventoryLotId: block.inventoryLotId, rowKey: `loc-${block.inventoryLotId}-replenish-${i}-${r.replenishmentId}`, })); }); return sortByTimestampDesc([...primary, ...fromBlocks]); }; export const hasMultipleLocations = (data: ItemLotTraceResponse): boolean => (data.locationBlocks?.length ?? 0) > 0 || (data.alternateLocations?.length ?? 0) > 0;