fix(lastleg): keep inventory warehouse snapshots canonical

This commit is contained in:
2026-09-08 16:16:20 +08:00
parent 6908969307
commit 40fe0ba0e1
16 changed files with 182 additions and 21 deletions
@@ -9,6 +9,8 @@ import com.baiyue.lastleg.inventory.query.mapper.InventoryQueryMapper;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Update;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -82,6 +84,22 @@ class InventorySchemaContractTest {
assertFalse(sql.contains("sku_code"));
}
@Test
void balanceQueriesHideZeroRowsAndMutationsKeepWarehouseDimensionCanonical() throws Exception {
assertTrue(InventoryQueryMapper.BALANCE_FILTER.contains("procurement_packages)>0"));
assertTrue(InventoryQueryMapper.JOINED_BALANCE_FILTER.contains("b.procurement_packages)>0"));
String bindSql = String.join(" ", com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper.class
.getMethod("bindInboundPlan", String.class, String.class, Long.class, String.class,
String.class, java.time.LocalDateTime.class)
.getAnnotation(Update.class).value());
assertTrue(bindSql.contains("overseas_warehouse_id=#{overseasWarehouseId}"));
String deleteSql = String.join(" ", com.baiyue.lastleg.inventory.command.mapper.InventoryCommandMapper.class
.getMethod("deleteEmptyBalance", String.class, Long.class)
.getAnnotation(Delete.class).value());
assertTrue(deleteSql.contains("in_transit_packages=0"));
assertTrue(deleteSql.contains("NOT EXISTS"));
}
@Test
void incrementalMigrationIsAdditiveAndRerunnable() throws IOException {
String migration = Files.readString(Path.of("..", "scripts", "db", "incremental.sql"), StandardCharsets.UTF_8)
@@ -140,6 +140,7 @@ class InventoryCommandServiceTest {
source.setInTransitPackages(12L);
when(balances.lockDimension("100", "WH-1", "ONT8", 101L, "IN-CODE-1")).thenReturn(target);
when(commands.lockInboundTransitBalances("100", 101L, "IN-CODE-1")).thenReturn(List.of(source));
when(commands.deleteEmptyBalance("100", 201L)).thenReturn(1);
InventoryCommandResponse result = service.stockIn("100", "7",
stockIn("IN-1", "stock-in-cross-warehouse", 12, 24));
@@ -152,6 +153,40 @@ class InventoryCommandServiceTest {
assertEquals(-12L, written.getAllValues().get(0).getDeltaPackages());
assertEquals("STOCK_IN", written.getAllValues().get(1).getBusinessType());
assertEquals("IN_TRANSIT", written.getAllValues().get(1).getStatusFrom());
verify(commands).deleteEmptyBalance("100", 201L);
}
@Test
void receivingWarehouseChangeRebindsOnlyInTransitBalanceAndWritesZeroDeltaAudit() {
InventoryBalance balance = balance(200L, 0);
balance.setInTransitPackages(12L);
when(commands.lockInboundBalances("100", 101L)).thenReturn(List.of(balance));
when(balances.lockDimension("100", "900", "ONT8", 101L, "IN-CODE-1")).thenReturn(null);
service.rebindReceivingWarehouse("100", 101L, 900L, "US-NYC-01", "纽约仓",
"admin", "change-1");
assertEquals("900", balance.getOverseasWarehouseId());
assertEquals("US-NYC-01", balance.getOverseasWarehouseCode());
assertEquals("纽约仓", balance.getOverseasWarehouseName());
ArgumentCaptor<InventoryLedger> audit = ArgumentCaptor.forClass(InventoryLedger.class);
verify(ledgers).insert(audit.capture());
assertEquals("RECEIVING_WAREHOUSE_CHANGED", audit.getValue().getBusinessType());
assertEquals(0L, audit.getValue().getDeltaPackages());
assertEquals(12L, audit.getValue().getBeforePackages());
assertEquals(12L, audit.getValue().getAfterPackages());
}
@Test
void receivingWarehouseChangeRejectsPhysicalInventoryBeforeAnySnapshotMutation() {
InventoryBalance balance = balance(200L, 1);
when(commands.lockInboundBalances("100", 101L)).thenReturn(List.of(balance));
assertThrows(ResponseStatusException.class, () -> service.rebindReceivingWarehouse(
"100", 101L, 900L, "US-NYC-01", "纽约仓", "admin", "change-physical"));
verify(balances, never()).updateById(any(InventoryBalance.class));
verify(ledgers, never()).insert(any(InventoryLedger.class));
}
@Test
@@ -311,6 +346,7 @@ class InventoryCommandServiceTest {
InventoryBalance value = new InventoryBalance();
value.setId(id); value.setCustomerId("100"); value.setCustomerName("Customer 100");
value.setOverseasWarehouseId("WH-1");
value.setOverseasWarehouseCode("WH1"); value.setOverseasWarehouseName("Warehouse 1");
value.setDestinationWarehouseCode("ONT8"); value.setInboundOrderId(101L);
value.setInboundOrderNo("IN-1"); value.setInboundCode("IN-CODE-1");
value.setAvailablePackages(available);