import test from 'node:test' import assert from 'node:assert/strict' import { verifyFleetExternalDispatch } from './fleet-external-dispatch-acceptance.mjs' function fixture(fault = '') { const segment = { fromIndex: 0, toIndex: 1, occupied: { palletSpaces: 2, weightKg: 200, volumeCbm: 2 }, remaining: { palletSpaces: 28, weightKg: 17800, volumeCbm: 88 } } const tripProof = { tripNo: 'TR-CURRENT', warehouseId: '92', dispatchNo: 'DP-OWN', stops: [{ name: '起点' }, { name: 'ONT8', destinationKey: 'FBA:ONT8' }], externalReceipt: { status: 'VERIFIED', createRequest: { customerId: '900719925474099301' }, incomingNo: 'WT-CURRENT', bookingNo: 'FB-CURRENT', warehousePalletId: '900719925474099311', palletNo: 'PALLET-EXT', finalSegments: [segment], finalBooking: { cargo: { destinationKey: 'FBA:ONT8' }, receipt: { source: { pallets: [{ weightKg: 100, volumeCbm: 1 }] } }, }, } } let version = 10, linked = false, replanned = false, transferred = false const calls = [], assertions = [] const customerId = tripProof.externalReceipt.createRequest.customerId const item = { warehousePalletId: tripProof.externalReceipt.warehousePalletId, packageCount: 1 } const booking = () => ({ bookingNo: 'FB-CURRENT', status: linked ? 'BOUND' : 'RECEIVED', incomingNo: 'WT-CURRENT', recordVersion: linked ? 4 : 3, dispatchNo: linked ? 'DP-EXT' : null }) const binding = () => ({ tripRecordVersion: version, booking: booking(), replayed: false }) const dispatches = [{ dispatchNo: 'DP-OWN', review: { status: 'PENDING' } }] const detail = () => ({ trip: { recordVersion: version, maxPalletSpaces: 30, vehiclePlate: 'TEST-TRUCK', driverName: 'TEST-DRIVER', driverPhone: '19900000000' }, dispatches }) const response = (data, message = '') => ({ http: 200, body: { code: message ? 'A0409' : '200', message, data: structuredClone(data) }, requestId: 'req', traceId: 'trace' }) const context = { marker: 'OFFLINE', createdResources: { fleetTrips: [tripProof] }, assert(module, name, res, passed, evidence, options) { assertions.push({ name, passed, options }) }, async request(method, path, body) { calls.push({ method, path, body }) if (path.endsWith('/capacity-plan')) { if (method === 'POST') { replanned = true; version++ } return response({ recordVersion: version, manifestHash: 'a'.repeat(64), planValid: !linked || replanned || fault === 'stale-plan', capacityPlan: { pallets: [{ warehousePalletId: 'OWN-PALLET', palletSpaces: 1, weightKg: 100, volumeCbm: 1, deliveryIndex: 1 }] }, cargo: [{ dispatchNo: 'DP-OWN', warehousePalletId: 'OWN-PALLET', packages: 1 }, ...(linked ? [{ dispatchNo: 'DP-EXT', warehousePalletId: tripProof.externalReceipt.warehousePalletId, packages: 1 }] : [])], availableSegments: replanned && fault === 'double-capacity' ? [{ ...segment, remaining: { ...segment.remaining, palletSpaces: 27 } }] : [segment] }) } if (path.includes('/candidates?')) return response([{ customerId: fault === 'foreign-customer' ? 'wrong' : customerId, overseasWarehouseId: '92', inboundCode: 'WT-CURRENT', warehousePalletId: tripProof.externalReceipt.warehousePalletId, palletNo: 'PALLET-EXT', packageCount: 1, sourceStage: 'RECEIVED', planPalletId: 'PLAN-PALLET' }]) if (path.endsWith('/drafts/containers')) return response({ id: 'CONTAINER' }) if (path.endsWith('/draft-locks/lock')) return response(null) if (path.endsWith('/pre-arrange')) return response({ dispatchNo: 'DP-EXT', packageCount: 1, pickedPackageCount: 0, shippedPackageCount: 0, items: [item] }) if (path.endsWith('/bookings')) return response({ tripRecordVersion: version, records: [booking()] }) if (path.endsWith('/bookings/FB-CURRENT/dispatch')) { if (linked) return response({ ...binding(), replayed: true }) linked = true; version++; dispatches.push({ dispatchNo: 'DP-EXT', review: { status: 'PENDING' } }); return response(binding()) } if (path.endsWith('/review')) { assert.equal(body.recordVersion, version); version++ const number = path.split('/').at(-2) if (fault !== 'review-not-applied') dispatches.find(row => row.dispatchNo === number).review.status = 'APPROVED' return response(detail()) } if (path.endsWith('/trips/TR-CURRENT')) return response(detail()) if (path.endsWith('/external-freight')) return response({ requiresDeliveryFee: false, snapshotHash: 'b'.repeat(64), quotes: [ { bookingNo: 'FB-CURRENT', incomingNo: 'WT-CURRENT', currency: 'CNY', amount: fault === 'stale-price' ? 50 : 30, quantity: 1, unitPrice: 30 }, ] }) if (path.endsWith('/transfer-delivery')) { if (body.fees.length) return response(null, '本排车全部货物已带入外接约定运费,请勿重复填写派送应收') const replayed = transferred; transferred = true return response({ dispatchNo: 'DP-EXT', outboundNo: 'OUT-EXT', packageCount: 1, deliveries: [{ deliveryNo: 'DEL-EXT' }], replayed }) } assert.match(path, /\/delivery-orders\/DEL-EXT\?customerId=900719925474099301$/) const rows = [{ feeDirection: 'RECEIVABLE', feeType: 'DELIVERY_FEE', currency: 'CNY', amount: 30, sourceStatus: 'ACTIVE', reviewStatus: 'APPROVED' }] if (fault === 'duplicate-fee' && calls.filter(row => row.path === path).length > 1) rows.push({ ...rows[0] }) return response({ order: { dispatchNo: 'DP-EXT' }, fees: rows }) }, } return { context, tripProof, calls, assertions } } test('external dispatch helper preserves reservation when binding physical cargo and publishes only agreed source fee', async () => { const f = fixture() const proof = await verifyFleetExternalDispatch(f.context, 'fleet-dispatch', f.tripProof) assert.equal(proof.status, 'VERIFIED') assert.equal(proof.dispatchNo, 'DP-EXT') assert.equal(proof.sourceFees.length, 1) assert.equal(proof.financeAcknowledgement, 'NOT_VERIFIED') assert.ok(f.assertions.every(row => row.passed && row.options.deploymentBlocker)) assert.ok(f.calls.every(row => !/\/pick|\/depart|\/cancel/.test(row.path))) await assert.rejects(() => verifyFleetExternalDispatch(f.context, 'fleet-dispatch', f.tripProof), /尚未执行关联/) }) for (const fault of ['foreign-customer', 'stale-plan', 'double-capacity', 'review-not-applied', 'stale-price', 'duplicate-fee']) { test(`external dispatch proof blocks ${fault}`, async () => { const f = fixture(fault) await assert.rejects(() => verifyFleetExternalDispatch(f.context, 'fleet-dispatch', f.tripProof)) assert.equal(f.tripProof.externalDispatch.status, 'CHECKING') assert.ok(f.assertions.some(row => !row.passed)) }) }