diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java index 752ad35c4..19ea22ea6 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java @@ -174,9 +174,14 @@ public class MeasurementLocationOccupationService { return order.getActualVolumeCbm(); } var measurement = measurements.findLatestMeasurement(tenantId, inboundId); - if (measurement != null && measurement.getOriginalVolumeCbm() != null - && measurement.getOriginalVolumeCbm().signum() > 0) { - return measurement.getOriginalVolumeCbm(); + if (measurement != null) { + BigDecimal measuredVolume = positive(measurement.getTotalVolumeCbm()); + BigDecimal declaredVolume = positive(measurement.getOriginalVolumeCbm()); + if (measuredVolume != null || declaredVolume != null) { + if (measuredVolume == null) return declaredVolume; + if (declaredVolume == null) return measuredVolume; + return measuredVolume.max(declaredVolume); + } } if (order.getOrderId() == null || order.getOrderId() <= 0) { throw new BizException(ResultCode.CONFLICT, "入库单缺少有效实测或客户申报体积"); @@ -200,6 +205,10 @@ public class MeasurementLocationOccupationService { throw new BizException(ResultCode.CONFLICT, "入库单缺少有效实测或客户申报体积"); } + private static BigDecimal positive(BigDecimal value) { + return value != null && value.signum() > 0 ? value : null; + } + private static int requirePackageCount(InboundOrderEntity order) { if (order.getTotalPackageCount() == null || order.getTotalPackageCount() <= 0) { throw new BizException(ResultCode.CONFLICT, "入库单缺少有效总箱数"); diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/MeasurementLocationOccupationServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/MeasurementLocationOccupationServiceTest.java index 98b45698b..7e14d9d89 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/MeasurementLocationOccupationServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/MeasurementLocationOccupationServiceTest.java @@ -144,6 +144,7 @@ class MeasurementLocationOccupationServiceTest { InboundOrderEntity inbound = inbound(); inbound.setActualVolumeCbm(null); InboundMeasurementEntity measurement = new InboundMeasurementEntity(); + measurement.setTotalVolumeCbm(new BigDecimal("1.0000")); measurement.setOriginalVolumeCbm(new BigDecimal("2.5000")); when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound); when(measurements.findLatestMeasurement(BUSINESS_TENANT, INBOUND)).thenReturn(measurement); @@ -162,6 +163,32 @@ class MeasurementLocationOccupationServiceTest { 20, new BigDecimal("2.5000"), block("OCCUPIED", 3)); } + @Test + void reservesByCurrentMeasuredVolumeBeforeFrozenDeclaredVolume() { + InboundOrderEntity inbound = inbound(); + inbound.setActualVolumeCbm(null); + InboundMeasurementEntity measurement = new InboundMeasurementEntity(); + measurement.setTotalVolumeCbm(new BigDecimal("2.5000")); + measurement.setOriginalVolumeCbm(new BigDecimal("1.0000")); + when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound); + when(measurements.findLatestMeasurement(BUSINESS_TENANT, INBOUND)).thenReturn(measurement); + when(measurements.listWeights(BUSINESS_TENANT, INBOUND)) + .thenReturn(confirmedWeights().subList(0, 1)); + when(warehouse.reserveBlock(org.mockito.ArgumentMatchers.eq("internal-token"), + org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(block("RESERVED", 3))); + when(warehouse.confirmBlock(org.mockito.ArgumentMatchers.eq("internal-token"), + org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(block("OCCUPIED", 3))); + + service.ensureForConfirmedWeight(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3); + + verify(orderCargo, never()).measurementDeclaration(org.mockito.ArgumentMatchers.anyString(), + org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong()); + verify(warehouse).reserveBlock(org.mockito.ArgumentMatchers.eq("internal-token"), + org.mockito.ArgumentMatchers.argThat(request -> request.requiredSlotCount() == 3)); + verify(allocations).replaceBlock(BUSINESS_TENANT, INBOUND, WAREHOUSE, + 20, new BigDecimal("2.5000"), block("OCCUPIED", 3)); + } + @Test void fallsBackToLatestOrderDeclarationWhenNoMeasurementBatchExists() { InboundOrderEntity inbound = inbound();