701 lines
23 KiB
TypeScript
701 lines
23 KiB
TypeScript
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
|
|
|
export const unifiedOrdersApiPath = '/platform/v1/orders'
|
|
|
|
export type UnifiedOrderMainStatus =
|
|
| 'PENDING_REVIEW'
|
|
| 'WAIT_MEASURE'
|
|
| 'WAIT_PALLETIZE'
|
|
| 'WAIT_SPLIT'
|
|
| 'LOADING'
|
|
| 'LOADED'
|
|
| 'DELIVERED'
|
|
| 'COMPLETED'
|
|
| 'WAIT_WEIGHT_CONFIRM' | 'WEIGHT_CONFIRMED' | 'WAIT_CUSTOMS_DOCS' | 'EXPORT_CUSTOMS'
|
|
| 'SAILING_CLEARANCE' | 'WAIT_UNLOAD' | 'WAIT_DISPATCH' | 'OUTBOUND_DOCUMENT' | 'DELIVERING' | 'SIGNED'
|
|
|
|
export const unifiedOrderStatusOptions: Array<{ value: UnifiedOrderMainStatus; label: string }> = [
|
|
{ value: 'PENDING_REVIEW', label: '待审核' },
|
|
{ value: 'WAIT_MEASURE', label: '待测量数据' },
|
|
{ value: 'WAIT_WEIGHT_CONFIRM', label: '待客户确认' },
|
|
{ value: 'WEIGHT_CONFIRMED', label: '已确认数据' },
|
|
{ value: 'WAIT_CUSTOMS_DOCS', label: '待上传资料' },
|
|
{ value: 'WAIT_PALLETIZE', label: '一件代发打托' },
|
|
{ value: 'WAIT_SPLIT', label: '待分柜' },
|
|
{ value: 'LOADING', label: '装柜中' },
|
|
{ value: 'LOADED', label: '装柜完成' },
|
|
{ value: 'EXPORT_CUSTOMS', label: '出口报关' },
|
|
{ value: 'SAILING_CLEARANCE', label: '已开船/待清关' },
|
|
{ value: 'WAIT_UNLOAD', label: '待拆柜' },
|
|
{ value: 'WAIT_DISPATCH', label: '待排车' },
|
|
{ value: 'OUTBOUND_DOCUMENT', label: '出库单' },
|
|
{ value: 'DELIVERING', label: '派送中' },
|
|
{ value: 'SIGNED', label: '签收完成' },
|
|
]
|
|
|
|
export interface UnifiedOrderMeasurementSummary {
|
|
reviewStatus: string | null
|
|
actualGrossWeightKg: number | null
|
|
actualVolumeCbm: number | null
|
|
chargeableWeightKg: number | null
|
|
completedAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderPreloadSummary {
|
|
status: string | null
|
|
version: number | null
|
|
itemCount: number | null
|
|
updatedAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderLoadingSummary {
|
|
status: string | null
|
|
loadingVersion: number | null
|
|
pickingVersion: number | null
|
|
expectedCount: number | null
|
|
pickedCount: number | null
|
|
evidenceCount: number | null
|
|
sealNo: string | null
|
|
updatedAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderDeliverySummary {
|
|
status: string | null
|
|
completedAt: string | null
|
|
trackingNo: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderTransportSummary {
|
|
loadingStatus: string | null
|
|
containerNo: string | null
|
|
cabinetNo: string | null
|
|
vesselName: string | null
|
|
voyageNo: string | null
|
|
estimatedSailingAt: string | null
|
|
actualSailingAt: string | null
|
|
effectiveSailingAt: string | null
|
|
effectiveSailingAtEstimated: boolean | null
|
|
estimatedPortArrivalAt: string | null
|
|
actualPortArrivalAt: string | null
|
|
effectivePortArrivalAt: string | null
|
|
effectivePortArrivalAtEstimated: boolean | null
|
|
}
|
|
|
|
export interface UnifiedOrderRelationSummary {
|
|
role: 'PARENT' | 'CHILD'
|
|
rootOrderId: number | string | null
|
|
parentOrderId: number | string | null
|
|
splitSequence: number | null
|
|
childCount: number
|
|
}
|
|
|
|
export interface UnifiedOrderCoLoadGroupSummary {
|
|
status: string
|
|
memberCount: number
|
|
memberInboundCodes: string[]
|
|
}
|
|
|
|
export interface UnifiedOrderResource {
|
|
orderId: number | string
|
|
orderVersion?: number | null
|
|
tenantId: number | string
|
|
orderNo: string | null
|
|
mainStatus: UnifiedOrderMainStatus
|
|
nextAction: string | null
|
|
relation: UnifiedOrderRelationSummary | null
|
|
internalOrderStatus: string | null
|
|
customerId: number | string | null
|
|
customerName: string | null
|
|
channelCode: string | null
|
|
channelName: string | null
|
|
channelChanged?: boolean
|
|
receivingWarehouseId: number | string | null
|
|
receivingWarehouseName: string | null
|
|
destinationWarehouseId: number | string | null
|
|
destinationWarehouseName: string | null
|
|
inboundId: number | string | null
|
|
inboundVersion: number | null
|
|
inboundCode: string | null
|
|
expectedShipDate: string | null
|
|
totalPackageCount: number | null
|
|
estimatedVolumeCbm?: number | null
|
|
expectedVolumeCbm?: number | null
|
|
locationCodes: string | null
|
|
actualGrossWeightKg: number | null
|
|
actualVolumeCbm: number | null
|
|
measurement: UnifiedOrderMeasurementSummary | null
|
|
preload: UnifiedOrderPreloadSummary | null
|
|
loading: UnifiedOrderLoadingSummary | null
|
|
delivery: UnifiedOrderDeliverySummary | null
|
|
transport: UnifiedOrderTransportSummary | null
|
|
coLoadGroup: UnifiedOrderCoLoadGroupSummary | null
|
|
createdAt: string | null
|
|
updatedAt: string | null
|
|
expectedArrivalAt: string | null
|
|
feeReviewStatus: string | null
|
|
holdFlag: boolean | null
|
|
currentHoldReason: string | null
|
|
companyName?: string | null
|
|
businessType?: string | null
|
|
fulfillmentType?: string | null
|
|
pickupMethod?: string | null
|
|
requestedPickupAt: string | null
|
|
pickupAt?: string | null
|
|
pickupContactPhone?: string | null
|
|
pickupAddress?: string | null
|
|
pickupPostalCode?: string | null
|
|
pickupContactEmail?: string | null
|
|
taxMode?: string | null
|
|
fullContainer?: boolean | null
|
|
customsInspection?: boolean | null
|
|
totalPalletCount: number | null
|
|
chargeableVolumeCbm: number | null
|
|
volumetricWeightKg: number | null
|
|
totalNetWeightKg: number | null
|
|
location?: string | null
|
|
destinationType?: string | null
|
|
destinationAddress?: string | null
|
|
destinationPostalCode?: string | null
|
|
destinationContact?: string | null
|
|
destinationContactPhone?: string | null
|
|
measurementCompletedAt: string | null
|
|
inboundCompletedAt: string | null
|
|
associatedFiles?: string[] | null
|
|
markFiles?: string[] | null
|
|
pcOrderFiles?: string[] | null
|
|
expressCompany: string | null
|
|
expressTrackingNo: string | null
|
|
skuNos: string[] | null
|
|
totalQuantity: number | null
|
|
shipmentId: string | null
|
|
referenceId: string | null
|
|
remark?: string | null
|
|
customerRemark?: string | null
|
|
latestInternalNote?: string | null
|
|
internalRemark?: string | null
|
|
warehouseRemark?: string | null
|
|
customerServiceRemark?: string | null
|
|
createdBy?: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderTimelineEvent {
|
|
source: string | null
|
|
eventType: string | null
|
|
mainStatus: UnifiedOrderMainStatus | null
|
|
action: string | null
|
|
remark: string | null
|
|
operatorId: number | string | null
|
|
operatorName: string | null
|
|
occurredAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderDetailOrderSnapshot {
|
|
id: number | string | null
|
|
version: number | null
|
|
tenantId: number | string | null
|
|
orderNo: string | null
|
|
customerId: number | string | null
|
|
customerName: string | null
|
|
transportMode: string | null
|
|
tradeTerm?: string | null
|
|
destinationCountryCode: string | null
|
|
destinationWarehouseId: number | string | null
|
|
destinationWarehouseName: string | null
|
|
expectedShipDate: string | null
|
|
customerRemark?: string | null
|
|
pickupMethod?: string | null
|
|
receivingWarehouseId: number | string | null
|
|
receivingWarehouseName: string | null
|
|
receivingWarehouseAddress?: string | null
|
|
receivingTime?: string | null
|
|
channelCode?: string | null
|
|
channelName: string | null
|
|
carrierId: number | string | null
|
|
carrierName: string | null
|
|
taxMode?: string | null
|
|
containerMode?: string | null
|
|
customsInspection?: boolean | null
|
|
destinationType?: string | null
|
|
amazonWarehouseCode?: string | null
|
|
shipmentId?: string | null
|
|
referenceId?: string | null
|
|
expressCompany?: string | null
|
|
expressTrackingNo?: string | null
|
|
submittedAt?: string | null
|
|
completedAt?: string | null
|
|
createdAt: string | null
|
|
updatedAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderDetailOrderResource {
|
|
order: UnifiedOrderDetailOrderSnapshot | null
|
|
cargoes: Array<Record<string, unknown>>
|
|
parties: Array<Record<string, unknown>>
|
|
internalNotes: UnifiedOrderInternalNoteResource[]
|
|
statusHistory: UnifiedOrderStatusHistoryResource[]
|
|
}
|
|
|
|
export interface UnifiedOrderInternalNoteResource {
|
|
id: number | string
|
|
content: string
|
|
createdBy: number | string | null
|
|
createdAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderStatusHistoryResource {
|
|
id: number | string
|
|
fromStatus: string | null
|
|
toStatus: string | null
|
|
action: string | null
|
|
reason: string | null
|
|
operatorId: number | string | null
|
|
operatorName: string | null
|
|
occurredAt: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderDetailResource {
|
|
summary: UnifiedOrderResource
|
|
order: UnifiedOrderDetailOrderResource
|
|
timeline: UnifiedOrderTimelineEvent[]
|
|
}
|
|
|
|
export interface UnifiedOrderFeeDetailResource {
|
|
id: number | string
|
|
sourceFeeId?: number | string | null
|
|
sourceFeeVersion?: number | null
|
|
inboundId: number | string
|
|
inboundCode: string | null
|
|
reviewStatus: string | null
|
|
direction: string | null
|
|
customerName: string | null
|
|
invoiceTitle: string | null
|
|
businessDate: string | null
|
|
channelName: string | null
|
|
destinationName: string | null
|
|
fbaNo?: string | null
|
|
packageCount: number | null
|
|
actualGrossWeightKg: number | null
|
|
actualVolumeCbm: number | null
|
|
feeTypeNameSnapshot: string | null
|
|
currency: string | null
|
|
amount: number | null
|
|
chargeableQuantity: number | null
|
|
chargeUnit: string | null
|
|
unitPrice: number | null
|
|
inboundedAt: string | null
|
|
outboundAt?: string | null
|
|
storageDays?: number | null
|
|
billNo?: string | null
|
|
settlementStartDate?: string | null
|
|
settlementEndDate?: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderPageResource {
|
|
records: UnifiedOrderResource[]
|
|
page: number
|
|
size: number
|
|
total: number
|
|
pages: number
|
|
}
|
|
|
|
export interface UnifiedOrderQuery {
|
|
tenantId?: string
|
|
keyword?: string
|
|
orderNo?: string
|
|
mainStatus?: UnifiedOrderMainStatus
|
|
customerId?: string
|
|
receivingWarehouseId?: string
|
|
destinationWarehouseId?: string
|
|
inboundCode?: string
|
|
internalOrderStatus?: string
|
|
expectedArrivalDate?: string
|
|
feeReviewStatus?: string
|
|
channelName?: string
|
|
containerNo?: string
|
|
cabinetNo?: string
|
|
sailingDate?: string
|
|
loaded?: boolean
|
|
fullContainer?: boolean
|
|
measurementReviewStatus?: string
|
|
fbaCode?: string
|
|
createdFrom?: string
|
|
createdTo?: string
|
|
page: number
|
|
size: number
|
|
}
|
|
|
|
export type UnifiedOrderStatusCountQuery = Omit<UnifiedOrderQuery, 'page' | 'size' | 'mainStatus'>
|
|
export interface UnifiedOrderStatusCounts {
|
|
counts: Partial<Record<UnifiedOrderMainStatus | 'MEASUREMENT_REVIEW', number>>
|
|
}
|
|
|
|
export async function getPlatformUnifiedOrderStatusCounts(query: UnifiedOrderStatusCountQuery): Promise<UnifiedOrderStatusCounts> {
|
|
// Strip these fields at runtime too, so callers cannot accidentally scope the other tabs.
|
|
const params = Object.fromEntries(Object.entries(query).filter(([key, value]) =>
|
|
!['page', 'size', 'mainStatus'].includes(key) && value !== undefined && value !== ''))
|
|
const response = await http.get<ApiEnvelope<UnifiedOrderStatusCounts>, ApiEnvelope<UnifiedOrderStatusCounts>>(
|
|
`${unifiedOrdersApiPath}/status-counts`, { params },
|
|
)
|
|
const result = unwrapApiResponse(response)
|
|
return { counts: Object.fromEntries(Object.entries(result.counts || {}).filter(([, count]) =>
|
|
typeof count === 'number' && Number.isSafeInteger(count) && count >= 0)) }
|
|
}
|
|
|
|
type PagePayload = Omit<UnifiedOrderPageResource, 'page' | 'size' | 'total' | 'pages'> & {
|
|
page: number | string
|
|
size: number | string
|
|
total: number | string
|
|
pages: number | string
|
|
}
|
|
|
|
function integer(value: number | string | null | undefined, fallback: number) {
|
|
const parsed = Number(value)
|
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.trunc(parsed) : fallback
|
|
}
|
|
|
|
function nullableInteger(value: number | string | null | undefined) {
|
|
if (value === null || value === undefined || value === '') return null
|
|
return integer(value, 0)
|
|
}
|
|
|
|
function numberValue(value: number | string | null | undefined) {
|
|
if (value === null || value === undefined || value === '') return null
|
|
const parsed = Number(value)
|
|
return Number.isFinite(parsed) ? parsed : null
|
|
}
|
|
|
|
function id(value: number | string | null | undefined) {
|
|
return value === null || value === undefined || value === '' ? null : String(value)
|
|
}
|
|
|
|
export interface UnifiedOrderDeclarationCargo {
|
|
itemNo: number
|
|
cargoName: string
|
|
cargoNameEn?: string | null
|
|
skuNo?: string | null
|
|
model?: string | null
|
|
packageCount: number
|
|
totalQuantity: number
|
|
lengthCm: number
|
|
widthCm: number
|
|
heightCm: number
|
|
grossWeightKg: number
|
|
volumeCbm: number
|
|
netWeightKg?: number | null
|
|
hsCode?: string | null
|
|
customsHsCode?: string | null
|
|
unitsPerPackage?: number | null
|
|
unitDeclaredValue?: number | null
|
|
declaredValue?: number | null
|
|
currency?: string | null
|
|
material?: string | null
|
|
usage?: string | null
|
|
brand?: string | null
|
|
cargoRemark?: string | null
|
|
}
|
|
|
|
export interface UpdateUnifiedOrderDeclarationRequest {
|
|
expectedVersion: number
|
|
customerRemark?: string | null
|
|
expectedArrivalAt?: string | null
|
|
estimatedVolumeCbm?: number | null
|
|
channelCode: string
|
|
channelName: string
|
|
cargoes: UnifiedOrderDeclarationCargo[]
|
|
}
|
|
|
|
export interface UnifiedOrderDeclarationChange {
|
|
itemNo: number | null
|
|
field: string
|
|
beforeValue: string | null
|
|
afterValue: string | null
|
|
}
|
|
|
|
export interface UpdateUnifiedOrderDeclarationResult {
|
|
orderNo: string | null
|
|
inboundCode: string | null
|
|
previousVersion: number
|
|
version: number
|
|
channelChangedBefore: boolean
|
|
channelChanged: boolean
|
|
changes: UnifiedOrderDeclarationChange[]
|
|
}
|
|
|
|
export interface UpdateUnifiedOrderPlanningRequest {
|
|
expectedVersion: number
|
|
expectedArrivalAt?: string | null
|
|
estimatedVolumeCbm?: number | null
|
|
}
|
|
|
|
function optionalText(value: string | null | undefined) {
|
|
const normalized = value?.trim()
|
|
return normalized || null
|
|
}
|
|
|
|
function queryParams(query: UnifiedOrderQuery) {
|
|
return Object.fromEntries(Object.entries(query).filter(([, value]) => value !== undefined && value !== ''))
|
|
}
|
|
|
|
function normalizeRow(raw: UnifiedOrderResource): UnifiedOrderResource {
|
|
return {
|
|
...raw,
|
|
orderId: String(raw.orderId),
|
|
orderVersion: nullableInteger(raw.orderVersion),
|
|
tenantId: String(raw.tenantId),
|
|
customerId: id(raw.customerId),
|
|
channelCode: optionalText(raw.channelCode),
|
|
receivingWarehouseId: id(raw.receivingWarehouseId),
|
|
destinationWarehouseId: id(raw.destinationWarehouseId),
|
|
inboundId: id(raw.inboundId),
|
|
holdFlag: raw.holdFlag === null || raw.holdFlag === undefined ? null : Boolean(raw.holdFlag),
|
|
currentHoldReason: optionalText(raw.currentHoldReason),
|
|
inboundVersion: nullableInteger(raw.inboundVersion),
|
|
relation: raw.relation ? {
|
|
...raw.relation,
|
|
rootOrderId: id(raw.relation.rootOrderId),
|
|
parentOrderId: id(raw.relation.parentOrderId),
|
|
splitSequence: nullableInteger(raw.relation.splitSequence),
|
|
childCount: integer(raw.relation.childCount, 0),
|
|
} : null,
|
|
totalPackageCount: nullableInteger(raw.totalPackageCount),
|
|
estimatedVolumeCbm: numberValue(raw.estimatedVolumeCbm),
|
|
expectedVolumeCbm: numberValue(raw.expectedVolumeCbm),
|
|
channelChanged: Boolean(raw.channelChanged),
|
|
actualGrossWeightKg: numberValue(raw.actualGrossWeightKg),
|
|
actualVolumeCbm: numberValue(raw.actualVolumeCbm),
|
|
totalPalletCount: nullableInteger(raw.totalPalletCount),
|
|
chargeableVolumeCbm: numberValue(raw.chargeableVolumeCbm),
|
|
volumetricWeightKg: numberValue(raw.volumetricWeightKg),
|
|
totalNetWeightKg: numberValue(raw.totalNetWeightKg),
|
|
totalQuantity: nullableInteger(raw.totalQuantity),
|
|
skuNos: raw.skuNos?.filter((value) => value.trim()) ?? null,
|
|
locationCodes: raw.locationCodes ?? raw.location ?? null,
|
|
measurement: raw.measurement ? {
|
|
...raw.measurement,
|
|
actualGrossWeightKg: numberValue(raw.measurement.actualGrossWeightKg),
|
|
actualVolumeCbm: numberValue(raw.measurement.actualVolumeCbm),
|
|
chargeableWeightKg: numberValue(raw.measurement.chargeableWeightKg),
|
|
} : null,
|
|
preload: raw.preload ? { ...raw.preload, version: nullableInteger(raw.preload.version), itemCount: nullableInteger(raw.preload.itemCount) } : null,
|
|
loading: raw.loading ? {
|
|
...raw.loading,
|
|
loadingVersion: nullableInteger(raw.loading.loadingVersion),
|
|
pickingVersion: nullableInteger(raw.loading.pickingVersion),
|
|
expectedCount: nullableInteger(raw.loading.expectedCount),
|
|
pickedCount: nullableInteger(raw.loading.pickedCount),
|
|
evidenceCount: nullableInteger(raw.loading.evidenceCount),
|
|
} : null,
|
|
transport: raw.transport ? { ...raw.transport } : null,
|
|
coLoadGroup: raw.coLoadGroup ? {
|
|
status: String(raw.coLoadGroup.status || ''),
|
|
memberCount: integer(raw.coLoadGroup.memberCount, 0),
|
|
memberInboundCodes: (raw.coLoadGroup.memberInboundCodes || [])
|
|
.map((value) => typeof value === 'string' ? value.trim() : '')
|
|
.filter(Boolean),
|
|
} : null,
|
|
}
|
|
}
|
|
|
|
export async function listPlatformUnifiedOrders(query: UnifiedOrderQuery) {
|
|
const response = await http.get<ApiEnvelope<PagePayload>, ApiEnvelope<PagePayload>>(unifiedOrdersApiPath, {
|
|
params: queryParams(query),
|
|
})
|
|
const result = unwrapApiResponse(response)
|
|
return {
|
|
...result,
|
|
records: (result.records || []).map(normalizeRow),
|
|
page: integer(result.page, query.page),
|
|
size: integer(result.size, query.size),
|
|
total: integer(result.total, 0),
|
|
pages: integer(result.pages, 0),
|
|
} satisfies UnifiedOrderPageResource
|
|
}
|
|
|
|
export async function getPlatformUnifiedOrder(tenantId: string, orderId: string) {
|
|
const response = await http.get<ApiEnvelope<UnifiedOrderDetailResource>, ApiEnvelope<UnifiedOrderDetailResource>>(
|
|
`${unifiedOrdersApiPath}/${orderId}`,
|
|
{ params: { tenantId } },
|
|
)
|
|
const result = unwrapApiResponse(response)
|
|
return {
|
|
...result,
|
|
summary: normalizeRow(result.summary),
|
|
order: {
|
|
...result.order,
|
|
order: result.order.order ? { ...result.order.order, version: nullableInteger(result.order.order.version) } : null,
|
|
},
|
|
}
|
|
}
|
|
|
|
export function updatePlatformUnifiedOrderDeclaration(
|
|
tenantId: string,
|
|
orderId: string,
|
|
request: UpdateUnifiedOrderDeclarationRequest,
|
|
) {
|
|
return http.put<ApiEnvelope<UpdateUnifiedOrderDeclarationResult>, ApiEnvelope<UpdateUnifiedOrderDeclarationResult>>(
|
|
`${unifiedOrdersApiPath}/${orderId}/declaration`,
|
|
request,
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export function updatePlatformUnifiedOrderPlanning(
|
|
tenantId: string,
|
|
orderId: string,
|
|
request: UpdateUnifiedOrderPlanningRequest,
|
|
) {
|
|
return http.put<ApiEnvelope<UpdateUnifiedOrderDeclarationResult>, ApiEnvelope<UpdateUnifiedOrderDeclarationResult>>(
|
|
`${unifiedOrdersApiPath}/${orderId}/planning`,
|
|
request,
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export function downloadPlatformProductImage(tenantId: string, fileId: string) {
|
|
return http.get<Blob, Blob>(
|
|
`/platform/v1/files/product-images/${encodeURIComponent(tenantId)}/${encodeURIComponent(fileId)}`,
|
|
{ responseType: 'blob' },
|
|
)
|
|
}
|
|
|
|
export function approvePlatformUnifiedOrder(tenantId: string, orderId: string) {
|
|
return http.post<ApiEnvelope<void>, ApiEnvelope<void>>(
|
|
`/platform/v1/orders/first-leg/${orderId}/approve`,
|
|
undefined,
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export interface UnifiedOrderBatchApprovalResult {
|
|
total: number
|
|
successCount: number
|
|
failureCount: number
|
|
successOrderIds: Array<number | string>
|
|
failedOrders: Array<{ orderId: number | string; code: string; message: string }>
|
|
}
|
|
|
|
export interface UnifiedOrderBatchReviewItem {
|
|
orderId: string
|
|
orderVersion: number
|
|
}
|
|
|
|
export interface UnifiedOrderBatchApprovalPreviewItem extends UnifiedOrderBatchReviewItem {
|
|
inboundCode: string | null
|
|
customerId: string | null
|
|
customerName: string | null
|
|
chineseGoodsNames: string[]
|
|
channelCode: string | null
|
|
channelName: string | null
|
|
destinationWarehouseCode: string | null
|
|
destinationWarehouseName: string | null
|
|
canApprove: boolean
|
|
blockReason: string | null
|
|
}
|
|
|
|
export interface UnifiedOrderBatchApprovalPreview {
|
|
total: number
|
|
approvableCount: number
|
|
items: UnifiedOrderBatchApprovalPreviewItem[]
|
|
}
|
|
|
|
function normalizeBatchApprovalPreview(result: UnifiedOrderBatchApprovalPreview): UnifiedOrderBatchApprovalPreview {
|
|
return {
|
|
...result,
|
|
total: integer(result.total, 0),
|
|
approvableCount: integer(result.approvableCount, 0),
|
|
items: (result.items || []).map((item) => ({
|
|
...item,
|
|
orderId: String(item.orderId),
|
|
orderVersion: integer(item.orderVersion, 0),
|
|
customerId: id(item.customerId),
|
|
chineseGoodsNames: (item.chineseGoodsNames || []).map((name) => name.trim()).filter(Boolean),
|
|
canApprove: Boolean(item.canApprove),
|
|
})),
|
|
}
|
|
}
|
|
|
|
export async function getPlatformUnifiedOrderBatchApprovalPreview(tenantId: string, items: UnifiedOrderBatchReviewItem[]) {
|
|
const response = await http.post<ApiEnvelope<UnifiedOrderBatchApprovalPreview>, ApiEnvelope<UnifiedOrderBatchApprovalPreview>>(
|
|
'/platform/v1/orders/first-leg/batch-review-preview',
|
|
{ items },
|
|
{ params: { tenantId } },
|
|
)
|
|
return normalizeBatchApprovalPreview(unwrapApiResponse(response))
|
|
}
|
|
|
|
export function batchApprovePlatformUnifiedOrders(tenantId: string, items: UnifiedOrderBatchReviewItem[]) {
|
|
return http.post<ApiEnvelope<UnifiedOrderBatchApprovalResult>, ApiEnvelope<UnifiedOrderBatchApprovalResult>>(
|
|
'/platform/v1/orders/first-leg/batch-approve',
|
|
{ items },
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export interface UnifiedOrderRemarksUpdateRequest {
|
|
expectedVersion: number
|
|
internalRemark: string | null
|
|
warehouseRemark: string | null
|
|
customerServiceRemark: string | null
|
|
}
|
|
|
|
export interface LegacyOrderImportItem {
|
|
excelRow: number
|
|
success: boolean
|
|
legacyInboundCode: string | null
|
|
orderId: number | string | null
|
|
orderNo: string | null
|
|
errorMessage: string | null
|
|
}
|
|
|
|
export interface LegacyOrderImportResult {
|
|
total: number
|
|
succeeded: number
|
|
failed: number
|
|
items: LegacyOrderImportItem[]
|
|
}
|
|
|
|
export function importPlatformLegacyOrders(file: File, idempotencyKey: string) {
|
|
const form = new FormData()
|
|
form.append('file', file)
|
|
return http.post<ApiEnvelope<LegacyOrderImportResult>, ApiEnvelope<LegacyOrderImportResult>>(
|
|
'/platform/v1/orders/first-leg/legacy-import',
|
|
form,
|
|
{ headers: { 'Content-Type': 'multipart/form-data', 'Idempotency-Key': idempotencyKey } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export function createLegacyOrderImportIdempotencyKey() {
|
|
const uuid = globalThis.crypto?.randomUUID?.()
|
|
return uuid ? `legacy-order-import-${uuid}` : `legacy-order-import-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
}
|
|
|
|
export interface UnifiedOrderRemarksUpdateResponse {
|
|
version: number
|
|
customerRemark: string | null
|
|
internalRemark: string | null
|
|
warehouseRemark: string | null
|
|
customerServiceRemark: string | null
|
|
}
|
|
|
|
export function updatePlatformUnifiedOrderRemarks(tenantId: string, orderId: string, request: UnifiedOrderRemarksUpdateRequest) {
|
|
return http.put<ApiEnvelope<UnifiedOrderRemarksUpdateResponse>, ApiEnvelope<UnifiedOrderRemarksUpdateResponse>>(
|
|
`${unifiedOrdersApiPath}/${orderId}/remarks`,
|
|
request,
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export async function listPlatformUnifiedOrderFeeDetails(accountId: string, inboundId: string) {
|
|
const response = await http.get<ApiEnvelope<UnifiedOrderFeeDetailResource[]>, ApiEnvelope<UnifiedOrderFeeDetailResource[]>>(
|
|
`/platform/v1/inbounds/${encodeURIComponent(inboundId)}/fee-details`,
|
|
{ params: { accountId } },
|
|
)
|
|
return unwrapApiResponse(response)
|
|
}
|
|
|
|
export function unifiedOrderStatusLabel(status: UnifiedOrderMainStatus) {
|
|
if (status === 'DELIVERED') return '签收完成'
|
|
if (status === 'COMPLETED') return '已完成'
|
|
return unifiedOrderStatusOptions.find((item) => item.value === status)?.label || '未知状态'
|
|
}
|