function id(value) { return value == null ? null : String(value) } function number(value) { return value == null || Number.isNaN(Number(value)) ? null : Number(value) } function text(value) { return value == null ? null : String(value) } function bool(value) { return value === true } function sorted(values, key) { return [...(Array.isArray(values) ? values : [])] .sort((left, right) => key(left).localeCompare(key(right))) } function planItem(item) { return { id: id(item?.id), loadingPlanId: id(item?.loadingPlanId), inboundId: id(item?.inboundId), inboundDetailId: id(item?.inboundDetailId), accountId: id(item?.accountId), orderId: id(item?.orderId), packageCount: number(item?.packageCount), loadSequence: number(item?.loadSequence), frozenAt: text(item?.frozenAt), version: number(item?.version), deleted: bool(item?.deleted), } } function detailItem(item) { return { itemId: id(item?.itemId), accountId: id(item?.accountId), inboundId: id(item?.inboundId), inboundDetailId: id(item?.inboundDetailId), packageCount: number(item?.packageCount), palletCount: number(item?.palletCount), loadSequence: number(item?.loadSequence), frozenAt: text(item?.frozenAt), } } function readiness(value) { return { preloadPushed: bool(value?.preloadPushed), containerNoReady: bool(value?.containerNoReady), preloadLinkCount: number(value?.preloadLinkCount), confirmedPreloadCount: number(value?.confirmedPreloadCount), oceanBookingId: id(value?.oceanBookingId), oceanBookingStatus: text(value?.oceanBookingStatus), pdaTaskId: id(value?.pdaTaskId), pdaTaskStatus: text(value?.pdaTaskStatus), confirmationStatus: text(value?.confirmationStatus), canConfirm: bool(value?.canConfirm), readyForPda: bool(value?.readyForPda), blockingReasons: sorted(value?.blockingReasons, (item) => text(item) || '').map(text), } } function history(value) { return { historyId: id(value?.historyId), itemId: id(value?.itemId), actionType: text(value?.actionType), fromStatus: text(value?.fromStatus), toStatus: text(value?.toStatus), beforeSnapshot: text(value?.beforeSnapshot), afterSnapshot: text(value?.afterSnapshot), operationReason: text(value?.operationReason), occurredAt: text(value?.occurredAt), } } function link(value) { return { id: id(value?.id), tenantId: id(value?.tenantId), inboundId: id(value?.inboundId), preloadPlanId: id(value?.preloadPlanId), preloadStatus: text(value?.preloadStatus), preloadVersion: number(value?.preloadVersion), loadingPlanId: id(value?.loadingPlanId), containerBookingId: id(value?.containerBookingId), containerNo: text(value?.containerNo), loadingPlanStatus: text(value?.loadingPlanStatus), loadingPlanVersion: number(value?.loadingPlanVersion), allocatedPackageCount: number(value?.allocatedPackageCount), linkedAt: text(value?.linkedAt), } } export function projectPushPreloadStability({ plan, detail, links, task }) { const summary = detail?.summary || {} return { plan: { id: id(plan?.id), bookingId: id(plan?.bookingId), status: text(plan?.status), containerNo: text(plan?.containerNo), voyageNo: text(plan?.voyageNo), version: number(plan?.version), items: sorted(plan?.items, (item) => id(item?.id) || '').map(planItem), }, detail: { summary: { planId: id(summary?.planId), containerBookingId: id(summary?.containerBookingId), containerNo: text(summary?.containerNo), cabinetNo: text(summary?.cabinetNo), status: text(summary?.status), version: number(summary?.version), skuCount: number(summary?.skuCount), totalPackageCount: number(summary?.totalPackageCount), readiness: readiness(summary?.readiness), }, items: sorted(detail?.items, (item) => id(item?.itemId) || '').map(detailItem), histories: sorted(detail?.histories, (item) => `${id(item?.historyId) || ''}:${text(item?.occurredAt) || ''}`).map(history), }, links: sorted(links, (item) => id(item?.id) || '').map(link), task: { http: number(task?.http), code: text(task?.code) }, } } function display(value) { if (value === undefined) return 'missing' return JSON.stringify(value) } export function diffPushPreloadStability(before, after) { const changes = [] function visit(left, right, path) { if (Object.is(left, right)) return if (Array.isArray(left) && Array.isArray(right)) { const length = Math.max(left.length, right.length) for (let index = 0; index < length; index += 1) visit(left[index], right[index], `${path}[${index}]`) return } if (left && right && typeof left === 'object' && typeof right === 'object') { const keys = [...new Set([...Object.keys(left), ...Object.keys(right)])].sort() for (const key of keys) visit(left[key], right[key], path ? `${path}.${key}` : key) return } changes.push(`${path}:${display(left)}->${display(right)}`) } visit(before, after, '') return changes }