opt:优化称重同步功能;

This commit is contained in:
2026-08-16 14:42:51 +08:00
parent 90163d54ce
commit 88c66adb41
25 changed files with 721 additions and 96 deletions

View File

@@ -63,16 +63,18 @@ public class EndDecisionChainer extends DecisionerChain<List> {
List<String> structs = new ArrayList<>();
//入库分配
if (in_storage) {
//混托任务判断
//非异常任务,且是混托任务判断,直接返回库位
if (startParam.getString("vehicle_code").contains("T")) {
List<SchBaseTask> schBaseTaskList = iSchBaseTaskService.list(new QueryWrapper<SchBaseTask>()
.eq("vehicle_code", startParam.getString("vehicle_code")).select("point_code2")
.lt("status", StatusEnum.FORM_STATUS.code("完成")));
if (CollectionUtil.isNotEmpty(schBaseTaskList)) {
if (!"errorTask".equals(startParam.getString("errorTask"))) {
structs.add(schBaseTaskList.get(0).getPoint_code2());
return structs;
}
}
}
StIvtStructattr struct = (StIvtStructattr) transfers.get(0);
UpdateWrapper<StIvtStructattr> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("lock_type", StatusEnum.LOCK.code("入库锁"))

View File

@@ -48,14 +48,12 @@ public class AlleyAveRuleHandler extends Decisioner<StIvtStructattr, JSONObject>
@Override
public List<StIvtStructattr> handler(List<StIvtStructattr> list, JSONObject param) {
// 判断仓位是否为空
if (CollectionUtils.isEmpty(list)) {
if (ObjectUtils.isEmpty(list)) {
log.error("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略无可用货位");
return Collections.emptyList();
}
long startTime1 = System.currentTimeMillis();
if (ObjectUtils.isNotEmpty(list)) {
//扩展库不需要均衡策略
if ("LXBCP02".equals(list.get(0).getSect_code())) {
}else {
//扩展库和移库不需要均衡策略
if ("LXBCP02".equals(list.get(0).getSect_code())||Boolean.parseBoolean(param.getString("is_move"))) {
return list;
}
}
@@ -93,7 +91,6 @@ public class AlleyAveRuleHandler extends Decisioner<StIvtStructattr, JSONObject>
subList = subList.stream().filter(r -> !r.getStruct_code().equals(result.getStruct_code())).collect(Collectors.toList());
}
log.info("均衡策略结果:载具号:" + param.getString("vehicle_code") + "分配结果: " + subList.stream().map(StIvtStructattr::getStruct_code).collect(Collectors.toList()));
log.info("均衡策略:载具号:" + param.getString("vehicle_code") + "获取仓位耗时:{}", System.currentTimeMillis() - startTime1);
if (subList.size() == 0) {
log.error("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略货位数量为0");
return Collections.emptyList();

View File

@@ -57,6 +57,7 @@ public class LimitStorageRuleHandler extends Decisioner<StIvtStructattr, JSONObj
String vehicleCode = param.getString("vehicle_code");
BmVehicleInfo vehileInfo = bmVehicleInfoService.vehileInfo(vehicleCode);
// if (vehileInfo == null) {
//
// throw new BadRequestException("限位策略,当前载具信息不存在:" + vehicleCode + "!");
// }
//限位策略特殊处理
@@ -99,7 +100,6 @@ public class LimitStorageRuleHandler extends Decisioner<StIvtStructattr, JSONObj
vehicle.setW(0);
vehicle.setL(0);
vehicle.setWeight(0);
}
BmVehicleInfo finalVehicle = vehicle;
Predicate<StIvtStructattr> eqLimt = stIvtStructattr -> {

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.nl.common.enums.StatusEnum;
import org.nl.common.utils.SpringContextHolder;
import org.nl.wms.decision_manage.handler.decisioner.Decisioner;
@@ -14,10 +15,7 @@ import org.nl.wms.stor_manage.struct.service.IStIvtStructattrService;
import org.nl.wms.stor_manage.struct.service.dao.StIvtStructattr;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/*
@@ -42,6 +40,73 @@ public class DepthPriorityHandler extends Decisioner<StIvtStructattr, JSONObject
if (list.get(0).getStor_code().equals(StatusEnum.STOCK_INFO.code("托盘库")) || "LXBCP02".equals(list.get(0).getSect_code())) {
return list;
}
//移库任务
if (Boolean.parseBoolean(param.getString("is_move"))) {
// 深货位
List<StIvtStructattr> allDepCollectL1 = list.stream()
.filter(a -> a.getRow_num() == 1)
.collect(Collectors.toList());
List<StIvtStructattr> allDepCollectL4 = list.stream()
.filter(a -> a.getRow_num() == 4)
.collect(Collectors.toList());
// 浅货位
List<StIvtStructattr> allShallowCollect = list.stream()
.filter(a -> a.getRow_num() == 2 || a.getRow_num() == 3)
.collect(Collectors.toList());
List<StIvtStructattr> allShallowCollectL2 = list.stream()
.filter(a -> a.getRow_num() == 2)
.collect(Collectors.toList());
List<StIvtStructattr> allShallowCollectL3 = list.stream()
.filter(a ->a.getRow_num() == 3)
.collect(Collectors.toList());
Set<String> allShallowCollectSetL2 = allShallowCollectL2.stream()
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
.collect(Collectors.toSet());
Set<String> allShallowCollectSetL3 = allShallowCollectL3.stream()
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
.collect(Collectors.toSet());
//过滤出无阻挡的全部深货位
List<StIvtStructattr> allDepListL1 = allDepCollectL1.stream()
.filter(r -> allShallowCollectSetL2.contains(r.getCol_num() + "_" + r.getLayer_num()))
.collect(Collectors.toList());
List<StIvtStructattr> allDepListL4 = allDepCollectL4.stream()
.filter(r -> allShallowCollectSetL3.contains(r.getCol_num() + "_" + r.getLayer_num()))
.collect(Collectors.toList());
List<StIvtStructattr> alldepList =new ArrayList<>();
alldepList.addAll(allDepListL1);
alldepList.addAll(allDepListL4);
List<StIvtStructattr> depCollect = alldepList.stream().filter(item -> item.getRow_num() == 1 && item.getLayer_num() >= 24 && item.getLayer_num() <= 31).collect(Collectors.toList());
List<StIvtStructattr> shallowCollect = allShallowCollect.stream().filter(item -> item.getRow_num() == 2 && item.getLayer_num() >= 24 && item.getLayer_num() <= 31).collect(Collectors.toList());
log.info("移库深位优先策略:载具号:{} 分配结果第一个: 全部深库位:{}, 全部浅库位:{}, 专属移库深库位:{}, 专属移库浅库位:{}",
param.getString("vehicle_code"),
alldepList.isEmpty() ? "无数据" : alldepList.get(0),
allShallowCollect.isEmpty() ? "无数据" : allShallowCollect.get(0),
depCollect.isEmpty() ? "无数据" : depCollect.get(0),
shallowCollect.isEmpty() ? "无数据" : shallowCollect.get(0)
);
// 实现深位优先策略
// 获取起始货位信息
String startStructCode = param.getString("start_struct_code");
String[] parts = startStructCode.split("-");
// int p = Integer.parseInt(parts[0].replaceAll("\\D", ""));
int l = Integer.parseInt(parts[1].replaceAll("\\D", ""));
int c = Integer.parseInt(parts[2].replaceAll("\\D", ""));
// 实现深位优先策略
StIvtStructattr result = findBestStructByDeepFirstStrategy(alldepList, allShallowCollect, depCollect, shallowCollect, l, c);
if (result != null) {
log.info("移库深位优先策略:载具号:{} 分配结果: 存在深位并对应浅位无货的库位,分配仓位:{}", param.getString("vehicle_code"),result.getStruct_code());
return Collections.singletonList(result);
}
log.info("移库深位优先策略:载具号:{} 分配结果: 不存在可用移库库位,查找入库库位", param.getString("vehicle_code"));
} else {
//入库任务
//34排不限制移库专属
List<StIvtStructattr> list2 = list.stream().filter(item -> item.getRow_num() > 2).collect(Collectors.toList());
List<StIvtStructattr> list3 = list.stream().filter(item -> (item.getRow_num() < 3) && (item.getLayer_num() < 24 || item.getLayer_num() > 31)).collect(Collectors.toList());
List<StIvtStructattr> list4 = new ArrayList<>(list2);
list4.addAll(list3);
list = list4;
}
long startTime1 = System.currentTimeMillis();
List<StIvtStructattr> returnResult = new ArrayList<>();
// 深货位
@@ -52,6 +117,7 @@ public class DepthPriorityHandler extends Decisioner<StIvtStructattr, JSONObject
List<StIvtStructattr> shallowCollect = list.stream()
.filter(a -> a.getRow_num() == 2 || a.getRow_num() == 3)
.collect(Collectors.toList());
//找出深和浅货位都无货的深货位
for (StIvtStructattr r : depCollect) {
for (StIvtStructattr s : shallowCollect) {
String depCode = r.getCol_num() + "-" + r.getLayer_num();
@@ -136,7 +202,7 @@ public class DepthPriorityHandler extends Decisioner<StIvtStructattr, JSONObject
.collect(Collectors.toList());
combinedResult.addAll(intersection2);
}
if (combinedResult.size() < 30) {
if (combinedResult.size() < 20) {
ISchBaseTaskService iSchBaseTaskService = SpringContextHolder.getBean(ISchBaseTaskService.class);
List<SchBaseTask> taskList = iSchBaseTaskService.list(
new LambdaQueryWrapper<SchBaseTask>()
@@ -148,7 +214,7 @@ public class DepthPriorityHandler extends Decisioner<StIvtStructattr, JSONObject
.filter(t -> t.getTask_type().equals(StatusEnum.IOBILL_TYPE_IN.code("生产入库")) || t.getTask_type().equals(StatusEnum.IOBILL_TYPE_IN.code("拣选回库")))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(taskList)) {
log.error("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位已不足30个");
log.error("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位已不足20个");
return Collections.emptyList();
}
}
@@ -161,5 +227,139 @@ public class DepthPriorityHandler extends Decisioner<StIvtStructattr, JSONObject
}
}
/**
* 深位优先策略:寻找最佳货位
*
* @param depCollect 深货位集合row_num=1
* @param shallowCollect 浅货位集合row_num=2
* @param targetCol 目标列号
* @param targetLayer 目标层号
* @return 最佳匹配的货位
*/
private StIvtStructattr findBestStructByDeepFirstStrategy(List<StIvtStructattr> allDepCollect,
List<StIvtStructattr> allShallowCollect,
List<StIvtStructattr> depCollect,
List<StIvtStructattr> shallowCollect,
int targetCol,
int targetLayer) {
// 1. 先在深货位中查找相同列的货位
StIvtStructattr result = findInCollectionWithSameColumn(depCollect,allDepCollect, targetCol, targetLayer);
if (result != null) {
return result;
}
// 2. 如果深货位中没有,则在浅货位中查找相同列的货位
result = findInCollectionWithSameColumn(shallowCollect,allShallowCollect, targetCol, targetLayer);
if (result != null) {
return result;
}
// 3. 如果都没有相同列,则查找最近的列(不需要排除层)
result = findNearestColumn(depCollect,allDepCollect, targetCol, targetLayer);
if (result != null) {
return result;
}
// 4. 最后尝试浅货位中最近的列
result = findNearestColumn(shallowCollect,allShallowCollect, targetCol, targetLayer);
return result;
}
/**
* 在集合中查找相同列的货位,排除自身层和相邻层
*
* @param collection 货位集合
* @param targetCol 目标列号
* @param targetLayer 目标层号
* @return 匹配的货位
*/
private StIvtStructattr findInCollectionWithSameColumn(List<StIvtStructattr> collection, List<StIvtStructattr> allCollect,
int targetCol,
int targetLayer) {
// 筛选出相同列的货位
List<StIvtStructattr> sameColList = collection.stream()
.filter(item -> item.getCol_num() != null && item.getCol_num() == targetCol)
.collect(Collectors.toList());
if (ObjectUtils.isEmpty(sameColList)) {
sameColList = allCollect.stream()
.filter(item -> item.getCol_num() != null && item.getCol_num() == targetCol)
.collect(Collectors.toList());
if (ObjectUtils.isEmpty(sameColList)) {
return null;
}
}
// 排除自身层和相邻层targetLayer-1, targetLayer, targetLayer+1
List<StIvtStructattr> filteredList = sameColList.stream()
.filter(item -> {
Integer layer = item.getLayer_num();
if (layer == null) {
return false;
}
// 排除自身层和相邻层
return Math.abs(layer - targetLayer) > 1;
})
.collect(Collectors.toList());
if (ObjectUtils.isEmpty(filteredList)) {
return null;
}
// 找到与目标层数最接近的货位
return filteredList.stream()
.min((a, b) -> {
int diffA = Math.abs(a.getLayer_num() - targetLayer);
int diffB = Math.abs(b.getLayer_num() - targetLayer);
return Integer.compare(diffA, diffB);
})
.orElse(null);
}
/**
* 在集合中查找最近的列(不需要排除层)
*
* @param collection 货位集合
* @param targetCol 目标列号
* @param targetLayer 目标层号
* @return 匹配的货位
*/
private StIvtStructattr findNearestColumn(List<StIvtStructattr> collection, List<StIvtStructattr> allCollect,
int targetCol,
int targetLayer) {
if (ObjectUtils.isEmpty(collection) && ObjectUtils.isEmpty(allCollect)) {
return null;
}
// 按列号分组,找出与目标列差值最小的列
Map<Integer, List<StIvtStructattr>> colGroupMap = collection.stream()
.filter(item -> item.getCol_num() != null)
.collect(Collectors.groupingBy(StIvtStructattr::getCol_num));
if (colGroupMap.isEmpty()) {
colGroupMap = allCollect.stream()
.filter(item -> item.getCol_num() != null)
.collect(Collectors.groupingBy(StIvtStructattr::getCol_num));
if (colGroupMap.isEmpty()) {
return null;
}
}
// 找到与目标列差值绝对值最小的列号
Integer nearestCol = colGroupMap.keySet().stream()
.min((col1, col2) -> {
int diff1 = Math.abs(col1 - targetCol);
int diff2 = Math.abs(col2 - targetCol);
return Integer.compare(diff1, diff2);
})
.orElse(null);
if (nearestCol == null) {
return null;
}
// 在该列中找到与目标层数最接近的货位
List<StIvtStructattr> nearestColList = colGroupMap.get(nearestCol);
return nearestColList.stream()
.min((a, b) -> {
Integer layerA = a.getLayer_num() != null ? a.getLayer_num() : 0;
Integer layerB = b.getLayer_num() != null ? b.getLayer_num() : 0;
int diffA = Math.abs(layerA - targetLayer);
int diffB = Math.abs(layerB - targetLayer);
return Integer.compare(diffA, diffB);
})
.orElse(null);
}
}

View File

@@ -78,6 +78,8 @@ public class SchBasePointController {
TableDataInfo result = pointService.bindOrUnbind(entity.getCode(), entity.getVehicle_code(), (entity.getPriority()));
if (!"200".equals(result.getCode())) {
throw new BadRequestException("地面站点:" + entity.getCode() + "绑定或解绑" + entity.getVehicle_code() + "指令下发CTU返回操作失败失败原因:" + result.getMsg());
}else{
lambdaUpdateWrapper.set(SchBasePoint::getRemark,"地面站点:" + entity.getCode() + "绑定或解绑" + entity.getVehicle_code() + "指令下发CTU返回操作成功。");
}
}
} else {

View File

@@ -118,12 +118,11 @@ public class MoveStorageTask extends AbstractTask {
//移库完成后,起点作为技改锁,支持技改,不再入库,技改完成后需要解锁
iStIvtStructattrService.update(
new UpdateWrapper<StIvtStructattr>()
.set("lock_type", StatusEnum.LOCK.code("技改"))
.set("is_used",0)
.set("lock_type", StatusEnum.LOCK.code("禁分配"))
.eq("struct_code", schBaseTask.getPoint_code1())
);
// List<SchBaseTask> taskList = taskService.list(new QueryWrapper<SchBaseTask>().eq("source_form_id", "99").lt("status", StatusEnum.FORM_STATUS.code("完成")));
//移库任务完成,解锁需要维护不能分配的区域
// // 移库任务完成,解锁需要维护不能分配的区域
// if (taskList.size() == 0) {
// UpdateWrapper<StIvtStructattr> wrapper = new UpdateWrapper<>();
// wrapper.set("update_time", DateUtil.now())
@@ -144,5 +143,14 @@ public class MoveStorageTask extends AbstractTask {
.eq("struct_code", schBaseTask.getPoint_code1());
iStIvtStructattrService.update(wrapper);
this.updateTask(data);
List<SchBaseTask> taskList = taskService.list(new QueryWrapper<SchBaseTask>().eq("source_form_id", "99").lt("status", StatusEnum.FORM_STATUS.code("完成")));
// 移库任务完成,解锁需要维护不能分配的区域
if (taskList.size() == 0) {
UpdateWrapper<StIvtStructattr> wrapper2 = new UpdateWrapper<>();
wrapper2.set("update_time", DateUtil.now())
.set("lock_type", StatusEnum.LOCK.code("无锁"))
.eq("lock_type", StatusEnum.LOCK.code("禁分配锁"));
iStIvtStructattrService.update(wrapper2);
}
}
}

View File

@@ -193,7 +193,7 @@ public class OutStorageTask extends AbstractTask {
AtomicReference<String> moveStruct = new AtomicReference<>();
RedissonUtils.lock(() -> {
System.out.println("---3--" + Thread.currentThread().getName());
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", block.getStor_code(), "vehicle_code", block.getVehicle_code())));
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", block.getStor_code(), "vehicle_code", block.getVehicle_code(),"start_struct_code", block.getStruct_code())));
moveStruct.set(((Map<String, String>) process.get("form_data")).get("end_struct_code"));
}, "1" + block.getStor_code(), 5);
Map moveForm = MapOf.of("task_type", StatusEnum.IOBILL_TYPE_MOVE.code("移库")

View File

@@ -120,11 +120,11 @@ public class SecondFloorAgvTransferTask extends AbstractTask {
@Transactional(rollbackFor = Exception.class)
public void cancel(JSONObject data) {
try {
SchBaseTask schBaseTask = iSchBaseTaskService.getOne(new QueryWrapper<SchBaseTask>().eq("task_code", data.getString("task_code")));
iSchBaseTaskService.update(new LambdaUpdateWrapper<SchBaseTask>()
.set(SchBaseTask::getTask_step, "1")
.eq(SchBaseTask::getTask_type, StatusEnum.IOBILL_TYPE_OUT.code("二楼CTU出库"))
.in(SchBaseTask::getGroup_code, schBaseTask.getGroup_code()));
// SchBaseTask schBaseTask = iSchBaseTaskService.getOne(new QueryWrapper<SchBaseTask>().eq("task_code", data.getString("task_code")));
// iSchBaseTaskService.update(new LambdaUpdateWrapper<SchBaseTask>()
// .set(SchBaseTask::getTask_step, "1")
// .eq(SchBaseTask::getTask_type, StatusEnum.IOBILL_TYPE_OUT.code("二楼CTU出库"))
// .in(SchBaseTask::getGroup_code, schBaseTask.getGroup_code()));
this.updateTask(data);
} catch (Exception e) {
throw new BadRequestException("取消任务失败,失败原因:" + e.getMessage());

View File

@@ -231,8 +231,10 @@ public class SecondFloorOutStorageTask extends AbstractTask {
.set(MdPbVehicleMater::getFrozen_qty, 0)
.set(MdPbVehicleMater::getRemark, r.getTask_code() + "任务被取消,任务组:" + r.getGroup_code() + "任务都被取消。")
.eq(MdPbVehicleMater::getId, r.getSource_form_id());
//任务取消后不再自动生成任务
LambdaUpdateWrapper<SchBaseTask> updateWrapper3 = new LambdaUpdateWrapper<SchBaseTask>()
.set(SchBaseTask::getRemark, r.getTask_code() + "任务被取消,任务组:" + r.getGroup_code() + "任务都被取消。")
.set(SchBaseTask::getTask_step,"2")
.eq(SchBaseTask::getId, r.getId());
if (r.getStatus().equals(StatusEnum.FORM_STATUS.code("完成"))) {
//清除库存

View File

@@ -15,6 +15,7 @@ import org.nl.common.utils.IdUtil;
import org.nl.common.utils.SecurityUtils;
import org.nl.common.utils.SpringContextHolder;
import org.nl.wms.dispatch_manage.point.service.ISchBasePointService;
import org.nl.wms.dispatch_manage.point.service.dao.SchBasePoint;
import org.nl.wms.dispatch_manage.task.handler.AbstractTask;
import org.nl.wms.dispatch_manage.task.service.ISchBaseTaskService;
import org.nl.wms.dispatch_manage.task.service.dao.SchBaseTask;
@@ -66,6 +67,12 @@ public class ToPickPlatformTask extends AbstractTask {
if (start_struct_code.contains("B")) {
target_point = "1311";
} else {
List<SchBasePoint> targetPoints = iSchBasePointService.list(new QueryWrapper<SchBasePoint>()
.eq("region_code", "PICK01").eq("is_used", true));
if (CollectionUtils.isEmpty(targetPoints)) {
throw new BadRequestException("当前拣选工位未启用");
}
if (targetPoints.size() > 1) {
List<SchBaseTask> list = iSchBaseTaskService.list(new QueryWrapper<SchBaseTask>()
.lt("status", StatusEnum.FORM_STATUS.code("完成")));
String pointCode1 = "1308";
@@ -73,6 +80,9 @@ public class ToPickPlatformTask extends AbstractTask {
long count1 = list.stream().filter(r -> r.getPoint_code2().equals(pointCode1)).count();
long count2 = list.stream().filter(r -> r.getPoint_code2().equals(pointCode2)).count();
target_point = count1 >= count2 ? pointCode2 : pointCode1;
} else {
target_point = targetPoints.get(0).getCode();
}
// List<SchBasePoint> targetPoints = iSchBasePointService.list(new QueryWrapper<SchBasePoint>()
// .eq("region_code", "PICK01").eq("is_used", true));
// //通过全局变量获取目标位置
@@ -98,7 +108,6 @@ public class ToPickPlatformTask extends AbstractTask {
if (!CollectionUtils.isEmpty(list)) {
throw new BadRequestException("当前载具存在任务:" + list.stream().map(SchBaseTask::getTask_code).collect(Collectors.joining(",")));
}
//移库判断
if (struct.getStor_code().equals("FStockId")) {
synchronized ("FStockId") {

View File

@@ -442,7 +442,7 @@ public class SchBaseTaskServiceImpl extends ServiceImpl<SchBaseTaskMapper, SchBa
RedissonUtils.lock(() -> {
System.out.println("---3--" + Thread.currentThread().getName());
//出阻挡说明是同排跟任务一个类型载具
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", stIvtStructattr.getStor_code(), "vehicle_code", task.getVehicle_code(), "errorTask", "errorTask")));
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", stIvtStructattr.getStor_code(), "vehicle_code", task.getVehicle_code(), "errorTask", "errorTask", "start_struct_code", block.getStruct_code())));
moveStruct.set(((Map<String, String>) process.get("form_data")).get("end_struct_code"));
}, "1" + stIvtStructattr.getStor_code(), 5);
Map moveForm = MapOf.of("task_type", StatusEnum.IOBILL_TYPE_MOVE.code("异常位移库")
@@ -503,7 +503,7 @@ public class SchBaseTaskServiceImpl extends ServiceImpl<SchBaseTaskMapper, SchBa
.set("lock_type", StatusEnum.LOCK.code("异常锁定"))
.set("update_time", DateUtil.now())
.set("remark", "入满异常:" + task_code)
.set("vehicle_code", task_code + "_ZD_" + org.nl.common.utils.IdUtil.getStringId()));
.set("vehicle_code", task_code + "6" + org.nl.common.utils.IdUtil.getStringId()));
}
List<MdPbVehicleMater> vehicleList = iMdPbVehicleMaterService
.list(new QueryWrapper<MdPbVehicleMater>()
@@ -533,15 +533,15 @@ public class SchBaseTaskServiceImpl extends ServiceImpl<SchBaseTaskMapper, SchBa
String new_struct_code = ((Map<String, String>) map.get("form_data")).get("end_struct_code");
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(vehicleList)) {
iActRuExecutionService.update(new UpdateWrapper<ActRuExecution>()
.set("remark", stIvtStructattr.getStruct_code() + "入满异常重新分配货位" + new_struct_code)
.set("remark", stIvtStructattr.getStruct_code() + "入满异常重新分配货位:" + stIvtStructattr.getStruct_code() + "->" + new_struct_code)
.eq("proc_inst_id", vehicleList.get(0).getProc_inst_id()));
}
log.error("任务:{},载具号{},原终点:{}入满异常重新分配货位:{}", task_code, task.getVehicle_code(), task.getPoint_code2(), new_struct_code);
log.info("【入满异常处理-更新任务】任务号:{}, 载具号:{}, 库位变更:{} -> {}, 阻挡库位:{}",
task_code, task.getVehicle_code(), stIvtStructattr.getStruct_code(), new_struct_code, stIvtStructattr.getStruct_code());
this.update(new UpdateWrapper<SchBaseTask>()
.set("point_code2", new_struct_code)
.set("remark", stIvtStructattr.getStruct_code() + "入满异常重新分配货" + new_struct_code)
.set("remark", "入满异常重新分配货位:原库位" + stIvtStructattr.getStruct_code() + "->新库" + new_struct_code + ",阻挡库位:" + stIvtStructattr.getStruct_code())
.eq("task_code", task_code));
JSONObject result = new JSONObject();
result.put("point_code2", new_struct_code);
return result;

View File

@@ -9,10 +9,12 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.TableDataInfo;
@@ -65,6 +67,7 @@ import java.util.stream.Collectors;
* @since 2024-04-24
*/
@Service
@Slf4j
public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGruopDick> implements IMdGruopDickService {
@Autowired
@@ -594,8 +597,10 @@ public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGru
+ "在ERP系统上检索不到相关物料信息请检查"
);
}
log.info(item.get(0).getVehicle_code()
+ "上的物料:" + r.getMaterial_code() + "单重为:" + materialInfo.getNet_weight());
r.setSingle_weight(materialInfo.getNet_weight());
r.setAssist_unit_id(materialInfo.getAssist_unit_id());
r.setWeight_unit_id(materialInfo.getWeight_unit_id());
}
//过滤出需要称重校验的物料(单重 > 0
List<MdPbVehicleMaterVo> validItems = item.stream()
@@ -660,8 +665,8 @@ public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGru
.map(r -> {
BigDecimal singleWeight = r.getSingle_weight();
// 辅助单位包含 kg
if (StringUtils.isNotBlank(r.getAssist_unit_id())) {
if (r.getAssist_unit_id().toLowerCase().contains("kg")) {
if (StringUtils.isNotBlank(r.getWeight_unit_id())) {
if (r.getWeight_unit_id().toLowerCase().contains("kg")) {
singleWeight = singleWeight.multiply(BigDecimal.valueOf(1000));
}
}
@@ -669,6 +674,7 @@ public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGru
return singleWeight.multiply(r.getQty());
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
log.info("物料理论总重量为:"+materialWeight);
unitIsG = isKg ? "kg" : "g";
//实际称重换算克
actualWeightG = isKg ? actualWeightKg.multiply(BigDecimal.valueOf(1000)) : actualWeightKg;
@@ -677,6 +683,12 @@ public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGru
if (netWeight.compareTo(BigDecimal.ZERO) < 0) {
netWeight = BigDecimal.ZERO;
}
//更新组盘信息表
iMdPbVehicleMaterService.update(
new UpdateWrapper<MdPbVehicleMater>()
.set("netWeight", netWeight)
.eq("id", item.get(0).getId())
);
// 差异重量 = 净重 - 理论重量 - 误差
BigDecimal diffWeight = netWeight
.subtract(materialWeight)
@@ -685,7 +697,7 @@ public class MdGruopDickServiceImpl extends ServiceImpl<MdGruopDickMapper, MdGru
log.error(item.get(0).getVehicle_code() + "的物料数量为:" + validItems.get(0).getQty()
+ ",上报重量为:" + actualWeightKg + ",载具重量为:" + weight + ",去皮重量为:" + netWeight + ",与物料实际重量:" + materialWeight + ",进行对比已超过误差值" + diffWeight + ",不允许入库,请检查。");
throw new BadRequestException(
(item.get(0).getVehicle_code() + "的物料数量为:" + validItems.get(0).getQty() + ",上报重量为:" + actualWeightKg + unitIsG + ",载具重量为:" + weight + "g" + ",物料单重为:" + validItems.get(0).getSingle_weight() + validItems.get(0).getAssist_unit_id() + ",去皮重量为:" + netWeight + "g与物料实际重量:" + materialWeight + "g进行对比已超过误差值" + diffWeight + "g不允许入库请检查。")
(item.get(0).getVehicle_code() + "的物料数量为:" + validItems.get(0).getQty() + ",上报重量为:" + actualWeightKg + unitIsG + ",载具重量为:" + weight + "g" + ",物料单重为:" + validItems.get(0).getSingle_weight() + validItems.get(0).getWeight_unit_id() + ",去皮重量为:" + netWeight + "g与物料实际重量:" + materialWeight + "g进行对比已超过误差值" + diffWeight + "g不允许入库请检查。")
);
}
}

View File

@@ -144,5 +144,11 @@ public class MdPbVehicleMater implements Serializable {
*/
private Boolean need_pick = Boolean.FALSE;
/**
* 物料净重
*/
private BigDecimal netWeight;
}

View File

@@ -17,14 +17,14 @@
<result property="material_name" column="material_name"/>
<result property="material_spec" column="material_spec"/>
<result property="single_weight" column="single_weight"/>
<result property="assist_unit_id" column="assist_unit_id"/>
<result property="weight_unit_id" column="weight_unit_id"/>
<result property="unit_name" column="unit_name"/>
<result property="form_data" column="form_data"
typeHandler="org.nl.common.domain.mybatis.handler.FastjsonSortTypeHandler"/>
</resultMap>
<select id="getVehicleMaters"
resultMap="VoResultMap">
select md_pb_vehicleMater.*, material_code, material_name, material_spec,single_weight,assist_unit_id
select md_pb_vehicleMater.*, material_code, material_name, material_spec,single_weight,weight_unit_id
from md_pb_vehicleMater
left join md_me_materialbase
on md_pb_vehicleMater.material_id = md_me_materialbase.material_id

View File

@@ -22,8 +22,8 @@ public class MdPbVehicleMaterVo extends MdPbVehicleMater {
private String material_code;
private String material_name;
private String material_spec;
//辅助重量
private String assist_unit_id;
//重量单位
private String weight_unit_id;
private BigDecimal single_weight;
private String unit_name;
}

View File

@@ -990,17 +990,23 @@ public class CockpitServiceImpl implements CockpitService {
real_qty_default.add(item);
}
if (ObjectUtil.isNotEmpty(real_qty)) {
//计算数量
// Map<String, BigDecimal> ghRealQtyMap = real_qty.stream()
// .filter(r -> StringUtils.isNotBlank(r.getUpdate_time()))
// .collect(Collectors.groupingBy(
// TaskInfo::getCreate_time,
// Collectors.reducing(BigDecimal.ZERO, TaskInfo::getQty, BigDecimal::add)
// ));
Map<String, BigDecimal> ghRealQtyMap = real_qty.stream()
.filter(r -> StringUtils.isNotBlank(r.getUpdate_time()))
.filter(r -> StringUtils.isNotBlank(r.getCreate_time()))
.collect(Collectors.groupingBy(
TaskInfo::getCreate_time,
task -> {
String createTime = task.getCreate_time();
try {
LocalDateTime dateTime = LocalDateTime.parse(createTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return dateTime.toLocalDate().format(formatter);
} catch (Exception e) {
try {
LocalDate date = LocalDate.parse(createTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return date.format(formatter);
} catch (Exception ex) {
return createTime;
}
}
},
Collectors.reducing(BigDecimal.ZERO, task -> {
int boxCount = task.getVehicle_code().split(",").length;
return BigDecimal.valueOf(boxCount);

View File

@@ -388,7 +388,6 @@ public class PdaIOService {
}
BmFormStruc formType = iBmFormStrucService.getFormType(pdaFormOutMst.getForm_type());
String billType = StatusEnum.IOBILL_TYPE_OUT.code(formType.getForm_desc());
StIvtIostorinv mst = new StIvtIostorinv();
mst.setId(IdUtil.getStringId());
mst.setCreate_name(SecurityUtils.getCurrentNickName());
@@ -408,6 +407,88 @@ public class PdaIOService {
mstJ.remove("children");
mstJ.putAll((Map) mstJ.remove("form_data"));
String mstString = mstJ.toJSONString();
// 如果仓库代码为"FStockPallet",需要特殊处理:优先锁定同一载具上的多个物料
boolean isFStockPallet = "FStockPallet".equals(pdaFormOutMst.getStor_code());
Set<String> processedSharedVehicles = new HashSet<>();
Map<String, List<MdPbVehicleMater>> sharedVehicleInfoMap = new HashMap<>(); // 记录共享载具信息,用于循环后冻结
if (isFStockPallet) {
// 创建final版本的dtls用于lambda表达式
final List<PdaFormOutDtl> finalDtls = dtls;
// 收集所有物料ID
List<String> materialIds = dtls.stream()
.map(PdaFormOutDtl::getMaterial_id)
.distinct().collect(Collectors.toList());
// 查询这些物料的库存信息(查询可用数量>0的物料
if (!CollectionUtils.isEmpty(materialIds)) {
List<MdPbVehicleMater> allVehicleMaters = iMdPbVehicleMaterService.list(
new QueryWrapper<MdPbVehicleMater>()
.in("material_id", materialIds)
.eq("is_delete", false)
.gt("qty", 0)
.eq("stor_code", pdaFormOutMst.getStor_code())
);
// 按载具分组,找出同一载具上有多个不同物料的情况
Map<String, List<MdPbVehicleMater>> vehicleMaterialMap = allVehicleMaters.stream()
.collect(Collectors.groupingBy(MdPbVehicleMater::getVehicle_code))
.entrySet().stream()
.filter(entry -> {
// 统计这个载具上有多少个不同的物料在dtls中
long distinctMaterialCount = entry.getValue().stream()
.map(MdPbVehicleMater::getMaterial_id)
.distinct()
.filter(materialId -> finalDtls.stream()
.anyMatch(dtl -> dtl.getMaterial_id().equals(materialId)))
.count();
return distinctMaterialCount > 1; // 只保留有多个不同物料的载具
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// 步骤1在循环前只移除共享载具中非第一个物料的dtl
if (!vehicleMaterialMap.isEmpty()) {
log.info("发现 {} 个共享载具,开始预处理过滤", vehicleMaterialMap.size());
// 记录每个共享载具对应的第一个物料ID
Set<String> keptDtlIds = new HashSet<>();
for (Map.Entry<String, List<MdPbVehicleMater>> entry : vehicleMaterialMap.entrySet()) {
String vehicleCode = entry.getKey();
List<MdPbVehicleMater> matersInVehicle = entry.getValue();
// 找到这个载具对应的第一个物料明细
PdaFormOutDtl firstDtl = finalDtls.stream()
.filter(dtl -> matersInVehicle.stream()
.anyMatch(vm -> vm.getMaterial_id().equals(dtl.getMaterial_id())))
.findFirst()
.orElse(null);
if (firstDtl != null) {
keptDtlIds.add(firstDtl.getId());
// 记录共享载具信息,用于循环后冻结
sharedVehicleInfoMap.put(vehicleCode, matersInVehicle);
}
}
// 过滤dtls如果是共享载具的物料只保留第一个如果不是共享载具全部保留
dtls = dtls.stream()
.filter(dtl -> {
// 检查这个dtl是否在共享载具上
boolean isInSharedVehicle = vehicleMaterialMap.values().stream()
.anyMatch(maters -> maters.stream()
.anyMatch(vm -> vm.getMaterial_id().equals(dtl.getMaterial_id())));
if (isInSharedVehicle) {
// 如果在共享载具上,只保留第一个
return keptDtlIds.contains(dtl.getId());
} else {
// 如果不在共享载具上,全部保留
return true;
}
})
.collect(Collectors.toList());
log.info("过滤后剩余 {} 个物料明细需要处理", dtls.size());
}
}
}
for (PdaFormOutDtl dtl : dtls) {
BigDecimal now_assign_qty = dtl.getNow_assign_qty();
if (now_assign_qty == null || now_assign_qty.intValue() == 0) {
@@ -422,6 +503,7 @@ public class PdaIOService {
throw new BadRequestException("出库申请失败:明细数据仓库字段未指定");
}
String pcsn = dtl.getPcsn();
// 正常分配逻辑(共享载具已在循环前处理并过滤)
List<StructAssignQty> structMaterials = iStIvtStructattrService.getStructIvtAssign(ListOf.of(dtl.getMaterial_id()), storCode);
if (CollectionUtils.isEmpty(structMaterials)) {
throw new BadRequestException(dtl.getMaterial_code() + "物料库存不足");
@@ -478,7 +560,8 @@ public class PdaIOService {
ivtDtl.setStatus(StatusEnum.FORM_STATUS.code("生成"));
ivtDtl.setSource_form_id(dtl.getId());
ivtDtl.setSource_form_type(dtl.getForm_type());
合并主表明细数据:{
// 合并主表明细数据
{
JSONObject sourceFormData = JSONObject.parseObject(mstString);
String dtlStr = JSON.toJSONString(dtl);
JSONObject dtlJ = JSONObject.parseObject(dtlStr);
@@ -491,6 +574,76 @@ public class PdaIOService {
list.add(ivtDtl);
}
}
// 步骤3最后一步处理共享载具的物料分配与冻结
if (isFStockPallet && !sharedVehicleInfoMap.isEmpty()) {
log.info("开始处理 {} 个共享载具的冻结", sharedVehicleInfoMap.size());
for (Map.Entry<String, List<MdPbVehicleMater>> entry : sharedVehicleInfoMap.entrySet()) {
String vehicleCode = entry.getKey();
List<MdPbVehicleMater> matersInVehicle = entry.getValue();
// 找到这个载具对应的第一个物料明细已经在dtls中保留
PdaFormOutDtl firstDtl = dtls.stream()
.filter(dtl -> matersInVehicle.stream()
.anyMatch(vm -> vm.getMaterial_id().equals(dtl.getMaterial_id())))
.findFirst()
.orElse(null);
if (firstDtl != null) {
// 第一个物料的已分配数量已经通过outDispense计算
BigDecimal firstAssignedQty = firstDtl.getNow_assign_qty();
// 计算其他同载具物料的总需求数量
BigDecimal otherNeed = matersInVehicle.stream()
.filter(vm -> !vm.getMaterial_id().equals(firstDtl.getMaterial_id()))
.map(vm -> {
PdaFormOutDtl matchingDtl = pdaFormOutMst.getChildren().stream()
.filter(dtl -> dtl.getMaterial_id().equals(vm.getMaterial_id()))
.findFirst()
.orElse(null);
return matchingDtl != null ? matchingDtl.getNow_assign_qty() : BigDecimal.ZERO;
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算可用数量(排除第一个物料已占用的)
BigDecimal availableQty = matersInVehicle.stream()
.map(vm -> vm.getQty().subtract(vm.getFrozen_qty() != null ? vm.getFrozen_qty() : BigDecimal.ZERO))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.subtract(firstAssignedQty);
if (availableQty.compareTo(otherNeed) >= 0) {
// 可用数量足够,冻结其他物料的需求数量
for (MdPbVehicleMater vm : matersInVehicle) {
// 跳过第一个物料它已经被outDispense冻结了
if (vm.getMaterial_id().equals(firstDtl.getMaterial_id())) {
continue;
}
PdaFormOutDtl matchingDtl = pdaFormOutMst.getChildren().stream()
.filter(dtl -> dtl.getMaterial_id().equals(vm.getMaterial_id()))
.findFirst()
.orElse(null);
if (matchingDtl != null) {
BigDecimal freezeQty = matchingDtl.getNow_assign_qty();
LambdaUpdateWrapper<MdPbVehicleMater> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MdPbVehicleMater::getId, vm.getId());
updateWrapper.setSql("frozen_qty = frozen_qty + " + freezeQty);
iMdPbVehicleMaterService.update(updateWrapper);
}
}
// 标记这个载具已处理
processedSharedVehicles.add(vehicleCode);
log.info("载具 {} 已冻结其他物料,包含 {} 个物料", vehicleCode, matersInVehicle.size());
} else {
log.warn("载具 {} 可用数量不足,无法冻结其他物料", vehicleCode);
}
}
}
}
iStIvtIostorinvdtlService.saveBatch(list);
iStIvtIostorinvService.save(mst);
//生成流程
@@ -526,6 +679,72 @@ public class PdaIOService {
return mst;
}
/**
* 处理载具分配逻辑用于FStockPallet仓库的特殊处理
*/
private void processVehicleAssignment(PdaFormOutDtl dtl, String vehicles, StIvtIostorinv mst,
List<StIvtIostorinvdtl> list, String productArea,
String storCode, String mstString, PdaFormOutMst pdaFormOutMst) {
List<MdPbVehicleMater> MdPbVehicleMaters = iMdPbVehicleMaterService.list(
new QueryWrapper<MdPbVehicleMater>()
.in("vehicle_code", vehicles.split(","))
.eq("is_delete", false)
.eq("material_id", dtl.getMaterial_id()));
Map<String, List<MdPbVehicleMater>> pcsnListMap = MdPbVehicleMaters.stream()
.collect(Collectors.groupingBy(MdPbVehicleMater::getPcsn));
// 手持生成出库单
for (String disPcsn : pcsnListMap.keySet()) {
List<MdPbVehicleMater> currentPcsnMater = pcsnListMap.get(disPcsn);
if (StringUtils.isNotBlank(pdaFormOutMst.getCode())) {
Set<String> materSet = currentPcsnMater.stream()
.map(MdPbVehicleMater::getVehicle_code)
.collect(Collectors.toSet());
// CTU更新单据号
LambdaUpdateWrapper<MdPbVehicleMater> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(MdPbVehicleMater::getVehicle_code, materSet);
updateWrapper.eq(MdPbVehicleMater::getIs_delete, false);
updateWrapper.set(MdPbVehicleMater::getPrd_ppbom_no, pdaFormOutMst.getCode());
iMdPbVehicleMaterService.update(updateWrapper);
}
HashMap map = MapOf.of("end_struct_code", "", "start_struct_code", "", "order", "", "product_area", productArea);
StIvtIostorinvdtl ivtDtl = new StIvtIostorinvdtl();
ivtDtl.setMaterial_id(dtl.getMaterial_id());
ivtDtl.setForm_data(new JSONObject(map));
ivtDtl.setQty(BigDecimal.valueOf(currentPcsnMater.stream()
.mapToInt(a -> a.getFrozen_qty() != null ? a.getFrozen_qty().intValue() : 0).sum()));
ivtDtl.setPcsn(disPcsn);
ivtDtl.setStor_code(storCode);
ivtDtl.setId(IdUtil.getStringId());
// 去重
ivtDtl.setVehicle_code(currentPcsnMater.stream()
.map(MdPbVehicleMater::getVehicle_code)
.distinct()
.collect(Collectors.joining(",")));
ivtDtl.setVehicle_id(currentPcsnMater.stream()
.map(MdPbVehicleMater::getId)
.distinct()
.collect(Collectors.joining(",")));
ivtDtl.setInv_id(mst.getId());
ivtDtl.setStatus(StatusEnum.FORM_STATUS.code("生成"));
ivtDtl.setSource_form_id(dtl.getId());
ivtDtl.setSource_form_type(dtl.getForm_type());
// 合并主表明细数据
{
JSONObject sourceFormData = JSONObject.parseObject(mstString);
String dtlStr = JSON.toJSONString(dtl);
JSONObject dtlJ = JSONObject.parseObject(dtlStr);
dtlJ.putAll((Map) dtlJ.remove("form_data"));
sourceFormData.putAll(dtlJ);
sourceFormData.put("pcsn", disPcsn);
sourceFormData.put("stock_code", "FStockId".equals(ivtDtl.getStor_code()) ? "25" : "24");
ivtDtl.setSource_form_data(sourceFormData);
}
list.add(ivtDtl);
}
}
private void pdaTaskOpen(StIvtIostorinv mst) {
iStIvtIostorinvService.taskOpen((JSONObject) JSONObject.toJSON(mst));
}

View File

@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -69,13 +70,20 @@ public class PdaPickController {
//托盘拣选信息
if (form.getVehicle_code().contains("T")) {
List<MdPbVehicleMater> list = iMdPbVehicleMaterService.list(new QueryWrapper<MdPbVehicleMater>()
.eq("vehicle_code", form.getVehicle_code()));
.eq("vehicle_code", form.getVehicle_code()).eq("is_delete", false).eq("need_pick", true));
if (CollectionUtils.isNotEmpty(list)) {
list = list.stream().filter(r -> StringUtils.isNotBlank(r.getRemark())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
list = list.stream().filter(r -> r.getRemark().contains("该托盘")).collect(Collectors.toList());
String remark = "需要拣选:";
//如果有多个则在元素前添加12,3
if (CollectionUtils.isNotEmpty(list)) {
throw new BadRequestException(list.get(0).getRemark());
AtomicInteger counter = new AtomicInteger(1);
remark = remark + list.stream()
.map(MdPbVehicleMater::getRemark)
.map(r -> counter.getAndIncrement() + ": " + r)
.collect(Collectors.joining("; "));
throw new BadRequestException(remark);
} else {
throw new BadRequestException("该托盘,托盘号为:" + form.getVehicle_code() + "无相关出库信息请在WMS系统查询库存变动信息");
}

View File

@@ -188,14 +188,14 @@ public class StIvtStructattrController {
public void exportFile(@RequestBody StructattrQuery query, HttpServletResponse response) {
PageQuery page = new PageQuery();
page.setPage(0);
page.setSize(99999);
page.setSize(500);
TableDataInfo<Map> structIvt = structattrService.getStructIvt(query, page);
List<Map> maps = structIvt.getContent();
columnInfoService.exportFile("", maps, response,
null,
MapOf.linkOf("stor_code", "仓库编码", "struct_code", "仓位", "vehicle_code", "载具编码",
"material_code", "物料编号", "material_code", "物料名称", "pcsn", "批号"
, "forzen_qty", "冻结数量", "qty", "库位库存", "counts", "物料总库存", "erpCounts", "ERP实时库存", "differCount", "立库-ERP库存差异", "create_time", "组盘入库时间"));
, "forzen_qty", "冻结数量", "qty", "库位库存", "counts", "物料总库存", "netWeight", "净重","erpCounts", "ERP实时库存", "differCount", "立库-ERP库存差异", "create_time", "组盘入库时间"));
}

View File

@@ -343,6 +343,7 @@
material.material_code,
material.material_name,
vm.create_time,
vm.netWeight,
struct.w as counts,
struct.l as erpCounts,
struct.weight as differCount

View File

@@ -34,6 +34,8 @@ public class StructattrQuery extends BaseQuery<StIvtStructattr> {
private String idleTime;
private Boolean isIdle;
private String idleTimes;
private String netWeight;

View File

@@ -46,6 +46,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -167,13 +168,13 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
update.set("need_pick", true);
//托盘出库提示拣选信息
if (!growth) {
update.set("remark", "该托盘需要拣选的物料为:" + materialbase.getMaterial_name() + ",物料编码为:" + materialbase.getMaterial_code() + ",数量" + vehicleMater.getFrozen_qty() + ",拣选完请把托盘剩余物料拉到入库口进行回库");
update.set("remark", materialbase.getMaterial_code() + ",数量:" + vehicleMater.getFrozen_qty());
}
}
}
//入库清除拣选信息
if (growth) {
update.set("remark", "").set("need_pick", false).set("is_check", null);
update.set("remark", "").set("need_pick", false).set("is_check", null).set("netWeight", null);
}
update.set("qty", subtract);//50
} else {
@@ -181,7 +182,7 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
//托盘整出需要扣库存,除了二楼料箱整出不扣库存,其他都扣库存
if (!("2114").equals(point_code2)) {
if (vehicleCode.contains("T")) {
update.set("remark", "该托盘需要拣选的物料为:"+materialbase.getMaterial_name()+",物料编码为:"+materialbase.getMaterial_code()+",数量为:"+ vehicleMater.getFrozen_qty() + "拣选完该物料数量为0如果托盘不存在其他类型物料,则作为空托盘使用,无需回库").set("need_pick",false);
update.set("remark", materialbase.getMaterial_code() + ",数量为:" + vehicleMater.getFrozen_qty() + "托盘不存在其他类型物料,则拉走空托盘,无需回库").set("need_pick", false);
}
if (!task_type.equals(StatusEnum.IOBILL_TYPE_OUT.code("盘点出库"))) {
update.set("qty", subtract);
@@ -390,6 +391,54 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
BigDecimal::add)
));
}
for (Map<String, Object> item : mst_detail) {
String key = (String) item.get("material_code");
MdMeMaterialbase material = mdMeMaterialbaseService.getOne(new QueryWrapper<MdMeMaterialbase>().eq("material_code", key));
BigDecimal weight;
if (item.get("netWeight") == null) {
if (material != null && material.getNet_weight() != null) {
BigDecimal qty = item.get("qty") != null ? new BigDecimal(item.get("qty").toString()) : BigDecimal.ZERO;
weight = qty.multiply(material.getNet_weight()).setScale(2, RoundingMode.HALF_UP);
} else {
weight = BigDecimal.ZERO;
}
} else {
try {
weight = new BigDecimal(item.get("netWeight").toString()).setScale(2, RoundingMode.HALF_UP);
} catch (NumberFormatException e) {
weight = BigDecimal.ZERO;
}
}
// 确定单位显示
String weightResult;
if ("FStockId".equals(item.get("stor_code"))) {
weightResult = weight + "g";
} else if (material != null && "g".equals(material.getWeight_unit_id())) {
weightResult = weight + "g";
} else {
weightResult = weight + "kg";
}
item.put("netWeight", weightResult);
}
// 如果按净重筛选,需要去除单位后再比较
if (StringUtils.isNotBlank(query.getNetWeight())) {
try {
BigDecimal filterWeight = new BigDecimal(query.getNetWeight().trim());
mst_detail = mst_detail.stream()
.filter(item -> item.get("netWeight") != null)
.filter(item -> {
// 从带单位的字符串中提取数值部分,如 "100.00g" -> 100.00
String netWeightStr = item.get("netWeight").toString();
String weightOnly = netWeightStr.replaceAll("[a-z A-Z]", "").trim();
BigDecimal netWeight = new BigDecimal(weightOnly);
return netWeight.compareTo(filterWeight) == 0;
})
.collect(Collectors.toList());
} catch (NumberFormatException e) {
// 如果格式不正确,跳过筛选
log.warn("净重筛选条件格式错误: {}", query.getNetWeight());
}
}
if (baseQty != null) {
for (Map<String, Object> item : mst_detail) {
String key = (String) item.get("material_code");
@@ -483,6 +532,92 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
@Override
@Transactional
public void createMoveTask(String structCodeList) {
// ISchBaseTaskService taskService = SpringContextHolder.getBean(ISchBaseTaskService.class);
// QueryWrapper<SchBaseTask> query1 = new QueryWrapper<SchBaseTask>()
// .likeRight("point_code1", structCodeQuery)
// .lt("status", StatusEnum.FORM_STATUS.code("完成"));
// List<SchBaseTask> schBaseTaskList = taskService.list(query1);
// if (!CollectionUtils.isEmpty(schBaseTaskList)) {
// throw new BadRequestException("当前同排同列库位在任务,请完成后再下发批量移库任务");
// }
if (StringUtils.isBlank(structCodeList)) {
throw new BadRequestException("移库数量不能为空");
}
if (!StringUtils.isNumeric(structCodeList)) {
throw new BadRequestException("移库数量必须为正整数");
}
int quantity = Integer.parseInt(structCodeList);
if (quantity <= 0) {
throw new BadRequestException("移库数量必须大于 0");
}
QueryWrapper<StIvtStructattr> query = new QueryWrapper<>();
query.eq("is_used", true);
query.isNotNull("vehicle_code");
query.eq("sect_code", "LXBCP01");
ArrayList<String> pai = new ArrayList<>();
pai.add("1");
pai.add("2");
query.in("row_num", pai)
.lt("row_num", 3)
.ge("layer_num", 24)
.le("layer_num", 31).orderByDesc("row_num").orderByAsc("col_num");
List<StIvtStructattr> list = this.list(query);
if (CollectionUtils.isEmpty(list)) {
throw new BadRequestException("批量移库任务申请失败,没有可用仓位!");
}
if (quantity > list.size()) {
throw new BadRequestException("移库数量不能超过列表总长度(当前列表长度为 " + list.size() + "");
}
list = list.stream().limit(quantity).collect(Collectors.toList());
UpdateWrapper<StIvtStructattr> updateWrapper = new UpdateWrapper<StIvtStructattr>()
.set("lock_type", StatusEnum.LOCK.code("禁分配锁"))
.eq("is_used", 1)
.isNull("vehicle_code")
.eq("sect_code", "LXBCP01")
.lt("row_num", 3)
.ge("layer_num", 24)
.le("layer_num", 31);
this.update(updateWrapper);
list.forEach(r -> {
DELAY_EXECUTOR.execute(() -> {
try {
Thread.sleep(3000);
AtomicReference<String> moveStruct = new AtomicReference<>();
String vehicleCode = r.getVehicle_code();
RedissonUtils.lock(() -> {
System.out.println("---3--" + Thread.currentThread().getName());
//出阻挡说明是同排跟任务一个类型载具
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", r.getStor_code(), "vehicle_code", vehicleCode, "start_struct_code", r.getStruct_code())));
moveStruct.set(((Map<String, String>) process.get("form_data")).get("end_struct_code"));
}, "1" + r.getStor_code(), 5);
Map moveForm = MapOf.of("task_type", StatusEnum.IOBILL_TYPE_MOVE.code("移库")
, "is_send", false
, "vehicle_code", StringUtils.isEmpty(vehicleCode) ? "YCZJ" + r.getVehicle_code() : vehicleCode, "form_data", new JSONObject(MapOf.of("start_struct_code", r.getStruct_code(), "end_struct_code", moveStruct.get())));
moveForm.put("isAllMove", "1");
SpringContextHolder.getBean(MoveStorageTask.class).createTask(new JSONObject(moveForm));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("延迟任务被中断", e);
} catch (Exception e) {
log.error("延迟下发任务执行失败", e);
}
});
});
// if (ObjectUtils.isNotEmpty(list2)) {
// LambdaUpdateWrapper<StIvtStructattr> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
// lambdaUpdateWrapper.set(StIvtStructattr::getLock_type, StatusEnum.LOCK.code("技改锁")).set(StIvtStructattr::getIs_used, 0);
// lambdaUpdateWrapper.in(StIvtStructattr::getStruct_code, list2);
// this.update(lambdaUpdateWrapper);
// }
}
/**
* 批量移库下发
*/
// @Override
@Transactional
public void createMoveTask1(String structCodeList) {
Set<String> structCodeSet = new HashSet<>();
String structCodeQuery;
String structCode = structCodeList.trim();
@@ -586,7 +721,7 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
RedissonUtils.lock(() -> {
System.out.println("---3--" + Thread.currentThread().getName());
//出阻挡说明是同排跟任务一个类型载具
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", r.getStor_code(), "vehicle_code", vehicleCode, "errorTask", "errorTask")));
Map process = SpringContextHolder.getBean(DecisionHandler.class).dispenseTransa(ListOf.of("limitStorage", "depthPriority", "alleyAve"), new JSONObject(MapOf.of("is_move", true, "stor_code", r.getStor_code(), "vehicle_code", vehicleCode, "errorTask", "errorTask", "start_struct_code", r.getStruct_code())));
moveStruct.set(((Map<String, String>) process.get("form_data")).get("end_struct_code"));
}, "1" + r.getStor_code(), 5);
Map moveForm = MapOf.of("task_type", StatusEnum.IOBILL_TYPE_MOVE.code("移库")
@@ -612,7 +747,6 @@ public class StIvtStructattrServiceImpl extends ServiceImpl<StIvtStructattrMappe
}
}
}
// @Override
// @Transactional
// public void createMoveTask(String structCodeList) {

View File

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.TableDataInfo;
import org.nl.common.enums.StatusEnum;
import org.nl.common.utils.BaseCode;
@@ -20,6 +21,7 @@ import org.nl.wms.dispatch_manage.task.handler.impl.SecondFloorAgvTransferTask;
import org.nl.wms.dispatch_manage.task.service.ISchBaseTaskService;
import org.nl.wms.dispatch_manage.task.service.dao.SchBaseTask;
import org.nl.wms.external_system.acs.service.WmsToAcsService;
import org.nl.wms.system_manage.service.param.dao.Param;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -172,6 +174,7 @@ public class TaskScheduleService {
}
}
}
private void handleTaskResponse(TableDataInfo response, List<String> taskCodes) {
if (response.getCode().equals(String.valueOf(HttpStatus.HTTP_OK))) {
iSchBaseTaskService.update(new UpdateWrapper<SchBaseTask>()

View File

@@ -7,6 +7,8 @@ spring:
check-template-location: false
profiles:
active: dev
#active: dev
#active: prod
jackson:
time-zone: GMT+8
data:

View File

@@ -82,6 +82,17 @@
@input="handleSearchInput('prd_ppbom_no')"
/>
</el-form-item>
<el-form-item label="物料重量">
<el-input
v-model="query.netWeight"
clearable
size="mini"
placeholder="请输入物料重量"
prefix-icon="el-icon-search"
class="filter-item"
@input="handleSearchInput('netWeight')"
/>
</el-form-item>
<el-form-item label="锁定类型">
<el-select
v-model="query.lock_type"
@@ -211,6 +222,7 @@
<el-table-column prop="qty" label="库位库存" show-tooltip-when-overflow />
<el-table-column prop="frozen_qty" label="冻结库存" show-tooltip-when-overflow />
<el-table-column prop="counts" label="物料总库存" min-width="90" show-tooltip-when-overflow />
<el-table-column prop="netWeight" label="物料重量" min-width="90" show-tooltip-when-overflow />
<el-table-column prop="erpCounts" label="ERP实时库存" min-width="90" show-tooltip-when-overflow />
<el-table-column prop="differCount" label="立库-ERP库存差异" min-width="120" show-tooltip-when-overflow />
<el-table-column prop="prd_ppbom_no" label="用料单号" min-width="150" show-tooltip-when-overflow />