提交
This commit is contained in:
+8
@@ -60,4 +60,12 @@ class FleetPickupMapperTest {
|
||||
db.update("INSERT INTO ll_fleet_pickup_task VALUES(1,'C1','WT-1','TR-1','PICKED',CURRENT_TIMESTAMP)");
|
||||
assertThat(mapper.unassign("TR-1")).isZero();assertThat(mapper.task(1L).getTripNo()).isEqualTo("TR-1");
|
||||
}
|
||||
/** 联动取消保留原车次身份,已取货成员不能被取消SQL覆盖。 */
|
||||
@Test void cancellationKeepsSourceLinkAndDoesNotRewritePickedFacts() {
|
||||
db.update("INSERT INTO ll_fleet_pickup_task VALUES(1,'C1','WT-1','TR-1','ASSIGNED',CURRENT_TIMESTAMP)");
|
||||
db.update("INSERT INTO ll_fleet_pickup_task VALUES(6,'C6','WT-6','TR-1','PICKED',CURRENT_TIMESTAMP)");
|
||||
assertThat(mapper.cancelTasks("TR-1")).isEqualTo(1);
|
||||
assertThat(mapper.task(1L).getTripNo()).isEqualTo("TR-1");assertThat(mapper.task(1L).getStatus()).isEqualTo("CANCELLED");
|
||||
assertThat(mapper.task(6L).getStatus()).isEqualTo("PICKED");assertThat(mapper.cancelTasks("TR-1")).isZero();
|
||||
}
|
||||
}
|
||||
|
||||
+44
-4
@@ -15,11 +15,15 @@ import static org.mockito.ArgumentMatchers.*;
|
||||
|
||||
class FleetPickupServiceTest {
|
||||
FleetPickupRepository repository;FleetTripService trips;FleetPickupService service;
|
||||
PickupDepartureReview departureReview;
|
||||
DriverService drivers;VehicleRepository vehicles;
|
||||
TripOperationsEvidenceGateway files;FleetTripEntity trip;FleetPickupSource source;FleetPickupTask task;
|
||||
final Map<String,String> commands=new HashMap<>();
|
||||
@BeforeEach void setup() {
|
||||
repository=mock(FleetPickupRepository.class);trips=mock(FleetTripService.class);files=mock(TripOperationsEvidenceGateway.class);
|
||||
service=new FleetPickupService(repository,trips,mock(FleetWarehouseDirectory.class),mock(DriverService.class),mock(VehicleRepository.class),files,new ObjectMapper().findAndRegisterModules());
|
||||
departureReview=mock(PickupDepartureReview.class);
|
||||
drivers=mock(DriverService.class);vehicles=mock(VehicleRepository.class);
|
||||
service=new FleetPickupService(repository,trips,mock(FleetWarehouseDirectory.class),drivers,vehicles,files,new ObjectMapper().findAndRegisterModules(),departureReview);
|
||||
trip=new FleetTripEntity();trip.setId(9L);trip.setTripNo("TR-1");trip.setTripPurpose("PICKUP");trip.setStatus("IN_TRANSIT");trip.setWarehouseId(100L);trip.setRecordVersion(2L);
|
||||
source=source(1L,"C1","WT-1","100");task=new FleetPickupTask();task.setTransferOrderId(1L);task.setCustomerId("C1");task.setTransferNo("WT-1");task.setTripNo("TR-1");task.setStatus("ASSIGNED");
|
||||
when(repository.trip("TR-1",true)).thenReturn(trip);when(repository.trip("TR-1",false)).thenReturn(trip);
|
||||
@@ -29,6 +33,29 @@ class FleetPickupServiceTest {
|
||||
doAnswer(c->{commands.put(c.getArgument(1),c.getArgument(2));return null;}).when(repository).command(anyString(),anyString(),anyString());
|
||||
doAnswer(c->{trip.setRecordVersion(trip.getRecordVersion()+1);return null;}).when(trips).recordExecution(any(),anyLong(),anyString(),anyString(),anyString());
|
||||
}
|
||||
/** 审核完成后直接在装货阶段上传取货照片,全车核齐自动进入派送。 */
|
||||
@Test void pickupPhotosStartDeliveryWithoutSeparateDeparture() {
|
||||
trip.setStatus("PLANNED");trip.setVehicleId(20L);trip.setDriverId(30L);trip.setExpectedDriverEndAt(LocalDateTime.now(ZoneOffset.UTC).plusDays(1));
|
||||
when(repository.ownsResources(9L,20L,30L)).thenReturn(true);
|
||||
var vehicle=mock(VehicleRepository.VehicleSnapshot.class);when(vehicle.region()).thenReturn("OVERSEAS");when(vehicle.status()).thenReturn("IN_SERVICE");when(vehicles.lockById(20L)).thenReturn(Optional.of(vehicle));
|
||||
var driver=mock(DriverModels.Response.class);var details=mock(DriverModels.Draft.class);when(details.region()).thenReturn("OVERSEAS");when(driver.details()).thenReturn(details);when(drivers.requireDispatchable(eq(30L),any())).thenReturn(driver);
|
||||
when(repository.ownsUpload(1L,"TR-1",88L)).thenReturn(true);
|
||||
when(files.metadata(9L,88L)).thenReturn(new TripOperationsRecordModels.EvidenceFile("88","取货照片.jpg","image/jpeg",500));
|
||||
var request=new FleetPickupModels.Pickup(2L,"pickup-photo-key",5,List.of(88L),null);
|
||||
service.picked("TR-1","C1","WT-1","OP",request);
|
||||
assertThat(task.getStatus()).isEqualTo("PICKED");assertThat(trip.getStatus()).isEqualTo("IN_TRANSIT");assertThat(trip.getDepartedAt()).isNotNull();
|
||||
verify(departureReview).requireApproved(9L);verify(trips,times(1)).recordExecution(any(),eq(2L),eq("PICKUP_PICKED"),anyString(),eq("OP"));
|
||||
service.picked("TR-1","C1","WT-1","OP",request);verify(repository,times(1)).update(task);
|
||||
}
|
||||
/** 原车队发车接口不能在两级审核未通过时写入实际发车事实。 */
|
||||
@Test void legacyDepartureCannotBypassReview() {
|
||||
trip.setStatus("PLANNED");
|
||||
doThrow(new IllegalStateException("请先完成两级审核")).when(departureReview).requireApproved(9L);
|
||||
assertThatThrownBy(()->service.depart("TR-1","OP",new FleetPickupModels.Command(2L,"depart-review-key","发车"))).hasMessageContaining("两级审核");
|
||||
assertThat(trip.getStatus()).isEqualTo("PLANNED");assertThat(trip.getDepartedAt()).isNull();
|
||||
verify(trips,never()).recordExecution(any(),anyLong(),anyString(),anyString(),anyString());
|
||||
assertThat(commands).isEmpty();
|
||||
}
|
||||
/** 原单所属域锁定来源后,车队仅以该来源核对真实送仓事实。 */
|
||||
@Test void pickupMustArriveBeforePda() {
|
||||
assertThatThrownBy(()->service.requireArrived(1L,"WAREHOUSE_PICKUP","WT-1","WT-1")).hasMessageContaining("先完成车辆取货送仓");
|
||||
@@ -79,10 +106,23 @@ class FleetPickupServiceTest {
|
||||
}
|
||||
@Test void arrivalOpensPdaAndCompletionKeepsWarehouseOrderInMeasurement() {
|
||||
task.setStatus("PICKED");task.setActualPackages(5);task.setPickedAt(LocalDateTime.now(ZoneOffset.UTC));
|
||||
service.arrive("TR-1","C1","WT-1","OP",new FleetPickupModels.Command(2L,"arrive-key-1","已送海外仓月台"));
|
||||
when(repository.ownsUpload(1L,"TR-1",89L)).thenReturn(true);
|
||||
when(files.metadata(9L,89L)).thenReturn(new TripOperationsRecordModels.EvidenceFile("89","到仓照片.jpg","image/jpeg",500));
|
||||
var request=new FleetPickupModels.Command(2L,"arrive-key-1","已送海外仓月台",List.of(89L));
|
||||
service.arrive("TR-1","C1","WT-1","OP",request);
|
||||
assertThat(task.getStatus()).isEqualTo("ARRIVED");assertThat(source.getStatus()).isEqualTo("WAIT_PDA_RECEIVING");
|
||||
service.complete("TR-1","OP",new FleetPickupModels.Command(3L,"complete-key-1","全部送仓"));
|
||||
assertThat(trip.getStatus()).isEqualTo("COMPLETED");assertThat(trip.getCompletionJson()).contains("complete-key-1");assertThat(source.getStatus()).isEqualTo("WAIT_PDA_RECEIVING");
|
||||
assertThat(trip.getStatus()).isEqualTo("COMPLETED");assertThat(trip.getCompletionJson()).contains("arrive-key-1");assertThat(source.getStatus()).isEqualTo("WAIT_PDA_RECEIVING");
|
||||
assertThat(task.getEvidenceJson()).contains("ARRIVAL","到仓照片");
|
||||
service.arrive("TR-1","C1","WT-1","OP",request);verify(repository,times(1)).update(task);
|
||||
}
|
||||
/** 到仓必须上传独立的新照片,不能用取货照片冒充或提前开放清点。 */
|
||||
@Test void arrivalRequiresFreshPhotoEvidence() {
|
||||
task.setStatus("PICKED");
|
||||
task.setEvidenceJson("[{\"fileId\":\"88\",\"fileName\":\"取货.jpg\",\"contentType\":\"image/jpeg\",\"sizeBytes\":1,\"phase\":\"PICKUP\"}]");
|
||||
assertThatThrownBy(()->service.arrive("TR-1","C1","WT-1","OP",new FleetPickupModels.Command(2L,"no-photo","送仓"))).hasMessageContaining("上传到仓照片");
|
||||
when(repository.ownsUpload(1L,"TR-1",88L)).thenReturn(true);
|
||||
assertThatThrownBy(()->service.arrive("TR-1","C1","WT-1","OP",new FleetPickupModels.Command(2L,"same-photo","送仓",List.of(88L)))).hasMessageContaining("不能复用取货照片");
|
||||
assertThat(task.getStatus()).isEqualTo("PICKED");verify(repository,never()).update(any());
|
||||
}
|
||||
@Test void staleVersionAndWrongTripPurposeAreRejected() {
|
||||
assertThatThrownBy(()->service.arrive("TR-1","C1","WT-1","OP",new FleetPickupModels.Command(1L,"arrive-key-1","送仓"))).hasMessageContaining("车次已变化");
|
||||
|
||||
+2
@@ -122,6 +122,8 @@ class FleetTripAuthorizationTest {
|
||||
@Bean com.baiyue.lastleg.fleet.business.FleetLooseboardDemandRepository looseboardDemandRepository() { return mock(com.baiyue.lastleg.fleet.business.FleetLooseboardDemandRepository.class); }
|
||||
/** 既有取货能力依赖原仓储引用;权限测试使用只读替身,不连接数据库。 */
|
||||
@Bean com.baiyue.lastleg.fleet.pickup.FleetPickupRepository pickups() { return mock(com.baiyue.lastleg.fleet.pickup.FleetPickupRepository.class); }
|
||||
/** 取消原单使用所属域替身,权限测试不写业务数据。 */
|
||||
@Bean com.baiyue.lastleg.fleet.pickup.PickupOrderCancellation pickupCancellation() { return mock(com.baiyue.lastleg.fleet.pickup.PickupOrderCancellation.class); }
|
||||
@Bean com.baiyue.lastleg.fleet.trip.work.AppointmentWorkTripChanges workTripChanges() { return mock(com.baiyue.lastleg.fleet.trip.work.AppointmentWorkTripChanges.class); }
|
||||
@Bean com.baiyue.lastleg.appointmentwork.AppointmentWorkDispatchPort workDispatches() { return mock(com.baiyue.lastleg.appointmentwork.AppointmentWorkDispatchPort.class); }
|
||||
@Bean FleetTripCalendarService calendar() { return mock(FleetTripCalendarService.class); }
|
||||
|
||||
Reference in New Issue
Block a user