优化
This commit is contained in:
+36
@@ -0,0 +1,36 @@
|
||||
package com.baiyue.firstleg.loading.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class LoadingFulfillmentCompletionMapperContractTest {
|
||||
@Test
|
||||
void completesLoadedSliceAndAggregatesRootOnlyAfterAllSlicesAreTerminal() throws Exception {
|
||||
String target = String.join(" ", LoadingInboundMapper.class
|
||||
.getMethod("completionTarget", long.class, long.class)
|
||||
.getAnnotation(Select.class).value()).replaceAll("\\s+", " ");
|
||||
String completeChild = String.join(" ", LoadingInboundMapper.class
|
||||
.getMethod("completeLoadedChild", long.class, long.class, long.class, int.class)
|
||||
.getAnnotation(Update.class).value()).replaceAll("\\s+", " ");
|
||||
String aggregateRoot = String.join(" ", LoadingInboundMapper.class
|
||||
.getMethod("aggregateRootLoaded", long.class, long.class, long.class)
|
||||
.getAnnotation(Update.class).value()).replaceAll("\\s+", " ");
|
||||
|
||||
assertThat(target)
|
||||
.contains("batch.source_inbound_id=#{inboundId}")
|
||||
.contains("batch.loaded_child_inbound_id=#{inboundId}")
|
||||
.contains("batch.status='APPLIED'");
|
||||
assertThat(completeChild)
|
||||
.contains("batch.loaded_child_inbound_id=child.id")
|
||||
.contains("child.process_status='LOADED'")
|
||||
.contains("source.version=#{expectedSourceVersion}");
|
||||
assertThat(aggregateRoot)
|
||||
.contains("remainder.split_purpose='REMAINDER'")
|
||||
.contains("remainder.split_status='NOT_SPLIT'")
|
||||
.contains("loaded.split_purpose='LOADED'")
|
||||
.contains("loaded.process_status<>'LOADED'");
|
||||
}
|
||||
}
|
||||
+39
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.loading.dto.LoadingRequests.VoidEvidenceRequest;
|
||||
import com.baiyue.firstleg.loading.dto.LoadingResponses.LoadingActionResponse;
|
||||
import com.baiyue.firstleg.loading.entity.LoadingEvidenceEntity;
|
||||
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper.Snapshot;
|
||||
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper.CompletionTarget;
|
||||
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
|
||||
import com.baiyue.firstleg.mapper.LoadingPickItemMapper;
|
||||
import com.baiyue.firstleg.repository.LoadingPickRepository;
|
||||
@@ -79,6 +80,44 @@ class LoadingDeliveryServiceTest {
|
||||
verify(histories).insert(any(InboundStatusHistoryEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void completesLoadedFulfillmentSliceBeforeAggregatingRoot() {
|
||||
when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
|
||||
when(repository.findInbound(10, 20)).thenReturn(new Snapshot(20L, 10L, "INBOUNDED", 3));
|
||||
when(repository.completionTarget(10, 20)).thenReturn(new CompletionTarget(
|
||||
20L, 21L, 20L, "INBOUNDED", 3, "LOADING", 1));
|
||||
LoadingPickItemMapper.InboundProgress progress = mock(LoadingPickItemMapper.InboundProgress.class);
|
||||
when(progress.getExpectedCount()).thenReturn(5);
|
||||
when(progress.getPickedCount()).thenReturn(5);
|
||||
when(progress.getTaskCount()).thenReturn(1);
|
||||
when(progress.getCompletedTaskCount()).thenReturn(1);
|
||||
when(progress.getUnresolvedCount()).thenReturn(0);
|
||||
when(loadingPicks.inboundProgress(10, 20)).thenReturn(progress);
|
||||
when(repository.listEvidence(10, 20)).thenReturn(List.of(
|
||||
evidence("PHOTO_STEP_1", 1L, null), evidence("PHOTO_STEP_2", 2L, null),
|
||||
evidence("PHOTO_STEP_3", 3L, null), evidence("PHOTO_STEP_4", 4L, null),
|
||||
evidence("SEAL", 5L, "LOCK-001")));
|
||||
when(files.validate(eq("token"), eq(10L), eq(20L), anyLong())).thenAnswer(invocation -> {
|
||||
long fileId = invocation.getArgument(3);
|
||||
String type = fileId == 5L ? "SEAL" : "PHOTO_STEP_" + fileId;
|
||||
return ApiResponse.success(new LoadingEvidenceFileClient.FileMetadata(
|
||||
fileId, type.toLowerCase() + ".png", "LOADING_" + type, "image/png"));
|
||||
});
|
||||
when(repository.completeLoadedChild(10, 20, 7, 3)).thenReturn(1);
|
||||
|
||||
LoadingActionResponse result = service.completeLoading(10, 20, 7, "admin", "slice-1",
|
||||
new CompleteLoadingRequest(3, null));
|
||||
|
||||
assertThat(result.mainStatus()).isEqualTo("LOADED");
|
||||
verify(loadingModelBridge).requireCompleted(10, 20);
|
||||
verify(completionGate).requireBookingTransportAndCustoms(10, 20);
|
||||
verify(repository).completeLoadedChild(10, 20, 7, 3);
|
||||
verify(repository).aggregateRootLoaded(10, 20, 7);
|
||||
verify(histories).insert(argThat((InboundStatusHistoryEntity history) ->
|
||||
Long.valueOf(21L).equals(history.getInboundId())));
|
||||
verify(repository, never()).completeLoading(anyLong(), anyLong(), anyLong(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsCompletionWhenEvidenceIsIncomplete() {
|
||||
when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
|
||||
|
||||
+15
-2
@@ -62,7 +62,7 @@ class InboundParentChildSqlContractTest {
|
||||
.contains("NEW.remaining_package_count")
|
||||
.contains("NEW.loaded_package_count + NEW.remaining_package_count <> NEW.package_count")
|
||||
.contains("source_batch.inbound_id = COALESCE(batch.source_inbound_id, batch.parent_inbound_id)")
|
||||
.contains("拆分批次来源必须是根主单或其余量子单")
|
||||
.contains("拆分批次来源必须是箱数匹配且未消费的根主单或余量子单")
|
||||
.contains("SUM(split_item.package_count) > source_item.package_count")
|
||||
.contains("子单承接箱数超过来源测量箱规箱数")
|
||||
.contains("child_order.package_count >= NEW.package_count")
|
||||
@@ -90,7 +90,8 @@ class InboundParentChildSqlContractTest {
|
||||
.contains("'fl_inbound_measurement', 'source_measurement_id'")
|
||||
.contains("'fl_inbound_measurement_item', 'split_item_id'")
|
||||
.contains("'fl_inbound_measurement_item', 'source_measurement_item_id'")
|
||||
.contains("source_measurement_id BIGINT UNSIGNED NULL")
|
||||
.contains("source_measurement_id BIGINT UNSIGNED NOT NULL")
|
||||
.contains("source_measurement_item_id BIGINT UNSIGNED NOT NULL")
|
||||
.contains("fk_inbound_split_item_measurement")
|
||||
.contains("fk_measure_split_batch")
|
||||
.contains("fk_measure_source_batch")
|
||||
@@ -100,6 +101,18 @@ class InboundParentChildSqlContractTest {
|
||||
.contains("idx_measure_item_split_source");
|
||||
}
|
||||
|
||||
@Test
|
||||
void finalAssertionIsTableSpecificAndRejectsLegacyIndexes() {
|
||||
assertThat(sql)
|
||||
.contains("table_name = 'fl_inbound_split_batch'")
|
||||
.contains("uk_inbound_split_source_once")
|
||||
.contains("table_name = 'fl_inbound_split_item'")
|
||||
.contains("uk_inbound_split_batch_source_child")
|
||||
.contains("is_nullable = 'NO'")
|
||||
.contains("'uk_inbound_one_secondary', 'uk_inbound_parent_sequence'")
|
||||
.contains("'uk_inbound_split_batch_source_item'");
|
||||
}
|
||||
|
||||
private static String loadSql() {
|
||||
try {
|
||||
return new ClassPathResource("db/phase3-inbound-parent-child-schema.sql")
|
||||
|
||||
+6
@@ -66,5 +66,11 @@ class PdaSplitSettlementSqlContractTest {
|
||||
.contains("container_booking_id")
|
||||
.contains("#{loadingPlanId}")
|
||||
.contains("#{containerBookingId}");
|
||||
|
||||
String clone = InboundSplitSettlementMapper.class.getMethod("cloneChildWithPurpose",
|
||||
long.class, long.class, long.class, long.class, String.class, int.class,
|
||||
int.class, String.class, long.class, String.class)
|
||||
.getAnnotation(Insert.class).value()[0];
|
||||
assertThat(clone).contains("CASE WHEN #{splitPurpose}='LOADED' THEN 'LOADING' ELSE 'INBOUNDED' END");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user