import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { oceanBookingDraft, publishPlatformLogisticsChannels, resolveOceanBookingMaster } from './ocean-booking-fixture.mjs' test('ocean booking fixture resolves the current inbound customer channel and warehouse', async () => { const steps = [] const context = { marker: 'ADMIN-RUN-1', createdResources: { orchestrationFixtures: { phase3Container: { marker: 'ADMIN-RUN-1', tenantId: '21', inboundId: '31', } } }, request: async () => ({ body: { code: '200', data: { summary: { tenantId: 21, customerName: 'IT 测试客户', channelCode: 'SEA-US', channelName: '美西海运', warehouseId: 41, warehouseName: '深圳仓', } } } }), addStep: (...args) => steps.push(args), } const master = await resolveOceanBookingMaster(context, 'test') assert.deepEqual(master, { customerId: '21', customerName: 'IT 测试客户', channelCode: 'SEA-US', channelName: '美西海运', warehouseId: '41', warehouseName: '深圳仓' }) assert.equal(steps.length, 0) }) test('ocean booking fixture blocks creation instead of inventing missing master data', async () => { const steps = [] const context = { marker: 'ADMIN-RUN-2', createdResources: {}, addStep: (...args) => steps.push(args) } assert.equal(await resolveOceanBookingMaster(context, 'test'), null) assert.equal(steps.length, 1) assert.match(steps[0][4], /missing=customerId,customerName,channelCode,channelName,warehouseId,warehouseName/) }) test('shared booking draft omits server-owned channelName and release transport data', () => { const draft = oceanBookingDraft({ marker: 'ADMIN-RUN-3' }, '3', { customerId: '21', customerName: 'IT 测试客户', channelCode: 'SEA-US', channelName: '美西海运', warehouseId: '41', warehouseName: '深圳仓', }) for (const key of ['customerId', 'customerName', 'channelCode', 'warehouseId', 'warehouseName']) { assert.ok(draft[key], `${key} is required`) } assert.equal(draft.channelName, undefined) assert.equal(draft.containerRequirements[0].capacityCbm, 68) assert.equal(draft.containerRequirements[0].maxWeightKg, 28000) for (const key of ['billOfLadingNo', 'vesselName', 'voyageNo', 'estimatedSailingAt', 'estimatedArrivalAt']) { assert.equal(draft[key], undefined, `${key} belongs to release, not draft`) } }) test('platform channel producer queries the selected origin warehouse and publishes current-marker resources', async () => { const calls = [] const context = { marker: 'ADMIN-RUN-CHANNELS', createdResources: {}, request: async (method, path) => { calls.push({ method, path }) return { body: { code: '200', data: [ { channelCode: 'SEA-A', channelName: '海运 A' }, { channelCode: 'SEA-B', channelName: '海运 B' }, ] } } }, apiSuccess: (_module, _name, response) => response.body.data, assert: (_module, _name, _response, condition) => assert.equal(condition, true), } const catalog = await publishPlatformLogisticsChannels(context, '41', 'test') assert.deepEqual(calls, [{ method: 'GET', path: '/api/platform/v1/ocean-bookings/channels?originWarehouseId=41' }]) assert.equal(catalog.marker, context.marker) assert.equal(catalog.originWarehouseId, '41') assert.deepEqual(catalog.channels.map((value) => value.channelCode), ['SEA-A', 'SEA-B']) assert.deepEqual(context.createdResources.platformLogisticsChannels, catalog) }) test('all direct ocean booking payload builders omit channelName under the frozen DraftData contract', () => { const regions = [ ['manual-state-loading-pda.mjs', 'const draft = {', 'const createResponse'], ['manual-state-ocean-trucking.mjs', 'function oceanPayload', 'async function createOcean'], ['phase3-loading.mjs', 'const bookingDraft = {', 'const bookingCreate'], ['phase3-order-splitting.mjs', 'function bookingPayload', 'async function loadOneFragment'], ['phase3-container-loading.mjs', 'const bookingDraft = {', "context.assert(MODULE, '订舱渠道与仓库快照完整'"], ] for (const [name, start, end] of regions) { const value = readFileSync(new URL(name, import.meta.url), 'utf8') const region = value.slice(value.indexOf(start), value.indexOf(end)) assert.doesNotMatch(region, /channelName\s*:/, name) } const container = readFileSync(new URL('phase3-container-loading.mjs', import.meta.url), 'utf8') assert.doesNotMatch(container, /data:\s*\{[^}]*channelName\s*:/s) }) test('all independent ocean booking producers use the shared master-data contract', () => { for (const name of ['ocean-bookings.mjs', 'phase3-port-schedules.mjs', 'phase3-carrier-schedule-queries.mjs']) { const source = readFileSync(new URL(name, import.meta.url), 'utf8') assert.match(source, /resolveOceanBookingMaster\(context, MODULE\)/, name) assert.match(source, /oceanBookingDraft\(context, suffix, master/, name) } const container = readFileSync(new URL('phase3-container-loading.mjs', import.meta.url), 'utf8') for (const snippet of ['channelCode', 'publishPlatformLogisticsChannels', 'warehouseId', 'warehouseName', 'capacityCbm: 100', 'maxWeightKg: 100000']) assert.match(container, new RegExp(snippet), snippet) })