fix(dispatch): persist and reuse the resolved draft group

This commit is contained in:
2026-10-15 18:12:55 +08:00
parent 23ce486539
commit 204ae10737
2 changed files with 69 additions and 3 deletions
@@ -160,6 +160,10 @@ class DispatchServiceTest {
verify(locks).insert(lock.capture());
assertEquals("draft-1", lock.getValue().getDraftToken());
assertEquals("7", lock.getValue().getOperatorId());
ArgumentCaptor<DispatchDraftContainer> group = ArgumentCaptor.forClass(DispatchDraftContainer.class);
verify(draftContainers).insert(group.capture());
assertNotNull(group.getValue().getId());
assertEquals(group.getValue().getId(), lock.getValue().getDraftContainerId());
assertNotNull(lock.getValue().getExpiresAt());
assertEquals(null, lock.getValue().getDispatchOrderId());
verify(locks).clearInactiveActiveKey("100", "PLAN:10");
@@ -175,6 +179,59 @@ class DispatchServiceTest {
verify(locks).insert(any(DispatchPalletLock.class));
}
private DispatchDraftContainer existingDraftGroup() {
DispatchDraft draft = new DispatchDraft();
draft.setId(20L); draft.setDraftToken("draft-1"); draft.setOperatorId("7");
when(drafts.lockActive("draft-1", "7")).thenReturn(draft);
DispatchDraftContainer group = new DispatchDraftContainer();
group.setId(21L); group.setDraftId(20L); group.setDraftToken("draft-1");
return group;
}
@Test void omittedGroupReusesTheOnlyGroupAndPersistsItsIdentity() {
var group = existingDraftGroup();
when(draftContainers.findByToken("draft-1")).thenReturn(List.of(group));
when(candidates.lockSelected("100", List.of(10L))).thenReturn(List.of(candidate(10L, null, "ONT8")));
service.lockDraftPallet("100", "7", new DispatchRequests.DraftPallet(10L, "draft-1"));
var lock = ArgumentCaptor.forClass(DispatchPalletLock.class);
verify(locks).insert(lock.capture());
assertEquals(21L, lock.getValue().getDraftContainerId());
verify(draftContainers, never()).insert(any(DispatchDraftContainer.class));
}
@Test void omittedGroupReplayDoesNotCreateAnotherGroupOrLock() {
var group = existingDraftGroup();
when(draftContainers.findByToken("draft-1")).thenReturn(List.of(group));
when(candidates.lockSelected("100", List.of(10L))).thenReturn(List.of(candidate(10L, null, "ONT8")));
var lock = new DispatchPalletLock(); lock.setDraftToken("draft-1"); lock.setOperatorId("7"); lock.setDraftContainerId(21L);
when(locks.lockActive("100", "PLAN:10")).thenReturn(lock);
service.lockDraftPallet("100", "7", new DispatchRequests.DraftPallet(10L, "draft-1"));
verify(draftContainers, never()).insert(any(DispatchDraftContainer.class));
verify(locks, never()).insert(any(DispatchPalletLock.class));
}
@Test void multipleGroupsRequireExplicitSelectionWithoutCreatingAnotherGroup() {
var group = existingDraftGroup();
var second = new DispatchDraftContainer(); second.setId(22L);
when(draftContainers.findByToken("draft-1")).thenReturn(List.of(group, second));
assertEquals(400, assertThrows(ResponseStatusException.class, () ->
service.lockDraftPallet("100", "7", new DispatchRequests.DraftPallet(10L, "draft-1"))).getStatusCode().value());
verify(draftContainers, never()).insert(any(DispatchDraftContainer.class));
verify(locks, never()).insert(any(DispatchPalletLock.class));
}
@Test void replayCannotSilentlyMoveAPalletToAnotherGroup() {
var group = existingDraftGroup();
when(draftContainers.selectById(21L)).thenReturn(group);
when(candidates.lockSelected("100", List.of(10L))).thenReturn(List.of(candidate(10L, null, "ONT8")));
var lock = new DispatchPalletLock(); lock.setDraftToken("draft-1"); lock.setOperatorId("7"); lock.setDraftContainerId(22L);
when(locks.lockActive("100", "PLAN:10")).thenReturn(lock);
assertEquals(409, assertThrows(ResponseStatusException.class, () ->
service.lockDraftPallet("100", "7", new DispatchRequests.DraftPallet(10L, "draft-1", 21L))).getStatusCode().value());
assertEquals(22L, lock.getDraftContainerId());
verify(locks, never()).insert(any(DispatchPalletLock.class));
}
@Test
void preArrangeAcceptsVolumeOnlyPlanPallet() {
when(candidates.lockSelected("100", List.of(10L)))