提交
This commit is contained in:
+10
@@ -35,6 +35,16 @@ public class InventoryQueryController {
|
||||
private static final String BASE_PATH = "/api/platform/v1/last-leg/inventory";
|
||||
|
||||
@Resource private InventoryQueryService service;
|
||||
@Resource private com.baiyue.lastleg.inventory.query.service.InventoryPieceService pieces;
|
||||
|
||||
/** 完整筛选读取当前可用件数、箱内全部SKU及未知箱数,不改变原有箱数契约。 */
|
||||
@GetMapping(BASE_PATH + "/piece-projection")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.INVENTORY_LIST + "')")
|
||||
public ApiResponse<com.baiyue.lastleg.inventory.query.dto.InventoryPieceProjection> pieceProjection(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,@RequestParam(required=false) String customerId,
|
||||
@Valid InventoryQueryRequests.BalanceQuery query) {
|
||||
return ApiResponse.success(pieces.project(platformScope(user,customerId),query));
|
||||
}
|
||||
|
||||
@GetMapping(BASE_PATH + "/summary")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.INVENTORY_LIST + "')")
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baiyue.lastleg.inventory.query.dto;
|
||||
import java.util.List;
|
||||
/** 当前严格可用件数与完整混箱SKU内容;不完整映射保持未知,不覆盖原有箱数API。 */
|
||||
public record InventoryPieceProjection(Long availablePieceCount,long knownAvailablePieceCount,long unknownCartonCount,
|
||||
long availableCartonCount,long availablePalletCount,List<Group> groups) {
|
||||
/** 与通用库存按客户、仓、目的仓、记账SKU分组对齐,箱内SKU不重复累计物理箱。 */
|
||||
public record Group(String customerId,String warehouseId,String destinationCode,String anchorSkuCode,
|
||||
Long availablePieceCount,long knownAvailablePieceCount,long unknownCartonCount,long availableCartonCount,
|
||||
long availablePalletCount,List<Sku> skuContents,List<Carton> cartons) { }
|
||||
/** 箱内实际SKU件数。 */
|
||||
public record Sku(String skuCode,long quantity) { }
|
||||
/** 保留箱唛及所在仓位,混箱SKU共享同一物理箱。 */
|
||||
public record Carton(String cartonMark,Long inventoryPositionId,Long palletId,Long quantity,List<Sku> items) { }
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.baiyue.lastleg.inventory.query.mapper;
|
||||
|
||||
import com.baiyue.lastleg.inventory.query.dto.InventoryQueryRequests;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import java.util.List;
|
||||
|
||||
/** 从原箱清点事实及实际目的仓签收定位箱内SKU,不按首SKU或箱规换算件数。 */
|
||||
@Mapper
|
||||
public interface InventoryPieceMapper {
|
||||
String POSITION_CTE = "WITH balances AS (SELECT * FROM ll_inventory_balance " + InventoryQueryMapper.BALANCE_FILTER + """
|
||||
), occupied AS (
|
||||
SELECT DISTINCT t.customer_id,t.operating_warehouse_id warehouse_id,t.inbound_code,
|
||||
COALESCE(NULLIF(c.customer_carton_mark,''),c.carton_mark) carton_mark
|
||||
FROM ll_warehouse_transfer_order t JOIN ll_warehouse_transfer_carton c
|
||||
ON c.transfer_order_id=t.id AND c.customer_id=t.customer_id
|
||||
-- 出库已扣减来源箱,后续签收生成目的仓库存,不再把同一原箱当作待出库预留。
|
||||
WHERE t.transfer_no<>t.inbound_code AND t.status NOT IN
|
||||
('DRAFT','REJECTED','CANCELLED','OUTBOUNDED','PARTIALLY_RECEIVED','RECEIVED')
|
||||
), raw_positions AS (SELECT p.* FROM ll_inventory_position p JOIN balances b
|
||||
ON b.id=p.balance_id AND b.customer_id=p.customer_id WHERE p.available_packages>0),
|
||||
located AS (
|
||||
SELECT p.id position_id,c.id carton_id,c.carton_mark,c.counted_quantity,c.sku_items_json
|
||||
FROM raw_positions p JOIN balances b ON b.id=p.balance_id AND b.customer_id=p.customer_id
|
||||
JOIN ll_warehouse_transfer_order t ON t.customer_id=b.customer_id AND t.inbound_order_id=b.inbound_order_id
|
||||
AND t.operating_warehouse_id=b.overseas_warehouse_id AND t.transfer_no=t.inbound_code
|
||||
JOIN ll_warehouse_transfer_pallet tp ON tp.transfer_order_id=t.id AND tp.customer_id=t.customer_id AND tp.warehouse_pallet_id=p.pallet_id
|
||||
JOIN ll_warehouse_transfer_carton c ON c.transfer_order_id=t.id AND c.customer_id=t.customer_id
|
||||
AND c.transfer_pallet_id=tp.id AND c.status='COUNTED'
|
||||
JOIN ll_warehouse_transfer_item i ON i.id=c.transfer_item_id AND i.customer_id=c.customer_id AND (b.sku_code='MIXED' OR i.sku_code=b.sku_code)
|
||||
UNION
|
||||
SELECT p.id,c.id,c.carton_mark,c.counted_quantity,c.sku_items_json
|
||||
FROM raw_positions p JOIN balances b ON b.id=p.balance_id AND b.customer_id=p.customer_id
|
||||
JOIN ll_warehouse_transfer_receipt r ON r.destination_inventory_position_id=p.id AND r.customer_id=p.customer_id
|
||||
JOIN ll_warehouse_transfer_inventory_allocation a ON a.id=r.allocation_id AND a.customer_id=r.customer_id AND a.status='RECEIVED'
|
||||
JOIN ll_inventory_position sp ON sp.id=a.inventory_position_id AND sp.customer_id=a.customer_id
|
||||
JOIN ll_warehouse_transfer_order outgoing ON outgoing.id=a.transfer_order_id AND outgoing.customer_id=a.customer_id
|
||||
JOIN ll_warehouse_transfer_carton chosen ON chosen.transfer_order_id=outgoing.id AND chosen.customer_id=outgoing.customer_id
|
||||
JOIN ll_warehouse_transfer_order origin ON origin.customer_id=outgoing.customer_id AND origin.inbound_code=outgoing.inbound_code
|
||||
AND origin.operating_warehouse_id=outgoing.operating_warehouse_id AND origin.transfer_no=origin.inbound_code
|
||||
JOIN ll_warehouse_transfer_carton c ON c.transfer_order_id=origin.id AND c.customer_id=origin.customer_id
|
||||
AND c.carton_mark=COALESCE(NULLIF(chosen.customer_carton_mark,''),chosen.carton_mark) AND c.status='SHIPPED'
|
||||
JOIN ll_warehouse_transfer_pallet tp ON tp.id=c.transfer_pallet_id AND tp.customer_id=c.customer_id AND tp.warehouse_pallet_id=sp.pallet_id
|
||||
JOIN ll_warehouse_transfer_item i ON i.id=c.transfer_item_id AND i.customer_id=c.customer_id AND (b.sku_code='MIXED' OR i.sku_code=b.sku_code)
|
||||
), reservations AS (
|
||||
SELECT p.id position_id,COUNT(DISTINCT l.carton_id) reserved_count
|
||||
FROM raw_positions p JOIN balances b ON b.id=p.balance_id AND b.customer_id=p.customer_id
|
||||
JOIN located l ON l.position_id=p.id JOIN occupied o ON o.customer_id=b.customer_id
|
||||
AND o.warehouse_id=b.overseas_warehouse_id AND o.inbound_code=b.inbound_code AND o.carton_mark=l.carton_mark
|
||||
GROUP BY p.id
|
||||
), positions AS (
|
||||
SELECT p.*,GREATEST(0,p.available_packages-COALESCE(r.reserved_count,0)) free_packages
|
||||
FROM raw_positions p LEFT JOIN reservations r ON r.position_id=p.id
|
||||
)
|
||||
SELECT p.id positionId,p.balance_id balanceId,b.customer_id customerId,b.overseas_warehouse_id warehouseId,
|
||||
b.destination_warehouse_code destinationCode,b.sku_code anchorSkuCode,p.pallet_id palletId,
|
||||
p.free_packages availablePackages,l.carton_id cartonId,l.carton_mark cartonMark,
|
||||
l.counted_quantity countedQuantity,l.sku_items_json skuItemsJson
|
||||
FROM positions p JOIN balances b ON b.id=p.balance_id AND b.customer_id=p.customer_id
|
||||
LEFT JOIN located l ON l.position_id=p.id AND NOT EXISTS (
|
||||
SELECT 1 FROM occupied o WHERE o.customer_id=b.customer_id AND o.warehouse_id=b.overseas_warehouse_id
|
||||
AND o.inbound_code=b.inbound_code AND o.carton_mark=l.carton_mark)
|
||||
WHERE p.free_packages>0
|
||||
ORDER BY p.id,l.carton_id
|
||||
""";
|
||||
|
||||
/** 完整筛选取箱级投影;页码/每页大小不参与查询。 */
|
||||
@Select("<script>" + POSITION_CTE + "</script>")
|
||||
List<PieceRow> rows(@Param("customerId") String customerId,@Param("q") InventoryQueryRequests.BalanceQuery query);
|
||||
|
||||
/** 每个当前可用仓位及其匹配箱事实;未知箱以空cartonId表达。 */
|
||||
record PieceRow(Long positionId,Long balanceId,String customerId,String warehouseId,String destinationCode,
|
||||
String anchorSkuCode,Long palletId,long availablePackages,Long cartonId,String cartonMark,Long countedQuantity,String skuItemsJson) { }
|
||||
}
|
||||
+2
-2
@@ -24,7 +24,7 @@ public interface InventoryQueryMapper {
|
||||
"<if test='q.inboundOrderNo != null and q.inboundOrderNo != \"\"'> AND inbound_order_no LIKE CONCAT('%',#{q.inboundOrderNo},'%')</if>" +
|
||||
"<if test='q.inboundCode != null and q.inboundCode != \"\"'> AND inbound_code LIKE CONCAT('%',#{q.inboundCode},'%')</if>" +
|
||||
"<if test='q.businessOrderNo != null and q.businessOrderNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=ll_inventory_balance.id AND l.customer_id=ll_inventory_balance.customer_id AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND sku_code LIKE CONCAT('%',#{q.skuCode},'%')</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND (sku_code LIKE CONCAT('%',#{q.skuCode},'%') OR EXISTS (SELECT 1 FROM ll_warehouse_transfer_order tq JOIN ll_warehouse_transfer_carton cq ON cq.transfer_order_id=tq.id AND cq.customer_id=tq.customer_id WHERE tq.customer_id=ll_inventory_balance.customer_id AND tq.inbound_order_id=ll_inventory_balance.inbound_order_id AND tq.operating_warehouse_id=ll_inventory_balance.overseas_warehouse_id AND tq.transfer_no=tq.inbound_code AND cq.status IN ('COUNTED','DISCARD_PENDING') AND EXISTS (SELECT 1 FROM ll_warehouse_transfer_item iq WHERE iq.id=cq.transfer_item_id AND iq.customer_id=cq.customer_id AND (ll_inventory_balance.sku_code='MIXED' OR iq.sku_code=ll_inventory_balance.sku_code)) AND JSON_SEARCH(cq.sku_items_json,'one',CONCAT('%',#{q.skuCode},'%'),NULL,'$[*].skuCode') IS NOT NULL) OR EXISTS (SELECT 1 FROM ll_inventory_position dp JOIN ll_warehouse_transfer_receipt rr ON rr.destination_inventory_position_id=dp.id AND rr.customer_id=dp.customer_id JOIN ll_warehouse_transfer_inventory_allocation aa ON aa.id=rr.allocation_id AND aa.customer_id=rr.customer_id AND aa.status='RECEIVED' JOIN ll_inventory_position sp ON sp.id=aa.inventory_position_id AND sp.customer_id=aa.customer_id JOIN ll_warehouse_transfer_order ot ON ot.id=aa.transfer_order_id AND ot.customer_id=aa.customer_id JOIN ll_warehouse_transfer_carton chosen ON chosen.transfer_order_id=ot.id AND chosen.customer_id=ot.customer_id JOIN ll_warehouse_transfer_order origin ON origin.customer_id=ot.customer_id AND origin.inbound_code=ot.inbound_code AND origin.operating_warehouse_id=ot.operating_warehouse_id AND origin.transfer_no=origin.inbound_code JOIN ll_warehouse_transfer_carton cc ON cc.transfer_order_id=origin.id AND cc.customer_id=origin.customer_id AND cc.carton_mark=COALESCE(NULLIF(chosen.customer_carton_mark,''),chosen.carton_mark) AND cc.status='SHIPPED' JOIN ll_warehouse_transfer_pallet pp ON pp.id=cc.transfer_pallet_id AND pp.customer_id=cc.customer_id AND pp.warehouse_pallet_id=sp.pallet_id JOIN ll_warehouse_transfer_item ii ON ii.id=cc.transfer_item_id AND ii.customer_id=cc.customer_id WHERE dp.balance_id=ll_inventory_balance.id AND dp.customer_id=ll_inventory_balance.customer_id AND dp.available_packages>0 AND (ll_inventory_balance.sku_code='MIXED' OR ii.sku_code=ll_inventory_balance.sku_code) AND JSON_SEARCH(cc.sku_items_json,'one',CONCAT('%',#{q.skuCode},'%'),NULL,'$[*].skuCode') IS NOT NULL))</if>" +
|
||||
"<if test='q.productName != null and q.productName != \"\"'> AND (product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR product_name_en LIKE CONCAT('%',#{q.productName},'%'))</if>" +
|
||||
"<if test='q.batchNo != null and q.batchNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=ll_inventory_balance.customer_id AND p.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))</if>" +
|
||||
"<if test='q.warehouseLocationCode != null and q.warehouseLocationCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=ll_inventory_balance.customer_id AND p.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))</if>" +
|
||||
@@ -48,7 +48,7 @@ public interface InventoryQueryMapper {
|
||||
"<if test='q.inboundOrderNo != null and q.inboundOrderNo != \"\"'> AND b.inbound_order_no LIKE CONCAT('%',#{q.inboundOrderNo},'%')</if>" +
|
||||
"<if test='q.inboundCode != null and q.inboundCode != \"\"'> AND b.inbound_code LIKE CONCAT('%',#{q.inboundCode},'%')</if>" +
|
||||
"<if test='q.businessOrderNo != null and q.businessOrderNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=b.id AND l.customer_id=b.customer_id AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND b.sku_code LIKE CONCAT('%',#{q.skuCode},'%')</if>" +
|
||||
"<if test='q.skuCode != null and q.skuCode != \"\"'> AND (b.sku_code LIKE CONCAT('%',#{q.skuCode},'%') OR EXISTS (SELECT 1 FROM ll_warehouse_transfer_order tq JOIN ll_warehouse_transfer_carton cq ON cq.transfer_order_id=tq.id AND cq.customer_id=tq.customer_id WHERE tq.customer_id=b.customer_id AND tq.inbound_order_id=b.inbound_order_id AND tq.operating_warehouse_id=b.overseas_warehouse_id AND tq.transfer_no=tq.inbound_code AND cq.status IN ('COUNTED','DISCARD_PENDING') AND EXISTS (SELECT 1 FROM ll_warehouse_transfer_item iq WHERE iq.id=cq.transfer_item_id AND iq.customer_id=cq.customer_id AND (b.sku_code='MIXED' OR iq.sku_code=b.sku_code)) AND JSON_SEARCH(cq.sku_items_json,'one',CONCAT('%',#{q.skuCode},'%'),NULL,'$[*].skuCode') IS NOT NULL) OR EXISTS (SELECT 1 FROM ll_inventory_position dp JOIN ll_warehouse_transfer_receipt rr ON rr.destination_inventory_position_id=dp.id AND rr.customer_id=dp.customer_id JOIN ll_warehouse_transfer_inventory_allocation aa ON aa.id=rr.allocation_id AND aa.customer_id=rr.customer_id AND aa.status='RECEIVED' JOIN ll_inventory_position sp ON sp.id=aa.inventory_position_id AND sp.customer_id=aa.customer_id JOIN ll_warehouse_transfer_order ot ON ot.id=aa.transfer_order_id AND ot.customer_id=aa.customer_id JOIN ll_warehouse_transfer_carton chosen ON chosen.transfer_order_id=ot.id AND chosen.customer_id=ot.customer_id JOIN ll_warehouse_transfer_order origin ON origin.customer_id=ot.customer_id AND origin.inbound_code=ot.inbound_code AND origin.operating_warehouse_id=ot.operating_warehouse_id AND origin.transfer_no=origin.inbound_code JOIN ll_warehouse_transfer_carton cc ON cc.transfer_order_id=origin.id AND cc.customer_id=origin.customer_id AND cc.carton_mark=COALESCE(NULLIF(chosen.customer_carton_mark,''),chosen.carton_mark) AND cc.status='SHIPPED' JOIN ll_warehouse_transfer_pallet pp ON pp.id=cc.transfer_pallet_id AND pp.customer_id=cc.customer_id AND pp.warehouse_pallet_id=sp.pallet_id JOIN ll_warehouse_transfer_item ii ON ii.id=cc.transfer_item_id AND ii.customer_id=cc.customer_id WHERE dp.balance_id=b.id AND dp.customer_id=b.customer_id AND dp.available_packages>0 AND (b.sku_code='MIXED' OR ii.sku_code=b.sku_code) AND JSON_SEARCH(cc.sku_items_json,'one',CONCAT('%',#{q.skuCode},'%'),NULL,'$[*].skuCode') IS NOT NULL))</if>" +
|
||||
"<if test='q.productName != null and q.productName != \"\"'> AND (b.product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR b.product_name_en LIKE CONCAT('%',#{q.productName},'%'))</if>" +
|
||||
"<if test='q.batchNo != null and q.batchNo != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=b.customer_id AND p2.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))</if>" +
|
||||
"<if test='q.warehouseLocationCode != null and q.warehouseLocationCode != \"\"'> AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=b.customer_id AND p2.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))</if>" +
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baiyue.lastleg.inventory.query.repository;
|
||||
import com.baiyue.lastleg.inventory.query.dto.InventoryQueryRequests;
|
||||
import com.baiyue.lastleg.inventory.query.mapper.InventoryPieceMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
/** 统一库存混箱事实查询入口。 */
|
||||
@Repository
|
||||
public class InventoryPieceRepository {
|
||||
@Resource private InventoryPieceMapper mapper;
|
||||
/** 读取相同筛选范围的全部当前可用箱。 */
|
||||
public List<InventoryPieceMapper.PieceRow> rows(String customerId,InventoryQueryRequests.BalanceQuery query) {
|
||||
return mapper.rows(customerId,query);
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.baiyue.lastleg.inventory.query.service;
|
||||
import com.baiyue.lastleg.inventory.query.dto.*;
|
||||
import com.baiyue.lastleg.inventory.query.mapper.InventoryPieceMapper.PieceRow;
|
||||
import com.baiyue.lastleg.inventory.query.repository.InventoryPieceRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** 用完整箱内清点投影当前可用件数,对缺失或不完整映射显式返回未知。 */
|
||||
@Service
|
||||
public class InventoryPieceService {
|
||||
@Resource private InventoryPieceRepository repository;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
/** 完整筛选的多分组汇总,同一物理托盘按客户及仓去重而非相减。 */
|
||||
@Transactional(readOnly=true)
|
||||
public InventoryPieceProjection project(String customerId,InventoryQueryRequests.BalanceQuery query) {
|
||||
var rows=repository.rows(customerId,query);
|
||||
var groups=rows.stream().collect(Collectors.groupingBy(r -> Arrays.asList(r.customerId(),r.warehouseId(),r.destinationCode(),r.anchorSkuCode()),LinkedHashMap::new,Collectors.toList()));
|
||||
var result=new ArrayList<InventoryPieceProjection.Group>(); var pallets=new HashSet<String>();
|
||||
for(var group:groups.values()) {
|
||||
result.add(group(group));
|
||||
for(var row:group) if(row.palletId()!=null) pallets.add(row.customerId()+":"+row.warehouseId()+":"+row.palletId());
|
||||
}
|
||||
long known=0,unknown=0,cartons=0;
|
||||
for(var group:result) { known=Math.addExact(known,group.knownAvailablePieceCount()); unknown+=group.unknownCartonCount(); cartons+=group.availableCartonCount(); }
|
||||
return new InventoryPieceProjection(unknown==0?known:null,known,unknown,cartons,pallets.size(),result);
|
||||
}
|
||||
|
||||
/** 每个仓位只有精确箱映射完整时才计入已知件数,不能从多余箱中截取或按比例推算。 */
|
||||
private InventoryPieceProjection.Group group(List<PieceRow> rows) {
|
||||
var positions=rows.stream().collect(Collectors.groupingBy(PieceRow::positionId,LinkedHashMap::new,Collectors.toList()));
|
||||
var contents=new TreeMap<String,Long>(); var cartons=new ArrayList<InventoryPieceProjection.Carton>();
|
||||
var pallets=new HashSet<Long>(); long available=0,unknown=0,known=0;
|
||||
for(var position:positions.values()) {
|
||||
var first=position.get(0); available+=first.availablePackages(); if(first.palletId()!=null) pallets.add(first.palletId());
|
||||
var boxes=position.stream().filter(r -> r.cartonId()!=null).collect(Collectors.toMap(PieceRow::cartonId,r -> r,(a,b)->a,LinkedHashMap::new));
|
||||
var parsed=new ArrayList<InventoryPieceProjection.Carton>();
|
||||
for(var row:boxes.values()) parsed.add(carton(row));
|
||||
if(boxes.size()!=first.availablePackages() || parsed.stream().anyMatch(c -> c.quantity()==null)) { unknown+=first.availablePackages(); continue; }
|
||||
for(var box:parsed) {
|
||||
cartons.add(box); known=Math.addExact(known,box.quantity());
|
||||
for(var sku:box.items()) contents.merge(sku.skuCode(),sku.quantity(),Math::addExact);
|
||||
}
|
||||
}
|
||||
var first=rows.get(0);
|
||||
return new InventoryPieceProjection.Group(first.customerId(),first.warehouseId(),first.destinationCode(),first.anchorSkuCode(),
|
||||
unknown==0?known:null,known,unknown,available,pallets.size(),contents.entrySet().stream().map(e -> new InventoryPieceProjection.Sku(e.getKey(),e.getValue())).toList(),cartons);
|
||||
}
|
||||
|
||||
/** 清点JSON与箱总件数必须一致;缺失信息保持未知,不拿首SKU替代混箱。 */
|
||||
private InventoryPieceProjection.Carton carton(PieceRow row) {
|
||||
var items=new ArrayList<InventoryPieceProjection.Sku>(); Long quantity=null;
|
||||
try {
|
||||
var lines=objectMapper.readTree(row.skuItemsJson()); long sum=0;
|
||||
if(lines.isArray() && !lines.isEmpty()) {
|
||||
for(var line:lines) {
|
||||
String sku=line.path("skuCode").asText(""); var count=line.path("quantity");
|
||||
if(sku.isBlank() || !count.asText().matches("[0-9]+")) throw new IllegalArgumentException("无效箱内SKU事实");
|
||||
long pieces=Long.parseLong(count.asText());
|
||||
if(pieces<=0) throw new IllegalArgumentException("箱内件数必须为正整数");
|
||||
items.add(new InventoryPieceProjection.Sku(sku,pieces)); sum=Math.addExact(sum,pieces);
|
||||
}
|
||||
if(row.countedQuantity()!=null && sum==row.countedQuantity()) quantity=sum;
|
||||
}
|
||||
} catch(Exception invalid) { items.clear(); }
|
||||
return new InventoryPieceProjection.Carton(row.cartonMark(),row.positionId(),row.palletId(),quantity,items);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user