import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { IMMUTABLE_TAILLEG_EVENT_FIXTURE, TAILLEG_ORDER_NUMBER, validContainerOrderGroup, validEventReplay, validOwnerSnapshots, } from './tailleg-owner-order-number-contract.mjs' const read = (relativeUrl) => readFileSync(new URL(relativeUrl, import.meta.url), 'utf8') const eventV2 = read('../../common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2.java') const eventV2Tests = read('../../common-event-contract/src/test/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2Test.java') const consumer = read('../../lastleg-service/src/main/java/com/baiyue/lastleg/service/LoadingCompletedConsumer.java') const orderEntity = read('../../lastleg-service/src/main/java/com/baiyue/lastleg/entity/LastlegOrder.java') const orderSummary = read('../../lastleg-service/src/main/java/com/baiyue/lastleg/dto/LastlegOrderSummary.java') const orderService = read('../../lastleg-service/src/main/java/com/baiyue/lastleg/service/LastlegOrderService.java') const generator = read('../../lastleg-service/src/main/java/com/baiyue/lastleg/service/LastlegOrderNoGenerator.java') const generatorTests = read('../../lastleg-service/src/test/java/com/baiyue/lastleg/service/LastlegOrderNoGeneratorTest.java') const consumerTests = read('../../lastleg-service/src/test/java/com/baiyue/lastleg/service/LoadingCompletedConsumerTest.java') test('new 15-order event requires one non-empty trusted owner snapshot', () => { const orders = Array.from({ length: 15 }, (_, index) => ({ sourceInboundId: `inbound-${index + 1}`, customerId: 'customer-1', customerName: '验收货主', })) assert.equal(validOwnerSnapshots(orders, 15), true) assert.equal(validOwnerSnapshots(orders.map((order, index) => index === 7 ? { ...order, customerName: '' } : order), 15), false) assert.equal(validOwnerSnapshots(orders.map((order, index) => index === 7 ? { ...order, customerName: '另一货主' } : order), 15), false) }) test('the processed historical event is immutable and cannot be reused for acceptance', () => { assert.deepEqual(IMMUTABLE_TAILLEG_EVENT_FIXTURE, { eventId: 'b569c7f6-3493-4a0f-a944-dd42698f183b', status: 'PROCESSED', payloadMutable: false, reusableForAcceptance: false, }) }) test('V2 event contract freezes customerId and customerName and rejects a blank or mixed owner', () => { assert.match(eventV2, /List items,\s*String customerId,\s*String customerName,\s*String orderType/) assert.match(eventV2, /customerId\s*=\s*customerId\.trim\(\)/) assert.match(eventV2, /customerName\s*=\s*customerName\.trim\(\)/) assert.match(eventV2, /orders must share one immutable customerId\/customerName snapshot/) assert.match(eventV2Tests, /rejectsMissingImmutableCustomerName/) assert.match(eventV2Tests, /freezesTrimmedOwnerSnapshotAndRejectsMixedOwners/) }) test('Lastleg rejects a missing owner snapshot, persists it, and never calls IAM to repair it', () => { assert.match(consumer, /OwnerSnapshot owner\s*=\s*requireOwnerSnapshot\(payload\.orders\(\),\s*envelope\.tenantId\(\)\)/) assert.match(consumer, /requiredOwnerValue\(orders\.get\(0\)\.customerName\(\),\s*"customerName"\)/) assert.match(consumer, /value\s*==\s*null\s*\|\|\s*value\.isBlank\(\)/) assert.match(consumer, /order\.setCustomerName\(customerName\)/) assert.match(orderEntity, /private String customerName;/) assert.doesNotMatch(consumer, /(?:Iam|IAM|\/iam|CustomerClient|customer.*client)/) }) test('Lastleg query DTO uses the persisted frozen owner name', () => { assert.match(orderSummary, /String customerName/) assert.match(orderService, /o\.getCustomerName\(\)/) }) test('head-leg sourced tail orders preserve the existing container grouping number', () => { assert.equal(TAILLEG_ORDER_NUMBER.pattern.test('FL-WH-20261020-000042'), true) assert.equal(TAILLEG_ORDER_NUMBER.pattern.test('LMO2087379674555461633'), false) assert.equal(TAILLEG_ORDER_NUMBER.sharedBy, 'containerNo') assert.match(generator, /FL-WH-/) assert.match(generator, /BASIC_ISO_DATE/) assert.match(generator, /SHA-256/) assert.match(generatorTests, /actualContainerNumberRemainsStableAndShared/) }) test('one container with 15 inbound rows shares one stable container order number', () => { const rows = Array.from({ length: 15 }, (_, index) => ({ containerNo: 'CONT-15', orderNo: 'FL-WH-20261020-000042', sourceInboundId: `inbound-${index + 1}`, })) assert.equal(validContainerOrderGroup(rows), true) assert.equal(validContainerOrderGroup(rows.map((row, index) => index === 14 ? { ...row, orderNo: 'FL-WH-20261020-000043' } : row)), false) assert.match(consumer, /String orderNo\s*=\s*orderNoGenerator\.forContainerNo\(payload\.containerNo\(\)\);[\s\S]*for \(int index/) assert.match(consumer, /createOrder\(envelope, payload, source, orderNo, rawSource, containerNo/) assert.match(consumerTests, /oneContainerWith15InboundRowsSharesOneStableContainerOrderNumber/) }) test('same event replay adds nothing and preserves the allocated number', () => { const before = { orderCount: 15, orderNo: 'FL-WH-20261020-000042', detailCount: 30, historyCount: 15 } assert.equal(validEventReplay(before, { ...before }), true) assert.equal(validEventReplay(before, { ...before, orderCount: 30 }), false) const duplicateBranch = consumer.slice(consumer.indexOf('if(existing!=null)'), consumer.indexOf('LastlegEventInbox inbox=')) assert.match(duplicateBranch, /existing\.getPayloadHash\(\)\.equalsIgnoreCase\(envelope\.payloadHash\(\)\)/) assert.match(duplicateBranch, /!"PROCESSED"\.equals\(existing\.getStatus\(\)\).*throw new IllegalStateException/) assert.match(duplicateBranch, /return DeliveryAck\.of\(envelope, DeliveryAck\.Outcome\.DUPLICATE\)/) assert.doesNotMatch(duplicateBranch, /createOrder|forContainerNo|nextValue/) const racedBranch = consumer.slice(consumer.indexOf('catch(DuplicateKeyException exception)'), consumer.indexOf('projectLoadingEvidence(envelope')) assert.match(racedBranch, /raced\.getPayloadHash\(\)\.equalsIgnoreCase\(envelope\.payloadHash\(\)\)/) assert.match(racedBranch, /!"PROCESSED"\.equals\(raced\.getStatus\(\)\).*throw new IllegalStateException/) assert.match(racedBranch, /DeliveryAck\.Outcome\.DUPLICATE/) assert.match(consumerTests, /replayPreservesExistingLmoNumberAndAddsNothing/) assert.match(consumerTests, /verifyNoInteractions\(sequences\)/) })