|
@@ -0,0 +1,643 @@
|
|
|
+package com.rongwei.rwapsserver.aps.taskassigning.tado;
|
|
|
+
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.ApsNochangeRollerDo;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.EquipmentRunTime;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.ProduceOrder;
|
|
|
+import com.rongwei.rwapsserver.aps.vo.ApsTypeVo;
|
|
|
+import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
|
|
|
+import org.optaplanner.core.api.score.stream.Constraint;
|
|
|
+import org.optaplanner.core.api.score.stream.ConstraintFactory;
|
|
|
+import org.optaplanner.core.api.score.stream.ConstraintProvider;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.Duration;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+public class ApsConstraintListThProvider implements ConstraintProvider {
|
|
|
+
|
|
|
+ private ZoneId zoneId = ZoneId.systemDefault();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
|
|
|
+
|
|
|
+ return new Constraint[]{
|
|
|
+ theEquipmentCanOnlyProcessOneProcessAtTheSameTime(constraintFactory),
|
|
|
+ optionalEquipment(constraintFactory),
|
|
|
+ // HARD
|
|
|
+ hasOnePreGbAfterNowNew(constraintFactory),
|
|
|
+// nextLockProNew(constraintFactory),
|
|
|
+// eqTimeCross(constraintFactory),
|
|
|
+// seriesProduceTimeWait(constraintFactory),
|
|
|
+// seriesProduceWashTimeWait(constraintFactory),
|
|
|
+// equipmentRunTime(constraintFactory),
|
|
|
+// eqTimeCrossTuihuo(constraintFactory),
|
|
|
+// eqTimeCrossTuihuoType(constraintFactory),
|
|
|
+// eqTimeCrossMinTuihuo(constraintFactory),
|
|
|
+// maxStartTime(constraintFactory),
|
|
|
+ // MEDIUM
|
|
|
+ deliveryDate(constraintFactory),
|
|
|
+// expecteddays(constraintFactory),
|
|
|
+ freeTimeEquipment(constraintFactory),
|
|
|
+// seriesProduceWashingFurnace(constraintFactory),
|
|
|
+ mergeTuihuo(constraintFactory),
|
|
|
+// tuihuoSp(constraintFactory),
|
|
|
+// sameEquipment(constraintFactory),
|
|
|
+// seriesZzLb(constraintFactory),
|
|
|
+//
|
|
|
+// preNextProcessSameWorkShop(constraintFactory),
|
|
|
+ // SOFT
|
|
|
+ processNear(constraintFactory),
|
|
|
+// lzbzSp(constraintFactory),
|
|
|
+// eqTimeCrossMinTuihuoSoft(constraintFactory),
|
|
|
+// preNextProcessSameEq(constraintFactory),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备生产的任务都在可选设备范围内
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint optionalEquipment(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(EquipmentTa.class)
|
|
|
+ .filter((equipment) -> {
|
|
|
+ return true;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(equipment) -> {
|
|
|
+ int b = 0;
|
|
|
+ List<ProductionProcessesTa> tasks = equipment.getTasks();
|
|
|
+ if(tasks != null && tasks.size()>0){
|
|
|
+ for (ProductionProcessesTa task : tasks) {
|
|
|
+ if(!task.getOptionalEquipments().contains(equipment.getId())){
|
|
|
+ b++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return b*100;
|
|
|
+ })
|
|
|
+ .asConstraint("optionalEquipment");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 每个任务都要分配资源
|
|
|
+ * @param factory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Constraint theEquipmentCanOnlyProcessOneProcessAtTheSameTime(ConstraintFactory factory) {
|
|
|
+ return factory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(job -> job.getEquipment() == null || job.getStartTime() == null || job.getEndTime() == null)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(productionProcesses) -> 100)
|
|
|
+ .asConstraint("theEquipmentCanOnlyProcessOneProcessAtTheSameTime");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单卷模式下前后道工序时间约束(新的等待时间调整)
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint hasOnePreGbAfterNowNew(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ boolean bln = false;
|
|
|
+ if(productionProcesses.getEquipment() != null && productionProcesses.getPreviousProcesses() != null && productionProcesses.getPreviousProcesses().size()>0){
|
|
|
+ // 此种情况简化为前道工序只有一个
|
|
|
+ for (ProductionProcessesTa previousProcess : productionProcesses.getPreviousProcesses()) {
|
|
|
+ ProductionProcessesTa preProcess = previousProcess;
|
|
|
+ // 流转时间(最小等待时间)
|
|
|
+ Integer lzTimes = 0;
|
|
|
+ if(preProcess.getEquipment() != null){
|
|
|
+ if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(productionProcesses.getEquipment().getWorkshopid())){
|
|
|
+ lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
|
|
|
+ }else{
|
|
|
+ lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
|
|
|
+ }
|
|
|
+ // 最小等待时间对比流转时间
|
|
|
+ if(productionProcesses.getMinWaitTime() != null && lzTimes<productionProcesses.getMinWaitTime()){
|
|
|
+ lzTimes = productionProcesses.getMinWaitTime();
|
|
|
+ }
|
|
|
+ // 最大等待时间
|
|
|
+ Integer maxWaitTime = productionProcesses.getMaxWaitTime();
|
|
|
+ if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(lzTimes))<0){
|
|
|
+ bln = true;
|
|
|
+ }
|
|
|
+ if(maxWaitTime != null && maxWaitTime>0){
|
|
|
+ if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(maxWaitTime))>0){
|
|
|
+ bln = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bln;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(productionProcesses) -> 40)
|
|
|
+ .asConstraint("hasOnePreGbAfterNow");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 递归计算是否比所有下道工序开始时间晚
|
|
|
+ * @param productionProcesses
|
|
|
+ * @param nextStartTimes
|
|
|
+ * @param totalMinWaitTime
|
|
|
+ */
|
|
|
+ private void getAllNextProTime(ProductionProcessesTa productionProcesses, List<LocalDateTime> nextStartTimes, Integer totalMinWaitTime){
|
|
|
+ List<ProductionProcessesTa> nextProcesses = productionProcesses.getNextProcesses();
|
|
|
+ if(nextProcesses != null && nextProcesses.size()>0){
|
|
|
+ Integer nowTotalMinWaitTime = totalMinWaitTime;
|
|
|
+ for (ProductionProcessesTa nextProcess : nextProcesses) {
|
|
|
+ if(nextProcess.getStartTime() != null){
|
|
|
+ LocalDateTime startTime = nextProcess.getStartTime();
|
|
|
+ if(nextProcess.getMinWaitTime() != null && nextProcess.getMinWaitTime()>0){
|
|
|
+ nowTotalMinWaitTime = totalMinWaitTime + nextProcess.getMinWaitTime();
|
|
|
+ startTime = startTime.minusMinutes(nowTotalMinWaitTime);
|
|
|
+ }
|
|
|
+ nextStartTimes.add(startTime);
|
|
|
+ }
|
|
|
+ getAllNextProTime(nextProcess,nextStartTimes,nowTotalMinWaitTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备运行时间段,不可再排产
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint equipmentRunTime(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(pro->{
|
|
|
+ return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退") && !pro.getProcessType().equals("小卷成退");
|
|
|
+ })
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ if(productionProcesses.getEquipment().getId().equals("0001be252874536843730b100024")){
|
|
|
+ int abc = 1;
|
|
|
+ if(productionProcesses.getDelay() == 270){
|
|
|
+ int abcd = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ boolean bol = false;
|
|
|
+ if(productionProcesses.getEquipment() != null && productionProcesses.getEquipment().getEquipmentRunTimes() != null &&
|
|
|
+ productionProcesses.getEquipment().getEquipmentRunTimes().size()>0
|
|
|
+ && productionProcesses.getStartTime() != null && productionProcesses.getEndTime() != null){
|
|
|
+ for (EquipmentRunTime equipmentRunTime : productionProcesses.getEquipment().getEquipmentRunTimes()) {
|
|
|
+ LocalDateTime startTime = equipmentRunTime.getStartRunTime();
|
|
|
+ LocalDateTime endRunTime = equipmentRunTime.getEndRunTime();
|
|
|
+ if(equipmentRunTime.getStartRunTime() != null && equipmentRunTime.getEndRunTime() != null){
|
|
|
+ if(productionProcesses.getStartTime().compareTo(endRunTime)>=0 || productionProcesses.getEndTime().compareTo(startTime)<=0){
|
|
|
+ continue;
|
|
|
+ }else{
|
|
|
+ bol = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(startTime != null && endRunTime == null){
|
|
|
+ if(productionProcesses.getEndTime().compareTo(startTime)>0){
|
|
|
+ bol = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bol;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(proc1)->80)
|
|
|
+ .asConstraint("equipmentRunTime");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 软约束:交货日期,根据延迟交货日期的天数来做惩罚分数计算
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint deliveryDate(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ /*
|
|
|
+ 获取最后一步工步的结束时间(最后一步工步的结束时间即此产品生产的实际结束时间)
|
|
|
+ 并且获取结束时间大于生产订单的交货日期
|
|
|
+ */
|
|
|
+ if(productionProcesses.getEndTime() == null || productionProcesses.getStartTime() == null || productionProcesses.getEquipment() == null){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 取最小订单交货日期
|
|
|
+ Date deliveryMinDate = null;
|
|
|
+ for (ProduceOrder produceOrder : productionProcesses.getProduceOrder()) {
|
|
|
+ if(deliveryMinDate == null){
|
|
|
+ deliveryMinDate = produceOrder.getDeliveryDate();
|
|
|
+ }else{
|
|
|
+ if(deliveryMinDate.compareTo(produceOrder.getDeliveryDate())>0){
|
|
|
+ deliveryMinDate = produceOrder.getDeliveryDate();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(deliveryMinDate == null){
|
|
|
+ return false;
|
|
|
+ }else{
|
|
|
+ if(productionProcesses.getApsOverallConfig().getStartTime().atZone(zoneId).toInstant().toEpochMilli()>deliveryMinDate.getTime()){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Boolean bol = productionProcesses.getEndTime().atZone(zoneId).toInstant().toEpochMilli()>deliveryMinDate.getTime();
|
|
|
+ return bol;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(productionProcesses) ->{
|
|
|
+ /*Date deliveryMinDate = null;
|
|
|
+ for (ProduceOrder produceOrder : productionProcesses.getProduceOrder()) {
|
|
|
+ if(deliveryMinDate == null){
|
|
|
+ deliveryMinDate = produceOrder.getDeliveryDate();
|
|
|
+ }else{
|
|
|
+ if(deliveryMinDate.compareTo(produceOrder.getDeliveryDate())>0){
|
|
|
+ deliveryMinDate = produceOrder.getDeliveryDate();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int i = (int) (DateUtil.between(deliveryMinDate, Date.from(productionProcesses.getEndTime().atZone(zoneId).toInstant()), DateUnit.MINUTE) + 1) * 10;
|
|
|
+ if(i<0){
|
|
|
+ int aa = 0;
|
|
|
+ }
|
|
|
+ return i;*/
|
|
|
+ return 1000;
|
|
|
+ })
|
|
|
+ .asConstraint("deliveryDate");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 软约束:交货日期,根据延迟交货日期的天数来做惩罚分数计算
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint expecteddays(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+// .filter(productionProcesses -> productionProcesses.getNextProcesses() == null || productionProcesses.getNextProcesses().size() == 0)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ // 非最后一道工序或者最后一道工序没有排程时间的工序直接跳过
|
|
|
+ if(productionProcesses.getEndTime() == null){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Long expecteddays = expecteddaysCount(productionProcesses);
|
|
|
+ if(expecteddays>0){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(productionProcesses) ->{
|
|
|
+ Long expecteddays = expecteddaysCount(productionProcesses);
|
|
|
+ return (int)(expecteddays*10000);
|
|
|
+ })
|
|
|
+ .asConstraint("expecteddays");
|
|
|
+ }
|
|
|
+
|
|
|
+ private Long expecteddaysCount(ProductionProcessesTa productionProcesses){
|
|
|
+ // 取最小订单交货天数
|
|
|
+ Integer deliveryMinDate = null;
|
|
|
+ for (ProduceOrder produceOrder : productionProcesses.getProduceOrder()) {
|
|
|
+ if(deliveryMinDate == null){
|
|
|
+ deliveryMinDate = produceOrder.getExpecteddays();
|
|
|
+ }else{
|
|
|
+ if(produceOrder.getExpecteddays() != null && produceOrder.getExpecteddays()<deliveryMinDate){
|
|
|
+ deliveryMinDate = produceOrder.getExpecteddays();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(deliveryMinDate == null){
|
|
|
+ deliveryMinDate = 15;
|
|
|
+ }
|
|
|
+ // 有铸轧的工序取铸轧后第一道工序开始时间,没有铸轧的直接取第一道工序开始时间
|
|
|
+ LocalDateTime startTime = null;
|
|
|
+ ProductionProcessesTa rooprocess = productionProcesses.getRooprocess();
|
|
|
+ if(rooprocess != null){
|
|
|
+ if("铸轧".equals(rooprocess.getProcessType())){
|
|
|
+ if("成退".equals(rooprocess.getNextProcesses().get(0).getProcessType()) || "中退".equals(rooprocess.getNextProcesses().get(0).getProcessType())
|
|
|
+ || "小卷成退".equals(rooprocess.getNextProcesses().get(0).getProcessType())){
|
|
|
+ startTime = null;
|
|
|
+ }else{
|
|
|
+ startTime = rooprocess.getNextProcesses().get(0).getStartTime();
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if ("成退".equals(rooprocess.getProcessType()) || "中退".equals(rooprocess.getProcessType()) || "小卷成退".equals(rooprocess.getProcessType())){
|
|
|
+ if(rooprocess.getNextProcesses() != null && rooprocess.getNextProcesses().size()>0){
|
|
|
+ startTime = rooprocess.getNextProcesses().get(0).getStartTime();
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ startTime = rooprocess.getStartTime();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ return 0L;
|
|
|
+ }
|
|
|
+ if(startTime == null){
|
|
|
+ return 0L;
|
|
|
+ }
|
|
|
+ long daysBetween = ChronoUnit.DAYS.between(startTime, productionProcesses.getEndTime());
|
|
|
+ return daysBetween-deliveryMinDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备生产的任务都在可选设备范围内
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint freeTimeEquipment(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(EquipmentTa.class)
|
|
|
+ .filter((equipment) -> {
|
|
|
+ return true;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipment) -> {
|
|
|
+ int b = 0;
|
|
|
+ List<ProductionProcessesTa> tasks = new ArrayList<>();
|
|
|
+
|
|
|
+ if(equipment.getTasks() != null && equipment.getTasks().size()>0){
|
|
|
+ if(equipment.getLastProcessEndTime() != null){
|
|
|
+ ProductionProcessesTa pta = new ProductionProcessesTa();
|
|
|
+ LocalDateTime eqlastTime = equipment.getLastProcessEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
|
|
+ LocalDateTime startTime = equipment.getTasks().get(0).getApsOverallConfig().getStartTime();
|
|
|
+ if(startTime.compareTo(eqlastTime)>0){
|
|
|
+ pta.setStartTime(startTime.plusMinutes(-10));
|
|
|
+ pta.setEndTime(startTime);
|
|
|
+ }else{
|
|
|
+ pta.setStartTime(eqlastTime.plusMinutes(-10));
|
|
|
+ pta.setEndTime(eqlastTime);
|
|
|
+ }
|
|
|
+ tasks.add(pta);
|
|
|
+ }else{
|
|
|
+ if(equipment.getEquipmentRunTimes() != null && equipment.getEquipmentRunTimes().size()>0){
|
|
|
+ for (EquipmentRunTime equipmentRunTime : equipment.getEquipmentRunTimes()) {
|
|
|
+ ProductionProcessesTa pta = new ProductionProcessesTa();
|
|
|
+ pta.setStartTime(equipmentRunTime.getStartRunTime());
|
|
|
+ pta.setEndTime(equipmentRunTime.getEndRunTime());
|
|
|
+ tasks.add(pta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tasks.addAll(equipment.getTasks());
|
|
|
+
|
|
|
+ // 根据开始时间排序
|
|
|
+ if(tasks.size()>1){
|
|
|
+ Collections.sort(tasks, Comparator.comparing(ProductionProcessesTa::getStartTime));
|
|
|
+ for (int i = 0; i < tasks.size()-1; i++) {
|
|
|
+ ProductionProcessesTa preTask = tasks.get(i);
|
|
|
+ ProductionProcessesTa nextTask = tasks.get(i + 1);
|
|
|
+ if(preTask.getEndTime().plusMinutes(60).compareTo(nextTask.getStartTime())<0){
|
|
|
+ b = b + 100;
|
|
|
+ // 上道工序结束时间和下道开始时间的分钟差,再减去1小时
|
|
|
+ long durationInMinutes = Duration.between(preTask.getEndTime(), nextTask.getStartTime()).toMinutes()-60;
|
|
|
+ if(durationInMinutes>0){
|
|
|
+ long hs = durationInMinutes / 60;
|
|
|
+ long hsm = durationInMinutes % 60;
|
|
|
+ if(hsm>0){
|
|
|
+ hs = hs + 1;
|
|
|
+ }
|
|
|
+ b = (int) (b + hs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return b;
|
|
|
+ })
|
|
|
+ .asConstraint("freeTimeEquipment");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 铸轧判断合金产品类型是否兼容
|
|
|
+ * @param beforePro
|
|
|
+ * @param afterPro
|
|
|
+ * @param apsNochangeRollerDos
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean zzSeriesJr(ProductionProcessesTa beforePro, ProductionProcessesTa afterPro, List<ApsNochangeRollerDo> apsNochangeRollerDos){
|
|
|
+ boolean ifJr = false;
|
|
|
+ String[] serspre = beforePro.getSeriesProduceMark().split("\\^_\\^");
|
|
|
+ String[] sersafter = afterPro.getSeriesProduceMark().split("\\^_\\^");
|
|
|
+ if(serspre.length == 5 && sersafter.length == 5){
|
|
|
+ // 合金和产品类型
|
|
|
+ // 前一道作业合金、产品类型
|
|
|
+ String bfhj = serspre[0];
|
|
|
+ // 获取产品类型二级
|
|
|
+ String bfcplx = serspre[1].split("-")[0];
|
|
|
+ // 后一道作业合金、产品类型
|
|
|
+ String afhj = sersafter[0];
|
|
|
+ // 获取产品类型二级
|
|
|
+ String afcplx = sersafter[1].split("-")[0];
|
|
|
+ // 合金和二级产品类型一样的无需换辊
|
|
|
+ if(bfhj.equals(afhj) && bfcplx.equals(afcplx)){
|
|
|
+ ifJr = true;
|
|
|
+ }else{
|
|
|
+ // 铸轧合金兼容配置
|
|
|
+ if(apsNochangeRollerDos != null && apsNochangeRollerDos.size()>0){
|
|
|
+ for (ApsNochangeRollerDo apsNochangeRollerDo : apsNochangeRollerDos) {
|
|
|
+ // 判断合金是否都包含,且相同
|
|
|
+ if(bfhj.equals(afhj)){
|
|
|
+ if(StrUtil.isNotBlank(apsNochangeRollerDo.getWorkingalloy())){
|
|
|
+ if(apsNochangeRollerDo.getWorkingalloy().contains(bfhj) && apsNochangeRollerDo.getWorkingalloy().contains(afhj)){
|
|
|
+ // 判断产品类型是包含还是不包含的关系
|
|
|
+ if("包含".equals(apsNochangeRollerDo.getCompatibilityrules())){
|
|
|
+ // 产品类型不为空
|
|
|
+ if(StrUtil.isNotBlank(apsNochangeRollerDo.getJobproducttype())){
|
|
|
+ if(apsNochangeRollerDo.getJobproducttype().contains(bfcplx) && apsNochangeRollerDo.getJobproducttype().contains(afcplx)){
|
|
|
+ ifJr = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 产品类型为空
|
|
|
+ else{
|
|
|
+ ifJr = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if ("不包含".equals(apsNochangeRollerDo.getCompatibilityrules())) {
|
|
|
+ // 产品类型不为空
|
|
|
+ if(StrUtil.isNotBlank(apsNochangeRollerDo.getJobproducttype())){
|
|
|
+ if(!apsNochangeRollerDo.getJobproducttype().contains(bfcplx) && !apsNochangeRollerDo.getJobproducttype().contains(afcplx)){
|
|
|
+ ifJr = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 产品类型为空
|
|
|
+ else{
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ifJr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 排程时间尽量靠前
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint processNear(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter((process)->{
|
|
|
+ if(process.getPreviousProcesses() == null || process.getPreviousProcesses().size() == 0){
|
|
|
+ if(process.getStartTime() == null || process.getApsOverallConfig().getStartTime() == null){
|
|
|
+ int ma = 0;
|
|
|
+ }
|
|
|
+ if(process.getStartTime() != null && process.getStartTime().compareTo(process.getApsOverallConfig().getStartTime())>0){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(process.getStartTime() != null){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_SOFT,(process) -> {
|
|
|
+ int processNearNum = 0;
|
|
|
+ processNearNum = (int)ChronoUnit.MINUTES.between(process.getApsOverallConfig().getStartTime(), process.getStartTime());
|
|
|
+ if(processNearNum<=0){
|
|
|
+ processNearNum = 0;
|
|
|
+ }
|
|
|
+ return processNearNum;
|
|
|
+ })
|
|
|
+ .asConstraint("processNear");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 前后工序可以在一个设备上的尽量在一个设备上
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint preNextProcessSameEq(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(pro->{
|
|
|
+ boolean a = false;
|
|
|
+ if(pro.getPreviousProcesses() != null && pro.getPreviousProcesses().size()>0){
|
|
|
+ a = true;
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_SOFT,(processes)->{
|
|
|
+ int a = 0;
|
|
|
+ EquipmentTa equipmentthis = processes.getEquipment();
|
|
|
+ EquipmentTa equipmentpre = processes.getPreviousProcesses().get(0).getEquipment();
|
|
|
+ if(!equipmentpre.getId().equals(equipmentthis.getId())){
|
|
|
+ a = a + 10000;
|
|
|
+ }
|
|
|
+ /*if(!equipmentpre.getWorkshopid().equals(equipmentthis.getWorkshopid())){
|
|
|
+ a = a + 10000;
|
|
|
+ }*/
|
|
|
+ return a;
|
|
|
+ })
|
|
|
+ .asConstraint("preNextProcessSameEq");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 前后工序可以在一个设备上的尽量在一个设备上
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint preNextProcessSameWorkShop(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcessesTa.class)
|
|
|
+ .filter(pro->{
|
|
|
+ boolean a = false;
|
|
|
+ if(pro.getPreviousProcesses() != null && pro.getPreviousProcesses().size()>0){
|
|
|
+ a = true;
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(processes)->{
|
|
|
+ int a = 0;
|
|
|
+ EquipmentTa equipmentthis = processes.getEquipment();
|
|
|
+ EquipmentTa equipmentpre = processes.getPreviousProcesses().get(0).getEquipment();
|
|
|
+ if(!equipmentpre.getWorkshopid().equals(equipmentthis.getWorkshopid())){
|
|
|
+ a = a + 5000;
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+ })
|
|
|
+ .asConstraint("preNextProcessSameWorkShop");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退火工序组炉规则
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Constraint mergeTuihuo(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(EquipmentTa.class)
|
|
|
+ .filter(equipmentTa->{
|
|
|
+ boolean a = false;
|
|
|
+ List<ProductionProcessesTa> tasks = equipmentTa.getTasks();
|
|
|
+ if(!tasks.isEmpty()){
|
|
|
+ if("成退,中退,小卷成退".contains(tasks.get(0).getProcessType())){
|
|
|
+ a = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentTa)->{
|
|
|
+ // 已占用的
|
|
|
+ List<EquipmentRunTime> equipmentRunTimes = equipmentTa.getEquipmentRunTimes();
|
|
|
+ // 同一工序的优先组炉
|
|
|
+ List<ProductionProcessesTa> ths = new ArrayList<>();
|
|
|
+ equipmentTa.getTasks().forEach(v->{
|
|
|
+ ths.add(v);
|
|
|
+ });
|
|
|
+ // 退火合并工序
|
|
|
+ Map<String,List<ProductionProcessesTa>> ppMap = new HashMap<>();
|
|
|
+ if(ths.size()>0){
|
|
|
+ for(int i=0;i<ths.size();i++){
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String startTimeKey = ths.get(i).getStartTime().format(formatter)+ths.get(i).getEquipmentId();
|
|
|
+ if(ppMap.containsKey(startTimeKey)){
|
|
|
+ ppMap.get(startTimeKey).add(ths.get(i));
|
|
|
+ }else{
|
|
|
+ List<ProductionProcessesTa> ps = new ArrayList<>();
|
|
|
+ ps.add(ths.get(i));
|
|
|
+ ppMap.put(startTimeKey,ps);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> hasMergeOldKeys = new ArrayList<>();
|
|
|
+ ppMap.forEach((k,v)->{
|
|
|
+ if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
|
|
|
+ for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
|
|
|
+ if(equipmentRunTime.getStartRunTime().compareTo(v.get(0).getStartTime()) == 0){
|
|
|
+ hasMergeOldKeys.add(k);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+// }
|
|
|
+// }
|
|
|
+ });
|
|
|
+ if(hasMergeOldKeys != null && hasMergeOldKeys.size()>0){
|
|
|
+ for (String hasMergeOldKey : hasMergeOldKeys) {
|
|
|
+ ppMap.remove(hasMergeOldKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int qz = 1;
|
|
|
+ ApsTypeVo scheduleType = equipmentTa.getTasks().get(0).getApsOverallConfig().getScheduleType();
|
|
|
+ if(scheduleType == null || scheduleType.getConstraintMode() == null || "th".equals(scheduleType.getConstraintMode())){
|
|
|
+ qz = 1100;
|
|
|
+ }
|
|
|
+ int zzdf = ppMap.size()*qz;
|
|
|
+ if(hasMergeOldKeys != null && hasMergeOldKeys.size()>0){
|
|
|
+ zzdf = zzdf + hasMergeOldKeys.size();
|
|
|
+ }
|
|
|
+ return zzdf;
|
|
|
+ })
|
|
|
+ .asConstraint("mergeTuihuo");
|
|
|
+ }
|
|
|
+
|
|
|
+}
|