diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/FbaPricingService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/FbaPricingService.java index 96c152a84..7be0be609 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/FbaPricingService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/FbaPricingService.java @@ -91,16 +91,25 @@ public class FbaPricingService { } } var measurement = measurementRepository.findLatestMeasurement(tenantId, inboundId); - if ("OUTER".equalsIgnoreCase(volumeSource) && measurement == null) { - throw conflict("外箱规测量批次不存在,不能生成对客费用"); + boolean actualMeasurementSource = "ACTUAL".equalsIgnoreCase(weightSource) + || "ACTUAL".equalsIgnoreCase(volumeSource); + boolean outerMeasurementSource = "OUTER".equalsIgnoreCase(weightSource) + || "OUTER".equalsIgnoreCase(volumeSource); + if ((actualMeasurementSource || outerMeasurementSource) && measurement == null) { + throw conflict(actualMeasurementSource + ? "实际测量数据不存在,不能生成对客费用" + : "外箱规测量批次不存在,不能生成对客费用"); } - if ("OUTER".equalsIgnoreCase(volumeSource)) { - var outerItems = measurementRepository.listItems(tenantId, measurement.getId()); - boolean incomplete = outerItems.isEmpty() || outerItems.stream().anyMatch(item -> + if (actualMeasurementSource || outerMeasurementSource) { + var measurementItems = measurementRepository.listItems(tenantId, measurement.getId()); + if (actualMeasurementSource && measurementItems.isEmpty()) { + throw conflict("实际测量明细不存在,不能生成对客费用"); + } + boolean incomplete = outerMeasurementSource && (measurementItems.isEmpty() || measurementItems.stream().anyMatch(item -> item.getOuterLengthCm() == null || item.getOuterLengthCm().signum() <= 0 || item.getOuterWidthCm() == null || item.getOuterWidthCm().signum() <= 0 || item.getOuterHeightCm() == null || item.getOuterHeightCm().signum() <= 0 - || !StringUtils.hasText(item.getCalculationRuleVersion())); + || !StringUtils.hasText(item.getCalculationRuleVersion()))); if (incomplete) throw conflict("外箱规数据或绑定的计算规则不完整,不能生成对客费用"); } ActivePriceBookEstimator.Estimate estimate = priceBookEstimator.estimate(new EstimateRequest( diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/FbaPricingServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/FbaPricingServiceTest.java index d46350cfe..992f7262e 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/FbaPricingServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/FbaPricingServiceTest.java @@ -133,6 +133,23 @@ class FbaPricingServiceTest { assertThat(fee.getValue().getActualVolumeCbm()).isEqualByComparingTo("1.0019"); } + @Test + @DisplayName("指定实际测量来源时必须存在测量批次和明细") + void requiresActualMeasurementDetailsForActualSource() { + readyRepository(); + InboundPricingEntity inbound = inbound("100.000", "0.7880"); + when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound); + + assertThatThrownBy(() -> service.calculate(TENANT, OPERATOR, INBOUND, NOW, + new BigDecimal("100.000"), new BigDecimal("0.7880"), + "ACTUAL", "ACTUAL", "calc-actual-missing")) + .isInstanceOf(BizException.class) + .hasMessageContaining("实际测量数据不存在"); + + verify(priceBookEstimator, never()).estimate(any()); + verify(repository, never()).insertFee(any()); + } + @Test @DisplayName("缺少订单客户归属时拒绝生成对客费用") void rejectsMissingOrderCustomerOwnership() {