230 lines
9.3 KiB
TypeScript
230 lines
9.3 KiB
TypeScript
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
|
|
|
import { normalizeOverseasPage, type OverseasPagePayload } from './lastMileOrders'
|
|
import { normalizeWarehouseTransferQuantity } from './warehouseTransferQuantities'
|
|
import type { ReceivingOverseasWarehouseDto } from './pallets'
|
|
|
|
export interface WarehouseTransferQuery {
|
|
page: number
|
|
size: number
|
|
transferNo?: string
|
|
operatingWarehouseId?: string
|
|
fbaWarehouseCode?: string
|
|
status?: string
|
|
needRelabel?: boolean
|
|
}
|
|
|
|
export interface WarehouseTransferSummaryDto {
|
|
id: string
|
|
transferNo: string
|
|
inboundCode?: string | null
|
|
lastlegOrderId?: string | null
|
|
lastlegOrderNo?: string | null
|
|
operatingWarehouseId?: string | null
|
|
fbaWarehouseCode?: string | null
|
|
packageCount: number
|
|
deliveryMethod?: string | null
|
|
needRelabel: boolean
|
|
relabelNo?: string | null
|
|
status: string
|
|
estimatedArrivalAt?: string | null
|
|
createdAt?: string | null
|
|
}
|
|
|
|
export interface WarehouseTransferItemDto {
|
|
id: string
|
|
skuCode: string
|
|
productNameZh: string
|
|
quantity?: number | string | null
|
|
packageCount: number
|
|
shippingMark?: string | null
|
|
}
|
|
|
|
export interface WarehouseTransferCartonDto {
|
|
items?: Array<{ transferItemId: string; skuCode: string; quantity: number | string }>
|
|
transferItemId?: string | null
|
|
transferPalletId?: string | null
|
|
length?: number | string | null
|
|
width?: number | string | null
|
|
height?: number | string | null
|
|
weight?: number | string | null
|
|
quantity?: number | string | null
|
|
countedAt?: string | null
|
|
discrepancyReason?: string | null
|
|
cartonMark?: string | null
|
|
customerCartonMark?: string | null
|
|
cartonIndex: number
|
|
totalCartons: number
|
|
status: string
|
|
}
|
|
|
|
export interface WarehouseTransferCartonLabelDto {
|
|
transferNo: string
|
|
cartons: WarehouseTransferCartonDto[]
|
|
printableHtml: string
|
|
}
|
|
|
|
export async function getWarehouseTransferCartonLabel(customerId: string, transferNo: string) {
|
|
const response = await http.get<ApiEnvelope<WarehouseTransferCartonLabelDto>, ApiEnvelope<WarehouseTransferCartonLabelDto>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/carton-label`, { params: { customerId } },
|
|
)
|
|
return unwrapApiResponse(response)
|
|
}
|
|
|
|
export interface WarehouseTransferRelabelBindingDto {
|
|
operationType: string
|
|
customerCartonMark: string
|
|
originalSku: string
|
|
newSku?: string | null
|
|
quantity: number
|
|
fbaCartonMark?: string | null
|
|
destinationWarehouseCode?: string | null
|
|
remark?: string | null
|
|
}
|
|
|
|
export interface WarehouseTransferPalletDto {
|
|
id: string
|
|
sequenceNo: number
|
|
warehouseLocationCode?: string | null
|
|
palletNo?: string | null
|
|
cartonCount: number
|
|
grossWeightKg: number
|
|
volumeCbm: number
|
|
status: string
|
|
}
|
|
|
|
export interface WarehouseTransferDetailDto extends WarehouseTransferSummaryDto {
|
|
inboundOrderId?: string | null
|
|
orderType?: string | null
|
|
orderStatus?: string | null
|
|
relabelApplicationId?: string | null
|
|
relabelStatus?: string | null
|
|
deliveryAddress?: string | null
|
|
estimatedShipAt?: string | null
|
|
fbaShipmentNo?: string | null
|
|
trackingNo?: string | null
|
|
fbaBoxNos?: string | null
|
|
remark?: string | null
|
|
items: WarehouseTransferItemDto[]
|
|
cartons: WarehouseTransferCartonDto[]
|
|
pallets: WarehouseTransferPalletDto[]
|
|
relabelBindings: WarehouseTransferRelabelBindingDto[]
|
|
customerConfirmedAt?: string | null
|
|
actualShipAt?: string | null
|
|
destinationWarehouseId?: string | null
|
|
destinationWarehouseCode?: string | null
|
|
destinationWarehouseName?: string | null
|
|
sourceOrders?: Array<{ lastlegOrderId: string; lastlegOrderNo?: string | null; inboundOrderId: string; inboundCode?: string | null }>
|
|
allocations?: Array<{ inventoryPositionId: string; inboundOrderId: string; inboundCode?: string | null; palletId: string; palletNo?: string | null; packageCount: number; status: string; destinationInventoryPositionId?: string | null; skuCode?: string | null }>
|
|
receiptCommands?: WarehouseTransferReceiptCommandDto[]
|
|
}
|
|
|
|
export interface WarehouseTransferReceiptCommandDto {
|
|
sourceInventoryPositionId: string
|
|
status: 'PREPARED' | 'RESERVED' | 'COMPLETED'
|
|
requestHash: string
|
|
request: ReceiveWarehouseTransferPayload
|
|
target: { warehouseId: string; warehouseCode: string; warehouseName: string; palletId: string; palletNo: string; locationId: string; locationCode: string; fbaId?: string | null; fbaCode: string; fbaName?: string | null }
|
|
}
|
|
|
|
export interface AllocateWarehouseTransferPayload {
|
|
idempotencyKey: string
|
|
allocations: Array<{ inventoryPositionId: string; palletId: string; packageCount: number }>
|
|
}
|
|
|
|
export interface OutboundWarehouseTransferPayload { idempotencyKey: string; remark?: string }
|
|
export interface ReceiveWarehouseTransferPayload {
|
|
sourceInventoryPositionId: string
|
|
destinationOverseasWarehouseId: string
|
|
destinationOverseasWarehouseCode: string
|
|
destinationOverseasWarehouseName: string
|
|
destinationWarehouseId?: string
|
|
destinationWarehouseCode: string
|
|
destinationWarehouseName?: string
|
|
destinationPalletId: string
|
|
destinationPalletNo: string
|
|
warehouseLocationId: string
|
|
warehouseLocationCode: string
|
|
batchNo: string
|
|
idempotencyKey: string
|
|
remark?: string
|
|
}
|
|
|
|
export async function outboundWarehouseTransfer(customerId: string, transferNo: string, payload: OutboundWarehouseTransferPayload) {
|
|
const response = await http.post<ApiEnvelope<WarehouseTransferDetailWire>, ApiEnvelope<WarehouseTransferDetailWire>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/outbound`, payload, { params: { customerId } },
|
|
)
|
|
return normalizeTransferDetail(unwrapApiResponse(response))
|
|
}
|
|
export async function receiveWarehouseTransfer(customerId: string, transferNo: string, payload: ReceiveWarehouseTransferPayload) {
|
|
const response = await http.post<ApiEnvelope<WarehouseTransferDetailWire>, ApiEnvelope<WarehouseTransferDetailWire>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/receipts`, payload, { params: { customerId } },
|
|
)
|
|
return normalizeTransferDetail(unwrapApiResponse(response))
|
|
}
|
|
|
|
export async function listTransferReceivingWarehouses() {
|
|
const records: ReceivingOverseasWarehouseDto[] = []
|
|
let total: number | undefined
|
|
for (let page = 1; page <= 100; page++) {
|
|
const response = await http.get<ApiEnvelope<OverseasPagePayload<ReceivingOverseasWarehouseDto>>, ApiEnvelope<OverseasPagePayload<ReceivingOverseasWarehouseDto>>>(
|
|
'/platform/v1/warehouse-admin/overseas-receiving-options', { params: { page, size: 200 } },
|
|
)
|
|
const value = normalizeOverseasPage(unwrapApiResponse(response))
|
|
if (total !== undefined && total !== value.total) throw new Error('收货仓列表已变化,请重新查询')
|
|
total = value.total
|
|
records.push(...value.records.map(w => ({ ...w, id: String(w.id), customerId: String(w.customerId) })))
|
|
if (records.length === total) {
|
|
if (new Set(records.map(w => w.id)).size !== records.length || records.some(w => w.customerId !== '0' || w.warehouseType !== 'OVERSEAS' || w.status !== 'ACTIVE')) throw new Error('收货仓返回范围不符合要求')
|
|
return { records }
|
|
}
|
|
if (!value.records.length || records.length > total) throw new Error('收货仓分页不完整,请重新查询')
|
|
}
|
|
throw new Error('收货仓分页超出查询限制')
|
|
}
|
|
|
|
type WarehouseTransferDetailWire = Omit<WarehouseTransferDetailDto, 'packageCount'> & { packageCount: number | string }
|
|
function normalizeTransferDetail(value: WarehouseTransferDetailWire): WarehouseTransferDetailDto {
|
|
return { ...value, packageCount: normalizeWarehouseTransferQuantity(value.packageCount, '本票转运箱数') }
|
|
}
|
|
|
|
/** The caller must use confirmed source positions, never aggregate inventory rows. */
|
|
export async function allocateWarehouseTransfer(customerId: string, transferNo: string, payload: AllocateWarehouseTransferPayload) {
|
|
const response = await http.post<ApiEnvelope<WarehouseTransferDetailWire>, ApiEnvelope<WarehouseTransferDetailWire>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/allocations`,
|
|
payload,
|
|
{ params: { customerId } },
|
|
)
|
|
return normalizeTransferDetail(unwrapApiResponse(response))
|
|
}
|
|
|
|
export async function listWarehouseTransfers(customerId: string, query: WarehouseTransferQuery) {
|
|
const response = await http.get<ApiEnvelope<OverseasPagePayload<WarehouseTransferSummaryDto>>, ApiEnvelope<OverseasPagePayload<WarehouseTransferSummaryDto>>>(
|
|
'/platform/v1/last-leg/warehouse-transfers',
|
|
{ params: { ...query, customerId } },
|
|
)
|
|
return normalizeOverseasPage(unwrapApiResponse(response))
|
|
}
|
|
|
|
export async function getWarehouseTransfer(customerId: string, transferNo: string) {
|
|
const response = await http.get<ApiEnvelope<WarehouseTransferDetailWire>, ApiEnvelope<WarehouseTransferDetailWire>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}`,
|
|
{ params: { customerId } },
|
|
)
|
|
return normalizeTransferDetail(unwrapApiResponse(response))
|
|
}
|
|
|
|
export async function reviewWarehouseTransfer(
|
|
customerId: string,
|
|
transferNo: string,
|
|
decision: 'APPROVE' | 'REJECT',
|
|
remark?: string,
|
|
) {
|
|
const response = await http.post<ApiEnvelope<WarehouseTransferDetailWire>, ApiEnvelope<WarehouseTransferDetailWire>>(
|
|
`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/review`,
|
|
{ decision, remark },
|
|
{ params: { customerId } },
|
|
)
|
|
return normalizeTransferDetail(unwrapApiResponse(response))
|
|
}
|