Commit 750a4a41 by 张晓

dispatch_order表调整

1 parent 4d9524c5
......@@ -19,5 +19,5 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and ( engineerCode is not null and engineerCode!='') ")
List<DispatchOrder> findAssigned(String groupId, String batchNo);
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderId(String groupId, String batchNo, String orderId);
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt);
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import com.dituhui.pea.dispatch.entity.OrderInfo;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.time.LocalDate;
import java.util.Optional;
......@@ -11,5 +12,6 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> {
// @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true)
Optional<OrderInfo> findOrderInfoByOrderIdOrderByDtDesc(String orderId);
Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt);
}
......@@ -36,6 +36,9 @@ public class DispatchOrder implements Serializable {
@Column(name = "order_id")
private String orderId;
@Column(name = "dt")
private String dt;
@Column(name = "x")
private String X;
......@@ -76,6 +79,14 @@ public class DispatchOrder implements Serializable {
@Column(name = "time_end")
private LocalDateTime timeEnd;
//到达耗时(分钟)
@Column(name = "path_time")
private Integer pathTime;
//到达距离(米)
@Column(name = "path_distance")
private Integer pathDistance;
private String status;
private String ext;
......
......@@ -28,7 +28,10 @@ public class OrderInfo implements Serializable {
@Column(name = "order_id")
private String orderId;
private java.sql.Date dt;
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dt;
@Column(name = "sub_id")
private String subId;
......
......@@ -21,6 +21,8 @@ public class Customer {
private long id;
private String code;
// orderid(code)+dt 确定唯一一条工单
private String dt;
@JsonIgnore
private Location location;
// 时间窗 分钟
......@@ -45,10 +47,11 @@ public class Customer {
public Customer() {
}
public Customer(long id, String code, 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) {
this.id = id;
this.code = code;
this.dt = dt;
this.location = location;
this.startTime = startTime;
this.endTime = endTime;
......@@ -116,7 +119,7 @@ public class Customer {
}
/**
* 与前一个订单或者出发地depot的距离
* 与前一个订单或者出发地depot的距离(米)
*
* @return
*/
......@@ -132,7 +135,7 @@ public class Customer {
}
/**
* 与前一个订单或者出发地depot的路程时间
* 与前一个订单或者出发地depot的路程时间(分钟)
*
* @return
*/
......@@ -168,16 +171,17 @@ public class Customer {
return "Customer{" +
"id=" + id +
", code='" + code + '\'' +
", dt='" + dt + '\'' +
", location=" + location +
", startTime=" + startTime +
", endTime=" + endTime +
", serviceDuration=" + serviceDuration +
", requiredSkill='" + requiredSkill + '\'' +
", technician=" + ((technician!=null) ? technician.getCode() : "null") +
", technician=" + ((technician != null) ? technician.getCode() : "null") +
", previousCustomer=" + ((previousCustomer != null) ? previousCustomer.getCode() : "null") +
", nextCustomer=" + ((nextCustomer != null) ? nextCustomer.getCode() : "null") +
", arrivalTime=" + arrivalTime +
", departureTime=" + ((getDepartureTime() != null )? getDepartureTime() : 0) +
", departureTime=" + ((getDepartureTime() != null) ? getDepartureTime() : 0) +
'}';
}
}
......@@ -19,9 +19,7 @@ public interface ExtractService {
/*
* 将dispath_order 中的计算结果,回写到 order_request, order_appointment
* order_appointment(新增、更新)
* order_request(主要更新状态)
* 将dispath_order 中的计算结果,回写到 order_info
* */
void extractDispatchToOrder(String groupId, String batchNo, boolean isConfirm) ;
......
......@@ -16,7 +16,9 @@ import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
......@@ -34,7 +36,6 @@ import static org.springframework.transaction.annotation.Isolation.READ_COMMITTE
@Service
public class ExtractServiceImpl implements ExtractService {
@Autowired
EngineerInfoRepository engineerInfoRepo;
......@@ -60,9 +61,8 @@ public class ExtractServiceImpl implements ExtractService {
/**
* 将dispath_order 中的计算结果,回写到 order_request, order_appointment
* order_appointment(新增、更新)
* order_request(主要更新状态)
* 将dispath_order 中的计算结果,回写到 order_info
* order_info(主要更新状态)
*/
@Transactional(isolation = READ_COMMITTED, propagation = Propagation.REQUIRED)
@Override
......@@ -82,11 +82,13 @@ public class ExtractServiceImpl implements ExtractService {
int idx = atomicInteger.getAndIncrement();
String orderId = dispatchOrder.getOrderId();
String engCode = dispatchOrder.getEngineerCode();
log.info("算法结果更新到工单, step1.1-loop, {}/{}, groupId:{}, batchNo:{}, orderId:{}, engCode:{}",
idx, dispatchOrderList.size(), groupId, batchNo, orderId, engCode);
String dt = dispatchOrder.getDt();
log.info("算法结果更新到工单, step1.1-loop, {}/{}, groupId:{}, batchNo:{}, orderId:{}, dt:{}, engCode:{}",
idx, dispatchOrderList.size(), groupId, batchNo, orderId, dt, engCode);
Optional<OrderInfo> orderOpt = orderInfoRepo.findOrderInfoByOrderIdOrderByDtDesc(orderId);
if (!orderOpt.isPresent()) {
LocalDate localDt = LocalDate.parse(dt, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Optional<OrderInfo> orderOpt = orderInfoRepo.findOrderInfoByOrderIdAndDt(orderId, localDt);
if (orderOpt.isEmpty()) {
log.warn("算法结果更新到工单, step1.1-loop, 工单不存在, groupId:{}, batchNo:{}, orderId:{}",
groupId, batchNo, orderId);
return;
......@@ -121,15 +123,13 @@ public class ExtractServiceImpl implements ExtractService {
age = DateUtil.age(birthDate.toJdkDate(), DateUtil.date());
}*/
if ("NOT_ASSIGNED".equals(orderInfo.getAppointmentStatus())) {
jdbcTemplate.update("update order_request set appointment_status ='ASSIGNED' where order_id =? and appointment_status='NOT_ASSIGNED'", orderId);
}
orderInfo.setEngineerCode(engCode);
orderInfo.setEngineerName(engName);
orderInfo.setEngineerPhone(phone);
orderInfo.setPlanStartTime(dispatchOrder.getTimeBegin());
orderInfo.setPlanEndTime(dispatchOrder.getTimeEnd());
orderInfo.setArriveElapsed(dispatchOrder.getPathTime());
orderInfo.setArriveDistance(dispatchOrder.getPathDistance());
orderInfo.setAppointmentStatus(isConfirm ? "CONFIRM" : "PRE");
orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo);
......
package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import com.dituhui.pea.dispatch.common.GeoDistanceCalculator;
import com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider;
import com.dituhui.pea.dispatch.dao.DispatchEngineerRepository;
import com.dituhui.pea.dispatch.dao.DispatchOrderRepository;
import com.dituhui.pea.dispatch.dao.OrderLogRepository;
import com.dituhui.pea.dispatch.dao.OrgGroupRepository;
import com.dituhui.pea.dispatch.entity.DispatchOrder;
import com.dituhui.pea.dispatch.entity.OrderLog;
import com.dituhui.pea.dispatch.entity.OrgGroup;
import com.dituhui.pea.dispatch.pojo.*;
import com.dituhui.pea.dispatch.service.ExtractService;
import com.dituhui.pea.dispatch.service.SolveService;
import com.dituhui.pea.dispatch.utils.DispatchSolutionUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.util.FileUtil;
import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory;
import org.optaplanner.core.config.solver.SolverConfig;
......@@ -29,12 +23,11 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
......@@ -77,9 +70,7 @@ public class SolveServiceImpl implements SolveService {
// 查询技术员所有技能集
private List<String> queryEngineerSkills(String engineerCode) {
String sql = "select concat( b.brand, '-', b.type, '-', b.skill) as skill from engineer_skill_group a left join skill_info b \n" +
" on a.skill_group_code= b.skill_group_code where a.engineer_code=? and a.status=1 \n" +
" and b.brand is not null ";
String sql = "select concat( b.brand, '-', b.type, '-', b.skill) as skill from engineer_skill_group a left join skill_info b \n" + " on a.skill_group_code= b.skill_group_code where a.engineer_code=? and a.status=1 \n" + " and b.brand is not null ";
Object[] param = {engineerCode};
return jdbcTemplate.queryForList(sql, param, String.class);
}
......@@ -141,8 +132,7 @@ public class SolveServiceImpl implements SolveService {
order.setPriority(0);
}
Customer customer = new Customer(order.getId(), order.getOrderId(), location, start, end,
order.getSkills(), order.getTakeTime());
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime());
customerList.add(customer);
});
......@@ -170,9 +160,7 @@ public class SolveServiceImpl implements SolveService {
preferedLoctionDistanceMap.put(customer.getCode(), distance);
});
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(),
engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, depot,
60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap);
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, depot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap);
technicianList.add(vehicle);
});
......@@ -185,8 +173,7 @@ public class SolveServiceImpl implements SolveService {
DispatchSolution solution = new DispatchSolution(groupId, batchNo, locationList, oneDepot, technicianList, customerList);
distanceCalculator.initDistanceMaps(locationList);
log.info("组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}",
groupId, batchNo, technicianList.size(), customerList.size(), locationList.size());
log.info("组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}", groupId, batchNo, technicianList.size(), customerList.size(), locationList.size());
return solution;
......@@ -203,11 +190,10 @@ public class SolveServiceImpl implements SolveService {
// Load the problem
DispatchSolution problem = prepareSolution(groupId, batchNo);
if (problem.getCustomerList().size() <= 0) {
log.info("dispatchRun 当前批次没有待指派工单 , group:{}, batch:{}, order-size:{}", groupId, batchNo, problem.getCustomerList().size());
log.info("dispatchRun 当前批次没有待指派工单 , group:{}, batch:{}, order-size:{}", groupId, batchNo, 0);
throw new RuntimeException("当前批次没有待指派工单");
}
SolverConfig solverConfig = new SolverConfig().withSolutionClass(DispatchSolution.class);
solverConfig.withEntityClassList(Arrays.asList(Technician.class, Customer.class));// 这里不能漏掉,否则约束不生效
solverConfig.withConstraintProviderClass(DispatchConstraintProvider.class);
......@@ -221,8 +207,7 @@ public class SolveServiceImpl implements SolveService {
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
log.info("调用引擎处理-结束, groupId:{}, batchNo:{}, score:{}", groupId, batchNo, solution.getScore());
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(
DispatchSolution.class);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
String fileName = String.format("dispatchSolution-%s-%s.json", groupId, batchNo);
exporter.write(solution, new File(fileName));
......@@ -288,47 +273,36 @@ public class SolveServiceImpl implements SolveService {
log.info("算法结果回写dispatch, step1-清除历史, groupId:{}, batchNo:{}", groupId, batchNo);
Object[] paramClear = {groupId, batchNo};
String sqlReset = "update dispatch_order set engineer_code='', seq=0, time_begin=null, time_end=null where group_id=? and batch_no=? and status!='CONFIRM' ";
String sqlReset = "update dispatch_order set engineer_code='', seq=0, time_begin=null, time_end=null, path_time=0, path_distance=0 " + "where group_id=? and batch_no=? and status!='CONFIRM' ";
jdbcTemplate.update(sqlReset, paramClear);
log.info("算法结果回写dispatch, step2-开始回写, groupId:{}, batchNo:{}", groupId, batchNo);
// 保存当前批次指派结果
solution.getTechnicianList().forEach(technician -> {
log.info("算法结果回写dispatch, step2.1-按技术员逐个回写, groupId:{}, batchNo:{}, technician: {}, max-minute:{}, customlist.size:{}",
groupId, batchNo, technician.getCode(), technician.getMaxMinute(), technician.getCustomerList().size());
log.info("算法结果回写dispatch, step2.1-按技术员逐个回写, groupId:{}, batchNo:{}, technician: {}, max-minute:{}, customlist.size:{}", groupId, batchNo, technician.getCode(), technician.getMaxMinute(), technician.getCustomerList().size());
AtomicInteger seq = new AtomicInteger();
technician.getCustomerList().forEach(customer -> {
int idx = seq.getAndIncrement();
// 统计按8:00开始 +take_time + 20分钟路程向后累积
Optional<DispatchOrder> optional = dispatchOrderRepo.findByGroupIdAndBatchNoAndOrderId(groupId, batchNo, customer.getCode());
if (optional.isPresent()) {
DispatchOrder dOrder = optional.get();
// 时间相加操作
// LocalDateTime localExpectBegin = LocalDateTime.ofInstant(expectBegin[0].toInstant(), ZoneId.systemDefault());
// LocalDateTime localEndTime = localExpectBegin.plusMinutes(dOrder.getTakeTime());
// Date end = Date.from(localEndTime.atZone(ZoneId.systemDefault()).toInstant());
// LocalDateTime localExpectBegin = LocalDateTime.ofInstant(expectBegin[0].toInstant(), ZoneId.systemDefault());
// LocalDateTime localEndTime = localExpectBegin.plusMinutes(dOrder.getTakeTime());
// Date end = Date.from(localEndTime.atZone(ZoneId.systemDefault()).toInstant());
log.info("算法结果回写dispatch, step3-逐个客户处理, groupId:{}, batchNo:{}, employ: {}, customer:{}, service-duration:{} ",
groupId, batchNo, technician.getCode(), customer.getCode(), customer.getServiceDuration());
log.info("算法结果回写dispatch, step3-逐个客户处理, groupId:{}, batchNo:{}, employ: {}, customer:{}, service-duration:{} ", groupId, 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 arriveTime = customDateTime.plusMinutes(customer.getArrivalTime());
LocalDateTime leaveTime = customDateTime.plusMinutes(customer.getDepartureTime());
Date arriveTime = DateUtil.beginOfDay(dOrder.getExpectTimeBegin()).offset(DateField.MINUTE, customer.getArrivalTime());
Date leaveTime = DateUtil.beginOfDay(dOrder.getExpectTimeBegin()).offset(DateField.MINUTE, customer.getDepartureTime());
Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, groupId, batchNo, customer.getCode()};
String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=? where group_id=? and batch_no=? and order_id=? and status!='CONFIRM' ";
int pathTime = customer.getPathTimeFromPreviousStandstill();
long pathDistance = customer.getDistanceFromPreviousStandstill();
String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=?, path_time=?, path_distance=? " + " where group_id=? and batch_no=? and order_id=? and dt=? and status!='CONFIRM' ";
Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, pathTime, pathDistance, groupId, batchNo, customer.getCode(), customer.getDt()};
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);
});
......
......@@ -264,7 +264,7 @@ public class DataUtils {
// 初始化订单+技能服务时间
List<Customer> customerList = new ArrayList<>();
for (int i = 0; i < customerIndexMap.keySet().size(); i++) {
customerList.add(new Customer(i + 1, customerIndexMap.get(i + 1), locationIndex.get(i + 2),
customerList.add(new Customer(i + 1, customerIndexMap.get(i + 1), "2000-01-01", locationIndex.get(i + 2),
customerStartMap.get(i + 1), customerEndMap.get(i + 1), customerSkillMap.get(i + 1),
// 初始化技能服务时间
customerCodeServiceTimeMap.get(customerIndexMap.get(i + 1))));
......
......@@ -42,7 +42,7 @@ class SolveServiceTest {
ExtractService extractService;
String groupId = "gsuzhou";
String day = "2023-03-20";
String day = "2023-07-23";
private SolverManager<DispatchSolution, UUID> solverManager;
private SolverFactory<DispatchSolution> solverFactory;
......@@ -53,7 +53,7 @@ class SolveServiceTest {
SolverConfig solverConfig = new SolverConfig().withSolutionClass(DispatchSolution.class);
solverConfig.withEntityClassList(Arrays.asList(Technician.class, Customer.class));// 这里不能漏掉,否则约束不生效
solverConfig.withConstraintProviderClass(DispatchConstraintProvider.class);
solverConfig.withTerminationSpentLimit(Duration.ofSeconds(10));
solverConfig.withTerminationSpentLimit(Duration.ofSeconds(5));
solverFactory = SolverFactory.create(solverConfig);
solver = solverFactory.buildSolver();
......@@ -81,7 +81,17 @@ class SolveServiceTest {
solveService.saveSolutionWrp(solution);
extractService.extractDispatchToOrder(groupId, batchNo, false);
log.info("testAsync done");
}
@Test
public void testExtraceToOrder() throws InterruptedException {
log.info("testExtraceToOrder init");
String batchNo = "20230723-0810";
extractService.extractDispatchToOrder(groupId, batchNo, false);
log.info("testExtraceToOrder done");
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!