Commit 23e3d84e by Ren Ping

feat:移除不满足工程师时间窗强约束的订单

1 parent 1181ddaf
...@@ -30,7 +30,7 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L ...@@ -30,7 +30,7 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
List<DispatchOrder> findAllWithoutConfirm(String groupId, String batchNo); List<DispatchOrder> findAllWithoutConfirm(String groupId, String batchNo);
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的 // 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
@Query("from DispatchOrder where teamId=?1 and batchNo=?2 and status !='CONFIRM' ") @Query("from DispatchOrder where teamId=?1 and batchNo=?2 ")
List<DispatchOrder> findAllWithoutConfirm2(String teamId, String batchNo); List<DispatchOrder> findAllWithoutConfirm2(String teamId, String batchNo);
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt); Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt);
......
...@@ -20,8 +20,11 @@ import lombok.Setter; ...@@ -20,8 +20,11 @@ import lombok.Setter;
public class Customer { public class Customer {
private long id; private long id;
private String code; private String code;
private String status;
// 已分配 // 已分配
private String dispatchedTechnicianCode; private String dispatchedTechnicianCode;
// 已排除 // 已排除
...@@ -56,7 +59,7 @@ public class Customer { ...@@ -56,7 +59,7 @@ public class Customer {
} }
public Customer(long id, String code, String dt, Location location, int startTime, int endTime, String requiredSkill, public Customer(long id, String code, String dt, Location location, int startTime, int endTime, String requiredSkill,
int serviceDuration) { int serviceDuration, String status) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.dt = dt; this.dt = dt;
...@@ -65,6 +68,7 @@ public class Customer { ...@@ -65,6 +68,7 @@ public class Customer {
this.endTime = endTime; this.endTime = endTime;
this.requiredSkill = requiredSkill; this.requiredSkill = requiredSkill;
this.serviceDuration = serviceDuration; this.serviceDuration = serviceDuration;
this.status = status;
} }
@InverseRelationShadowVariable(sourceVariableName = "customerList") @InverseRelationShadowVariable(sourceVariableName = "customerList")
......
...@@ -26,7 +26,7 @@ public interface ExtractService { ...@@ -26,7 +26,7 @@ public interface ExtractService {
/* /*
* 按小队将dispath_order 中的计算结果,回写到 order_info * 按小队将dispath_order 中的计算结果,回写到 order_info
* */ * */
void extractDispatchToOrder2(String TeamId, String batchNo, boolean isConfirm) ; void extractDispatchToOrder2(String TeamId, String batchNo, boolean cutOff) ;
} }
...@@ -259,7 +259,7 @@ public class SolveServiceImpl implements SolveService { ...@@ -259,7 +259,7 @@ public class SolveServiceImpl implements SolveService {
order.setPriority(0); order.setPriority(0);
} }
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime()); 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); OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0);
if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod()) if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod())
&& StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus())) && StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus()))
...@@ -271,11 +271,11 @@ public class SolveServiceImpl implements SolveService { ...@@ -271,11 +271,11 @@ public class SolveServiceImpl implements SolveService {
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);
}); });
...@@ -284,62 +284,62 @@ public class SolveServiceImpl implements SolveService { ...@@ -284,62 +284,62 @@ public class SolveServiceImpl implements SolveService {
// technicianList // technicianList
ArrayList<Technician> technicianList = new ArrayList<>(); ArrayList<Technician> technicianList = new ArrayList<>();
dispatchEngineerRepo.findByTeamIdAndBatchNo(teamId, batchNo).forEach(engineer -> { dispatchEngineerRepo.findByTeamIdAndBatchNo(teamId, batchNo).forEach(engineer -> {
// 技术员时间窗 // 技术员时间窗
int[][] timeWindows = engineerCalendarService.timeWindows(engineer.getEngineerCode(), teamId, int[][] timeWindows = engineerCalendarService.timeWindows(engineer.getEngineerCode(), teamId,
LocalDateTimeUtil.parseDate(currDay, DateTimeFormatter.ofPattern("yyyy-MM-dd"))); LocalDateTimeUtil.parseDate(currDay, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
if (null != timeWindows && timeWindows.length > 0) { if (null != timeWindows && timeWindows.length > 0) {
log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, timeWindows:{}", teamId, batchNo, log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, timeWindows:{}", teamId, batchNo,
engineer.getEngineerName(), new Gson().toJson(timeWindows)); engineer.getEngineerName(), new Gson().toJson(timeWindows));
// 技术员技能 // 技术员技能
List<String> skillList = queryEngineerSkills(engineer.getEngineerCode()); List<String> skillList = queryEngineerSkills(engineer.getEngineerCode());
// 距离偏好map // 距离偏好map
Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点", Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点",
StrUtil.isEmpty(engineer.getX()) ? 0 : Double.parseDouble(engineer.getX()), StrUtil.isEmpty(engineer.getX()) ? 0 : Double.parseDouble(engineer.getX()),
StrUtil.isEmpty(engineer.getY()) ? 0 : Double.parseDouble(engineer.getY())); StrUtil.isEmpty(engineer.getY()) ? 0 : Double.parseDouble(engineer.getY()));
Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>(); Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>();
if (location.getLongitude() > 1 && location.getLatitude() > 1) { if (location.getLongitude() > 1 && location.getLatitude() > 1) {
// 设置了偏好位置 // 设置了偏好位置
customerList.forEach(customer -> { customerList.forEach(customer -> {
long distance = distanceCalculator.calculateDistance(location, customer.getLocation()); long distance = distanceCalculator.calculateDistance(location, customer.getLocation());
preferedLoctionDistanceMap.put(customer.getCode(), distance); preferedLoctionDistanceMap.put(customer.getCode(), distance);
}); });
} else { } else {
// 未设置,不参与计算 // 未设置,不参与计算
} }
// 最大距离,硬约束:电动车固定40km上限,其他无限制 // 最大距离,硬约束:电动车固定40km上限,其他无限制
int maxDistance = engineer.getMaxDistance() * 1000; int maxDistance = engineer.getMaxDistance() * 1000;
if (engineer.getVehicleType() != null && engineer.getVehicleType() == 2) { if (engineer.getVehicleType() != null && engineer.getVehicleType() == 2) {
maxDistance = 40 * 1000; maxDistance = 40 * 1000;
} }
// 技术员出发地 // 技术员出发地
Double x = null; Double x = null;
Double y = null; Double y = null;
if (ObjectUtil.equal(engineer.getDeparture(), DepartureEnum.WORK_ADDR.getCode())) { if (ObjectUtil.equal(engineer.getDeparture(), DepartureEnum.WORK_ADDR.getCode())) {
x = Double.parseDouble(engineer.getWorkX()); x = Double.parseDouble(engineer.getWorkX());
y = Double.parseDouble(engineer.getWorkY()); y = Double.parseDouble(engineer.getWorkY());
} else { } else {
x = Double.parseDouble(orgWarehouseInfoEntity.getX()); x = Double.parseDouble(orgWarehouseInfoEntity.getX());
y = Double.parseDouble(orgWarehouseInfoEntity.getY()); y = Double.parseDouble(orgWarehouseInfoEntity.getY());
} }
Location engineerLocation = new Location(engineer.getId(), engineer.getEngineerCode(), "起点", x, y); Location engineerLocation = new Location(engineer.getId(), engineer.getEngineerCode(), "起点", x, y);
Depot engineerDepot = new Depot(engineer.getId(), engineer.getEngineerCode(), engineerLocation, 60 * 8, Depot engineerDepot = new Depot(engineer.getId(), engineer.getEngineerCode(), engineerLocation, 60 * 8,
60 * 18); 60 * 18);
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(),
engineer.getMaxMinute(), maxDistance, engineer.getVehicleType(), engineerDepot, timeWindows, engineer.getMaxMinute(), maxDistance, engineer.getVehicleType(), engineerDepot, timeWindows,
Set.copyOf(skillList), preferedLoctionDistanceMap); Set.copyOf(skillList), preferedLoctionDistanceMap);
technicianList.add(vehicle); technicianList.add(vehicle);
} else { } else {
// 没有时间窗技术员,不参与派工 // 没有时间窗技术员,不参与派工
log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, no timeWindows", teamId, batchNo, log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, no timeWindows", teamId, batchNo,
engineer.getEngineerName()); engineer.getEngineerName());
} }
}); });
log.info("组织问题对象, technician-list, teamId:{}, batchNo:{}, technician-list:{}", teamId, batchNo, technicianList.size()); log.info("组织问题对象, technician-list, teamId:{}, batchNo:{}, technician-list:{}", teamId, batchNo, technicianList.size());
// locationlist 起点+订单地点 // locationlist 起点+订单地点
...@@ -535,7 +535,8 @@ public class SolveServiceImpl implements SolveService { ...@@ -535,7 +535,8 @@ public class SolveServiceImpl implements SolveService {
log.info("算法结果回写dispatch, step1-清除历史, groupId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果回写dispatch, step1-清除历史, groupId:{}, batchNo:{}", teamId, batchNo);
Object[] paramClear = {teamId, batchNo}; Object[] paramClear = {teamId, batchNo};
String sqlReset = "update dispatch_order set engineer_code='', seq=0, time_begin=null, time_end=null, path_time=0, path_distance=0 " + "where team_id=? and batch_no=? and status!='CONFIRM' "; // confirm 状态工单不清除
String sqlReset = "update dispatch_order set engineer_code=null, seq=0, time_begin=null, time_end=null, path_time=0, path_distance=0 " + "where team_id=? and batch_no=? and status!='CONFIRM' ";
jdbcTemplate.update(sqlReset, paramClear); jdbcTemplate.update(sqlReset, paramClear);
log.info("算法结果回写dispatch, step2-开始回写, teamId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果回写dispatch, step2-开始回写, teamId:{}, batchNo:{}", teamId, batchNo);
...@@ -561,7 +562,7 @@ public class SolveServiceImpl implements SolveService { ...@@ -561,7 +562,7 @@ public class SolveServiceImpl implements SolveService {
int pathTime = customer.getPathTimeFromPreviousStandstill(); int pathTime = customer.getPathTimeFromPreviousStandstill();
long pathDistance = customer.getDistanceFromPreviousStandstill(); long pathDistance = customer.getDistanceFromPreviousStandstill();
String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=?, path_time=?, path_distance=? " + " where team_id=? and batch_no=? and order_id=? and dt=? and status!='CONFIRM' "; String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=?, path_time=?, path_distance=? " + " where team_id=? and batch_no=? and order_id=? and dt=?";
Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, pathTime, pathDistance, teamId, batchNo, customer.getCode(), customer.getDt()}; Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, pathTime, pathDistance, teamId, batchNo, customer.getCode(), customer.getDt()};
int rowUpdated = jdbcTemplate.update(sql, param); int rowUpdated = jdbcTemplate.update(sql, param);
log.info("算法结果回写dispatch, step3-逐个客户处理, order_id:{}, engineer_code:{}, seq: {}, begin:{}, end:{} ,rowUpdated:{}", customer.getCode(), technician.getCode(), seq, arriveTime, leaveTime, rowUpdated); log.info("算法结果回写dispatch, step3-逐个客户处理, order_id:{}, engineer_code:{}, seq: {}, begin:{}, end:{} ,rowUpdated:{}", customer.getCode(), technician.getCode(), seq, arriveTime, leaveTime, rowUpdated);
......
...@@ -11,6 +11,7 @@ import java.util.stream.Collectors; ...@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.optaplanner.constraint.streams.drools.DroolsConstraintStreamScoreDirector; import org.optaplanner.constraint.streams.drools.DroolsConstraintStreamScoreDirector;
...@@ -400,7 +401,8 @@ public class DispatchSolutionUtils { ...@@ -400,7 +401,8 @@ public class DispatchSolutionUtils {
List<Customer> customerList = new ArrayList<>(); List<Customer> customerList = new ArrayList<>();
customerList.addAll(((Technician) indictedObject).getCustomerList()); customerList.addAll(((Technician) indictedObject).getCustomerList());
for (Customer customer : customerList) { for (Customer customer : customerList) {
if (!customer.isInTechnicianTimeWindows()) { if (!customer.isInTechnicianTimeWindows()
&& !StrUtil.equals("CONFIRM", customer.getStatus())) {
// 更新shadow变量 // 更新shadow变量
updateShadowVariable(customer); updateShadowVariable(customer);
// 移除技术员 // 移除技术员
...@@ -411,6 +413,19 @@ public class DispatchSolutionUtils { ...@@ -411,6 +413,19 @@ public class DispatchSolutionUtils {
} }
} }
break; break;
case dispatchedMatch:
for (Object indictedObject : constraintMatch.getIndictedObjectList()) {
// 违反硬约束对象,根据具体约束返回不同类型对象
if (indictedObject instanceof Customer) {
Customer customer = (Customer) indictedObject;
// 更新shadow变量
updateShadowVariable(customer);
// 移除技术员
customer.getTechnician().getCustomerList().remove(customer);
solution.getUnDispatchedCustomers().add(customer);
}
}
break;
default: default:
break; break;
} }
......
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 10 8-23 * * ? expr: 0 9 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!