This commit is contained in:
2026-08-08 21:14:39 +08:00
parent e5c6e03033
commit 2dae8b2029
20 changed files with 53421 additions and 17 deletions
@@ -35,6 +35,9 @@ class ServiceCenterUnifiedSqlContractTest {
.contains("5102154")
.contains("PLATFORM_ADMIN")
.contains("ORDER_OPERATOR")
.contains("COUNT(DISTINCT CONCAT(r.role_code, '|', p.permission_code))")
.contains("p.permission_code LIKE 'platform:firstleg:ocean-booking:%') <> 20")
.contains("p.permission_code LIKE 'platform:firstleg:truck-appointment:%') <> 10")
.contains("assert_phase3_service_center_schema()")
.contains("CALL assert_phase3_service_center_schema();");
}
@@ -95,7 +95,12 @@ class SmartLoadingSqlContractTest {
.contains("CALL migrate_legacy_loading_pick_task()")
.contains("CREATE TABLE IF NOT EXISTS fl_inbound_loading_pick_task")
.contains("5102121, 0, 'PLATFORM'")
.contains("5102129, 0, 'PLATFORM'");
.contains("5102129, 0, 'PLATFORM'")
.contains("三期入库装柜角色授权未完整写入")
.contains("permission.permission_code IN (")
.contains("role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR')")
.contains("permission.permission_code IN (\n 'firstleg:inbound:split'")
.contains(")) <> 18 THEN");
}
@Test
@@ -1,6 +1,8 @@
package com.baiyue.firstleg.service;
import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.PartialPickRequest;
import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest;
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
import com.baiyue.firstleg.entity.LoadingPickItemEntity;
import com.baiyue.firstleg.entity.LoadingPickTaskEntity;
@@ -59,6 +61,38 @@ class LoadingPickServiceTest {
verify(repository).insert(any(LoadingPickHistoryEntity.class));
}
@Test
void completesPlanWhenLastItemIsPartiallyPicked() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity item = item();
when(repository.history("partial-1")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.partial(30L, 1, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
service.partial(20L, 30L, new PartialPickRequest(101L, 1, List.of(), 0, "partial-1"), 9L, "operator");
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
}
@Test
void completesPlanWhenLastItemIsSkipped() {
LoadingPickTaskEntity task = task();
LoadingPickItemEntity item = item();
when(repository.history("skip-1")).thenReturn(null);
when(repository.task(20L)).thenReturn(task);
when(repository.item(20L, 30L, 101L)).thenReturn(item);
when(repository.skip(30L, 0, 101L)).thenReturn(1);
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
when(repository.items(20L, 101L)).thenReturn(List.of(item));
service.skip(20L, 30L, new SkipRequest(101L, 0, "skip-1", "fixture unavailable"), 9L, "operator");
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
}
private static LoadingPickTaskEntity task() {
LoadingPickTaskEntity task = new LoadingPickTaskEntity();
task.setId(20L);
@@ -7,9 +7,13 @@ import com.baiyue.firstleg.dto.TruckAppointmentDtos.SaveRequest;
import com.baiyue.firstleg.entity.TruckAppointmentEntity;
import com.baiyue.firstleg.entity.TruckAppointmentHistoryEntity;
import com.baiyue.firstleg.entity.TruckAppointmentOperationEntity;
import com.baiyue.firstleg.entity.LoadingPlanEntity;
import com.baiyue.firstleg.entity.ContainerBookingEntity;
import com.baiyue.firstleg.repository.TruckAppointmentRepository;
import com.baiyue.firstleg.repository.SmartLoadingRepository;
import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerAllocationEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -28,6 +32,7 @@ import static org.mockito.Mockito.*;
class TruckAppointmentServiceTest {
@Mock TruckAppointmentRepository repository;
@Mock OceanBookingRepository oceanBookings;
@Mock SmartLoadingRepository loadingPlans;
@InjectMocks TruckAppointmentService service;
@BeforeEach void setUp() { MockitoAnnotations.openMocks(this); }
@@ -53,6 +58,7 @@ class TruckAppointmentServiceTest {
when(request.expectedVersion()).thenReturn(0);
when(request.oceanBookingId()).thenReturn(99L);
when(request.customerId()).thenReturn(7L);
when(request.loadingPlanId()).thenReturn(null);
OceanBookingEntity booking = new OceanBookingEntity(); booking.setId(99L); booking.setStatus("RELEASED"); booking.setCustomerId(7L);
when(oceanBookings.find(99L)).thenReturn(booking);
service.create(7L, "admin", request);
@@ -60,6 +66,47 @@ class TruckAppointmentServiceTest {
verify(repository).history(any(TruckAppointmentHistoryEntity.class));
}
@Test void createRejectsLoadingPlanFromAnotherContainer() {
SaveRequest request = mock(SaveRequest.class);
when(request.expectedVersion()).thenReturn(0);
when(request.oceanBookingId()).thenReturn(99L);
when(request.containerBookingId()).thenReturn(88L);
when(request.loadingPlanId()).thenReturn(77L);
OceanBookingEntity booking = new OceanBookingEntity(); booking.setId(99L); booking.setStatus("RELEASED");
when(oceanBookings.find(99L)).thenReturn(booking);
ContainerBookingEntity container = new ContainerBookingEntity(); container.setId(88L);
when(oceanBookings.containerBooking(88L)).thenReturn(container);
var allocation = new OceanBookingContainerAllocationEntity();
allocation.setContainerBookingId(88L);
when(oceanBookings.allocations(99L)).thenReturn(java.util.List.of(allocation));
LoadingPlanEntity plan = new LoadingPlanEntity(); plan.setId(77L); plan.setContainerBookingId(66L);
when(loadingPlans.plan(77L)).thenReturn(plan);
assertThatThrownBy(() -> service.create(7L, "admin", request))
.isInstanceOf(BizException.class).hasMessageContaining("loadingPlanId").hasMessageContaining("柜体");
verify(repository, never()).insert(any());
}
@Test void createRejectsUnknownLoadingPlan() {
SaveRequest request = mock(SaveRequest.class);
when(request.expectedVersion()).thenReturn(0);
when(request.oceanBookingId()).thenReturn(99L);
when(request.containerBookingId()).thenReturn(88L);
when(request.loadingPlanId()).thenReturn(77L);
OceanBookingEntity booking = new OceanBookingEntity(); booking.setId(99L); booking.setStatus("RELEASED");
when(oceanBookings.find(99L)).thenReturn(booking);
ContainerBookingEntity container = new ContainerBookingEntity(); container.setId(88L);
when(oceanBookings.containerBooking(88L)).thenReturn(container);
var allocation = new OceanBookingContainerAllocationEntity();
allocation.setContainerBookingId(88L);
when(oceanBookings.allocations(99L)).thenReturn(java.util.List.of(allocation));
when(loadingPlans.plan(77L)).thenReturn(null);
assertThatThrownBy(() -> service.create(7L, "admin", request))
.isInstanceOf(BizException.class).hasMessageContaining("装柜计划不存在");
verify(repository, never()).insert(any());
}
@Test void actionAdvancesMainLifecycleAndWritesIdempotentOperation() {
TruckAppointmentEntity e = entity(TruckAppointmentStatus.DRAFT, 0);
when(repository.find(1L)).thenReturn(e);