import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' import { normalizeReturnSource, type ReturnSourceIdentity } from '../returnSource' import { normalizeOverseasPage, type OverseasPagePayload } from './lastMileOrders' import type { DeliveryDocumentSummary } from './deliveryDocuments' export interface DeliveryOrderQuery { page: number size: number customerId?: string documentNo?: string dispatchNo?: string waybillNo?: string warehouseId?: string status?: string vehiclePlate?: string driverName?: string deliveryMethod?: string plannedFrom?: string plannedTo?: string } export interface DeliveryOrderRow { version: number allowedActions: string[] bolNo?: string | null documentSummary?: DeliveryDocumentSummary id: string customerId: string customerName?: string | null deliveryNo: string outboundNo: string dispatchNo: string destinationWarehouseId?: string | null destinationWarehouseCode?: string | null destinationWarehouseName?: string | null destinationType?: 'FBA' | 'PRIVATE' | null deliveryAddress?: string | null contactName?: string | null contactPhone?: string | null overseasWarehouseId?: string | null overseasWarehouseName?: string | null status: string waybillNo?: string | null deliveryMethod?: string | null carrierName?: string | null pickupMethod?: string | null loadingType?: string | null vehicleType?: string | null vehicleSize?: string | null vehiclePlate?: string | null driverName?: string | null driverPhone?: string | null appointmentAccount?: string | null sellerName?: string | null palletCount: number packageCount: number signedPackages: number | null totalWeightKg?: number | null totalVolumeCbm?: number | null plannedDeliveryAt?: string | null dispatchedAt?: string | null expectedArrivalAt?: string | null signedAt?: string | null remark?: string | null createdAt: string } export interface DeliverySkuRow { inboundCode?: string | null; customerName?: string | null; destinationWarehouseCode?: string | null; receivingAddress?: string | null; shipmentNo?: string | null; fbaTrackingNo?: string | null; skuCode?: string | null; productName?: string | null; packageCount: number; productQuantity?: number | null; weightKg?: number | null; volumeCbm?: number | null } export interface DeliveryFeeRow { id: string; feeDirection: string; feeType: string; currency: string; amount: number; remark?: string | null; reviewStatus?: string | null; sourceStatus?: string | null; voidStatus?: string | null } export interface DeliveryOperationRow { id: string; operatedAt: string; operationNode: string; operatorName?: string | null; result: string } export interface DeliveryOrderDetail { order: DeliveryOrderRow; skus: DeliverySkuRow[]; fees: DeliveryFeeRow[]; operations: DeliveryOperationRow[]; feeCoverage?: import('../feeCoverageTypes').FeeCoverageEvidence | null } export interface DeliveryReturnSource extends ReturnSourceIdentity { outboundPalletItemId: string cartonMark?: string | null palletNo?: string | null skuCode?: string | null maxReturnPackages: number } export interface DeliveryReturnRelation { lastMileOrderId: string inboundOrderId?: string | null inboundCode?: string | null lastMileOrderNo?: string | null customerId: string returnSources: DeliveryReturnSource[] } export interface MarkDeliveryReturnPayload { lastMileOrderId: string reason: string returnDirection: 'OVERSEAS_WAREHOUSE' | 'CUSTOMER' | 'OTHER' returnLogisticsNo?: string items: Array idempotencyKey: string } export async function listDeliveryOrders(query: DeliveryOrderQuery) { const { customerId, ...params } = query const response = await http.get>, ApiEnvelope>>( '/platform/v1/last-leg/delivery-orders', { params: { ...params, ...(customerId ? { customerId } : {}) } }, ) return normalizeOverseasPage(unwrapApiResponse(response)) } export async function getDeliveryOrder(deliveryNo: string, customerId: string) { const response = await http.get, ApiEnvelope>( `/platform/v1/last-leg/delivery-orders/${encodeURIComponent(deliveryNo)}`, { params: { customerId, page: 1, size: 200 } }, ) const detail = unwrapApiResponse(response) // Java Long values are serialized as decimal strings, including the version. const rawVersion: unknown = detail.order.version const version = typeof rawVersion === 'string' && /^(0|[1-9]\d*)$/.test(rawVersion) ? Number(rawVersion) : rawVersion if (typeof version !== 'number' || !Number.isSafeInteger(version) || version < 0) { throw new Error('派送单缺少有效版本,请刷新后重试') } return { ...detail, order: { ...detail.order, version } } } export async function listDeliveryReturnInboundOptions(deliveryNo: string, customerId: string) { const response = await http.get, ApiEnvelope>( `/platform/v1/last-leg/delivery-orders/${encodeURIComponent(deliveryNo)}/return-inbound-options`, { params: { customerId } }, ) return unwrapApiResponse(response).map(relation => { if (typeof relation.lastMileOrderId !== 'string' || !/^[1-9]\d*$/.test(relation.lastMileOrderId)) throw new Error('退回候选缺少有效尾程主单标识,请重新加载') return { ...relation, returnSources: relation.returnSources.map(source => { const quantity: unknown = source.maxReturnPackages if ((typeof quantity !== 'number' && typeof quantity !== 'string') || !/^\d+$/.test(String(quantity)) || !Number.isSafeInteger(Number(quantity))) throw new Error('可退箱数无效,请重新加载') return { ...normalizeReturnSource(source), maxReturnPackages: Number(quantity) } }) } }) } export async function markDeliveryReturn(deliveryNo: string, customerId: string, payload: MarkDeliveryReturnPayload) { const response = await http.post, ApiEnvelope<{ id: string; exceptionNo: string; status: string }>>( `/platform/v1/last-leg/delivery-orders/${encodeURIComponent(deliveryNo)}/mark-return`, payload, { params: { customerId } }, ) return unwrapApiResponse(response) }