diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java index a888e52b7..75edd385a 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java @@ -125,7 +125,8 @@ public final class LoadingPickDtos { Long operatorId, String operatorName, LocalDateTime createdAt) { } - public record Task(Long id, Long loadingPlanId, Long containerBookingId, String cabinetNo, + public record Task(Long id, Long loadingPlanId, Long containerBookingId, Long inboundId, + Integer inboundVersion, Integer loadingVersion, String cabinetNo, String currentContainerNo, String taskStatus, String workflowStatus, Integer version, Assignment assignment, Review review, List items) { diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java index 113d16681..75818b687 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java @@ -578,7 +578,16 @@ public class LoadingPickService { : assigned == null ? "UNASSIGNED" : repository.allTaskItemsResolved(task.getId()) ? "AWAITING_REVIEW" : "IN_PROGRESS"; var booking = smartLoadingRepository.booking(task.getContainerBookingId()); - return new Task(task.getId(), task.getLoadingPlanId(), task.getContainerBookingId(), task.getCabinetNo(), + var owners = repository.inboundOwners(task.getId()); + Long detailInboundId = source.isEmpty() ? null : source.get(0).getInboundId(); + var owner = detailInboundId == null ? null : owners.stream() + .filter(value -> detailInboundId.equals(value.inboundId())).findFirst().orElse(null); + var inbound = owner == null || owner.tenantId() == null || owner.inboundId() == null + ? null : repository.inbound(owner.tenantId(), owner.inboundId()); + var plan = smartLoadingRepository.plan(task.getLoadingPlanId()); + return new Task(task.getId(), task.getLoadingPlanId(), task.getContainerBookingId(), + owner == null ? null : owner.inboundId(), inbound == null ? null : inbound.version(), + plan == null ? null : plan.getVersion(), task.getCabinetNo(), booking == null ? null : booking.getContainerNo(), task.getTaskStatus(), workflowStatus, task.getVersion(), assignment, review, items); } diff --git a/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml b/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml index 3a7ddcd3f..cbbc5361e 100644 --- a/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml +++ b/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml @@ -124,11 +124,14 @@ components: schemas: Task: type: object - required: [id, loadingPlanId, containerBookingId, cabinetNo, taskStatus, workflowStatus, version, items] + required: [id, loadingPlanId, containerBookingId, inboundId, inboundVersion, loadingVersion, cabinetNo, taskStatus, workflowStatus, version, items] properties: id: {type: integer, format: int64} loadingPlanId: {type: integer, format: int64} containerBookingId: {type: integer, format: int64} + inboundId: {type: integer, format: int64, description: Stable inbound identity selected from the task item; evidence identity is taskId+inboundId+loadingPlanId+containerBookingId} + inboundVersion: {type: integer, minimum: 0, description: Current fl_inbound_order.version for inboundId; never inferred from PDA task version} + loadingVersion: {type: integer, minimum: 0, description: Current fl_loading_plan.version for loadingPlanId; used as the loading/evidence concurrency snapshot} cabinetNo: {type: string} currentContainerNo: {type: string, nullable: true, description: Mutable transport display field; changing it never resynchronizes the task or item versions and it is never task identity} taskStatus: {type: string, enum: [LOADING, COMPLETED]} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java index ff275fe86..36b97fa8c 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java @@ -33,6 +33,9 @@ class PdaConvergenceOpenApiContractTest { .contains("advances every associated inbound from WAIT_SPLIT to LOADING with optimistic locking") .contains("workflowStatus may later become AWAITING_REVIEW") .contains("without using containerNo as an association key") + .contains("evidence identity is taskId+inboundId+loadingPlanId+containerBookingId") + .contains("Current fl_inbound_order.version for inboundId") + .contains("Current fl_loading_plan.version for loadingPlanId") .contains("CompleteLoadingRequest"); String taskLookup = yaml.substring( diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java index cdb85a3fe..54e07def4 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java @@ -229,6 +229,32 @@ class LoadingPickServiceTest { verify(inboundHistories, never()).insert(any(InboundStatusHistoryEntity.class)); } + @Test + void taskDetailReturnsServerInboundAndLoadingVersions() { + LoadingPickTaskEntity task = task(); + when(repository.task(20L)).thenReturn(task); + when(repository.items(20L, 101L)).thenReturn(List.of(item())); + when(repository.cartonLabels(20L)).thenReturn(List.of()); + when(repository.assignment(20L)).thenReturn(null); + when(repository.review(20L)).thenReturn(null); + when(repository.allTaskItemsResolved(20L)).thenReturn(false); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(101L, 50L))); + when(repository.inbound(101L, 50L)).thenReturn( + new LoadingInboundMapper.Snapshot(50L, 101L, "LOADING", 7)); + var plan = new com.baiyue.firstleg.entity.LoadingPlanEntity(); + plan.setId(10L); plan.setVersion(11); + when(smartLoadingRepository.plan(10L)).thenReturn(plan); + + var result = service.task(20L, 101L); + + assertThat(result.inboundId()).isEqualTo(50L); + assertThat(result.inboundVersion()).isEqualTo(7); + assertThat(result.loadingVersion()).isEqualTo(11); + assertThat(result.loadingPlanId()).isEqualTo(10L); + assertThat(result.containerBookingId()).isEqualTo(99L); + } + @Test void claimStartsLoadingAndSameOperatorReentryDoesNotDuplicateStartHistory() { LoadingPickTaskEntity task = task();