124 lines
5.2 KiB
TypeScript
124 lines
5.2 KiB
TypeScript
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
|
|
|
export interface UnifiedOrderFulfillmentFragment {
|
|
orderId: string
|
|
orderNo: string | null
|
|
splitSequence: number | null
|
|
splitRole: string | null
|
|
plannedPackageCount: number | null
|
|
pickedPackageCount: number | null
|
|
unpickedPackageCount: number | null
|
|
loadingPlanId: string | null
|
|
containerBookingId: string | null
|
|
sourceOrderId: string | null
|
|
status: string | null
|
|
historical: boolean
|
|
}
|
|
|
|
export interface UnifiedOrderFulfillmentTree {
|
|
rootOrderId: string
|
|
rootOrderNo: string | null
|
|
rootVersion: number | null
|
|
originalPackageCount: number | null
|
|
cumulativeLoadedPackageCount: number | null
|
|
currentRemainderPackageCount: number | null
|
|
fragments: UnifiedOrderFulfillmentFragment[]
|
|
historicalTwoChildModel: boolean
|
|
}
|
|
|
|
type UnknownRecord = Record<string, unknown>
|
|
|
|
function record(value: unknown): UnknownRecord {
|
|
return value && typeof value === 'object' ? value as UnknownRecord : {}
|
|
}
|
|
|
|
function stringValue(value: unknown) {
|
|
return value === null || value === undefined || value === '' ? null : String(value)
|
|
}
|
|
|
|
function numberValue(value: unknown) {
|
|
if (value === null || value === undefined || value === '') return null
|
|
const parsed = Number(value)
|
|
return Number.isFinite(parsed) ? Math.trunc(parsed) : null
|
|
}
|
|
|
|
function firstNumber(source: UnknownRecord, keys: string[]) {
|
|
for (const key of keys) {
|
|
const value = numberValue(source[key])
|
|
if (value !== null) return value
|
|
}
|
|
return null
|
|
}
|
|
|
|
function firstString(source: UnknownRecord, keys: string[]) {
|
|
for (const key of keys) {
|
|
const value = stringValue(source[key])
|
|
if (value !== null) return value
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function normalizeOrderFulfillmentTree(payload: unknown, fallbackOrderId: string): UnifiedOrderFulfillmentTree {
|
|
const raw = record(payload)
|
|
const rootOrderId = firstString(raw, ['rootOrderId', 'parentOrderId', 'orderId']) || fallbackOrderId
|
|
const rootOrderNo = firstString(raw, ['rootOrderNo', 'parentOrderNo', 'orderNo'])
|
|
const children = Array.isArray(raw.fragments) ? raw.fragments : Array.isArray(raw.children) ? raw.children : []
|
|
const legacy = raw.historicalTwoChildModel === true
|
|
|| children.some((item) => {
|
|
const child = record(item)
|
|
const role = firstString(child, ['splitRole', 'role'])
|
|
const childId = firstString(child, ['orderId', 'childOrderId'])
|
|
const sourceId = firstString(child, ['sourceOrderId', 'parentOrderId'])
|
|
return role === 'LOADED' && childId !== null && sourceId !== null && childId !== sourceId
|
|
})
|
|
const original = firstNumber(raw, ['originalPackageCount', 'sourcePackageCount'])
|
|
?? (() => {
|
|
const allocated = firstNumber(raw, ['cumulativeLoadedPackageCount', 'allocatedPackageCount', 'loadedPackageCount'])
|
|
const remainder = firstNumber(raw, ['currentRemainderPackageCount', 'remainingPackageCount'])
|
|
return allocated === null || remainder === null ? null : allocated + remainder
|
|
})()
|
|
const cumulativeLoaded = firstNumber(raw, ['cumulativeLoadedPackageCount', 'allocatedPackageCount', 'loadedPackageCount'])
|
|
const currentRemainder = firstNumber(raw, ['currentRemainderPackageCount', 'remainingPackageCount'])
|
|
const fragments = children.map((item): UnifiedOrderFulfillmentFragment => {
|
|
const child = record(item)
|
|
const role = firstString(child, ['splitRole', 'fragmentRole', 'role'])
|
|
const planned = firstNumber(child, ['plannedPackageCount', 'sourcePackageCount', 'packageCount'])
|
|
const picked = firstNumber(child, ['pickedPackageCount', 'loadedPackageCount'])
|
|
?? (role === 'LOADED' ? firstNumber(child, ['packageCount']) : 0)
|
|
const unpicked = firstNumber(child, ['unpickedPackageCount', 'remainingPackageCount'])
|
|
?? (planned === null || picked === null ? null : Math.max(0, planned - picked))
|
|
return {
|
|
orderId: firstString(child, ['orderId', 'childOrderId', 'sourceOrderId']) || '',
|
|
orderNo: firstString(child, ['orderNo', 'childOrderNo', 'sourceOrderNo']),
|
|
splitSequence: firstNumber(child, ['splitSequence', 'sequence']),
|
|
splitRole: role,
|
|
plannedPackageCount: planned,
|
|
pickedPackageCount: picked,
|
|
unpickedPackageCount: unpicked,
|
|
loadingPlanId: firstString(child, ['loadingPlanId']),
|
|
containerBookingId: firstString(child, ['containerBookingId']),
|
|
sourceOrderId: firstString(child, ['sourceOrderId', 'parentOrderId']),
|
|
status: firstString(child, ['status', 'orderStatus', 'processStatus']),
|
|
historical: legacy,
|
|
}
|
|
}).filter((item) => item.orderId)
|
|
return {
|
|
rootOrderId,
|
|
rootOrderNo,
|
|
rootVersion: firstNumber(raw, ['rootVersion', 'parentVersion']),
|
|
originalPackageCount: original,
|
|
cumulativeLoadedPackageCount: cumulativeLoaded,
|
|
currentRemainderPackageCount: currentRemainder,
|
|
fragments,
|
|
historicalTwoChildModel: legacy,
|
|
}
|
|
}
|
|
|
|
export async function getPlatformOrderFulfillmentTree(tenantId: string, orderId: string) {
|
|
const response = await http.get<ApiEnvelope<unknown>, ApiEnvelope<unknown>>(
|
|
`/platform/v1/orders/${encodeURIComponent(orderId)}/fulfillment-tree`,
|
|
{ params: { tenantId } },
|
|
)
|
|
return normalizeOrderFulfillmentTree(unwrapApiResponse(response), orderId)
|
|
}
|