diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java index 4103f9045..ab620e3e3 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java @@ -211,7 +211,7 @@ public class DispatchService { if (existing.size() > 1) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "存在多个装车分组,请明确选择目标分组"); if (existing.size() == 1) boundContainer = existing.get(0); else { - boundContainer = new DispatchDraftContainer(); boundContainer.setId(IdWorker.getId()); boundContainer.setDraftId(draft.getId()); boundContainer.setDraftToken(request.draftToken()); boundContainer.setSequenceNo(1); boundContainer.setCapacity(500); boundContainer.setCreatedAt(LocalDateTime.now()); boundContainer.setUpdatedAt(LocalDateTime.now()); draftContainers.insert(boundContainer); + boundContainer = new DispatchDraftContainer(); boundContainer.setId(IdWorker.getId()); boundContainer.setDraftId(draft.getId()); boundContainer.setDraftToken(request.draftToken()); boundContainer.setSequenceNo(1); boundContainer.setCapacity(30); boundContainer.setCreatedAt(LocalDateTime.now()); boundContainer.setUpdatedAt(LocalDateTime.now()); draftContainers.insert(boundContainer); } } if (boundContainer == null || !request.draftToken().equals(boundContainer.getDraftToken()) || !Objects.equals(boundContainer.getDraftId(), draft.getId())) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "装车托盘不存在"); @@ -335,7 +335,9 @@ public class DispatchService { actualGroups.add(container.getId()); var group = groups.get(container.getId()); if (group == null) throw new ResponseStatusException(HttpStatus.CONFLICT, "草稿分组已变化,请重新加载"); - if (container.getCapacity() == null || bound.size() > container.getCapacity()) + if (container.getCapacity() == null || !Set.of(15, 30).contains(container.getCapacity())) + throw new ResponseStatusException(HttpStatus.CONFLICT, "车辆大小仅支持15托或30托"); + if (bound.size() > container.getCapacity()) throw new ResponseStatusException(HttpStatus.CONFLICT, "装车分组超过车型托位容量"); Set actual = new HashSet<>(); Set customers = new HashSet<>(); diff --git a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml index fd13c94b2..c86721ade 100644 --- a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml +++ b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml @@ -2808,7 +2808,7 @@ components: returnReceiptId: { type: string } sourceType: { type: string, enum: [INBOUND_PLAN, RETURN_RECEIPT] } draftToken: { type: string, minLength: 1, maxLength: 64 } - draftContainerId: { type: string, nullable: true, description: 托盘所在草稿车厢ID } + draftContainerId: { type: string, nullable: true, description: 托盘所在草稿车厢ID;省略时复用唯一分组,无分组则新建30托默认组,多组时必须明确选择 } SmartDispatchDraftRelease: type: object required: [draftToken] diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java index 7367f9a75..8775a623b 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java @@ -163,6 +163,7 @@ class DispatchServiceTest { ArgumentCaptor group = ArgumentCaptor.forClass(DispatchDraftContainer.class); verify(draftContainers).insert(group.capture()); assertNotNull(group.getValue().getId()); + assertEquals(30, group.getValue().getCapacity()); assertEquals(group.getValue().getId(), lock.getValue().getDraftContainerId()); assertNotNull(lock.getValue().getExpiresAt()); assertEquals(null, lock.getValue().getDispatchOrderId()); @@ -676,6 +677,40 @@ class DispatchServiceTest { verify(orders, never()).insert(any(DispatchOrder.class)); verify(items, never()).insert(any(DispatchItem.class)); } + @Test + void groupedPreArrangeRejectsUnsupportedStoredCapacityBeforeCreatingDispatches() { + var fixture = twoGroupFixture(); + for (Integer capacity : java.util.Arrays.asList(null, 0, 31, 500)) { + fixture.containers().get(0).setCapacity(capacity); + var error = assertThrows(ResponseStatusException.class, + () -> service.preArrangeDraft("7", fixture.request())); + assertEquals(409, error.getStatusCode().value()); + assertEquals("车辆大小仅支持15托或30托", error.getReason()); + } + verify(orders, never()).insert(any(DispatchOrder.class)); + verify(items, never()).insert(any(DispatchItem.class)); + } + + @Test + void groupedPreArrangeRejectsThirtyOnePalletsInThirtyPalletVehicle() { + twoGroupFixture(); + var palletIds = java.util.stream.LongStream.rangeClosed(100, 130).boxed().toList(); + var bound = palletIds.stream().map(id -> { + var lock = new DispatchPalletLock(); + lock.setPlanPalletId(id); + return lock; + }).toList(); + when(locks.lockActiveByDraftContainer("draft-multi", 21L)).thenReturn(bound); + var request = new DispatchRequests.PreArrangeDraft("draft-multi", + List.of(new DispatchRequests.DraftGroup(21L, palletIds, List.of()))); + var error = assertThrows(ResponseStatusException.class, + () -> service.preArrangeDraft("7", request)); + assertEquals(409, error.getStatusCode().value()); + assertEquals("装车分组超过车型托位容量", error.getReason()); + verify(orders, never()).insert(any(DispatchOrder.class)); + verify(items, never()).insert(any(DispatchItem.class)); + } + @Test void secondGroupFailureRollsBackFirstGroupInsertInTheSameTransaction() { var fixture = twoGroupFixture();