2026-08-26 15:48:34 +08:00
import { beforeEach , describe , expect , it , vi } from 'vitest'
2026-09-29 17:56:00 +08:00
import { http } from '@/shared/api/http'
2026-09-01 19:57:36 +08:00
import { getDeliveryOrder , listDeliveryOrders , listDeliveryReturnInboundOptions , markDeliveryReturn } from './deliveryOrders'
2026-08-26 15:48:34 +08:00
2026-09-29 17:56:00 +08:00
vi . mock ( '@/shared/api/http' , async ( importOriginal ) => ({ ...( await importOriginal < typeof import ( '@/shared/api/http' ) >()), http : { get : vi . fn (), post : vi.fn () } }))
2026-08-26 15:48:34 +08:00
describe ( 'delivery order API' , () => {
2026-09-01 19:57:36 +08:00
beforeEach (() => {
2026-09-29 17:56:00 +08:00
vi . mocked ( http . get ). mockReset ()
vi . mocked ( http . post ). mockReset ()
2026-09-01 19:57:36 +08:00
})
2026-08-26 15:48:34 +08:00
it ( 'passes paging and expanded filters and normalizes page numbers' , async () => {
2026-09-29 17:56:00 +08:00
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : { records : [], page : '2' , size : '20' , total : '41' , pages : '3' } })
2026-08-26 15:48:34 +08:00
const result = await listDeliveryOrders ({ page : 2 , size : 20 , documentNo : 'DEL-1' , vehiclePlate : 'CA-1' })
2026-09-29 17:56:00 +08:00
expect ( http . get ). toHaveBeenCalledWith ( '/platform/v1/last-leg/delivery-orders' , { params : { page : 2 , size : 20 , documentNo : 'DEL-1' , vehiclePlate : 'CA-1' } })
2026-08-26 15:48:34 +08:00
expect ( result ). toMatchObject ({ page : 2 , size : 20 , total : 41 , pages : 3 })
})
it ( 'loads an encoded detail in its explicit customer scope' , async () => {
2026-09-29 17:56:00 +08:00
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : { order : { deliveryNo : 'DEL/1' , version : '0' }, skus : [], fees : [], operations : [] } })
2026-08-26 15:48:34 +08:00
await getDeliveryOrder ( 'DEL/1' , '1001' )
2026-09-29 17:56:00 +08:00
expect ( http . get ). toHaveBeenCalledWith ( '/platform/v1/last-leg/delivery-orders/DEL%2F1' , { params : { customerId : '1001' , page : 1 , size : 200 } })
2026-08-26 15:48:34 +08:00
})
2026-09-01 19:57:36 +08:00
2026-10-03 23:10:44 +08:00
it . each ([ null , 0 , 3 ])( 'preserves actual nullable signed quantity %s in list and detail' , async signedPackages => {
const order = { deliveryNo : 'DEL-1' , version : '0' , packageCount : 9 , signedPackages }
vi . mocked ( http . get ). mockResolvedValueOnce ({ code : '200' , data : { records : [ order ], page : 1 , size : 20 , total : 1 , pages : 1 } })
const page = await listDeliveryOrders ({ page : 1 , size : 20 })
expect ( page . records [ 0 ] ? . signedPackages ). toBe ( signedPackages )
vi . mocked ( http . get ). mockResolvedValueOnce ({ code : '200' , data : { order , skus : [], fees : [], operations : [] } })
expect (( await getDeliveryOrder ( 'DEL-1' , '1001' )). order . signedPackages ). toBe ( signedPackages )
})
2026-09-09 13:51:14 +08:00
it . each ([ '0' , '7' , '9007199254740991' ])( 'reads Java Long version %s for status editing' , async version => {
2026-09-29 17:56:00 +08:00
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : { order : { version , id : '2097515131537313794' } } })
2026-09-09 13:51:14 +08:00
const detail = await getDeliveryOrder ( 'DEL/1' , '1001' )
expect ( detail . order . version ). toBe ( Number ( version ))
expect ( detail . order . id ). toBe ( '2097515131537313794' )
})
it . each ([ null , undefined , '' , ' ' , '-1' , '1.5' , '9007199254740992' , - 1 ])( 'rejects invalid version %s' , async version => {
2026-09-29 17:56:00 +08:00
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : { order : { version } } })
2026-09-09 13:51:14 +08:00
await expect ( getDeliveryOrder ( 'DEL/1' , '1001' )). rejects . toThrow ( '派送单缺少有效版本' )
})
2026-09-01 19:57:36 +08:00
it ( 'loads return options and marks a return in the explicit customer scope' , async () => {
2026-10-18 16:37:37 +08:00
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : [{ lastMileOrderId : '109' , lastMileOrderNo : 'LM-1' , inboundOrderId : '9' , inboundCode : 'IN-1' , returnSources : [] }] })
2026-09-01 19:57:36 +08:00
await listDeliveryReturnInboundOptions ( 'DEL/1' , '1001' )
2026-09-29 17:56:00 +08:00
expect ( http . get ). toHaveBeenCalledWith ( '/platform/v1/last-leg/delivery-orders/DEL%2F1/return-inbound-options' , { params : { customerId : '1001' } })
2026-09-01 19:57:36 +08:00
2026-10-18 16:37:37 +08:00
const payload = { lastMileOrderId : '109' , reason : '客户拒收' , returnDirection : 'OVERSEAS_WAREHOUSE' as const , items : [{ outboundPalletItemId : '9007199254740995' , inventoryPositionId : '9007199254740996' , packageCount : 2 }], idempotencyKey : 'return-1' }
2026-09-29 17:56:00 +08:00
vi . mocked ( http . post ). mockResolvedValue ({ code : '200' , data : { id : '19' , exceptionNo : 'EXC-1' , status : 'PENDING' } })
2026-09-01 19:57:36 +08:00
await markDeliveryReturn ( 'DEL/1' , '1001' , payload )
2026-09-29 17:56:00 +08:00
expect ( http . post ). toHaveBeenCalledWith ( '/platform/v1/last-leg/delivery-orders/DEL%2F1/mark-return' , payload , { params : { customerId : '1001' } })
2026-09-01 19:57:36 +08:00
})
2026-10-18 16:37:37 +08:00
it ( 'preserves original return carton identity and submits it without inventing an inventory position' , async () => {
const source = { outboundPalletItemId : '9007199254740995' , inventoryPositionId : null , returnCartonId : '9007199254740997' , cartonMark : 'RTN-CARTON-1' , maxReturnPackages : 1 }
const relation = { lastMileOrderId : '9007199254741299' , lastMileOrderNo : 'LM-RETURN-1' , inboundOrderId : null , inboundCode : null , customerId : '1001' , returnSources : [{ ... source , maxReturnPackages : '1' }] }
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : [ relation ] })
const options = await listDeliveryReturnInboundOptions ( 'DEL/1' , '1001' )
expect ( options [ 0 ] ? . returnSources [ 0 ]). toEqual ( source )
expect ( options [ 0 ]). toMatchObject ({ lastMileOrderId : relation.lastMileOrderId , inboundOrderId : null , inboundCode : null })
const payload = { lastMileOrderId : relation.lastMileOrderId , reason : '原箱拒收' , returnDirection : 'OVERSEAS_WAREHOUSE' as const , items : [{ outboundPalletItemId : source.outboundPalletItemId , returnCartonId : source.returnCartonId , packageCount : 1 }], idempotencyKey : 'carton-return' }
vi . mocked ( http . post ). mockResolvedValue ({ code : '200' , data : { exceptionNo : 'EX-1' } })
await markDeliveryReturn ( 'DEL/1' , '1001' , payload )
expect ( http . post ). toHaveBeenLastCalledWith ( '/platform/v1/last-leg/delivery-orders/DEL%2F1/mark-return' , payload , { params : { customerId : '1001' } })
expect ( vi . mocked ( http . post ). mock . calls [ 0 ] ? .[ 1 ]). not . toHaveProperty ( 'inboundOrderId' )
})
it . each ([ undefined , null , '' , '0' , 'invalid' ])( 'rejects a candidate with invalid master identity %s even if it has an inbound association' , async lastMileOrderId => {
vi . mocked ( http . get ). mockResolvedValue ({ code : '200' , data : [{ lastMileOrderId , inboundOrderId : '9' , inboundCode : 'IN-1' , returnSources : [] }] })
await expect ( listDeliveryReturnInboundOptions ( 'DEL/1' , '1001' )). rejects . toThrow ( '尾程主单标识' )
expect ( http . post ). not . toHaveBeenCalled ()
})
2026-08-26 15:48:34 +08:00
})