fix: align audit and dispatch workflows and release failed requests
This commit is contained in:
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import ElementPlus, { ElMessageBox } from 'element-plus'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import { ApiResponseError } from '@/shared/api/http'
|
||||
import { ApiResponseError, http } from '@/shared/api/http'
|
||||
import type { ContainerCustomsStatus, ContainerCustomsView, DeclarationBatch, ClearanceResultType } from '../api/platformContainerCustoms'
|
||||
|
||||
const api = vi.hoisted(() => ({
|
||||
@@ -94,6 +94,8 @@ describe('ContainerCustomsPanel', () => {
|
||||
global: { plugins: [ElementPlus] },
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('ENTRY-001')
|
||||
expect(wrapper.text()).not.toContain('版本')
|
||||
await wrapper.findAll('button').find(button => button.text() === '标记海关异常/结果')!.trigger('click')
|
||||
const state = (wrapper.vm.$ as unknown as { setupState: {
|
||||
clearanceBatch: DeclarationBatch; clearanceResultType: ClearanceResultType; clearanceRemark: string; clearanceDialogVisible: boolean
|
||||
@@ -167,11 +169,11 @@ describe('ContainerCustomsPanel', () => {
|
||||
expect(wrapper.find('[aria-label="报关概况"]').exists()).toBe(false)
|
||||
expect(wrapper.text()).toContain('客户退税资料.pdf')
|
||||
expect(wrapper.text()).toContain('客户退税资料')
|
||||
expect(wrapper.text()).toContain('报关行回执')
|
||||
expect(wrapper.text()).toContain('预录单')
|
||||
expect(wrapper.text()).not.toContain('客户报关资料')
|
||||
expect(wrapper.find('[aria-label="下载客户退税资料 客户退税资料.pdf"]').exists()).toBe(true)
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('提交')
|
||||
})
|
||||
|
||||
@@ -204,13 +206,13 @@ describe('ContainerCustomsPanel', () => {
|
||||
it('allows completion upload and overwrite only while DECLARING with manage permission', async () => {
|
||||
let wrapper = await render('DECLARING', true, false)
|
||||
expect(wrapper.text()).toContain('首次发送报关行')
|
||||
expect(wrapper.text()).toContain('首次发送后上传回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传报关行回执')
|
||||
expect(wrapper.text()).toContain('首次发送后上传预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传预录单')
|
||||
wrapper.unmount()
|
||||
|
||||
wrapper = await render('DECLARING', true, true)
|
||||
expect(wrapper.text()).toContain('发送报关行执行')
|
||||
expect(wrapper.text()).toContain('覆盖报关行回执')
|
||||
expect(wrapper.text()).toContain('覆盖预录单')
|
||||
expect(wrapper.text()).toContain('报关行回执.pdf')
|
||||
expect(wrapper.text()).toContain('真实报关完税文件.pdf')
|
||||
expect(wrapper.text()).toContain('确认 · 2026/8/29 11:15:00 · 客户一')
|
||||
@@ -218,8 +220,8 @@ describe('ContainerCustomsPanel', () => {
|
||||
|
||||
wrapper = await render('DECLARING', false, true)
|
||||
expect(wrapper.text()).toContain('只读')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('提交')
|
||||
})
|
||||
|
||||
@@ -235,14 +237,40 @@ describe('ContainerCustomsPanel', () => {
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('隐藏资料版本但保留预录单历史、原文件名和上传并发版本', async () => {
|
||||
const value = customs('DECLARING', true)
|
||||
const document = value.documents[0]!
|
||||
document.receipt!.version = 7
|
||||
document.receiptHistory = [{ version: 6, file: { ...document.receipt!, version: 6 }, operatorName: '报关员', createdAt: '2026-08-29T10:50:00' }]
|
||||
api.get.mockResolvedValue(value)
|
||||
const wrapper = mount(ContainerCustomsPanel, {
|
||||
props: { loadingPlanId: value.loadingPlanId, canList: true, canManage: true, departureState: 'WAITING_OTHER_GATES' },
|
||||
global: { plugins: [ElementPlus] },
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('th').map(header => header.text())).toEqual(['操作', '客户退税资料', '预录单', '真实报关完税文件', '关联入仓码', '报关行状态', '客户', '预录单情况'])
|
||||
expect(wrapper.text()).not.toMatch(/版本|退税资料 v|回执 v|完税 v/)
|
||||
expect(wrapper.text()).toContain('预录单历史:2026/8/29 10:50:00 · 报关员')
|
||||
expect(wrapper.text()).toContain('确认 · 2026/8/29 11:15:00 · 客户一')
|
||||
expect(wrapper.find('[aria-label="下载预录单 报关行回执.pdf"]').exists()).toBe(true)
|
||||
const selected = new File(['receipt'], '新预录单.pdf', { type: 'application/pdf' })
|
||||
const onChange = wrapper.findAllComponents({ name: 'ElUpload' })[0]!.props('onChange') as (upload: { raw: File }) => void
|
||||
onChange({ raw: selected })
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find(button => button.text() === '提交')!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(api.upload).toHaveBeenCalledWith(document.documentId, selected, 7)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('keeps COMPLETED strictly read-only with both files visible and downloadable', async () => {
|
||||
const wrapper = await render('COMPLETED', true, true)
|
||||
expect(wrapper.text()).toContain('客户退税资料.pdf')
|
||||
expect(wrapper.text()).toContain('报关行回执.pdf')
|
||||
expect(wrapper.text()).toContain('真实报关完税文件.pdf')
|
||||
expect(wrapper.text()).toContain('报关已完成,待其他离仓条件')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖报关行回执')
|
||||
expect(buttonTexts(wrapper)).not.toContain('上传预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('覆盖预录单')
|
||||
expect(buttonTexts(wrapper)).not.toContain('提交')
|
||||
})
|
||||
|
||||
@@ -253,7 +281,7 @@ describe('ContainerCustomsPanel', () => {
|
||||
expect(api.downloadSource).toHaveBeenCalledWith('2092438843630391407')
|
||||
expect(api.downloadReceipt).not.toHaveBeenCalled()
|
||||
|
||||
await wrapper.get('[aria-label="下载报关行回执 报关行回执.pdf"]').trigger('click')
|
||||
await wrapper.get('[aria-label="下载预录单 报关行回执.pdf"]').trigger('click')
|
||||
await flushPromises()
|
||||
expect(api.downloadReceipt).toHaveBeenCalledWith('2092438843630391407')
|
||||
await wrapper.get('[aria-label="下载报关完税文件 真实报关完税文件.pdf"]').trigger('click')
|
||||
@@ -277,4 +305,46 @@ describe('ContainerCustomsPanel', () => {
|
||||
expect(wrapper.text()).toContain('trace-customs-download')
|
||||
expect(api.downloadReceipt).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('下载预录单失败时透传正式名称与诊断信息,保留原文件名', async () => {
|
||||
const get = vi.spyOn(http, 'get').mockResolvedValueOnce(new Blob([JSON.stringify({ code: 'A0404', message: '预录单不存在', data: null, requestId: 'request-pre-entry', traceId: 'trace-pre-entry' })], { type: 'application/json' }))
|
||||
api.downloadReceipt.mockImplementationOnce(async (documentId: string) => {
|
||||
const actual = await vi.importActual<typeof import('../api/platformContainerCustoms')>('../api/platformContainerCustoms')
|
||||
return actual.downloadContainerCustomsReceipt(documentId)
|
||||
})
|
||||
const wrapper = await render('COMPLETED', false, true)
|
||||
|
||||
await wrapper.get('[aria-label="下载预录单 报关行回执.pdf"]').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
await vi.waitFor(() => expect(wrapper.text()).toContain('预录单不存在'))
|
||||
expect(wrapper.text()).toContain('request-pre-entry')
|
||||
expect(wrapper.text()).toContain('trace-pre-entry')
|
||||
expect(wrapper.text()).toContain('报关行回执.pdf')
|
||||
expect(wrapper.text()).not.toContain('报关行回执不存在')
|
||||
expect(HTMLAnchorElement.prototype.click).not.toHaveBeenCalled()
|
||||
expect(get).toHaveBeenCalledWith('/platform/v1/customs/loading-plans/documents/2092438843630391407/completion/download', { responseType: 'blob' })
|
||||
get.mockRestore()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('上传冲突时展示服务端预录单提示并保留待上传文件', async () => {
|
||||
const message = '客户确认的预录单已发送给报关行,不可再修改预录单'
|
||||
api.upload.mockRejectedValueOnce(new ApiResponseError(message, 'A0409', 200, undefined, 'request-pre-entry-upload', 'trace-pre-entry-upload'))
|
||||
const wrapper = await render('DECLARING', true, true)
|
||||
const selected = new File(['receipt'], '预录单.pdf', { type: 'application/pdf' })
|
||||
const onChange = wrapper.findAllComponents({ name: 'ElUpload' })[0]!.props('onChange') as (upload: { raw: File }) => void
|
||||
onChange({ raw: selected })
|
||||
await flushPromises()
|
||||
const submit = wrapper.findAll('button').find(button => button.text() === '提交')!
|
||||
await submit.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain(message)
|
||||
expect(wrapper.text()).toContain('A0409')
|
||||
expect(wrapper.text()).toContain('request-pre-entry-upload')
|
||||
expect(wrapper.text()).toContain('trace-pre-entry-upload')
|
||||
expect(submit.attributes('disabled')).toBeUndefined()
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user