fix(firstleg): align measurement package validation
This commit is contained in:
@@ -264,7 +264,8 @@ public class InboundMeasurementService {
|
|||||||
"即使只有一箱,也必须上传并确认至少一张称重图片后再提交测量审核");
|
"即使只有一箱,也必须上传并确认至少一张称重图片后再提交测量审核");
|
||||||
}
|
}
|
||||||
|
|
||||||
requireConfirmedPackageTotal(inbound, items);
|
int latestDeclaredPackageCount = loadLatestDeclaration(inbound).snapshot().totalPackageCount();
|
||||||
|
requireConfirmedPackageTotal(latestDeclaredPackageCount, items);
|
||||||
measurement.setStatus(STATUS_SUBMITTED);
|
measurement.setStatus(STATUS_SUBMITTED);
|
||||||
if (!repository.updateMeasurement(measurement)) {
|
if (!repository.updateMeasurement(measurement)) {
|
||||||
throw concurrentModification();
|
throw concurrentModification();
|
||||||
@@ -275,6 +276,9 @@ public class InboundMeasurementService {
|
|||||||
inbound.setMeasureCompletedAt(LocalDateTime.now());
|
inbound.setMeasureCompletedAt(LocalDateTime.now());
|
||||||
inbound.setActualGrossWeightKg(confirmedTotals.grossWeightKg());
|
inbound.setActualGrossWeightKg(confirmedTotals.grossWeightKg());
|
||||||
inbound.setActualNetWeightKg(confirmedTotals.netWeightKg());
|
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 ("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType())) {
|
||||||
if (inbound.getPalletCount() == null || inbound.getPalletCount() < 1) {
|
if (inbound.getPalletCount() == null || inbound.getPalletCount() < 1) {
|
||||||
throw new BizException(ResultCode.VALIDATION_FAILED, "请先录入预计托数并保存,再提交测量审核");
|
throw new BizException(ResultCode.VALIDATION_FAILED, "请先录入预计托数并保存,再提交测量审核");
|
||||||
@@ -566,7 +570,7 @@ public class InboundMeasurementService {
|
|||||||
LatestDeclaration latestDeclaration) {
|
LatestDeclaration latestDeclaration) {
|
||||||
InboundMeasurementResponses.DeclarationSnapshot declaration = latestDeclaration.snapshot();
|
InboundMeasurementResponses.DeclarationSnapshot declaration = latestDeclaration.snapshot();
|
||||||
return new InboundMeasurementResponses.Detail(
|
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.getChannelName(), inbound.getFulfillmentType(), inbound.getPalletCount(),
|
||||||
inbound.getProcessStatus(), inbound.getMeasureReviewStatus(),
|
inbound.getProcessStatus(), inbound.getMeasureReviewStatus(),
|
||||||
RECOMMENDED_PALLET_TYPE,
|
RECOMMENDED_PALLET_TYPE,
|
||||||
@@ -740,23 +744,28 @@ public class InboundMeasurementService {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requireConfirmedPackageTotal(InboundOrderEntity inbound,
|
private void requireConfirmedPackageTotal(int latestDeclaredPackageCount,
|
||||||
List<InboundMeasurementItemEntity> items) {
|
List<InboundMeasurementItemEntity> items) {
|
||||||
if (inbound.getTotalPackageCount() == null || inbound.getTotalPackageCount() < 1) {
|
if (latestDeclaredPackageCount < 1) {
|
||||||
throw new BizException(ResultCode.VALIDATION_FAILED, "入库单原始总箱数无效,不能提交测量");
|
throw new BizException(ResultCode.VALIDATION_FAILED, "客户最新申报总箱数无效,不能提交测量");
|
||||||
}
|
}
|
||||||
long confirmed = items.stream()
|
long confirmed = items.stream()
|
||||||
.map(InboundMeasurementItemEntity::getPackageCount)
|
.map(InboundMeasurementItemEntity::getPackageCount)
|
||||||
.filter(java.util.Objects::nonNull)
|
.filter(java.util.Objects::nonNull)
|
||||||
.mapToLong(Integer::longValue)
|
.mapToLong(Integer::longValue)
|
||||||
.sum();
|
.sum();
|
||||||
if (confirmed != inbound.getTotalPackageCount()) {
|
if (confirmed != latestDeclaredPackageCount) {
|
||||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||||
"人工确认箱数合计" + confirmed + "箱,与入库单总箱数"
|
"人工确认箱数合计" + confirmed + "箱,与客户最新申报总箱数"
|
||||||
+ inbound.getTotalPackageCount() + "箱不一致");
|
+ 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) {
|
private InboundMeasurementResponses.WeightResult toWeight(InboundWeightResultEntity weight) {
|
||||||
return toWeight(weight, weight.getId() == null ? null
|
return toWeight(weight, weight.getId() == null ? null
|
||||||
: palletAllocations.findByWeightResult(weight.getTenantId(), weight.getInboundId(), weight.getId()));
|
: palletAllocations.findByWeightResult(weight.getTenantId(), weight.getInboundId(), weight.getId()));
|
||||||
|
|||||||
+46
-1
@@ -376,6 +376,19 @@ class InboundMeasurementServiceTest {
|
|||||||
verify(orderCargoClient, times(1)).listForCartonLabels("internal-token", 1L, 80L);
|
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
|
@Test
|
||||||
void detailRejectsCargoBatchWhoseOrderOwnershipDoesNotMatchInbound() {
|
void detailRejectsCargoBatchWhoseOrderOwnershipDoesNotMatchInbound() {
|
||||||
InboundOrderEntity inbound = inbound("MEASURE_PENDING");
|
InboundOrderEntity inbound = inbound("MEASURE_PENDING");
|
||||||
@@ -1167,7 +1180,39 @@ class InboundMeasurementServiceTest {
|
|||||||
assertThat(inbound.getPalletCount()).isEqualTo(1);
|
assertThat(inbound.getPalletCount()).isEqualTo(1);
|
||||||
assertThat(inbound.getActualVolumeCbm()).isEqualByComparingTo("1.2345");
|
assertThat(inbound.getActualVolumeCbm()).isEqualByComparingTo("1.2345");
|
||||||
assertThat(inbound.getTotalPackageCount()).isEqualTo(3);
|
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
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user