fix(events): allow manual nodes without tracking query
This commit is contained in:
+4
-1
@@ -28,7 +28,10 @@ public record FirstLegContainerShippingNodeRecordedV1(
|
|||||||
"EMPTY_RETURNED", 100);
|
"EMPTY_RETURNED", 100);
|
||||||
|
|
||||||
public FirstLegContainerShippingNodeRecordedV1 {
|
public FirstLegContainerShippingNodeRecordedV1 {
|
||||||
if (queryId == null || queryId.isBlank() || oceanBookingId == null || oceanBookingId.isBlank()
|
if (queryId != null && queryId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("船节点跟踪任务标识不能为空字符串");
|
||||||
|
}
|
||||||
|
if (oceanBookingId == null || oceanBookingId.isBlank()
|
||||||
|| containerBookingId == null || containerBookingId.isBlank()
|
|| containerBookingId == null || containerBookingId.isBlank()
|
||||||
|| containerNo == null || containerNo.isBlank()) {
|
|| containerNo == null || containerNo.isBlank()) {
|
||||||
throw new IllegalArgumentException("船节点交接业务标识不能为空");
|
throw new IllegalArgumentException("船节点交接业务标识不能为空");
|
||||||
|
|||||||
@@ -42,10 +42,9 @@ components:
|
|||||||
destinationType: {type: string, enum: [FBA, OVERSEAS]}
|
destinationType: {type: string, enum: [FBA, OVERSEAS]}
|
||||||
FirstLegContainerShippingNodeRecordedV1:
|
FirstLegContainerShippingNodeRecordedV1:
|
||||||
type: object
|
type: object
|
||||||
required: [queryId, customerId, oceanBookingId, sourceContainerBookingId, containerNo, standardNode, nodeSequence, observedAt, actualAt, providerCode, providerEventId, providerNodeCode, rawPayloadHash]
|
required: [oceanBookingId, sourceContainerBookingId, containerNo, standardNode, nodeSequence, observedAt, actualAt, providerCode, providerEventId, providerNodeCode, rawPayloadHash]
|
||||||
properties:
|
properties:
|
||||||
queryId: {type: string}
|
queryId: {type: [string, 'null'], description: Automatic tracking task ID; null for a direct platform manual node.}
|
||||||
customerId: {type: string}
|
|
||||||
oceanBookingId: {type: string}
|
oceanBookingId: {type: string}
|
||||||
sourceContainerBookingId: {type: string, minLength: 1}
|
sourceContainerBookingId: {type: string, minLength: 1}
|
||||||
containerNo: {type: string, minLength: 1, description: Uppercase normalized physical container number; never cabinetNo or a technical identity}
|
containerNo: {type: string, minLength: 1, description: Uppercase normalized physical container number; never cabinetNo or a technical identity}
|
||||||
|
|||||||
+12
@@ -35,6 +35,18 @@ class FirstLegContainerShippingNodeRecordedV1Test {
|
|||||||
.hasMessageContaining("normalized");
|
.hasMessageContaining("normalized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void acceptsDirectManualNodeWithoutTrackingQuery() {
|
||||||
|
var payload = payload();
|
||||||
|
var manual = new FirstLegContainerShippingNodeRecordedV1(
|
||||||
|
null, payload.oceanBookingId(), 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();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void rejectsEstimatedOnlyOrIncompleteProviderFacts() {
|
void rejectsEstimatedOnlyOrIncompleteProviderFacts() {
|
||||||
assertThatThrownBy(() -> new FirstLegContainerShippingNodeRecordedV1(
|
assertThatThrownBy(() -> new FirstLegContainerShippingNodeRecordedV1(
|
||||||
|
|||||||
+17
@@ -93,6 +93,23 @@ class CarrierScheduleNodeOutboxServiceTest {
|
|||||||
verify(mapper, never()).insert(org.mockito.ArgumentMatchers.any(InboundOutboxEntity.class));
|
verify(mapper, never()).insert(org.mockito.ArgumentMatchers.any(InboundOutboxEntity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void directManualActualFactDoesNotRequireTrackingQuery() throws Exception {
|
||||||
|
CarrierScheduleNodeFactEntity fact = fact();
|
||||||
|
fact.setProviderCode("MANUAL"); fact.setProviderEventId("manual-event");
|
||||||
|
fact.setSourceReference("MANUAL:7");
|
||||||
|
|
||||||
|
service.publishContainerNode(2088000000000000004L, 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("sourceContainerBookingId").asText())
|
||||||
|
.isEqualTo("2088000000000000003");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void initialOutboundDepartureUsesVersionZeroWithoutEnvelopeFailure() throws Exception {
|
void initialOutboundDepartureUsesVersionZeroWithoutEnvelopeFailure() throws Exception {
|
||||||
CarrierScheduleQueryEntity query = query();
|
CarrierScheduleQueryEntity query = query();
|
||||||
|
|||||||
Reference in New Issue
Block a user