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 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 run(OrderDTO[] dtoList, Long sceneId) { List orders = buildOrderList(dtoList); if (CollectionUtil.isEmpty(orders)) { return R.failed("请选择待排产订单"); } UUID problemId = UUID.randomUUID(); SolverJob 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 buildOrderList(OrderDTO[] dtoList) { if (dtoList == null || dtoList.length == 0) { return null; } List 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 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 orders, Long sceneId) { List tasks = new ArrayList<>(); //按照零件分组 Map> partOrderMap = orders.stream().collect(Collectors.groupingBy(Order::getPartId)); partOrderMap.forEach((k, v) -> { List 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 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 getOpCapIds(Long opId) { OperationBo operation = apsCoreService.queryOperation(opId); return operation.getCapabilityIds(); } /** * 合并订单 * * @param orders * @return */ private List merge(List 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 refs = routing.getRefs(); if (fromId == null) { List roIds = routing.getOperations().stream().map(ro -> ro.getId()).collect(Collectors.toList()); List 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 opt = refs.stream().filter(r -> r.getFromId().equals(fromId)).findFirst(); if (opt.isPresent()) { return routingService.getDtoByPk(opt.get().getToId()); } } return null; } }