修复私人地址逐箱收货的目的地匹配

This commit is contained in:
2026-11-04 13:45:59 +08:00
parent a01598bd21
commit 22e8939f1f
2 changed files with 79 additions and 10 deletions
@@ -956,28 +956,35 @@ public class InboundPdaWorkflowService {
} }
private boolean sameWarehouse(InboundPlanPallet left, InboundPlanPallet right) { private boolean sameWarehouse(InboundPlanPallet left, InboundPlanPallet right) {
String leftKey = left.getDestinationWarehouseId() != null String leftKey = destinationKey(left.getDestinationWarehouseId(), left.getDestinationWarehouseCode(),
? left.getDestinationWarehouseId() : left.getDestinationWarehouseCode(); left.getDestinationWarehouseName());
String rightKey = right.getDestinationWarehouseId() != null String rightKey = destinationKey(right.getDestinationWarehouseId(), right.getDestinationWarehouseCode(),
? right.getDestinationWarehouseId() : right.getDestinationWarehouseCode(); right.getDestinationWarehouseName());
return leftKey != null && leftKey.equals(rightKey); return leftKey != null && leftKey.equals(rightKey);
} }
private boolean sameWarehouse(InboundPlanCarton carton, InboundPlanPallet pallet) { private boolean sameWarehouse(InboundPlanCarton carton, InboundPlanPallet pallet) {
String cartonKey = carton.getDestinationWarehouseId() != null String cartonKey = destinationKey(carton.getDestinationWarehouseId(), carton.getDestinationWarehouseCode(),
? carton.getDestinationWarehouseId() : carton.getDestinationWarehouseCode(); carton.getDestinationWarehouseName());
String palletKey = pallet.getDestinationWarehouseId() != null String palletKey = destinationKey(pallet.getDestinationWarehouseId(), pallet.getDestinationWarehouseCode(),
? pallet.getDestinationWarehouseId() : pallet.getDestinationWarehouseCode(); pallet.getDestinationWarehouseName());
return cartonKey != null && cartonKey.equals(palletKey); return cartonKey != null && cartonKey.equals(palletKey);
} }
private String destinationKey(InboundPlanPallet pallet) { private String destinationKey(InboundPlanPallet pallet) {
String value = pallet.getDestinationWarehouseId() != null String value = destinationKey(pallet.getDestinationWarehouseId(), pallet.getDestinationWarehouseCode(),
? pallet.getDestinationWarehouseId() : pallet.getDestinationWarehouseCode(); pallet.getDestinationWarehouseName());
if (value == null || value.isBlank()) throw conflict("Planned pallet destination warehouse is empty"); if (value == null || value.isBlank()) throw conflict("Planned pallet destination warehouse is empty");
return value; return value;
} }
private String destinationKey(String warehouseId, String warehouseCode, String privateAddressName) {
if (warehouseId != null) return warehouseId;
if (warehouseCode != null) return warehouseCode;
if (privateAddressName == null || privateAddressName.isBlank()) return null;
return "PRIVATE:" + privateAddressName.trim();
}
private void validateDestinationWarehouse(InboundPlanPallet pallet, long warehouseId) { private void validateDestinationWarehouse(InboundPlanPallet pallet, long warehouseId) {
String destinationId = pallet.getDestinationWarehouseId(); String destinationId = pallet.getDestinationWarehouseId();
if (destinationId == null || destinationId.isBlank()) return; if (destinationId == null || destinationId.isBlank()) return;
@@ -308,6 +308,68 @@ class InboundPdaWorkflowServiceTest {
verify(warehouse, never()).reserve(any(), anyLong(), anyLong(), anyLong(), any(), any(), any()); verify(warehouse, never()).reserve(any(), anyLong(), anyLong(), anyLong(), any(), any(), any());
} }
@Test
void privateAddressCartonCanValidateAndScanBeforeItsPlanBindingExists() {
InboundPlanCarton carton = carton("BOX-PRIVATE", "UNASSIGNED", null, null);
carton.setPlanId(null);
carton.setDestinationWarehouseName("私人地址 A");
targetPallet.setDestinationWarehouseId(null);
targetPallet.setDestinationWarehouseName("私人地址 A");
activeTask();
when(repository.lockCarton("100", "BOX-PRIVATE")).thenReturn(carton);
when(repository.lineForCarton(plan.getId(), carton)).thenReturn(targetLine);
when(repository.lockPallet(plan.getId(), targetPallet.getId())).thenReturn(targetPallet);
when(repository.lockAllocation(plan.getId(), targetLine.getId(), targetPallet.getId())).thenReturn(target);
service.validateCartonResolved("100", plan, targetLine, targetPallet, carton.getCartonMark());
var scanned = service.scanCarton("100", "LIP1",
new PdaRequests.ScanCarton(carton.getCartonMark(), targetPallet.getId(), "private-scan", "7", "worker"));
assertEquals("SCANNED", scanned.result());
assertEquals(plan.getId(), carton.getPlanId());
assertEquals(targetLine.getId(), carton.getLineId());
assertEquals(1, target.getPickedPackageCount());
verify(repository).update(carton);
}
@Test
void privateAddressCartonRejectsDifferentAndEmptyDestinationNames() {
InboundPlanCarton carton = carton("BOX-PRIVATE", "UNASSIGNED", targetLine.getId(), null);
targetPallet.setDestinationWarehouseId(null);
targetPallet.setDestinationWarehouseName("私人地址 A");
activeTask();
when(repository.lockCarton("100", carton.getCartonMark())).thenReturn(carton);
when(repository.line(plan.getId(), targetLine.getId())).thenReturn(targetLine);
for (String name : List.of("私人地址 B", " ")) {
carton.setDestinationWarehouseName(name);
ResponseStatusException failure = assertThrows(ResponseStatusException.class,
() -> service.validateCartonResolved("100", plan, targetLine, targetPallet, carton.getCartonMark()));
assertEquals("Carton and pallet destination warehouses must match", failure.getReason());
}
verify(repository, never()).update(carton);
}
@Test
void privateAddressPalletCanReserveResourcesForItsNamedDestination() {
targetPallet.setDestinationWarehouseId(null);
targetPallet.setDestinationWarehouseName("私人地址 A");
targetPallet.setWarehouseResourceLockId(null);
WarehouseResourceGateway.WarehousePalletReference resource =
new WarehouseResourceGateway.WarehousePalletReference(188L, "A002", 88L, 288L,
"IDLE", "", 1);
when(warehouse.reserve("100", 88L, 188L, 288L, "INBOUND_CONTAINER_DESTINATION_PALLET",
"CONT-1:PRIVATE:私人地址 A", "INBOUND_CONTAINER_DESTINATION_PALLET:CONT-1:PRIVATE:私人地址 A:188"))
.thenReturn(999L);
when(repository.pallets(plan.getId())).thenReturn(List.of(targetPallet));
service.assignResolvedPallet("100", plan, targetPallet, resource);
assertEquals("ASSIGNED", targetPallet.getAssignmentStatus());
assertEquals(999L, targetPallet.getWarehouseResourceLockId());
assertEquals("A002", targetPallet.getPalletNo());
}
@Test @Test
void cartonScanBindsOnlyExpectedCartonAndRemoveMakesItScannableAgain() { void cartonScanBindsOnlyExpectedCartonAndRemoveMakesItScannableAgain() {
InboundPlanCarton carton = carton("BOX-001", "UNASSIGNED", targetLine.getId(), "WH-A"); InboundPlanCarton carton = carton("BOX-001", "UNASSIGNED", targetLine.getId(), "WH-A");