diff --git a/firstleg/src/main/java/com/baiyue/firstleg/mapper/SmartLoadingCandidateMapper.java b/firstleg/src/main/java/com/baiyue/firstleg/mapper/SmartLoadingCandidateMapper.java index 2896f01d6..87053d277 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/mapper/SmartLoadingCandidateMapper.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/mapper/SmartLoadingCandidateMapper.java @@ -359,6 +359,21 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba Candidate candidate(@Param("planId") long planId,@Param("warehouseId") long warehouseId, @Param("inboundId") long inboundId,@Param("detailId") long detailId); + @Select(""" + SELECT SUM(i.package_count) + FROM fl_inbound_measurement m + JOIN fl_inbound_measurement_item i + ON i.tenant_id=m.tenant_id AND i.measurement_id=m.id + WHERE m.tenant_id=#{accountId} AND m.inbound_id=#{inboundId} AND m.status='APPROVED' + AND m.id=(SELECT MAX(m2.id) FROM fl_inbound_measurement m2 + WHERE m2.tenant_id=m.tenant_id AND m2.inbound_id=m.inbound_id + AND m2.status='APPROVED') + AND i.inbound_detail_id=#{detailId} AND i.package_count>0 + """) + Integer measuredPackageCount(@Param("accountId") long accountId, + @Param("inboundId") long inboundId, + @Param("detailId") long detailId); + @lombok.Getter @lombok.Setter class ChannelContainerCountRow { private String channelCode; private Long availableContainerCount; diff --git a/firstleg/src/main/java/com/baiyue/firstleg/repository/SmartLoadingRepository.java b/firstleg/src/main/java/com/baiyue/firstleg/repository/SmartLoadingRepository.java index 84e1167c4..8b8812efa 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/repository/SmartLoadingRepository.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/repository/SmartLoadingRepository.java @@ -65,6 +65,9 @@ public class SmartLoadingRepository { public Candidate candidate(long planId, long warehouseId, long inboundId, long detailId) { return candidates.candidate(planId, warehouseId, inboundId, detailId); } + public Integer measuredPackageCount(long accountId, long inboundId, long detailId) { + return candidates.measuredPackageCount(accountId, inboundId, detailId); + } public InboundOrderEntity inbound(long accountId, long inboundId) { return inbounds.selectOne(new LambdaQueryWrapper() .eq(InboundOrderEntity::getTenantId, accountId) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java index 3419e04ef..443e56184 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java @@ -1429,7 +1429,7 @@ public class SmartLoadingService { int picked = task.pickedByPlanItem().getOrDefault(item.getId(), 0); item.setPickedPackageCount(picked); item.setMinPackageCount(Math.max(1, picked)); - int total = adjustmentTotal(p.getId(), b.getWarehouseId(), item); + int total = adjustmentTotal(item); item.setTotalPackageCount(total); item.setRemainingPackageCount(Math.max(0, total - item.getPackageCount())); item.setCanAdjust(mutable); @@ -1441,18 +1441,21 @@ public class SmartLoadingService { b.getContainerNo(),b.getVoyageNo(),p.getVersion(),mutable,mutable,blockedReason,finalStatus, task.taskId(),task.taskStatus(),task.taskVersion(),planCoLoadGroups(p.getId()),items); } - private int adjustmentTotal(long planId, long warehouseId, LoadingPlanItemEntity item) { + private int adjustmentTotal(LoadingPlanItemEntity item) { int current = item.getPackageCount() == null ? 0 : item.getPackageCount(); - Candidate measured = repository.candidate(planId, warehouseId, item.getInboundId(), item.getInboundDetailId()); - if (measured != null) { - return current + Math.max(0, measured.availablePackageCount() == null - ? 0 : measured.availablePackageCount()); - } - InboundOrderEntity inbound = repository.inbound(item.getAccountId(), item.getInboundId()); - if (inbound == null || !Set.of("PREPARING", "WAIT_MEASURE", "MEASURING", "MEASURE_PENDING", - "MEASURE_REJECTED", "WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING") - .contains(inbound.getProcessStatus())) return current; try { + if (item.getAccountId() == null || item.getInboundId() == null + || item.getInboundDetailId() == null) return current; + InboundOrderEntity inbound = repository.inbound(item.getAccountId(), item.getInboundId()); + if (inbound == null) return current; + if (Set.of("WAIT_SPLIT", "LOADING").contains(inbound.getProcessStatus())) { + Integer measured = repository.measuredPackageCount(item.getAccountId(), item.getInboundId(), + item.getInboundDetailId()); + return Math.max(current, measured == null ? 0 : measured); + } + if (!Set.of("PREPARING", "WAIT_MEASURE", "MEASURING", "MEASURE_PENDING", + "MEASURE_REJECTED", "WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING") + .contains(inbound.getProcessStatus()) || item.getOrderId() == null) return current; OrderCargoClient.CargoBinding cargo = loadCargo(item.getAccountId(), item.getOrderId(), item.getInboundDetailId()); return Math.max(current, cargo.originalPackageCount() == null ? 0 : cargo.originalPackageCount()); } catch (RuntimeException ignored) { diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java index 3473c5b34..83f057ead 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java @@ -23,6 +23,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.dao.DataAccessResourceFailureException; import java.math.BigDecimal; import java.util.List; @@ -107,6 +108,40 @@ class SmartLoadingProvisionalAdjustmentTest { }); } + @Test + void planReadFallsBackToAssignedCountWhenQuantityEnrichmentFails() { + LoadingPlanEntity plan = plan(103); + when(repository.planByBooking(99L)).thenReturn(plan); + when(repository.booking(99L)).thenReturn(booking()); + when(repository.items(1L)).thenReturn(List.of(item)); + when(repository.inbound(9L, 10L)) + .thenThrow(new DataAccessResourceFailureException("read query failed")); + + Plan result = service.draftByBooking(99L); + + assertThat(result.items()).singleElement().satisfies(updated -> { + assertThat(updated.getTotalPackageCount()).isEqualTo(20); + assertThat(updated.getRemainingPackageCount()).isZero(); + }); + } + + @Test + void planReadUsesApprovedMeasurementWithoutCallingTheLockedAdjustmentQuery() { + inbound.setProcessStatus("WAIT_SPLIT"); + when(repository.planByBooking(99L)).thenReturn(plan(103)); + when(repository.booking(99L)).thenReturn(booking()); + when(repository.items(1L)).thenReturn(List.of(item)); + when(repository.inbound(9L, 10L)).thenReturn(inbound); + when(repository.measuredPackageCount(9L, 10L, 20L)).thenReturn(100); + + Plan result = service.draftByBooking(99L); + + assertThat(result.items()).singleElement().satisfies(updated -> { + assertThat(updated.getTotalPackageCount()).isEqualTo(100); + assertThat(updated.getRemainingPackageCount()).isEqualTo(80); + }); + } + private static LoadingPlanEntity plan(int version) { LoadingPlanEntity value = new LoadingPlanEntity(); value.setId(1L);