fix: 按物理箱贯通一件代发履约箱数

This commit is contained in:
2026-09-16 20:49:35 +08:00
parent 8797c0bef9
commit 545ad2083d
34 changed files with 779 additions and 132 deletions
@@ -0,0 +1,41 @@
package com.baiyue.lastleg.discard;
import com.baiyue.lastleg.discard.mapper.CargoDiscardInventoryMapper;
import org.apache.ibatis.annotations.Select;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class CargoDiscardPhysicalCartonMapperContractTest {
@Test
void candidatesJoinSkuFactsButCountAvailableOrdersPhysically() throws Exception {
String candidates = select("candidates", String.class, String.class);
assertTrue(candidates.contains("JOIN ll_dropship_carton_sku cs"));
assertTrue(candidates.contains("cs.carton_id=c.id"));
assertTrue(candidates.contains("COUNT(c.id) available_packages"));
String physicalTotal = select("countAvailableOrder", String.class, Long.class);
assertTrue(physicalTotal.contains("COUNT(*) FROM ll_dropship_carton"));
assertTrue(!physicalTotal.contains("ll_dropship_carton_sku"));
}
@Test
void skuSelectionResolvesThroughPhysicalCartonSkuFacts() throws Exception {
String count = select("countAvailable", String.class, Long.class, String.class);
String lock = select("lockAvailable", String.class, Long.class, String.class, int.class);
for (String sql : new String[] {count, lock}) {
assertTrue(sql.contains("EXISTS (SELECT 1 FROM ll_dropship_carton_sku cs"));
assertTrue(sql.contains("cs.carton_id=c.id"));
assertTrue(sql.contains("cs.sku_code=#{skuCode}"));
}
assertTrue(lock.contains("FOR UPDATE"));
}
private String select(String method, Class<?>... parameterTypes) throws Exception {
Select annotation = CargoDiscardInventoryMapper.class.getMethod(method, parameterTypes)
.getAnnotation(Select.class);
assertNotNull(annotation);
return String.join("", annotation.value());
}
}
@@ -6,8 +6,16 @@ import com.baiyue.lastleg.discard.entity.CargoDiscardItem;
import com.baiyue.lastleg.discard.mapper.CargoDiscardInventoryMapper;
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
import com.baiyue.lastleg.dropship.entity.DropshipCartonLedger;
import com.baiyue.lastleg.dropship.entity.DropshipCartonSku;
import com.baiyue.lastleg.dropship.entity.DropshipOrderProfile;
import com.baiyue.lastleg.dropship.entity.DropshipSkuInventory;
import com.baiyue.lastleg.dropship.mapper.DropshipCartonLedgerMapper;
import com.baiyue.lastleg.dropship.mapper.DropshipCartonSkuMapper;
import com.baiyue.lastleg.dropship.mapper.DropshipOrderProfileMapper;
import com.baiyue.lastleg.dropship.mapper.DropshipSkuInventoryMapper;
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
import com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper;
import com.baiyue.lastleg.inventory.mapper.InventoryPositionMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -37,6 +45,11 @@ import static org.mockito.Mockito.when;
class CargoDiscardInventoryAdjustmentServiceTest {
@Mock CargoDiscardInventoryMapper inventory;
@Mock DropshipCartonLedgerMapper ledgers;
@Mock DropshipCartonSkuMapper cartonSkus;
@Mock DropshipSkuInventoryMapper skuInventories;
@Mock DropshipOrderProfileMapper profiles;
@Mock InventoryPositionMapper positions;
@Mock InventoryBalanceMapper balances;
private CargoDiscardInventoryAdjustmentService service;
@BeforeEach
@@ -44,6 +57,45 @@ class CargoDiscardInventoryAdjustmentServiceTest {
service = new CargoDiscardInventoryAdjustmentService();
ReflectionTestUtils.setField(service, "inventory", inventory);
ReflectionTestUtils.setField(service, "cartonLedgers", ledgers);
ReflectionTestUtils.setField(service, "cartonSkus", cartonSkus);
ReflectionTestUtils.setField(service, "skuInventories", skuInventories);
ReflectionTestUtils.setField(service, "profiles", profiles);
ReflectionTestUtils.setField(service, "positions", positions);
ReflectionTestUtils.setField(service, "balances", balances);
}
@Test
void pdaDiscardDeductsEverySkuInsideOnePhysicalCartonOnce() {
CargoDiscardApplication application = application(1);
CargoDiscardItem item = item(1);
item.setProfileId(201L);
DropshipCarton carton = carton(1L);
carton.setSkuCode("MIXED"); carton.setProductQuantity(5L);
DropshipCartonSku skuA = cartonSku("SKU-A", 2L);
DropshipCartonSku skuB = cartonSku("SKU-B", 3L);
DropshipOrderProfile profile = new DropshipOrderProfile();
profile.setId(201L); profile.setCustomerId("100"); profile.setInventoryPositionId(801L);
InventoryPosition position = new InventoryPosition();
position.setId(801L); position.setBalanceId(901L);
when(inventory.lockSkuInventory("100", 301L)).thenReturn(sku(5));
when(inventory.lockCarton("100", 1L)).thenReturn(carton);
when(cartonSkus.listCarton("100", 1L)).thenReturn(List.of(skuA, skuB));
when(skuInventories.deduct("100", 201L, "SKU-A", 1, 2)).thenReturn(1);
when(skuInventories.deduct("100", 201L, "SKU-B", 1, 3)).thenReturn(1);
when(profiles.selectById(201L)).thenReturn(profile);
when(positions.findTenantPosition("100", 801L)).thenReturn(position);
when(positions.deductAvailable("100", 801L, 1)).thenReturn(1);
when(balances.deductAvailable("100", 901L, 1)).thenReturn(1);
when(inventory.changeCartonStatus("100", 1L, "DISCARD_PENDING", "DISCARDED")).thenReturn(1);
when(inventory.skuPackages("100", 301L)).thenReturn(4L);
var result = service.discardPalletItem("100", application, item, List.of(link(1L)),
1, "operator", LocalDateTime.now());
assertEquals(1, result.discardedPackages());
verify(skuInventories).deduct("100", 201L, "SKU-A", 1, 2);
verify(skuInventories).deduct("100", 201L, "SKU-B", 1, 3);
verify(positions).deductAvailable("100", 801L, 1);
}
@Test
@@ -105,4 +157,8 @@ class CargoDiscardInventoryAdjustmentServiceTest {
private DropshipCarton carton(long id) {
DropshipCarton value = new DropshipCarton(); value.setId(id); value.setCartonMark("C-" + id); return value;
}
private DropshipCartonSku cartonSku(String skuCode, long quantity) {
DropshipCartonSku value = new DropshipCartonSku();
value.setSkuCode(skuCode); value.setProductQuantity(quantity); return value;
}
}
@@ -10,6 +10,7 @@ import com.baiyue.lastleg.discard.mapper.CargoDiscardCartonMapper;
import com.baiyue.lastleg.discard.mapper.CargoDiscardInventoryMapper;
import com.baiyue.lastleg.discard.mapper.CargoDiscardItemMapper;
import com.baiyue.lastleg.discard.mapper.CargoDiscardStatusHistoryMapper;
import com.baiyue.lastleg.discard.model.CargoDiscardCandidateRow;
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
import com.baiyue.lastleg.dropship.entity.DropshipSkuInventory;
import com.baiyue.lastleg.entity.LastlegOrder;
@@ -102,6 +103,20 @@ class CargoDiscardServiceTest {
verify(inventory, never()).deductSkuInventory(any(), anyLong(), anyInt());
}
@Test
void candidateTotalCountsPhysicalCartonsInsteadOfSkuRows() {
CargoDiscardCandidateRow skuA = candidate("SKU-A", 20L);
CargoDiscardCandidateRow skuB = candidate("SKU-B", 20L);
when(inventory.candidates("100", "RK-1")).thenReturn(List.of(skuA, skuB));
when(inventory.countAvailableOrder("100", 101L)).thenReturn(20L);
var result = service.candidates("100", "RK-1");
assertEquals(1, result.size());
assertEquals(20, result.get(0).availablePackages());
assertEquals(2, result.get(0).skus().size());
}
@Test
void approvalPushesToPdaWithoutDeductingInventory() {
CargoDiscardApplication application = pendingApplication();
@@ -179,4 +194,12 @@ class CargoDiscardServiceTest {
value.setCustomerId("100"); value.setCartonId(cartonId); value.setCartonMark("C-" + cartonId);
return value;
}
private CargoDiscardCandidateRow candidate(String skuCode, long packages) {
CargoDiscardCandidateRow value = new CargoDiscardCandidateRow();
value.setOrderId(101L); value.setInboundCode("RK-1"); value.setInboundOrderNo("IN-1");
value.setOverseasWarehouseId("WH-1"); value.setOverseasWarehouseName("LA");
value.setSkuCode(skuCode); value.setProductName(skuCode); value.setAvailablePackages(packages);
return value;
}
}