fix: gate device scans by actual measurement submission state
This commit is contained in:
@@ -147,7 +147,7 @@ public class CartonMeasurementService {
|
|||||||
if (inbound == null) {
|
if (inbound == null) {
|
||||||
throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
||||||
}
|
}
|
||||||
if (!DEVICE_WRITABLE_STATUSES.contains(inbound.getProcessStatus())) {
|
if (!deviceWritable(inbound, tenantId)) {
|
||||||
throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据");
|
throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据");
|
||||||
}
|
}
|
||||||
InboundMeasurementItemEntity item = repository.findItemByBoxCode(tenantId, boxCode);
|
InboundMeasurementItemEntity item = repository.findItemByBoxCode(tenantId, boxCode);
|
||||||
@@ -245,7 +245,6 @@ public class CartonMeasurementService {
|
|||||||
item.setTotalVolumeCbm(totalVolume);
|
item.setTotalVolumeCbm(totalVolume);
|
||||||
item.setVolumeWeightKg(totalVolume.multiply(VOLUME_WEIGHT_FACTOR).setScale(3, RoundingMode.CEILING));
|
item.setVolumeWeightKg(totalVolume.multiply(VOLUME_WEIGHT_FACTOR).setScale(3, RoundingMode.CEILING));
|
||||||
item.setCalculationRuleVersion(weighted.calculationRuleVersion());
|
item.setCalculationRuleVersion(weighted.calculationRuleVersion());
|
||||||
item.setOverLimitWarning(weighted.warning());
|
|
||||||
item.setOuterLengthCm(weighted.outerLengthCm());
|
item.setOuterLengthCm(weighted.outerLengthCm());
|
||||||
item.setOuterWidthCm(weighted.outerWidthCm());
|
item.setOuterWidthCm(weighted.outerWidthCm());
|
||||||
item.setOuterHeightCm(weighted.outerHeightCm());
|
item.setOuterHeightCm(weighted.outerHeightCm());
|
||||||
@@ -306,12 +305,25 @@ public class CartonMeasurementService {
|
|||||||
if (inbound == null) {
|
if (inbound == null) {
|
||||||
throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
||||||
}
|
}
|
||||||
if (!DEVICE_WRITABLE_STATUSES.contains(inbound.getProcessStatus())) {
|
if (!deviceWritable(inbound, tenantId)) {
|
||||||
throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据");
|
throw new BizException(ResultCode.CONFLICT, "测量已提交,设备不能新增或覆盖数据");
|
||||||
}
|
}
|
||||||
return inbound;
|
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) {
|
private InboundOrderEntity requireManualCountEditableInbound(long tenantId, long inboundId) {
|
||||||
InboundOrderEntity inbound = repository.findInbound(tenantId, inboundId);
|
InboundOrderEntity inbound = repository.findInbound(tenantId, inboundId);
|
||||||
if (inbound == null) {
|
if (inbound == null) {
|
||||||
|
|||||||
+28
-3
@@ -113,7 +113,7 @@ class CartonMeasurementServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void oversizeScanKeepsImageAndActualDimensionsForManualReview() {
|
void scanOutsideConfiguredWeightingRulesKeepsImageAndActualDimensions() {
|
||||||
InboundMeasurementEntity measurement = measurement(30001L, "RECEIVED", 0);
|
InboundMeasurementEntity measurement = measurement(30001L, "RECEIVED", 0);
|
||||||
when(repository.findItemByBoxCode(10001L, "RK-001#5-1")).thenReturn(null);
|
when(repository.findItemByBoxCode(10001L, "RK-001#5-1")).thenReturn(null);
|
||||||
when(repository.findLatestEditableMeasurement(10001L, 70001L)).thenReturn(measurement);
|
when(repository.findLatestEditableMeasurement(10001L, 70001L)).thenReturn(measurement);
|
||||||
@@ -131,8 +131,8 @@ class CartonMeasurementServiceTest {
|
|||||||
assertThat(insertedItem.get().getSourceImageFileId()).isEqualTo(99001L);
|
assertThat(insertedItem.get().getSourceImageFileId()).isEqualTo(99001L);
|
||||||
assertThat(insertedItem.get().getLengthCm()).isEqualByComparingTo("60.100");
|
assertThat(insertedItem.get().getLengthCm()).isEqualByComparingTo("60.100");
|
||||||
assertThat(insertedItem.get().getCalculationRuleVersion())
|
assertThat(insertedItem.get().getCalculationRuleVersion())
|
||||||
.isEqualTo("ACTUAL_DIMENSION_OVERSIZE_V1");
|
.isEqualTo("ACTUAL_DIMENSION_V1");
|
||||||
assertThat(insertedItem.get().getOverLimitWarning()).contains("人工复核");
|
assertThat(insertedItem.get().getOverLimitWarning()).isNull();
|
||||||
verify(images, never()).delete(any(), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE), any(Long.TYPE));
|
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());
|
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
|
@Test
|
||||||
void platformSimulationRejectsBoxCodeFromAnotherInboundBeforeUploadingImage() {
|
void platformSimulationRejectsBoxCodeFromAnotherInboundBeforeUploadingImage() {
|
||||||
assertThatThrownBy(() -> service.upsertForInbound(10001L, 90001L, 70002L, command()))
|
assertThatThrownBy(() -> service.upsertForInbound(10001L, 90001L, 70002L, command()))
|
||||||
|
|||||||
Reference in New Issue
Block a user