Merge remote-tracking branch 'origin/test' into test
This commit is contained in:
+13
@@ -5,6 +5,8 @@ import org.apache.ibatis.annotations.Select;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -187,6 +189,17 @@ class DispatchCandidateMapperContractTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void relabelCandidatesReadWeightFromWarehouseTransferPalletSnapshot() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchCandidateMapper.java"));
|
||||
int start = source.indexOf("List<DispatchPalletCandidate> relabelAvailable");
|
||||
int end = source.indexOf("List<DispatchPalletCandidate> nativeReturnRelabelAvailable");
|
||||
String sql = source.substring(source.lastIndexOf("@Select", start), end);
|
||||
assertTrue(sql.contains("MAX(wtp.gross_weight_kg) AS grossWeightKg"));
|
||||
assertTrue(sql.contains("MAX(wtp.volume_cbm) AS volumeCbm"));
|
||||
assertTrue(sql.contains("wtp.warehouse_pallet_id=pos.pallet_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void candidateGrossWeightUsesPhysicalSourcesAndNeverBillingVolumeWeight() throws Exception {
|
||||
for (Method method : List.of(
|
||||
|
||||
+5
@@ -25,6 +25,11 @@ class DispatchPhysicalWeightTest {
|
||||
int to = sql.indexOf(" AS grossWeightKg,");
|
||||
if (from < 0 || to < 0) continue;
|
||||
String projection = sql.substring(from + "AS volumeWeightKg,".length(), to);
|
||||
if (projection.contains("wtp.gross_weight_kg")) {
|
||||
assertThat(jdbc.queryForObject("SELECT " + projection + " FROM (SELECT CAST(NULL AS DECIMAL(12,3)) gross_weight_kg) wtp", BigDecimal.class)).isNull();
|
||||
assertThat(jdbc.queryForObject("SELECT " + projection + " FROM (SELECT 80 gross_weight_kg) wtp", BigDecimal.class)).isEqualByComparingTo("80");
|
||||
continue;
|
||||
}
|
||||
String query = "SELECT " + projection + " FROM (SELECT '10' AS customer_id) ip "
|
||||
+ "CROSS JOIN (SELECT 1 AS order_id,10 AS volume_cbm) l "
|
||||
+ "CROSS JOIN (SELECT 1 AS line_id,5 AS allocated_volume_cbm) a "
|
||||
|
||||
+2
@@ -65,11 +65,13 @@ class DispatchServiceTest {
|
||||
@Mock com.baiyue.lastleg.fleet.trip.FleetDispatchBindingGuard fleetBindings;
|
||||
@Mock com.baiyue.lastleg.fleet.trip.FleetDispatchWorkflowQuery fleetWorkflow;
|
||||
@Mock ReturnRelabelDispatchStock returnRelabelStock;
|
||||
@Mock com.baiyue.lastleg.relabel.service.RelabelPalletMeasurementService relabelMeasurements;
|
||||
private DispatchService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new DispatchService();
|
||||
ReflectionTestUtils.setField(service, "relabelMeasurements", relabelMeasurements);
|
||||
ReflectionTestUtils.setField(service, "fleetWorkflow", fleetWorkflow);
|
||||
ReflectionTestUtils.setField(service, "fleetBindings", fleetBindings);
|
||||
ReflectionTestUtils.setField(service, "returnRelabelStock", returnRelabelStock);
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class PdaPalletOperationControllerContractTest {
|
||||
.filter(PostMapping.class::isInstance).map(PostMapping.class::cast)
|
||||
.flatMap(annotation -> Arrays.stream(annotation.value())).collect(Collectors.toSet());
|
||||
assertEquals(Set.of("/pallets/resolve", "/relabel-pallet-label", "/assemble", "/disassemble",
|
||||
"/relabel-disassemble", "/relabel-sources", "/swap", "/unbind"), paths);
|
||||
"/relabel-disassemble", "/relabel-sources", "/relabel-pallet-measure", "/relabel-pallet-measurements", "/swap", "/unbind"), paths);
|
||||
}
|
||||
|
||||
@Test void palletContentAnnotationUsesNativeGreaterThanOperator() throws Exception {
|
||||
|
||||
+32
-3
@@ -138,14 +138,14 @@ class PdaPalletOperationServiceTest {
|
||||
new PalletOperationRequests.PalletExpectation("SOURCE", 1),
|
||||
new PalletOperationRequests.PalletExpectation("TARGET", 2), List.of("BOX-1"), "rebind");
|
||||
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service,
|
||||
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request));
|
||||
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request, false));
|
||||
verifyNoInteractions(physical);
|
||||
var binding = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory();
|
||||
binding.setDetailJson("{\"round\":\"INITIAL\",\"cartonMarks\":[\"BOX-1\"]}");
|
||||
when(workHistory.selectList(any())).thenReturn(List.of(binding));
|
||||
task.setReviewedAt(LocalDateTime.of(2026, 10, 12, 12, 0));
|
||||
assertThrows(ResponseStatusException.class, () -> ReflectionTestUtils.invokeMethod(service,
|
||||
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request));
|
||||
"bindReturnRelabelPallet", identity(), app, List.of(item), source, target, request, false));
|
||||
task.setReviewedAt(null);
|
||||
when(physical.resolveLocation(88L, 1020L)).thenReturn(
|
||||
new PalletPhysicalGateway.LocationReference(1020L, "SOURCE-LOC", "STORAGE", "ACTIVE"));
|
||||
@@ -155,7 +155,7 @@ class PdaPalletOperationServiceTest {
|
||||
when(physical.resolve("TARGET")).thenReturn(target);
|
||||
var result = (com.baiyue.lastleg.palletops.dto.PalletOperationResponses.Operation)
|
||||
ReflectionTestUtils.invokeMethod(service, "bindReturnRelabelPallet", identity(), app,
|
||||
List.of(item), source, target, request);
|
||||
List.of(item), source, target, request, false);
|
||||
assertEquals("TARGET", box.getPalletCode());
|
||||
assertEquals(0, result.pallets().get(0).totalPackages());
|
||||
assertEquals(2, result.pallets().get(1).totalPackages());
|
||||
@@ -584,6 +584,35 @@ class PdaPalletOperationServiceTest {
|
||||
assertThrows(ResponseStatusException.class, () -> service.createRelabelPallet(identity(), new PalletOperationRequests.NewRelabelPallet("RL-1", "different")));
|
||||
}
|
||||
|
||||
@Test void wholeRelabelCanRetainOriginalPalletWithoutMovingStockAndPartialCannot() {
|
||||
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
|
||||
var histories = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelHistoryMapper.class);
|
||||
ReflectionTestUtils.setField(service,"relabelWorkTasks",tasks); ReflectionTestUtils.setField(service,"relabelWorkHistory",histories);
|
||||
var app = new RelabelApplication();app.setId(600L);app.setCustomerId("100");app.setRelabelNo("RL-1");
|
||||
app.setOverseasWarehouseId("88");app.setStatus("READY_FOR_OUTBOUND");app.setFulfillmentStatus("WAIT_PRE_DISPATCH");
|
||||
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
when(relabelApplications.lockAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask();task.setId(900L);task.setStatus("COMPLETED");
|
||||
when(tasks.find("100",600L)).thenReturn(task);
|
||||
var item = relabelItem(701L,"CARTON-A",100L);
|
||||
when(relabelItems.selectList(any())).thenReturn(List.of(item));
|
||||
when(relabelApplications.selectById(600L)).thenReturn(app);
|
||||
when(physical.resolve("SOURCE")).thenReturn(pallet(10L,"SOURCE",88L,0));
|
||||
when(physical.resolveLocation(88L,1010L)).thenReturn(new PalletPhysicalGateway.LocationReference(1010L,"LOC-1010","STORAGE","ACTIVE"));
|
||||
var position = position(100L,10L,"SOURCE",1,0);when(positions.selectById(100L)).thenReturn(position);
|
||||
var row = row(100L,10L,0,0);row.setHoldPackages(1L);
|
||||
when(mapper.lockPosition("88",100L)).thenReturn(row);when(mapper.content("88",10L)).thenReturn(List.of(row));
|
||||
when(mapper.palletPackages("88",10L)).thenReturn(1L);
|
||||
var request = new PalletOperationRequests.RelabelDisassemble("retain-1","RL-1",
|
||||
new PalletOperationRequests.PalletExpectation("SOURCE",0),new PalletOperationRequests.PalletExpectation("SOURCE",0),List.of("CARTON-A"),"整托贴标");
|
||||
var result = service.relabelDisassemble(identity(),request);
|
||||
assertEquals("COMPLETED",result.status()); assertEquals(1,result.pallets().size());
|
||||
verify(positions,never()).updateById(any(InventoryPosition.class)); verifyNoInteractions(relabelPalletMutations,ledgers);
|
||||
verify(histories).insert(any(com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory.class));
|
||||
when(mapper.palletPackages("88",10L)).thenReturn(2L);
|
||||
assertTrue(assertThrows(ResponseStatusException.class,() -> service.relabelDisassemble(identity(),request)).getReason().contains("部分贴标"));
|
||||
}
|
||||
|
||||
private static PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("7", "picker", 88L); }
|
||||
private static PalletPhysicalGateway.PalletReference pallet(long id, String code, long warehouse, int version) {
|
||||
return new PalletPhysicalGateway.PalletReference(id, code, warehouse, 1000L + id,
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package com.baiyue.lastleg.relabel.service;
|
||||
|
||||
import com.baiyue.lastleg.relabel.mapper.*;
|
||||
import com.baiyue.lastleg.relabel.entity.*;
|
||||
import com.baiyue.lastleg.relabel.pda.entity.*;
|
||||
import com.baiyue.lastleg.relabel.pda.mapper.*;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
|
||||
class RelabelPalletMeasurementServiceTest {
|
||||
final RelabelPalletMeasurementService service = new RelabelPalletMeasurementService();
|
||||
final RelabelPalletMeasurementMapper mapper = mock(RelabelPalletMeasurementMapper.class);
|
||||
final RelabelApplicationMapper apps = mock(RelabelApplicationMapper.class);
|
||||
final RelabelItemMapper items = mock(RelabelItemMapper.class);
|
||||
final PdaRelabelHistoryMapper histories = mock(PdaRelabelHistoryMapper.class);
|
||||
final PdaRelabelTaskMapper tasks = mock(PdaRelabelTaskMapper.class);
|
||||
final RelabelApplication app = new RelabelApplication();
|
||||
final List<PdaRelabelHistory> records = new ArrayList<>();
|
||||
final ObjectMapper json = new ObjectMapper();
|
||||
@BeforeEach void setup() {
|
||||
ReflectionTestUtils.setField(service,"mapper",mapper); ReflectionTestUtils.setField(service,"applications",apps);
|
||||
ReflectionTestUtils.setField(service,"items",items); ReflectionTestUtils.setField(service,"histories",histories);
|
||||
ReflectionTestUtils.setField(service,"tasks",tasks); ReflectionTestUtils.setField(service,"json",json);
|
||||
app.setId(1L);app.setCustomerId("7");app.setRelabelNo("RL-1");app.setOverseasWarehouseId("92");
|
||||
app.setStatus("READY_FOR_OUTBOUND");app.setFulfillmentStatus("WAIT_PRE_DISPATCH");
|
||||
when(apps.findAnyByRelabelNo("RL-1")).thenReturn(app);when(apps.lockAnyByRelabelNo("RL-1")).thenReturn(app);
|
||||
when(mapper.transfer("7","RL-1")).thenReturn(10L);
|
||||
when(mapper.originals("7",10L)).thenReturn(List.of(new RelabelPalletMeasurementMapper.Original(100L,"OLD",10,
|
||||
new BigDecimal("100"),new BigDecimal("100"),new BigDecimal("100"),new BigDecimal("80"),BigDecimal.ONE)));
|
||||
when(mapper.stock("7","92")).thenReturn(List.of(stock(1,100,"OLD",10,1)));
|
||||
when(items.selectList(any())).thenReturn(List.of());
|
||||
when(histories.selectList(any())).thenAnswer(i -> List.copyOf(records));
|
||||
when(histories.insert(any(PdaRelabelHistory.class))).thenAnswer(i -> { records.add(i.getArgument(0));return 1; });
|
||||
var task = new PdaRelabelTask(); task.setId(2L); task.setStatus("COMPLETED");
|
||||
when(tasks.find("7",1L)).thenReturn(task);
|
||||
}
|
||||
RelabelPalletMeasurementMapper.Stock stock(long id,long pallet,String code,long count,long version) {
|
||||
return new RelabelPalletMeasurementMapper.Stock(id,pallet,code,count,version);
|
||||
}
|
||||
@Test void wholeOriginalPalletInheritsWithoutInventingOrRescalingMeasurements() {
|
||||
var p = service.snapshots(app).get(0);assertTrue(p.inherited()); assertEquals(new BigDecimal("80"),p.grossWeightKg());
|
||||
assertEquals(BigDecimal.ONE,p.volumeCbm());assertDoesNotThrow(() -> service.requireMeasured(app));
|
||||
}
|
||||
@Test void partialSplitRequiresBothNewPalletAndOriginalRemainderMeasurements() throws Exception {
|
||||
split(); var values = service.snapshots(app);assertEquals(2,values.size());
|
||||
assertTrue(values.stream().allMatch(p -> p.volumeCbm()==null && p.grossWeightKg()==null));
|
||||
assertThrows(ResponseStatusException.class,() -> service.requireMeasured(app));
|
||||
}
|
||||
@Test void explicitFinalMeasurementsAreAuditedAndReplayDoesNotDuplicateFacts() throws Exception {
|
||||
split();
|
||||
for (var p : service.snapshots(app)) {
|
||||
var request = new RelabelPalletMeasurementService.Measure("RL-1",p.palletCode(),"measure-"+p.palletId(),p.stockVersion(),
|
||||
new BigDecimal("100"),new BigDecimal("50"),new BigDecimal("50"),new BigDecimal("40"));
|
||||
service.save(identity(),request);service.save(identity(),request);
|
||||
}
|
||||
assertEquals(3,records.size()); // One binding, two measurements.
|
||||
assertDoesNotThrow(() -> service.requireMeasured(app));
|
||||
assertTrue(service.snapshots(app).stream().allMatch(p -> p.volumeCbm().compareTo(new BigDecimal("0.25"))==0));
|
||||
when(mapper.stock("7","92")).thenReturn(List.of(stock(1,100,"OLD",5,3),stock(2,200,"NEW",5,1)));
|
||||
assertThrows(ResponseStatusException.class,() -> service.requireMeasured(app));
|
||||
}
|
||||
@Test void staleAndForeignMeasurementsAndAllocatedOrdersAreRejected() {
|
||||
var request = new RelabelPalletMeasurementService.Measure("RL-1","OLD","key","stale",
|
||||
BigDecimal.ONE,BigDecimal.ONE,BigDecimal.ONE,BigDecimal.ONE);
|
||||
assertThrows(ResponseStatusException.class,() -> service.save(identity(),request));
|
||||
app.setOverseasWarehouseId("93"); assertThrows(ResponseStatusException.class,() -> service.list(identity(),"RL-1"));
|
||||
app.setOverseasWarehouseId("92");app.setFulfillmentStatus("PRE_DISPATCH_CREATED");
|
||||
assertThrows(ResponseStatusException.class,() -> service.save(identity(),request));
|
||||
verify(histories,never()).insert(any(PdaRelabelHistory.class));
|
||||
}
|
||||
private void split() throws Exception {
|
||||
when(mapper.stock("7","92")).thenReturn(List.of(stock(1,100,"OLD",5,2),stock(2,200,"NEW",5,1)));
|
||||
when(mapper.movements("7",100L)).thenReturn(1);
|
||||
var binding = new PdaRelabelHistory();binding.setAction("PALLET_BIND");
|
||||
binding.setDetailJson(json.writeValueAsString(Map.of("sourcePallets",List.of("OLD"),"targetPallets",List.of("NEW")))); records.add(binding);
|
||||
}
|
||||
private PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("operator","现场人员",92L); }
|
||||
}
|
||||
Reference in New Issue
Block a user