diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCommonController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCommonController.java
index 845c6428a..f193080a3 100644
--- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCommonController.java
+++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCommonController.java
@@ -144,6 +144,28 @@ public class EmisCommonController extends EmisBaseController
@Autowired
private EmisTmsSiteBatchMissMapper emisTmsSiteBatchMissMapper;
+ /**
+ * 跟踪预警触发:查询长时间未更新扫描记录的运单并通知相关人员
+ */
+ @GetMapping("/autoTraceWarningTrigger")
+ public AjaxResult autoTraceWarningTrigger() {
+ String lockKey = "autoTraceWarningTrigger";
+ log.info("autoTraceWarningTrigger start");
+
+ redissonService.lock(lockKey, 300);
+ try {
+ emisWaybillService.autoTraceWarning();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ log.error("autoTraceWarningTrigger exception:" + ex.getMessage());
+ } finally {
+ redissonService.unlock(lockKey);
+ }
+
+ log.info("autoTraceWarningTrigger end");
+ return AjaxResult.success("发送成功");
+ }
+
/**
* 在线支付回调
* @param method
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSalesmenRelMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSalesmenRelMapper.java
index affc5ba92..57fc985d0 100644
--- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSalesmenRelMapper.java
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSalesmenRelMapper.java
@@ -11,8 +11,10 @@
package com.xdadan.erp.emis.mapper;
import java.util.List;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xdadan.erp.emis.domain.EmisSalesmenRel;
+import org.apache.ibatis.annotations.Param;
/**
* @ClassName EmisSalesmenRelMapper
* @Description
销售人员关联表 Mapper 接口
@@ -85,4 +87,12 @@ public interface EmisSalesmenRelMapper extends BaseMapper
* @return 结果
*/
public int deleteEmisSalesmenRelByIds(Long[] ids);
+
+ /**
+ * 批量查询有效的销售分享关系
+ *
+ * @param salesmenList 销售联系人列表
+ * @return 关联关系列表
+ */
+ public List selectValidRelBySalesmenList(@Param("salesmenList") List salesmenList);
}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWaybillMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWaybillMapper.java
index 37651a741..67c773e35 100644
--- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWaybillMapper.java
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWaybillMapper.java
@@ -10,6 +10,7 @@
*/
package com.xdadan.erp.emis.mapper;
+import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -398,4 +399,16 @@ public interface EmisWaybillMapper extends BaseMapper
* @return 运单明细列表
*/
List selectMonthlyCustomerShipmentDetail(EmisWaybill emisWaybill);
+
+ /**
+ * 跟踪预警:查询未签收且超过指定时间未有扫描记录的运单(分页)
+ *
+ * @param startSendDate 发件开始日期(含)
+ * @param offset 起始位置
+ * @param pageSize 每页大小
+ * @return 运单列表
+ */
+ List selectTraceWarningWaybillList(@Param("startSendDate") Date startSendDate,
+ @Param("offset") int offset,
+ @Param("pageSize") int pageSize);
}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWaybillService.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWaybillService.java
index 94cc188ed..0bdaddc21 100644
--- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWaybillService.java
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWaybillService.java
@@ -322,4 +322,9 @@ public interface IEmisWaybillService extends IDataAuditService
* @return 运单列表
*/
List selectProblemWaybillsForResubmit(EmisWaybill emisWaybill);
+
+ /**
+ * 跟踪预警:查找长时间未更新扫描记录的运单并发送预警通知
+ */
+ void autoTraceWarning();
}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWaybillServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWaybillServiceImpl.java
index b2007d4f8..b118484be 100644
--- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWaybillServiceImpl.java
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWaybillServiceImpl.java
@@ -27,16 +27,19 @@ package com.xdadan.erp.emis.service.impl;
import com.xdadan.erp.common.utils.BarcodeUtils;
import com.xdadan.erp.common.utils.DateUtils;
import com.xdadan.erp.common.utils.DictUtils;
- import com.xdadan.erp.common.utils.SecurityUtils;
+import com.xdadan.erp.common.utils.SecurityUtils;
+import com.xdadan.erp.common.utils.NoticeUtils;
import com.xdadan.erp.common.utils.file.FileUploadUtils;
import com.xdadan.erp.common.utils.idgen.UUID;
- import com.xdadan.erp.emis.domain.*;
- import com.xdadan.erp.emis.domain.enumtype.*;
- import com.xdadan.erp.emis.domain.exception.EmisBizError;
- import com.xdadan.erp.emis.domain.vo.WaybillOrder;
- import com.xdadan.erp.emis.domain.vo.scan.ScanInfo;
- import com.xdadan.erp.emis.mapper.*;
- import com.xdadan.erp.emis.service.*;
+import com.xdadan.erp.emis.domain.*;
+import com.xdadan.erp.emis.domain.enumtype.*;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+import com.xdadan.erp.emis.domain.vo.WaybillOrder;
+import com.xdadan.erp.emis.domain.vo.scan.ScanInfo;
+import com.xdadan.erp.emis.mapper.EmisSalesmenRelMapper;
+import com.xdadan.erp.emis.domain.EmisSalesmenRel;
+import com.xdadan.erp.emis.mapper.*;
+import com.xdadan.erp.emis.service.*;
import com.xdadan.erp.emis.service.print.IXddTplPrint;
import com.xdadan.erp.emis.service.print.tanex.TanexPdfPrinter;
import com.xdadan.erp.emis.service.warehouse.DocUtils;
@@ -154,6 +157,9 @@ public class EmisWaybillServiceImpl extends EmisBaseService implements IEmisWayb
@Autowired
private EmisWaybillOtherMapper emisWaybillOtherMapper;
+ @Autowired
+ private EmisSalesmenRelMapper emisSalesmenRelMapper;
+
/**
* 保存或更新运单其他信息副表
* @param emisWaybillSave
@@ -1908,7 +1914,7 @@ public class EmisWaybillServiceImpl extends EmisBaseService implements IEmisWayb
scanInfo.setScanData(scanDataList);
try {
- emisTmsScanRecordService.scan(scanInfo,dispatchOrSendManCode,emisWaybillSave.getSendSiteCode());
+ emisTmsScanRecordService.scan(scanInfo,dispatchOrSendManCode,emisWaybillSave.getStartSiteCode());
} catch (Exception e) {
e.printStackTrace();
}
@@ -2360,13 +2366,6 @@ public class EmisWaybillServiceImpl extends EmisBaseService implements IEmisWayb
*/
private void calcWayBillCommonInfo(EmisWaybill emisWaybillSave,EmisWaybill oldWaybil,boolean isNew) throws EmisBizError {
- // 校验货物信息,不能只包含空格或符号
- String goodsInfo = emisWaybillSave.getGoodsInfo();
- if (StringUtils.isBlank(goodsInfo) || !Pattern.compile("[\\p{L}\\p{N}]").matcher(goodsInfo).find()) {
- // 货物信息不能只包含空格、标点或特殊符号
- throw new EmisBizError(EmisBizErrorType.PARAM_ERROR1, "货物名称命名不规范,请检查!");
- }
-
String orderSn = WaybillHelper.genOrderSn();
// 订单号
@@ -3416,7 +3415,7 @@ public class EmisWaybillServiceImpl extends EmisBaseService implements IEmisWayb
scanDateItem.put("scanWeight", "0.0");
scanDataList.add(scanDateItem);
scanInfo.setScanData(scanDataList);
- emisTmsScanRecordService.scan(scanInfo,dispatchOrSendManCode,emisWaybillSave.getSendSiteCode());
+ emisTmsScanRecordService.scan(scanInfo,dispatchOrSendManCode,emisWaybillSave.getStartSiteCode());
} catch (Exception e) {
e.printStackTrace();
}
@@ -6151,6 +6150,123 @@ public class EmisWaybillServiceImpl extends EmisBaseService implements IEmisWayb
return emisWaybillMapper.selectMasterEmisWaybills(emisWaybill);
}
+ /**
+ * 跟踪预警:查找长时间未更新扫描记录的运单并发送预警通知
+ */
+ @Override
+ public void autoTraceWarning() {
+ try {
+ // 2025-12-01 00:00:00 之后的运单
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.YEAR, 2025);
+ cal.set(Calendar.MONTH, Calendar.DECEMBER);
+ cal.set(Calendar.DAY_OF_MONTH, 1);
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ Date startSendDate = cal.getTime();
+
+ int pageSize = 1000;
+ int offset = 0;
+
+ while (true) {
+ List waybillList = emisWaybillMapper.selectTraceWarningWaybillList(startSendDate, offset, pageSize);
+ if (CollectionUtils.isEmpty(waybillList)) {
+ break;
+ }
+
+ Date now = new Date();
+
+ // 当前批次所有销售联系人,批量查询分享关系
+ Set batchSalesmenSet = new LinkedHashSet<>();
+ for (EmisWaybill waybill : waybillList) {
+ if (waybill != null && !StringUtils.isEmpty(waybill.getSalesmen())) {
+ batchSalesmenSet.add(waybill.getSalesmen());
+ }
+ }
+
+ Map> salesRelMap = new HashMap<>();
+ if (!batchSalesmenSet.isEmpty()) {
+ List relAllList = emisSalesmenRelMapper
+ .selectValidRelBySalesmenList(new ArrayList<>(batchSalesmenSet));
+ if (!CollectionUtils.isEmpty(relAllList)) {
+ for (EmisSalesmenRel rel : relAllList) {
+ if (rel == null || StringUtils.isEmpty(rel.getSalesmen())) {
+ continue;
+ }
+ salesRelMap.computeIfAbsent(rel.getSalesmen(), k -> new ArrayList<>()).add(rel);
+ }
+ }
+ }
+
+ for (EmisWaybill waybill : waybillList) {
+ if (waybill == null || StringUtils.isEmpty(waybill.getBillCode())) {
+ continue;
+ }
+
+ try {
+ // 收集需要通知的员工编码:销售联系人、销售支持、销售分享人
+ Set notifyEmpCodes = new LinkedHashSet<>();
+
+ // 销售联系人
+ if (!StringUtils.isEmpty(waybill.getSalesmen())) {
+ String salesmen = waybill.getSalesmen();
+ notifyEmpCodes.add(salesmen);
+
+ // 销售分享关系:salesmen -> salesAss(使用当前批次预加载的关系)
+ List relList = salesRelMap.get(salesmen);
+ if (!CollectionUtils.isEmpty(relList)) {
+ for (EmisSalesmenRel rel : relList) {
+ if (rel == null || StringUtils.isEmpty(rel.getSalesAss())) {
+ continue;
+ }
+ notifyEmpCodes.add(rel.getSalesAss());
+ }
+ }
+ }
+
+ // 销售支持(可能为逗号分隔)
+ if (!StringUtils.isEmpty(waybill.getSalesSupport())) {
+ String[] supports = waybill.getSalesSupport().split("[,,]");
+ for (String support : supports) {
+ if (!StringUtils.isEmpty(support)) {
+ notifyEmpCodes.add(support.trim());
+ }
+ }
+ }
+
+ if (notifyEmpCodes.isEmpty()) {
+ continue;
+ }
+
+ String empCodeStr = String.join(",", notifyEmpCodes);
+ String billCode = waybill.getBillCode();
+ String timeStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, now);
+ String title = "轨迹异常:运单【" + billCode + "】停留超过3天_" + timeStr;
+ String content = title;
+ String url = "/d24/waybillManagement/WaybillList?billCode=" + billCode;
+
+ try {
+ NoticeUtils.outSendNoticeToInner(title, content, url, empCodeStr, 3);
+ } catch (Exception ex) {
+ log.error("autoTraceWarning: send notice error, billCode={}, empCodes={}", billCode, empCodeStr, ex);
+ }
+ } catch (Exception ex) {
+ log.error("autoTraceWarning: handle waybill error, billCode={}", waybill.getBillCode(), ex);
+ }
+ }
+
+ if (waybillList.size() < pageSize) {
+ break;
+ }
+ offset += pageSize;
+ }
+ } catch (Exception ex) {
+ log.error("autoTraceWarning: unexpected error", ex);
+ }
+ }
+
@Override
@Async
public void handleHistoryVirtualWaybill() {
diff --git a/emis-biz/src/main/resources/mapper/EmisSalesmenRelMapper.xml b/emis-biz/src/main/resources/mapper/EmisSalesmenRelMapper.xml
index a66f1b452..8cf6531c5 100644
--- a/emis-biz/src/main/resources/mapper/EmisSalesmenRelMapper.xml
+++ b/emis-biz/src/main/resources/mapper/EmisSalesmenRelMapper.xml
@@ -143,4 +143,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
+
+
+
\ No newline at end of file
diff --git a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml
index 506615ac4..4e178bdd0 100644
--- a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml
+++ b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml
@@ -592,6 +592,30 @@
+
+
+