perf(selfop): page stock keys before sales enrichment

This commit is contained in:
2026-10-13 02:13:56 +08:00
parent 2c8c26490a
commit afd3bbaa3d
2 changed files with 78 additions and 11 deletions
@@ -283,6 +283,55 @@ public class AnalyticsSqlSemanticTest {
var second=inventory(null,30,"PHYSICAL_DESC",1,1);assertEquals("OLD-2",second.get(0).skuCode());
assertEquals(D.minusDays(60),second.get(0).lastOutbound());
}
@Test void stockFirstAllKeepsNullOrderingPageBoundariesThresholdsAndExactScope() throws Exception {
for(String owner:List.of("B","C")){
profile(22,owner,"A","INVENTORY_OBSERVATION",utc(D.minusDays(90),0),"PCS");
stock(owner,"A",0,"100");daily(11,"W",owner,"A",D.minusDays(1),owner.equals("C")?"5":"10");
}
profile(22,"C","B","INVENTORY_OBSERVATION",utc(D.minusDays(90),0),"PCS");stock("C","B",0,"100");
daily(11,"W","C","B",D.minusDays(40),"9");
profile(22,"C","NO-SALES","NONE",null,"PCS");stock("C","NO-SALES",0,"80");
profile(22,"C","UNIT","INVENTORY_OBSERVATION",utc(D.minusDays(90),0),null);stock("C","UNIT",0,"999");
profile(22,"C","UNKNOWN","INVENTORY_OBSERVATION",utc(D.minusDays(90),0),"PCS");
stockExact("UNKNOWN",0,"100",null,"0","0","UNKNOWN","FIELD_MISSING");
daily(99,"W","C","A",D.minusDays(1),"9000");daily(11,"OTHER","C","A",D.minusDays(1),"8000");
profile(22,"C","OTHER-WAREHOUSE","INVENTORY_OBSERVATION",utc(D.minusDays(90),0),"PCS");
try(var statement=schema.createStatement()){statement.execute("UPDATE ll_selfop_sku_profile SET warehouse_code='OTHER' WHERE sku_code='OTHER-WAREHOUSE'");}
var options=new AnalyticsInventoryOptions(null,null,null,90,null,null,null,null);
var p=request("INVENTORY",D.minusDays(30),D,null,null,utc(D,8),0,2);
assertEquals(6L,((Number)literalQuery("inventoryCount",p,options).get(0)).longValue());
var first=inventoryRows(p,options);assertEquals(List.of("B/A","C/A"),first.stream().map(r->r.customerCode()+"/"+r.skuCode()).toList());
assertDecimal("5",first.get(1).outboundQuantity30d());assertDecimal("600",first.get(1).coverageDays());assertEquals(1,first.get(1).aboveThreshold());
var second=inventoryRows(request("INVENTORY",D.minusDays(30),D,null,null,utc(D,8),2,2),options);
assertEquals(List.of("B","NO-SALES"),second.stream().map(AnalyticsReadRows.Inventory::skuCode).toList());
assertEquals(D.minusDays(40),second.get(0).lastOutbound());assertDecimal("0",second.get(0).outboundQuantity30d());
assertNull(second.get(1).outboundQuantity30d());assertTrue(second.get(1).unassessable());
var third=inventoryRows(request("INVENTORY",D.minusDays(30),D,null,null,utc(D,8),4,2),options);
assertEquals(List.of("UNIT","UNKNOWN"),third.stream().map(AnalyticsReadRows.Inventory::skuCode).toList());
assertTrue(third.stream().allMatch(r->r.availableQuantity()==null));assertNull(third.get(0).physicalQuantity());assertDecimal("100",third.get(1).physicalQuantity());
assertTrue(inventoryRows(request("INVENTORY",D.minusDays(30),D,null,null,utc(D,8),6,2),options).isEmpty());
assertEquals(List.of("C"),inventoryRows(request("INVENTORY",D.minusDays(30),D,"C","A",utc(D,8),0,20),options).stream().map(AnalyticsReadRows.Inventory::customerCode).toList());
assertEquals(2,inventoryRows(request("INVENTORY",D.minusDays(30),D,null,"A",utc(D,8),0,20),options).size());
var bucket=new AnalyticsInventoryOptions(null,null,null,null,"DAYS_GT_90","COVERAGE_DISTRIBUTION_V1",null,null);
assertFalse(AnalyticsInventorySql.inventoryPage(Map.of("p",p,"o",bucket)).contains("stock_paged"));
assertEquals(List.of("B/A","C/A"),inventoryRows(p,bucket).stream().map(r->r.customerCode()+"/"+r.skuCode()).toList());
for(String sort:List.of("PHYSICAL_DESC","COVERAGE_DAYS_DESC","OUTBOUND_30D_ASC"))
assertFalse(AnalyticsInventorySql.inventoryPage(Map.of("p",p,"o",new AnalyticsInventoryOptions(null,"ALL",sort,null,null,null,null,null))).contains("stock_paged"));
}
@Test void stockFirstDoesNotTurnUnavailableSalesOrExpiredInventoryIntoKnownValues() throws Exception {
profile(22,"C","SKU","INVENTORY_OBSERVATION",utc(D.minusDays(60),0),"PCS");stock("C","SKU",0,"10");daily(11,"W","C","SKU",D.minusDays(1),"3");
var options=new AnalyticsInventoryOptions(null,null,null,90,null,null,null,null);
var stale=new AnalyticsSqlRequest("demo","W",null,null,11,22,D.minusDays(30),D,D,D.minusDays(30),D.minusDays(30),D,
utc(D.minusDays(30),0),utc(D,8),true,true,true,true,false,0,20,"INVENTORY");
var row=inventoryRows(stale,options).get(0);assertNull(row.physicalQuantity());assertNull(row.availableQuantity());assertDecimal("3",row.ownerOutbound());assertNull(row.coverageDays());
var noSales=new AnalyticsSqlRequest("demo","W",null,null,0,22,D.minusDays(30),D,D,D.minusDays(30),null,null,null,null,false,false,false,false,true,0,20,"INVENTORY");
row=inventoryRows(noSales,options).get(0);assertDecimal("10",row.availableQuantity());assertNull(row.ownerOutbound());assertNull(row.observedOutbound());assertNull(row.outboundQuantity30d());assertNull(row.lastOutbound());
var empty=new AnalyticsSqlRequest("demo","OTHER",null,null,0,0,D.minusDays(30),D,D,D.minusDays(30),null,null,null,null,false,false,false,false,false,0,20,"INVENTORY");
assertTrue(inventoryRows(empty,options).isEmpty());assertEquals(0L,((Number)literalQuery("inventoryCount",empty,options).get(0)).longValue());
}
@SuppressWarnings("unchecked") private List<AnalyticsReadRows.Inventory> inventoryRows(AnalyticsSqlRequest p,AnalyticsInventoryOptions o){
return (List<AnalyticsReadRows.Inventory>)(List<?>)literalQuery("inventoryPage",p,o);
}
@SuppressWarnings("unchecked") private List<AnalyticsReadMapper.RankingStat> rankingStats(AnalyticsSqlRequest p){
return (List<AnalyticsReadMapper.RankingStat>)(List<?>)literalQuery("rankingStats",p,new AnalyticsInventoryOptions(null,null,null,null,null,null,null,null));
}