package com.chinaztt.mes.aps.core;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.chinaztt.mes.aps.core.domain.*;
|
import com.chinaztt.mes.aps.core.helper.ResourceHelper;
|
import com.chinaztt.mes.aps.dto.OrderDTO;
|
import com.chinaztt.mes.aps.entity.SceneTask;
|
import com.chinaztt.mes.aps.service.*;
|
import com.chinaztt.mes.plan.entity.ManufacturingOrder;
|
import com.chinaztt.mes.plan.service.ManufacturingOrderService;
|
import com.chinaztt.mes.technology.dto.RefDTO;
|
import com.chinaztt.mes.technology.dto.RoutingDTO;
|
import com.chinaztt.mes.technology.dto.RoutingOperationDTO;
|
import com.chinaztt.mes.technology.service.RoutingService;
|
import com.chinaztt.ztt.common.core.util.R;
|
import lombok.AllArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.optaplanner.core.api.score.Score;
|
import org.optaplanner.core.api.score.ScoreManager;
|
import org.optaplanner.core.api.solver.SolverFactory;
|
import org.optaplanner.core.api.solver.SolverJob;
|
import org.optaplanner.core.api.solver.SolverManager;
|
import org.optaplanner.core.impl.score.director.ScoreDirector;
|
import org.optaplanner.core.impl.score.director.ScoreDirectorFactory;
|
import org.springframework.stereotype.Component;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.Duration;
|
import java.time.LocalDateTime;
|
import java.util.*;
|
import java.util.concurrent.ExecutionException;
|
import java.util.stream.Collectors;
|
|
/**
|
* 排产核心类
|
*
|
* @Author: zhangxy
|
* @Date: 2020-09-23 11:00
|
*/
|
@AllArgsConstructor
|
@Component
|
@Slf4j
|
public class ApsMain {
|
|
private ResourceHelper resourceHelper;
|
private RoutingService routingService;
|
private ApsCoreService apsCoreService;
|
private ManufacturingOrderService manufacturingOrderService;
|
private SolverManager<ApsSolution, UUID> solverManager;
|
private SolverFactory solverFactory;
|
|
private ScoreManager scoreManager;
|
|
public static void main(String[] arg) {
|
|
LocalDateTime a = LocalDateTime.now();
|
|
LocalDateTime b = a.plusDays(1);
|
|
Duration d = Duration.between(b, a);
|
System.out.println(d.toMinutes());
|
|
|
}
|
|
|
/**
|
* 运行排产,传入待排产订单集合
|
* !!!计算的时间单位都是分钟!!!
|
*
|
* @param dtoList
|
* @return
|
*/
|
public R<Boolean> run(OrderDTO[] dtoList, Long sceneId) {
|
List<Order> orders = buildOrderList(dtoList);
|
if (CollectionUtil.isEmpty(orders)) {
|
return R.failed("请选择待排产订单");
|
}
|
UUID problemId = UUID.randomUUID();
|
SolverJob<ApsSolution, UUID> solverJob = solverManager.solve(problemId, generateProblem(orders, sceneId));
|
ApsSolution solution;
|
try {
|
solution = solverJob.getFinalBestSolution();
|
saveSceneTask(solution.getTaskList(), sceneId);
|
System.out.println(JSON.toJSONString(solution));
|
} catch (InterruptedException | ExecutionException e) {
|
throw new IllegalStateException("Solving failed.", e);
|
}
|
|
return R.ok();
|
}
|
|
|
private List<Order> buildOrderList(OrderDTO[] dtoList) {
|
if (dtoList == null || dtoList.length == 0) {
|
return null;
|
}
|
List<Order> orders = new ArrayList<>();
|
for (OrderDTO dto : dtoList) {
|
ManufacturingOrder mo = manufacturingOrderService.getById(dto.getId());
|
Order order = new Order();
|
order.setPriority(dto.getPriority());
|
order.setId(mo.getId());
|
order.setPartId(mo.getPartId());
|
order.setQuantity(mo.getQtyRequired());
|
order.setRouting(routingService.getRoutingById(mo.getTechnologyRoutingId()));
|
orders.add(order);
|
}
|
|
return orders;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
protected void saveSceneTask(List<Task> taskList, Long sceneId) {
|
if (CollectionUtil.isNotEmpty(taskList)) {
|
for (Task task : taskList) {
|
SceneTask sceneTask = new SceneTask();
|
sceneTask.setSceneId(sceneId);
|
sceneTask.setStartTime(task.getPlanStartTime());
|
sceneTask.setEndTime(task.getPlanEndTime());
|
sceneTask.setResourceId(task.getResourceBo().getId());
|
sceneTask.setOrderId(task.getOrderId());
|
sceneTask.setRoutingOperationId(task.getRoutingOperationId());
|
sceneTask.setRoutingId(task.getRoutingId());
|
sceneTask.setQuantity(task.getQuantity());
|
sceneTask.setPartId(task.getPartId());
|
apsCoreService.saveSceneTask(sceneTask);
|
}
|
}
|
}
|
|
|
/**
|
* 构造问题,传给求解引擎
|
* @param orders
|
* @param sceneId
|
* @return
|
*/
|
private ApsSolution generateProblem(List<Order> orders, Long sceneId) {
|
List<Task> tasks = new ArrayList<>();
|
//按照零件分组
|
Map<Long, List<Order>> partOrderMap = orders.stream().collect(Collectors.groupingBy(Order::getPartId));
|
partOrderMap.forEach((k, v) -> {
|
List<Order> mergedOrders = merge(v);
|
for (Order order : mergedOrders) {
|
buildTaskVariable(tasks, order);
|
}
|
});
|
|
ApsSolution problem = new ApsSolution();
|
problem.setResourceBoList(resourceHelper.buildResourceVariable(sceneId));
|
problem.setTaskList(tasks);
|
return problem;
|
}
|
|
|
private void buildTaskVariable(List tasks, Order order) {
|
int i = 1;
|
RoutingOperationDTO first = first(order.getRouting());
|
Task task = new Task();
|
task.setQuantity(order.getQuantity());
|
task.setOrderPriority(order.getPriority());
|
task.setOperationPriority(i++);
|
task.setOpNo(first.getOperationNo());
|
task.setOrderId(order.getId());
|
task.setRoutingId(order.getRouting().getId());
|
task.setRoutingOperationId(first.getId());
|
task.setName(first.getOperationName());
|
task.setCapabilityIds(getOpCapIds(first.getOperationId()));
|
task.setPartId(order.getPartId());
|
task.setSuccessorOfRouting(repeatOperation(task, order, first.getId(), tasks, i));
|
tasks.add(task);
|
}
|
|
|
private Task repeatOperation(Task pre, Order order, Long fromId, List<Task> list, int i) {
|
RoutingOperationDTO dto = next(order.getRouting(), fromId);
|
if (dto != null) {
|
Task task = new Task();
|
task.setQuantity(order.getQuantity());
|
task.setOrderPriority(order.getPriority());
|
task.setOperationPriority(i++);
|
task.setPartId(order.getPartId());
|
task.setOpNo(dto.getOperationNo());
|
task.setOrderId(order.getId());
|
task.setRoutingId(order.getRouting().getId());
|
task.setRoutingOperationId(dto.getId());
|
task.setName(dto.getOperationName());
|
task.setCapabilityIds(getOpCapIds(dto.getOperationId()));
|
task.setPredecessorOfRouting(pre);
|
task.setSuccessorOfRouting(repeatOperation(task, order, dto.getId(), list, i));
|
list.add(task);
|
return task;
|
}
|
return null;
|
}
|
|
|
private Set<Long> getOpCapIds(Long opId) {
|
OperationBo operation = apsCoreService.queryOperation(opId);
|
return operation.getCapabilityIds();
|
}
|
|
|
/**
|
* 合并订单
|
*
|
* @param orders
|
* @return
|
*/
|
private List<Order> merge(List<Order> orders) {
|
//todo 同一零件是否合并生产
|
return orders;
|
}
|
|
|
/**
|
* 工艺的首道工序
|
*
|
* @param routing
|
* @return
|
*/
|
public RoutingOperationDTO first(RoutingDTO routing) {
|
return next(routing, null);
|
}
|
|
/**
|
* 下道工序,fromId传null时找的是首道
|
*
|
* @param routing
|
* @param fromId
|
* @return
|
*/
|
public RoutingOperationDTO next(RoutingDTO routing, Long fromId) {
|
List<RefDTO> refs = routing.getRefs();
|
if (fromId == null) {
|
List<Long> roIds = routing.getOperations().stream().map(ro -> ro.getId()).collect(Collectors.toList());
|
List<Long> toIds = refs.stream().map(r -> r.getToId()).collect(Collectors.toList());
|
roIds.removeAll(toIds);
|
return routingService.getDtoByPk(roIds.get(0));
|
} else if (CollectionUtil.isNotEmpty(refs)) {
|
Optional<RefDTO> opt = refs.stream().filter(r -> r.getFromId().equals(fromId)).findFirst();
|
if (opt.isPresent()) {
|
return routingService.getDtoByPk(opt.get().getToId());
|
}
|
}
|
return null;
|
}
|
|
|
}
|