fix(appointments): show authoritative timezone and business source

This commit is contained in:
2026-10-10 18:38:08 +08:00
parent 7f39adf9f5
commit ebff6f8167
5 changed files with 28 additions and 8 deletions
@@ -12,7 +12,7 @@ vi.mock('./planningApi', () => ({ listExternalAppointmentCandidates: vi.fn(), li
vi.mock('vue-router', () => ({ useRouter: () => ({ push: vi.fn() }) }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
const source: PlanningSource = { sourceKey: 'ORDER:1', customerId: 'A', orderId: '1', inboundCode: 'IN-A', bookingNo: null, containerNo: 'CONTAINER-A', originWarehouseId: '100', originWarehouseName: '美国仓', destinationKey: 'FBA:ONT8', destinationWarehouseCode: 'ONT8', packages: 20, sourceVersion: 'ORDER:1', canFollowup: true, blockReasons: [] }
const cargo: PlanningCargo = { sourceKey: source.sourceKey, customerId: 'A', customerName: '客户甲', orderId: '1', inboundCode: 'IN-A', containerBookingId: '2', containerNo: 'CONTAINER-A', originWarehouseId: '100', originWarehouseCode: 'US', originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', packages: 20, receivedPackages: null, shippedPackages: null, sourcePalletCount: null, volumeCbm: null, estimatedArrivalAt: null, estimatedWarehouseAt: null, orderVersion: 1, standardNode: 'DEPARTED', shippingVersion: null, shippingObservedAt: null, shippingProvider: null, hasInboundPlan: false, hasActiveAppointment: false, detained: false, mixedDestinations: false }
const cargo: PlanningCargo = { sourceKey: source.sourceKey, customerId: 'A', customerName: '客户甲', orderId: '1', inboundCode: 'IN-A', containerBookingId: '2', containerNo: 'CONTAINER-A', originWarehouseId: '100', originWarehouseCode: 'US', originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', packages: 20, receivedPackages: null, shippedPackages: null, sourcePalletCount: null, volumeCbm: null, estimatedArrivalAt: null, estimatedWarehouseAt: '2026-10-10T13:48:15', orderVersion: 1, standardNode: 'DEPARTED', shippingVersion: null, shippingObservedAt: null, shippingProvider: null, hasInboundPlan: false, hasActiveAppointment: false, detained: false, mixedDestinations: false }
const coverage = { status: 'UNASSIGNED', appointments: [], missingFields: [], changeReviewRequired: false }
describe('appointment tables use actual shared table slots', () => {
@@ -27,7 +27,7 @@ describe('appointment tables use actual shared table slots', () => {
vi.mocked(listPlanningCargo).mockResolvedValue({ records: [cargo], page: 1, size: 20, total: 1, pages: 1 })
const external: PlanningSource = { ...source, sourceKey: 'BOOKING:B-1', customerId: 'B', orderId: null, inboundCode: null, bookingNo: 'B-1', packages: null }
vi.mocked(listExternalAppointmentCandidates).mockResolvedValue({ records: [{ source: external, customerName: '客户乙', tripNo: 'TR-1', coverage: { status: 'UNSCHEDULED', appointments: [], missingFields: [], changeReviewRequired: false } }], total: 1 })
vi.mocked(previewPlanningBatch).mockResolvedValue({ group: { originWarehouseId: '100', destinationKey: 'FBA:ONT8', packages: null, sourceCount: 2, customerCount: 2, readyFrom: null, readyTo: null, readinessIncomplete: true, unknownQuantitySources: 1 }, originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', sources: [source, external], missingFields: [] })
vi.mocked(previewPlanningBatch).mockResolvedValue({ group: { originWarehouseId: '100', destinationKey: 'FBA:ONT8', packages: null, sourceCount: 2, customerCount: 2, readyFrom: null, readyTo: null, readinessIncomplete: true, unknownQuantitySources: 1 }, originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', destinationTimezone: 'America/Los_Angeles', sources: [source, external], missingFields: [] })
const wrapper = mount(AppointmentCargoPanel, { global: { plugins: [ElementPlus], stubs: { AppDialog: { template: '<section><slot /></section>' } } } })
await flushPromises()
expect(listExternalAppointmentCandidates).not.toHaveBeenCalled()
@@ -44,7 +44,7 @@ describe('appointment tables use actual shared table slots', () => {
it('combines an original external booking with first-leg cargo and retries the identical save command', async () => {
const external: PlanningSource={...source,sourceKey:'BOOKING:B-1',customerId:'B',bookingNo:'B-1',orderId:null,inboundCode:null,packages:null}
vi.mocked(listPlanningCargo).mockResolvedValue({records:[cargo],page:1,size:20,total:1,pages:1})
vi.mocked(previewPlanningBatch).mockResolvedValue({group:{originWarehouseId:'100',destinationKey:'FBA:ONT8',packages:null,sourceCount:2,customerCount:2,readyFrom:null,readyTo:null,readinessIncomplete:true,unknownQuantitySources:1},originWarehouseName:'美国仓',destinationWarehouseCode:'ONT8',sources:[external,source],missingFields:['CARGO_QUANTITY_REVIEW']})
vi.mocked(previewPlanningBatch).mockResolvedValue({group:{originWarehouseId:'100',destinationKey:'FBA:ONT8',packages:null,sourceCount:2,customerCount:2,readyFrom:null,readyTo:null,readinessIncomplete:true,unknownQuantitySources:1},originWarehouseName:'美国仓',destinationWarehouseCode:'ONT8',destinationTimezone:null,sources:[external,source],missingFields:['CARGO_QUANTITY_REVIEW']})
vi.mocked(createSourceAppointment).mockRejectedValueOnce(new Error('network interrupted')).mockResolvedValueOnce({id:'1',version:0,appointmentNo:'AP-MIXED',appointmentStatus:'PENDING',originWarehouseId:'100',fbaWarehouseCode:'ONT8',selectedCount:2,items:[]})
const wrapper=mount(AppointmentCargoPanel,{props:{externalSource:external},global:{plugins:[ElementPlus],stubs:{AppDialog:{template:'<section><slot /><button data-save @click="$emit(\'confirm\')">Save</button></section>'}}}})
await flushPromises()
@@ -72,7 +72,7 @@ describe('appointment tables use actual shared table slots', () => {
})
it('selects multiple customers and makes one authoritative batch check without per-row resolution', async () => {
vi.mocked(listPlanningCargo).mockResolvedValue({ records: [cargo, { ...cargo, sourceKey: 'ORDER:2', orderId: '2', inboundCode: 'IN-B', customerId: 'B', customerName: '客户乙' }], page: 1, size: 20, total: 2, pages: 1 })
vi.mocked(previewPlanningBatch).mockResolvedValue({ group: { originWarehouseId: '100', destinationKey: 'FBA:ONT8', packages: 40, sourceCount: 2, customerCount: 2, readyFrom: null, readyTo: null, readinessIncomplete: true, unknownQuantitySources: 0 }, originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', sources: [source], missingFields: ['READY_WINDOW_UNVERIFIED'] })
vi.mocked(previewPlanningBatch).mockResolvedValue({ group: { originWarehouseId: '100', destinationKey: 'FBA:ONT8', packages: 40, sourceCount: 2, customerCount: 2, readyFrom: null, readyTo: null, readinessIncomplete: true, unknownQuantitySources: 0 }, originWarehouseName: '美国仓', destinationWarehouseCode: 'ONT8', destinationTimezone: 'America/Los_Angeles', sources: [source], missingFields: ['READY_WINDOW_UNVERIFIED'] })
const wrapper = mount(AppointmentCargoPanel, { global: { plugins: [ElementPlus], stubs: { AppDialog: { template: '<section><slot /></section>' } } } })
await flushPromises()
await wrapper.findAll('button').find(button => button.text() === '选择本页可合批货物')!.trigger('click')
@@ -82,6 +82,10 @@ describe('appointment tables use actual shared table slots', () => {
expect(resolvePlanningSource).not.toHaveBeenCalled()
expect(wrapper.text()).toContain('2 票 / 2 个客户 / 预报 40 箱')
expect(wrapper.text()).toContain('保存前尚未占用货物')
expect(wrapper.text()).toContain('America/Los_Angeles')
expect(wrapper.text()).not.toContain('目的仓时区待核实')
expect(wrapper.text()).toContain('2026-10-10 13:48:15')
expect(wrapper.text()).toContain('来源时区未明确')
wrapper.unmount()
})
it('keeps the cargo list usable when impact service is unavailable and never reports a false zero', async () => {