fix(events): allow container nodes before ocean booking
This commit is contained in:
+4
-2
@@ -31,8 +31,10 @@ public record FirstLegContainerShippingNodeRecordedV1(
|
||||
if (queryId != null && queryId.isBlank()) {
|
||||
throw new IllegalArgumentException("船节点跟踪任务标识不能为空字符串");
|
||||
}
|
||||
if (oceanBookingId == null || oceanBookingId.isBlank()
|
||||
|| containerBookingId == null || containerBookingId.isBlank()
|
||||
if (oceanBookingId != null && oceanBookingId.isBlank()) {
|
||||
throw new IllegalArgumentException("船节点订舱标识不能为空字符串");
|
||||
}
|
||||
if (containerBookingId == null || containerBookingId.isBlank()
|
||||
|| containerNo == null || containerNo.isBlank()) {
|
||||
throw new IllegalArgumentException("船节点交接业务标识不能为空");
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@ components:
|
||||
destinationType: {type: string, enum: [FBA, OVERSEAS]}
|
||||
FirstLegContainerShippingNodeRecordedV1:
|
||||
type: object
|
||||
required: [oceanBookingId, sourceContainerBookingId, containerNo, standardNode, nodeSequence, observedAt, actualAt, providerCode, providerEventId, providerNodeCode, rawPayloadHash]
|
||||
required: [sourceContainerBookingId, containerNo, standardNode, nodeSequence, observedAt, actualAt, providerCode, providerEventId, providerNodeCode, rawPayloadHash]
|
||||
properties:
|
||||
queryId: {type: [string, 'null'], description: Automatic tracking task ID; null for a direct platform manual node.}
|
||||
oceanBookingId: {type: string}
|
||||
oceanBookingId: {type: [string, 'null'], description: Ocean booking ID when the physical container has already been linked; null is valid for a direct manual node.}
|
||||
sourceContainerBookingId: {type: string, minLength: 1}
|
||||
containerNo: {type: string, minLength: 1, description: Uppercase normalized physical container number; never cabinetNo or a technical identity}
|
||||
standardNode: {type: string}
|
||||
|
||||
+2
-1
@@ -39,12 +39,13 @@ class FirstLegContainerShippingNodeRecordedV1Test {
|
||||
void acceptsDirectManualNodeWithoutTrackingQuery() {
|
||||
var payload = payload();
|
||||
var manual = new FirstLegContainerShippingNodeRecordedV1(
|
||||
null, payload.oceanBookingId(), payload.containerBookingId(), payload.containerNo(),
|
||||
null, null, payload.containerBookingId(), payload.containerNo(),
|
||||
payload.standardNode(), payload.nodeSequence(), payload.observedAt(), payload.actualAt(),
|
||||
payload.locationCode(), payload.locationName(), "MANUAL", "manual-event", payload.providerNodeCode(),
|
||||
"MANUAL:7", payload.rawPayloadHash());
|
||||
|
||||
assertThat(manual.queryId()).isNull();
|
||||
assertThat(manual.oceanBookingId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS ll_loading_event_inbox (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_container_shipping_gate (
|
||||
container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID',
|
||||
ocean_booking_id VARCHAR(128) NOT NULL COMMENT '来源海运订舱ID', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
|
||||
ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE',
|
||||
standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点', node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号',
|
||||
observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间', actual_at DATETIME(3) NULL COMMENT '节点实际发生时间',
|
||||
@@ -3307,7 +3307,7 @@ PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCA
|
||||
-- 海运节点达到可提柜后才允许海外 PDA 认领;装柜完成只建立等待门禁快照。
|
||||
CREATE TABLE IF NOT EXISTS ll_container_shipping_gate (
|
||||
container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID',
|
||||
ocean_booking_id VARCHAR(128) NOT NULL COMMENT '来源海运订舱ID',
|
||||
ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空',
|
||||
container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE',
|
||||
standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点',
|
||||
@@ -4604,3 +4604,7 @@ CALL assert_overseas_finance_p0_ready();
|
||||
DROP PROCEDURE IF EXISTS assert_overseas_finance_p0_ready;
|
||||
|
||||
SELECT 'PASS' AS migration_status, '海外财务P0费用来源字段已就绪' AS message;
|
||||
|
||||
-- 人工货柜节点独立于订舱:货柜尚未关联海运订舱时仍可同步当前节点。
|
||||
ALTER TABLE ll_container_shipping_gate
|
||||
MODIFY ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空';
|
||||
|
||||
+2
-1
@@ -99,13 +99,14 @@ class CarrierScheduleNodeOutboxServiceTest {
|
||||
fact.setProviderCode("MANUAL"); fact.setProviderEventId("manual-event");
|
||||
fact.setSourceReference("MANUAL:7");
|
||||
|
||||
service.publishContainerNode(2088000000000000004L, 2088000000000000003L,
|
||||
service.publishContainerNode(null, 2088000000000000003L,
|
||||
fact, "ZCSU7881970");
|
||||
|
||||
ArgumentCaptor<InboundOutboxEntity> captor = ArgumentCaptor.forClass(InboundOutboxEntity.class);
|
||||
verify(mapper).insert(captor.capture());
|
||||
EventEnvelope envelope = objectMapper.readValue(captor.getValue().getPayloadJson(), EventEnvelope.class);
|
||||
assertThat(envelope.payload().path("queryId").isNull()).isTrue();
|
||||
assertThat(envelope.payload().path("oceanBookingId").isNull()).isTrue();
|
||||
assertThat(envelope.payload().path("sourceContainerBookingId").asText())
|
||||
.isEqualTo("2088000000000000003");
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS ll_loading_event_inbox (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_container_shipping_gate (
|
||||
container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID',
|
||||
ocean_booking_id VARCHAR(128) NOT NULL COMMENT '来源海运订舱ID', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
|
||||
ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE',
|
||||
standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点', node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号',
|
||||
observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间', actual_at DATETIME(3) NULL COMMENT '节点实际发生时间',
|
||||
|
||||
Reference in New Issue
Block a user