贴标申请,仓储转运

This commit is contained in:
2026-09-20 15:06:17 +08:00
parent a7d458cddd
commit 02844da360
56 changed files with 2121 additions and 111 deletions
@@ -1,6 +1,8 @@
package com.baiyue.lastleg.palletops.controller;
import com.baiyue.lastleg.palletops.dto.PalletOperationResponses;
import com.baiyue.lastleg.palletops.mapper.PdaPalletOperationMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.annotations.Select;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -8,6 +10,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@@ -35,4 +38,21 @@ class PdaPalletOperationControllerContractTest {
assertFalse(sql.contains("<"));
assertFalse(sql.contains(">"));
}
@Test void relabelSourceAndResolvedPalletSerializeSnowflakeIdsAsStrings() throws Exception {
ObjectMapper mapper = new ObjectMapper();
var source = new PalletOperationResponses.RelabelSource(2100204001227157507L, 2L,
2100203890682015746L, "PLT-1", "LOC-1", "IN-1", 1L, 1L, List.of("C-1"));
var content = new PalletOperationResponses.PalletContent(2100203890682015746L, "PLT-1",
"OCCUPIED", 1, 2092783373163335682L, "LOC-1", null, 1L, List.of());
assertEquals("2100204001227157507", mapper.readTree(mapper.writeValueAsString(source))
.path("positionId").textValue());
assertEquals("2100203890682015746", mapper.readTree(mapper.writeValueAsString(source))
.path("palletId").textValue());
assertEquals("2100203890682015746", mapper.readTree(mapper.writeValueAsString(content))
.path("palletId").textValue());
assertEquals("2092783373163335682", mapper.readTree(mapper.writeValueAsString(content))
.path("locationId").textValue());
}
}
@@ -9,6 +9,7 @@ import org.springframework.web.client.RestClient;
import org.springframework.web.server.ResponseStatusException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@@ -37,4 +38,23 @@ class HttpPalletPhysicalGatewayTest {
.hasMessageContaining("404");
server.verify();
}
@Test
void resolveIgnoresNewWarehousePalletMetadata() {
server.expect(requestTo("http://warehouse/internal/v1/warehouse-pallets/resolve/PAL-1"))
.andRespond(withSuccess("""
{"code":"200","message":"success","data":{"palletId":"30","palletCode":"PAL-1",
"warehouseId":"88","locationId":"40","status":"IDLE","fbaWarehouseCode":"XLX1",
"unitPrice":1.00,"version":2,"locationType":"VIRTUAL","locationStatus":"ACTIVE",
"reservable":true,"reservationBlockReason":null},
"timestamp":"2026-09-19T03:18:35.283336500Z"}
""", MediaType.APPLICATION_JSON));
var result = gateway.resolve("PAL-1");
assertThat(result.palletId()).isEqualTo(30L);
assertThat(result.palletCode()).isEqualTo("PAL-1");
assertThat(result.fbaWarehouseCode()).isEqualTo("XLX1");
server.verify();
}
}
@@ -18,6 +18,11 @@ import com.baiyue.lastleg.relabel.entity.RelabelItem;
import com.baiyue.lastleg.relabel.mapper.RelabelApplicationMapper;
import com.baiyue.lastleg.relabel.mapper.RelabelItemMapper;
import com.baiyue.lastleg.relabel.service.RelabelPalletMutationService;
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton;
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCartonItem;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryBalanceMapper;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonItemMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -62,6 +67,9 @@ class PdaPalletOperationServiceTest {
@Mock private RelabelApplicationMapper relabelApplications;
@Mock private RelabelItemMapper relabelItems;
@Mock private RelabelPalletMutationService relabelPalletMutations;
@Mock private ReturnInventoryCartonMapper returnCartons;
@Mock private ReturnInventoryCartonItemMapper returnCartonItems;
@Mock private ReturnInventoryBalanceMapper returnBalances;
private PdaPalletOperationService service;
@BeforeEach void setUp() {
@@ -75,10 +83,44 @@ class PdaPalletOperationServiceTest {
ReflectionTestUtils.setField(service, "relabelApplications", relabelApplications);
ReflectionTestUtils.setField(service, "relabelItems", relabelItems);
ReflectionTestUtils.setField(service, "relabelPalletMutations", relabelPalletMutations);
ReflectionTestUtils.setField(service, "returnCartons", returnCartons);
ReflectionTestUtils.setField(service, "returnCartonItems", returnCartonItems);
ReflectionTestUtils.setField(service, "returnBalances", returnBalances);
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper().findAndRegisterModules());
service.configureTransactions(new NoOpTransactionManager());
}
@Test void partialReturnRelabelKeepsUnlabelledRemainderOnOriginalPallet() {
RelabelApplication app = new RelabelApplication(); app.setId(600L); app.setCustomerId("100"); app.setRelabelNo("RL-1");
RelabelItem item = new RelabelItem(); item.setId(701L); item.setSkuCode("SKU-1");
item.setReturnCartonId(801L); item.setDestinationFbaWarehouseCode("XLX6");
ReturnInventoryCarton original = new ReturnInventoryCarton(); original.setId(801L);
original.setCustomerId("100"); original.setOverseasWarehouseId("88");
original.setTotalQuantity(100L); original.setPalletCode("OLD");
ReturnInventoryCartonItem originalLine = new ReturnInventoryCartonItem();
originalLine.setId(901L); originalLine.setSkuCode("SKU-1"); originalLine.setQuantity(100L);
when(relabelItems.selectList(any())).thenReturn(List.of(item));
when(returnCartonItems.lockCarton(801L)).thenReturn(List.of(originalLine));
when(returnCartonItems.updateById(any(ReturnInventoryCartonItem.class))).thenReturn(1);
when(returnCartons.releasePartial(801L, "100", 600L, 70L)).thenReturn(1);
when(returnCartons.insert(any(ReturnInventoryCarton.class))).thenReturn(1);
when(returnCartonItems.insert(any(ReturnInventoryCartonItem.class))).thenReturn(1);
when(returnBalances.adjustCartonQuantity("100", "88", "SKU-1", 1)).thenReturn(1);
when(relabelItems.updateById(any(RelabelItem.class))).thenReturn(1);
ReflectionTestUtils.invokeMethod(service, "splitReturnRelabelCarton", app, item, original,
pallet(30L, "NEW-XLX6", 88L, 0), 30L);
assertEquals(70L, originalLine.getQuantity());
var moved = ArgumentCaptor.forClass(ReturnInventoryCarton.class);
verify(returnCartons).insert(moved.capture());
assertEquals(30L, moved.getValue().getTotalQuantity());
assertEquals("NEW-XLX6", moved.getValue().getPalletCode());
assertEquals("XLX6", moved.getValue().getDestinationWarehouseCode());
assertEquals(moved.getValue().getId(), item.getReturnCartonId());
verify(returnBalances).adjustCartonQuantity("100", "88", "SKU-1", 1);
}
@Test void resolveRejectsPalletOutsideTokenFrozenWarehouse() {
when(physical.resolve("P-1")).thenReturn(pallet(10L, "P-1", 99L, 1));
assertThrows(ResponseStatusException.class, () -> service.resolve(identity(),
@@ -100,7 +142,7 @@ class PdaPalletOperationServiceTest {
RelabelApplication application = new RelabelApplication(); application.setRelabelNo("RL-1");
application.setStatus("READY_FOR_OUTBOUND"); application.setOverseasWarehouseId("88");
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(application);
when(physical.ensureRelabelPallet(88L, "RL-1:new-pallet-1")).thenReturn(
when(physical.ensureRelabelPallet(88L, "RL-1:new-pallet-1", null)).thenReturn(
new PalletPhysicalGateway.PalletReference(30L, "PAL-NEW-1", 88L, 1030L, "IDLE", null, 0));
var result = service.createRelabelPallet(identity(),
@@ -358,6 +400,27 @@ class PdaPalletOperationServiceTest {
assertEquals(java.util.Set.of(), ReflectionTestUtils.invokeMethod(service, "boundRelabelMarks", app));
}
@Test void relabelSourcesExposeAuthoritativePalletId() {
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
RelabelApplication 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);
RelabelItem item = relabelItem(701L, "CARTON-A", 100L);
when(relabelItems.selectList(any())).thenReturn(List.of(item));
when(positions.selectById(100L)).thenReturn(position(100L, 20L, "DISPLAY-CODE", 1L, 3L));
PalletInventoryRow source = row(100L, 20L, 3L, 0L); source.setPalletNo("CANONICAL-CODE");
source.setHoldPackages(1L);
when(mapper.relabelSources("100", "88", 200L)).thenReturn(List.of(source));
var result = service.relabelSources(identity(), new PalletOperationRequests.RelabelSources("RL-1"));
assertEquals(1, result.size());
assertEquals(20L, result.get(0).palletId());
assertEquals("CANONICAL-CODE", result.get(0).palletCode());
}
@Test void createsPalletBeforeCustomerConfirmationOnlyForClaimingOperator() {
var tasks = mock(com.baiyue.lastleg.relabel.pda.mapper.PdaRelabelTaskMapper.class);
ReflectionTestUtils.setField(service, "relabelWorkTasks", tasks);
@@ -366,7 +429,7 @@ class PdaPalletOperationServiceTest {
when(relabelApplications.findAnyByRelabelNo("RL-1")).thenReturn(app);
var task = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelTask(); task.setStatus("PROCESSING"); task.setOperatorKey("7");
when(tasks.find("100", 600L)).thenReturn(task);
when(physical.ensureRelabelPallet(88L, "RL-1:before-confirm")).thenReturn(pallet(30L, "NEW", 88L, 0));
when(physical.ensureRelabelPallet(88L, "RL-1:before-confirm", null)).thenReturn(pallet(30L, "NEW", 88L, 0));
assertEquals("NEW", service.createRelabelPallet(identity(), new PalletOperationRequests.NewRelabelPallet("RL-1", "before-confirm")).palletCode());
task.setOperatorKey("other");
assertThrows(ResponseStatusException.class, () -> service.createRelabelPallet(identity(), new PalletOperationRequests.NewRelabelPallet("RL-1", "different")));