import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' const source = readFileSync(new URL('./phase3-order-splitting.mjs', import.meta.url), 'utf8') test('each remainder uses a simulation linked to a released booking requirement', () => { assert.match(source, /POST', CONTAINERS/) assert.match(source, /POST', '\/api\/platform\/v1\/ocean-bookings'/) assert.match(source, /订舱为 RELEASED 且不预生成真实柜/) assert.doesNotMatch(source, /ocean-bookings\/\$\{oceanBookingId\}\/(?:submit|confirm)/) const createPayload = source.slice(source.indexOf('function bookingPayload'), source.indexOf('async function loadOneFragment')) assert.match(createPayload, /oceanBookingDraft\(\{ marker \}/) assert.match(createPayload, /customerId: source\.tenantId/) assert.match(createPayload, /channelCode: source\.channelCode/) assert.match(source, /ocean-booking-link/) assert.match(source, /oceanBookingId, requirementId: id\(requirement\.id\), containerNo: realContainerNo/) assert.match(source, /ocean-bookings\/\$\{oceanBookingId\}\/release/) const releaseStart = source.indexOf('const releaseResponse') const releaseBlock = source.slice(releaseStart, source.indexOf('bookingDetailResponse = await', releaseStart)) assert.match(releaseBlock, /expectedVersion: Number\(bookingCreated\?\.oceanBooking\?\.version\)/) assert.match(releaseBlock, /'Idempotency-Key': `\$\{operationBase\}-booking-release`\.slice\(0, 128\)/) assert.match(source, /oceanBooking\?\.status === 'RELEASED' && releasedAllocationMatches/) assert.match(source, /id\(item\?\.containerBookingId\) === containerId/) assert.match(source, /candidates\?bookingId=\$\{encodeURIComponent\(containerId\)\}&warehouseId=\$\{encodeURIComponent\(warehouseId\)\}/) assert.match(source, /`\$\{SMART\}\/plans`, \{ bookingId: containerId/) assert.doesNotMatch(source, /candidates\?warehouseId=/) }) test('release freezes and detail replays the same complete transport snapshot', () => { assert.match(source, /const BOOKING_TRANSPORT_FIELDS = \[/) assert.match(source, /const createdTransport = bookingTransportSnapshot\(bookingConfirmed\?\.oceanBooking\)/) assert.match(source, /const persistedTransport = bookingTransportSnapshot\(bookingDetail\?\.oceanBooking\)/) assert.match(source, /completeBookingTransport\(createdTransport\)/) assert.match(source, /sameBookingTransport\(createdTransport, persistedTransport\)/) assert.match(source, /if \(!transportFrozen\) return null/) }) test('PDA opens only after linking a released requirement and uses stable plan identity', () => { const pushIndex = source.indexOf("`${SMART}/plans/${planId}/push-preload`") const linkIndex = source.indexOf("`${CONTAINERS}/${containerId}/ocean-booking-link`") const releaseIndex = source.indexOf("`/api/platform/v1/ocean-bookings/${oceanBookingId}/release`") const confirmIndex = source.indexOf("`/api/platform/v1/first-leg/loading-plans/${encodeURIComponent(planId)}/confirm`") const taskIndex = source.indexOf("`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`") const canonicalTaskIndex = source.indexOf("`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`", taskIndex + 1) assert.ok(releaseIndex >= 0 && linkIndex > releaseIndex && pushIndex > linkIndex && taskIndex > pushIndex && confirmIndex > taskIndex && canonicalTaskIndex > confirmIndex) assert.match(source, /const realContainerNo = `SPLIT-/) assert.match(source, /const transportStable = linked\?\.containerNo === realContainerNo/) assert.match(source, /linked\?\.cabinetNo === simulation\.cabinetNo/) assert.match(source, /if \(!transportStable\) return null/) assert.match(source, /计划确认前不生成 PDA 任务/) assert.match(source, /summary\?\.readiness\?\.canConfirm === true/) assert.match(source, /Object\.freeze\(\{ expectedVersion: confirmableVersion \}\)/) assert.match(source, /confirmationStatus === 'CONFIRMED'/) assert.match(source, /readiness\?\.readyForPda === true/) assert.match(source, /taskId === confirmedTaskId/) assert.match(source, /计划确认同键同参精确重放/) assert.doesNotMatch(source, /\/preload\/confirming|\/preload\/confirm\?tenantId=/) assert.match(source, /id\(task\?\.loadingPlanId\) === planId/) assert.match(source, /id\(task\?\.containerBookingId\) === containerId/) assert.doesNotMatch(source, /\$\{PDA\}\/tasks\?containerNo=/) }) test('each remainder settles only through inventory snapshot, atomic batch and explicit complete', () => { const claimIndex = source.indexOf("`${PDA}/tasks/${taskId}/claim`") const snapshotIndex = source.indexOf('inventory-snapshot?warehouseId=') const batchIndex = source.indexOf('const batchPath = `${PDA}/tasks/${taskId}/batch`') const completeIndex = source.indexOf('const completePath = `${PDA}/tasks/${taskId}/complete`') const treeIndex = source.indexOf('`回查 ${sourceOrderNo} 拆分后的根聚合`') assert.ok(claimIndex >= 0 && snapshotIndex > claimIndex && batchIndex > snapshotIndex && completeIndex > batchIndex && treeIndex > completeIndex) assert.match(source, /loadingPlanId: planId, containerBookingId: containerId/) assert.match(source, /expectedVersion: Number\(inventory\.taskVersion\)/) assert.match(source, /inventorySnapshotToken: inventory\.snapshotToken/) assert.match(source, /action: 'PICK', pickedPackageCount: 1/) assert.match(source, /version: Number\(claimedItem\.version\), releaseMode: 'MANUAL', locationIds: \[\]/) assert.match(source, /'Idempotency-Key': batchKey/) assert.match(source, /differentReplay/) assert.match(source, /workflowStatus === 'AWAITING_REVIEW'/) assert.match(source, /expectedTaskVersion: Number\(picked\?\.version\)/) assert.match(source, /operationId: `\$\{operationBase\}-complete`/) assert.match(source, /completeReplay/) assert.match(source, /workflowStatus === 'COMPLETED'/) assert.doesNotMatch(source, /\/items\/\$\{[^}]+\}\/pick/) }) test('booking freezes the source customer channel and warehouse scope', () => { assert.match(source, /customerId: source\.tenantId/) assert.match(source, /channelCode: source\.channelCode/) assert.match(source, /warehouseId: source\.warehouseId/) assert.match(source, /containerType === '40HC'/) assert.match(source, /containerType: '40HC', capacityCbm: 76, maxWeightKg: 28000/) }) test('booking fixture never invents supplier names without formal IDs', () => { assert.match(source, /oceanBookingDraft/) assert.doesNotMatch(source, /SPLIT-SHIPPING|SPLIT-AGENT/) assert.doesNotMatch(source, /shippingCompanyName: `|bookingAgentName: `/) })