fix(ocean-booking): make customer optional through release

This commit is contained in:
2026-09-09 11:21:13 +08:00
parent 89d237e129
commit 87fc08b06e
4 changed files with 58 additions and 9 deletions
@@ -6,6 +6,7 @@ import { listPlatformTenants } from '@/modules/iam'
import { listPlatformPartners } from '@/modules/master-data'
import { listPlatformWarehouses } from '@/modules/warehouses'
import {
createOceanBooking,
getOceanBooking,
listOceanBookingAgents,
listWarehouseLogisticsChannels,
@@ -16,8 +17,9 @@ import type { OceanBookingDetail, OceanBookingStatus } from '../types'
import OceanBookingDetailView from './OceanBookingDetailView.vue'
const routerReplace = vi.hoisted(() => vi.fn())
const routeState = vi.hoisted(() => ({ name: 'ocean-booking-detail', params: { bookingId: '123' } }))
vi.mock('vue-router', () => ({
useRoute: () => ({ name: 'ocean-booking-detail', params: { bookingId: '123' } }),
useRoute: () => routeState,
useRouter: () => ({ push: vi.fn(), replace: routerReplace }),
}))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
@@ -61,7 +63,10 @@ function booking(status: OceanBookingStatus = 'DRAFT', version = 3, billOfLading
}
type ViewModel = {
form: { data: { billOfLadingNo: string } }
form: { data: import('../types').OceanBookingDraftData }
save: () => Promise<void>
selectCustomer: (value: unknown) => void
canManageDocuments: boolean
detail: OceanBookingDetail | null
actionError: { code?: string; requestId?: string; traceId?: string; message: string } | null
actionSaving: boolean
@@ -86,6 +91,7 @@ async function mountView() {
describe('OceanBookingDetailView one-click release', () => {
beforeEach(() => {
routeState.name = 'ocean-booking-detail'; routeState.params.bookingId = '123'
vi.clearAllMocks()
vi.mocked(getOceanBooking).mockResolvedValue(booking())
vi.mocked(listPlatformTenants).mockResolvedValue({ records: [], page: 1, size: 200, total: 0, pages: 0 })
@@ -110,6 +116,49 @@ describe('OceanBookingDetailView one-click release', () => {
expect(vm.detail?.version).toBe(5)
})
it('saves a new booking without a customer using explicit nulls', async () => {
routeState.name = 'ocean-booking-create'; routeState.params.bookingId = 'new'
vi.mocked(createOceanBooking).mockResolvedValue(booking())
const { vm, wrapper } = await mountView()
await vm.save()
expect(createOceanBooking).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining({ customerId: null, customerName: null }) }))
wrapper.unmount()
})
it('clears an existing customer before saving and releasing with the returned version', async () => {
const saved = booking('DRAFT', 4)
saved.customerId = null; saved.customerName = null; saved.oceanBooking.customerId = null; saved.oceanBooking.customerName = null
vi.mocked(updateOceanBookingDraft).mockResolvedValue(saved)
vi.mocked(releaseOceanBooking).mockResolvedValue({ ...saved, status: 'RELEASED', version: 5 })
const { vm, wrapper } = await mountView()
vm.selectCustomer('')
await vm.submitRelease()
expect(updateOceanBookingDraft).toHaveBeenCalledWith('123', expect.objectContaining({ data: expect.objectContaining({ customerId: null, customerName: null }) }))
expect(releaseOceanBooking).toHaveBeenCalledWith('123', { expectedVersion: 4 })
wrapper.unmount()
})
it('allows documents and release for a saved booking with no single customer', async () => {
const empty = booking()
empty.customerId = null; empty.customerName = null; empty.oceanBooking.customerId = null; empty.oceanBooking.customerName = null
vi.mocked(getOceanBooking).mockResolvedValue(empty)
vi.mocked(releaseOceanBooking).mockResolvedValue({ ...empty, status: 'RELEASED', version: 4 })
const { vm, wrapper } = await mountView()
expect(vm.canManageDocuments).toBe(true)
await vm.submitRelease()
expect(releaseOceanBooking).toHaveBeenCalledWith('123', { expectedVersion: 3 })
expect(updateOceanBookingDraft).not.toHaveBeenCalled()
wrapper.unmount()
})
it('preserves a selected single customer when saving', async () => {
vi.mocked(updateOceanBookingDraft).mockResolvedValue(booking('DRAFT', 4))
const { vm, wrapper } = await mountView()
await vm.save()
expect(updateOceanBookingDraft).toHaveBeenCalledWith('123', expect.objectContaining({ data: expect.objectContaining({ customerId: '456', customerName: '测试客户' }) }))
wrapper.unmount()
})
it('does not call release when automatic draft saving fails', async () => {
vi.mocked(updateOceanBookingDraft).mockRejectedValue(new ApiResponseError('保存草稿失败', 'A0409', 409, undefined, 'request-save', 'trace-save'))
const { vm } = await mountView()