feat: complete phase 5 overseas fulfillment contracts

This commit is contained in:
2026-09-01 14:24:59 +08:00
parent ffed9bf898
commit 97168b19d8
46 changed files with 2446 additions and 409 deletions
@@ -3,6 +3,7 @@ package com.baiyue.lastleg.dispatch.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baiyue.lastleg.dispatch.dto.DispatchRequests;
import com.baiyue.lastleg.dispatch.dto.DispatchResponse;
import com.baiyue.lastleg.dispatch.entity.DispatchItem;
import com.baiyue.lastleg.dispatch.entity.DispatchOrder;
import com.baiyue.lastleg.dispatch.entity.DispatchPalletLock;
@@ -13,6 +14,8 @@ import com.baiyue.lastleg.dispatch.mapper.DispatchItemMapper;
import com.baiyue.lastleg.dispatch.mapper.DispatchOrderMapper;
import com.baiyue.lastleg.dispatch.mapper.DispatchPalletLockMapper;
import com.baiyue.lastleg.dispatch.model.DispatchPalletCandidate;
import com.baiyue.lastleg.dispatch.pda.entity.DispatchPdaTask;
import com.baiyue.lastleg.dispatch.pda.mapper.DispatchPdaTaskMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -45,6 +48,7 @@ class DispatchServiceTest {
@Mock DispatchCandidateMapper candidates;
@Mock DispatchDraftMapper drafts;
@Mock DispatchDraftContainerMapper draftContainers;
@Mock DispatchPdaTaskMapper pdaTasks;
private DispatchService service;
@BeforeEach
@@ -56,6 +60,7 @@ class DispatchServiceTest {
ReflectionTestUtils.setField(service, "candidates", candidates);
ReflectionTestUtils.setField(service, "drafts", drafts);
ReflectionTestUtils.setField(service, "draftContainers", draftContainers);
ReflectionTestUtils.setField(service, "pdaTasks", pdaTasks);
ReflectionTestUtils.setField(service, "orderNoGenerator", new com.baiyue.lastleg.service.LastlegOrderNoGenerator());
lenient().when(items.findByDispatchOrder(any(), any())).thenReturn(List.of());
}
@@ -73,6 +78,11 @@ class DispatchServiceTest {
assertEquals("ONT8", result.route());
ArgumentCaptor<DispatchOrder> dispatch = ArgumentCaptor.forClass(DispatchOrder.class);
verify(orders).insert(dispatch.capture());
ArgumentCaptor<DispatchPdaTask> pdaTask = ArgumentCaptor.forClass(DispatchPdaTask.class);
verify(pdaTasks).insert(pdaTask.capture());
assertEquals(dispatch.getValue().getId(), pdaTask.getValue().getDispatchOrderId());
assertEquals("WH-1", pdaTask.getValue().getWarehouseId());
assertEquals("PDA_PENDING", pdaTask.getValue().getStatus());
assertEquals(1, dispatch.getValue().getPalletCount());
verify(locks).insert(any(DispatchPalletLock.class));
verify(items).insert(any(DispatchItem.class));
@@ -204,20 +214,35 @@ class DispatchServiceTest {
}
@Test
void editCannotBypassPdaManagedDispatchStatus() {
void platformEditResolvesCustomerFromGlobalDispatchNumberAndPreservesStatus() {
DispatchOrder dispatch = new DispatchOrder();
dispatch.setId(1L); dispatch.setCustomerId("100"); dispatch.setDispatchNo("PC1");
dispatch.setStatus(DispatchService.PENDING_DEPARTURE);
when(orders.findByDispatchNo("100", "PC1")).thenReturn(dispatch);
when(orders.lockById("100", 1L)).thenReturn(dispatch);
when(orders.lockGlobalByDispatchNo("PC1")).thenReturn(dispatch);
DispatchRequests.Update request = new DispatchRequests.Update("ABC-1", "Driver", null, null, null,
null, null, null, LocalDateTime.now());
DispatchResponse result = service.update("PC1", request);
assertEquals(DispatchService.PENDING_DEPARTURE, dispatch.getStatus());
assertEquals("ABC-1", result.vehiclePlate());
verify(orders).updateById(dispatch);
verify(items).findByDispatchOrder("100", 1L);
}
@Test
void platformEditRejectsAnExecutedDispatchWithoutWriting() {
DispatchOrder dispatch = new DispatchOrder();
dispatch.setId(1L); dispatch.setCustomerId("100"); dispatch.setDispatchNo("PC1");
dispatch.setStatus("DEPARTED");
when(orders.lockGlobalByDispatchNo("PC1")).thenReturn(dispatch);
DispatchRequests.Update request = new DispatchRequests.Update(null, null, null, null, null,
LocalDateTime.now(), null, null, null, null, "COMPLETED");
null, null, null, null);
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
() -> service.update("100", "PC1", request));
() -> service.update("PC1", request));
assertEquals(400, exception.getStatusCode().value());
assertEquals(DispatchService.PENDING_DEPARTURE, dispatch.getStatus());
assertEquals(409, exception.getStatusCode().value());
verify(orders, never()).updateById(any(DispatchOrder.class));
}
@@ -255,13 +280,34 @@ class DispatchServiceTest {
void platformDetailUsesCustomerFromMatchedDispatch() {
DispatchOrder dispatch = new DispatchOrder();
dispatch.setId(1L); dispatch.setCustomerId("200"); dispatch.setDispatchNo("PC1");
when(orders.findAcrossCustomersByDispatchNo("PC1")).thenReturn(List.of(dispatch));
when(orders.findGlobalByDispatchNo("PC1")).thenReturn(dispatch);
service.platformDetail("PC1");
verify(items).findByDispatchOrder("200", 1L);
}
@Test
void globalCancelIsIdempotentAndReleasesOnlyTheResolvedCustomerLocks() {
DispatchOrder dispatch = new DispatchOrder();
dispatch.setId(1L); dispatch.setCustomerId("200"); dispatch.setDispatchNo("PC1");
dispatch.setStatus(DispatchService.PENDING_DEPARTURE);
DispatchPalletLock lock = new DispatchPalletLock();
lock.setStatus("ACTIVE"); lock.setActiveKey("PALLET:1");
when(orders.lockGlobalByDispatchNo("PC1")).thenReturn(dispatch);
when(locks.selectList(any())).thenReturn(List.of(lock));
service.cancel("PC1");
assertEquals(DispatchService.CANCELLED, dispatch.getStatus());
assertEquals("RELEASED", lock.getStatus());
assertEquals(null, lock.getActiveKey());
verify(locks).updateById(lock);
service.cancel("PC1");
verify(locks, org.mockito.Mockito.times(1)).selectList(any());
}
private DispatchPalletCandidate candidate(long planPalletId, Long warehousePalletId, String destination) {
return candidate(planPalletId, warehousePalletId, destination, 12);
}