优化
This commit is contained in:
@@ -1,346 +1,65 @@
|
||||
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
import type { DispatchEvidenceKind, DispatchRoute, DispatchRouteCommand } from '../dispatchContracts'
|
||||
import { requireVersion, requireBatchVersions, type AddCargo, type ArrangeDelivery, type CandidateQuery, type ConvertDraft, type CreateDispatch, type DispatchQuery, type DraftContainer, type DraftSelection, type LoadingComplete, type ReasonCommand, type ReviewCommand, type UpdateDispatch, type VersionCommand, type DispatchBatchAllocation } from '../dispatchContracts'
|
||||
import { normalizeArrangementPreview, normalizeCandidateList, normalizeConvertedDraft, normalizeDispatchCommand, normalizeDispatchDetail, normalizeDispatchDraft, normalizeDispatchItems, normalizeDispatchPage, normalizeEvidenceFile, normalizeLoadingPreview, type ArrangementPreviewWire, type CandidateListWire, type CommandResultWire, type ConvertedDraftWire, type DispatchDetailWire, type DispatchDraftWire, type DispatchEvidenceFileWire, type DispatchItemsWire, type DispatchPageWire, type LoadingPreviewWire } from '../dispatchWire'
|
||||
export type { DispatchBatchReference, DispatchBatchAllocation } from '../dispatchContracts'
|
||||
|
||||
import { normalizeOverseasPage, type OverseasPagePayload } from './lastMileOrders'
|
||||
|
||||
export interface DispatchQuery {
|
||||
page: number
|
||||
size: number
|
||||
dispatchNo?: string
|
||||
vehiclePlate?: string
|
||||
status?: string
|
||||
fbaAppointmentNo?: string
|
||||
stage?: 'BEFORE_LOADING' | 'LOADING' | 'AFTER_LOADING' | 'CANCELLED'
|
||||
}
|
||||
|
||||
export interface DispatchReview { status: 'PENDING' | 'APPROVED' | 'REJECTED'; reason: string | null; reviewedAt: string | null }
|
||||
export interface DispatchWorkflow { tripNo: string; dispatchReview: DispatchReview; loadingReview: DispatchReview }
|
||||
export interface DispatchActions {
|
||||
canEdit: boolean
|
||||
editBlockReason: string | null
|
||||
canCancel: boolean
|
||||
cancelBlockReason: string | null
|
||||
canRemovePallet: boolean
|
||||
removePalletBlockReason: string | null
|
||||
canTransfer: boolean
|
||||
transferBlockReason: string | null
|
||||
outboundNo: string | null
|
||||
outboundStatus: string | null
|
||||
}
|
||||
|
||||
export interface DispatchPalletCandidateDto {
|
||||
sourceType?: 'INBOUND_PLAN' | 'RETURN_RECEIPT'
|
||||
returnReceiptId?: string | null
|
||||
returnReceiptNo?: string | null
|
||||
planId?: string | null
|
||||
planPalletId?: string | null
|
||||
warehousePalletId?: string | null
|
||||
orderId: string
|
||||
customerId?: string | null
|
||||
customerName?: string | null
|
||||
planNo?: string | null
|
||||
orderType?: string | null
|
||||
volumeWeightKg?: number | null
|
||||
grossWeightKg?: number | null
|
||||
containerNo?: string | null
|
||||
appointmentAt?: string | null
|
||||
expectedLoadingAt?: string | null
|
||||
overseasWarehouseId?: string | null
|
||||
overseasWarehouseCode?: string | null
|
||||
overseasWarehouseName?: string | null
|
||||
orderNo?: string | null
|
||||
orderRefs?: string | null
|
||||
inboundCode?: string | null
|
||||
palletNo?: string | null
|
||||
destinationWarehouseId?: string | null
|
||||
destinationWarehouseCode?: string | null
|
||||
destinationWarehouseName?: string | null
|
||||
fbaWarehouseCode?: string | null
|
||||
packageCount?: number | null
|
||||
volumeCbm?: number | null
|
||||
sourceStage?: 'PLAN' | 'RECEIVED' | 'RELABEL' | null
|
||||
cartonMarks?: string | null
|
||||
relabelCartonMarks?: string | null
|
||||
destinationType?: 'FBA' | 'PRIVATE' | null
|
||||
deliveryAddress?: string | null
|
||||
postalCode?: string | null
|
||||
contactName?: string | null
|
||||
contactPhone?: string | null
|
||||
}
|
||||
|
||||
export interface DispatchCandidateQuery {
|
||||
planIds?: string
|
||||
orderNo?: string
|
||||
fbaWarehouseCode?: string
|
||||
sourceStage?: 'PLAN' | 'RECEIVED' | 'RELABEL'
|
||||
draftToken?: string
|
||||
}
|
||||
export interface DispatchDraftContainerDto { id: string; capacity: number; palletIds: string[] }
|
||||
export interface DispatchDraftDto { draftToken: string; containers?: DispatchDraftContainerDto[] }
|
||||
|
||||
export interface PreArrangeDispatchPayload {
|
||||
batchAllocations?: DispatchBatchAllocation[]
|
||||
planPalletIds: string[]
|
||||
returnReceiptIds?: string[]
|
||||
fbaAppointmentNo?: string
|
||||
fbaAppointmentStatus?: string
|
||||
vehicleAppointmentStatus?: string
|
||||
draftToken?: string
|
||||
relabelNo?: string
|
||||
}
|
||||
|
||||
export interface PreArrangeDispatchDraftGroup {
|
||||
batchAllocations?: DispatchBatchAllocation[]
|
||||
draftContainerId: string
|
||||
planPalletIds: string[]
|
||||
returnReceiptIds: string[]
|
||||
}
|
||||
export interface PreArrangeDispatchDraftPayload {
|
||||
draftToken: string
|
||||
groups: PreArrangeDispatchDraftGroup[]
|
||||
}
|
||||
export interface PreArrangeDispatchDraftResult {
|
||||
draftContainerId: string
|
||||
dispatch: DispatchSummaryDto
|
||||
}
|
||||
export interface DispatchBatchAllocation { planPalletId: string; batchKey: string; customerId: string; sourceKey: string; destinationKey: string; packageCount: number }
|
||||
export interface BatchDispatchCandidate { planPalletId: string; palletNo: string; planId: string; planNo: string; customerId: string; sourceStage: string; packageCount: number | null; allocations: DispatchBatchAllocation[]; blockReasons: string[] }
|
||||
export interface BatchDispatchCandidates { batchKey: string; version: number; candidates: BatchDispatchCandidate[]; blockReasons: string[] }
|
||||
export async function getBatchDispatchCandidates(batchKey: string) {
|
||||
return unwrapApiResponse(await http.get<ApiEnvelope<BatchDispatchCandidates>, ApiEnvelope<BatchDispatchCandidates>>(`/platform/v1/last-leg/appointment-planning/batches/${encodeURIComponent(batchKey)}/dispatch-candidates`))
|
||||
}
|
||||
|
||||
export interface DispatchBatchReference { batchKey: string; batchNo: string | null; customerId: string; sources: Array<{ sourceKey: string; destinationKey: string; packageCount: number }> }
|
||||
export interface DispatchSummaryDto {
|
||||
actions?: DispatchActions
|
||||
appointmentBatches: DispatchBatchReference[]
|
||||
workflow?: DispatchWorkflow | null
|
||||
id: string
|
||||
dispatchNo: string
|
||||
vehiclePlate?: string | null
|
||||
driverName?: string | null
|
||||
driverPhone?: string | null
|
||||
carrierName?: string | null
|
||||
orderNos?: string | null
|
||||
route?: string | null
|
||||
overseasWarehouseId?: string | null
|
||||
overseasWarehouseName?: string | null
|
||||
departAt?: string | null
|
||||
fbaAppointmentNo?: string | null
|
||||
fbaAppointmentStatus?: string | null
|
||||
vehicleAppointmentStatus?: string | null
|
||||
estimatedArrivalAt?: string | null
|
||||
status?: string | null
|
||||
itemCount?: number | null
|
||||
palletCount?: number | null
|
||||
packageCount?: number | null
|
||||
pickedPackageCount?: number | null
|
||||
shippedPackageCount?: number | null
|
||||
remainingPackageCount?: number | null
|
||||
partialCompletionReason?: string | null
|
||||
createdAt?: string | null
|
||||
items?: DispatchItemDto[]
|
||||
bolLines?: DispatchBolLineDto[]
|
||||
}
|
||||
|
||||
export interface DispatchBolLineDto {
|
||||
containerNo?: string | null
|
||||
palletNo?: string | null
|
||||
fbaWarehouseCode?: string | null
|
||||
destinationWarehouseName?: string | null
|
||||
warehouseNo?: string | null
|
||||
fbaShipmentId?: string | null
|
||||
poReferenceNo?: string | null
|
||||
packageCount: number
|
||||
}
|
||||
|
||||
export interface UpdateDispatchPayload {
|
||||
vehiclePlate?: string | null
|
||||
driverName?: string | null
|
||||
driverPhone?: string | null
|
||||
carrierName?: string | null
|
||||
departAt?: string | null
|
||||
fbaAppointmentNo?: string | null
|
||||
fbaAppointmentStatus?: string | null
|
||||
vehicleAppointmentStatus?: string | null
|
||||
estimatedArrivalAt?: string | null
|
||||
}
|
||||
|
||||
export interface DispatchItemDto {
|
||||
id: string
|
||||
planPalletId: string
|
||||
warehousePalletId?: string | null
|
||||
palletNo?: string | null
|
||||
overseasWarehouseId?: string | null
|
||||
overseasWarehouseName?: string | null
|
||||
orderNo?: string | null
|
||||
orderRefs?: string | null
|
||||
inboundCode?: string | null
|
||||
destinationWarehouseCode?: string | null
|
||||
destinationWarehouseName?: string | null
|
||||
fbaWarehouseCode?: string | null
|
||||
packageCount?: number | null
|
||||
grossWeightKg?: number | null
|
||||
volumeWeightKg?: number | null
|
||||
volumeCbm?: number | null
|
||||
sourceStage?: string | null
|
||||
}
|
||||
const base = '/platform/v1/last-leg/dispatches'
|
||||
const path = (dispatchNo: string) => `${base}/${encodeURIComponent(dispatchNo)}`
|
||||
async function get<T>(url: string) { return unwrapApiResponse(await http.get<ApiEnvelope<T>, ApiEnvelope<T>>(url)) }
|
||||
async function post<T>(url: string, body: object) { return unwrapApiResponse(await http.post<ApiEnvelope<T>, ApiEnvelope<T>>(url, body)) }
|
||||
const postCommand = (url: string, body: object) => post<CommandResultWire>(url, body).then(normalizeDispatchCommand)
|
||||
const postDraft = (url: string, body: object) => post<DispatchDraftWire>(url, body).then(normalizeDispatchDraft)
|
||||
function versioned<T extends VersionCommand>(body: T): T { requireVersion(body.recordVersion); return body }
|
||||
|
||||
export async function listDispatches(query: DispatchQuery) {
|
||||
const response = await http.get<ApiEnvelope<OverseasPagePayload<DispatchSummaryDto>>, ApiEnvelope<OverseasPagePayload<DispatchSummaryDto>>>(
|
||||
'/platform/v1/last-leg/dispatches',
|
||||
{ params: query },
|
||||
)
|
||||
return normalizeOverseasPage(unwrapApiResponse(response))
|
||||
return normalizeDispatchPage(unwrapApiResponse(await http.get<ApiEnvelope<DispatchPageWire>, ApiEnvelope<DispatchPageWire>>(base, { params: query })))
|
||||
}
|
||||
export const getDispatch = (dispatchNo: string) => get<DispatchDetailWire>(path(dispatchNo)).then(normalizeDispatchDetail)
|
||||
export const getDispatchItems = (no: string) => get<DispatchItemsWire>(`${path(no)}/items`).then(normalizeDispatchItems)
|
||||
export const getDispatchRoute = (no: string) => get<DispatchRoute>(`${path(no)}/route`)
|
||||
export async function reorderDispatchRoute(no: string, body: DispatchRouteCommand) { return normalizeDispatchCommand(unwrapApiResponse(await http.put<ApiEnvelope<CommandResultWire>, ApiEnvelope<CommandResultWire>>(`${path(no)}/route`, versioned(body)))) }
|
||||
const evidencePath = (no: string, kind: DispatchEvidenceKind, id?: string) => `${path(no)}/evidence/${kind}${id ? `/${encodeURIComponent(id)}` : ''}`
|
||||
export async function uploadDispatchEvidence(no: string, kind: DispatchEvidenceKind, file: File) { const form = new FormData(); form.append('file', file); return post<DispatchEvidenceFileWire>(evidencePath(no, kind), form).then(normalizeEvidenceFile) }
|
||||
export const getDispatchEvidence = (no: string, kind: DispatchEvidenceKind, id: string) => get<DispatchEvidenceFileWire>(evidencePath(no, kind, id)).then(normalizeEvidenceFile)
|
||||
export const getDispatchEvidenceContent = (no: string, kind: DispatchEvidenceKind, id: string) => http.get<Blob, Blob>(`${evidencePath(no, kind, id)}/content`, { responseType: 'blob' })
|
||||
export const getDispatchLoading = (dispatchNo: string) => get<LoadingPreviewWire>(`${path(dispatchNo)}/loading`).then(normalizeLoadingPreview)
|
||||
export const getDispatchCommand = (dispatchNo: string, key: string) => get<CommandResultWire>(`${path(dispatchNo)}/commands/${encodeURIComponent(key)}`).then(normalizeDispatchCommand)
|
||||
export const createDispatch = (body: CreateDispatch) => { requireBatchVersions(body.batchAllocations); return postCommand(base, body) }
|
||||
export async function updateDispatch(dispatchNo: string, body: UpdateDispatch) {
|
||||
versioned(body)
|
||||
if (body.vehicleAppointment) requireVersion(body.vehicleAppointment.recordVersion)
|
||||
return normalizeDispatchCommand(unwrapApiResponse(await http.put<ApiEnvelope<CommandResultWire>, ApiEnvelope<CommandResultWire>>(path(dispatchNo), body)))
|
||||
}
|
||||
export const addDispatchCargo = (no: string, body: AddCargo) => { versioned(body); requireBatchVersions(body.batchAllocations); return postCommand(`${path(no)}/items`, body) }
|
||||
export const removeDispatchItem = (no: string, itemId: string, body: ReasonCommand) => postCommand(`${path(no)}/items/${encodeURIComponent(itemId)}/remove`, versioned(body))
|
||||
export const cancelDispatch = (no: string, body: ReasonCommand) => postCommand(`${path(no)}/cancel`, versioned(body))
|
||||
export const submitDispatchReview = (no: string, body: VersionCommand & { remark: string | null }) => postCommand(`${path(no)}/submit-review`, versioned(body))
|
||||
export const reviewDispatch = (no: string, body: ReviewCommand) => postCommand(`${path(no)}/dispatch-review`, versioned(body))
|
||||
export const reviewDispatchLoading = (no: string, body: ReviewCommand) => postCommand(`${path(no)}/loading-review`, versioned(body))
|
||||
export const returnDispatchToReview = (no: string, body: ReasonCommand) => postCommand(`${path(no)}/return-to-review`, versioned(body))
|
||||
export const completeDispatchLoading = (no: string, body: LoadingComplete) => postCommand(`${path(no)}/loading-complete`, versioned(body))
|
||||
export const departDispatch = (no: string, body: VersionCommand & { remark: string | null }) => postCommand(`${path(no)}/depart`, versioned(body))
|
||||
export const getDispatchArrangement = (no: string) => get<ArrangementPreviewWire>(`${path(no)}/delivery-arrangement`).then(normalizeArrangementPreview)
|
||||
export const transferDispatchToDelivery = (no: string, body: ArrangeDelivery) => postCommand(`${path(no)}/transfer-delivery`, versioned(body))
|
||||
export const getDispatchBolPdf = (no: string) => http.get<Blob, Blob>(`${path(no)}/prints/bol`, { responseType: 'blob' })
|
||||
|
||||
export async function getDispatch(dispatchNo: string) {
|
||||
const response = await http.get<ApiEnvelope<DispatchSummaryDto>, ApiEnvelope<DispatchSummaryDto>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}`,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
export async function listDispatchCandidates(query: CandidateQuery) {
|
||||
return normalizeCandidateList(unwrapApiResponse(await http.get<ApiEnvelope<CandidateListWire>, ApiEnvelope<CandidateListWire>>(`${base}/candidates`, { params: query, paramsSerializer: { indexes: null } })))
|
||||
}
|
||||
export const listDispatchDrafts = () => get<DispatchDraftWire[]>(`${base}/drafts`).then(values => values.map(normalizeDispatchDraft))
|
||||
export const createDispatchDraft = (body: { idempotencyKey: string; warehouseId: string }) => postDraft(`${base}/drafts`, body)
|
||||
export const createDispatchDraftContainer = (body: VersionCommand & { draftToken: string; capacity: number }) => postDraft(`${base}/drafts/containers`, versioned(body))
|
||||
export const saveDispatchDraftSnapshot = (body: VersionCommand & { draftToken: string; planIds: string[]; containers: DraftContainer[] }) => postDraft(`${base}/drafts/snapshot`, versioned(body))
|
||||
export const lockDispatchDraftPallet = (body: DraftSelection) => postDraft(`${base}/draft-locks/lock`, versioned(body))
|
||||
export const unlockDispatchDraftPallet = (body: DraftSelection) => postDraft(`${base}/draft-locks/unlock`, versioned(body))
|
||||
export const releaseDispatchDraft = (body: VersionCommand & { draftToken: string }) => postDraft(`${base}/draft-locks/release`, versioned(body))
|
||||
export async function deleteDispatchDraftContainer(token: string, id: string, body: ReasonCommand) {
|
||||
return normalizeDispatchDraft(unwrapApiResponse(await http.delete<ApiEnvelope<DispatchDraftWire>, ApiEnvelope<DispatchDraftWire>>(`${base}/drafts/${encodeURIComponent(token)}/containers/${encodeURIComponent(id)}`, { data: versioned(body) })))
|
||||
}
|
||||
export const convertDispatchDraft = (body: ConvertDraft) => { versioned(body); requireBatchVersions(body.groups.flatMap(group => group.dispatch.batchAllocations)); return post<ConvertedDraftWire>(`${base}/drafts/pre-arrange`, body).then(normalizeConvertedDraft) }
|
||||
|
||||
export async function getDispatchBolPdf(dispatchNo: string) {
|
||||
return http.get<Blob, Blob>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}/prints/bol`,
|
||||
{ responseType: 'blob' },
|
||||
)
|
||||
}
|
||||
|
||||
export async function updateDispatch(dispatchNo: string, payload: UpdateDispatchPayload) {
|
||||
const response = await http.put<ApiEnvelope<DispatchSummaryDto>, ApiEnvelope<DispatchSummaryDto>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}`, payload,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function cancelDispatch(dispatchNo: string) {
|
||||
const response = await http.delete<ApiEnvelope<null>, ApiEnvelope<null>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}`,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function removeDispatchItem(dispatchNo: string, itemId: string) {
|
||||
const response = await http.delete<ApiEnvelope<DispatchSummaryDto>, ApiEnvelope<DispatchSummaryDto>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}/items/${encodeURIComponent(itemId)}`,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function listDispatchCandidates(query: DispatchCandidateQuery) {
|
||||
const response = await http.get<ApiEnvelope<DispatchPalletCandidateDto[]>, ApiEnvelope<DispatchPalletCandidateDto[]>>(
|
||||
'/platform/v1/last-leg/dispatches/candidates',
|
||||
{ params: query },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function preArrangeDispatch(payload: PreArrangeDispatchPayload) {
|
||||
const response = await http.post<ApiEnvelope<DispatchSummaryDto>, ApiEnvelope<DispatchSummaryDto>>(
|
||||
'/platform/v1/last-leg/dispatches/pre-arrange',
|
||||
payload,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function preArrangeDraftDispatch(payload: PreArrangeDispatchDraftPayload) {
|
||||
const response = await http.post<ApiEnvelope<PreArrangeDispatchDraftResult[]>, ApiEnvelope<PreArrangeDispatchDraftResult[]>>(
|
||||
'/platform/v1/last-leg/dispatches/drafts/pre-arrange', payload,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
function draftSource(selection: string) {
|
||||
return selection.startsWith('RETURN:')
|
||||
? { sourceType: 'RETURN_RECEIPT', returnReceiptId: selection.slice(7) }
|
||||
: { planPalletId: selection }
|
||||
}
|
||||
export async function lockDispatchDraftPallet(selection: string, draftToken: string, draftContainerId?: string) {
|
||||
const response = await http.post<ApiEnvelope<null>, ApiEnvelope<null>>(
|
||||
'/platform/v1/last-leg/dispatches/draft-locks/lock', { ...draftSource(selection), draftToken, ...(draftContainerId ? { draftContainerId } : {}) },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function listDispatchDrafts() {
|
||||
const response = await http.get<ApiEnvelope<DispatchDraftDto[]>, ApiEnvelope<DispatchDraftDto[]>>('/platform/v1/last-leg/dispatches/drafts')
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
export async function createDispatchDraftContainer(draftToken: string, capacity: number) {
|
||||
const response = await http.post<ApiEnvelope<DispatchDraftContainerDto>, ApiEnvelope<DispatchDraftContainerDto>>('/platform/v1/last-leg/dispatches/drafts/containers', { draftToken, capacity })
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
export async function deleteDispatchDraftContainer(draftToken: string, containerId: string) {
|
||||
const response = await http.delete<ApiEnvelope<null>, ApiEnvelope<null>>(`/platform/v1/last-leg/dispatches/drafts/${encodeURIComponent(draftToken)}/containers/${encodeURIComponent(containerId)}`)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function unlockDispatchDraftPallet(selection: string, draftToken: string) {
|
||||
const response = await http.post<ApiEnvelope<null>, ApiEnvelope<null>>(
|
||||
'/platform/v1/last-leg/dispatches/draft-locks/unlock', { ...draftSource(selection), draftToken },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function releaseDispatchDraft(draftToken: string) {
|
||||
const response = await http.post<ApiEnvelope<null>, ApiEnvelope<null>>(
|
||||
'/platform/v1/last-leg/dispatches/draft-locks/release', { draftToken },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export interface TransferDeliveryItem { deliveryNo: string; deliveryStatus: string; destinationWarehouseId?: string | null; destinationWarehouseCode?: string | null; destinationWarehouseName?: string | null; palletCount: number; packageCount: number }
|
||||
export interface TransferDeliveryResult { dispatchNo: string; outboundNo: string; outboundStatus: string; palletCount: number; packageCount: number; deliveries: TransferDeliveryItem[]; replayed: boolean }
|
||||
export interface TransferDeliveryPayload {
|
||||
feeCoverageCargoHash?: string
|
||||
feeCoverage?: import('../feeCoverageTypes').FeeCoverageSelection[]
|
||||
externalFreightHash?: string
|
||||
idempotencyKey: string
|
||||
plannedDeliveryAt: string
|
||||
deliveryMethod: string
|
||||
waybillNo?: string
|
||||
carrierName?: string
|
||||
pickupMethod: string
|
||||
loadingType: string
|
||||
vehicleType?: string
|
||||
vehicleSize?: string
|
||||
driverName?: string
|
||||
driverPhone?: string
|
||||
vehiclePlate?: string
|
||||
appointmentAccount?: string
|
||||
sellerName?: string
|
||||
remark?: string
|
||||
fees: Array<{ feeType: string; feeName: string; direction: 'RECEIVABLE' | 'PAYABLE'; currency: 'CNY' | 'USD'; amount: number
|
||||
supplierId?: string; supplierName?: string; supplierCategory?: string; settlementMode?: 'ON_ACCOUNT' | 'DIRECT_PAID'
|
||||
paidAt?: string; paymentMethod?: 'ONLINE' | 'BANK_TRANSFER' | 'CASH' | 'OTHER'; paymentReferenceNo?: string
|
||||
paymentVoucherFileIds?: string[]; chargeableQuantity?: number; quantityUnit?: string; unitPrice?: number
|
||||
periodStart?: string; periodEnd?: string; remark?: string }>
|
||||
}
|
||||
export async function transferDispatchToDelivery(dispatchNo: string, payload: TransferDeliveryPayload) {
|
||||
const response = await http.post<ApiEnvelope<TransferDeliveryResult>, ApiEnvelope<TransferDeliveryResult>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}/transfer-delivery`, payload,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export interface ExternalFreightPreview {
|
||||
snapshotHash: string
|
||||
requiresDeliveryFee: boolean
|
||||
quotes: Array<{ bookingNo: string; recordVersion: string | number; incomingNo: string; inboundCode: string;
|
||||
customerName: string; destinationKey: string; currency: string; amount: number; quantity: number; quantityUnit: string; unitPrice: number }>
|
||||
}
|
||||
export async function getDispatchExternalFreight(dispatchNo: string): Promise<ExternalFreightPreview> {
|
||||
const response = await http.get<ApiEnvelope<ExternalFreightPreview>, ApiEnvelope<ExternalFreightPreview>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}/external-freight`,
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function getDispatchFeeCoverage(dispatchNo: string): Promise<import('../feeCoverageTypes').FeeCoveragePreview> {
|
||||
const response = await http.get<ApiEnvelope<import('../feeCoverageTypes').FeeCoveragePreview>, ApiEnvelope<import('../feeCoverageTypes').FeeCoveragePreview>>(
|
||||
`/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}/fee-coverage`,
|
||||
)
|
||||
const data = unwrapApiResponse(response)
|
||||
return { ...data, cargo: data.cargo.map(row => ({ ...row, dispatchItemId: String(row.dispatchItemId), warehousePalletId: String(row.warehousePalletId), orderId: row.orderId == null ? null : String(row.orderId), sourceInboundId: row.sourceInboundId == null ? null : String(row.sourceInboundId), packages: Number(row.packages) })), feeSources: data.feeSources.map(row => ({ ...row, financeFeeId: String(row.financeFeeId), sourceFeeId: String(row.sourceFeeId), customerId: String(row.customerId), sourceInboundId: String(row.sourceInboundId), sourceVersion: Number(row.sourceVersion), amount: Number(row.amount) })) }
|
||||
}
|
||||
// Existing appointment-domain provider; its consumer handoff remains with the coordinator.
|
||||
export interface BatchDispatchCandidate { planPalletId: string; palletNo: string; planId: string; planNo: string; customerId: string; sourceStage: string; packageCount: number | null; allocations: DispatchBatchAllocation[]; blockReasons: string[] }
|
||||
export interface BatchDispatchCandidates { batchKey: string; version: number; candidates: BatchDispatchCandidate[]; blockReasons: string[] }
|
||||
export const getBatchDispatchCandidates = (key: string) => get<BatchDispatchCandidates>(`/platform/v1/last-leg/appointment-planning/batches/${encodeURIComponent(key)}/dispatch-candidates`).then(value => { requireBatchVersions(value.candidates.flatMap(row => row.allocations)); return value })
|
||||
|
||||
Reference in New Issue
Block a user