package com.repair.controller; import com.repair.common.utils.*; import com.repair.config.WxOpenidConfig; import com.repair.model.pojo.*; import com.repair.model.vo.*; import com.repair.services.*; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @Component //@EnableAsync public class ScheduleController { /** * @Scheduled注解会在默认情况下以单线程的方式执行定时任务。 这个“单线程”指两个方面: * 如果一个定时任务执行时间大于其任务间隔时间,那么下一次将会等待上一次执行结束后再继续执行。 * 如果多个定时任务在同一时刻执行,任务会依次执行。 * @Async:对某个方法进行异步执行 * @EnableAsync:开启异步支持 */ @Autowired private WxOpenidConfig wxOpenidConfig; @Autowired private RepairUserService repairUserService; @Autowired private RepairRecordService repairRecordService; @Autowired private RepairEvaluateService repairEvaluateService; @Autowired private RepairTrackRecordService repairTrackRecordService; @Autowired private RepairArticleBuildService repairArticleBuildService; @Autowired private RepairRefundRecordService repairRefundRecordService; @Autowired private RepairShiftSettingsService repairShiftSettingsService; @Autowired private RepairSystemSettingService repairSystemSettingService; @Autowired private RepairSystemMessagesService repairSystemMessagesService; @Autowired private RepairDispatchRecordService repairDispatchRecordService; //定时格式参考:https://blog.csdn.net/java13992394428/article/details/108740453 /** * 每天八点自动派单 * 周六周日定时器不生效 * 其余时间都是早上八点前捞一遍当前时间以前的单子 * 有合适的维修师傅就把单子派给维修师傅 * 周一到周五早上七点执行:0 0 7 ? * MON-FRI * 周一到周五1、2、3、4、5、6、7、18、19、20、21、22点执行:0 0 1,2,3,4,5,6,7,18,19,20,21,22 ? * MON-FRI */ //每小时执行一次:0 0 */1 * * ? //每分钟执行一次:0 */1 * * * ? @Async @Scheduled(cron = "0 0 7 ? * MON-FRI ") //@Scheduled(cron = "0 */1 * * * ? ") @Transactional(rollbackFor = {Exception.class}) public void autoDispatch() throws Exception { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":自动派单进来执行了一次!"); /** * 读取未被派单的数据 * 拿到当前时间为止的所有未被派单的数据 */ List records = repairRecordService.queryPendingOrder(); //有待接单数据 if (records.size() >= 0) { Date nowDate = new Date(); String dateHour = new SimpleDateFormat("HH:mm").format(nowDate); String dateNow = new SimpleDateFormat("yyyy-MM-dd").format(nowDate); /** * 只获取当天排班和能接单的 * 获取维修师傅和郭班长的单子 */ List users = repairUserService.autoDispatchUser(dateNow); String shiftStr = StringUtils.join(users.stream().map(AutoDispatchUserVo::getShiftId).collect(Collectors.toList()), ","); List shifts = Arrays.asList(shiftStr.split(",")).stream().distinct().collect(Collectors.toList()); //只获取不是值班 或下班后的排班数据 List shiftDatas = repairShiftSettingsService.getRepairsShiftIdByHour(shifts, dateHour); //2023-11-03 A-jax 添加获取报修关联楼栋 List articleBuilds = new ArrayList<>(); if(users != null && users.size() > 0){ List userIds = users.stream().map(AutoDispatchUserVo::getId).collect(Collectors.toList()); articleBuilds = repairArticleBuildService.queryArticleBuild(StringUtils.join(userIds,",")); } List rdrs = new ArrayList<>(); List rsms = new ArrayList<>(); List rtrs = new ArrayList<>(); for (pendingOrderVo record : records) { //跟张总确认一下是不是到时候维修师傅会把所有楼栋都勾选上 List schoolUsers = new ArrayList<>(); for (AutoDispatchUserVo user:users) { long owner = articleBuilds != null && articleBuilds.size() > 0 ? articleBuilds.stream().filter(e -> e.getUserId() == user.getId() && ("," + e.getArticleId() + ",").contains("," + record.getArticleId() + ",") && ("," + e.getBuildId() + ",").contains("," + record.getBuildId() + ",")).count() : 0; if(owner > 0){ schoolUsers.add(user); } } schoolUsers.sort(Comparator.comparing(AutoDispatchUserVo::getRdrCount)); for (AutoDispatchUserVo user : schoolUsers) { List datas = shiftDatas.stream().filter(e -> ("," + user.getShiftId() + ",").contains("," + e.getId() + ",")).collect(Collectors.toList()); if (datas.size() <= 0) { continue; } Integer isDuty = 0; int acceptanceAssessTime = user.getAcceptanceTime(); try { //2023-10-08 看是否是值班时间接单 if (shiftDatas.size() > 0) { Optional shiftData = datas.stream().filter(e -> nowDate.before(TimeExchange.StringToDate(e.getEndTime(), "HH:mm"))).sorted(Comparator.comparing(RepairShiftSettings::getStartTime)).findFirst(); if (shiftData != null && shiftData.isPresent()) { if (shiftData.get().getIsDuty().intValue() == 1) { isDuty = 1; } } } //下班之后或者值班接的单不考核 将报修工单中的is_duty改为1 Date workTime = TimeExchange.StringToDate(dateNow + " " + datas.get(0).getEndTime() + ":00", "yyyy-MM-dd HH:mm:ss"); if (workTime.before(nowDate)) { isDuty = 1; } if (isDuty == 0) { //在工作时间才去派单 List tvs = DelayedUtils.timeVos(datas); //工作的时间是否够修完 临下班接的单不做延长 for (int i = 0; i < tvs.size(); i++) { Date startWorkTime = TimeExchange.StringToDate(dateNow + " " + tvs.get(i).getStart() + ":00", "yyyy-MM-dd HH:mm:ss"); Date endWorkTime = TimeExchange.StringToDate(dateNow + " " + tvs.get(i).getEnd() + ":00", "yyyy-MM-dd HH:mm:ss"); //小于工作时间段的开始时间 if (nowDate.before(startWorkTime) || nowDate.equals(startWorkTime) && i == 0) { //早上开始上班之前的单子 int minute = TimeExchange.getOffsetMinutes(nowDate, startWorkTime); int workMinte = TimeExchange.getOffsetMinutes(nowDate, endWorkTime); acceptanceAssessTime = acceptanceAssessTime + minute; acceptanceAssessTime = DelayedUtils.addMinuteStart(tvs, endWorkTime, acceptanceAssessTime, nowDate, dateNow, workMinte, i, 1); break; } else if ((startWorkTime.before(nowDate) || startWorkTime.equals(nowDate)) && (nowDate.before(endWorkTime) || nowDate.equals(endWorkTime))) { //工作时间段内的单子 int workMinte = TimeExchange.getOffsetMinutes(nowDate, endWorkTime); acceptanceAssessTime = DelayedUtils.addMinuteStart(tvs, endWorkTime, acceptanceAssessTime, nowDate, dateNow, workMinte, i, 1); break; } else { //非工作时间段的单子 Date nextStartWorkTime = TimeExchange.StringToDate(dateNow + " " + tvs.get(i + 1).getStart() + ":00", "yyyy-MM-dd HH:mm:ss"); if ((endWorkTime.before(nowDate) || endWorkTime.equals(nowDate)) && (nowDate.before(nextStartWorkTime) || nowDate.equals(nextStartWorkTime))) { Date nextEndWorkTime = TimeExchange.StringToDate(dateNow + " " + tvs.get(i + 1).getEnd() + ":00", "yyyy-MM-dd HH:mm:ss"); int minute = TimeExchange.getOffsetMinutes(nowDate, nextStartWorkTime); int workMinte = TimeExchange.getOffsetMinutes(nowDate, nextEndWorkTime); acceptanceAssessTime = acceptanceAssessTime + minute; acceptanceAssessTime = DelayedUtils.addMinuteStart(tvs, nextEndWorkTime, acceptanceAssessTime, nowDate, dateNow, workMinte, i, 2); break; } } } RepairDispatchRecord rdr = new RepairDispatchRecord(); //创建派单记录 rdr.setAssignedTime(new Date()); rdr.setAcceptanceAssessTime(acceptanceAssessTime); rdr.setOrderType(0); rdr.setIsLoseEfficacy(0); rdr.setUsersId(user.getId()); rdr.setRecordId(record.getId()); rdr.setCreateTime(new Date()); rdr.setUpdateTime(new Date()); rdr.setCreateUser("定时器自动派单"); rdr.setUpdateUser("定时器自动派单"); rdr.setDeleted(0); rdrs.add(rdr); user.setRdrCount(user.getRdrCount() + 1); //给用户的消息中心数据 RepairSystemMessages rsmU = new RepairSystemMessages(); rsmU.setRecordId(record.getId()); rsmU.setRecipientId(record.getUserId()); rsmU.setContent("工单已交给系统,系统将催促师傅师尽快接单!"); rsmU.setIsRead(0); rsmU.setCreateTime(new Date()); rsmU.setUpdateTime(new Date()); rsmU.setCreateUser("定时器自动派单"); rsmU.setUpdateUser("定时器自动派单"); rsmU.setDeleted(0); rsms.add(rsmU); //给师傅的消息中心数据 RepairSystemMessages rsmS = new RepairSystemMessages(); rsmS.setRecordId(record.getId()); rsmS.setRecipientId(user.getId()); rsmS.setContent("系统自动分配工单,请尽快处理!"); rsmS.setIsRead(0); rsmS.setCreateTime(new Date()); rsmS.setUpdateTime(new Date()); rsmS.setCreateUser("定时器自动派单"); rsmS.setUpdateUser("定时器自动派单"); rsmS.setDeleted(0); rsms.add(rsmS); //添加跟踪记录 RepairTrackRecord rtr = new RepairTrackRecord(); rtr.setRecordId(record.getId()); rtr.setMaintenanceState(1); rtr.setContent("已派单"); rtr.setUserId(0); rtr.setUserZzstr("系统自动派单"); rtr.setCreateTime(new Date()); rtr.setUpdateTime(new Date()); rtr.setCreateUser("定时器自动派单"); rtr.setUpdateUser("定时器自动派单"); rtr.setDeleted(0); rtrs.add(rtr); break; } } catch (Exception e) { System.out.println("自动派单失败:" + e.getMessage()); throw new Exception("自动派单失败!"); } } } try { boolean insertDis = repairDispatchRecordService.insertDispatchBatch(rdrs); if (!insertDis) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":存储派单数据异常!"); throw new Exception("自动派单失败!"); } boolean insertRsm = repairSystemMessagesService.inserBatchSystemMessage(rsms); if (!insertRsm) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":消息中心数据存储异常!"); throw new Exception("自动派单失败!"); } boolean insertRtr = repairTrackRecordService.insertTrackBatch(rtrs); if (!insertRtr) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":根据记录数据存储异常!"); throw new Exception("自动派单失败!"); } } catch (Exception e) { System.out.println("新增自动派单失败:" + e.getMessage()); throw new Exception("自动派单失败!"); } } System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":自动派单执行成功了一次!"); } /** * 每小时执行一次 * 自动好评定时器 * XX小时后未评价的订单 * 获取已完成没有好评数据的维修单数据,并且自动好评 * 好评完成之后在消息中心添加自动好评提示信息 * 发给维修师傅和用户 */ //每小时执行一次:0 0 */1 * * ? //每分钟执行一次:0 */1 * * * ? @Async @Scheduled(cron = "0 0 */1 * * ? ") @Transactional(rollbackFor = {Exception.class}) public void autoEvaluate() throws Exception { //读取系统设置表数据 没设置就不好评 RepairSystemSetting setting = repairSystemSettingService.queryRepairSystemSetting(); if (setting != null && setting.getHour() != null) { String dateStr = TimeExchange.TimeRangeHour(new Date(), -setting.getHour(), "yyyy-MM-dd HH:mm:ss"); List evaluates = repairEvaluateService.queryEvaluateList(dateStr); List res = new ArrayList<>(); List rsms = new ArrayList<>(); for (RecordEvaluateVo evaluate : evaluates) { RepairEvaluate re = new RepairEvaluate(); re.setRecordId(evaluate.getId()); re.setStar(5); re.setContent("自动好评"); re.setCreateTime(new Date()); re.setUpdateTime(new Date()); re.setCreateUser("定时器自动评价"); re.setUpdateUser("定时器自动评价"); re.setDeleted(0); res.add(re); RepairSystemMessages rsm = new RepairSystemMessages(); rsm.setRecordId(evaluate.getId()); rsm.setRecipientId(evaluate.getUserId()); rsm.setContent("维修单" + setting.getHour() + "小时内未评价,系统自动5星好评"); rsm.setIsRead(0); rsm.setCreateTime(new Date()); rsm.setUpdateTime(new Date()); rsm.setCreateUser("定时器自动评价"); rsm.setUpdateUser("定时器自动评价"); rsm.setDeleted(0); rsms.add(rsm); if (evaluate.getMaintenancerId() != null) { String[] userIds = evaluate.getMaintenancerId().split(","); for (int i = 0; i < userIds.length; i++) { RepairSystemMessages rsmSf = new RepairSystemMessages(); rsmSf.setRecordId(evaluate.getId()); rsmSf.setRecipientId(Integer.valueOf(userIds[i])); rsmSf.setContent("维修单二十四小时内未评价,系统自动5星好评"); rsmSf.setIsRead(0); rsmSf.setCreateTime(new Date()); rsmSf.setUpdateTime(new Date()); rsmSf.setCreateUser("定时器自动评价"); rsmSf.setUpdateUser("定时器自动评价"); rsmSf.setDeleted(0); rsms.add(rsmSf); } } } try { boolean insertRes = repairEvaluateService.inserBatchEvaluate(res); if (!insertRes) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":存储评价数据异常!"); throw new Exception("自动评价失败!"); } boolean insertRsm = repairSystemMessagesService.inserBatchSystemMessage(rsms); if (!insertRsm) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":消息中心数据存储异常!"); throw new Exception("自动评价失败!"); } } catch (Exception e) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":好评异常,异常信息:" + e.getMessage()); throw new Exception("自动评价失败!"); } System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":好评执行成功了一次!"); } } /** * 2023-10-26 A-jax 添加退款订单查询 * 凌晨2点执行退款查询操作 */ //凌晨两点:0 0 2 * * ? //每分钟执行一次:0 */1 * * * ? @Async @Scheduled(cron = "0 0 2 * * ?") @Transactional(rollbackFor = {Exception.class}) public void queryRefund() throws Exception { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":开始查询退款进度!"); //获取退款中或部分退款的订单 List dataList = repairRefundRecordService.queryRefundRecord(); List datas = dataList == null ? new ArrayList<>() : dataList.stream().map(repairRefundVo::getRecordNo).distinct().collect(Collectors.toList()); List rrrs = new ArrayList<>(); for (String data : datas) { Map params = new HashMap(); params.put("appid", wxOpenidConfig.getXappid());//微信分配的小程序ID params.put("mch_id", wxOpenidConfig.getShappid());//微信支付分配的商户号 params.put("out_trade_no", data);//"086339330913483");//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。详见商户订单号 String nonceStr = WxUtil.getWxNonceStr(); params.put("nonce_str", nonceStr);//随机字符串,长度要求在32位以内。推荐随机数生成算法 String Sign = WxUtil.getSign(params, wxOpenidConfig.getShsecret());//参数 + 商户密钥 params.put("sign", Sign); String retXml = WxUtil.getRequestXml(params); String msg = HttpUtils.post("https://api.mch.weixin.qq.com/pay/refundquery", retXml); System.out.println(msg); try { Map dateSre = XmlUtil.fromXML(msg); if (dateSre.get("return_code").toString().equals("SUCCESS") && dateSre.get("result_code").toString().equals("SUCCESS")) { List repairRefunds = dataList.stream().filter(e -> e.getRecordNo().equals(data)).collect(Collectors.toList()); if(repairRefunds != null && repairRefunds.size() > 0){ for (repairRefundVo repairRefund : repairRefunds) { String price = repairRefund.getPayPrice().multiply(new BigDecimal(100)).toString(); String outRefundNo =null; String refundId = null; for (int i = 0;i 0){ boolean result = repairRefundRecordService.updateRdfundBatch(rrrs); if(!result){ System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":退款进度更新失败!"); throw new Exception("退款进度查询失败!"); } } } catch (Exception e) { System.out.println(TimeExchange.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + ":退款查询,异常信息:" + e.getMessage()); throw new Exception("退款进度查询失败!"); } } }