fix(loading): remove ISO container validation across PDA fulfillment

This commit is contained in:
2026-10-23 11:12:36 +08:00
parent c38f1758c5
commit 9c19980736
22 changed files with 215 additions and 162 deletions
@@ -3624,7 +3624,7 @@ components:
required: [sourceContainerBookingId, containerNo, overseasWarehouseId, overseasWarehouseCode, overseasWarehouseName, assignmentVersion, canChangeReceivingWarehouse, totalOrderCount, inboundCodeCount, missingInboundCodeCount, planCount, plannedInboundCodeCount, pendingPlanCount, resourcePendingPlanCount, allPlansReady]
properties:
sourceContainerBookingId: { type: string }
containerNo: { type: string, pattern: '^[A-Z]{3}[UJZ][0-9]{7}$', description: 装柜完成事件非空且通过 ISO 6346 校验位验证的规范化真实集装箱号;不使用 cabinetNo、订单号或内部 ID 回退 }
containerNo: { type: string, minLength: 1, description: 装柜完成事件中非空且已移除空白并转大写的真实集装箱号,不校验 ISO 6346 长度、结构、设备类别或校验位;不使用 cabinetNo、订单号或内部 ID 回退 }
overseasWarehouseId: { type: string, pattern: '^[1-9][0-9]*$', description: 平台预分配的海外接柜仓ID,不是FBA目的仓 }
overseasWarehouseCode: { type: string, description: 海外接柜仓业务编码 }
overseasWarehouseName: { type: string, description: 海外接柜仓业务名称 }
@@ -281,6 +281,28 @@ class LoadingCompletedConsumerTest {
assertEquals(Set.of("PHOTO_STEP_1","PHOTO_STEP_2","PHOTO_STEP_3","PHOTO_STEP_4","SEAL"),captured.getAllValues().stream().map(com.baiyue.lastleg.inboundplan.pda.entity.ContainerLoadingEvidence::getEvidenceType).collect(java.util.stream.Collectors.toSet()));
assertTrue(captured.getAllValues().stream().allMatch(value->"book-1".equals(value.getSourceContainerBookingId())));
}
/** 当前 V3 事件接受非 ISO 柜号,海外订单和来源柜快照保持同一实箱值。 */
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource(strings = {"JZXH10231043", "MSCU6639871", "ABC", "LOCAL-2026-001"})
void consumesV3EventWithNonIsoContainerNumber(String containerNo) {
EventEnvelope source=event();
var node=(com.fasterxml.jackson.databind.node.ObjectNode)v2Payload(source);
node.put("containerNo",containerNo);
var values=node.putArray("loadingEvidence"); int fileId=10;
for(String type:List.of("PHOTO_STEP_1","PHOTO_STEP_2","PHOTO_STEP_3","PHOTO_STEP_4","SEAL"))
values.addObject().put("evidenceType",type).put("fileId",fileId++).put("fileName",type+".jpg");
String hash=EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(node));
EventEnvelope event=new EventEnvelope(source.eventId(),source.eventType(),3,source.occurredAt(),source.tenantId(),
source.aggregateType(),source.aggregateId(),source.aggregateVersion(),3L,source.traceId(),source.correlationId(),
source.causationId(),node,hash);
assertEquals(DeliveryAck.Outcome.APPLIED,service.consume(event).outcome());
ArgumentCaptor<LastlegOrder> captured=ArgumentCaptor.forClass(LastlegOrder.class);
verify(orders,times(2)).insert(captured.capture());
assertTrue(captured.getAllValues().stream().allMatch(order->containerNo.equals(order.getContainerNo())));
assertEquals(containerNo,frozenContainerNos.get("book-1"));
}
@Test void rejectsV3EventWithoutTheFiveDomesticLoadingPhotos(){
EventEnvelope source=event(); JsonNode node=v2Payload(source);
String hash=EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(node));