24 changed files with 1859 additions and 85 deletions
@ -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; |
||||
|
|
||||
|
|
||||
|
} |
@ -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> |
@ -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; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -1,30 +1,246 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
<?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"> |
<!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"> |
<resultMap id="BaseResultMap" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData"> |
||||
<!-- |
<result property="id" column="id"/> |
||||
WARNING - This element is automatically generated by MyBatis Generator ! |
<result property="code" column="code"/> |
||||
Do not modify this file directly, any changes will be overwritten. |
<result property="proc_inst_id" column="proc_inst_id"/> |
||||
--> |
<result property="source_form_type" column="source_form_type"/> |
||||
<id column="id" property="id" jdbcType="BIGINT"/> |
<result property="source_form_id" column="source_form_id"/> |
||||
<result property="form_id" column="form_id" jdbcType="BIGINT"/> |
<result property="source_form_date" column="source_form_date"/> |
||||
<result property="form_type" column="form_type" jdbcType="VARCHAR"/> |
<result property="form_type" column="form_type"/> |
||||
<result property="status" column="status" jdbcType="VARCHAR"/> |
<result property="status" column="status"/> |
||||
<result property="create_name" column="create_name" jdbcType="VARCHAR"/> |
<result property="create_name" column="create_name"/> |
||||
<result property="create_time" column="create_time" jdbcType="TIMESTAMP"/> |
<result property="create_time" column="create_time"/> |
||||
<result property="material_id" column="material_id" jdbcType="BIGINT"/> |
<result property="material_id" column="material_id"/> |
||||
<result property="qty" column="qty" jdbcType="DECIMAL"/> |
<result property="qty" column="qty"/> |
||||
<result property="pcsn" column="pcsn" jdbcType="VARCHAR"/> |
<result property="pcsn" column="pcsn"/> |
||||
<result property="vehicle_code" column="vehicle_code" jdbcType="VARCHAR"/> |
<result property="vehicle_code" column="vehicle_code"/> |
||||
<result property="parent_id" column="parent_id" jdbcType="BIGINT"/> |
<result property="parent_id" column="parent_id"/> |
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/> |
<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="unit_id" column="unit_id"/> |
||||
</resultMap> |
</resultMap> |
||||
<resultMap id="ResultMapWithBLOBs" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData" extends="BaseResultMap"> |
|
||||
<!-- |
<resultMap id="dataDetail" type="org.nl.wms.pm_manage.form_data.service.dto.PmFormDataDto" > |
||||
WARNING - This element is automatically generated by MyBatis Generator ! |
<result property="id" column="id"/> |
||||
Do not modify this file directly, any changes will be overwritten. |
<result property="code" column="code"/> |
||||
--> |
<result property="proc_inst_id" column="proc_inst_id"/> |
||||
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/> |
<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> |
</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> |
</mapper> |
||||
|
Loading…
Reference in new issue