From d9a43845850c98f0b891e31fb09b2b52a43e0c45 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 14 Sep 2026 18:32:32 +0800 Subject: [PATCH] fix(firstleg): align measurement package validation --- .../service/InboundMeasurementService.java | 25 ++++++---- .../InboundMeasurementServiceTest.java | 47 ++++++++++++++++++- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java index 6f84a362f..506daba74 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java @@ -264,7 +264,8 @@ public class InboundMeasurementService { "即使只有一箱,也必须上传并确认至少一张称重图片后再提交测量审核"); } - requireConfirmedPackageTotal(inbound, items); + int latestDeclaredPackageCount = loadLatestDeclaration(inbound).snapshot().totalPackageCount(); + requireConfirmedPackageTotal(latestDeclaredPackageCount, items); measurement.setStatus(STATUS_SUBMITTED); if (!repository.updateMeasurement(measurement)) { throw concurrentModification(); @@ -275,6 +276,9 @@ public class InboundMeasurementService { inbound.setMeasureCompletedAt(LocalDateTime.now()); inbound.setActualGrossWeightKg(confirmedTotals.grossWeightKg()); inbound.setActualNetWeightKg(confirmedTotals.netWeightKg()); + // Once the warehouse confirms every carton, downstream split/loading must use the + // same package total that was just validated against the live Order declaration. + inbound.setTotalPackageCount(latestDeclaredPackageCount); if ("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType())) { if (inbound.getPalletCount() == null || inbound.getPalletCount() < 1) { throw new BizException(ResultCode.VALIDATION_FAILED, "请先录入预计托数并保存,再提交测量审核"); @@ -566,7 +570,7 @@ public class InboundMeasurementService { LatestDeclaration latestDeclaration) { InboundMeasurementResponses.DeclarationSnapshot declaration = latestDeclaration.snapshot(); return new InboundMeasurementResponses.Detail( - inbound.getId(), inbound.getInboundCode(), inbound.getCompanyName(), inbound.getChannelCode(), + inbound.getId(), inbound.getInboundCode(), customerDisplayName(inbound), inbound.getChannelCode(), inbound.getChannelName(), inbound.getFulfillmentType(), inbound.getPalletCount(), inbound.getProcessStatus(), inbound.getMeasureReviewStatus(), RECOMMENDED_PALLET_TYPE, @@ -740,23 +744,28 @@ public class InboundMeasurementService { ) { } - private void requireConfirmedPackageTotal(InboundOrderEntity inbound, + private void requireConfirmedPackageTotal(int latestDeclaredPackageCount, List items) { - if (inbound.getTotalPackageCount() == null || inbound.getTotalPackageCount() < 1) { - throw new BizException(ResultCode.VALIDATION_FAILED, "入库单原始总箱数无效,不能提交测量"); + if (latestDeclaredPackageCount < 1) { + throw new BizException(ResultCode.VALIDATION_FAILED, "客户最新申报总箱数无效,不能提交测量"); } long confirmed = items.stream() .map(InboundMeasurementItemEntity::getPackageCount) .filter(java.util.Objects::nonNull) .mapToLong(Integer::longValue) .sum(); - if (confirmed != inbound.getTotalPackageCount()) { + if (confirmed != latestDeclaredPackageCount) { throw new BizException(ResultCode.VALIDATION_FAILED, - "人工确认箱数合计" + confirmed + "箱,与入库单总箱数" - + inbound.getTotalPackageCount() + "箱不一致"); + "人工确认箱数合计" + confirmed + "箱,与客户最新申报总箱数" + + latestDeclaredPackageCount + "箱不一致"); } } + private static String customerDisplayName(InboundOrderEntity inbound) { + if (StringUtils.hasText(inbound.getCompanyName())) return inbound.getCompanyName(); + return StringUtils.hasText(inbound.getCustomerName()) ? inbound.getCustomerName() : null; + } + private InboundMeasurementResponses.WeightResult toWeight(InboundWeightResultEntity weight) { return toWeight(weight, weight.getId() == null ? null : palletAllocations.findByWeightResult(weight.getTenantId(), weight.getInboundId(), weight.getId())); diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java index dbb5b29cc..3d2e9134c 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java @@ -376,6 +376,19 @@ class InboundMeasurementServiceTest { verify(orderCargoClient, times(1)).listForCartonLabels("internal-token", 1L, 80L); } + @Test + void detailFallsBackToCustomerNameWhenLegacyCompanyNameIsEmpty() { + InboundOrderEntity inbound = inbound("MEASURING"); + inbound.setCustomerName("柏悦测试客户"); + inbound.setCompanyName(null); + when(repository.findInbound(1L, 10L)).thenReturn(inbound); + when(repository.listWeights(1L, 10L)).thenReturn(List.of()); + + InboundMeasurementResponses.Detail result = service.detail(1L, 10L); + + assertThat(result.companyName()).isEqualTo("柏悦测试客户"); + } + @Test void detailRejectsCargoBatchWhoseOrderOwnershipDoesNotMatchInbound() { InboundOrderEntity inbound = inbound("MEASURE_PENDING"); @@ -1167,7 +1180,39 @@ class InboundMeasurementServiceTest { assertThat(inbound.getPalletCount()).isEqualTo(1); assertThat(inbound.getActualVolumeCbm()).isEqualByComparingTo("1.2345"); assertThat(inbound.getTotalPackageCount()).isEqualTo(3); - verify(inbound, never()).setTotalPackageCount(any()); + verify(inbound).setTotalPackageCount(3); + } + + @Test + void submitUsesLatestOrderDeclarationAndRefreshesStaleInboundPackageTotal() { + InboundOrderEntity inbound = inbound("MEASURING"); + inbound.setTotalPackageCount(20); + InboundMeasurementEntity measurement = new InboundMeasurementEntity(); + measurement.setId(30L); + measurement.setStatus("DRAFT"); + measurement.setVersion(2); + measurement.setTotalPackageCount(18); + InboundMeasurementItemEntity item = new InboundMeasurementItemEntity(); + item.setPackageCount(18); + InboundWeightResultEntity weight = weight(20L, "197.000", "KG", "CONFIRMED", 1); + weight.setGrossWeightKg(new BigDecimal("197.000")); + weight.setNetWeightKg(new BigDecimal("181.000")); + when(repository.findInbound(1L, 10L)).thenReturn(inbound); + when(repository.findMeasurement(1L, 10L, 30L)).thenReturn(measurement); + when(repository.listItems(1L, 30L)).thenReturn(List.of(item)); + when(repository.listWeights(1L, 10L)).thenReturn(List.of(weight)); + when(repository.updateMeasurement(measurement)).thenReturn(true); + when(repository.updateInbound(inbound)).thenReturn(true); + when(orderCargoClient.listForCartonLabels("internal-token", 1L, 80L)).thenReturn( + ApiResponse.success(List.of(new OrderCargoClient.CargoLabelBinding( + 80001L, 80L, 1, "测试货物", null, 18, new BigDecimal("60"), + new BigDecimal("50"), new BigDecimal("50"), "SHIP-001")))); + + service.submit(1L, 10L, 9L, + new InboundMeasurementRequests.SubmitRequest(30L, 2)); + + assertThat(inbound.getTotalPackageCount()).isEqualTo(18); + assertThat(inbound.getProcessStatus()).isEqualTo("MEASURE_PENDING"); } @Test