fix(oms): 出库导入批次分配优化:批次号优先排序、移除归属校验、库存不足统一报错
对 c1f483f0 出库导入指定仓库功能的迭代调整:
1. 移除物料仓库归属前置校验(countInventoryByWarehouse):物料档案全仓共享、
不属于任何仓库,仓库约束收敛到批次分配环节——分不到当前仓批次即报库存不足
2. getkcId 增加分配排序:同物料同仓多条可用库存时,有批次号的优先、空批次
沉底、同组按库存ID(入库先后);此前无排序随机取第一条,会分到无批次号的
历史脏数据记录
3. 明细仓库编码/名称兜底:部分历史库存记录只存仓库ID未存编码/名称,按ID
反查仓库表补齐,修复明细仓库只显示ID不显示名称
4. 库存校验改收集式:全部物料批次比较完成后统一报出不足物料清单,原为逐行
分配时立即抛错,首个不足即中断、后续物料不参与比较
This commit is contained in:
-20
@@ -259,26 +259,6 @@ public class ExecutionStockInOrderImpl extends ServiceImpl<ExecutionStockInOrder
|
||||
throw new Exception("出库物料不是同一个货主!");
|
||||
}
|
||||
|
||||
// ====== 物料仓库校验(物料档案全仓共享;指定仓库时,物料必须在该仓库有库存记录才可出库) ======
|
||||
if (warehouseId != null && warehouseId > 0) {
|
||||
String warehouseName = reservationStockInOrderMapper.getWarehouseName(warehouseId);
|
||||
List<String> wrongWarehouseMaterials = new ArrayList<>();
|
||||
for (ProductDetail productDetail : productDetailList) {
|
||||
MaterialBaseInfoPO materialBaseInfoPO = stockInOrderMapper.getByCode(productDetail.getProductCode());
|
||||
if (materialBaseInfoPO == null) {
|
||||
continue;
|
||||
}
|
||||
int count = reservationStockInOrderMapper.countInventoryByWarehouse(materialBaseInfoPO.getMaterialBaseInfoId(), warehouseId);
|
||||
if (count <= 0) {
|
||||
wrongWarehouseMaterials.add(productDetail.getProductCode());
|
||||
}
|
||||
}
|
||||
if (!wrongWarehouseMaterials.isEmpty()) {
|
||||
throw new Exception("物料[" + String.join("、", wrongWarehouseMaterials) + "]在当前仓库["
|
||||
+ (warehouseName == null ? warehouseId : warehouseName) + "]没有库存记录,无法从该仓库出库,请确认导入仓库是否正确");
|
||||
}
|
||||
}
|
||||
|
||||
ExecutionStockOutOrderDO reservationStockOutOrderDO = new ExecutionStockOutOrderDO();
|
||||
reservationStockOutOrderDO.setOutOrderNumber(OrderSequence.getOrderCode("CK"));
|
||||
reservationStockOutOrderDO.setShipperId((Long) shipperIds.get(0).get("shipperId"));
|
||||
|
||||
-6
@@ -37,12 +37,6 @@ public interface ReservationStockInOrderMapper extends BaseMapper<ReservationSto
|
||||
|
||||
public List<ReservationMaterialInventoryPO> getkcId(@Param("id") Long id,@Param("q") BigDecimal q, @Param("warehouseId") Long warehouseId);
|
||||
|
||||
/**
|
||||
* 出库导入校验:物料在指定仓库是否存在库存记录(存在即视为归属该仓库,不限数量)
|
||||
* @return 库存记录数
|
||||
*/
|
||||
public int countInventoryByWarehouse(@Param("id") Long id, @Param("warehouseId") Long warehouseId);
|
||||
|
||||
public MaterialWarehouseControlPO getInfoByMaterialBaseInfoIds(@Param("id") Long id);
|
||||
|
||||
public MaterialGoodsRulePO getGoodsInfoByMaterialBaseInfoIds(@Param("id") Long id);
|
||||
|
||||
+33
-17
@@ -309,24 +309,9 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
|
||||
throw new Exception(String.join(";", problems) + ",维护完成后重新导入");
|
||||
}
|
||||
|
||||
// ====== 第四步:物料仓库校验(物料档案全仓共享;指定仓库时,物料必须在该仓库有库存记录才可出库,
|
||||
// 防止取到其他仓库的批次库存、单据显示成其他仓库) ======
|
||||
if (warehouseId != null && warehouseId > 0) {
|
||||
String warehouseName = stockInOrderMapper.getWarehouseName(warehouseId);
|
||||
List<String> wrongWarehouseMaterials = new ArrayList<>();
|
||||
for (MaterialBaseInfoPO materialBaseInfoPO : materialCache.values()) {
|
||||
int count = stockInOrderMapper.countInventoryByWarehouse(materialBaseInfoPO.getMaterialBaseInfoId(), warehouseId);
|
||||
if (count <= 0) {
|
||||
wrongWarehouseMaterials.add(materialBaseInfoPO.getMaterialCode());
|
||||
}
|
||||
}
|
||||
if (!wrongWarehouseMaterials.isEmpty()) {
|
||||
throw new Exception("物料[" + String.join("、", wrongWarehouseMaterials) + "]在当前仓库["
|
||||
+ (warehouseName == null ? warehouseId : warehouseName) + "]没有库存记录,无法从该仓库出库,请确认导入仓库是否正确");
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 后续处理(编号均已存在):货主归属校验、建单落库 ======
|
||||
// 物料档案全仓共享、不属于任何仓库;仓库约束在下方"分配批次"环节生效:
|
||||
// getkcId 按 warehouseId 过滤,分不到当前仓库的批次即报"批次库存数量少于出库数量",不会取到其他仓库的库存
|
||||
for (MaterialBaseInfoPO materialBaseInfoPO : materialCache.values()) {
|
||||
if (materialBaseInfoPO.getShipperId() != null && processedShipperIds.add(materialBaseInfoPO.getShipperId())) {
|
||||
Map<String, Object> shipper = new HashMap<>();
|
||||
@@ -347,6 +332,28 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 库存预检:所有物料的批次库存全部比较完成后再统一报错 ======
|
||||
// (原为逐行分配时立即抛错,首个不足即中断,排在后面的物料不再参与比较)
|
||||
if (!productDetailList.isEmpty()) {
|
||||
Set<String> insufficientMaterials = new HashSet<>();
|
||||
for (ProductDetail productDetail : productDetailList) {
|
||||
MaterialBaseInfoPO materialBaseInfoPO = materialCache.get(productDetail.getProductCode());
|
||||
if (materialBaseInfoPO == null) {
|
||||
continue; // 存在性已在前面统一校验
|
||||
}
|
||||
BigDecimal requireQty = new BigDecimal(productDetail.getPieceCount()).setScale(2, BigDecimal.ROUND_HALF_UP);
|
||||
List<ReservationMaterialInventoryPO> inventoryList = stockInOrderMapper.getkcId(
|
||||
materialBaseInfoPO.getMaterialBaseInfoId(), requireQty, warehouseId);
|
||||
if (inventoryList == null || inventoryList.isEmpty()) {
|
||||
insufficientMaterials.add(productDetail.getProductCode());
|
||||
}
|
||||
}
|
||||
if (!insufficientMaterials.isEmpty()) {
|
||||
throw new Exception("物料[" + String.join("、", insufficientMaterials) + "]"
|
||||
+ (warehouseId != null && warehouseId > 0 ? "在当前仓库" : "") + "批次库存数量少于出库数量!");
|
||||
}
|
||||
}
|
||||
|
||||
ReservationStockOutOrderDO reservationStockOutOrderDO = new ReservationStockOutOrderDO();
|
||||
// 生成出库业务单号
|
||||
String orderNumber = reservationStockOutOrderApplicationService.generateReserveOrderNumber();
|
||||
@@ -415,6 +422,15 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
|
||||
Long invWarehouseId = reservationMaterialInventoryPO.getWarehouseId();
|
||||
String warehouseCode = reservationMaterialInventoryPO.getWarehouseCode();
|
||||
String warehouseName = reservationMaterialInventoryPO.getWarehouseName();
|
||||
// 兜底:部分历史库存记录只存了仓库ID未存编码/名称,按ID查仓库表补齐,避免明细仓库显示不全
|
||||
if (invWarehouseId != null && invWarehouseId > 0) {
|
||||
if (warehouseCode == null || warehouseCode.trim().isEmpty()) {
|
||||
warehouseCode = stockInOrderMapper.getWarehouseCode(invWarehouseId);
|
||||
}
|
||||
if (warehouseName == null || warehouseName.trim().isEmpty()) {
|
||||
warehouseName = stockInOrderMapper.getWarehouseName(invWarehouseId);
|
||||
}
|
||||
}
|
||||
String inOrderNumber = reservationMaterialInventoryPO.getInOrderNumber();
|
||||
BigDecimal inventoryQuantity = reservationMaterialInventoryPO.getInventoryQuantity();
|
||||
String unit = reservationMaterialInventoryPO.getUnit();
|
||||
|
||||
+2
-5
@@ -559,11 +559,8 @@
|
||||
<if test="warehouseId != null">
|
||||
and WAREHOUSE_ID = #{warehouseId}
|
||||
</if>
|
||||
</select>
|
||||
<!-- 出库导入校验:物料在指定仓库是否存在库存记录(存在即视为归属该仓库,不限数量) -->
|
||||
<select id="countInventoryByWarehouse" resultType="int">
|
||||
select count(1) from "NGWL_TEST_WMS".MATERIAL_INVENTORY
|
||||
where 1 = 1 and DEL_FLAG = 1 and MATERIAL_BASE_INFO_ID = #{id} and WAREHOUSE_ID = #{warehouseId}
|
||||
<!-- 同物料同仓存在多条可用库存时:有批次号的优先分配(空批次的历史记录沉底),同组按入库先后 -->
|
||||
order by (case when BATCH_NUMBER is null or BATCH_NUMBER = '' then 1 else 0 end), MATERIAL_INVENTORY_ID asc
|
||||
</select>
|
||||
<select id="getUserNcCode" parameterType="java.lang.Long" resultType="java.lang.String">
|
||||
select CUSTOMER_NC_CODE from "NGWL_TEST_USER".USER_SHIPPER where 1 = 1 and DEL_FLAG = 1 and USER_ID = #{id} limit 1
|
||||
|
||||
Reference in New Issue
Block a user