diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/CartonMeasurementService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/CartonMeasurementService.java index 50eb5747b..301f37b2f 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/CartonMeasurementService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/CartonMeasurementService.java @@ -147,7 +147,7 @@ public class CartonMeasurementService { if (inbound == null) { throw new BizException(ResultCode.NOT_FOUND, "入库单不存在"); } - if (!DEVICE_WRITABLE_STATUSES.contains(inbound.getProcessStatus())) { + if (!deviceWritable(inbound, tenantId)) { throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据"); } InboundMeasurementItemEntity item = repository.findItemByBoxCode(tenantId, boxCode); @@ -245,7 +245,6 @@ public class CartonMeasurementService { item.setTotalVolumeCbm(totalVolume); item.setVolumeWeightKg(totalVolume.multiply(VOLUME_WEIGHT_FACTOR).setScale(3, RoundingMode.CEILING)); item.setCalculationRuleVersion(weighted.calculationRuleVersion()); - item.setOverLimitWarning(weighted.warning()); item.setOuterLengthCm(weighted.outerLengthCm()); item.setOuterWidthCm(weighted.outerWidthCm()); item.setOuterHeightCm(weighted.outerHeightCm()); @@ -306,12 +305,25 @@ public class CartonMeasurementService { if (inbound == null) { throw new BizException(ResultCode.NOT_FOUND, "入库单不存在"); } - if (!DEVICE_WRITABLE_STATUSES.contains(inbound.getProcessStatus())) { + if (!deviceWritable(inbound, tenantId)) { throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据"); } return inbound; } + /** + * 设备回传门禁以入库流程状态为主,并用测量批次状态兜底校验提交语义。 + * RECEIVED/DRAFT 只是设备资料,不能把处于 WAIT_MEASURE 的入库单误判为已提交; + * SUBMITTED/APPROVED 则必须继续保留设备覆盖保护,即使旧数据的主状态快照滞后。 + */ + private boolean deviceWritable(InboundOrderEntity inbound, long tenantId) { + if (!DEVICE_WRITABLE_STATUSES.contains(inbound.getProcessStatus())) { + return false; + } + InboundMeasurementEntity latest = repository.findLatestMeasurement(tenantId, inbound.getId()); + return latest == null || !Set.of("SUBMITTED", "APPROVED").contains(latest.getStatus()); + } + private InboundOrderEntity requireManualCountEditableInbound(long tenantId, long inboundId) { InboundOrderEntity inbound = repository.findInbound(tenantId, inboundId); if (inbound == null) { diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/CartonMeasurementServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/CartonMeasurementServiceTest.java index 3469dddb9..914af30f5 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/CartonMeasurementServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/CartonMeasurementServiceTest.java @@ -113,7 +113,7 @@ class CartonMeasurementServiceTest { } @Test - void oversizeScanKeepsImageAndActualDimensionsForManualReview() { + void scanOutsideConfiguredWeightingRulesKeepsImageAndActualDimensions() { InboundMeasurementEntity measurement = measurement(30001L, "RECEIVED", 0); when(repository.findItemByBoxCode(10001L, "RK-001#5-1")).thenReturn(null); when(repository.findLatestEditableMeasurement(10001L, 70001L)).thenReturn(measurement); @@ -131,8 +131,8 @@ class CartonMeasurementServiceTest { assertThat(insertedItem.get().getSourceImageFileId()).isEqualTo(99001L); assertThat(insertedItem.get().getLengthCm()).isEqualByComparingTo("60.100"); assertThat(insertedItem.get().getCalculationRuleVersion()) - .isEqualTo("ACTUAL_DIMENSION_OVERSIZE_V1"); - assertThat(insertedItem.get().getOverLimitWarning()).contains("人工复核"); + .isEqualTo("ACTUAL_DIMENSION_V1"); + assertThat(insertedItem.get().getOverLimitWarning()).isNull(); verify(images, never()).delete(any(), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE)); } @@ -146,6 +146,31 @@ class CartonMeasurementServiceTest { verify(images, never()).upload(any(), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE), any()); } + @Test + void waitMeasureWithFrozenLabelsAndReceivedDeviceBatchAllowsFirstScan() { + InboundMeasurementEntity received = measurement(30001L, "RECEIVED", 0); + when(repository.findLatestMeasurement(10001L, 70001L)).thenReturn(received); + when(repository.findItemByBoxCode(10001L, "RK-001#5-1")).thenReturn(null); + when(repository.findLatestEditableMeasurement(10001L, 70001L)).thenReturn(received); + when(repository.listItems(10001L, 30001L)).thenAnswer(invocation -> List.of(insertedItem.get())); + when(repository.updateMeasurement(received)).thenReturn(true); + + CartonMeasurementResult result = service.upsert(10001L, 90001L, command()); + + assertThat(result.created()).isTrue(); + assertThat(result.confirmedPackageCount()).isEqualTo(1); + } + + @Test + void staleWaitMeasureSnapshotStillRejectsWhenLatestBatchWasSubmitted() { + InboundMeasurementEntity submitted = measurement(30001L, "SUBMITTED", 1); + when(repository.findLatestMeasurement(10001L, 70001L)).thenReturn(submitted); + + assertThatThrownBy(() -> service.upsert(10001L, 90001L, command())) + .isInstanceOf(BizException.class).hasMessageContaining("不能新增或覆盖"); + verify(images, never()).upload(any(), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE), any()); + } + @Test void platformSimulationRejectsBoxCodeFromAnotherInboundBeforeUploadingImage() { assertThatThrownBy(() -> service.upsertForInbound(10001L, 90001L, 70002L, command()))