Commit 102701f5 by Ren Ping

feat:自动排版优化

1 parent 2c85e672
......@@ -2,46 +2,53 @@ package com.dituhui.pea.dispatch.constraint;
/**
* 约束枚举
*
* @author zhangguoping
*
* @author zhangguoping
*/
public enum ConstraintNameEnum {
// 硬约束
/**
* 技术员技能跟订单相匹配
*/
skillMatch,
/**
* 订单到达时间跟时间窗吻合
*/
customerTimeWindowsMatch,
/**
* 技术员不加班
*/
technicianTimeWindowsMatch,
/**
* 技术员订单数量不超过最大值
*/
technicianCapacityMatch,
/**
* 已分配和已排除技术员匹配
*/
dispatchedMatch,
// 软约束
/**
* 订单数量均衡
*/
technicianBalanceSoft,
/**
* 总路程最小
*/
totalDistance,
/**
* 技术员中心点偏好
*/
preferredTotalDistance
// 硬约束
/**
* 技术员技能跟订单相匹配
*/
skillMatch,
/**
* 订单到达时间跟时间窗吻合
*/
customerTimeWindowsMatch,
/**
* 工单副工程师和主工程师必须同时存在
*/
customerSubAndMainEngineerMustCoexist,
/**
* 技术员不加班
*/
technicianTimeWindowsMatch,
/**
* 技术员订单数量不超过最大值
*/
technicianCapacityMatch,
/**
* 已分配和已排除技术员匹配
*/
dispatchedMatch,
// 软约束
/**
* 订单数量均衡
*/
technicianBalanceSoft,
/**
* 总路程最小
*/
totalDistance,
/**
* 技术员中心点偏好
*/
preferredTotalDistance
}
......@@ -3,6 +3,7 @@ package com.dituhui.pea.dispatch.constraint;
import java.util.List;
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.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintFactory;
......@@ -26,6 +27,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
technicianCapacityMatch(factory),
skillMatch(factory),
dispatchedMatch(factory),
//工单副工程师和主工程师必须同时存在
customerSubAndMainEngineerMustCoexist(factory),
// 软约束
technicianBalanceSoft(factory),
......@@ -55,6 +58,15 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.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) {
return factory.forEach(Technician.class).filter(
technician -> {
......@@ -129,7 +141,9 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected Constraint skillMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class)
.filter(customer -> customer.getTechnician() != null
&& !customer.getCode().endsWith("_sub")
&& !customer.getTechnician().getSkills().contains(customer.getRequiredSkill()))
.penalizeLong(HardSoftLongScore.ONE_HARD,
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 3-技能匹配问题1个,时间窗问题8个
......
......@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.DispatchEngineer;
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.Query;
import org.springframework.data.repository.CrudRepository;
......@@ -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" +
" 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 (a.is_multiple<>1 or a.engineer_code_sub is null)" + //指定了辅助工程师的不参与自动派单
" order by a.expect_time_begin asc ",
nativeQuery = true)
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;
import java.util.List;
import com.dituhui.pea.dispatch.entity.OrderEvent;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
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;
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.repository.CrudRepository;
......@@ -9,16 +10,16 @@ import java.util.List;
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)
Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfo> findByOrderId(String orderId);
List<OrderInfo> findByOrgTeamIdAndDt(String teamId, LocalDate dt);
List<OrderInfo> findByOrgGroupIdAndDt(String groupId, LocalDate dt);
}
......@@ -26,7 +26,7 @@ public class DispatchOrder implements Serializable {
@Column(name = "group_id")
private String groupId;
@Column(name = "batch_no")
private String batchNo;
......
......@@ -55,6 +55,11 @@ public class Customer {
private boolean isInTechnicianTimeWindows = true;
/**
* 主工程师工单
*/
private Customer mainCustomer;
public Customer() {
}
......@@ -164,7 +169,8 @@ public class Customer {
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
//return Long.valueOf(this.id).hashCode();
return this.code.hashCode();
}
@Override
......@@ -175,7 +181,8 @@ public class Customer {
return false;
if (obj == this)
return true;
return this.id == ((Customer) obj).getId();
//return this.id == ((Customer) obj).getId();
return this.code.equals(((Customer) obj).getCode());
}
@Override
......
......@@ -26,6 +26,8 @@ public class AutoDispatchJob extends QuartzJobBean {
public static final String TEAM_JOB_PREFIX = "BOXI_TEAM_";
public static final String SUB_ORDER_ID_SUFFIX = "_sub";
@Resource
private SchedulerService schedulerService;
......
......@@ -279,10 +279,14 @@ public class BatchServiceImpl implements BatchService {
dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderConfirmList), DispatchOrder.class));
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=?",
engCount, orderCount + orderConfirmCount, LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
} else {
......
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 com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.dituhui.pea.bean.AllotResultParam;
import com.dituhui.pea.bean.Reason;
import com.dituhui.pea.bean.RemoteBeanApi;
import com.dituhui.pea.bean.Rescheduled;
import com.dituhui.pea.dispatch.dao.*;
import com.dituhui.pea.dispatch.entity.*;
import com.dituhui.pea.dispatch.pojo.Customer;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
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 cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
......@@ -31,11 +30,9 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;
......@@ -219,6 +216,7 @@ public class ExtractServiceImpl implements ExtractService {
}
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());
......@@ -226,6 +224,10 @@ public class ExtractServiceImpl implements ExtractService {
dispatchOrderList.forEach(dispatchOrder -> {
int idx = atomicInteger.getAndIncrement();
String orderId = dispatchOrder.getOrderId();
if (orderId.endsWith(AutoDispatchJob.SUB_ORDER_ID_SUFFIX)) {
return;
}
String dt = dispatchOrder.getDt();
String engCode = dispatchOrder.getEngineerCode();
......@@ -281,23 +283,28 @@ public class ExtractServiceImpl implements ExtractService {
}
orderInfo.setDispatcher("AUTO_BATCH");
orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo);
if (cutOff) {
AllotResultParam allotResultParam = new AllotResultParam();
allotResultParam.setRisId(orderInfo.getOrderId());
allotResultParam.setExecutorWorkNo(engineerInfo.getCosmosId());
allotResultParam.setAssistantWorkNo(null);
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(">>> 【服务工单派单结果更新】请求参数:{}, 响应结果:{}", JSONObject.toJSON(allotResultParam), result);
DispatchOrder subDispatchOrder = orderIdMap.get(orderId + AutoDispatchJob.SUB_ORDER_ID_SUFFIX);
if (Objects.nonNull(subDispatchOrder)) {
orderInfo.setEngineerCodeSub(subDispatchOrder.getEngineerCode());
orderInfo.setSubElapsed(subDispatchOrder.getPathTime());
orderInfo.setSubDistance(subDispatchOrder.getPathDistance());
orderInfo.setSubPlanStartTime(subDispatchOrder.getTimeBegin());
orderInfo.setSubPlanEndTime(subDispatchOrder.getTimeEnd());
} else {
orderInfo.setEngineerCodeSub(null);
orderInfo.setSubElapsed(null);
orderInfo.setSubDistance(null);
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())
.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("")
.setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());
orderEventRepo.save(orderEvent);
......@@ -311,24 +318,32 @@ public class ExtractServiceImpl implements ExtractService {
} else {
log.warn("算法结果更新到工单, step1.2-loop, 未能分配到技术员, teamId:{}, batchNo:{}, orderId:{}, dt:{}",
teamId, batchNo, orderId, dt);
orderInfo.setEngineerCode("");
orderInfo.setEngineerName("");
orderInfo.setEngineerPhone("");
orderInfo.setEngineerCode(null);
orderInfo.setEngineerName(null);
orderInfo.setEngineerPhone(null);
orderInfo.setPlanStartTime(orderInfo.getExpectTimeBegin());
orderInfo.setPlanEndTime(orderInfo.getExpectTimeEnd());
orderInfo.setArriveElapsed(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");
if (cutOff) {
orderInfo.setAppointmentMethod("MANUAL");
orderInfo.setDispatcher("MANUAL");
log.info("算法结果更新工单为人工, teamId:{}, batchNo:{}, orderId:{}", teamId, batchNo, orderId);
} else {
log.info("算法结果更新工单为人工, teamId:{}, batchNo:{}, orderId:{}", teamId, batchNo, orderId);
} else if (null != orderInfo.getDispatcher() && !orderInfo.getDispatcher().startsWith("MANUAL")) {
orderInfo.setDispatcher("AUTO_BATCH");
}
orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo);
entityManager.merge(orderInfo);
OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH")
.setContent(String.format("批量自动指派:<%s,%s>", "", "抹掉技术员")).setContentOld("")
......@@ -341,5 +356,57 @@ public class ExtractServiceImpl implements ExtractService {
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.*;
import com.dituhui.pea.dispatch.entity.*;
import com.dituhui.pea.dispatch.enums.DepartureEnum;
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.ExtractService;
import com.dituhui.pea.dispatch.service.SolveService;
......@@ -35,6 +36,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
......@@ -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());
OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0);
if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod())
&& StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus()))
|| ObjectUtil.equal(1, orderInfo.getIsAppointEngineer())) {
customer.setDispatchedTechnicianCode(orderInfo.getEngineerCode());
}
if (!order.getOrderId().endsWith("_sub")) {
OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0);
if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod())
&& StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus()))
|| ObjectUtil.equal(1, orderInfo.getIsAppointEngineer())) {
customer.setDispatchedTechnicianCode(orderInfo.getEngineerCode());
}
if (ObjectUtil.equal(2, orderInfo.getIsAppointEngineer())) {
customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ?
orderInfo.getAppointEngineerCodes().trim() : null);
}
if (ObjectUtil.equal(2, orderInfo.getIsAppointEngineer())) {
customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ?
orderInfo.getAppointEngineerCodes().trim() : null);
}
log.info(
"订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}",
teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(),
customer.getExclusiveTechnicianCode());
log.info(
"订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}",
teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(),
customer.getExclusiveTechnicianCode());
}
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());
// technicianList
......
......@@ -443,6 +443,30 @@ public class DispatchSolutionUtils {
}
}
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:
break;
}
......
......@@ -3,7 +3,7 @@ server:
dispatch:
cron:
expr: 0 57 8-23 * * ?
expr: 0 22 8-23 * * ?
next-day-limit: 2
scheduler:
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!