feat(firstleg): converge phase3 loading models and pda

This commit is contained in:
2026-08-09 11:21:38 +08:00
parent 9b88fb4b9e
commit ed5b9fe77f
46 changed files with 2028 additions and 96 deletions
@@ -0,0 +1,27 @@
package com.baiyue.firstleg.controller;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class PdaConvergenceOpenApiContractTest {
@Test
void publishesClaimAssignWorkAndReviewRoutes() throws Exception {
String yaml = new ClassPathResource("openapi/phase3-pda-convergence-v1.yaml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(yaml)
.contains("/api/platform/v1/first-leg/pda-loading/tasks:")
.contains("/tasks/{taskId}/claim:")
.contains("/tasks/{taskId}/assign:")
.contains("/tasks/{taskId}/items/{itemId}/pick:")
.contains("/tasks/{taskId}/items/{itemId}/partial:")
.contains("/tasks/{taskId}/items/{itemId}/skip:")
.contains("/tasks/{taskId}/review:")
.contains("/tasks/{taskId}/operations:")
.contains("expectedAssignmentVersion")
.contains("expectedTaskVersion");
}
}
@@ -0,0 +1,30 @@
package com.baiyue.firstleg.controller;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.firstleg.dto.LoadingPickDtos.*;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
import java.lang.reflect.Method;
import static org.assertj.core.api.Assertions.assertThat;
class PlatformLoadingPdaControllerContractTest {
@Test
void exposesAssignmentWorkAndReviewWithDedicatedAuthorities() throws Exception {
authority("task", "platform:firstleg:pda:view", AuthenticatedUser.class, String.class, long.class);
authority("claim", "platform:firstleg:pda:work", AuthenticatedUser.class, long.class, ClaimRequest.class);
authority("assign", "platform:firstleg:pda:assign", AuthenticatedUser.class, long.class, AssignRequest.class);
authority("pick", "platform:firstleg:pda:work", AuthenticatedUser.class, long.class, long.class, PickRequest.class);
authority("partial", "platform:firstleg:pda:work", AuthenticatedUser.class, long.class, long.class, PartialPickRequest.class);
authority("skip", "platform:firstleg:pda:work", AuthenticatedUser.class, long.class, long.class, SkipRequest.class);
authority("review", "platform:firstleg:pda:review", AuthenticatedUser.class, long.class, ReviewRequest.class);
authority("operations", "platform:firstleg:pda:view", AuthenticatedUser.class, long.class);
}
private void authority(String name, String expected, Class<?>... parameterTypes) throws Exception {
Method method = PlatformLoadingPdaController.class.getDeclaredMethod(name, parameterTypes);
assertThat(method.getAnnotation(PreAuthorize.class).value())
.isEqualTo("hasAuthority('" + expected + "')");
}
}
@@ -0,0 +1,35 @@
package com.baiyue.firstleg.loading.bridge;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class LoadingModelBridgeContractTest {
@Test
void moduleSqlUsesExplicitManyToManyLinksAndRepeatableBackfill() throws Exception {
String sql = new ClassPathResource("db/phase3-loading-model-bridge-schema.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql)
.contains("CREATE TABLE IF NOT EXISTS fl_preload_loading_plan_link")
.contains("UNIQUE KEY uk_preload_loading_pair (tenant_id, inbound_id, loading_plan_id)")
.contains("FOREIGN KEY (preload_plan_id) REFERENCES fl_preload_plan (id)")
.contains("FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id)")
.contains("INSERT IGNORE INTO fl_preload_loading_plan_link")
.doesNotContain("ALTER TABLE fl_preload_plan ADD COLUMN loading_plan_id");
}
@Test
void openApiDocumentsAtomicBindAndBothDirections() throws Exception {
String yaml = new ClassPathResource("openapi/phase3-loading-model-bridge-v1.yaml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(yaml)
.contains("/api/platform/v1/inbounds/{inboundId}/preload/loading-plans:")
.contains("/api/platform/v1/inbounds/{inboundId}/preload/loading-plans/{loadingPlanId}:")
.contains("/api/platform/v1/first-leg/smart-loading/plans/{loadingPlanId}/preloads:")
.contains("required: [expectedPreloadVersion, expectedLoadingPlanVersion]")
.contains("either conflict rolls back the whole link operation");
}
}
@@ -0,0 +1,74 @@
package com.baiyue.firstleg.loading.bridge.service;
import com.baiyue.firstleg.loading.bridge.dto.LoadingModelBridgeDtos.BindRequest;
import com.baiyue.firstleg.loading.bridge.dto.LoadingModelBridgeDtos.Link;
import com.baiyue.firstleg.loading.bridge.mapper.LoadingModelBridgeMapper.LoadingPlanSnapshot;
import com.baiyue.firstleg.loading.bridge.mapper.LoadingModelBridgeMapper.PreloadSnapshot;
import com.baiyue.firstleg.loading.bridge.repository.LoadingModelBridgeRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class LoadingModelBridgeServiceTest {
@Mock LoadingModelBridgeRepository repository;
@InjectMocks LoadingModelBridgeService service;
@Test
void bindsManyToManyModelsWithBothOptimisticLocks() {
when(repository.preload(10, 20)).thenReturn(new PreloadSnapshot(30L, 10L, 20L, "PENDING", 2));
when(repository.loadingPlan(40)).thenReturn(new LoadingPlanSnapshot(40L, 50L, "C1", "EDITING", 3));
when(repository.allocatedPackages(10, 20, 40)).thenReturn(8);
when(repository.touchPreload(30, 10, 20, 2, 7, "admin")).thenReturn(1);
when(repository.touchLoadingPlan(40, 3, 7, "admin")).thenReturn(1);
Link linked = link("PENDING", 3, "EDITING", 4, 8);
when(repository.byInbound(10, 20)).thenReturn(List.of(linked));
Link result = service.bind(10, 20, 40, 7, "admin", "bridge-1", new BindRequest(2, 3));
assertThat(result.loadingPlanId()).isEqualTo(40);
verify(repository).insert(any());
verify(repository).touchPreload(30, 10, 20, 2, 7, "admin");
verify(repository).touchLoadingPlan(40, 3, 7, "admin");
}
@Test
void secondVersionConflictDoesNotProceedAsSuccess() {
when(repository.preload(10, 20)).thenReturn(new PreloadSnapshot(30L, 10L, 20L, "PENDING", 2));
when(repository.loadingPlan(40)).thenReturn(new LoadingPlanSnapshot(40L, 50L, "C1", "EDITING", 3));
when(repository.allocatedPackages(10, 20, 40)).thenReturn(8);
when(repository.touchPreload(30, 10, 20, 2, 7, "admin")).thenReturn(1);
when(repository.touchLoadingPlan(40, 3, 7, "admin")).thenReturn(0);
assertThatThrownBy(() -> service.bind(10, 20, 40, 7, "admin", "bridge-2", new BindRequest(2, 3)))
.hasMessageContaining("刷新后重试");
verify(repository, never()).byInbound(10, 20);
}
@Test
void terminalGateRequiresEveryLinkedContainerPlanCompleted() {
when(repository.byInbound(10, 20)).thenReturn(List.of(
link("CONFIRMED", 4, "COMPLETED", 7, 5),
new Link(2L, 10L, 20L, 30L, "CONFIRMED", 4, 41L, 51L, "C2",
"LOADING", 6, 3, LocalDateTime.now())));
assertThatThrownBy(() -> service.requireCompleted(10, 20))
.hasMessageContaining("尚未全部完成装柜");
}
private static Link link(String preloadStatus, int preloadVersion, String loadingStatus,
int loadingVersion, int packages) {
return new Link(1L, 10L, 20L, 30L, preloadStatus, preloadVersion, 40L, 50L, "C1",
loadingStatus, loadingVersion, packages, LocalDateTime.now());
}
}
@@ -21,6 +21,8 @@ class LoadingDeliveryOpenApiContractTest {
.contains("required: [expectedVersion, evidenceType, fileId]")
.contains("enum: [PHOTO_STEP_1, PHOTO_STEP_2, PHOTO_STEP_3, PHOTO_STEP_4, SEAL]")
.contains("Required when evidenceType is SEAL")
.contains("Complete a started PDA picking task");
.contains("compatibility projection")
.contains("must exactly match the server-derived container-task aggregate")
.contains("cannot complete canonical picking");
}
}
@@ -0,0 +1,54 @@
package com.baiyue.firstleg.loading.repository;
import com.baiyue.firstleg.mapper.LoadingPickItemMapper;
import com.baiyue.firstleg.loading.mapper.InboundLoadingPickTaskMapper;
import org.junit.jupiter.api.Test;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class PdaConvergenceSqlContractTest {
@Test
void hasIndependentAssignmentReviewOperationAuditAndPermissionGrants() throws Exception {
String sql = new ClassPathResource("db/phase3-pda-convergence-schema.sql")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(sql)
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_assignment")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_review")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_operation")
.contains("UNIQUE KEY uk_loading_pick_operation_id")
.contains("trg_loading_pick_review_before_update")
.contains("trg_loading_pick_operation_before_delete")
.contains("5102190, 0, 'PLATFORM'")
.contains("5102193, 0, 'PLATFORM'")
.contains("role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR')")
.contains("platform:firstleg:pda:view")
.contains("platform:firstleg:pda:assign")
.contains("platform:firstleg:pda:work")
.contains("platform:firstleg:pda:review");
}
@Test
void derivesInboundProjectionFromCanonicalContainerItems() throws Exception {
String aggregate = String.join(" ", LoadingPickItemMapper.class
.getDeclaredMethod("selectInboundProgress", long.class, long.class)
.getAnnotation(Select.class).value());
String upsert = InboundLoadingPickTaskMapper.class.getDeclaredMethod("upsertProjection",
long.class, long.class, long.class, String.class, int.class, int.class, long.class, String.class)
.getAnnotation(Insert.class).value()[0];
assertThat(aggregate)
.contains("fl_loading_plan_item")
.contains("fl_loading_pick_item")
.contains("fl_loading_pick_task")
.contains("plan_item.account_id=#{tenantId}")
.contains("pick_task.task_status='COMPLETED'");
assertThat(upsert)
.contains("INSERT INTO fl_inbound_loading_pick_task")
.contains("ON DUPLICATE KEY UPDATE")
.contains("柜次PDA自动汇总");
}
}
@@ -8,8 +8,10 @@ import com.baiyue.firstleg.loading.dto.LoadingRequests.PickingRequest;
import com.baiyue.firstleg.loading.dto.LoadingRequests.UpsertEvidenceRequest;
import com.baiyue.firstleg.loading.dto.LoadingResponses.LoadingActionResponse;
import com.baiyue.firstleg.loading.entity.LoadingEvidenceEntity;
import com.baiyue.firstleg.loading.entity.InboundLoadingPickTaskEntity;
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper.Snapshot;
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
import com.baiyue.firstleg.mapper.LoadingPickItemMapper;
import com.baiyue.firstleg.repository.LoadingPickRepository;
import com.baiyue.firstleg.loading.repository.LoadingRepository;
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -30,6 +32,8 @@ import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class LoadingDeliveryServiceTest {
@Mock LoadingRepository repository;
@Mock LoadingModelBridgeService loadingModelBridge;
@Mock LoadingPickRepository loadingPicks;
@Mock InboundStatusHistoryMapper histories;
@Mock LoadingEvidenceFileClient files;
@InjectMocks LoadingDeliveryService service;
@@ -48,9 +52,13 @@ class LoadingDeliveryServiceTest {
void completesLoadingOnlyAfterPickingAndFiveEvidenceFiles() {
when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
when(repository.findInbound(10, 20)).thenReturn(new Snapshot(20L, 10L, "LOADING", 3));
InboundLoadingPickTaskEntity pick = new InboundLoadingPickTaskEntity();
pick.setStatus("COMPLETED"); pick.setExpectedCount(5); pick.setPickedCount(5);
when(repository.findPickTask(10, 20)).thenReturn(pick);
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),
@@ -64,6 +72,7 @@ class LoadingDeliveryServiceTest {
when(repository.completeLoading(10, 20, 7, 3)).thenReturn(1);
LoadingActionResponse result = service.completeLoading(10, 20, 7, "admin", "k1", new CompleteLoadingRequest(3, null));
assertThat(result.mainStatus()).isEqualTo("LOADED");
verify(loadingModelBridge).requireCompleted(10, 20);
verify(histories).insert(any(InboundStatusHistoryEntity.class));
}
@@ -71,9 +80,13 @@ class LoadingDeliveryServiceTest {
void rejectsCompletionWhenEvidenceIsIncomplete() {
when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
when(repository.findInbound(10, 20)).thenReturn(new Snapshot(20L, 10L, "LOADING", 3));
InboundLoadingPickTaskEntity pick = new InboundLoadingPickTaskEntity();
pick.setStatus("COMPLETED"); pick.setExpectedCount(5); pick.setPickedCount(5);
when(repository.findPickTask(10, 20)).thenReturn(pick);
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("SEAL", 5L, "LOCK-001")));
assertThatThrownBy(() -> service.completeLoading(10, 20, 7, "admin", "k-missing",
@@ -111,13 +124,12 @@ class LoadingDeliveryServiceTest {
}
@Test
void rejectsCompletingPickingBeforeTaskStarts() {
void rejectsCompletingPickingWithoutCanonicalContainerTask() {
when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
when(repository.findInbound(10, 20)).thenReturn(new Snapshot(20L, 10L, "LOADING", 3));
when(repository.findPickTask(10, 20)).thenReturn(null);
assertThatThrownBy(() -> service.completePicking(10, 20, 7, "admin", "k-picking",
new PickingRequest(0, 1, 1, null))).hasMessageContaining("尚未开始");
new PickingRequest(0, 1, 1, null))).hasMessageContaining("真实柜次");
verify(repository, never()).createPickTask(any());
}
@@ -23,10 +23,15 @@ class Phase3FinalUnifiedSqlContractTest {
.contains("CREATE TABLE IF NOT EXISTS fl_customs_receipt")
.contains("CREATE TABLE IF NOT EXISTS fl_port_schedule")
.contains("CREATE TABLE IF NOT EXISTS fl_port_schedule_history")
.contains("CREATE TABLE IF NOT EXISTS fl_preload_loading_plan_link")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_assignment")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_review")
.contains("CREATE TABLE IF NOT EXISTS fl_loading_pick_operation")
.contains("uk_loading_evidence_seal (tenant_id,seal_no)")
.contains("CALL assert_phase3_final_schema()")
.contains("trg_port_schedule_history_before_update")
.contains("trg_port_schedule_history_before_delete");
.contains("trg_port_schedule_history_before_delete")
.contains("trg_loading_pick_operation_before_delete");
}
@Test
@@ -36,10 +41,12 @@ class Phase3FinalUnifiedSqlContractTest {
for (int id = 5102160; id <= 5102164; id++) assertThat(sql).contains(Integer.toString(id));
for (int id = 5102170; id <= 5102175; id++) assertThat(sql).contains(Integer.toString(id));
for (int id = 5102180; id <= 5102183; id++) assertThat(sql).contains(Integer.toString(id));
for (int id = 5102190; id <= 5102193; id++) assertThat(sql).contains(Integer.toString(id));
assertThat(sql)
.contains("platform:firstleg:outbound-dispatch:%")
.contains("platform:firstleg:customs:%")
.contains("platform:firstleg:port-schedule:%")
.contains("platform:firstleg:pda:%")
.contains("role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR')")
.contains("角色授权未完整写入");
}
@@ -3,7 +3,10 @@ package com.baiyue.firstleg.service;
import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.PartialPickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest;
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity;
import com.baiyue.firstleg.entity.LoadingPickItemEntity;
import com.baiyue.firstleg.entity.LoadingPickTaskEntity;
import com.baiyue.firstleg.repository.LoadingPickRepository;
@@ -34,9 +37,12 @@ class LoadingPickServiceTest {
LoadingPickItemEntity item = item();
when(repository.history("pick-1")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.assignment(20L)).thenReturn(assignment());
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.pick(30L, 2, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(false);
when(repository.touchTask(20L, 0)).thenReturn(1);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
service.pick(20L, 30L, new PickRequest(101L, 2, List.of(), 0, "pick-1"), 9L, "operator");
@@ -50,14 +56,16 @@ class LoadingPickServiceTest {
LoadingPickItemEntity item = item();
when(repository.history("pick-2")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.assignment(20L)).thenReturn(assignment());
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.pick(30L, 2, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
when(repository.touchTask(20L, 0)).thenReturn(1);
service.pick(20L, 30L, new PickRequest(101L, 2, List.of(), 0, "pick-2"), 9L, "operator");
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
verify(repository).insert(any(LoadingPickHistoryEntity.class));
}
@@ -67,14 +75,16 @@ class LoadingPickServiceTest {
LoadingPickItemEntity item = item();
when(repository.history("partial-1")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.assignment(20L)).thenReturn(assignment());
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.partial(30L, 1, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
when(repository.touchTask(20L, 0)).thenReturn(1);
service.partial(20L, 30L, new PartialPickRequest(101L, 1, List.of(), 0, "partial-1"), 9L, "operator");
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
}
@Test
@@ -83,14 +93,37 @@ class LoadingPickServiceTest {
LoadingPickItemEntity item = item();
when(repository.history("skip-1")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.assignment(20L)).thenReturn(assignment());
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.skip(30L, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
when(repository.touchTask(20L, 0)).thenReturn(1);
service.skip(20L, 30L, new SkipRequest(101L, 0, "skip-1", "fixture unavailable"), 9L, "operator");
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
}
@Test
void reviewSettlesPartialItemsBeforeCompletingPlan() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity item = item();
item.setPlannedPackageCount(5);
item.setPickedPackageCount(3);
item.setItemStatus("PARTIAL");
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.task(20L)).thenReturn(task);
when(repository.items(20L)).thenReturn(List.of(item));
when(repository.settlePartial(40L, 30L, 3, 5, 9L, "operator")).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.approve(20L, 9L, "operator", "checked")).thenReturn(1);
service.review(20L, new ReviewRequest(0, "review-1", "checked"), 9L, "operator");
verify(repository).insert(any(LoadingPickOperationEntity.class));
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
verify(repository).syncInboundProjections(20L, 9L, "operator");
}
private static LoadingPickTaskEntity task() {
@@ -116,4 +149,13 @@ class LoadingPickServiceTest {
item.setVersion(0);
return item;
}
private static LoadingPickAssignmentEntity assignment() {
LoadingPickAssignmentEntity assignment = new LoadingPickAssignmentEntity();
assignment.setPickTaskId(20L);
assignment.setAssigneeId(9L);
assignment.setAssigneeName("operator");
assignment.setVersion(0);
return assignment;
}
}
@@ -1,6 +1,7 @@
package com.baiyue.firstleg.split.service;
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
import com.baiyue.firstleg.split.dto.SplitRequests.ConfirmPreloadRequest;
import com.baiyue.firstleg.split.dto.SplitRequests.PreloadItem;
import com.baiyue.firstleg.split.dto.SplitRequests.SmartSplitRequest;
@@ -30,6 +31,7 @@ import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class SplitPreloadServiceTest {
@Mock SplitRepository repository;
@Mock LoadingModelBridgeService loadingModelBridge;
@Mock InboundStatusHistoryMapper histories;
@InjectMocks SplitPreloadService service;
private final ObjectMapper objectMapper = new ObjectMapper();
@@ -61,11 +63,13 @@ class SplitPreloadServiceTest {
plan.setTenantId(10L); plan.setInboundId(20L); plan.setStatus("CONFIRMING"); plan.setVersion(1);
plan.setItemsJson("[]");
when(repository.findPlan(10, 20)).thenReturn(plan);
org.mockito.Mockito.doNothing().when(loadingModelBridge).requireStarted(10, 20);
when(repository.changePlanStatus(10, 20, "CONFIRMING", "CONFIRMED", 7, "admin", 1)).thenReturn(1);
when(repository.beginLoading(10, 20, 7, 4)).thenReturn(1);
SplitActionResponse result = service.confirmPreload(10, 20, 7, "admin", "k3",
new ConfirmPreloadRequest(1));
assertThat(result.mainStatus()).isEqualTo("LOADING");
verify(loadingModelBridge).requireStarted(10, 20);
verify(repository).beginLoading(10, 20, 7, 4);
}
}