add:增加出入库分配策略类
This commit is contained in:
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.nl.common.domain.query.PageQuery;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
|
||||
import org.nl.wms.warehouse_management.service.dao.IOStorInv;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
@@ -101,4 +102,7 @@ public interface IStructattrService extends IService<Structattr> {
|
||||
* @return Structattr
|
||||
*/
|
||||
Structattr getByCode(String struct_code);
|
||||
|
||||
|
||||
List<StructattrVechielDto> collectVechicle(Map query);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package org.nl.wms.basedata_manage.service.dao;
|
||||
|
||||
import lombok.Data;
|
||||
import org.nl.wms.warehouse_management.service.dao.GroupPlate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2023/5/4 19:49
|
||||
*/
|
||||
@Data
|
||||
public class StructattrVechielDto extends MdPbStoragevehicleext {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 仓位标识
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 载具物料id
|
||||
*/
|
||||
private String vm_id;
|
||||
/**
|
||||
* 入库类型
|
||||
*/
|
||||
private String source_form_type;
|
||||
|
||||
/**
|
||||
* 仓位编码
|
||||
*/
|
||||
private String struct_code;
|
||||
|
||||
/**
|
||||
* 仓位名称
|
||||
*/
|
||||
private String struct_name;
|
||||
|
||||
/**
|
||||
* 库区标识
|
||||
*/
|
||||
private String sect_code;
|
||||
|
||||
/**
|
||||
* 仓库标识
|
||||
*/
|
||||
private String stor_code;
|
||||
|
||||
/**
|
||||
* 容量
|
||||
*/
|
||||
private Integer capacity;
|
||||
|
||||
/**
|
||||
* 宽度
|
||||
*/
|
||||
private Integer w;
|
||||
|
||||
/**
|
||||
* 高度
|
||||
*/
|
||||
private Integer h;
|
||||
|
||||
/**
|
||||
* 深度(长度)
|
||||
*/
|
||||
private Integer l;
|
||||
|
||||
/**
|
||||
* 承受重量
|
||||
*/
|
||||
private Integer weight;
|
||||
|
||||
/**
|
||||
* 起始X坐标
|
||||
*/
|
||||
private BigDecimal xqty;
|
||||
|
||||
/**
|
||||
* 起始Y坐标
|
||||
*/
|
||||
private BigDecimal yqty;
|
||||
|
||||
/**
|
||||
* 起始Z坐标
|
||||
*/
|
||||
private BigDecimal zqty;
|
||||
|
||||
/**
|
||||
* 排
|
||||
*/
|
||||
private Integer row_num;
|
||||
|
||||
/**
|
||||
* 列
|
||||
*/
|
||||
private Integer col_num;
|
||||
|
||||
/**
|
||||
* 层
|
||||
*/
|
||||
private Integer layer_num;
|
||||
|
||||
/**
|
||||
* 块
|
||||
*/
|
||||
private Integer block_num;
|
||||
|
||||
/**
|
||||
* 超限货位关联的货位编号
|
||||
*/
|
||||
private String control_code;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String create_id;
|
||||
|
||||
/**
|
||||
* 创建人姓名
|
||||
*/
|
||||
private String create_name;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private String create_time;
|
||||
|
||||
/**
|
||||
* 是否临时仓位
|
||||
*/
|
||||
private Boolean is_temp;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Boolean is_used;
|
||||
|
||||
/**
|
||||
* 锁定类型
|
||||
*/
|
||||
private String lock_type;
|
||||
|
||||
/**
|
||||
* 是否判断高度
|
||||
*/
|
||||
private String is_zdepth;
|
||||
|
||||
/**
|
||||
* 存储载具号
|
||||
*/
|
||||
private String vehicle_code;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 背景图片
|
||||
*/
|
||||
private String back_ground_pic;
|
||||
|
||||
/**
|
||||
* 前景色
|
||||
*/
|
||||
private String front_ground_color;
|
||||
|
||||
/**
|
||||
* 背景色
|
||||
*/
|
||||
private String back_ground_color;
|
||||
|
||||
/**
|
||||
* 字体显示方向
|
||||
*/
|
||||
private String font_direction_scode;
|
||||
|
||||
|
||||
}
|
||||
@@ -3,6 +3,10 @@ package org.nl.wms.basedata_manage.service.dao.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
@@ -11,4 +15,6 @@ import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
@Mapper
|
||||
public interface StructattrMapper extends BaseMapper<Structattr>{
|
||||
|
||||
List<StructattrVechielDto> collectVehicle(Map query);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.nl.wms.basedata_manage.service.dao.mapper.StructattrMapper">
|
||||
<select id="collectVehicle" resultType="org.nl.wms.basedata_manage.service.dao.StructattrVechielDto">
|
||||
SELECT
|
||||
vm.canuse_qty,
|
||||
vm.frozen_qty,
|
||||
vm.update_time,
|
||||
vm.material_id,
|
||||
vm.pcsn,
|
||||
vm.storagevehicleext_id AS vm_id,
|
||||
ivt.*
|
||||
FROM
|
||||
st_ivt_structattr ivt
|
||||
LEFT JOIN md_pb_storagevehicleext vm ON ivt.storagevehicle_code = vm.storagevehicle_code
|
||||
WHERE
|
||||
vm.material_id = #{material_id}
|
||||
<if test="pcsn != null and pcsn != ''">
|
||||
AND vm.pcsn = #{pcsn}
|
||||
</if>
|
||||
AND ivt.stor_code = #{stor_code}
|
||||
<if test="vehicles != null and vehicles.size() > 0">
|
||||
AND ivt.storagevehicle_code in
|
||||
<foreach collection="vehicles" item="value" index="key" open="(" close=")" separator=",">
|
||||
#{value}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="is_lock != null and is_lock != ''">
|
||||
and ivt.lock_type = '00'
|
||||
and vm.frozen_qty = 0
|
||||
</if>
|
||||
<if test="order_by != null and order_by != ''">
|
||||
order by ${order_by}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -25,6 +25,7 @@ import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.BsrealStorattr;
|
||||
import org.nl.wms.basedata_manage.service.dao.Sectattr;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
|
||||
import org.nl.wms.basedata_manage.service.dao.mapper.StructattrMapper;
|
||||
import org.nl.wms.warehouse_management.enums.IOSEnum;
|
||||
import org.nl.wms.warehouse_management.service.dao.IOStorInv;
|
||||
@@ -300,4 +301,11 @@ public class StructattrServiceImpl extends ServiceImpl<StructattrMapper, Structa
|
||||
return one;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructattrVechielDto> collectVechicle(Map query) {
|
||||
List<StructattrVechielDto> collectVehicle = this.baseMapper.collectVehicle(query);
|
||||
return collectVehicle;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.config.SpringContextHolder;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.IStStrategyConfigService;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.dao.StStrategyConfig;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:13
|
||||
*/
|
||||
public abstract class Decisioner<T,P> implements InitializingBean {
|
||||
|
||||
//每个策略的配置信息
|
||||
public StStrategyConfig strategyConfig;
|
||||
@Autowired
|
||||
private IStStrategyConfigService iStStrategyConfigService;
|
||||
@Autowired
|
||||
private SpringContextHolder springContextHolder;
|
||||
|
||||
public abstract List<T> handler(List<T> list, P param);
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet(){
|
||||
String type = SpringContextHolder.getApplicationContext().getBeanNamesForType(ResolvableType.forClass(this.getClass()))[0];
|
||||
this.strategyConfig =iStStrategyConfigService.getOne(new QueryWrapper<StStrategyConfig>().eq("strategy_code",type));
|
||||
if (this.strategyConfig == null){
|
||||
throw new BadRequestException("启动失败:当前策略"+type+"没有实例信息");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.common.utils.MapOf;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 巷道均衡策略:XYZ: 排列层
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("alleyAve")
|
||||
public class AlleyAveRuleHandler extends Decisioner<Structattr, JSONObject> {
|
||||
|
||||
|
||||
@Autowired
|
||||
private IStructattrService iStructattrService;
|
||||
|
||||
|
||||
/**
|
||||
* 巷道均衡策略
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:出入库单明细:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
// 判断仓位是否为空
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new BadRequestException("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略无可用货位");
|
||||
}
|
||||
long startTime1 = System.currentTimeMillis();
|
||||
if (ObjectUtils.isNotEmpty(list)) {
|
||||
//扩展库不需要均衡策略
|
||||
if ("LXBCP02".equals(list.get(0).getSect_code())) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 根据XYZ进行均衡排序:排层列
|
||||
*/
|
||||
String configParam = this.strategyConfig.getParam();
|
||||
List<String> configList = JSONObject.parseArray(configParam, String.class);
|
||||
list.sort((o1, o2) -> {
|
||||
BigDecimal rowNum1 = o1.getRow_num();
|
||||
BigDecimal colNum1 = o1.getCol_num();
|
||||
BigDecimal layerNum1 = o1.getLayer_num();
|
||||
BigDecimal rowNum2 = o2.getRow_num();
|
||||
BigDecimal colNum2 = o2.getCol_num();
|
||||
BigDecimal layerNum2 = o2.getLayer_num();
|
||||
HashMap<String, Integer> of1 = MapOf.of("x", rowNum1, "y", colNum1, "z", layerNum1);
|
||||
HashMap<String, Integer> of2 = MapOf.of("x", rowNum2, "y", colNum2, "z", layerNum2);
|
||||
for (String sort : configList) {
|
||||
if (of1.get(sort) > of2.get(sort)) {
|
||||
return 1;
|
||||
}
|
||||
if (of1.get(sort) < of2.get(sort)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
List<Structattr> subList = list.subList(0, Math.min(list.size(), 10));
|
||||
Structattr result = iStructattrService.getOne(
|
||||
new LambdaQueryWrapper<Structattr>()
|
||||
.eq(Structattr::getStruct_code, subList.get(0).getStruct_code())
|
||||
);
|
||||
if (result.getStoragevehicle_code() != null || !"00".equals(result.getLock_type())) {
|
||||
log.error("均衡策略分配异常,出现流程节点完成库存延迟锁定,载具号" + param.getString("vehicle_code") + "分配异常,仓位: " + result.getStruct_code() + ",该仓位被其他任务的载具锁定或其锁类型锁住");
|
||||
subList = subList.stream().filter(r -> !r.getStruct_code().equals(result.getStruct_code())).collect(Collectors.toList());
|
||||
}
|
||||
log.info("均衡策略结果:载具号:" + param.getString("vehicle_code") + "分配结果: " + subList.stream().map(Structattr::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");
|
||||
throw new BadRequestException("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略货位数量为0");
|
||||
}
|
||||
return subList;
|
||||
}
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// List<Structattr> list = new ArrayList<>();
|
||||
// for (int i =0;i<10;i++){
|
||||
// Structattr structattr = new Structattr();
|
||||
// structattr.setRow_num(new Random().nextInt(2)+1);
|
||||
// structattr.setCol_num(new Random().nextInt(10)+1);
|
||||
// structattr.setLayer_num(new Random().nextInt(2)+1);
|
||||
// list.add(structattr);
|
||||
// }
|
||||
// System.out.println(list);
|
||||
// ArrayList<String> of = ListOf.of("x", "z","y");
|
||||
// list.sort((o1, o2) -> {
|
||||
// Integer rowNum1 = o1.getRow_num();
|
||||
// Integer colNum1 = o1.getCol_num();
|
||||
// Integer layerNum1 = o1.getLayer_num();
|
||||
// Integer rowNum2 = o2.getRow_num();
|
||||
// Integer colNum2 = o2.getCol_num();
|
||||
// Integer layerNum2 = o2.getLayer_num();
|
||||
// HashMap<String,Integer> of1 = MapOf.of("x", rowNum1, "y", colNum1, "z", layerNum1);
|
||||
// HashMap<String,Integer> of2 = MapOf.of("x", rowNum2, "y", colNum2, "z", layerNum2);
|
||||
// for (String sort : of) {
|
||||
// Integer in1 = of1.get(sort);
|
||||
// Integer in2 = of2.get(sort);
|
||||
// if (in1 > in2){
|
||||
// return 1;
|
||||
// }
|
||||
// if (in1 < in2){
|
||||
// return -1;
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// });
|
||||
// System.out.println(list.toString());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 入库策略
|
||||
*
|
||||
* @param attrList :仓位集合
|
||||
* @param jsonParam:materialId :物料标识(此方法只根据物料进行匹配)
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
// private List<Structattr> inHandler(List<Structattr> attrList, PmFormData jsonParam) {
|
||||
// // in查询条件处理
|
||||
// List<Integer> blockNumIn = attrList.stream()
|
||||
// .map(Structattr::getBlock_num)
|
||||
// .distinct()
|
||||
// .collect(Collectors.toList());
|
||||
// // 查询相同巷道货位相同物料
|
||||
// List<Structattr> blockAttrList = null;
|
||||
// iStructattrService.getByQuery(new StructattrQuery());
|
||||
// // 如果为空说明这些巷道都没有相同物料的巷道,则返回所有仓位
|
||||
// if (ObjectUtil.isEmpty(blockAttrList)) {
|
||||
// return attrList;
|
||||
// }
|
||||
// // 计算每个巷道的相同物料
|
||||
// Map<Integer, List<Structattr>> collectMap = blockAttrList.stream()
|
||||
// .collect(Collectors.groupingBy(Structattr::getBlock_num));
|
||||
// // 巷道
|
||||
// int blockNum = blockAttrList.get(0).getBlock_num().intValue();
|
||||
// // 集合数量
|
||||
// int size = blockAttrList.size();
|
||||
// for (Integer num : collectMap.keySet()) {
|
||||
// int min = Math.min(size, collectMap.get(num).size());
|
||||
// if (size > min) {
|
||||
// // 返回最小的巷道
|
||||
// blockNum = num.intValue();
|
||||
// size = min;
|
||||
// }
|
||||
// }
|
||||
// // 匹配相同巷道的集合并返回
|
||||
// int finalBlockNum = blockNum;
|
||||
// return attrList.stream()
|
||||
// .filter(row -> row.getBlock_num().intValue() == finalBlockNum)
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 出库策略 - 查询物料最多的巷道
|
||||
*
|
||||
* @param attrList: 仓位物料
|
||||
* @return 巷道
|
||||
*/
|
||||
// private int getMaxMaterial(List<Structattr> attrList) {
|
||||
// // 根据巷道分组
|
||||
// Map<Integer, List<Structattr>> collectMap = attrList.stream()
|
||||
// .collect(Collectors.groupingBy(Structattr::getBlock_num));
|
||||
// // 找最大物料巷道
|
||||
// // 巷道
|
||||
// int blockNum = attrList.get(0).getBlock_num().intValue();
|
||||
// // 集合数量
|
||||
// int size = 0;
|
||||
// for (Integer num : collectMap.keySet()) {
|
||||
// int max = Math.max(size, collectMap.get(num).size());
|
||||
// if (size < max) {
|
||||
// // 返回最大的巷道
|
||||
// blockNum = num.intValue();
|
||||
// size = max;
|
||||
// }
|
||||
// }
|
||||
// return blockNum;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 同类型聚簇策略
|
||||
*/
|
||||
@Service("cluster")
|
||||
public class ClusterRuleHandler extends Decisioner<Structattr, String> {
|
||||
|
||||
/**
|
||||
* 仓位服务
|
||||
*/
|
||||
@Autowired
|
||||
private IStructattrService iStructattrService;
|
||||
|
||||
|
||||
/**
|
||||
* 同类物品集中原则
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, String param) {
|
||||
// 判断仓位是否为空
|
||||
if (ObjectUtil.isEmpty(list)) {
|
||||
throw new BadRequestException("仓位集合为空!");
|
||||
}
|
||||
|
||||
// 判断策略类型
|
||||
JSONObject jsonParam = JSONObject.parseObject(param, JSONObject.class);
|
||||
|
||||
List<Structattr> resultList = new ArrayList<>();
|
||||
|
||||
switch (jsonParam.getString("ioType")) {
|
||||
case "1":
|
||||
// 入库策略
|
||||
resultList = inHandler(list, jsonParam);
|
||||
break;
|
||||
case "2":
|
||||
// 出库策略
|
||||
// resultList = outHandler(list,jsonParam);
|
||||
break;
|
||||
case "3":
|
||||
// 通用策略
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("策略类型错误!");
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库策略
|
||||
*
|
||||
* @param attrList :仓位集合
|
||||
* @param jsonParam:materialId :物料标识(此方法只根据物料、排进行匹配)
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
private List<Structattr> inHandler(List<Structattr> attrList, JSONObject jsonParam) {
|
||||
// in查询条件处理
|
||||
List<BigDecimal> rowNumIn = attrList.stream()
|
||||
.map(Structattr::getRow_num)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
// 查询仓位中是否有相同的物料
|
||||
List<Structattr> attrLikeList = new ArrayList<>();
|
||||
// = iStructattrService.list(
|
||||
// new QueryWrapper<Structattr>().lambda()
|
||||
// .eq(Structattr::getMaterial_id, jsonParam.getString("materialId"))
|
||||
// .in(Structattr::getRow_num, rowNumIn)
|
||||
if (ObjectUtil.isEmpty(attrLikeList)) {
|
||||
return attrList;
|
||||
}
|
||||
// 取其中一个排进行匹配并返回
|
||||
return attrList.stream()
|
||||
.filter(row -> row.getRow_num().intValue() == attrLikeList.get(0).getRow_num().intValue())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库策略
|
||||
* @param attrList :仓位物料信息
|
||||
* @param jsonParam:iostorinvdtlId : 出入库明细标识(此方法只根据明细物料匹配)
|
||||
* @return List<Structattr> :需出库仓位集合
|
||||
*/
|
||||
// private List<Structattr> outHandler(List<Structattr> attrList, JSONObject jsonParam) {
|
||||
//
|
||||
// // 查询对应的出入库明细
|
||||
// StIvtIostorinvdtlIn dtlDao = iStIvtIostorinvdtlService.getById(jsonParam.getString("iostorinvdtlId"));
|
||||
//
|
||||
// // 查询传入仓位物料中的数量是否满足明细中的数量
|
||||
// List<String> vehicleCodeIn = attrList.stream()
|
||||
// .map(Structattr::getStoragevehicle_code)
|
||||
// .distinct()
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// List<MdPbStoragevehicleext> extList = iMdPbStoragevehicleextService.list(
|
||||
// new QueryWrapper<MdPbStoragevehicleext>().lambda()
|
||||
// .in(MdPbStoragevehicleext::getStoragevehicle_code, vehicleCodeIn)
|
||||
// );
|
||||
//
|
||||
// double attrQty = extList.stream()
|
||||
// .map(MdPbStoragevehicleext::getQty)
|
||||
// .reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
// .doubleValue();
|
||||
//
|
||||
// if (dtlDao.getUnassign_qty().doubleValue() > attrQty) {
|
||||
// // 说明不满足所需重量则全部返回
|
||||
// return attrList;
|
||||
// }
|
||||
//
|
||||
// // 需返回仓位物料集合
|
||||
// List<Structattr> resultList = new ArrayList<>();
|
||||
// // 满足所需数量: 根据巷道进行平均分配
|
||||
// double unAssingQty = dtlDao.getUnassign_qty().doubleValue();
|
||||
//
|
||||
// while (unAssingQty > 0) {
|
||||
//
|
||||
// // 添加需返回的仓位物料
|
||||
// Structattr attrDao = attrList.get(0);
|
||||
// resultList.add(attrDao);
|
||||
//
|
||||
// // 减去未分配重量
|
||||
// MdPbStoragevehicleext extDao = extList.stream()
|
||||
// .filter(row -> row.getStoragevehicle_code().equals(attrDao.getStoragevehicle_code()))
|
||||
// .findFirst().orElse(null);
|
||||
//
|
||||
// if (ObjectUtil.isEmpty(extDao)) {
|
||||
// throw new BadRequestException("未查询到载具对应的物料【"+attrDao.getStoragevehicle_code()+"】");
|
||||
// }
|
||||
//
|
||||
// unAssingQty = NumberUtil.sub(unAssingQty,extDao.getQty().doubleValue());
|
||||
//
|
||||
// // 移出此仓位物料,方便下一轮进行匹配
|
||||
// attrList.remove(attrDao);
|
||||
// }
|
||||
//
|
||||
// return resultList;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.common.utils.MapOf;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 先进先出策略
|
||||
*/
|
||||
@Service("fifo")
|
||||
@Slf4j
|
||||
public class FIFORuleHandler extends Decisioner<StructattrVechielDto, JSONObject> {
|
||||
|
||||
/**
|
||||
* 出入库明细服务
|
||||
*/
|
||||
@Autowired
|
||||
private IStructattrService iStructattrService;
|
||||
|
||||
@Override
|
||||
public List<StructattrVechielDto> handler(List<StructattrVechielDto> list, JSONObject param) {
|
||||
//分配数量
|
||||
int plan_qty = param.getInteger("qty");
|
||||
int finalPlan_qty = plan_qty;
|
||||
//当前条件只有id,批次
|
||||
log.info("---------执行fifo出库分配规则---------");
|
||||
List<StructattrVechielDto> vechielDtos = iStructattrService.collectVechicle(MapOf.of("material_id", param.getString("material_id")
|
||||
, "pcsn", param.getString("pcsn")
|
||||
, "stor_code", param.getString("stor_code")
|
||||
, "plan_qty", plan_qty
|
||||
, "is_lock", "false"
|
||||
, "order_by", "md_pb_vehicleMater.pcsn asc")
|
||||
);
|
||||
if (ObjectUtils.isEmpty(vechielDtos)) {
|
||||
throw new BadRequestException("当前出库策略:先进先出,库存分配失败,失败原因:库存不足!");
|
||||
}
|
||||
List<StructattrVechielDto> disList = new ArrayList<>();
|
||||
Map<String, List<StructattrVechielDto>> groupedMap = vechielDtos.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
StructattrVechielDto::getPcsn,
|
||||
Collectors.collectingAndThen(
|
||||
Collectors.toList(),
|
||||
r -> r.stream()
|
||||
.sorted(Comparator.comparing(StructattrVechielDto::getPcsn))
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
));
|
||||
LinkedHashMap<String, List<StructattrVechielDto>> sortedGroupMap = groupedMap.entrySet().stream()
|
||||
.sorted(Comparator.comparing(entry -> entry.getValue().get(0).getPcsn()))
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
Map.Entry::getValue,
|
||||
(r, s) -> r,
|
||||
LinkedHashMap::new
|
||||
));
|
||||
for (Map.Entry<String, List<StructattrVechielDto>> entry : sortedGroupMap.entrySet()) {
|
||||
List<StructattrVechielDto> sortedList = new ArrayList<>(entry.getValue());
|
||||
for (StructattrVechielDto structattr : sortedList) {
|
||||
BigDecimal qty = structattr.getCanuse_qty() != null ? structattr.getCanuse_qty() : BigDecimal.ZERO;
|
||||
BigDecimal frozen = structattr.getFrozen_qty() != null ? structattr.getFrozen_qty() : BigDecimal.ZERO;
|
||||
int available = qty.subtract(frozen).intValue();
|
||||
if (available <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (finalPlan_qty <= available) {
|
||||
structattr.setFrozen_qty(frozen.add(new BigDecimal(finalPlan_qty)));
|
||||
disList.add(structattr);
|
||||
finalPlan_qty = 0;
|
||||
break;
|
||||
} else {
|
||||
structattr.setFrozen_qty(frozen.add(new BigDecimal(available)));
|
||||
disList.add(structattr);
|
||||
finalPlan_qty -= available;
|
||||
}
|
||||
}
|
||||
if (finalPlan_qty <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return disList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 巷道均衡策略
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
// @Override
|
||||
// public List<StructattrVechielDto> handler1(List<StructattrVechielDto> list, JSONObject param) {
|
||||
// // 判断仓位是否为空
|
||||
//// if (ObjectUtil.isEmpty(list)) {
|
||||
//// throw new BadRequestException("库存分配失败:库存不足!");
|
||||
//// }
|
||||
//// List<String> need = list.stream().map(StructattrVechielDto::getStoragevehicle_code).collect(Collectors.toList());
|
||||
// //分配数量
|
||||
// int plan_qty = param.getInteger("qty");
|
||||
// //当前条件只有id,批次
|
||||
// log.info("---------执行fifo出库分配规则---------");
|
||||
// List<StructattrVechielDto> vechielDtos = iStructattrService.collectVechicle(MapOf.of("material_id", param.getString("material_id")
|
||||
// , "pcsn", param.getString("pcsn")
|
||||
// , "stor_code", param.getString("stor_code")
|
||||
// , "plan_qty", plan_qty
|
||||
// , "is_lock", "false"
|
||||
//// , "order_by","block_num asc,ABS(qty-#{plan_qty}) asc,update_time asc")
|
||||
// , "order_by","block_num asc,ABS(qty-#{plan_qty}) asc,update_time asc")
|
||||
// );
|
||||
// int finalPlan_qty = 0;
|
||||
//// vechielDtos.sort(Comparator.comparingInt(o -> (o.getQty().intValue() - finalPlan_qty)));
|
||||
// List<StructattrVechielDto> disList = new ArrayList<>();
|
||||
// for (StructattrVechielDto structattr : vechielDtos) {
|
||||
//// if (need.contains(structattr.getStoragevehicle_code()) && structattr.getFrozen_qty().intValue()==0){
|
||||
// if (structattr.getFrozen_qty().intValue()==0){
|
||||
// int cause_qty = structattr.getQty().subtract(structattr.getFrozen_qty()).intValue();
|
||||
// int sub = plan_qty - cause_qty;
|
||||
// finalPlan_qty = sub;
|
||||
// disList.add(structattr);
|
||||
// if (sub<=0){
|
||||
// structattr.setFrozen_qty(new BigDecimal(plan_qty));
|
||||
// break;
|
||||
// }
|
||||
// structattr.setFrozen_qty(new BigDecimal(cause_qty));
|
||||
// plan_qty = sub;
|
||||
// }
|
||||
// }
|
||||
// if (finalPlan_qty>0){
|
||||
// throw new BadRequestException("库存不足:物料"+param.getString("material_id")+"当前库存可用数"+(param.getInteger("qty").intValue()-finalPlan_qty));
|
||||
// }
|
||||
// return disList;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.wms.basedata_manage.service.IMdPbStoragevehicleinfoService;
|
||||
import org.nl.wms.basedata_manage.service.dao.MdPbStoragevehicleinfo;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 货位限位策略: 限高,限宽,限长,限重
|
||||
*/
|
||||
@Service("limitStorage")
|
||||
@Slf4j
|
||||
public class LimitStorageRuleHandler extends Decisioner<Structattr, JSONObject> {
|
||||
|
||||
|
||||
/**
|
||||
* 载具扩展属性服务服务
|
||||
*/
|
||||
@Autowired
|
||||
private IMdPbStoragevehicleinfoService bmVehicleInfoService;
|
||||
|
||||
/**
|
||||
* 货位限位策略:根据货位的长宽高
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
long startTime1 = System.currentTimeMillis();
|
||||
// 判断仓位是否为空
|
||||
// 判断策略类型
|
||||
String vehicleCode = param.getString("vehicle_code");
|
||||
MdPbStoragevehicleinfo vehileInfo = bmVehicleInfoService.getOne(new QueryWrapper<MdPbStoragevehicleinfo>().eq("storagevehicle_code", vehicleCode));
|
||||
if (vehileInfo == null) {
|
||||
throw new BadRequestException("限位策略,当前载具信息不存在:" + vehicleCode + "!");
|
||||
}
|
||||
//限位策略特殊处理
|
||||
String start_point = param.getString("start_point");
|
||||
String errorTask = param.getString("errorTask");
|
||||
log.info("限位策略:起点为" + start_point + ",载具号:" + vehicleCode + "执行策略前仓位位数为:" + list.size() + ",第一个仓位为:" + list.get(0).getStruct_code());
|
||||
if ((StringUtils.isNotBlank(start_point) || StringUtils.isNotBlank(errorTask))) {
|
||||
list = list.stream().filter(struct -> struct.getCol_num().intValue() > 2).collect(Collectors.toList());
|
||||
if ("1109".equals(start_point)) {
|
||||
log.info("限位策略:起点为1109,载具号:" + vehicleCode + "排除小于3排的仓位成功!");
|
||||
}
|
||||
if (StringUtils.isNotBlank(errorTask)) {
|
||||
log.info("限位策略:任务类型为入满或出阻挡任务,载具号:" + vehicleCode + "排除小于3排的仓位成功!");
|
||||
}
|
||||
}
|
||||
List<Structattr> result = inHandler(list, vehileInfo);
|
||||
if (CollectionUtils.isEmpty(result)) {
|
||||
log.error("限位策略:载具号:" + vehicleCode + "获取仓位失败,该高度等级对应库位数量为0!");
|
||||
throw new BadRequestException("限位策略:载具号:" + vehicleCode + "获取仓位失败,该高度等级对应库位数量为0!");
|
||||
}
|
||||
log.info("限位策略:起点为" + start_point + ",载具号:" + vehicleCode + "执行策略后仓位位数为:" + result.size() + ",第一个仓位为:" + result.get(0).getStruct_code());
|
||||
log.info("限位策略:载具号:" + vehicleCode + "获取仓位耗时:{}", System.currentTimeMillis() - startTime1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库策略:判断货位的长宽高
|
||||
*
|
||||
* @param attrList :仓位集合
|
||||
* @param vehicle :物料标识、width: 宽度、 height:高度、zdepth:深度
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
private List<Structattr> inHandler(List<Structattr> attrList, MdPbStoragevehicleinfo vehicle) {
|
||||
//限制条件:限制哪些
|
||||
List<String> limits = JSONArray.parseArray(strategyConfig.getParam(), String.class);
|
||||
Predicate<Structattr> eqLimt = Structattr -> {
|
||||
Boolean result = Boolean.TRUE;
|
||||
if (limits.contains("h")) {
|
||||
result = result && Structattr.getHeight().equals(vehicle.getVehicle_height());
|
||||
}
|
||||
if (limits.contains("w")) {
|
||||
result = result && Structattr.getWidth().equals(vehicle.getVehicle_width());
|
||||
}
|
||||
if (limits.contains("l")) {
|
||||
result = result && Structattr.getZdepth().equals(vehicle.getVehicle_long());
|
||||
}
|
||||
if (limits.contains("weight")) {
|
||||
result = result && Structattr.getWeight().equals(vehicle.getWeigth());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// 判断长宽高是否符合要求
|
||||
List<Structattr> eqLimitCollect = attrList.stream()
|
||||
.filter(eqLimt)
|
||||
.collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(eqLimitCollect)) {
|
||||
return eqLimitCollect;
|
||||
}
|
||||
Predicate<Structattr> ltLimt = Structattr -> {
|
||||
Boolean result = Boolean.TRUE;
|
||||
if (limits.contains("h")) {
|
||||
result = result && Structattr.getHeight().compareTo(vehicle.getVehicle_height()) > 0;
|
||||
}
|
||||
if (limits.contains("w")) {
|
||||
result = result && Structattr.getWidth().compareTo(vehicle.getVehicle_width()) > 0;
|
||||
}
|
||||
if (limits.contains("l")) {
|
||||
result = result && Structattr.getZdepth().compareTo(vehicle.getVehicle_long()) > 0;
|
||||
}
|
||||
if (limits.contains("weight")) {
|
||||
result = result && Structattr.getWeight().compareTo(vehicle.getWeigth()) > 0;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// 判断长宽高是否符合要求
|
||||
List<Structattr> ltLimtCollect = attrList.stream()
|
||||
.filter(ltLimt)
|
||||
.collect(Collectors.toList());
|
||||
return ltLimtCollect;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 就近放置策略:根据物料ABC类区分
|
||||
*/
|
||||
@Service("nearby")
|
||||
@Slf4j
|
||||
public class NearbyRuleHandler extends Decisioner<Structattr, JSONObject> {
|
||||
//每个策略的配置信息
|
||||
/**
|
||||
* 出入库明细服务
|
||||
*/
|
||||
@Autowired
|
||||
private IStructattrService iStructattrService;
|
||||
|
||||
/**
|
||||
* 载具扩展属性服务服务
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 就近放置策略:根据出入库顺序进行判断
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new BadRequestException("当前分配策略无可用货位");
|
||||
}
|
||||
List<Structattr> before = list.subList(0, list.size() > 10 ? 10 : list.size());
|
||||
log.info("就近分配前:" + before.stream().map(Structattr::getStruct_code).collect(Collectors.joining(",")));
|
||||
list.sort(Comparator.comparingInt(i -> i.getRow_num().add(i.getCol_num()).add(i.getLayer_num()).intValue()));
|
||||
//就近分配区分出库还是入库策略
|
||||
List<Structattr> subList = list.subList(0, list.size() > 10 ? 10 : list.size());
|
||||
log.info("就近分配结果:" + subList.stream().map(Structattr::getStruct_code).collect(Collectors.joining(",")));
|
||||
return subList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 轻上重下策略
|
||||
*/
|
||||
@Service("weight")
|
||||
public class WeightRuleHandler extends Decisioner<Structattr, String> {
|
||||
|
||||
|
||||
/**
|
||||
* 轻上重下策略:根据物品的重量
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, String param) {
|
||||
// 判断仓位是否为空
|
||||
if (ObjectUtil.isEmpty(list)) {
|
||||
throw new BadRequestException("仓位集合为空!");
|
||||
}
|
||||
|
||||
// 判断策略类型
|
||||
JSONObject jsonParam = JSONObject.parseObject(param, JSONObject.class);
|
||||
|
||||
List<Structattr> resultList = new ArrayList<>();
|
||||
|
||||
switch (jsonParam.getString("ioType")) {
|
||||
case "1":
|
||||
// 入库策略
|
||||
resultList = inHandler(list, jsonParam);
|
||||
break;
|
||||
case "2":
|
||||
// 出库策略
|
||||
// resultList = outHandler(list,jsonParam);
|
||||
break;
|
||||
case "3":
|
||||
// 通用策略
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("策略类型错误!");
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库策略:根据重量找对应的货位
|
||||
*
|
||||
* @param attrList :仓位集合
|
||||
* @param jsonParam:materialId :物料标识、weight: 重量
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
private List<Structattr> inHandler(List<Structattr> attrList, JSONObject jsonParam) {
|
||||
// 过滤对应的货位
|
||||
return attrList.stream()
|
||||
.filter(row -> row.getWeight().doubleValue() <= jsonParam.getDoubleValue("weight"))
|
||||
.sorted(Comparator.comparing(Structattr::getWeight))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库策略:默认出库
|
||||
* @param attrList :仓位物料信息
|
||||
* @param jsonParam:iostorinvdtlId : 出入库明细标识(此方法只根据时间匹配)
|
||||
* @return List<Structattr> :需出库仓位集合
|
||||
*/
|
||||
// private List<Structattr> outHandler(List<Structattr> attrList, JSONObject jsonParam) {
|
||||
//
|
||||
// // 查询对应的出入库明细
|
||||
// StIvtIostorinvdtlIn dtlDao = iStIvtIostorinvdtlService.getById(jsonParam.getString("iostorinvdtlId"));
|
||||
//
|
||||
// // 查询传入仓位物料中的数量是否满足明细中的数量
|
||||
// List<String> vehicleCodeIn = attrList.stream()
|
||||
// .map(Structattr::getStoragevehicle_code)
|
||||
// .distinct()
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// // 查询对应的载具物料
|
||||
// List<MdPbStoragevehicleext> extList = iMdPbStoragevehicleextService.list(
|
||||
// new QueryWrapper<MdPbStoragevehicleext>().lambda()
|
||||
// .in(MdPbStoragevehicleext::getStoragevehicle_code, vehicleCodeIn)
|
||||
// );
|
||||
//
|
||||
// double attrQty = extList.stream()
|
||||
// .map(MdPbStoragevehicleext::getQty)
|
||||
// .reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
// .doubleValue();
|
||||
//
|
||||
// if (dtlDao.getUnassign_qty().doubleValue() > attrQty) {
|
||||
// // 说明不满足所需重量则全部返回
|
||||
// return attrList;
|
||||
// }
|
||||
//
|
||||
// // 需返回仓位物料集合
|
||||
// List<Structattr> resultList = new ArrayList<>();
|
||||
// // 满足所需数量: 根据巷道进行平均分配
|
||||
// double unAssingQty = dtlDao.getUnassign_qty().doubleValue();
|
||||
//
|
||||
// while (unAssingQty > 0) {
|
||||
//
|
||||
// // 添加需返回的仓位物料
|
||||
// Structattr attrDao = attrList.get(0);
|
||||
// resultList.add(attrDao);
|
||||
//
|
||||
// // 减去未分配重量
|
||||
// MdPbStoragevehicleext extDao = extList.stream()
|
||||
// .filter(row -> row.getStoragevehicle_code().equals(attrDao.getStoragevehicle_code()))
|
||||
// .findFirst().orElse(null);
|
||||
//
|
||||
// if (ObjectUtil.isEmpty(extDao)) {
|
||||
// throw new BadRequestException("未查询到载具对应的物料【"+attrDao.getStoragevehicle_code()+"】");
|
||||
// }
|
||||
//
|
||||
// unAssingQty = NumberUtil.sub(unAssingQty,extDao.getQty().doubleValue());
|
||||
//
|
||||
// // 移出此仓位物料,方便下一轮进行匹配
|
||||
// attrList.remove(attrDao);
|
||||
// }
|
||||
//
|
||||
// return resultList;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
##货位分配原则 出入库
|
||||
|
||||
###1、上轻下重原则
|
||||
根据货物重量选择摆放位置。把重的东西放在下层,把轻放在货架上层。需要人工搬运的大型货物以腰部的高度摆放。这样提高效率、保证安全。
|
||||
###2、优先靠近出入口原则
|
||||
根据出入库频率选定位置。出入库频率高的货物应放在靠近出入口,易于作业的地方;流动性差的货物放在离出入口较远的地方;季节性物品按季节特性来选定场所摆放。
|
||||
###3、先进先出原则
|
||||
一般企业为了加快周转,先入先出一同种物料出库时,先入库的物资,需要先提取出库,以加快物料周转,从而避免因物料长期积压产生锈蚀、变形、变质及其他损坏造成的损失。因此在货位分配时要方便先进物品优先出库。
|
||||
###4、同类物品集中原则
|
||||
同一品种同一地方保管。为提高作业效率和保管效率同一物品或类似物品应在同一地方保管,提高仓储工作效率。
|
||||
###5、多巷道分布原则
|
||||
货位分配是应提高可靠性,分巷道存放一仓库有多个巷道时,同种物品分散在不同的巷道进行存放。以防止因某巷道堵塞影响某种物料的出库,造成生产中断。
|
||||
###6.超限分配原则:
|
||||
对于货位超限:横向/纵向暂用多个货位.高度超限
|
||||
|
||||
##规则处理方式:责任链模式
|
||||
list->5
|
||||
1->list->2->list->3->list list.get(0)
|
||||
class
|
||||
List<> handler(List<货位集合>,入库物料信息)
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 自定义类处理器
|
||||
*/
|
||||
public class ClassRuleHandler extends Decisioner<String,String> {
|
||||
@Override
|
||||
public List<String> handler(List<String> list, String param) {
|
||||
System.out.println("迭代器使用中"+this.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.config.SpringContextHolder;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.nl.wms.sch_manage.enums.StatusEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
*深位优先
|
||||
* @author ZZQ
|
||||
* @Date 2024/7/31 15:19
|
||||
*/
|
||||
@Service("depthPriority")
|
||||
@Slf4j
|
||||
public class DepthPriorityHandler extends Decisioner<Structattr, JSONObject> {
|
||||
public DepthPriorityHandler() {
|
||||
}
|
||||
|
||||
//现场1/4排深位
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
//托盘库和扩展库不需要深位判断
|
||||
if (list.get(0).getStor_code().equals(StatusEnum.STOCK_INFO.code("托盘库")) || "LXBCP02".equals(list.get(0).getSect_code())) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
long startTime1 = System.currentTimeMillis();
|
||||
List<Structattr> returnResult = new ArrayList<>();
|
||||
// 深货位
|
||||
List<Structattr> depCollect = list.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 1 || a.getRow_num().intValue() == 4)
|
||||
.collect(Collectors.toList());
|
||||
// 浅货位
|
||||
List<Structattr> shallowCollect = list.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 2 || a.getRow_num().intValue() == 3)
|
||||
.collect(Collectors.toList());
|
||||
for (Structattr r : depCollect) {
|
||||
for (Structattr s : shallowCollect) {
|
||||
String depCode = r.getCol_num() + "-" + r.getLayer_num();
|
||||
String shallowCode = s.getCol_num() + "-" + s.getLayer_num();
|
||||
if ((r.getRow_num().intValue() == 1 && s.getRow_num().intValue() == 2) ||
|
||||
(r.getRow_num().intValue() == 4 && s.getRow_num().intValue() == 3)) {
|
||||
if (depCode.equals(shallowCode)) {
|
||||
returnResult.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (returnResult.size() > 0) {
|
||||
if (returnResult.size() < 3) {
|
||||
return getOtherStructattr(list, param, startTime1, depCollect);
|
||||
} else {
|
||||
log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 存在深位并对应浅位无货的库位,分配仓位:" + returnResult.get(0).getStruct_code());
|
||||
log.info("深位优先策略:载具号:"+param.getString("vehicle_code")+"获取深货位且浅货位无货仓位耗时:{}", System.currentTimeMillis() - startTime1);
|
||||
return returnResult;
|
||||
}
|
||||
} else {
|
||||
return getOtherStructattr(list, param, startTime1, depCollect);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Structattr> getOtherStructattr(List<Structattr> list, JSONObject param, long startTime1, List<Structattr> depCollect) {
|
||||
// if (!depCollect.isEmpty()) {
|
||||
// log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 存在深位无货但对应浅位有货的库位,需要移库,分配仓位:" + depCollect.get(0).getStruct_code());
|
||||
// log.info("深位优先策略:获取深货位无货且浅货位有货仓位耗时:{}", System.currentTimeMillis() - startTime1);
|
||||
// return depCollect;
|
||||
// }
|
||||
//浅货位,则需要判断对应
|
||||
IStructattrService iStructattrService = SpringContextHolder.getBean(IStructattrService.class);
|
||||
if (list.get(0).getStor_code().equals(StatusEnum.STOCK_INFO.code("料箱库"))) {
|
||||
List<Structattr> list1 = iStructattrService.list(new LambdaUpdateWrapper<Structattr>()
|
||||
.in(Structattr::getRow_num, Arrays.asList(1, 4))
|
||||
.eq(Structattr::getStor_code, StatusEnum.STOCK_INFO.code("料箱库"))
|
||||
.eq(Structattr::getIs_used, 1)
|
||||
.eq(Structattr::getLock_type, StatusEnum.LOCK.code("无锁")));
|
||||
//先找2排的再找3排的
|
||||
if (!list1.isEmpty()) {
|
||||
List<Structattr> combinedResult = new ArrayList<>();
|
||||
//1排
|
||||
List<Structattr> deepCollect1 = list1.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 1)
|
||||
.collect(Collectors.toList());
|
||||
List<Structattr> shallowCollect1 = list.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 2)
|
||||
.collect(Collectors.toList());
|
||||
Set<String> deepCollect1Set = deepCollect1.stream()
|
||||
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
|
||||
.collect(Collectors.toSet());
|
||||
List<Structattr> intersection1 = shallowCollect1.stream()
|
||||
.filter(r ->deepCollect1Set.contains(r.getCol_num() + "_" + r.getLayer_num()))
|
||||
.collect(Collectors.toList());
|
||||
if (!intersection1.isEmpty()) {
|
||||
combinedResult.addAll(intersection1);
|
||||
} else {
|
||||
//4排
|
||||
List<Structattr> deepCollect2 = list1.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 4)
|
||||
.collect(Collectors.toList());
|
||||
List<Structattr> shallowCollect2 = list.stream()
|
||||
.filter(a -> a.getRow_num().intValue() == 3)
|
||||
.collect(Collectors.toList());
|
||||
Set<String> deepCollect2Set = deepCollect2.stream()
|
||||
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
|
||||
.collect(Collectors.toSet());
|
||||
List<Structattr> intersection2 = shallowCollect2.stream()
|
||||
.filter(r -> deepCollect2Set.contains(r.getCol_num() + "_" + r.getLayer_num()))
|
||||
.collect(Collectors.toList());
|
||||
combinedResult.addAll(intersection2);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(combinedResult)) {
|
||||
log.error("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位数量为0!");
|
||||
throw new BadRequestException("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位数量为0!");
|
||||
}
|
||||
log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 深货位有货且浅货位无货仓位,无需移库,分配仓位:" + combinedResult.get(0).getStruct_code());
|
||||
log.info("深位优先策略:获取深货位有货且浅货位无货仓位耗时:{}", System.currentTimeMillis() - startTime1);
|
||||
return combinedResult;
|
||||
}
|
||||
return list;
|
||||
} else {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.common.utils.MapOf;
|
||||
import org.nl.wms.basedata_manage.service.IStructattrService;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.nl.wms.sch_manage.enums.StatusEnum;
|
||||
import org.nl.wms.sch_manage.service.ISchBaseTaskService;
|
||||
import org.nl.wms.sch_manage.service.dao.SchBaseTask;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2024/4/6 16:18
|
||||
* 入库双叉分配测策略
|
||||
*/
|
||||
@Service("inventory")
|
||||
public class InventoryRuleHandler extends Decisioner<Structattr, JSONObject> {
|
||||
|
||||
|
||||
private static final Map<String, String> LINK_POINT = MapOf.of("1109", "1110", "1110", "1109");
|
||||
|
||||
//每个策略的配置信息
|
||||
/**
|
||||
* 出入库明细服务
|
||||
*/
|
||||
@Autowired
|
||||
private IStructattrService iStructattrService;
|
||||
@Autowired
|
||||
private ISchBaseTaskService taskService;
|
||||
@Autowired
|
||||
private IStructattrService StructattrService;
|
||||
|
||||
/**
|
||||
* 载具扩展属性服务服务
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 就近放置策略:根据出入库顺序进行判断
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new BadRequestException("当前分配策略无可用货位");
|
||||
}
|
||||
String start_point = param.getString("start_point");
|
||||
String target = LINK_POINT.get(start_point);
|
||||
if (StringUtils.isNotEmpty(target)){
|
||||
LambdaQueryWrapper<SchBaseTask> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(SchBaseTask::getPoint_code1, target)
|
||||
.lt(SchBaseTask::getTask_status, StatusEnum.FORM_STATUS.code("执行中"));
|
||||
List<SchBaseTask> tasks = taskService.list(lqw);
|
||||
for (SchBaseTask task : tasks) {
|
||||
String point_code2 = task.getPoint_code2();
|
||||
List new_list = getInventory(list, point_code2);
|
||||
if (!CollectionUtils.isEmpty(new_list)) {
|
||||
return new_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
private List<Structattr> getInventory(List<Structattr> list, String point_code2) {
|
||||
Structattr structattr = StructattrService.getOne(new LambdaQueryWrapper<Structattr>().eq(Structattr::getStruct_code, point_code2).eq(Structattr::getIs_used, true));
|
||||
return Optional.ofNullable(list)
|
||||
.orElse(new CopyOnWriteArrayList<>())
|
||||
.stream()
|
||||
.filter(stru -> stru.getRow_num().equals(structattr.getRow_num()) && stru.getLayer_num().equals(structattr.getLayer_num()))
|
||||
.filter(stru -> (stru.getCol_num().intValue() / 4 == structattr.getCol_num().intValue() / 4) && (((stru.getCol_num().intValue() % 4) + (structattr.getCol_num().intValue() % 4) == 2) || (stru.getCol_num().intValue() % 4) + (structattr.getCol_num().intValue() % 4) == 4))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 手动过滤XYZ排信息
|
||||
* {"y":[1,2,3,104,103,102]}
|
||||
*/
|
||||
@Service("passRCL")
|
||||
@Slf4j
|
||||
public class PassRCLHandler extends Decisioner<Structattr, JSONObject> {
|
||||
//现场1/4排深位
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
String configParam = this.strategyConfig.getParam();
|
||||
JSONObject jsonP = JSONObject.parseObject(configParam);
|
||||
List x = jsonP.getObject("x", List.class);
|
||||
List y = jsonP.getObject("y", List.class);
|
||||
List z = jsonP.getObject("z", List.class);
|
||||
Stream<Structattr> stream = list.stream();
|
||||
if (!CollectionUtils.isEmpty(x)){
|
||||
stream = stream.filter(Structattr -> !x.contains(Structattr.getRow_num()));
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(y)){
|
||||
stream = stream.filter(Structattr -> !y.contains(Structattr.getCol_num()));
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(z)){
|
||||
stream = stream.filter(Structattr -> !z.contains(Structattr.getLayer_num()));
|
||||
}
|
||||
List<Structattr> collect = stream.collect(Collectors.toList());
|
||||
log.info("手动过滤XYZ排信息策略过滤数量:"+(list.size()-collect.size()));
|
||||
return collect;
|
||||
}
|
||||
// public static void main(String[] args) {
|
||||
// List<Structattr> list = new ArrayList<>();
|
||||
// for (int i =0;i<10;i++){
|
||||
// Structattr structattr = new Structattr();
|
||||
// structattr.setRow_num(new Random().nextInt(2)+1);
|
||||
// structattr.setCol_num(new Random().nextInt(10)+1);
|
||||
// structattr.setLayer_num(new Random().nextInt(2)+1);
|
||||
// list.add(structattr);
|
||||
// }
|
||||
// System.out.println(list);
|
||||
// String configParam = "{\"z\":[2]}";
|
||||
// JSONObject jsonP = JSONObject.parseObject(configParam);
|
||||
// List x = jsonP.getObject("x", List.class);
|
||||
// List y = jsonP.getObject("y", List.class);
|
||||
// List z = jsonP.getObject("z", List.class);
|
||||
// Stream<Structattr2> stream = list.stream();
|
||||
// if (!CollectionUtils.isEmpty(x)){
|
||||
// stream = stream.filter(Structattr -> !x.contains(Structattr.getRow_num()));
|
||||
// }
|
||||
// if (!CollectionUtils.isEmpty(y)){
|
||||
// stream = stream.filter(Structattr -> !y.contains(Structattr.getCol_num()));
|
||||
// }
|
||||
// if (!CollectionUtils.isEmpty(z)){
|
||||
// stream = stream.filter(Structattr -> !z.contains(Structattr.getLayer_num()));
|
||||
// }
|
||||
// List<Structattr2> collect = stream.collect(Collectors.toList());
|
||||
// System.out.println(collect);
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.wms.basedata_manage.service.dao.Structattr;
|
||||
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author GBX
|
||||
* @Date 2025/2/1 16:18
|
||||
* 相同巷道,自下而上分配,左右相邻
|
||||
*/
|
||||
@Service("sameBlockNum")
|
||||
@Slf4j
|
||||
public class SameBlockNumRuleHandler extends Decisioner<Structattr, JSONObject> {
|
||||
|
||||
|
||||
/**
|
||||
* 相同巷道,自下而上分配,提高CTU放货效率
|
||||
*
|
||||
* @param list :仓位集合
|
||||
* @param param:出入库单明细:物料相关信息、出入类型:{ ioType: 出入类型
|
||||
* materialId: 物料标识
|
||||
* ...
|
||||
* }
|
||||
* @return List<Structattr> :仓位集合
|
||||
*/
|
||||
@Override
|
||||
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
|
||||
// 判断仓位是否为空
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new BadRequestException("当前分配策略sameBlockNum无可用货位");
|
||||
}
|
||||
// 1. 找出最小巷道号
|
||||
BigDecimal minBlockNum = list.stream()
|
||||
.map(Structattr::getBlock_num)
|
||||
.min(BigDecimal::compareTo)
|
||||
.orElseThrow(() -> new BadRequestException("未找到可用的巷道"));
|
||||
// 2. 筛选出这个巷道的所有结构,按列 -> 层排序
|
||||
List<Structattr> blockList = list.stream()
|
||||
.filter(item -> item.getBlock_num().compareTo(minBlockNum) == 0)
|
||||
.sorted(Comparator
|
||||
.comparing(Structattr::getCol_num)
|
||||
.thenComparing(Structattr::getLayer_num))
|
||||
.collect(Collectors.toList());
|
||||
List<Structattr> result = new ArrayList<>();
|
||||
// 3. 找出所有层号(去重 + 升序)
|
||||
Set<BigDecimal> allLayers = blockList.stream()
|
||||
.map(Structattr::getLayer_num)
|
||||
.collect(Collectors.toCollection(TreeSet::new)); // 自动排序
|
||||
// 4. 从小层号开始,尝试找同一列的货位
|
||||
for (BigDecimal layer : allLayers) {
|
||||
List<Structattr> currentLayer = blockList.stream()
|
||||
.filter(item -> item.getLayer_num().compareTo(layer) == 0)
|
||||
.collect(Collectors.toList());
|
||||
if (!currentLayer.isEmpty()) {
|
||||
result.addAll(currentLayer);
|
||||
break; // 找到一层就跳出
|
||||
}
|
||||
}
|
||||
// 5. 如果没找到符合的,就用全部 blockList
|
||||
if (result.isEmpty()) {
|
||||
result.addAll(blockList);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -192,7 +192,7 @@ public class PmFormData implements Serializable {
|
||||
* 单重
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String single_weight;
|
||||
private String net_weight;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,6 @@ public interface PmFormDataMapper extends BaseMapper<PmFormData> {
|
||||
|
||||
List<PmFormDataDto> queryTree2(@Param("query") FormDataQuery query);
|
||||
|
||||
List<PmFormDataDto> queryCtuOrderList(@Param("query") FormDataQuery query);
|
||||
|
||||
|
||||
List<PmFormDataDto> selectChilds(List<String> parents);
|
||||
@@ -36,9 +35,6 @@ public interface PmFormDataMapper extends BaseMapper<PmFormData> {
|
||||
void dynamicSql(@Param("sql") String sql);
|
||||
|
||||
|
||||
Set<String> existFormDataList(@Param("form_type") String form_type);
|
||||
|
||||
Set<String> existFormCodeDataList();
|
||||
|
||||
BigDecimal queryTreeCounts(@Param("query") FormDataQuery query);
|
||||
|
||||
|
||||
@@ -1,30 +1,246 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.nl.wms.pm_manage.form_data.service.dao.PmFormDataDao">
|
||||
<mapper namespace="org.nl.wms.pm_manage.form_data.service.dao.mapper.PmFormDataMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData">
|
||||
<!--
|
||||
WARNING - This element is automatically generated by MyBatis Generator !
|
||||
Do not modify this file directly, any changes will be overwritten.
|
||||
-->
|
||||
<id column="id" property="id" jdbcType="BIGINT"/>
|
||||
<result property="form_id" column="form_id" jdbcType="BIGINT"/>
|
||||
<result property="form_type" column="form_type" jdbcType="VARCHAR"/>
|
||||
<result property="status" column="status" jdbcType="VARCHAR"/>
|
||||
<result property="create_name" column="create_name" jdbcType="VARCHAR"/>
|
||||
<result property="create_time" column="create_time" jdbcType="TIMESTAMP"/>
|
||||
<result property="material_id" column="material_id" jdbcType="BIGINT"/>
|
||||
<result property="qty" column="qty" jdbcType="DECIMAL"/>
|
||||
<result property="pcsn" column="pcsn" jdbcType="VARCHAR"/>
|
||||
<result property="vehicle_code" column="vehicle_code" jdbcType="VARCHAR"/>
|
||||
<result property="parent_id" column="parent_id" jdbcType="BIGINT"/>
|
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
|
||||
<result property="unit_id" column="unit_id" jdbcType="BIGINT"/>
|
||||
<result property="id" column="id"/>
|
||||
<result property="code" column="code"/>
|
||||
<result property="proc_inst_id" column="proc_inst_id"/>
|
||||
<result property="source_form_type" column="source_form_type"/>
|
||||
<result property="source_form_id" column="source_form_id"/>
|
||||
<result property="source_form_date" column="source_form_date"/>
|
||||
<result property="form_type" column="form_type"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="create_name" column="create_name"/>
|
||||
<result property="create_time" column="create_time"/>
|
||||
<result property="material_id" column="material_id"/>
|
||||
<result property="qty" column="qty"/>
|
||||
<result property="pcsn" column="pcsn"/>
|
||||
<result property="vehicle_code" column="vehicle_code"/>
|
||||
<result property="parent_id" column="parent_id"/>
|
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
|
||||
<result property="unit_id" column="unit_id"/>
|
||||
</resultMap>
|
||||
<resultMap id="ResultMapWithBLOBs" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData" extends="BaseResultMap">
|
||||
<!--
|
||||
WARNING - This element is automatically generated by MyBatis Generator !
|
||||
Do not modify this file directly, any changes will be overwritten.
|
||||
-->
|
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
|
||||
|
||||
<resultMap id="dataDetail" type="org.nl.wms.pm_manage.form_data.service.dto.PmFormDataDto" >
|
||||
<result property="id" column="id"/>
|
||||
<result property="code" column="code"/>
|
||||
<result property="proc_inst_id" column="proc_inst_id"/>
|
||||
<result property="source_form_type" column="source_form_type"/>
|
||||
<result property="source_form_id" column="source_form_id"/>
|
||||
<result property="source_form_type" column="source_form_type"/>
|
||||
<result property="form_type" column="form_type"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="create_name" column="create_name"/>
|
||||
<result property="create_time" column="create_time"/>
|
||||
<result property="material_id" column="material_id"/>
|
||||
<result property="qty" column="qty"/>
|
||||
<result property="assign_qty" column="assign_qty"/>
|
||||
<result property="plan_qty" column="plan_qty"/>
|
||||
<result property="pcsn" column="pcsn"/>
|
||||
<result property="material_code" column="material_code"/>
|
||||
<result property="material_name" column="material_name"/>
|
||||
<result property="material_spec" column="material_spec"/>
|
||||
<result property="net_weight" column="net_weight"/>
|
||||
<result property="vehicle_code" column="vehicle_code"/>
|
||||
<result property="vehicle_id" column="vehicle_id"/>
|
||||
<result property="parent_id" column="parent_id"/>
|
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
|
||||
<result property="unit_id" column="unit_id"/>
|
||||
<result property="unit_name" column="unit_name"/>
|
||||
<!-- <result property="HasChildren" column="HasChildren"/>-->
|
||||
</resultMap>
|
||||
|
||||
<select id="query" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
child.*
|
||||
FROM
|
||||
pm_form_data child
|
||||
<where>
|
||||
<if test="query.form_type != null and query.form_type != ''">
|
||||
and form_type = #{query.form_type}
|
||||
</if>
|
||||
<if test="query.form_query != null and query.form_query.size() > 0">
|
||||
<foreach collection="query.form_query" item="value" index="key" >
|
||||
<if test="value != null and value != ''">
|
||||
and JSON_CONTAINS(child.form_data, '{"${key}":"${value}"}')
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<select id="queryTree" resultMap="dataDetail">
|
||||
SELECT
|
||||
pm_form_data.*,
|
||||
md_me_materialbase.material_code,
|
||||
md_me_materialbase.material_name,
|
||||
md_me_materialbase.material_spec,
|
||||
md_me_materialbase.net_weight
|
||||
FROM
|
||||
pm_form_data
|
||||
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
|
||||
<where>
|
||||
<if test="query.form_type != null and query.form_type != ''">
|
||||
and form_type = #{query.form_type}
|
||||
</if>
|
||||
<if test="query.status != null and query.status != ''">
|
||||
and pm_form_data.status IN
|
||||
<foreach collection="query.status" item="status" separator="," open="(" close=")">
|
||||
#{status}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="query.parent_id != null and query.parent_id != ''">
|
||||
and parent_id = #{query.parent_id}
|
||||
</if>
|
||||
<if test="query.form_query != null and query.form_query.size() > 0">
|
||||
<foreach collection="query.form_query" item="value" index="key" >
|
||||
<if test="value != null and value != ''">
|
||||
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
<select id="queryTree2" resultMap="dataDetail">
|
||||
SELECT
|
||||
pm_form_data.*,
|
||||
md_me_materialbase.material_code,
|
||||
md_me_materialbase.material_name,
|
||||
md_me_materialbase.material_spec,
|
||||
md_me_materialbase.net_weight
|
||||
FROM
|
||||
pm_form_data
|
||||
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
|
||||
<where>
|
||||
<if test="query.search != null and query.search != ''">
|
||||
and form_data LIKE '%${query.search}%'
|
||||
</if>
|
||||
<if test="query.form_type != null and query.form_type != ''">
|
||||
and form_type = #{query.form_type}
|
||||
</if>
|
||||
<if test="query.pcsn != null and query.pcsn != ''">
|
||||
and pcsn = #{query.pcsn}
|
||||
</if>
|
||||
<if test="query.code != null and query.code != ''">
|
||||
and code LIKE '%${query.code}'
|
||||
</if>
|
||||
<if test="query.bill_code != null and query.bill_code != ''">
|
||||
and source_form_date = #{query.bill_code}
|
||||
</if>
|
||||
<if test="query.mater != null and query.mater != ''">
|
||||
and md_me_materialbase.material_code like '%${query.mater}%'
|
||||
</if>
|
||||
<if test="query.start_time != null and query.start_time != ''">
|
||||
and pm_form_data.create_time >= #{query.start_time}
|
||||
</if>
|
||||
<if test="query.end_time != null and query.end_time != ''">
|
||||
and #{query.end_time} >= pm_form_data.create_time
|
||||
</if>
|
||||
<if test="query.status != null and query.status != ''">
|
||||
and pm_form_data.status IN
|
||||
<foreach collection="query.status" item="status" separator="," open="(" close=")">
|
||||
#{status}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="query.parent_id != null and query.parent_id != ''">
|
||||
and parent_id = #{query.parent_id}
|
||||
</if>
|
||||
<if test="query.form_query != null and query.form_query.size() > 0">
|
||||
<foreach collection="query.form_query" item="value" index="key">
|
||||
<if test="value != null and value != ''">
|
||||
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
<select id="queryTreeCounts" resultType="java.math.BigDecimal">
|
||||
SELECT
|
||||
SUM(pm_form_data.qty) as counts
|
||||
FROM
|
||||
pm_form_data
|
||||
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
|
||||
<where>
|
||||
<if test="query.search != null and query.search != ''">
|
||||
and form_data LIKE '%${query.search}%'
|
||||
</if>
|
||||
<if test="query.form_type != null and query.form_type != ''">
|
||||
and form_type = #{query.form_type}
|
||||
</if>
|
||||
<if test="query.pcsn != null and query.pcsn != ''">
|
||||
and pcsn = #{query.pcsn}
|
||||
</if>
|
||||
<if test="query.code != null and query.code != ''">
|
||||
and code LIKE '%${query.code}'
|
||||
</if>
|
||||
<if test="query.bill_code != null and query.bill_code != ''">
|
||||
and source_form_date = #{query.bill_code}
|
||||
</if>
|
||||
<if test="query.mater != null and query.mater != ''">
|
||||
and md_me_materialbase.material_code like '%${query.mater}%'
|
||||
</if>
|
||||
<if test="query.start_time != null and query.start_time != ''">
|
||||
and pm_form_data.create_time >= #{query.start_time}
|
||||
</if>
|
||||
<if test="query.end_time != null and query.end_time != ''">
|
||||
and #{query.end_time} >= pm_form_data.create_time
|
||||
</if>
|
||||
<if test="query.status != null and query.status != ''">
|
||||
and pm_form_data.status IN
|
||||
<foreach collection="query.status" item="status" separator="," open="(" close=")">
|
||||
#{status}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="query.parent_id != null and query.parent_id != ''">
|
||||
and parent_id = #{query.parent_id}
|
||||
</if>
|
||||
<if test="query.form_query != null and query.form_query.size() > 0">
|
||||
<foreach collection="query.form_query" item="value" index="key">
|
||||
<if test="value != null and value != ''">
|
||||
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
<select id="selectChild" resultMap="dataDetail">
|
||||
select
|
||||
pm_form_data.*,
|
||||
md_me_materialbase.material_code,
|
||||
md_me_materialbase.material_name,
|
||||
md_me_materialbase.material_spec,
|
||||
md_me_materialbase.net_weight
|
||||
from pm_form_data left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
|
||||
where parent_id = #{id}
|
||||
</select>
|
||||
<select id="selectChilds" resultMap="dataDetail">
|
||||
select
|
||||
pm_form_data.*,
|
||||
md_me_materialbase.material_code,
|
||||
md_me_materialbase.material_name,
|
||||
md_me_materialbase.material_spec,
|
||||
md_me_materialbase.net_weight,
|
||||
md_pb_measureunit.unit_name
|
||||
from pm_form_data left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
|
||||
left join md_pb_measureunit on pm_form_data.unit_id = md_pb_measureunit.measure_unit_id
|
||||
where parent_id in
|
||||
<foreach collection="parents" open="(" close=")" item="parent_id" separator=",">
|
||||
#{parent_id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="existFormDataList" resultType="java.lang.String">
|
||||
SELECT id
|
||||
FROM pm_form_data
|
||||
WHERE form_type LIKE CONCAT('%', #{form_type}, '%')
|
||||
</select>
|
||||
<select id="existFormCodeDataList" resultType="java.lang.String">
|
||||
SELECT code
|
||||
FROM pm_form_data
|
||||
WHERE DATE(create_time) = CURDATE()
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -102,7 +102,7 @@ public class PmFormDataDto implements Serializable {
|
||||
/**
|
||||
* 物料单重
|
||||
*/
|
||||
private String single_weight;
|
||||
private String net_weight;
|
||||
/**
|
||||
* 单据编号
|
||||
*/
|
||||
|
||||
@@ -278,7 +278,7 @@ CREATE TABLE `md_base_material` (
|
||||
`material_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL COMMENT '物料名称 ',
|
||||
`material_spec` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '物料规格',
|
||||
`material_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '物料型号',
|
||||
`single_weight` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '单重 / 吨',
|
||||
`net_weight` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '单重 / 吨',
|
||||
`a_long_side` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'A长边',
|
||||
`b_short_side` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'B短边',
|
||||
`h_height` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'H高度',
|
||||
@@ -303,8 +303,8 @@ CREATE TABLE `md_base_material` (
|
||||
`matsize` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL,
|
||||
`standing_time_lower` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`standing_time_upper` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`single_weight_upper` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`single_weight_lower` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`net_weight_upper` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`net_weight_lower` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`standard_size_height1` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`standard_size_height1_lower` decimal(5, 0) NULL DEFAULT NULL,
|
||||
`standard_size_height1_upper` decimal(5, 0) NULL DEFAULT NULL,
|
||||
|
||||
Reference in New Issue
Block a user