From f5304c1f31979d9ea7f66a9d31fca47af8b86bd7 Mon Sep 17 00:00:00 2001
From: "HUOJIN\\92525" <925259474@qq.com>
Date: Sun, 16 Nov 2025 20:23:29 +0800
Subject: [PATCH] no message
---
.../cpte/modules/base/mapper/AreaMapper.java | 9 -
.../cpte/modules/base/mapper/ItemMapper.java | 9 -
.../cpte/modules/base/mapper/PointMapper.java | 9 -
.../cpte/modules/base/mapper/StockMapper.java | 9 -
.../modules/base/service/IItemService.java | 7 +
.../modules/base/service/IPointService.java | 8 +
.../modules/base/service/IStockService.java | 9 +
.../base/service/impl/ItemServiceImpl.java | 24 +-
.../base/service/impl/PointServiceImpl.java | 24 +-
.../base/service/impl/StockServiceImpl.java | 23 +-
.../inventory/mapper/InventoryMapper.java | 15 +-
.../inventory/mapper/xml/InventoryMapper.xml | 29 +-
.../inventory/service/IInventoryService.java | 2 +
.../service/impl/InventoryServiceImpl.java | 12 +
.../service/impl/InventoryLogServiceImpl.java | 3 +-
.../cpte/modules/quartz/job/AllocateJob.java | 84 ++++
.../cpte/modules/quartz/job/TesAgvJob.java | 3 +
.../receive/mapper/AsnDetailMapper.java | 3 +
.../receive/service/impl/AsnServiceImpl.java | 54 ++-
.../saiWms/controller/SaiWmsController.java | 4 +-
.../saiWms/request/OutboundRequest.java | 1 -
.../service/impl/ISaiWmsServiceImpl.java | 2 +-
.../modules/shipping/entity/PickDetail.java | 1 +
.../shipping/mapper/PickDetailMapper.java | 10 +
.../shipping/service/IPickService.java | 77 ++--
.../service/impl/PickServiceImpl.java | 401 +++++++++++++++++-
.../shipping/vo/InventoryGroupKey.java | 27 ++
.../system/controller/SysLogController.java | 2 +-
28 files changed, 739 insertions(+), 122 deletions(-)
create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/AllocateJob.java
create mode 100644 cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryGroupKey.java
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java
index 295c6bd..fdf3b5e 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/AreaMapper.java
@@ -22,13 +22,4 @@ public interface AreaMapper extends BaseMapper {
*/
@Select("select * from base_area where area_code = #{areaCode}")
Area queryByAreaCode(@Param("areaCode") String areaCode);
-
- /**
- * 通过库区编码查询库区信息
- *
- * @param areaCodes 库区编号集合
- * @return List-
- */
- @Select("select * from base_area where area_code in (#{areaCodes})")
- List queryByAreaCodes(@Param("areaCodes") List areaCodes);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java
index 5119691..05bae38 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/ItemMapper.java
@@ -23,13 +23,4 @@ public interface ItemMapper extends BaseMapper
- {
*/
@Select("select * from base_item where item_code = #{itemCode}")
Item queryByItemCode(@Param("itemCode") String itemCode);
-
- /**
- * 通过物料编码查询物料信息
- *
- * @param itemCodes 物料编号集合
- * @return List
-
- */
- @Select("select * from base_item where item_code in (#{itemCodes})")
- List
- queryByItemCodes(@Param("itemCodes") List itemCodes);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java
index b3719a2..be8aaef 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/PointMapper.java
@@ -23,15 +23,6 @@ public interface PointMapper extends BaseMapper {
@Select("select * from base_point where point_code = #{pointCode}")
Point queryByPointCode(@Param("pointCode") String pointCode);
- /**
- * 通过库位编码查询库位信息
- *
- * @param pointCodes 库位编号集合
- * @return List
- */
- @Select("select * from base_point where point_code in (#{pointCodes})")
- List queryByPointCodes(@Param("pointCodes") List pointCodes);
-
/**
* 查询库位信息
*
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java
index f22e649..3e52af1 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/mapper/StockMapper.java
@@ -22,13 +22,4 @@ public interface StockMapper extends BaseMapper {
*/
@Select("select * from base_stock where stock_code = #{stockCode}")
Stock queryByStockCode(@Param("stockCode") String stockCode);
-
- /**
- * 通过容器编码查询容器信息
- *
- * @param stockCodes 容器编号集合
- * @return List
- */
- @Select("select * from base_stock where stock_code in (#{stockCodes})")
- List queryByStockCodes(@Param("stockCodes") List stockCodes);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IItemService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IItemService.java
index 264d9c7..4002298 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IItemService.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IItemService.java
@@ -36,5 +36,12 @@ public interface IItemService extends IService
- {
*/
Map queryByItemCodesToMap(List itemCodes);
+ /**
+ * 根据物料ID集合查询物料信息
+ *
+ * @param itemIds 物料ID集合
+ * @return Map
+ */
+ Map queryByItemIdsToMap(List itemIds);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java
index 48a4253..977cf4b 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IPointService.java
@@ -34,4 +34,12 @@ public interface IPointService extends IService {
* @return Map
*/
Map queryByPointCodesToMap(List pointCodes);
+
+ /**
+ * 根据库位ID集合查询库位信息
+ *
+ * @param pointIds 库位集合
+ * @return Map
+ */
+ Map queryByPointIdsToMap(List pointIds);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java
index 0e546ab..97199c5 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java
@@ -37,4 +37,13 @@ public interface IStockService extends IService {
*/
Map queryByStockCodesToMap(List stockCodes);
+ /**
+ * 根据容器ID集合查询容器信息
+ *
+ * @param stockIds 容器ID集合
+ * @return Map
+ */
+ Map queryByStockIdsToMap(List stockIds);
+
+
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java
index 134d523..8f6b87a 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/ItemServiceImpl.java
@@ -55,7 +55,15 @@ public class ItemServiceImpl extends ServiceImpl implements II
* @return List
*/
public List
- queryByItemCodes(List itemCodes) {
- return itemMapper.queryByItemCodes(itemCodes);
+ if (CollectionUtils.isEmpty(itemCodes)) {
+ return Collections.emptyList();
+ }
+ //查询物料
+ LambdaQueryWrapper
- queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(Item::getItemCode, itemCodes);
+ queryWrapper.eq(Item::getDelFlag, 0);
+ queryWrapper.eq(Item::getIzActive, 1);
+ return itemMapper.selectList(queryWrapper);
}
/**
@@ -77,4 +85,18 @@ public class ItemServiceImpl extends ServiceImpl implements II
}
return itemMap;
}
+
+ @Override
+ public Map queryByItemIdsToMap(List itemIds) {
+ if (CollectionUtils.isEmpty(itemIds)) {
+ return Collections.emptyMap();
+ }
+ List
- itemList = this.listByIds(itemIds);
+ //封装成map
+ Map itemMap = Maps.newHashMap();
+ for (Item item : itemList) {
+ itemMap.put(item.getId(), item);
+ }
+ return itemMap;
+ }
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java
index f4a90ce..44a0d03 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/PointServiceImpl.java
@@ -6,6 +6,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.cpte.modules.base.entity.Area;
import org.cpte.modules.base.entity.Point;
+import org.cpte.modules.base.entity.Stock;
import org.cpte.modules.base.mapper.AreaMapper;
import org.cpte.modules.base.mapper.PointMapper;
import org.cpte.modules.base.service.IAreaService;
@@ -62,7 +63,15 @@ public class PointServiceImpl extends ServiceImpl implements
* @return List
*/
public List queryByPointCodes(List pointCodes) {
- return pointMapper.queryByPointCodes(pointCodes);
+ if (CollectionUtils.isEmpty(pointCodes)) {
+ return Collections.emptyList();
+ }
+ //查询库位
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(Point::getPointCode, pointCodes);
+ queryWrapper.eq(Point::getDelFlag, 0);
+ queryWrapper.eq(Point::getIzActive, 1);
+ return pointMapper.selectList(queryWrapper);
}
/**
@@ -84,4 +93,17 @@ public class PointServiceImpl extends ServiceImpl implements
}
return PointMap;
}
+
+ @Override
+ public Map queryByPointIdsToMap(List pointIds) {
+ if (CollectionUtils.isEmpty(pointIds)) {
+ return Collections.emptyMap();
+ }
+ List pointList = this.listByIds(pointIds);
+ Map pointMap = Maps.newHashMap();
+ for (Point point : pointList) {
+ pointMap.put(point.getId(), point);
+ }
+ return pointMap;
+ }
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java
index ca33022..676ae15 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/impl/StockServiceImpl.java
@@ -59,7 +59,15 @@ public class StockServiceImpl extends ServiceImpl implements
* @return List
*/
public List queryByStockCodes(List stockCodes) {
- return stockMapper.queryByStockCodes(stockCodes);
+ if (CollectionUtils.isEmpty(stockCodes)) {
+ return Collections.emptyList();
+ }
+ //查询容器
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(Stock::getStockCode, stockCodes);
+ queryWrapper.eq(Stock::getDelFlag, 0);
+ queryWrapper.eq(Stock::getIzActive, 1);
+ return stockMapper.selectList(queryWrapper);
}
/**
@@ -81,4 +89,17 @@ public class StockServiceImpl extends ServiceImpl implements
}
return stockMap;
}
+
+ @Override
+ public Map queryByStockIdsToMap(List stockIds) {
+ if (CollectionUtils.isEmpty(stockIds)) {
+ return Collections.emptyMap();
+ }
+ List stockList = this.listByIds(stockIds);
+ Map stockMap = Maps.newHashMap();
+ for (Stock stock : stockList) {
+ stockMap.put(stock.getId(), stock);
+ }
+ return stockMap;
+ }
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java
index aa09efc..881a4aa 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java
@@ -1,12 +1,13 @@
package org.cpte.modules.inventory.mapper;
-import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.cpte.modules.inventory.entity.Inventory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import java.util.List;
+
/**
* @Description: 库存表
* @author: cpte
@@ -23,4 +24,16 @@ public interface InventoryMapper extends BaseMapper {
*/
@Select("select * from data_inventory where stock_id = #{stockId} and quantity>0 for update")
Inventory queryByStockId(@Param("stockId") Long stockId);
+
+ /**
+ * 查询库存列表
+ *
+ * @param itemIds 物料ID
+ * @param propC1List 批次号
+ * @param propC3List 外部库存状态
+ * @param whCodeList 外部仓库
+ * @return List
+ */
+ List queryInventoryWithLock(@Param("itemIds") List itemIds, @Param("propC1List") List propC1List, @Param("propC3List") List propC3List, @Param("whCodeList") List whCodeList);
+
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml
index 36265d3..6358ea0 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml
@@ -1,5 +1,32 @@
-
+
\ No newline at end of file
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java
index 4146c0a..eaa396d 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java
@@ -7,6 +7,8 @@ import org.cpte.modules.receive.entity.AsnDetail;
import org.cpte.modules.receive.entity.ReceiveRecord;
import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
/**
* @Description: 库存表
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java
index e944274..adeba64 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java
@@ -1,5 +1,9 @@
package org.cpte.modules.inventory.service.impl;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.apache.commons.collections4.CollectionUtils;
+import org.cpte.modules.base.entity.Area;
+import org.cpte.modules.base.mapper.AreaMapper;
import org.cpte.modules.constant.enums.InventoryStatusEnum;
import org.cpte.modules.inventory.entity.Inventory;
import org.cpte.modules.inventory.mapper.InventoryMapper;
@@ -15,6 +19,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
+import java.util.List;
+import java.util.Map;
/**
* @Description: 库存表
@@ -24,6 +30,12 @@ import java.util.Date;
*/
@Service
public class InventoryServiceImpl extends ServiceImpl implements IInventoryService {
+
+ @Autowired
+ private AreaMapper areaMapper;
+ @Autowired
+ private InventoryMapper inventoryMapper;
+
@Override
@Transactional(rollbackFor = Exception.class)
public Inventory createInventory(Long stockId, BigDecimal receivedQty, Asn asn, AsnDetail asnDetail, ReceiveRecord receiveRecord) {
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java
index b696c40..e264280 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventoryLog/service/impl/InventoryLogServiceImpl.java
@@ -62,11 +62,10 @@ public class InventoryLogServiceImpl extends ServiceImpl processedCache = new ConcurrentHashMap<>();
+
+ // 缓存最大大小,防止内存溢出
+ private static final int MAX_CACHE_SIZE = 1000;
+
+ @Override
+ public void execute(JobExecutionContext jobExecutionContext) {
+ // 查询未分配或者部分分配的出库明细
+ List pickDetailList = pickDetailMapper.queryUnallocatedPickDetail();
+ if (pickDetailList.isEmpty()) {
+ return;
+ }
+ // 分配出库明细
+ long startTime = System.currentTimeMillis();
+ List resultMsg = iPickService.allocatePickDetail2(pickDetailList);
+ long endTime = System.currentTimeMillis();
+ log.info("分配出库明细耗时:{}ms", endTime - startTime);
+ if (CollectionUtils.isNotEmpty(resultMsg)) {
+ // 生成缓存键
+ String cacheKey = generateCacheKey(resultMsg);
+
+ // 检查是否已经处理过相同的内容
+ if (!processedCache.containsKey(cacheKey)) {
+ // 新内容,记录日志
+ baseCommonService.addLog("出库任务分配:" + "\n" + cacheKey, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_1);
+
+ // 添加到缓存
+ processedCache.put(cacheKey, true);
+
+ // 控制缓存大小
+ if (processedCache.size() > MAX_CACHE_SIZE) {
+ // 移除一部分旧缓存(简单实现,可以按需优化)
+ processedCache.clear();
+ }
+ }
+ }
+ }
+
+ /**
+ * 生成缓存键 - 基于分配结果生成唯一标识
+ */
+ private String generateCacheKey(List resultMsg) {
+ // 对结果进行排序后拼接,确保相同内容生成相同键
+ return resultMsg.stream()
+ .filter(Objects::nonNull)
+ .sorted()
+ .collect(Collectors.joining("\n"));
+ }
+}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java
index fcdb8d4..87b2742 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java
@@ -26,6 +26,9 @@ public class TesAgvJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 查询待执行任务
List agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue());
+ if (agvTaskList.isEmpty()) {
+ return;
+ }
String taskSubmitUrl = "http://localhost:8000/cpte-wms/tes/apiv2/newMovePodTask";
for (AgvTask agvTask : agvTaskList) {
try {
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java
index 64702ca..5ac980a 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java
@@ -42,4 +42,7 @@ public interface AsnDetailMapper extends BaseMapper {
*/
@Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} for update")
AsnDetail queryByStockCode(@Param("stockId") Long stockId, @Param("status") Integer status);
+
+ @Select("select MAX(line_no) from data_asn_detail where asn_id = #{asnId} ")
+ Integer queryMaxLineNoByAsnId(@Param("asnId") Long asnId);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java
index dbad152..877f37b 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java
@@ -5,11 +5,9 @@ import org.cpte.modules.base.entity.Point;
import org.cpte.modules.base.entity.Stock;
import org.cpte.modules.base.mapper.PointMapper;
import org.cpte.modules.base.mapper.StockMapper;
-import org.cpte.modules.base.service.IStockService;
import org.cpte.modules.constant.enums.AsnStatusEnum;
import org.cpte.modules.constant.enums.CommonStatusEnum;
import org.cpte.modules.inventory.entity.Inventory;
-import org.cpte.modules.inventory.mapper.InventoryMapper;
import org.cpte.modules.inventory.service.IInventoryService;
import org.cpte.modules.inventoryLog.service.IInventoryLogService;
import org.cpte.modules.receive.entity.Asn;
@@ -46,7 +44,6 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS
private StockMapper stockMapper;
@Autowired
private PointMapper pointMapper;
-
@Autowired
private AsnMapper asnMapper;
@Autowired
@@ -62,15 +59,22 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS
@Transactional(rollbackFor = Exception.class)
public void saveMain(Asn asn, List asnDetailList) {
asnMapper.insert(asn);
- if (asnDetailList != null && !asnDetailList.isEmpty()) {
- AtomicInteger lineNoCounter = new AtomicInteger(1);
- for (AsnDetail entity : asnDetailList) {
- if (entity.getLineNo() == null || entity.getLineNo() == 0) {
- entity.setLineNo(lineNoCounter.getAndIncrement());
- }
- entity.setAsnId(asn.getId());
- asnDetailMapper.insert(entity);
+
+ if (asnDetailList == null || asnDetailList.isEmpty()) {
+ throw new RuntimeException("请新增入库明细");
+ }
+
+ if(asnDetailList.size()>1){
+ throw new RuntimeException("入库明细只允许新增一条");
+ }
+
+ AtomicInteger lineNoCounter = new AtomicInteger(1);
+ for (AsnDetail entity : asnDetailList) {
+ if (entity.getLineNo() == null || entity.getLineNo() == 0) {
+ entity.setLineNo(lineNoCounter.getAndIncrement());
}
+ entity.setAsnId(asn.getId());
+ asnDetailMapper.insert(entity);
}
//刷新入库单
refreshAsn(asn, asnDetailList);
@@ -114,20 +118,28 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMain(Asn asn, List asnDetailList) {
- // 直接更新主表
asnMapper.updateById(asn);
- // 更新明细表 - 只更新传入的明细数据
- if (asnDetailList != null && !asnDetailList.isEmpty()) {
- for (AsnDetail entity : asnDetailList) {
- entity.setAsnId(asn.getId());
- // 直接更新,而不是删除后重新插入
- if (entity.getId() != null) {
- asnDetailMapper.updateById(entity);
- }
- }
+ if (asnDetailList == null || asnDetailList.isEmpty()) {
+ throw new RuntimeException("请新增入库明细");
}
+ if(asnDetailList.size()>1){
+ throw new RuntimeException("入库明细只允许新增一条");
+ }
+
+ AtomicInteger lineNoCounter = new AtomicInteger(1);
+ for (AsnDetail entity : asnDetailList) {
+ if (entity.getLineNo() == null || entity.getLineNo() == 0) {
+ entity.setLineNo(lineNoCounter.getAndIncrement());
+ }
+ entity.setAsnId(asn.getId());
+ if (entity.getId() != null) {
+ asnDetailMapper.updateById(entity);
+ } else {
+ asnDetailMapper.insert(entity);
+ }
+ }
// 刷新入库单状态
refreshAsn(asn, asnDetailList);
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java
index df1c27b..1cb7a6a 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java
@@ -36,7 +36,7 @@ public class SaiWmsController {
@IgnoreAuth
public Result inBoundTask(@RequestBody @Valid InboundRequest inboundRequest) {
iSaiWmsService.inBoundTask(inboundRequest);
- return Result.OK("下发成功!");
+ return Result.OK("操作成功!");
}
/**
@@ -50,6 +50,6 @@ public class SaiWmsController {
@IgnoreAuth
public Result outBoundTask(@RequestBody @Valid OutboundRequest outboundRequest) {
iSaiWmsService.outBoundTask(outboundRequest);
- return Result.OK("下发成功!");
+ return Result.OK("操作成功!");
}
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java
index 62344d7..6c1acf1 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/OutboundRequest.java
@@ -39,7 +39,6 @@ public class OutboundRequest {
private Integer type;
// 生产车间
- @NotBlank(message = "生产车间")
@JsonProperty("Enterprise")
private String enterprise;
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java
index d8f9a43..f32861b 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java
@@ -140,7 +140,7 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
//获取不存在的物料
List notExitItemCodes = itemCodes.stream().filter(itemCode -> !exitItemMap.containsKey(itemCode)).toList();
if (!notExitItemCodes.isEmpty()) {
- throw new RuntimeException("系统无【" + notExitItemCodes + "】物料,请维护");
+ throw new RuntimeException("系统无" + notExitItemCodes + "物料,请维护");
}
// 创建出库单和明细
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java
index 4afe5ef..4d55156 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/PickDetail.java
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToEmptyObjectSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java
index 16a4618..00f59a4 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/PickDetailMapper.java
@@ -1,6 +1,8 @@
package org.cpte.modules.shipping.mapper;
import java.util.List;
+
+import org.apache.ibatis.annotations.Select;
import org.cpte.modules.shipping.entity.PickDetail;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -28,4 +30,12 @@ public interface PickDetailMapper extends BaseMapper {
* @return List
*/
public List selectByMainId(@Param("mainId") Long mainId);
+
+ @Select("select * from data_pick_detail where status = 1 " +
+ "union all " +
+ "select * from data_pick_detail where status = 2 ")
+ List queryUnallocatedPickDetail();
+
+ @Select("select MAX(line_no) from data_pick_detail where pick_id = #{pickId} ")
+ Integer queryMaxLineNoByPickId(@Param("pickId") Long pickId);
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java
index 70d0819..c663893 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/IPickService.java
@@ -3,6 +3,7 @@ package org.cpte.modules.shipping.service;
import org.cpte.modules.shipping.entity.PickDetail;
import org.cpte.modules.shipping.entity.Pick;
import com.baomidou.mybatisplus.extension.service.IService;
+
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@@ -10,39 +11,53 @@ import java.util.List;
/**
* @Description: 出库单
* @author: cpte
- * @Date: 2025-11-14
+ * @Date: 2025-11-14
* @Version: V1.0
*/
public interface IPickService extends IService {
- /**
- * 添加一对多
- *
- * @param pick
- * @param pickDetailList
- */
- public void saveMain(Pick pick,List pickDetailList) ;
-
- /**
- * 修改一对多
- *
- * @param pick
- * @param pickDetailList
- */
- public void updateMain(Pick pick,List pickDetailList);
-
- /**
- * 删除一对多
- *
- * @param id
- */
- public void delMain (Long id);
-
- /**
- * 批量删除一对多
- *
- * @param idList
- */
- public void delBatchMain (Collection extends Serializable> idList);
-
+ /**
+ * 添加一对多
+ *
+ * @param pick
+ * @param pickDetailList
+ */
+ public void saveMain(Pick pick, List pickDetailList);
+
+ /**
+ * 修改一对多
+ *
+ * @param pick
+ * @param pickDetailList
+ */
+ public void updateMain(Pick pick, List pickDetailList);
+
+ /**
+ * 删除一对多
+ *
+ * @param id
+ */
+ public void delMain(Long id);
+
+ /**
+ * 批量删除一对多
+ *
+ * @param idList
+ */
+ public void delBatchMain(Collection extends Serializable> idList);
+
+ /**
+ * 分配出库单明细
+ *
+ * @param pickDetails 出库单明细集合
+ */
+ List allocatePickDetail(List pickDetails);
+
+ /**
+ * 分配出库单明细
+ *
+ * @param pickDetails 出库单明细集合
+ */
+ List allocatePickDetail2(List pickDetails);
+
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java
index 787efb8..eefdfbb 100644
--- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/PickServiceImpl.java
@@ -1,15 +1,30 @@
package org.cpte.modules.shipping.service.impl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.shiro.lang.util.StringUtils;
+import org.cpte.modules.base.entity.Item;
+import org.cpte.modules.base.entity.Point;
+import org.cpte.modules.base.entity.Stock;
+import org.cpte.modules.base.service.IItemService;
+import org.cpte.modules.base.service.IPointService;
+import org.cpte.modules.base.service.IStockService;
import org.cpte.modules.constant.enums.AsnStatusEnum;
+import org.cpte.modules.constant.enums.InventoryStatusEnum;
import org.cpte.modules.constant.enums.PickStatusEnum;
-import org.cpte.modules.receive.entity.Asn;
-import org.cpte.modules.receive.entity.AsnDetail;
+import org.cpte.modules.inventory.entity.Inventory;
+import org.cpte.modules.inventory.mapper.InventoryMapper;
+import org.cpte.modules.inventory.service.IInventoryService;
+import org.cpte.modules.inventoryLog.service.IInventoryLogService;
import org.cpte.modules.shipping.entity.Pick;
import org.cpte.modules.shipping.entity.PickDetail;
import org.cpte.modules.shipping.mapper.PickDetailMapper;
import org.cpte.modules.shipping.mapper.PickMapper;
import org.cpte.modules.shipping.service.IPickService;
+import org.cpte.modules.shipping.vo.InventoryGroupKey;
import org.cpte.modules.utils.BigDecimalUtil;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,10 +32,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Collection;
+import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
/**
* @Description: 出库单
@@ -29,31 +43,72 @@ import java.util.concurrent.atomic.AtomicInteger;
* @Version: V1.0
*/
@Service
+@Slf4j
public class PickServiceImpl extends ServiceImpl implements IPickService {
@Autowired
private PickMapper pickMapper;
@Autowired
private PickDetailMapper pickDetailMapper;
+ @Autowired
+ private InventoryMapper inventoryMapper;
+ @Autowired
+ private IItemService iItemService;
+ @Autowired
+ private IStockService iStockService;
+ @Autowired
+ private IPointService iPointService;
+ @Autowired
+ private IInventoryLogService iInventoryLogService;
+ @Autowired
+ private BaseCommonService baseCommonService;
+
+ /**
+ * 获取出库单Map
+ *
+ * @param pickIds 出库单id
+ * @return 出库单Map
+ */
+ private Map queryByPickIdsToMap(List pickIds) {
+ Map pickMap = new HashMap<>();
+ List pickList = pickMapper.selectByIds(pickIds);
+ for (Pick pick : pickList) {
+ pickMap.put(pick.getId(), pick);
+ }
+ return pickMap;
+ }
+
@Override
@Transactional(rollbackFor = Exception.class)
public void saveMain(Pick pick, List pickDetailList) {
pickMapper.insert(pick);
- if (pickDetailList != null && !pickDetailList.isEmpty()) {
- AtomicInteger lineNoCounter = new AtomicInteger(1);
- for (PickDetail entity : pickDetailList) {
- if (entity.getLineNo() == null || entity.getLineNo() == 0) {
- entity.setLineNo(lineNoCounter.getAndIncrement());
- }
- entity.setPickId(pick.getId());
- pickDetailMapper.insert(entity);
+
+ if (pickDetailList == null || pickDetailList.isEmpty()) {
+ throw new RuntimeException("请新增出库明细");
+ }
+
+ // 获取当前出库单下已存在的最大序号
+ Integer maxLineNo = pickDetailMapper.queryMaxLineNoByPickId(pick.getId());
+ AtomicInteger lineNoCounter = new AtomicInteger((maxLineNo != null) ? maxLineNo + 1 : 1);
+
+ for (PickDetail entity : pickDetailList) {
+ if (entity.getLineNo() == null || entity.getLineNo() == 0) {
+ entity.setLineNo(lineNoCounter.getAndIncrement());
}
+ entity.setPickId(pick.getId());
+ pickDetailMapper.insert(entity);
}
//刷新出库单
refreshPick(pick, pickDetailList);
}
+ /**
+ * 刷新出库单状态
+ *
+ * @param pick 出库单
+ * @param pickDetails 出库明细
+ */
public synchronized void refreshPick(Pick pick, List pickDetails) {
if (pickDetails == null) {
pickDetails = new ArrayList<>();
@@ -103,17 +158,41 @@ public class PickServiceImpl extends ServiceImpl implements IP
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMain(Pick pick, List pickDetailList) {
- // 直接更新主表
pickMapper.updateById(pick);
- // 更新明细表 - 只更新传入的明细数据
- if (pickDetailList != null && !pickDetailList.isEmpty()) {
- for (PickDetail entity : pickDetailList) {
- entity.setPickId(pick.getId());
- // 直接更新,而不是删除后重新插入
- if (entity.getId() != null) {
- pickDetailMapper.updateById(entity);
- }
+ if (pickDetailList == null || pickDetailList.isEmpty()) {
+ throw new RuntimeException("请新增出库明细");
+ }
+
+ // 删除多余的出库明细
+ List exitPickDetailList = pickDetailMapper.selectByMainId(pick.getId());
+ if (exitPickDetailList.size() > pickDetailList.size()) {
+ List pickDetailIds = pickDetailList.stream()
+ .map(PickDetail::getId)
+ .toList();
+ //两个集合的差集id 需要删除
+ List deleteIds = exitPickDetailList.stream()
+ .filter(e -> e.getId() != null && !pickDetailIds.contains(e.getId()))
+ .map(PickDetail::getId)
+ .toList();
+ pickDetailMapper.deleteByIds(deleteIds);
+ //添加删除日志
+ baseCommonService.addLog(pick.getNo() + "任务号,删除明细:" + deleteIds, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_4);
+ }
+
+ // 获取当前出库单下已存在的最大序号
+ Integer maxLineNo = pickDetailMapper.queryMaxLineNoByPickId(pick.getId());
+ AtomicInteger lineNoCounter = new AtomicInteger((maxLineNo != null) ? maxLineNo + 1 : 1);
+
+ for (PickDetail entity : pickDetailList) {
+ if (entity.getLineNo() == null || entity.getLineNo() == 0) {
+ entity.setLineNo(lineNoCounter.getAndIncrement());
+ }
+ entity.setPickId(pick.getId());
+ if (entity.getId() != null) {
+ pickDetailMapper.updateById(entity);
+ } else {
+ pickDetailMapper.insert(entity);
}
}
@@ -150,4 +229,282 @@ public class PickServiceImpl extends ServiceImpl implements IP
}
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public List allocatePickDetail(List pickDetails) {
+ List errorMsgList = new ArrayList<>();
+
+ //查询出库单
+ List pickIds = pickDetails.stream().map(PickDetail::getPickId).distinct().toList();
+ Map pickMap = queryByPickIdsToMap(pickIds);
+
+ //获取不为null、空字符的批次号
+ List propC1List = pickDetails.stream().map(PickDetail::getPropC1).filter(Objects::nonNull).filter(e -> !e.isEmpty()).distinct().toList();
+
+ //获取不为null、空字符的外部库存状态
+ List propC3List = pickDetails.stream().map(PickDetail::getPropC3).filter(Objects::nonNull).filter(e -> !e.isEmpty()).distinct().toList();
+
+
+ //获取不为null、空字符的仓库代码
+ List whCodeList = pickMap.values().stream().map(Pick::getWhCode).filter(Objects::nonNull).filter(e -> !e.isEmpty()).distinct().toList();
+
+
+ //查询需要分配的物料
+ List itemIds = pickDetails.stream().map(PickDetail::getItemId).distinct().toList();
+ Map itemMap = iItemService.queryByItemIdsToMap(itemIds);
+
+ //根据物料、批次号、外部库存状态、外部仓库代码批量查询库存
+ List inventories = inventoryMapper.queryInventoryWithLock(itemIds, propC1List, propC3List, whCodeList);
+ if (inventories.isEmpty()) {
+ List itemCodes = itemMap.values().stream().map(Item::getItemCode).toList();
+ errorMsgList.add(itemCodes + "物料库存不足");
+ return errorMsgList;
+ }
+
+ //容器
+ List stockIds = inventories.stream().map(Inventory::getStockId).distinct().toList();
+ Map stockMap = iStockService.queryByStockIdsToMap(stockIds);
+
+ //目标库位
+ List pointIds = inventories.stream().map(Inventory::getPointId).distinct().toList();
+ Map pointMap = iPointService.queryByPointIdsToMap(pointIds);
+
+ List updateToInventory = new ArrayList<>();
+ List updateToPickDetail = new ArrayList<>();
+
+ for (PickDetail pickDetail : pickDetails) {
+ Pick pick = pickMap.get(pickDetail.getPickId());
+ Item item = itemMap.get(pickDetail.getItemId());
+
+ //待分配数量
+ BigDecimal unAllocatedQty = BigDecimalUtil.subtract(pickDetail.getOrderQty(), pickDetail.getAllocatedQty(), 0);
+ // 如果已经满足需求则跳过
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) <= 0) {
+ continue;
+ }
+
+ for (Inventory inventory : inventories) {
+ // 筛选符合要求的库存记录
+ if (!inventory.getItemId().equals(pickDetail.getItemId())) {
+ continue;
+ }
+ // 匹配批次号(如果有指定)
+ if (pickDetail.getPropC1() != null && !pickDetail.getPropC1().isEmpty()) {
+ if (!pickDetail.getPropC1().equals(inventory.getPropC1())) {
+ continue;
+ }
+ }
+ // 匹配库存状态(如果有指定)
+ if (pickDetail.getPropC3() != null && !pickDetail.getPropC3().isEmpty()) {
+ if (!pickDetail.getPropC3().equals(inventory.getPropC3())) {
+ continue;
+ }
+ }
+ // 匹配仓库
+ if (!pick.getWhCode().equals(inventory.getWhCode())) {
+ continue;
+ }
+ //库存可用数量
+ BigDecimal availableQty = BigDecimalUtil.subtract(inventory.getQuantity(), inventory.getQueuedQty(), 0);
+ if (availableQty.compareTo(BigDecimal.ZERO) <= 0) {
+ continue;
+ }
+
+ BigDecimal allocateQty = unAllocatedQty.compareTo(availableQty) < 0 ? unAllocatedQty : availableQty;
+
+ // 更新库存占用数量
+ inventory.setQueuedQty(BigDecimalUtil.add(inventory.getQueuedQty(), allocateQty, 0));
+ inventory.setStatus(InventoryStatusEnum.ALLOCATED.getValue());
+ updateToInventory.add(inventory);
+
+ // 更新明细分配数量
+ BigDecimal fpQty = BigDecimalUtil.add(pickDetail.getAllocatedQty(), allocateQty, 0);
+ pickDetail.setAllocatedQty(fpQty);
+
+ // 更新明细状态
+ if (fpQty.compareTo(pickDetail.getOrderQty()) >= 0) {
+ pickDetail.setStatus(PickStatusEnum.ASSIGNED.getValue());
+ } else {
+ pickDetail.setStatus(PickStatusEnum.PARTIAL.getValue());
+ }
+ updateToPickDetail.add(pickDetail);
+
+ //容器
+ Stock stock = stockMap.get(inventory.getStockId());
+
+ //库位
+ Point point = pointMap.get(inventory.getPointId());
+
+ //TODO 后续补充生成Task任务
+ //判断是否整托
+ String tuo = "拆托";
+ if (inventory.getQuantity().compareTo(allocateQty) == 0) {
+ tuo = "整托";
+ }
+ log.info("生成任务: {} - {} - {}", stock.getStockCode(), point.getPointCode(), tuo);
+
+ unAllocatedQty = BigDecimalUtil.subtract(unAllocatedQty, allocateQty, 0);
+
+ //分配库存日志
+ iInventoryLogService.addAllocInventoryLog(inventory, allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
+
+ // 如果已完全分配,则跳出内层循环
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) <= 0) {
+ break;
+ }
+ }
+ // 若仍有未分配的数量,说明库存不足
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) > 0) {
+ errorMsgList.add(item.getItemCode() + "物料库存不足");
+ continue;
+ }
+
+ }
+
+ //批量操作
+ if (CollectionUtils.isNotEmpty(updateToInventory)) {
+ inventoryMapper.updateById(updateToInventory);
+ }
+ if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
+ pickDetailMapper.updateById(updateToPickDetail);
+ }
+
+ //刷新出库单
+ for (Pick pick : pickMap.values()) {
+ refreshPick(pick, pickDetailMapper.selectByMainId(pick.getId()));
+ }
+ return errorMsgList;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public List allocatePickDetail2(List pickDetails) {
+ // 错误信息去重(LinkedHashSet保证顺序和唯一)
+ Set errorMsgSet = new LinkedHashSet<>();
+
+ // -------------------------- 1. 查询关联数据(批量查询,减少DB交互)--------------------------
+ //获取出库单
+ List pickIds = pickDetails.stream().map(PickDetail::getPickId).distinct().toList();
+ Map pickMap = queryByPickIdsToMap(pickIds);
+
+ //获取物料
+ List itemIds = pickDetails.stream().map(PickDetail::getItemId).distinct().toList();
+ Map itemMap = iItemService.queryByItemIdsToMap(itemIds);
+
+ //筛选查询库存的条件(非空去重)批次、外部库存状态 、外部仓库
+ List propC1List = pickDetails.stream().map(PickDetail::getPropC1).filter(StringUtils::hasText).distinct().toList();
+ List propC3List = pickDetails.stream().map(PickDetail::getPropC3).filter(StringUtils::hasText).distinct().toList();
+ List whCodeList = pickMap.values().stream().map(Pick::getWhCode).filter(StringUtils::hasText).distinct().toList();
+
+ //查询库存
+ List inventories = inventoryMapper.queryInventoryWithLock(itemIds, propC1List, propC3List, whCodeList);
+ if (CollectionUtils.isEmpty(inventories)) {
+ String itemCodes = itemMap.values().stream().map(Item::getItemCode).collect(Collectors.joining(","));
+ errorMsgSet.add("【" + itemCodes + "】物料库存不足");
+ return new ArrayList<>(errorMsgSet);
+ }
+
+ //获取容器
+ List stockIds = inventories.stream().map(Inventory::getStockId).distinct().toList();
+ Map stockMap = iStockService.queryByStockIdsToMap(stockIds);
+
+ //获取目标库位
+ List pointIds = inventories.stream().map(Inventory::getPointId).distinct().toList();
+ Map pointMap = iPointService.queryByPointIdsToMap(pointIds);
+
+ // -------------------------- 2. 库存分组排序(优化匹配效率)--------------------------
+ // 按「物料ID+批次+库存状态+仓库」分组,且按创建时间升序(FIFO分配规则)
+ Map> inventoryGroupMap = inventories.stream()
+ .sorted(Comparator.comparing(Inventory::getCreateTime))
+ .collect(Collectors.groupingBy(inv -> InventoryGroupKey.of(
+ inv.getItemId(),
+ inv.getPropC1(),
+ inv.getPropC3(),
+ inv.getWhCode()
+ )));
+
+ // -------------------------- 3. 创建更新列表---------------------------
+ List updateToInventory = new ArrayList<>();
+ List updateToPickDetail = new ArrayList<>();
+
+ // -------------------------- 4. 循环分配库存 -------------------
+ for (PickDetail pickDetail : pickDetails) {
+ //出库单
+ Pick pick = pickMap.get(pickDetail.getPickId());
+ //物料
+ Item item = itemMap.get(pickDetail.getItemId());
+ //未分配数量
+ BigDecimal unAllocatedQty = BigDecimalUtil.subtract(pickDetail.getOrderQty(), pickDetail.getAllocatedQty(), 0);
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) <= 0) {
+ continue;
+ }
+ //匹配目标库存(通过分组key快速定位)
+ InventoryGroupKey groupKey = InventoryGroupKey.of(
+ pickDetail.getItemId(),
+ pickDetail.getPropC1(),
+ pickDetail.getPropC3(),
+ pick.getWhCode()
+ );
+ List matchedInventories = inventoryGroupMap.getOrDefault(groupKey, Collections.emptyList());
+ if (CollectionUtils.isEmpty(matchedInventories)) {
+ errorMsgSet.add(String.format("物料【%s】无匹配库存(物料ID:%s,批次:%s,库存状态:%s,仓库:%s)",
+ item.getItemCode(), item.getId(), pickDetail.getPropC1(), pickDetail.getPropC3(), pick.getWhCode()));
+ continue;
+ }
+ for (Inventory inventory : matchedInventories) {
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) <= 0) {
+ break;
+ }
+ // 库存可用数量
+ BigDecimal availableQty = BigDecimalUtil.subtract(inventory.getQuantity(), inventory.getQueuedQty(), 0);
+ if (availableQty.compareTo(BigDecimal.ZERO) <= 0) {
+ continue;
+ }
+ //本次分配数量(取最小值)
+ BigDecimal allocateQty = unAllocatedQty.min(availableQty);
+ // 更新库存占用数量
+ inventory.setQueuedQty(BigDecimalUtil.add(inventory.getQueuedQty(), allocateQty, 0));
+ inventory.setStatus(InventoryStatusEnum.ALLOCATED.getValue());
+ updateToInventory.add(inventory);
+ // 更新明细分配数量和状态
+ BigDecimal fpQty = BigDecimalUtil.add(pickDetail.getAllocatedQty(), allocateQty, 0);
+ pickDetail.setAllocatedQty(fpQty);
+ Integer status = fpQty.compareTo(pickDetail.getOrderQty()) >= 0 ? PickStatusEnum.ASSIGNED.getValue() : PickStatusEnum.PARTIAL.getValue();
+ pickDetail.setStatus(status);
+ updateToPickDetail.add(pickDetail);
+ //容器
+ Stock stock = stockMap.get(inventory.getStockId());
+ //库位
+ Point point = pointMap.get(inventory.getPointId());
+ String tuoType = inventory.getQuantity().compareTo(allocateQty) == 0 ? "整托" : "拆托";
+ log.info("生成拣货任务: 容器:{} - 库位:{} - 类型:{}- 分配数量:{}", stock.getStockCode(), point.getPointCode(), tuoType, allocateQty);
+ //分配库存日志
+ iInventoryLogService.addAllocInventoryLog(inventory, allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
+ //更新未分配数量
+ unAllocatedQty = BigDecimalUtil.subtract(unAllocatedQty, allocateQty, 0);
+ }
+ //分配后仍有缺货,记录错误
+ if (unAllocatedQty.compareTo(BigDecimal.ZERO) > 0) {
+ errorMsgSet.add(String.format("物料【%s】库存不足(需求:%s,已分配:%s,缺货:%s)",
+ item.getItemCode(), pickDetail.getOrderQty(),
+ BigDecimalUtil.subtract(pickDetail.getOrderQty(), unAllocatedQty, 0),
+ unAllocatedQty));
+ }
+ }
+
+ // -------------------------- 5. 批量更新(减少DB交互)--------------------------
+ if (CollectionUtils.isNotEmpty(updateToInventory)) {
+ inventoryMapper.updateById(updateToInventory);
+ }
+ if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
+ pickDetailMapper.updateById(updateToPickDetail);
+ }
+
+ // -------------------------- 6. 刷新出库单状态 --------------------------
+ for (Pick pick : pickMap.values()) {
+ refreshPick(pick, pickDetailMapper.selectByMainId(pick.getId()));
+ }
+ return new ArrayList<>(errorMsgSet);
+ }
+
}
diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryGroupKey.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryGroupKey.java
new file mode 100644
index 0000000..f85fa1f
--- /dev/null
+++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryGroupKey.java
@@ -0,0 +1,27 @@
+package org.cpte.modules.shipping.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode
+public class InventoryGroupKey {
+ private Long itemId;
+ private String propC1; // 批次号
+ private String propC3; // 库存状态
+ private String whCode; // 仓库代码
+
+ public static InventoryGroupKey of(Long itemId, String propC1, String propC3, String whCode) {
+ return new InventoryGroupKey(
+ itemId,
+ StringUtils.defaultIfBlank(propC1, ""), // 空值统一为"",避免分组不一致
+ StringUtils.defaultIfBlank(propC3, ""),
+ StringUtils.defaultIfBlank(whCode, "")
+ );
+ }
+}
diff --git a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
index 9aaea3e..4794696 100644
--- a/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
+++ b/cpte-module-system/cpte-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
@@ -64,7 +64,7 @@ public class SysLogController extends JeecgController {
//日志关键词
String keyWord = req.getParameter("keyWord");
if(oConvertUtils.isNotEmpty(keyWord)) {
- queryWrapper.like("log_content",keyWord);
+ queryWrapper.like("log_content",keyWord).or().like("request_param",keyWord);
}
//TODO 过滤逻辑处理
//TODO begin、end逻辑处理