Commit 0a89d6ba by 刘鑫

Merge branch 'develop' of https://gitlab.dituhui.com/bsh/project/project into develop

2 parents f18ddae4 a32bf84c
......@@ -197,4 +197,25 @@ public class OrderInfo implements Serializable {
@Column(name = "update_time")
private LocalDateTime updateTime;
/**
* 是否重物搬运(双人上门) 0:否 1:是 默认0
*/
@Column(name = "is_multiple")
private Integer isMultiple = 0;
/**
* 是否指定某个工程师/是否排除某个工程师 0:否 1:指定 2:排除 默认0
*/
@Column(name = "is_appoint_engineer")
private Integer isAppointEngineer = 0;
/**
* 指定某个工程师/排除某个工程师 codes 多个,分割
*/
@Column(name = "appoint_engineer_codes")
private String appointEngineerCodes;
}
package com.dituhui.pea.dispatch.quartz.engineerCapacity;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.common.DateUtil;
import com.dituhui.pea.dispatch.common.DateUtils;
import com.dituhui.pea.dispatch.common.OccupyInfoDetail;
......@@ -189,7 +190,7 @@ public class InitEngineerCapacityScheduler {
// 初始化一个工程师、一天的容量
CapacityEngineerStatEntity statEntity = capacityEngineerStatDao.getByWorkdayAndEngineerCode(date, engineerCode);
if (statEntity != null && !rewriteForce) {
log.error("技术员容量信息记录已存在, 直接返回");
log.error("技术员容量信息记录(engineer: {}, date:{})已存在, 直接返回", engineerCode, date);
return;
}
log.info("日期[{}] 技术员[{}] 有日历记录需要特别处理 ===", date, engineerCode);
......@@ -212,10 +213,11 @@ public class InitEngineerCapacityScheduler {
}
public void initOneEngineerByDays(String bdate, String edate, String branchId) {
LocalDate currentDate = DateUtils.localDateFromStr(bdate);
LocalDate endDate = DateUtils.localDateFromStr(edate);
List<String> allEngineerCodes = engineerInfoDao.getAllByBranchId(branchId).stream().map(EngineerInfo::getEngineerCode).collect(Collectors.toList());
for(String engineerCode: allEngineerCodes){
log.warn(">>> 分部工程师容量初始化开始,branchId: {},工程师数量:{}", branchId, allEngineerCodes.size());
for (String engineerCode : allEngineerCodes) {
LocalDate currentDate = DateUtils.localDateFromStr(bdate);
LocalDate endDate = DateUtils.localDateFromStr(edate);
while (!currentDate.isAfter(endDate)) {
initOneEngineer(DateUtils.formatDate(currentDate), engineerCode);
currentDate = currentDate.plusDays(1);
......
......@@ -84,7 +84,7 @@ public class SchedulerServiceImpl implements SchedulerService {
return;
}
OrgGroup orgGroup=orgGroupRepository.findByGroupId(orgTeamEntity.getGroupId()).get();
OrgGroup orgGroup = orgGroupRepository.findByGroupId(orgTeamEntity.getGroupId()).get();
if (ObjectUtil.equals(2, orgGroup.getCategory())) {
log.error(">>> teamId:{} 来自网点,不自动派工", teamId);
......@@ -97,6 +97,7 @@ public class SchedulerServiceImpl implements SchedulerService {
}
LocalDateTime now = LocalDateTime.now();
String today = DateUtil.format(now, "yyyy-MM-dd");
String nowTime = DateUtil.format(now, "HH:mm");
String nowTimePlus30 = DateUtil.format(now.plusMinutes(30), "HH:mm");
......@@ -109,10 +110,13 @@ public class SchedulerServiceImpl implements SchedulerService {
String groupId = orgTeamEntity.getGroupId();
log.info("dispatchRun group:{}, team:{} done", groupId, teamId);
for (int i = 1; i <= nextDaysLimit; i++) {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
Optional<DispatchBatch> optional = dispatchBatchRepository.findByTeamIdAndBatchDate(teamId, currDay);
if (optional.isPresent() && Objects.nonNull(optional.get().getCutoffedTime())) {
if (optional.isPresent()
&& Objects.nonNull(optional.get().getCutoffedTime())
&& today.equals(DateUtil.format(optional.get().getCutoffedTime(), "yyyy-MM-dd"))) {
//自动任务截止
log.error(">>> teamId:{}, day:{} 自动任务已截止", teamId, currDay);
continue;
......
package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
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.OrgGroupRepository;
import com.dituhui.pea.dispatch.dao.OrgTeamDao;
import com.dituhui.pea.dispatch.dao.*;
import com.dituhui.pea.dispatch.entity.DispatchOrder;
import com.dituhui.pea.dispatch.entity.OrderInfo;
import com.dituhui.pea.dispatch.entity.OrgGroup;
import com.dituhui.pea.dispatch.entity.OrgTeamEntity;
import com.dituhui.pea.dispatch.pojo.*;
......@@ -59,6 +58,9 @@ public class SolveServiceImpl implements SolveService {
DispatchOrderRepository dispatchOrderRepo;
@Autowired
private OrderInfoRepository orderInfoRepository;
@Autowired
OrgGroupRepository groupRepository;
......@@ -252,6 +254,17 @@ public class SolveServiceImpl implements SolveService {
}
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime());
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);
}
customerList.add(customer);
});
......
......@@ -3,7 +3,7 @@ server:
dispatch:
cron:
expr: 0 14 8-22 * * ?
expr: 0 55 8-22 * * ?
next-day-limit: 2
# expr: 0 */10 8-18 * * ?
......@@ -11,9 +11,9 @@ scheduler:
init-engineer-capacity:
# 每天22点1次
#cron-expr: 0 0 22 * * ?
cron-expr: 0 29 * * * ?
cron-expr: 0 51 * * * ?
day-offset-begin: 0
day-offset-end: 14
day-offset-end: 20
rewrite-force: true
calc-engineer-capacity:
......@@ -49,12 +49,12 @@ spring:
enabled: false
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username: root
password: 123456
# url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
# username: boxi
# password: boxi_dev_0725
# url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
# username: root
# password: 123456
url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username: boxi
password: boxi_dev_0725
type: com.alibaba.druid.pool.DruidDataSource
jpa:
......
......@@ -73,6 +73,24 @@
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异常文件输出设置,将异常堆栈另外保存一份到单独的文件中,方便查找 -->
<appender name="FILE_WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_FILE}/warn/${spring.application.name:-}.warn.log</File>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_FILE}/warn/${spring.application.name:-}.warn-%d{yyyy-MM-dd}-%i.zip
</FileNamePattern>
<maxFileSize>${LOG_MAXFILESIZE}</maxFileSize>
<maxHistory>${LOG_FILEMAXDAY}</maxHistory>
<totalSizeCap>500MB</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印警告日志 -->
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
......@@ -118,6 +136,7 @@
<appender-ref ref="console"/>
<appender-ref ref="FileAppender"/>
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_WARN"/>
</root>
</configuration>
\ No newline at end of file
......@@ -13,7 +13,9 @@ import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/pea-order")
......@@ -54,13 +56,15 @@ public class OrderAssignController {
@PostMapping("/order/assign/list")
public Result<?> orderAssign(@RequestBody List<OrderAssignReq> assignReqList) {
// 服务单指派-指派提交
try {
for (OrderAssignReq assignReq : assignReqList) {
orderAssign.orderAssign(assignReq);
Map<String, Result> resultMap = new HashMap<>();
for (OrderAssignReq assignReq : assignReqList) {
// 服务单指派-指派提交
try {
Result result = orderAssign.orderAssign(assignReq);
resultMap.put(assignReq.getOrderId(), result);
} catch (BusinessException e) {
resultMap.put(assignReq.getOrderId(), Result.failed(e.getMessage()));
}
} catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success();
}
......@@ -89,6 +93,19 @@ public class OrderAssignController {
return res;
}
@GetMapping("/order/rescheduling/reason")
public Result<?> orderReschedulingReason() {
// 订单改约原因
Result<?> res = null;
try {
res = orderInfoService.orderReschedulingReason();
} catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return res;
}
/**
* 批量改约
*
......@@ -97,14 +114,16 @@ public class OrderAssignController {
*/
@PostMapping("/order/rescheduling/list")
public Result<?> orderRescheduling(@RequestBody List<OrderReschedule> rescheduleList) {
// 订单改约
try {
for (OrderReschedule reschedule : rescheduleList) {
orderInfoService.orderReschedule(reschedule);
Map<String, Result> resultMap = new HashMap<>();
for (OrderReschedule reschedule : rescheduleList) {
// 订单改约
try {
Result result = orderInfoService.orderReschedule(reschedule);
resultMap.put(reschedule.getOrderId(), result);
} catch (BusinessException e) {
resultMap.put(reschedule.getOrderId(), Result.failed(e.getMessage()));
}
} catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success();
return Result.success(resultMap);
}
}
......@@ -4,6 +4,7 @@ import com.dituhui.pea.order.dto.param.Location;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.List;
@Data
public class OrderReschedule {
......@@ -47,5 +48,8 @@ public class OrderReschedule {
*/
private String reschedulingReason;
/**
* 标签
*/
private List<String> orderTags;
}
......@@ -219,6 +219,7 @@ public class OrderDTO {
*/
private String reschedulingReason;
private List<String> orderTags;
}
/**
......
......@@ -44,4 +44,11 @@ public interface OrderInfoService {
* @return
*/
Result<?> orderReschedule(OrderReschedule req);
/**
* 改约原因
*
* @return
*/
Result<?> orderReschedulingReason();
}
......@@ -278,11 +278,11 @@ public class DispatchServiceImpl implements DispatchService {
EngineerInfoEntity engineer = engineerInfoDao.getByEngineerCode(engineerCode);
if (engineer == null) {
throw new BusinessException("技术员不存在");
return Result.failed("技术员不存在");
}
List<OrderInfoEntity> orders = orderInfoDao.findAllByDtAndOrderIdIn(localDate, orderIds);
if (ListUtils.isEmpty(orders)) {
throw new BusinessException("订单不存在");
return Result.failed("订单不存在");
}
List<OrgTeamEngineerEntity> orgTeamEngineers = orgTeamEngineerDao.findByEngineerCode(engineer.getEngineerCode());
......@@ -292,6 +292,9 @@ public class DispatchServiceImpl implements DispatchService {
OrgTeamEntity byTeamId = orgTeamDao.getByTeamId(orgTeamEngineers.get(0).getTeamId());
for (OrderInfoEntity entity : orders) {
if (entity.getEngineerCode().equals(engineer.getEngineerCode())) {
return Result.failed(String.format("订单已指派个技术员[%s], 不必重复指派给同一个技术员", engineer.getName()));
}
SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(CommonUtil.fixBrand(entity.getBrand()), entity.getType(), entity.getSkill());
entity.setTakeTime(skill.getTakeTime());
entity.setPlanStartTime(entity.getExpectTimeBegin());
......@@ -596,7 +599,7 @@ public class DispatchServiceImpl implements DispatchService {
//过滤
List<OrderInfoEntity> orders = records.stream()
.filter(r -> r.getOrderStatus().equals("NORMAL"))
.filter(r -> !r.getOrderStatus().equals(OrderStatusEnum.CANCELED))
.collect(Collectors.toList());
return orders.stream().collect(Collectors.groupingBy(OrderInfoEntity::getEngineerCode));
......
......@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.common.ResultEnum;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.OrderAssignCheck;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.dao.*;
......@@ -13,6 +14,7 @@ import com.dituhui.pea.order.dto.param.Location;
import com.dituhui.pea.order.dto.param.OrderDTO;
import com.dituhui.pea.order.dto.param.OrgTeamInfo;
import com.dituhui.pea.order.entity.*;
import com.dituhui.pea.order.enums.AppointmentMethodEnum;
import com.dituhui.pea.order.enums.OrderFlowEnum;
import com.dituhui.pea.order.enums.OrderStatusEnum;
import com.dituhui.pea.order.enums.ServiceStatusEnum;
......@@ -22,6 +24,7 @@ import com.dituhui.pea.pojo.saas.req.AdministrativeDistrictReq;
import com.dituhui.pea.pojo.saas.resp.AdministrativeDistrictResp;
import com.dituhui.pea.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -154,41 +157,38 @@ public class OrderAssignImpl implements OrderAssign {
public Result<?> orderAssign(OrderAssignReq req) throws BusinessException {
// 服务单指派-指派提交
OrderInfoEntity order = orderInfoDao.getByOrderId(req.getOrderId());
if (order == null) {
throw new BusinessException("订单不存在");
OrderInfoEntity entity = orderInfoDao.getByOrderId(req.getOrderId());
if (entity == null) {
return Result.failed("订单不存在");
}
EngineerInfoEntity engineer = engineerInfoDao.getByEngineerCode(req.getEngineerCode());
boolean record = false;
OrderInfoEntity op = orderInfoDao.getByOrderIdAndDt(req.getOrderId(), order.getDt());
if (op != null) {
record = true;
List<OrgTeamEngineerEntity> orgTeamEngineers = orgTeamEngineerDao.findByEngineerCode(engineer.getEngineerCode());
if (CollectionUtils.isEmpty(orgTeamEngineers)) {
return Result.failed(StatusCodeEnum.TEAM_UNMATCHED);
}
OrgTeamEntity byTeamId = orgTeamDao.getByTeamId(orgTeamEngineers.get(0).getTeamId());
if (op != null && !order.getAppointmentStatus().equals("NOT_ASSIGNED") && op.getEngineerCode().equals(req.getEngineerCode())) {
if (entity != null && !entity.getAppointmentStatus().equals("NOT_ASSIGNED") && entity.getEngineerCode().equals(req.getEngineerCode())) {
throw new BusinessException(String.format("订单已指派个技术员[%s], 不必重复指派给同一个技术员", engineer.getName()));
}
// OrderAssignCheck.Result result = orderAssignCheck.orderAssignCheck(orderId, order.getDt(), engineerCode);
// log.info("指派检查结果:{}", result);
// if (result.getIndex() < 0) {
// throw new BusinessException("指派失败, 未能找到合适的时间段, 请选择其他技术员");
// }
// OrderAssignCheck.OrderNode insertNode = result.getCurOrderNode();
// Timestamp planStartTime = Timestamp.valueOf(insertNode.getPlanStartTime());
// Timestamp planEndTime = Timestamp.valueOf(insertNode.getPlanEndTime());
// 更新order_info表状态
// String sql = "UPDATE OrderInfo e SET e.appointmentStatus = 'CONFIRM', e.appointmentMethod='MANUAL', e.planStartTime = :planStartTime, e.planEndTime = :panEndTime WHERE e.orderId = :orderId";
// Query query = entityManager.createQuery(sql);
// query.setParameter("planStartTime", planStartTime);
// query.setParameter("planEndTime", planEndTime);
// query.setParameter("orderId", orderId);
// query.executeUpdate();
order.setEngineerCode(engineer.getEngineerCode());
orderInfoDao.save(order);
SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(CommonUtil.fixBrand(entity.getBrand()), entity.getType(), entity.getSkill());
entity.setTakeTime(skill.getTakeTime());
entity.setPlanStartTime(entity.getExpectTimeBegin());
entity.setPlanEndTime(entity.getExpectTimeBegin().plusMinutes(skill.getTakeTime()));
entity.setEngineerCode(engineer.getEngineerCode());
entity.setEngineerName(engineer.getName());
entity.setEngineerPhone(engineer.getPhone());
entity.setAppointmentStatus(OrderFlowEnum.CONFIRM.name());
entity.setAppointmentMethod(AppointmentMethodEnum.MANUAL.name());
entity.setOrgTeamId(byTeamId.getTeamId());
entity.setOrgBranchId(byTeamId.getBranchId());
entity.setOrgClusterId(byTeamId.getClusterId());
orderInfoDao.save(entity);
// entity.setEngineerCode(engineer.getEngineerCode());
// orderInfoDao.save(order);
// 工单变更登记
commonService.addOrderEvent(req.getOrderId(), "", "PEA-WEB", req.getOperator(), OrderStatusEnum.ASSIGN.getDescription(), OrderStatusEnum.ASSIGN.getDescription(), "");
......
......@@ -421,13 +421,13 @@ public class OrderCreateServiceImpl implements OrderCreateService {
entity.setTakeTime(skillInfoEntity.getTakeTime());
String joinTags = CollectionUtils.isEmpty(req.getOrderTags()) ? "" : String.join(",", req.getOrderTags());
entity.setBeanTags(joinTags);
entity.setIsMultiple(joinTags.contains("重物搬运") ? 1 : 0);
entity.setBeanPriority(req.getPriority());
if (req.getPriority().equals("1")) {
entity.setAppointmentMethod(AppointmentMethodEnum.AUTO_NOW.name());
//发送通知分部消息
// sendMsg(entity.getOrgBranchId(), orderId, entity.getExpectTimeBegin().toLocalDate());
}
entity.setIsMultiple(joinTags.contains("重物搬运") ? 1 : 0);
//一家多单
Result<String> addMultipleOrders = orderInfoService.addMultipleOrders(entity.getDt(), location.getAddressId(), orderId);
......
......@@ -7,6 +7,7 @@ import com.dituhui.pea.common.Result;
import com.dituhui.pea.common.ResultEnum;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.constant.OrderReschedulingReason;
import com.dituhui.pea.order.dao.*;
import com.dituhui.pea.order.dto.MsgDTO;
import com.dituhui.pea.order.dto.OrderReschedule;
......@@ -182,6 +183,7 @@ public class OrderInfoServiceImpl implements OrderInfoService {
reschedule.setProductType(request.getProductType());
reschedule.setServiceType(request.getServiceType());
reschedule.setReschedulingReason(request.getReschedulingReason());
reschedule.setOrderTags(request.getOrderTags());
reschedule.setExpectBegin(DateUtil.handleDate(request.getNewReservationTime(), orderInfo.getExpectTimeBegin()));
reschedule.setExpectEnd(DateUtil.handleDate(request.getNewReservationTime(), orderInfo.getExpectTimeEnd()));
if (StringUtils.isNotBlank(request.getDescription())) {
......@@ -220,6 +222,21 @@ public class OrderInfoServiceImpl implements OrderInfoService {
order.setExpectTimeDesc(req.getExpectDesc());
order.setOrderStatus(OrderStatusEnum.RESCHEDULED.getCode());
boolean skillUpdate = false;
if (CollectionUtils.isEmpty(req.getOrderTags())) {
if (StringUtils.isBlank(order.getBeanTags())) {
String joinTags = CollectionUtils.isEmpty(req.getOrderTags()) ? "" : String.join(",", req.getOrderTags());
order.setBeanTags(joinTags);
order.setIsMultiple(joinTags.contains("重物搬运") ? 1 : 0);
} else {
for (String orderTag : req.getOrderTags()) {
if (order.getBeanTags().contains(orderTag)) {
continue;
}
order.setBeanTags(order.getBeanTags() + "," + orderTag);
}
order.setIsMultiple(order.getBeanTags().contains("重物搬运") ? 1 : 0);
}
}
if (StringUtils.isNotBlank(req.getBrand()) && !CommonUtil.fixBrand(req.getBrand()).equals(order.getBrand())) {
order.setBrand(CommonUtil.fixBrand(req.getBrand()));
skillUpdate = true;
......@@ -290,7 +307,7 @@ public class OrderInfoServiceImpl implements OrderInfoService {
// i.自有:优先改约指派给当前工程师
// ii.网点:优先改约指派给当前网点
// (不给当前工程师)
if (!isToday && isBelong && skillUpdate) {
if (!isToday && isBelong && skillUpdate && order.getIsAppointEngineer() != 1) {
//地址变更需要从新分单
order = orderFendan(order, req, location);
clusterId = order.getOrgClusterId();
......@@ -370,6 +387,11 @@ public class OrderInfoServiceImpl implements OrderInfoService {
return Result.success(null);
}
@Override
public Result<?> orderReschedulingReason() {
return Result.success(OrderReschedulingReason.ReschedulingReasonMap);
}
/**
* 订单重新分单
*
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!