no message
parent
f39de8e134
commit
3d5c48edf1
|
|
@ -116,8 +116,7 @@ public class BatchProcessor {
|
||||||
* 批量处理分配操作
|
* 批量处理分配操作
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void batchAllocate(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask) {
|
public boolean batchAllocate(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask) {
|
||||||
|
|
||||||
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
||||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||||
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
||||||
|
|
@ -128,7 +127,9 @@ public class BatchProcessor {
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(createToTask)) {
|
if (CollectionUtils.isNotEmpty(createToTask)) {
|
||||||
batchUtil.saveBatchTask(createToTask);
|
batchUtil.saveBatchTask(createToTask);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -154,9 +154,9 @@ public class InventoryController extends JeecgController<Inventory, IInventorySe
|
||||||
pointMapper.updateById(newPoint);
|
pointMapper.updateById(newPoint);
|
||||||
}
|
}
|
||||||
ItemKey itemKey = itemKeyService.createItemKey(inventory.getItemId(), inventory.getWhCode(), inventory.getProject(), inventory.getTaskNo(), inventory.getPropC1(), inventory.getPropC3());
|
ItemKey itemKey = itemKeyService.createItemKey(inventory.getItemId(), inventory.getWhCode(), inventory.getProject(), inventory.getTaskNo(), inventory.getPropC1(), inventory.getPropC3());
|
||||||
oldInventory.setItemKeyId(itemKey.getId());
|
inventory.setItemKeyId(itemKey.getId());
|
||||||
oldInventory.setItemId(inventory.getItemId());
|
inventory.setItemId(inventory.getItemId());
|
||||||
inventoryMapper.updateById(oldInventory);
|
inventoryService.updateById(inventory);
|
||||||
return Result.OK("编辑成功!");
|
return Result.OK("编辑成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,6 @@ public class AllocatePickDetailJob implements Job {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPickDetailService pickDetailService;
|
private IPickDetailService pickDetailService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BaseCommonService baseCommonService;
|
|
||||||
|
|
||||||
// 使用 ConcurrentHashMap 缓存已处理的结果
|
|
||||||
private static final Map<String, Boolean> processedCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
// 缓存最大大小,防止内存溢出
|
|
||||||
private static final int MAX_CACHE_SIZE = 1000;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobExecutionContext jobExecutionContext) {
|
public void execute(JobExecutionContext jobExecutionContext) {
|
||||||
//1.获取未拣货完成的出库明细
|
//1.获取未拣货完成的出库明细
|
||||||
|
|
@ -176,7 +167,10 @@ public class AllocatePickDetailJob implements Job {
|
||||||
|
|
||||||
// 检查是否需要分配
|
// 检查是否需要分配
|
||||||
if (shouldAllocatePickDetail(executingTaskKeys, currentKey)) {
|
if (shouldAllocatePickDetail(executingTaskKeys, currentKey)) {
|
||||||
allocatePickDetail(detail);
|
boolean allocated = allocatePickDetail(detail);
|
||||||
|
if (allocated) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // 未分配任何明细
|
return false; // 未分配任何明细
|
||||||
|
|
@ -221,7 +215,10 @@ public class AllocatePickDetailJob implements Job {
|
||||||
if (isAlreadyAssigned(detail.getStatus())) {
|
if (isAlreadyAssigned(detail.getStatus())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
allocatePickDetail(detail);
|
boolean allocated = allocatePickDetail(detail);
|
||||||
|
if (allocated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,45 +232,13 @@ public class AllocatePickDetailJob implements Job {
|
||||||
return PickStatusEnum.ASSIGNED.getValue().equals(status);
|
return PickStatusEnum.ASSIGNED.getValue().equals(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void allocatePickDetail(PickDetail pickDetail) {
|
private boolean allocatePickDetail(PickDetail pickDetail) {
|
||||||
// 分配单个出库明细
|
|
||||||
List<String> resultMsg;
|
|
||||||
try {
|
try {
|
||||||
// 每次只分配一个出库单明细
|
return pickService.allocatePickDetail(pickDetail);
|
||||||
resultMsg = pickService.allocatePickDetail(pickDetail);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
resultMsg = List.of(e.getMessage());
|
log.error("分配出库明细失败,ID: {}, 错误: {}", pickDetail.getId(), e.getMessage());
|
||||||
log.error("分配出库明细失败,ID: {}, 错误: {}", pickDetail.getId(), resultMsg);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成缓存键 - 基于分配结果生成唯一标识
|
|
||||||
*/
|
|
||||||
private String generateCacheKey(List<String> resultMsg) {
|
|
||||||
// 对结果进行排序后拼接,确保相同内容生成相同键
|
|
||||||
return resultMsg.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.sorted()
|
|
||||||
.collect(Collectors.joining("\n"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,10 @@ public class Asn implements Serializable {
|
||||||
@Schema(description = "系统单号")
|
@Schema(description = "系统单号")
|
||||||
private java.lang.String orderNo;
|
private java.lang.String orderNo;
|
||||||
/**
|
/**
|
||||||
* 外部单号
|
* 赛意单号
|
||||||
*/
|
*/
|
||||||
@Excel(name = "外部单号", width = 15)
|
@Excel(name = "赛意单号", width = 15)
|
||||||
@Schema(description = "外部单号")
|
@Schema(description = "赛意单号")
|
||||||
private java.lang.String thirdOrderNo;
|
private java.lang.String thirdOrderNo;
|
||||||
/**
|
/**
|
||||||
* 任务号
|
* 任务号
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public interface IPickService extends IService<Pick> {
|
||||||
*
|
*
|
||||||
* @param pickDetail 出库单明细
|
* @param pickDetail 出库单明细
|
||||||
*/
|
*/
|
||||||
List<String> allocatePickDetail(PickDetail pickDetail);
|
boolean allocatePickDetail(PickDetail pickDetail);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消分配
|
* 取消分配
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> allocatePickDetail(PickDetail pickDetail) {
|
public boolean allocatePickDetail(PickDetail pickDetail) {
|
||||||
return allocateProcessor.allocatePickDetail(pickDetail);
|
return allocateProcessor.allocatePickDetail(pickDetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,14 @@ import org.cpte.modules.shipping.vo.InventoryScore;
|
||||||
import org.cpte.modules.shipping.vo.ItemGroupKey;
|
import org.cpte.modules.shipping.vo.ItemGroupKey;
|
||||||
import org.cpte.modules.utils.BigDecimalUtil;
|
import org.cpte.modules.utils.BigDecimalUtil;
|
||||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,6 +84,9 @@ public class AllocateProcessor {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IInventoryLogService inventoryLogService;
|
private IInventoryLogService inventoryLogService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BaseCommonService baseCommonService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ScanTrayProcessor scanTrayProcessor;
|
private ScanTrayProcessor scanTrayProcessor;
|
||||||
|
|
||||||
|
|
@ -93,6 +99,12 @@ public class AllocateProcessor {
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisDistributedLockUtil redissonLock;
|
private RedisDistributedLockUtil redissonLock;
|
||||||
|
|
||||||
|
// 使用 ConcurrentHashMap 缓存已处理的结果
|
||||||
|
private static final Map<String, Boolean> processedCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 缓存最大大小,防止内存溢出
|
||||||
|
private static final int MAX_CACHE_SIZE = 1000;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分配出库单
|
* 分配出库单
|
||||||
|
|
@ -108,7 +120,7 @@ public class AllocateProcessor {
|
||||||
AllocationData data = prepareAllocationData(pickIds);
|
AllocationData data = prepareAllocationData(pickIds);
|
||||||
|
|
||||||
//2.验证库存
|
//2.验证库存
|
||||||
if (!validateInventory(data, errorMsgSet)) {
|
if (validateInventory(data, errorMsgSet)) {
|
||||||
return new ArrayList<>(errorMsgSet);
|
return new ArrayList<>(errorMsgSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,7 +151,7 @@ public class AllocateProcessor {
|
||||||
* @param pickDetail 出库单明细
|
* @param pickDetail 出库单明细
|
||||||
* @return 错误信息
|
* @return 错误信息
|
||||||
*/
|
*/
|
||||||
public List<String> allocatePickDetail(PickDetail pickDetail) {
|
public boolean allocatePickDetail(PickDetail pickDetail) {
|
||||||
// 错误信息去重(LinkedHashSet保证顺序和唯一)
|
// 错误信息去重(LinkedHashSet保证顺序和唯一)
|
||||||
Set<String> errorMsgSet = new LinkedHashSet<>();
|
Set<String> errorMsgSet = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
|
@ -147,8 +159,8 @@ public class AllocateProcessor {
|
||||||
AllocationData data = prepareAllocationDetailData(pickDetail);
|
AllocationData data = prepareAllocationDetailData(pickDetail);
|
||||||
|
|
||||||
//2.验证库存
|
//2.验证库存
|
||||||
if (!validateInventory(data, errorMsgSet)) {
|
if (validateInventory(data, errorMsgSet)) {
|
||||||
return new ArrayList<>(errorMsgSet);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//3.创建数据结构
|
//3.创建数据结构
|
||||||
|
|
@ -164,12 +176,12 @@ public class AllocateProcessor {
|
||||||
moveTask(createToTask, movePoints);
|
moveTask(createToTask, movePoints);
|
||||||
|
|
||||||
//6.批量操作
|
//6.批量操作
|
||||||
batchProcessor.batchAllocate(inventoryUpdateMap, pickDetailUpdateMap, createToTask);
|
boolean result = batchProcessor.batchAllocate(inventoryUpdateMap, pickDetailUpdateMap, createToTask);
|
||||||
|
|
||||||
//7.刷新出库单
|
//7.刷新出库单
|
||||||
refreshData(data);
|
refreshData(data);
|
||||||
|
|
||||||
return new ArrayList<>(errorMsgSet);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -212,8 +224,8 @@ public class AllocateProcessor {
|
||||||
List<Long> itemKeyIds = list.stream().map(Inventory::getItemKeyId).distinct().toList();
|
List<Long> itemKeyIds = list.stream().map(Inventory::getItemKeyId).distinct().toList();
|
||||||
List<ItemKey> iks = itemKeyMapper.selectByIds(itemKeyIds);
|
List<ItemKey> iks = itemKeyMapper.selectByIds(itemKeyIds);
|
||||||
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
||||||
for (ItemKey ik : iks){
|
for (ItemKey ik : iks) {
|
||||||
if(!itemKeys.contains(ik)){
|
if (!itemKeys.contains(ik)) {
|
||||||
itemKeys.add(ik);
|
itemKeys.add(ik);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,7 +235,7 @@ public class AllocateProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(CollectionUtils.isNotEmpty(itemKeys)){
|
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
||||||
//根据物料属性分组
|
//根据物料属性分组
|
||||||
Map<ItemGroupKey, ItemKey> itemGroupKey = itemKeys.stream()
|
Map<ItemGroupKey, ItemKey> itemGroupKey = itemKeys.stream()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
|
|
@ -306,8 +318,8 @@ public class AllocateProcessor {
|
||||||
List<Long> itemKeyIds = list.stream().map(Inventory::getItemKeyId).distinct().toList();
|
List<Long> itemKeyIds = list.stream().map(Inventory::getItemKeyId).distinct().toList();
|
||||||
List<ItemKey> iks = itemKeyMapper.selectByIds(itemKeyIds);
|
List<ItemKey> iks = itemKeyMapper.selectByIds(itemKeyIds);
|
||||||
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
||||||
for (ItemKey ik : iks){
|
for (ItemKey ik : iks) {
|
||||||
if(!itemKeys.contains(ik)){
|
if (!itemKeys.contains(ik)) {
|
||||||
itemKeys.add(ik);
|
itemKeys.add(ik);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +328,7 @@ public class AllocateProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(CollectionUtils.isNotEmpty(itemKeys)){
|
if (CollectionUtils.isNotEmpty(itemKeys)) {
|
||||||
//根据物料属性分组
|
//根据物料属性分组
|
||||||
Map<ItemGroupKey, ItemKey> itemGroupKey = itemKeys.stream()
|
Map<ItemGroupKey, ItemKey> itemGroupKey = itemKeys.stream()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
|
|
@ -373,9 +385,11 @@ public class AllocateProcessor {
|
||||||
if (CollectionUtils.isEmpty(inventories)) {
|
if (CollectionUtils.isEmpty(inventories)) {
|
||||||
String itemCodes = data.getItemMap().values().stream().map(Item::getItemCode).collect(Collectors.joining(","));
|
String itemCodes = data.getItemMap().values().stream().map(Item::getItemCode).collect(Collectors.joining(","));
|
||||||
errorMsgSet.add("【" + itemCodes + "】物料库存不足");
|
errorMsgSet.add("【" + itemCodes + "】物料库存不足");
|
||||||
return false;
|
String cacheKey = generateCacheKey(errorMsgSet);
|
||||||
|
logAndCacheResult(cacheKey);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -465,6 +479,9 @@ public class AllocateProcessor {
|
||||||
);
|
);
|
||||||
|
|
||||||
ItemKey itemKey = data.getItemGroupMap().get(groupKey);
|
ItemKey itemKey = data.getItemGroupMap().get(groupKey);
|
||||||
|
if (itemKey == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
return data.getInventoryMap().get(itemKey.getId());
|
return data.getInventoryMap().get(itemKey.getId());
|
||||||
}
|
}
|
||||||
|
|
@ -482,6 +499,8 @@ public class AllocateProcessor {
|
||||||
errorMsgSet.add(String.format("物料【%s】无匹配库存(物料ID:%s,批次:%s,库存状态:%s,仓库:%s)",
|
errorMsgSet.add(String.format("物料【%s】无匹配库存(物料ID:%s,批次:%s,库存状态:%s,仓库:%s)",
|
||||||
item.getItemCode(), item.getId(),
|
item.getItemCode(), item.getId(),
|
||||||
pickDetail.getPropC1(), pickDetail.getPropC3(), pick.getWhCode()));
|
pickDetail.getPropC1(), pickDetail.getPropC3(), pick.getWhCode()));
|
||||||
|
String cacheKey = generateCacheKey(errorMsgSet);
|
||||||
|
logAndCacheResult(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -516,7 +535,7 @@ public class AllocateProcessor {
|
||||||
Stock stock = stockService.getById(pickDetail.getStockId());
|
Stock stock = stockService.getById(pickDetail.getStockId());
|
||||||
String message = String.format("任务号【%s】,容器【%s】无库存", pick.getNo(), stock.getStockCode());
|
String message = String.format("任务号【%s】,容器【%s】无库存", pick.getNo(), stock.getStockCode());
|
||||||
errorMsgSet.add(message);
|
errorMsgSet.add(message);
|
||||||
return;
|
logAndCacheResult(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
//未分配数量
|
//未分配数量
|
||||||
|
|
@ -877,6 +896,7 @@ public class AllocateProcessor {
|
||||||
unallocateQty
|
unallocateQty
|
||||||
);
|
);
|
||||||
errorMsgSet.add(failInfo);
|
errorMsgSet.add(failInfo);
|
||||||
|
logAndCacheResult(failInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -992,4 +1012,35 @@ public class AllocateProcessor {
|
||||||
pickDetailService.refreshPick(entry.getValue(), pickDetailMapper.selectByMainId(entry.getKey()));
|
pickDetailService.refreshPick(entry.getValue(), pickDetailMapper.selectByMainId(entry.getKey()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录日志并缓存处理结果
|
||||||
|
*
|
||||||
|
* @param cacheKey 缓存键
|
||||||
|
*/
|
||||||
|
private void logAndCacheResult(String cacheKey) {
|
||||||
|
// 检查是否已经处理过相同的内容
|
||||||
|
if (!processedCache.containsKey(cacheKey)) {
|
||||||
|
// 新内容,记录日志
|
||||||
|
// 注意:这里需要注入baseCommonService
|
||||||
|
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(Collection<String> resultMsg) {
|
||||||
|
// 对结果进行排序后拼接,确保相同内容生成相同键
|
||||||
|
return resultMsg.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue