Commit 8312e0fa by Ren Ping

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

1 parent f83b0d31
...@@ -76,6 +76,9 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -76,6 +76,9 @@ public class DispatchConstraintProvider implements ConstraintProvider {
if (!in) { if (!in) {
// 到达时间在日历窗口外,惩罚得分 // 到达时间在日历窗口外,惩罚得分
ret = true; ret = true;
customer.setInTechnicianTimeWindows(false);
} else {
customer.setInTechnicianTimeWindows(true);
} }
} }
} }
...@@ -93,18 +96,18 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -93,18 +96,18 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.asConstraint(ConstraintNameEnum.technicianCapacityMatch.name()); .asConstraint(ConstraintNameEnum.technicianCapacityMatch.name());
} }
protected Constraint dispatchedMatch(ConstraintFactory factory) { protected Constraint dispatchedMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class).filter(customer -> return factory.forEach(Customer.class).filter(customer ->
// 已分配但是分给了别人 // 已分配但是分给了别人
(customer.getDispatchedTechnicianCode() != null && customer.getTechnician() != null (customer.getDispatchedTechnicianCode() != null && customer.getTechnician() != null
&& !StringUtils.equals(customer.getDispatchedTechnicianCode(), customer.getTechnician().getCode())) || && !StringUtils.equals(customer.getDispatchedTechnicianCode(), customer.getTechnician().getCode())) ||
// 已排除但是分给了这个人 // 已排除但是分给了这个人
(customer.getExclusiveTechnicianCode() != null && customer.getTechnician() != null (customer.getExclusiveTechnicianCode() != null && customer.getTechnician() != null
&& StringUtils.equals(customer.getExclusiveTechnicianCode(), && StringUtils.equals(customer.getExclusiveTechnicianCode(),
customer.getTechnician().getCode()))) customer.getTechnician().getCode())))
.penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 50) .penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 50)
.asConstraint(ConstraintNameEnum.dispatchedMatch.name()); .asConstraint(ConstraintNameEnum.dispatchedMatch.name());
} }
// protected Constraint customerTimeWindowsMatch1(ConstraintFactory factory) { // protected Constraint customerTimeWindowsMatch1(ConstraintFactory factory) {
// return factory.forEach(Customer.class).filter( // return factory.forEach(Customer.class).filter(
......
...@@ -21,12 +21,12 @@ public class Customer { ...@@ -21,12 +21,12 @@ public class Customer {
private long id; private long id;
private String code; private String code;
// 已分配 // 已分配
private String dispatchedTechnicianCode; private String dispatchedTechnicianCode;
// 已排除 // 已排除
private String exclusiveTechnicianCode; private String exclusiveTechnicianCode;
// orderid(code)+dt 确定唯一一条工单 // orderid(code)+dt 确定唯一一条工单
private String dt; private String dt;
@JsonIgnore @JsonIgnore
...@@ -50,6 +50,8 @@ public class Customer { ...@@ -50,6 +50,8 @@ public class Customer {
// 离开时间 // 离开时间
// private Integer departureTime; // private Integer departureTime;
private boolean isInTechnicianTimeWindows = true;
public Customer() { public Customer() {
} }
...@@ -135,9 +137,9 @@ public class Customer { ...@@ -135,9 +137,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet."); // throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
} }
if (previousCustomer == null) { if (previousCustomer == null) {
return technician.getDepot().getLocation().getDistanceTo(technician.getVehicleType(),location); return technician.getDepot().getLocation().getDistanceTo(technician.getVehicleType(), location);
} }
return previousCustomer.getLocation().getDistanceTo(technician.getVehicleType(),location); return previousCustomer.getLocation().getDistanceTo(technician.getVehicleType(), location);
} }
/** /**
...@@ -151,9 +153,9 @@ public class Customer { ...@@ -151,9 +153,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet."); // throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
} }
if (previousCustomer == null) { if (previousCustomer == null) {
return technician.getDepot().getLocation().getPathTimeTo(technician.getVehicleType(),location); return technician.getDepot().getLocation().getPathTimeTo(technician.getVehicleType(), location);
} }
return previousCustomer.getLocation().getPathTimeTo(technician.getVehicleType(),location); return previousCustomer.getLocation().getPathTimeTo(technician.getVehicleType(), location);
} }
@Override @Override
......
package com.dituhui.pea.dispatch.quartz.dispatch; package com.dituhui.pea.dispatch.quartz.dispatch;
import com.dituhui.pea.dispatch.common.RedissonUtil;
import com.dituhui.pea.dispatch.service.SchedulerService; import com.dituhui.pea.dispatch.service.SchedulerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution; import org.quartz.DisallowConcurrentExecution;
...@@ -23,7 +24,7 @@ import javax.annotation.Resource; ...@@ -23,7 +24,7 @@ import javax.annotation.Resource;
@DisallowConcurrentExecution @DisallowConcurrentExecution
public class AutoDispatchJob extends QuartzJobBean { public class AutoDispatchJob extends QuartzJobBean {
public static final String TEAM_JOB_PREFIX="BOXI_TEAM_"; public static final String TEAM_JOB_PREFIX = "BOXI_TEAM_";
@Resource @Resource
private SchedulerService schedulerService; private SchedulerService schedulerService;
...@@ -36,6 +37,9 @@ public class AutoDispatchJob extends QuartzJobBean { ...@@ -36,6 +37,9 @@ public class AutoDispatchJob extends QuartzJobBean {
String teamId = name.substring(TEAM_JOB_PREFIX.length()); String teamId = name.substring(TEAM_JOB_PREFIX.length());
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
log.info(">>> 自动派工(teamId:{}) 自动任务开始", teamId); log.info(">>> 自动派工(teamId:{}) 自动任务开始", teamId);
/*RedissonUtil.lockOperation(AutoDispatchJob.TEAM_JOB_PREFIX + teamId, 60, () -> {
schedulerService.dispatchRun2(teamId);
});*/
schedulerService.dispatchRun2(teamId); schedulerService.dispatchRun2(teamId);
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
log.info(">>> 自动派工(teamId:{}) 自动任务结束,耗时:{}", teamId, end - start); log.info(">>> 自动派工(teamId:{}) 自动任务结束,耗时:{}", teamId, end - start);
......
...@@ -113,52 +113,45 @@ public class SchedulerServiceImpl implements SchedulerService { ...@@ -113,52 +113,45 @@ public class SchedulerServiceImpl implements SchedulerService {
for (int i = 1; i <= nextDaysLimit; i++) { for (int i = 1; i <= nextDaysLimit; i++) {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE); String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
boolean finalCutOff = cutOff; Optional<DispatchBatch> optional = dispatchBatchRepository.findByTeamIdAndBatchDate(teamId, currDay);
RedissonUtil.lockOperation(AutoDispatchJob.TEAM_JOB_PREFIX + teamId, 60, () -> { if (optional.isPresent()
dispatchRun2OneDay(teamId, currDay, today, finalCutOff); && Objects.nonNull(optional.get().getCutoffedTime())
}); && DateUtil.format(optional.get().getCutoffedTime(), "yyyy-MM-dd").equals(today)) {
} //自动任务截止
} log.error(">>> teamId:{}, day:{} 自动任务已截止", teamId, currDay);
private void dispatchRun2OneDay(String teamId, String currDay, String today, boolean cutOff) {
Optional<DispatchBatch> optional = dispatchBatchRepository.findByTeamIdAndBatchDate(teamId, currDay);
if (optional.isPresent()
&& Objects.nonNull(optional.get().getCutoffedTime())
&& DateUtil.format(optional.get().getCutoffedTime(), "yyyy-MM-dd").equals(today)) {
//自动任务截止
log.error(">>> teamId:{}, day:{} 自动任务已截止", teamId, currDay);
return;
}
try {
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay, cutOff);
UUID problemId = solveService.generateProblemId(teamId, batchNo);
log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
DispatchSolution problem = solveService.prepareSolution2(teamId, batchNo, currDay);
if (problem.getCustomerList().size() <= 0) {
log.info("dispatchRun 当前批次没有待指派工单 , teamId:{}, day:{}, batch:{}, problemId:{}, order-size:{}", teamId, currDay, batchNo, problemId, problem.getCustomerList().size());
return; return;
} }
log.info("dispatchRun prepare done, teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
Solver<DispatchSolution> solver = solverFactory.buildSolver(); try {
DispatchSolution solution = solver.solve(problem); log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay);
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
log.info("dispatchRun solve done, teamId:{}, day:{}, batch:{}, problemId:{}, score:{}", teamId, currDay, batchNo, problemId, solution.getScore().toShortString()); String batchNo = batchService.buildBatchData2(teamId, currDay, cutOff);
this.solveService.saveSolutionWrp2(solution); UUID problemId = solveService.generateProblemId(teamId, batchNo);
this.extractService.extractDispatchToOrder2(teamId, batchNo, cutOff); log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay);
DispatchSolution problem = solveService.prepareSolution2(teamId, batchNo, currDay);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json", teamId, currDay))); if (problem.getCustomerList().size() <= 0) {
log.info("dispatchRun 当前批次没有待指派工单 , teamId:{}, day:{}, batch:{}, problemId:{}, order-size:{}", teamId, currDay, batchNo, problemId, problem.getCustomerList().size());
//log.info("dispatchRun group:{}, team:{} done", groupId, teamId); return;
} catch (Exception e) { }
log.error(">>> (teamId:{}, day:{})自动排班失败:{}", teamId, currDay, e.getMessage(), e); log.info("dispatchRun prepare done, teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
//throw e; Solver<DispatchSolution> solver = solverFactory.buildSolver();
DispatchSolution solution = solver.solve(problem);
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
log.info("dispatchRun solve done, teamId:{}, day:{}, batch:{}, problemId:{}, score:{}", teamId, currDay, batchNo, problemId, solution.getScore().toShortString());
this.solveService.saveSolutionWrp2(solution);
this.extractService.extractDispatchToOrder2(teamId, batchNo, cutOff);
log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json", teamId, currDay)));
//log.info("dispatchRun group:{}, team:{} done", groupId, teamId);
} catch (Exception e) {
log.error(">>> (teamId:{}, day:{})自动排班失败:{}", teamId, currDay, e.getMessage(), e);
//throw e;
}
} }
} }
} }
\ No newline at end of file
...@@ -553,7 +553,6 @@ public class SolveServiceImpl implements SolveService { ...@@ -553,7 +553,6 @@ public class SolveServiceImpl implements SolveService {
// Date end = Date.from(localEndTime.atZone(ZoneId.systemDefault()).toInstant()); // Date end = Date.from(localEndTime.atZone(ZoneId.systemDefault()).toInstant());
log.info("算法结果回写dispatch, step3-逐个客户处理, teamId:{}, batchNo:{}, employ: {}, customer:{}, service-duration:{} ", teamId, batchNo, technician.getCode(), customer.getCode(), customer.getServiceDuration()); log.info("算法结果回写dispatch, step3-逐个客户处理, teamId:{}, batchNo:{}, employ: {}, customer:{}, service-duration:{} ", teamId, batchNo, technician.getCode(), customer.getCode(), customer.getServiceDuration());
log.info(customer.toString());
LocalDateTime customDateTime = LocalDateTime.parse(customer.getDt() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); LocalDateTime customDateTime = LocalDateTime.parse(customer.getDt() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime arriveTime = customDateTime.plusMinutes(customer.getArrivalTime()); LocalDateTime arriveTime = customDateTime.plusMinutes(customer.getArrivalTime());
LocalDateTime leaveTime = customDateTime.plusMinutes(customer.getDepartureTime()); LocalDateTime leaveTime = customDateTime.plusMinutes(customer.getDepartureTime());
......
...@@ -3,8 +3,8 @@ server: ...@@ -3,8 +3,8 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 */3 8-23 * * ? expr: 0 10 8-23 * * ?
next-day-limit: 20 next-day-limit: 2
scheduler: scheduler:
init-engineer-capacity: init-engineer-capacity:
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!