refactor(admin): scope truck orders to bookings
This commit is contained in:
@@ -18,15 +18,12 @@ vi.mock('../api/platformTrucking', () => ({ listTruckAppointmentCandidates: vi.f
|
||||
const model: SaveTruckAppointmentRequest = {
|
||||
expectedVersion: 0,
|
||||
oceanBookingId: null,
|
||||
containerBookingId: null,
|
||||
loadingPlanId: null,
|
||||
carrierId: null,
|
||||
plannedLoadingAt: null,
|
||||
}
|
||||
const candidates = [
|
||||
{ oceanBookingId: 'booking-1', oceanBookingNo: 'OB-1', billOfLadingNo: 'BL-1', warehouseId: 'WH-1', warehouseName: '义乌仓', channelCode: 'SEA', channelName: '海运', requirementId: 'requirement-1', containerType: '40HC', requirementQuantity: 2, containerBookingId: 'container-1', cabinetNo: 'CAB-1', containerNo: 'CBHU8888883', loadingPlanId: 'plan-1', loadingPlanNo: 'LP-1', loadingPlanStatus: 'EDITING', bookingDocumentReady: true },
|
||||
{ oceanBookingId: 'booking-1', oceanBookingNo: 'OB-1', billOfLadingNo: 'BL-1', warehouseId: 'WH-1', warehouseName: '义乌仓', channelCode: 'SEA', channelName: '海运', requirementId: 'requirement-1', containerType: '40HC', requirementQuantity: 2, containerBookingId: 'container-pending', cabinetNo: 'CAB-X', containerNo: null, loadingPlanId: null, loadingPlanNo: null, loadingPlanStatus: null, bookingDocumentReady: true },
|
||||
{ oceanBookingId: 'booking-2', oceanBookingNo: 'OB-2', billOfLadingNo: 'BL-2', warehouseId: 'WH-2', warehouseName: '东莞仓', channelCode: 'SEA', channelName: '海运', requirementId: 'requirement-2', containerType: '40GP', requirementQuantity: 1, containerBookingId: 'container-2', cabinetNo: 'CAB-2', containerNo: 'MSCU6639870', loadingPlanId: null, loadingPlanNo: null, loadingPlanStatus: null, bookingDocumentReady: true },
|
||||
{ oceanBookingId: 'booking-1', oceanBookingNo: 'OB-1', billOfLadingNo: 'BL-1', warehouseId: 'WH-1', warehouseName: '义乌仓', channelCode: 'SEA', channelName: '海运', bookingDocumentReady: true },
|
||||
{ oceanBookingId: 'booking-2', oceanBookingNo: 'OB-2', billOfLadingNo: 'BL-2', warehouseId: 'WH-2', warehouseName: '东莞仓', channelCode: 'SEA', channelName: '海运', bookingDocumentReady: true },
|
||||
]
|
||||
function detail(id: string) {
|
||||
const candidate = candidates.find((item) => item.oceanBookingId === id)!
|
||||
@@ -36,9 +33,9 @@ function detail(id: string) {
|
||||
containers: [],
|
||||
}
|
||||
}
|
||||
function resource(id: string, bookingId: string, containerId: string): TruckAppointmentResource {
|
||||
const candidate = candidates.find((item) => item.oceanBookingId === bookingId && item.containerBookingId === containerId)!
|
||||
return { id, status: 'DRAFT', oceanBookingId: bookingId, oceanBookingNo: candidate.oceanBookingNo, containerBookingId: containerId, cabinetNo: candidate.cabinetNo, containerNo: candidate.containerNo, relatedContainerType: candidate.containerType }
|
||||
function resource(id: string, bookingId: string): TruckAppointmentResource {
|
||||
const candidate = candidates.find((item) => item.oceanBookingId === bookingId)!
|
||||
return { id, status: 'DRAFT', oceanBookingId: bookingId, oceanBookingNo: candidate.oceanBookingNo, billOfLadingNo: candidate.billOfLadingNo, warehouseId: candidate.warehouseId, warehouseName: candidate.warehouseName }
|
||||
}
|
||||
|
||||
describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
@@ -48,7 +45,7 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
vi.mocked(getOceanBooking).mockImplementation(async (id) => detail(id) as never)
|
||||
})
|
||||
|
||||
it('selects a released booking, exposes pending-pickup internal containers, and never emits customer fields', async () => {
|
||||
it('selects only server-approved released bookings and never exposes container identity', async () => {
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model } }, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
const selects = wrapper.findAllComponents({ name: 'ElSelect' })
|
||||
@@ -58,8 +55,8 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
expect(listTruckAppointmentCandidates).toHaveBeenCalledWith({ page: 1, size: 200 })
|
||||
expect(getOceanBooking).not.toHaveBeenCalled()
|
||||
const labels = wrapper.findAllComponents({ name: 'ElOption' }).map((option) => String(option.props('label') || ''))
|
||||
expect(labels.some((label) => label.includes('CAB-1') && label.includes('CBHU8888883'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('CAB-X') && label.includes('40HC') && label.includes('待补录'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('OB-1') && label.includes('BL-1'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('CAB-'))).toBe(false)
|
||||
const emitted = wrapper.emitted('update:modelValue')?.at(-1)?.[0] as SaveTruckAppointmentRequest
|
||||
expect(emitted.oceanBookingId).toBe('booking-1')
|
||||
expect(emitted.billOfLadingNo).toBe('BL-1')
|
||||
@@ -68,23 +65,20 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('clears a selected container when switching to another booking', async () => {
|
||||
it('replaces frozen booking snapshots when switching the selected booking', async () => {
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model } }, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
const selects = wrapper.findAllComponents({ name: 'ElSelect' })
|
||||
selects[0]!.vm.$emit('update:modelValue', 'booking-1')
|
||||
await flushPromises()
|
||||
selects[1]!.vm.$emit('update:modelValue', 'container-1')
|
||||
await flushPromises()
|
||||
expect((wrapper.emitted('update:modelValue')?.at(-1)?.[0] as SaveTruckAppointmentRequest).containerBookingId).toBe('container-1')
|
||||
|
||||
selects[0]!.vm.$emit('update:modelValue', 'booking-2')
|
||||
await flushPromises()
|
||||
const emitted = wrapper.emitted('update:modelValue')?.at(-1)?.[0] as SaveTruckAppointmentRequest
|
||||
expect(emitted.oceanBookingId).toBe('booking-2')
|
||||
expect(emitted.containerBookingId).toBeNull()
|
||||
expect(emitted.billOfLadingNo).toBe('BL-2')
|
||||
expect(emitted.warehouseId).toBe('WH-2')
|
||||
const labels = wrapper.findAllComponents({ name: 'ElOption' }).map((option) => String(option.props('label') || ''))
|
||||
expect(labels.some((label) => label.includes('CAB-2'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('OB-2'))).toBe(true)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
@@ -95,11 +89,11 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
if (id === 'booking-1') resolveFirst = resolve as typeof resolveFirst
|
||||
else resolveSecond = resolve as typeof resolveSecond
|
||||
}) as never)
|
||||
const firstResource = resource('appointment-1', 'booking-1', 'container-1')
|
||||
const secondResource = resource('appointment-2', 'booking-2', 'container-2')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1', containerBookingId: 'container-1' }, resource: firstResource }, global: { plugins: [ElementPlus] } })
|
||||
const firstResource = resource('appointment-1', 'booking-1')
|
||||
const secondResource = resource('appointment-2', 'booking-2')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1' }, resource: firstResource }, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
await wrapper.setProps({ modelValue: { ...model, oceanBookingId: 'booking-2', containerBookingId: 'container-2' }, resource: secondResource })
|
||||
await wrapper.setProps({ modelValue: { ...model, oceanBookingId: 'booking-2' }, resource: secondResource })
|
||||
await flushPromises()
|
||||
|
||||
resolveSecond(detail('booking-2'))
|
||||
@@ -108,8 +102,8 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
await flushPromises()
|
||||
|
||||
const labels = wrapper.findAllComponents({ name: 'ElOption' }).map((option) => String(option.props('label') || ''))
|
||||
expect(labels.some((label) => label.includes('CAB-2') && label.includes('不可重选'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('CAB-1'))).toBe(false)
|
||||
expect(labels.some((label) => label.includes('OB-2') && label.includes('不可重选'))).toBe(true)
|
||||
expect(labels.some((label) => label.includes('OB-1'))).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('所选订舱缺少有效的订舱确认文件或提单文件')
|
||||
expect(listTruckAppointmentCandidates).not.toHaveBeenCalled()
|
||||
wrapper.unmount()
|
||||
@@ -117,8 +111,8 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
|
||||
it('preserves the business code and request trace when booking readiness fails', async () => {
|
||||
vi.mocked(getOceanBooking).mockRejectedValueOnce(new ApiResponseError('订舱版本冲突', 'A0409', 409, undefined, 'req-booking', 'trace-booking'))
|
||||
const current = resource('appointment-1', 'booking-1', 'container-1')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1', containerBookingId: 'container-1' }, resource: current }, global: { plugins: [ElementPlus] } })
|
||||
const current = resource('appointment-1', 'booking-1')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1' }, resource: current }, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('订舱版本冲突')
|
||||
expect(wrapper.text()).toContain('A0409')
|
||||
@@ -129,8 +123,8 @@ describe('TruckAppointmentForm booking-only behavior', () => {
|
||||
|
||||
it('flags an edit binding whose booking has become unreleased without adding it to create candidates', async () => {
|
||||
vi.mocked(getOceanBooking).mockResolvedValueOnce({ ...detail('booking-1'), status: 'DRAFT' } as never)
|
||||
const current = resource('appointment-1', 'booking-1', 'container-1')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1', containerBookingId: 'container-1' }, resource: current }, global: { plugins: [ElementPlus] } })
|
||||
const current = resource('appointment-1', 'booking-1')
|
||||
const wrapper = mount(TruckAppointmentForm, { props: { modelValue: { ...model, oceanBookingId: 'booking-1' }, resource: current }, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('当前绑定订舱已不是放舱状态')
|
||||
expect(listTruckAppointmentCandidates).not.toHaveBeenCalled()
|
||||
|
||||
Reference in New Issue
Block a user