import { describe, expect, it } from 'vitest' import { oceanBookingPrintSignature, oceanBookingWorkflow } from './workflow' import type { OceanBookingDetail, OceanBookingResource } from './types' function detail(): OceanBookingDetail { // 流程只消费订舱已保存事实,不依赖权限、选项请求或页面临时输入。 const resource: OceanBookingResource = { id: '123', bookingNo: 'OB-123', status: 'DRAFT', version: 1, customerId: null, customerName: null, billOfLadingNo: null, shipperName: null, consigneeName: null, containerCount: 1, channelCode: null, channelName: null, warehouseId: null, warehouseName: null, shippingCompanyId: null, shippingCompanyName: null, carrierCode: null, bookingAgentId: null, bookingAgentName: null, vesselName: null, voyageNo: null, departurePortCode: null, departurePortName: null, destinationPortCode: null, destinationPortName: null, placeOfDelivery: null, estimatedSailingAt: null, estimatedArrivalAt: null, remark: null, createdAt: null, updatedAt: null, orderNo: null, carrierName: null, bookingAgent: null, pol: null, pod: null, mblShipper: null, mblConsignee: null, soNo: null, cutoffAt: null, etd: null, atd: null, eta: null, ata: null, containerSummary: null, amount: null, currency: null, declaredPackageCount: 500, declaredGrossWeightKg: 15000, declaredVolumeCbm: 68, actualPackageCount: null, actualGrossWeightKg: null, actualVolumeCbm: null, } return { ...resource, oceanBooking: resource, parties: [], containerRequirements: [], containers: [], documents: [], histories: [], statusHistory: [] } } describe('ocean booking workflow milestones', () => { it('starts on the first step and does not mark an unsaved form as complete', () => { expect(oceanBookingWorkflow(null, false, false, {}).map(step => step.state)) .toEqual(['current', 'pending', 'pending', 'pending']) expect(oceanBookingWorkflow(detail(), true, false, {})[0]).toMatchObject({ state: 'current', status: '修改待保存' }) }) it('advances from saved draft to preview, then to release without inventing a print record', () => { const saved = detail() const initial = oceanBookingWorkflow(saved, false, false, {}) expect(initial.map(step => step.state)).toEqual(['complete', 'current', 'pending', 'pending']) expect(initial[0]?.status).toBe('已保存') const previews = { SHIPPING_INSTRUCTION: oceanBookingPrintSignature(saved, 'SHIPPING_INSTRUCTION') } const previewed = oceanBookingWorkflow(saved, false, false, previews) expect(previewed.map(step => step.state)).toEqual(['complete', 'complete', 'current', 'pending']) expect(previewed[1]?.status).toBe('已预览') expect(previewed.some(step => step.status === '已打印')).toBe(false) }) it('restores released progress from server data and requires all saved actual values before final completion', () => { const saved = detail() saved.status = 'RELEASED' let steps = oceanBookingWorkflow(saved, false, false, {}) expect(steps.map(step => step.state)).toEqual(['complete', 'complete', 'complete', 'current']) expect(steps[1]).toMatchObject({ state: 'complete', status: '可重新预览 / 打印' }) expect(steps[2]).toMatchObject({ state: 'complete', status: '已放舱' }) expect(steps[3]).toMatchObject({ state: 'current', status: '待补齐实值' }) saved.actualPackageCount = 480 saved.actualGrossWeightKg = 14320 saved.actualVolumeCbm = 65 const previews = { BILL_OF_LADING_CONFIRMATION: oceanBookingPrintSignature(saved, 'BILL_OF_LADING_CONFIRMATION') } expect(oceanBookingWorkflow(saved, false, true, previews)[3]).toMatchObject({ state: 'current', status: '实值待保存' }) steps = oceanBookingWorkflow(saved, false, false, {}) expect(steps[3]).toMatchObject({ state: 'current', status: '可预览 / 打印' }) expect(oceanBookingWorkflow(saved, false, false, previews)[3]).toMatchObject({ state: 'complete', status: '已预览' }) }) it('invalidates only previews whose actual data changed', () => { const saved = detail() saved.status = 'RELEASED' saved.actualPackageCount = 480; saved.actualGrossWeightKg = 14320; saved.actualVolumeCbm = 65 const previews = { SHIPPING_INSTRUCTION: oceanBookingPrintSignature(saved, 'SHIPPING_INSTRUCTION'), BILL_OF_LADING_CONFIRMATION: oceanBookingPrintSignature(saved, 'BILL_OF_LADING_CONFIRMATION'), } saved.version = 100 // 附件等引起的订舱版本变化不会伪造或抹去相同单据的预览事实。 saved.actualPackageCount = 490 let steps = oceanBookingWorkflow(saved, false, false, previews) expect(steps[1]?.state).toBe('complete') expect(steps[3]).toMatchObject({ state: 'current', status: '可预览 / 打印' }) saved.declaredPackageCount = 510 steps = oceanBookingWorkflow(saved, false, false, previews) expect(steps[1]).toMatchObject({ state: 'complete', status: '可重新预览 / 打印' }) }) it('requires a fresh preview when draft print data changes before release', () => { const saved = detail() const previews = { SHIPPING_INSTRUCTION: oceanBookingPrintSignature(saved, 'SHIPPING_INSTRUCTION') } saved.declaredPackageCount = 510 expect(oceanBookingWorkflow(saved, false, false, previews).map(step => step.state)) .toEqual(['complete', 'current', 'pending', 'pending']) }) })