feat(fleet): integrate trip management and fee coverage workflows
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import ElementPlus, { ElFormItem, ElDatePicker, ElSelect, ElCheckbox } from 'element-plus'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import QueryToolbar, { type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||||
import { cancelDispatch, getDispatchBolPdf, listDispatches, removeDispatchItem, transferDispatchToDelivery, updateDispatch } from '../api/dispatches'
|
||||
import { cancelDispatch, getDispatchBolPdf, getDispatchExternalFreight, getDispatchFeeCoverage, listDispatches, removeDispatchItem, transferDispatchToDelivery, updateDispatch } from '../api/dispatches'
|
||||
import DeliveryFeeCoveragePanel from '../components/DeliveryFeeCoveragePanel.vue'
|
||||
import DispatchesView from './DispatchesView.vue'
|
||||
|
||||
const canPermission = vi.hoisted(() => vi.fn<(permissionCode: string) => boolean>(() => true))
|
||||
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: canPermission }) }))
|
||||
vi.mock('../api/dispatches', () => ({ listDispatches: vi.fn(), removeDispatchItem: vi.fn(), getDispatchBolPdf: vi.fn(), updateDispatch: vi.fn(), cancelDispatch: vi.fn(), transferDispatchToDelivery: vi.fn() }))
|
||||
vi.mock('../api/dispatches', () => ({ listDispatches: vi.fn(), removeDispatchItem: vi.fn(), getDispatchBolPdf: vi.fn(), getDispatchExternalFreight: vi.fn(), getDispatchFeeCoverage: vi.fn(), updateDispatch: vi.fn(), cancelDispatch: vi.fn(), transferDispatchToDelivery: vi.fn() }))
|
||||
|
||||
class ResizeObserverStub implements ResizeObserver {
|
||||
observe() {}
|
||||
@@ -52,6 +54,8 @@ describe('DispatchesView', () => {
|
||||
vi.mocked(removeDispatchItem).mockReset()
|
||||
vi.mocked(cancelDispatch).mockReset()
|
||||
vi.mocked(transferDispatchToDelivery).mockReset()
|
||||
vi.mocked(getDispatchExternalFreight).mockReset().mockResolvedValue({ snapshotHash: 'own-hash', requiresDeliveryFee: true, quotes: [] })
|
||||
vi.mocked(getDispatchFeeCoverage).mockReset().mockResolvedValue({ dispatchNo: 'PC-1', sourceComplete: true, blockReason: null, cargoHash: 'cargo-hash', cargo: [], feeSources: [] })
|
||||
canPermission.mockReset().mockReturnValue(true)
|
||||
})
|
||||
|
||||
@@ -150,6 +154,54 @@ describe('DispatchesView', () => {
|
||||
expect(source).toContain('请确认海外尾程排车接口已发布')
|
||||
})
|
||||
|
||||
it('loads external quotes only when opened and submits their hash without a duplicate delivery charge', async () => {
|
||||
vi.mocked(getDispatchExternalFreight).mockResolvedValue({ snapshotHash: 'external-hash', requiresDeliveryFee: false, quotes: [
|
||||
{ bookingNo: 'FB-1', recordVersion: '4', incomingNo: 'WT-1', inboundCode: 'IN-1', customerName: '客户甲', destinationKey: 'FBA:ONT8', currency: 'CNY', amount: 60, quantity: 2, quantityUnit: '托位', unitPrice: 30 },
|
||||
] })
|
||||
const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(getDispatchExternalFreight).not.toHaveBeenCalled()
|
||||
await wrapper.findAll('button').find(button => button.text() === '转派送')!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(getDispatchExternalFreight).toHaveBeenCalledOnce()
|
||||
expect(getDispatchExternalFreight).toHaveBeenCalledWith('PC-1')
|
||||
const dialog = wrapper.findAllComponents(AppDialog).find(item => item.props('title') === '转派送')!
|
||||
expect(dialog.text()).toContain('FB-1')
|
||||
expect(dialog.text()).not.toContain('请输入派送费用')
|
||||
dialog.findComponent(ElDatePicker).vm.$emit('update:modelValue', '2026-10-03T12:00:00')
|
||||
for (const [label, value] of [['派送方式', 'TRUCK_PALLET'], ['提货方式', 'WAREHOUSE_PICKUP'], ['装车类型', 'PALLET']]) {
|
||||
dialog.findAllComponents(ElFormItem).find(item => item.props('label') === label)!.findComponent(ElSelect).vm.$emit('update:modelValue', value)
|
||||
}
|
||||
await flushPromises()
|
||||
dialog.vm.$emit('confirm')
|
||||
await flushPromises()
|
||||
expect(transferDispatchToDelivery).toHaveBeenCalledWith('PC-1', expect.objectContaining({ fees: [], externalFreightHash: 'external-hash' }))
|
||||
})
|
||||
|
||||
it('confirms an original delivery fee without submitting a new receivable', async () => {
|
||||
vi.mocked(getDispatchFeeCoverage).mockResolvedValue({ dispatchNo: 'PC-1', sourceComplete: true, blockReason: null, cargoHash: 'actual-cargo',
|
||||
cargo: [{ dispatchItemId: '201', warehousePalletId: '501', palletNo: 'PLT-1', orderId: '401', sourceRegion: 'FIRSTLEG', sourceInboundId: '11', inboundCode: 'IN-11', packages: 20, dispatchInboundCode: 'IN-11' }],
|
||||
feeSources: [{ financeFeeId: '711', sourceFeeId: '811', sourceType: 'INBOUND_FEE', sourceVersion: 3, customerId: '101', sourceInboundId: '11', inboundCode: 'IN-11', feeItemCode: 'FREIGHT', feeItemName: '原运费', currency: 'CNY', amount: 100, sourceHash: 'original-fee-hash', status: 'AVAILABLE' }],
|
||||
})
|
||||
const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(getDispatchFeeCoverage).not.toHaveBeenCalled()
|
||||
await wrapper.findAll('button').find(button => button.text() === '转派送')!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(getDispatchFeeCoverage).toHaveBeenCalledTimes(1)
|
||||
const dialog = wrapper.findAllComponents(AppDialog).find(item => item.props('title') === '转派送')!
|
||||
await dialog.findComponent(DeliveryFeeCoveragePanel).findAllComponents(ElCheckbox).find(row => row.text() === '已含派送')!.find('input').setValue(true)
|
||||
dialog.findComponent(ElDatePicker).vm.$emit('update:modelValue', '2026-10-03T12:00:00')
|
||||
for (const [label, value] of [['派送方式', 'TRUCK_PALLET'], ['提货方式', 'WAREHOUSE_PICKUP'], ['装车类型', 'PALLET']]) {
|
||||
dialog.findAllComponents(ElFormItem).find(item => item.props('label') === label)!.findComponent(ElSelect).vm.$emit('update:modelValue', value)
|
||||
}
|
||||
await flushPromises()
|
||||
expect(dialog.text()).toContain('本次全部货物已覆盖:派送')
|
||||
dialog.vm.$emit('confirm')
|
||||
await flushPromises()
|
||||
expect(transferDispatchToDelivery).toHaveBeenCalledWith('PC-1', expect.objectContaining({ fees: [], feeCoverageCargoHash: 'actual-cargo', feeCoverage: [{ financeFeeId: '711', sourceVersion: 3, sourceHash: 'original-fee-hash', services: ['DELIVERY_FEE'] }] }))
|
||||
})
|
||||
|
||||
it('gates edit, cancel and transfer with independent permissions and service statuses', async () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages/DispatchesView.vue'), 'utf8')
|
||||
expect(source).toContain('permission.dispatchEdit')
|
||||
|
||||
Reference in New Issue
Block a user