package com.chinaztt.mes.aps.core.domain; import com.chinaztt.mes.aps.core.helper.Constants; import com.chinaztt.mes.aps.core.solver.StartTimeUpdatingVariableListener; import com.chinaztt.mes.aps.core.solver.TaskDifficultyComparator; import com.chinaztt.mes.aps.entity.ResourceDuration; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.optaplanner.core.api.domain.entity.PlanningEntity; import org.optaplanner.core.api.domain.variable.*; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Optional; import java.util.Set; /** * @Author: zhangxy * @Date: 2020-10-19 19:42 */ @PlanningEntity(difficultyComparatorClass = TaskDifficultyComparator.class) @Data public class Task extends AbstractTaskOrResource { /** * id 可能为空 */ private Long id; private Long orderId; private Long routingId; private Long routingOperationId; private int orderPriority; private int operationPriority; private String opNo; private String name; private BigDecimal quantity; private Long partId; private Set capabilityIds; @JsonIgnore private Task successorOfRouting; @JsonIgnore private Task predecessorOfRouting; @CustomShadowVariable(variableListenerClass = StartTimeUpdatingVariableListener.class, sources = {@PlanningVariableReference(variableName = "previousTaskOrResource"),}) private LocalDateTime planStartTime; @JsonIgnore @PlanningVariable(valueRangeProviderRefs = {"resourceRange", "taskRange"}, graphType = PlanningVariableGraphType.CHAINED) private AbstractTaskOrResource previousTaskOrResource; @AnchorShadowVariable(sourceVariableName = "previousTaskOrResource") private ResourceBo resourceBo; @Override public LocalDateTime getPlanEndTime() { if (this.planStartTime == null || this.getResourceBo() == null || this.getResourceBo().getDurations() == null) { return LocalDateTime.now(); } Optional opt = this.getResourceBo().getDurations().stream().filter(d -> d.getPartId().equals(this.getPartId())).findFirst(); if (opt.isPresent()) { return this.planStartTime.plusMinutes(calculateCostTime(quantity, opt.get())); } return this.planStartTime; } /** * 计算task耗用时间,单位分钟 * @param quantity * @param rd * @return */ private long calculateCostTime(BigDecimal quantity, ResourceDuration rd) { long cost = 0L; if (Constants.UNIT_PER_MIN.equals(rd.getProductionRateUnit())) { //单位数/分钟 cost += rd.getSetupTime().longValue(); cost += quantity.divide(rd.getProductionRate(), 0, BigDecimal.ROUND_UP).longValue(); cost += rd.getPostProcessing().longValue(); } else if (Constants.MIN_PER_UNIT.equals(rd.getProductionRateUnit())) { //分钟数/单位 cost += rd.getSetupTime().longValue(); cost += quantity.multiply(rd.getProductionRate()).intValue(); cost += rd.getPostProcessing().longValue(); } return cost; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Task task = (Task) o; if (orderPriority != task.orderPriority) { return false; } if (operationPriority != task.operationPriority) { return false; } if (!orderId.equals(task.orderId)) { return false; } if (!routingOperationId.equals(task.routingOperationId)) { return false; } if (!quantity.equals(task.quantity)) { return false; } return partId.equals(task.partId); } @Override public int hashCode() { int result = orderId.hashCode(); result = 31 * result + routingOperationId.hashCode(); result = 31 * result + orderPriority; result = 31 * result + operationPriority; result = 31 * result + quantity.hashCode(); result = 31 * result + partId.hashCode(); return result; } @Override public String toString() { return "Task{" + "operationPriority=" + operationPriority + ", name='" + name + '\'' + ", quantity=" + quantity + ", capabilityIds=" + capabilityIds + ", planStartTime=" + planStartTime + '}'; } }