fix: block unsafe container plan actions
This commit is contained in:
@@ -285,6 +285,29 @@ describe('LastMileOrdersView pending order and container conversion', () => {
|
|||||||
expect(getContainerPlanProgress).not.toHaveBeenCalled()
|
expect(getContainerPlanProgress).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('keeps an invalid historical cabinet readable while blocking plan generation', async () => {
|
||||||
|
const invalid = {
|
||||||
|
...summary,
|
||||||
|
overseasWarehouseId: null,
|
||||||
|
overseasWarehouseCode: null,
|
||||||
|
overseasWarehouseName: null,
|
||||||
|
blockingReason: '柜内接柜仓业务快照不一致',
|
||||||
|
}
|
||||||
|
vi.mocked(listContainerPlanProgress).mockResolvedValueOnce({ records: [invalid], page: 1, size: 10, total: 1, pages: 1 } as never)
|
||||||
|
vi.mocked(getContainerPlanProgress).mockResolvedValueOnce({ summary: invalid, orders: [] } as never)
|
||||||
|
const wrapper = await mountView()
|
||||||
|
await wrapper.findAll('.el-radio-button').find((item) => item.text().startsWith('柜子'))!.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.text()).toContain('柜内接柜仓业务快照不一致')
|
||||||
|
expect((button(wrapper, '生成入库计划')!.element as HTMLButtonElement).disabled).toBe(true)
|
||||||
|
await wrapper.get('.container-workbench-card__detail').trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
expect(getContainerPlanProgress).toHaveBeenCalledWith(bookingId)
|
||||||
|
expect(document.body.textContent).toContain('柜子详情 · CONT-15')
|
||||||
|
expect(convertLastMileContainerToInboundPlans).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
it('shows the receiving warehouse and changes it from ACTIVE OVERSEAS master data with versioning', async () => {
|
it('shows the receiving warehouse and changes it from ACTIVE OVERSEAS master data with versioning', async () => {
|
||||||
vi.mocked(listAllPlatformWarehouses).mockResolvedValueOnce([receivingWarehouse] as never)
|
vi.mocked(listAllPlatformWarehouses).mockResolvedValueOnce([receivingWarehouse] as never)
|
||||||
const wrapper = await mountView()
|
const wrapper = await mountView()
|
||||||
|
|||||||
@@ -181,7 +181,20 @@ function formatDateTime(value: string | null | undefined) {
|
|||||||
return value ? value.replace('T', ' ').slice(0, 19) : '—'
|
return value ? value.replace('T', ' ').slice(0, 19) : '—'
|
||||||
}
|
}
|
||||||
function canGenerateContainerPlans(container: ContainerPlanProgressSummaryDto) {
|
function canGenerateContainerPlans(container: ContainerPlanProgressSummaryDto) {
|
||||||
return Boolean(container.containerNo) && container.pendingPlanCount > 0
|
return Boolean(container.containerNo
|
||||||
|
&& container.overseasWarehouseId
|
||||||
|
&& container.overseasWarehouseCode
|
||||||
|
&& container.overseasWarehouseName
|
||||||
|
&& container.assignmentVersion >= 0
|
||||||
|
&& container.pendingPlanCount > 0)
|
||||||
|
}
|
||||||
|
function containerSnapshotBlockReason(container: ContainerPlanProgressSummaryDto) {
|
||||||
|
if (!container.containerNo) return container.blockingReason || '来源柜真实集装箱号缺失、格式无效或存在漂移'
|
||||||
|
if (!container.overseasWarehouseId || !container.overseasWarehouseCode
|
||||||
|
|| !container.overseasWarehouseName || container.assignmentVersion < 0) {
|
||||||
|
return '柜内接柜仓业务快照不一致'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
function pendingInboundCodeCount(container: ContainerPlanProgressSummaryDto) {
|
function pendingInboundCodeCount(container: ContainerPlanProgressSummaryDto) {
|
||||||
return Math.max(0, container.inboundCodeCount - container.plannedInboundCodeCount)
|
return Math.max(0, container.inboundCodeCount - container.plannedInboundCodeCount)
|
||||||
@@ -498,7 +511,8 @@ onMounted(() => { void load() })
|
|||||||
<span class="container-workbench-card__top"><strong>{{ container.containerNo || '柜号待补充' }}</strong></span>
|
<span class="container-workbench-card__top"><strong>{{ container.containerNo || '柜号待补充' }}</strong></span>
|
||||||
<span class="container-workbench-card__warehouse">
|
<span class="container-workbench-card__warehouse">
|
||||||
<small>海外接柜仓</small><strong>{{ receivingWarehouseLabel(container) }}</strong>
|
<small>海外接柜仓</small><strong>{{ receivingWarehouseLabel(container) }}</strong>
|
||||||
<small v-if="!container.canChangeReceivingWarehouse && container.receivingWarehouseLockReason" class="is-locked">{{ container.receivingWarehouseLockReason }}</small>
|
<small v-if="containerSnapshotBlockReason(container)" class="is-locked">{{ containerSnapshotBlockReason(container) }}</small>
|
||||||
|
<small v-else-if="!container.canChangeReceivingWarehouse && container.receivingWarehouseLockReason" class="is-locked">{{ container.receivingWarehouseLockReason }}</small>
|
||||||
</span>
|
</span>
|
||||||
<span class="container-workbench-card__arrival"><small>计划到仓</small><strong>{{ formatDateTime(container.plannedArrivalAt) }}</strong></span>
|
<span class="container-workbench-card__arrival"><small>计划到仓</small><strong>{{ formatDateTime(container.plannedArrivalAt) }}</strong></span>
|
||||||
<span class="container-workbench-card__pending">
|
<span class="container-workbench-card__pending">
|
||||||
|
|||||||
Reference in New Issue
Block a user