feat: enforce canonical container identity across regions

This commit is contained in:
2026-08-31 12:13:20 +08:00
parent b386f35ab4
commit 942dbace19
78 changed files with 1203 additions and 730 deletions
@@ -106,7 +106,7 @@ class InboundUnloadCompletedOutboxRelayTest {
}
private EventEnvelope event() {
var payload = objectMapper.valueToTree(new OverseasContainerUnloadedV1("1001", "MSCU1234567",
var payload = objectMapper.valueToTree(new OverseasContainerUnloadedV1("1001", "MSCU6639870",
Instant.parse("2026-08-20T03:00:00Z"), Instant.parse("2026-08-20T02:30:00Z"), null));
return new EventEnvelope("00000000-0000-4000-8000-000000000009",
EventTypes.OVERSEAS_CONTAINER_UNLOADED, 1, Instant.parse("2026-08-20T03:00:01Z"),
@@ -45,7 +45,7 @@ class InboundUnloadCompletedOutboxServiceTest {
Instant photoUploadedAt = Instant.parse("2026-08-24T08:00:00Z");
Instant containerCompletedAt = Instant.parse("2026-08-24T09:30:00Z");
service.publishContainerCompleted("100", "booking-1", "MSCU1234567",
service.publishContainerCompleted("100", "booking-1", "MSCU6639870",
containerCompletedAt, photoUploadedAt, 7);
ArgumentCaptor<LastlegEventOutbox> captured = ArgumentCaptor.forClass(LastlegEventOutbox.class);
@@ -64,7 +64,7 @@ class InboundUnloadCompletedOutboxServiceTest {
void legacySinglePlanEntryUsesTaskCompletionTime() throws Exception {
InboundPlan plan = new InboundPlan();
plan.setSourceOrderId(11L);
plan.setContainerNo("MSCU1234567");
plan.setContainerNo("MSCU6639870");
InboundPdaTask task = new InboundPdaTask();
task.setCustomerId("100");
task.setCompletedAt(LocalDateTime.parse("2026-08-24T09:30:00"));
@@ -87,11 +87,11 @@ class InboundUnloadCompletedOutboxServiceTest {
@Test
void repeatedContainerCompletionDoesNotPublishAnotherEvent() {
LastlegEventOutbox existing = existing("100", "booking-1", "MSCU1234567");
LastlegEventOutbox existing = existing("100", "booking-1", "MSCU6639870");
when(mapper.findByEventKey(EventTypes.OVERSEAS_CONTAINER_UNLOADED + ":booking-1"))
.thenReturn(existing);
service.publishContainerCompleted("100", "booking-1", "MSCU1234567",
service.publishContainerCompleted("100", "booking-1", "MSCU6639870",
Instant.parse("2026-08-24T10:00:00Z"), Instant.parse("2026-08-24T08:00:00Z"), 8);
verify(mapper, never()).insert(any(LastlegEventOutbox.class));
@@ -99,11 +99,11 @@ class InboundUnloadCompletedOutboxServiceTest {
@Test
void sameIdempotencyKeyCannotRepresentAnotherPhysicalContainer() {
LastlegEventOutbox existing = existing("100", "booking-1", "MSCU1234567");
LastlegEventOutbox existing = existing("100", "booking-1", "MSCU6639870");
when(mapper.findByEventKey(EventTypes.OVERSEAS_CONTAINER_UNLOADED + ":booking-1"))
.thenReturn(existing);
assertThatThrownBy(() -> service.publishContainerCompleted("100", "booking-1", "TGHU7654321",
assertThatThrownBy(() -> service.publishContainerCompleted("100", "booking-1", "ZCSU7881970",
Instant.parse("2026-08-24T10:00:00Z"), Instant.parse("2026-08-24T08:00:00Z"), 8))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("conflicts with another container");