feat(fleet): integrate trip management and fee coverage workflows
This commit is contained in:
@@ -65,9 +65,9 @@ export interface DeliveryOrderRow {
|
||||
}
|
||||
|
||||
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 }
|
||||
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[] }
|
||||
export interface DeliveryOrderDetail { order: DeliveryOrderRow; skus: DeliverySkuRow[]; fees: DeliveryFeeRow[]; operations: DeliveryOperationRow[]; feeCoverage?: import('../feeCoverageTypes').FeeCoverageEvidence | null }
|
||||
|
||||
export interface DeliveryReturnSource {
|
||||
outboundPalletItemId: string
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { cancelDispatch, createDispatchDraftContainer, deleteDispatchDraftContainer, getDispatch, getDispatchBolPdf, listDispatchCandidates, listDispatchDrafts, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, transferDispatchToDelivery, unlockDispatchDraftPallet, updateDispatch } from './dispatches'
|
||||
import { cancelDispatch, createDispatchDraftContainer, deleteDispatchDraftContainer, getDispatch, getDispatchBolPdf, getDispatchExternalFreight, getDispatchFeeCoverage, listDispatchCandidates, listDispatchDrafts, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, transferDispatchToDelivery, unlockDispatchDraftPallet, updateDispatch } from './dispatches'
|
||||
|
||||
vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOriginal<typeof import('@/shared/api/http')>()), http: { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn() } }))
|
||||
|
||||
describe('dispatch overseas API', () => {
|
||||
it('reads external freight from the scoped dispatch without a supplied customer', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { snapshotHash: 'hash', requiresDeliveryFee: false, quotes: [] } })
|
||||
expect(await getDispatchExternalFreight('DP/1')).toEqual({ snapshotHash: 'hash', requiresDeliveryFee: false, quotes: [] })
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/DP%2F1/external-freight')
|
||||
})
|
||||
it('loads per-shipment coverage without exposing a caller-supplied customer or losing long IDs', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { dispatchNo: 'DP/1', sourceComplete: true, blockReason: null, cargoHash: 'hash', cargo: [], feeSources: [{ financeFeeId: '190000000000000099', sourceFeeId: '190000000000000100', customerId: '101', sourceInboundId: '11', sourceVersion: '2', amount: '100.25' }] } })
|
||||
const result = await getDispatchFeeCoverage('DP/1')
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/DP%2F1/fee-coverage')
|
||||
expect(result.feeSources[0]).toMatchObject({ financeFeeId: '190000000000000099', sourceVersion: 2, amount: 100.25 })
|
||||
})
|
||||
beforeEach(() => {
|
||||
vi.mocked(http.get).mockReset()
|
||||
vi.mocked(http.post).mockReset()
|
||||
|
||||
@@ -235,6 +235,9 @@ export async function releaseDispatchDraft(draftToken: string) {
|
||||
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
|
||||
@@ -262,3 +265,24 @@ export async function transferDispatchToDelivery(dispatchNo: string, payload: Tr
|
||||
)
|
||||
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) })) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user