Commit 102701f5 by Ren Ping

feat:自动排版优化

1 parent 2c85e672
...@@ -2,46 +2,53 @@ package com.dituhui.pea.dispatch.constraint; ...@@ -2,46 +2,53 @@ package com.dituhui.pea.dispatch.constraint;
/** /**
* 约束枚举 * 约束枚举
*
* @author zhangguoping
* *
* @author zhangguoping
*/ */
public enum ConstraintNameEnum { public enum ConstraintNameEnum {
// 硬约束 // 硬约束
/** /**
* 技术员技能跟订单相匹配 * 技术员技能跟订单相匹配
*/ */
skillMatch, skillMatch,
/** /**
* 订单到达时间跟时间窗吻合 * 订单到达时间跟时间窗吻合
*/ */
customerTimeWindowsMatch, customerTimeWindowsMatch,
/**
* 技术员不加班 /**
*/ * 工单副工程师和主工程师必须同时存在
technicianTimeWindowsMatch, */
/** customerSubAndMainEngineerMustCoexist,
* 技术员订单数量不超过最大值
*/ /**
technicianCapacityMatch, * 技术员不加班
/** */
* 已分配和已排除技术员匹配 technicianTimeWindowsMatch,
*/
dispatchedMatch, /**
* 技术员订单数量不超过最大值
// 软约束 */
/** technicianCapacityMatch,
* 订单数量均衡
*/ /**
technicianBalanceSoft, * 已分配和已排除技术员匹配
/** */
* 总路程最小 dispatchedMatch,
*/
totalDistance, // 软约束
/** /**
* 技术员中心点偏好 * 订单数量均衡
*/ */
preferredTotalDistance technicianBalanceSoft,
/**
* 总路程最小
*/
totalDistance,
/**
* 技术员中心点偏好
*/
preferredTotalDistance
} }
...@@ -3,6 +3,7 @@ package com.dituhui.pea.dispatch.constraint; ...@@ -3,6 +3,7 @@ package com.dituhui.pea.dispatch.constraint;
import java.util.List; import java.util.List;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore; import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
import org.optaplanner.core.api.score.stream.Constraint; import org.optaplanner.core.api.score.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintFactory; import org.optaplanner.core.api.score.stream.ConstraintFactory;
...@@ -26,6 +27,8 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -26,6 +27,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
technicianCapacityMatch(factory), technicianCapacityMatch(factory),
skillMatch(factory), skillMatch(factory),
dispatchedMatch(factory), dispatchedMatch(factory),
//工单副工程师和主工程师必须同时存在
customerSubAndMainEngineerMustCoexist(factory),
// 软约束 // 软约束
technicianBalanceSoft(factory), technicianBalanceSoft(factory),
...@@ -55,6 +58,15 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -55,6 +58,15 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.asConstraint(ConstraintNameEnum.customerTimeWindowsMatch.name()); .asConstraint(ConstraintNameEnum.customerTimeWindowsMatch.name());
} }
//工单副工程师和主工程师必须同时存在
public Constraint customerSubAndMainEngineerMustCoexist(ConstraintFactory factory) {
return factory.forEach(Customer.class).filter(customer -> customer.getCode().endsWith(AutoDispatchJob.SUB_ORDER_ID_SUFFIX)
&& null != customer.getTechnician()
&& null != customer.getMainCustomer()
&& null == customer.getMainCustomer().getTechnician())
.penalizeLong(HardSoftLongScore.ONE_HARD, Customer -> 1).asConstraint(ConstraintNameEnum.customerSubAndMainEngineerMustCoexist.name());
}
protected Constraint technicianTimeWindowsMatch(ConstraintFactory factory) { protected Constraint technicianTimeWindowsMatch(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter( return factory.forEach(Technician.class).filter(
technician -> { technician -> {
...@@ -129,7 +141,9 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -129,7 +141,9 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected Constraint skillMatch(ConstraintFactory factory) { protected Constraint skillMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class) return factory.forEach(Customer.class)
.filter(customer -> customer.getTechnician() != null .filter(customer -> customer.getTechnician() != null
&& !customer.getCode().endsWith("_sub")
&& !customer.getTechnician().getSkills().contains(customer.getRequiredSkill())) && !customer.getTechnician().getSkills().contains(customer.getRequiredSkill()))
.penalizeLong(HardSoftLongScore.ONE_HARD, .penalizeLong(HardSoftLongScore.ONE_HARD,
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题 // 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 3-技能匹配问题1个,时间窗问题8个 // 3-技能匹配问题1个,时间窗问题8个
......
...@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.dao; ...@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.DispatchEngineer; import com.dituhui.pea.dispatch.entity.DispatchEngineer;
import com.dituhui.pea.dispatch.entity.DispatchOrder; import com.dituhui.pea.dispatch.entity.DispatchOrder;
import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
...@@ -58,8 +59,21 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L ...@@ -58,8 +59,21 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
" where a.org_team_id=?3 and a.dt = ?4 and bean_status='OPEN'\n" + " where a.org_team_id=?3 and a.dt = ?4 and bean_status='OPEN'\n" +
" and (appointment_method like 'AUTO%' or appointment_method='MANUAL') and a.appointment_status in ('CONFIRM')\n" + " and (appointment_method like 'AUTO%' or appointment_method='MANUAL') and a.appointment_status in ('CONFIRM')\n" +
" and order_status in ('NORMAL','RESCHEDULED') and service_status='INIT'\n" + " and order_status in ('NORMAL','RESCHEDULED') and service_status='INIT'\n" +
" and (a.is_multiple<>1 or a.engineer_code_sub is null)" + //指定了辅助工程师的不参与自动派单
" order by a.expect_time_begin asc ", " order by a.expect_time_begin asc ",
nativeQuery = true) nativeQuery = true)
List<Map<String,Object>> getNewDispatchConfirmOrder(String groupId, String batchNo, String teamId, String batchDay); List<Map<String,Object>> getNewDispatchConfirmOrder(String groupId, String batchNo, String teamId, String batchDay);
@Query(value = " select ?1 group_id, ?2 batch_no, a.org_team_id team_id, concat(a.order_id,'"+ AutoDispatchJob.SUB_ORDER_ID_SUFFIX +"')order_id, date_format(a.dt,'%Y-%m-%d') dt, a.x, a.y , \n" +
" a.expect_time_begin, DATE_ADD(a.expect_time_end, INTERVAL 15 MINUTE) expect_time_end, a.tags, a.priority , \n" +
" '' skills , 15 take_time, a.appointment_status status, \n" +
" a.engineer_code_sub engineer_code, date_format(a.sub_plan_start_time,'%Y-%m-%d %H:%i:%s') time_begin, date_format(a.sub_plan_end_time,'%Y-%m-%d %H:%i:%s') time_end \n" +
" from order_info a \n" +
" where a.org_team_id=?3 and a.dt = ?4 and bean_status='OPEN'\n" +
" and (appointment_method like 'AUTO%' or appointment_method='MANUAL') and a.appointment_status in ('INIT', 'PRE', 'CONFIRM')\n" +
" and order_status in ('NORMAL','RESCHEDULED') and service_status='INIT'\n" +
" and (a.is_multiple=1 and a.engineer_code is not null and a.engineer_code !='' and a.engineer_code_sub is not null and a.engineer_code_sub !='')\n" +
" order by a.expect_time_begin asc ",
nativeQuery = true)
List<Map<String,Object>> getNewDispatchSubOrder(String groupId, String batchNo, String teamId, String batchDay);
} }
\ No newline at end of file
...@@ -3,9 +3,12 @@ package com.dituhui.pea.dispatch.dao; ...@@ -3,9 +3,12 @@ package com.dituhui.pea.dispatch.dao;
import java.util.List; import java.util.List;
import com.dituhui.pea.dispatch.entity.OrderEvent; import com.dituhui.pea.dispatch.entity.OrderEvent;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
public interface OrderEventRepository extends CrudRepository<OrderEvent, Long> { public interface OrderEventRepository extends CrudRepository<OrderEvent, Long>, JpaRepository<OrderEvent, Long> {
long countByOrderIdAndEventLike(String orderId, String event);
} }
package com.dituhui.pea.dispatch.dao; package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.OrderInfo; import com.dituhui.pea.dispatch.entity.OrderInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
...@@ -9,16 +10,16 @@ import java.util.List; ...@@ -9,16 +10,16 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> { public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long>, JpaRepository<OrderInfo, Long> {
// @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true) // @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true)
Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt); Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfo> findByOrderId(String orderId); List<OrderInfo> findByOrderId(String orderId);
List<OrderInfo> findByOrgTeamIdAndDt(String teamId, LocalDate dt); List<OrderInfo> findByOrgTeamIdAndDt(String teamId, LocalDate dt);
List<OrderInfo> findByOrgGroupIdAndDt(String groupId, LocalDate dt); List<OrderInfo> findByOrgGroupIdAndDt(String groupId, LocalDate dt);
} }
...@@ -26,7 +26,7 @@ public class DispatchOrder implements Serializable { ...@@ -26,7 +26,7 @@ public class DispatchOrder implements Serializable {
@Column(name = "group_id") @Column(name = "group_id")
private String groupId; private String groupId;
@Column(name = "batch_no") @Column(name = "batch_no")
private String batchNo; private String batchNo;
......
...@@ -55,6 +55,11 @@ public class Customer { ...@@ -55,6 +55,11 @@ public class Customer {
private boolean isInTechnicianTimeWindows = true; private boolean isInTechnicianTimeWindows = true;
/**
* 主工程师工单
*/
private Customer mainCustomer;
public Customer() { public Customer() {
} }
...@@ -164,7 +169,8 @@ public class Customer { ...@@ -164,7 +169,8 @@ public class Customer {
@Override @Override
public int hashCode() { public int hashCode() {
return Long.valueOf(this.id).hashCode(); //return Long.valueOf(this.id).hashCode();
return this.code.hashCode();
} }
@Override @Override
...@@ -175,7 +181,8 @@ public class Customer { ...@@ -175,7 +181,8 @@ public class Customer {
return false; return false;
if (obj == this) if (obj == this)
return true; return true;
return this.id == ((Customer) obj).getId(); //return this.id == ((Customer) obj).getId();
return this.code.equals(((Customer) obj).getCode());
} }
@Override @Override
......
...@@ -26,6 +26,8 @@ public class AutoDispatchJob extends QuartzJobBean { ...@@ -26,6 +26,8 @@ public class AutoDispatchJob extends QuartzJobBean {
public static final String TEAM_JOB_PREFIX = "BOXI_TEAM_"; public static final String TEAM_JOB_PREFIX = "BOXI_TEAM_";
public static final String SUB_ORDER_ID_SUFFIX = "_sub";
@Resource @Resource
private SchedulerService schedulerService; private SchedulerService schedulerService;
......
...@@ -279,10 +279,14 @@ public class BatchServiceImpl implements BatchService { ...@@ -279,10 +279,14 @@ public class BatchServiceImpl implements BatchService {
dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderConfirmList), DispatchOrder.class)); dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderConfirmList), DispatchOrder.class));
int orderConfirmCount = orderConfirmList.size(); int orderConfirmCount = orderConfirmList.size();
log.info("准备批次数据 engCount:{}, orderCount:{}, orderConfirmCount:{}", engCount, orderCount, orderConfirmCount); List<Map<String, Object>> orderSubList = dispatchOrderRepository.getNewDispatchSubOrder(groupId, batchNo, teamId, batchDay);
dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderSubList), DispatchOrder.class));
int orderSubCount = orderSubList.size();
log.info("准备批次数据 engCount:{}, orderCount:{}, orderConfirmCount:{}, orderSubCount:{}", engCount, orderCount, orderConfirmCount,orderSubCount);
if (orderCount + orderConfirmCount > 0) {
if (orderCount + orderConfirmCount + orderSubCount > 0) {
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=null, status='RUNNING', cutoffed_time=? where team_id=? and batch_no=?", jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=null, status='RUNNING', cutoffed_time=? where team_id=? and batch_no=?",
engCount, orderCount + orderConfirmCount, LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo); engCount, orderCount + orderConfirmCount, LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
} else { } else {
......
package com.dituhui.pea.dispatch.service.impl; package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils; import com.alibaba.nacos.common.utils.CollectionUtils;
import com.dituhui.pea.bean.AllotResultParam; import com.dituhui.pea.bean.AllotResultParam;
import com.dituhui.pea.bean.Reason;
import com.dituhui.pea.bean.RemoteBeanApi; import com.dituhui.pea.bean.RemoteBeanApi;
import com.dituhui.pea.bean.Rescheduled;
import com.dituhui.pea.dispatch.dao.*; import com.dituhui.pea.dispatch.dao.*;
import com.dituhui.pea.dispatch.entity.*; import com.dituhui.pea.dispatch.entity.*;
import com.dituhui.pea.dispatch.pojo.Customer; import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.service.ExtractService; import com.dituhui.pea.dispatch.service.ExtractService;
import com.dituhui.pea.enums.OrderEventEnum;
import com.dituhui.pea.util.DateUtil;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
...@@ -31,11 +30,9 @@ import java.time.LocalDate; ...@@ -31,11 +30,9 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED; import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;
...@@ -219,6 +216,7 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -219,6 +216,7 @@ public class ExtractServiceImpl implements ExtractService {
} }
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAllWithoutConfirm2(teamId, batchNo); List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAllWithoutConfirm2(teamId, batchNo);
Map<String, DispatchOrder> orderIdMap = dispatchOrderList.stream().collect(Collectors.toMap(DispatchOrder::getOrderId, Function.identity()));
log.info("算法结果更新到工单, step1-开始处理, teamId:{}, batchNo:{}, order-size:{}", teamId, batchNo, dispatchOrderList.size()); log.info("算法结果更新到工单, step1-开始处理, teamId:{}, batchNo:{}, order-size:{}", teamId, batchNo, dispatchOrderList.size());
...@@ -226,6 +224,10 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -226,6 +224,10 @@ public class ExtractServiceImpl implements ExtractService {
dispatchOrderList.forEach(dispatchOrder -> { dispatchOrderList.forEach(dispatchOrder -> {
int idx = atomicInteger.getAndIncrement(); int idx = atomicInteger.getAndIncrement();
String orderId = dispatchOrder.getOrderId(); String orderId = dispatchOrder.getOrderId();
if (orderId.endsWith(AutoDispatchJob.SUB_ORDER_ID_SUFFIX)) {
return;
}
String dt = dispatchOrder.getDt(); String dt = dispatchOrder.getDt();
String engCode = dispatchOrder.getEngineerCode(); String engCode = dispatchOrder.getEngineerCode();
...@@ -281,23 +283,28 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -281,23 +283,28 @@ public class ExtractServiceImpl implements ExtractService {
} }
orderInfo.setDispatcher("AUTO_BATCH"); orderInfo.setDispatcher("AUTO_BATCH");
orderInfo.setUpdateTime(LocalDateTime.now()); orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo);
if (cutOff) { DispatchOrder subDispatchOrder = orderIdMap.get(orderId + AutoDispatchJob.SUB_ORDER_ID_SUFFIX);
AllotResultParam allotResultParam = new AllotResultParam(); if (Objects.nonNull(subDispatchOrder)) {
allotResultParam.setRisId(orderInfo.getOrderId()); orderInfo.setEngineerCodeSub(subDispatchOrder.getEngineerCode());
allotResultParam.setExecutorWorkNo(engineerInfo.getCosmosId()); orderInfo.setSubElapsed(subDispatchOrder.getPathTime());
allotResultParam.setAssistantWorkNo(null); orderInfo.setSubDistance(subDispatchOrder.getPathDistance());
allotResultParam.setReason("自动派单"); orderInfo.setSubPlanStartTime(subDispatchOrder.getTimeBegin());
String format = "yyyy-MM-dd HH:mm:ss"; orderInfo.setSubPlanEndTime(subDispatchOrder.getTimeEnd());
allotResultParam.setAppointmentStartTime(orderInfo.getPlanStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } else {
allotResultParam.setAppointmentEndTime(orderInfo.getPlanEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); orderInfo.setEngineerCodeSub(null);
orderInfo.setSubElapsed(null);
boolean result = remoteBeanApi.allotResultUpdate(allotResultParam); orderInfo.setSubDistance(null);
log.info(">>> 【服务工单派单结果更新】请求参数:{}, 响应结果:{}", JSONObject.toJSON(allotResultParam), result); orderInfo.setSubPlanStartTime(null);
orderInfo.setSubPlanEndTime(null);
}
entityManager.merge(orderInfo);
if (cutOff) {
//同步自动派单结果到Bean
syncOrderToBean(orderInfo, engineerInfoMap);
OrderEvent orderEvent = new OrderEvent().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setHappen(LocalDateTime.now()) OrderEvent orderEvent = new OrderEvent().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setHappen(LocalDateTime.now())
.setEvent("批量自动指派").setOperator("DISPATCH").setOperatorName("算法批量指派").setSource("PEA-DISPATCH") .setEvent(OrderEventEnum.reassignment.getEvent()).setOperator("DISPATCH").setOperatorName("算法批量指派").setSource("PEA-DISPATCH")
.setDescription(String.format("批量自动指派:<%s,%s>", engCode, engName)).setMemo("") .setDescription(String.format("批量自动指派:<%s,%s>", engCode, engName)).setMemo("")
.setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now()); .setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());
orderEventRepo.save(orderEvent); orderEventRepo.save(orderEvent);
...@@ -311,24 +318,32 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -311,24 +318,32 @@ public class ExtractServiceImpl implements ExtractService {
} else { } else {
log.warn("算法结果更新到工单, step1.2-loop, 未能分配到技术员, teamId:{}, batchNo:{}, orderId:{}, dt:{}", log.warn("算法结果更新到工单, step1.2-loop, 未能分配到技术员, teamId:{}, batchNo:{}, orderId:{}, dt:{}",
teamId, batchNo, orderId, dt); teamId, batchNo, orderId, dt);
orderInfo.setEngineerCode(""); orderInfo.setEngineerCode(null);
orderInfo.setEngineerName(""); orderInfo.setEngineerName(null);
orderInfo.setEngineerPhone(""); orderInfo.setEngineerPhone(null);
orderInfo.setPlanStartTime(orderInfo.getExpectTimeBegin()); orderInfo.setPlanStartTime(orderInfo.getExpectTimeBegin());
orderInfo.setPlanEndTime(orderInfo.getExpectTimeEnd()); orderInfo.setPlanEndTime(orderInfo.getExpectTimeEnd());
orderInfo.setArriveElapsed(0); orderInfo.setArriveElapsed(0);
orderInfo.setArriveDistance(0); orderInfo.setArriveDistance(0);
if (ObjectUtil.equals(1, orderInfo.getIsMultiple())) {
orderInfo.setEngineerCodeSub(null);
orderInfo.setSubElapsed(0);
orderInfo.setSubDistance(0);
orderInfo.setSubPlanStartTime(orderInfo.getExpectTimeBegin());
orderInfo.setSubPlanEndTime(orderInfo.getExpectTimeBegin().plusMinutes(15));
}
orderInfo.setAppointmentStatus("INIT"); orderInfo.setAppointmentStatus("INIT");
if (cutOff) { if (cutOff) {
orderInfo.setAppointmentMethod("MANUAL"); orderInfo.setAppointmentMethod("MANUAL");
orderInfo.setDispatcher("MANUAL"); orderInfo.setDispatcher("MANUAL");
log.info("算法结果更新工单为人工, teamId:{}, batchNo:{}, orderId:{}", teamId, batchNo, orderId); log.info("算法结果更新工单为人工, teamId:{}, batchNo:{}, orderId:{}", teamId, batchNo, orderId);
} else { } else if (null != orderInfo.getDispatcher() && !orderInfo.getDispatcher().startsWith("MANUAL")) {
orderInfo.setDispatcher("AUTO_BATCH"); orderInfo.setDispatcher("AUTO_BATCH");
} }
orderInfo.setUpdateTime(LocalDateTime.now()); orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo); entityManager.merge(orderInfo);
OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH") OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH")
.setContent(String.format("批量自动指派:<%s,%s>", "", "抹掉技术员")).setContentOld("") .setContent(String.format("批量自动指派:<%s,%s>", "", "抹掉技术员")).setContentOld("")
...@@ -341,5 +356,57 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -341,5 +356,57 @@ public class ExtractServiceImpl implements ExtractService {
log.info("算法结果更新到工单完成, teamId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果更新到工单完成, teamId:{}, batchNo:{}", teamId, batchNo);
} }
private void syncOrderToBean(OrderInfo orderInfo, Map<String, EngineerInfo> engineerInfoMap) {
if (orderEventRepo.countByOrderIdAndEventLike(orderInfo.getOrderId(), "%" + OrderEventEnum.reassignment.getEvent() + "%") == 0) {
AllotResultParam allotResultParam = new AllotResultParam();
allotResultParam.setRisId(orderInfo.getOrderId());
allotResultParam.setExecutorWorkNo(engineerInfoMap.get(orderInfo.getEngineerCode()).getCosmosId());
if (null != orderInfo.getEngineerCodeSub()) {
EngineerInfo subEngineerInfo = engineerInfoMap.get(orderInfo.getEngineerCodeSub());
allotResultParam.setAssistantWorkNo(subEngineerInfo.getCosmosId());
}
allotResultParam.setReason("自动派单");
String format = "yyyy-MM-dd HH:mm:ss";
allotResultParam.setAppointmentStartTime(orderInfo.getPlanStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
allotResultParam.setAppointmentEndTime(orderInfo.getPlanEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
boolean result = remoteBeanApi.allotResultUpdate(allotResultParam);
log.info(">>> 同步自动派单结果到Bean,【服务工单派单结果更新】请求参数:{}, 响应结果:{}", JSONObject.toJSON(allotResultParam), result);
} else {
OrderInfo oldOrderInfo = orderInfoRepo.findByOrderId(orderInfo.getOrderId()).get(0);
Rescheduled rescheduled = new Rescheduled();
rescheduled.setRisId(orderInfo.getOrderId());
rescheduled.setInitiatorOfRescheduling("");
rescheduled.setReasonForRescheduling(new Reason());
rescheduled.setRescheduledDate(DateUtil.toMilliseconds(orderInfo.getPlanStartTime()));
rescheduled.setRequireApprove(Boolean.FALSE);
if (StrUtil.isNotEmpty(orderInfo.getEngineerCode())) {
String engineerCode = orderInfo.getEngineerCode();
EngineerInfo engineerInfo = engineerInfoMap.get(engineerCode);
rescheduled.setExecutorWorkNo(engineerInfo.getCosmosId());
rescheduled.setOrgUnitId(engineerInfo.getGroupId());
}
if (StrUtil.isNotEmpty(orderInfo.getEngineerCodeSub())) {
EngineerInfo engineerInfo = engineerInfoMap.get(orderInfo.getEngineerCodeSub());
rescheduled.setAssistantWorkNo(engineerInfo.getCosmosId());
rescheduled.setAssOrgUnitId(engineerInfo.getGroupId());
}
//判断是否是改派
if ((StrUtil.isNotEmpty(orderInfo.getEngineerCode()) && !Objects.equals(orderInfo.getEngineerCode(), oldOrderInfo.getEngineerCode())) ||
(StrUtil.isNotEmpty(orderInfo.getEngineerCodeSub()) && !Objects.equals(orderInfo.getEngineerCodeSub(), oldOrderInfo.getEngineerCodeSub()))) {
rescheduled.setReassignment(Boolean.TRUE);
} else {
rescheduled.setReassignment(Boolean.FALSE);
}
boolean result = remoteBeanApi.orderRescheduled(rescheduled);
log.info(">>> 同步自动派单结果到Bean,【服务工单改约】请求参数:{}, 响应结果:{}", JSONObject.toJSON(rescheduled), result);
}
}
} }
...@@ -10,6 +10,7 @@ import com.dituhui.pea.dispatch.dao.*; ...@@ -10,6 +10,7 @@ import com.dituhui.pea.dispatch.dao.*;
import com.dituhui.pea.dispatch.entity.*; import com.dituhui.pea.dispatch.entity.*;
import com.dituhui.pea.dispatch.enums.DepartureEnum; import com.dituhui.pea.dispatch.enums.DepartureEnum;
import com.dituhui.pea.dispatch.pojo.*; import com.dituhui.pea.dispatch.pojo.*;
import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
import com.dituhui.pea.dispatch.service.EngineerCalendarService; import com.dituhui.pea.dispatch.service.EngineerCalendarService;
import com.dituhui.pea.dispatch.service.ExtractService; import com.dituhui.pea.dispatch.service.ExtractService;
import com.dituhui.pea.dispatch.service.SolveService; import com.dituhui.pea.dispatch.service.SolveService;
...@@ -35,6 +36,7 @@ import java.time.LocalDateTime; ...@@ -35,6 +36,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
...@@ -260,26 +262,36 @@ public class SolveServiceImpl implements SolveService { ...@@ -260,26 +262,36 @@ public class SolveServiceImpl implements SolveService {
} }
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime(), order.getStatus()); Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime(), order.getStatus());
OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0); if (!order.getOrderId().endsWith("_sub")) {
if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod()) OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0);
&& StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus())) if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod())
|| ObjectUtil.equal(1, orderInfo.getIsAppointEngineer())) { && StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus()))
customer.setDispatchedTechnicianCode(orderInfo.getEngineerCode()); || ObjectUtil.equal(1, orderInfo.getIsAppointEngineer())) {
} customer.setDispatchedTechnicianCode(orderInfo.getEngineerCode());
}
if (ObjectUtil.equal(2, orderInfo.getIsAppointEngineer())) { if (ObjectUtil.equal(2, orderInfo.getIsAppointEngineer())) {
customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ? customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ?
orderInfo.getAppointEngineerCodes().trim() : null); orderInfo.getAppointEngineerCodes().trim() : null);
} }
log.info( log.info(
"订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}", "订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}",
teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(), teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(),
customer.getExclusiveTechnicianCode()); customer.getExclusiveTechnicianCode());
}
customerList.add(customer); customerList.add(customer);
}); });
Map<String,Customer> customerCodeMap= customerList.stream().collect(Collectors.toMap(Customer::getCode, Function.identity()));
customerList.forEach(customer -> {
if(customer.getCode().endsWith(AutoDispatchJob.SUB_ORDER_ID_SUFFIX)){
String code=customer.getCode();
customer.setMainCustomer(customerCodeMap.get(code.substring(0,code.length()-AutoDispatchJob.SUB_ORDER_ID_SUFFIX.length())));
}
});
log.info("组织问题对象, customer-list, teamId:{}, batchNo:{}, customer-list:{}", teamId, batchNo, customerList.size()); log.info("组织问题对象, customer-list, teamId:{}, batchNo:{}, customer-list:{}", teamId, batchNo, customerList.size());
// technicianList // technicianList
......
...@@ -443,6 +443,30 @@ public class DispatchSolutionUtils { ...@@ -443,6 +443,30 @@ public class DispatchSolutionUtils {
} }
} }
break; break;
case customerSubAndMainEngineerMustCoexist:
for (Object indictedObject : constraintMatch.getIndictedObjectList()) {
// 违反硬约束对象,根据具体约束返回不同类型对象
if (indictedObject instanceof Customer) {
Customer customer = (Customer) indictedObject;
log.warn(">>> 副工单({})违背 customerSubAndMainEngineerMustCoexist 硬约束: 主工单:{}, 主工程师: {}, 副工程师: {}, arriveTime: {},departureTime: {}",
customer.getCode(),
customer.getMainCustomer().getCode(),
null != customer.getMainCustomer().getTechnician() ? customer.getMainCustomer().getTechnician().getCode() : null,
null != customer.getTechnician() ? customer.getTechnician().getCode() : null,
customer.getArrivalTime(),
customer.getDepartureTime());
List<Customer> removeCustomers = CollectionUtil.toList(customer,customer.getMainCustomer());
removeCustomers.forEach(customer1 -> {
// 更新shadow变量
updateShadowVariable(customer1);
// 移除技术员
customer1.getTechnician().getCustomerList().remove(customer1);
solution.getUnDispatchedCustomers().add(customer1);
});
}
}
break;
default: default:
break; break;
} }
......
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 57 8-23 * * ? expr: 0 22 8-23 * * ?
next-day-limit: 2 next-day-limit: 2
scheduler: scheduler:
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!