2026-08-08 13:32:27 +08:00
|
|
|
import { describe, expect, it, vi } from 'vitest'
|
2026-08-18 16:09:43 +08:00
|
|
|
import { createOceanBooking, deleteOceanBookingDraft, listOceanBookings, listWarehouseLogisticsChannels, releaseOceanBooking, updateOceanBookingDraft } from './platformOceanBookings'
|
2026-08-08 13:32:27 +08:00
|
|
|
import { http } from '@/shared/api/http'
|
2026-08-10 09:12:06 +08:00
|
|
|
|
2026-08-18 16:09:43 +08:00
|
|
|
const detailResponse = (version = 0, status = 'DRAFT') => ({
|
2026-08-10 09:12:06 +08:00
|
|
|
oceanBooking: {
|
2026-08-17 20:01:51 +08:00
|
|
|
id: 123, bookingNo: 'OB123', status, version, customerId: 456, customerName: '客户', shipperName: '发货企业', consigneeName: '收货企业', containerCount: '2',
|
2026-08-10 09:12:06 +08:00
|
|
|
},
|
2026-08-17 13:24:55 +08:00
|
|
|
parties: [],
|
2026-08-18 16:09:43 +08:00
|
|
|
containerRequirements: [{ id: 9007199254740994, oceanBookingId: 123, containerType: '40HC', containerKind: 'FCL', quantity: 2, capacityCbm: 76, maxWeightKg: 28000 }],
|
2026-08-17 13:24:55 +08:00
|
|
|
containers: [{ containerBookingId: 9007199254740993, cabinetNo: 'CAB-1', containerNo: 'MSCU1234567', requirementId: 9007199254740994, allocationId: 9007199254740995, containerType: '40HC', containerKind: 'FCL', capacityCbm: 76, maxWeightKg: 28000, warehouseId: 9007199254740996, warehouseName: '义乌仓', channelCode: 'SEA', channelName: '海运', customerId: 456, customerName: '客户' }],
|
|
|
|
|
histories: [],
|
2026-08-10 09:12:06 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
describe('ocean bookings api', () => {
|
|
|
|
|
it('normalizes pagination and long ids', async () => {
|
2026-08-17 20:01:51 +08:00
|
|
|
vi.spyOn(http, 'get').mockResolvedValueOnce({ code: '200', message: 'ok', data: { records: [{ id: 123, customerId: 456, shipperName: '发货企业', consigneeName: '收货企业', containerCount: '3' }], page: '2', size: '20', total: '21', pages: '2' } })
|
2026-08-10 09:12:06 +08:00
|
|
|
const result = await listOceanBookings({ page: 1, size: 10 })
|
|
|
|
|
expect(result.page).toBe(2)
|
|
|
|
|
expect(result.total).toBe(21)
|
|
|
|
|
expect(result.records[0]?.id).toBe('123')
|
|
|
|
|
expect(result.records[0]?.customerId).toBe('456')
|
2026-08-17 20:01:51 +08:00
|
|
|
expect(result.records[0]).toMatchObject({ shipperName: '发货企业', consigneeName: '收货企业', containerCount: 3 })
|
2026-08-10 09:12:06 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('uses version zero for create and extracts the id from the returned Detail', async () => {
|
2026-08-18 16:09:43 +08:00
|
|
|
const post = vi.spyOn(http, 'post').mockResolvedValue({ code: '200', message: 'ok', data: detailResponse() })
|
|
|
|
|
const created = await createOceanBooking({ expectedVersion: 0, data: { customerId: null, customerName: null, channelCode: null, warehouseId: null, billOfLadingNo: '', vesselName: '', voyageNo: '', estimatedSailingAt: null, estimatedArrivalAt: null, serviceTerm: null, freightTerm: null, parties: [], containerRequirements: [{ containerType: '40HC', containerKind: 'FCL', quantity: 2, capacityCbm: 76, maxWeightKg: 28000 }] } })
|
2026-08-14 19:59:32 +08:00
|
|
|
const sentPayload = post.mock.calls[0]?.[1] as { expectedVersion: number; data: Record<string, unknown> }
|
2026-08-18 16:09:43 +08:00
|
|
|
expect(sentPayload).toMatchObject({ expectedVersion: 0, data: { customerId: null, customerName: null, channelCode: null, warehouseId: null } })
|
2026-08-14 19:59:32 +08:00
|
|
|
expect(sentPayload).not.toMatchObject({ data: { customerId: '', customerName: '' } })
|
2026-08-18 16:09:43 +08:00
|
|
|
expect(sentPayload.data).toMatchObject({ containerRequirements: [{ containerType: '40HC', quantity: 2, capacityCbm: 76, maxWeightKg: 28000 }] })
|
|
|
|
|
expect(sentPayload.data).not.toHaveProperty('containers')
|
2026-08-17 13:24:55 +08:00
|
|
|
expect(sentPayload.data).not.toHaveProperty('warehouseName')
|
2026-08-10 09:12:06 +08:00
|
|
|
expect(post.mock.calls[0]?.[2]).toMatchObject({ headers: { 'Idempotency-Key': expect.any(String) } })
|
|
|
|
|
expect(created.id).toBe('123')
|
|
|
|
|
expect(created.version).toBe(0)
|
2026-08-18 16:09:43 +08:00
|
|
|
expect(created.status).toBe('DRAFT')
|
|
|
|
|
expect(created.containerRequirements[0]).toMatchObject({ id: '9007199254740994', requirementId: '9007199254740994', quantity: 2 })
|
|
|
|
|
expect(created.containers[0]).toMatchObject({ containerBookingId: '9007199254740992', requirementId: '9007199254740994' })
|
2026-08-10 09:12:06 +08:00
|
|
|
})
|
|
|
|
|
|
2026-08-18 16:09:43 +08:00
|
|
|
it('uses draft update, delete and release contracts without legacy actions', async () => {
|
|
|
|
|
const put = vi.spyOn(http, 'put').mockResolvedValue({ code: '200', message: 'ok', data: detailResponse(4) })
|
|
|
|
|
const remove = vi.spyOn(http, 'delete').mockResolvedValue({ code: '200', message: 'ok', data: null })
|
|
|
|
|
const post = vi.spyOn(http, 'post').mockResolvedValue({ code: '200', message: 'ok', data: detailResponse(5, 'RELEASED') })
|
|
|
|
|
const data = { customerId: null, customerName: null, channelCode: null, warehouseId: null, billOfLadingNo: '', vesselName: '', voyageNo: '', estimatedSailingAt: null, estimatedArrivalAt: null, serviceTerm: null, freightTerm: null, parties: [], containerRequirements: [] }
|
|
|
|
|
await updateOceanBookingDraft('123', { expectedVersion: 3, data })
|
|
|
|
|
await deleteOceanBookingDraft('123', 4)
|
|
|
|
|
await releaseOceanBooking('123', { expectedVersion: 4 })
|
|
|
|
|
expect(put).toHaveBeenCalledWith('/platform/v1/ocean-bookings/123', { expectedVersion: 3, data }, { headers: { 'Idempotency-Key': expect.any(String) } })
|
|
|
|
|
expect(remove).toHaveBeenCalledWith('/platform/v1/ocean-bookings/123', { data: { expectedVersion: 4 }, headers: { 'Idempotency-Key': expect.any(String) } })
|
|
|
|
|
expect(post).toHaveBeenCalledWith('/platform/v1/ocean-bookings/123/release', { expectedVersion: 4 }, { headers: { 'Idempotency-Key': expect.any(String) } })
|
2026-08-10 09:12:06 +08:00
|
|
|
})
|
2026-08-14 18:50:11 +08:00
|
|
|
|
|
|
|
|
it('loads warehouse-scoped logistics channels from the booking contract', async () => {
|
|
|
|
|
vi.spyOn(http, 'get').mockResolvedValue({ code: '200', message: 'ok', data: [{ channelCode: 'SEA_FCL', channelName: '海运整箱' }] })
|
|
|
|
|
await expect(listWarehouseLogisticsChannels('8')).resolves.toEqual([{ channelCode: 'SEA_FCL', channelName: '海运整箱' }])
|
|
|
|
|
expect(http.get).toHaveBeenCalledWith('/platform/v1/ocean-bookings/channels', { params: { originWarehouseId: '8' } })
|
|
|
|
|
})
|
2026-08-10 09:12:06 +08:00
|
|
|
})
|