diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java index dd92040..dad5d11 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java @@ -498,8 +498,8 @@ public class TencentDocController extends BaseController { return AjaxResult.error("物流链接不能为空"); } - // 2. 检查订单是否已推送(防止重复推送) - JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(thirdPartyOrderNo); + // 2. 检查订单是否已推送(防止重复推送);单号与客户/第三方单号任一完全匹配 + JDOrder order = jdOrderService.selectJDOrderByOrderIdOrThirdPartyOrderNo(thirdPartyOrderNo); if (order == null) { logOperation(null, null, null, "WRITE_SINGLE", thirdPartyOrderNo, null, logisticsLink, "FAILED", "订单不存在"); @@ -645,7 +645,7 @@ public class TencentDocController extends BaseController { JSONObject orderNoCell = cells.getJSONObject(orderNoColumn); if (orderNoCell.containsKey("cellValue")) { String cellText = orderNoCell.getJSONObject("cellValue").getString("text"); - if (thirdPartyOrderNo.equals(cellText)) { + if (tencentSheetOrderNoMatches(order, thirdPartyOrderNo, cellText)) { targetRow = configStartRow + i; break; } @@ -696,9 +696,9 @@ public class TencentDocController extends BaseController { verifyOrderNo = verifyOrderNoCell.getJSONObject("cellValue").getString("text"); } - if (!thirdPartyOrderNo.equals(verifyOrderNo)) { + if (!tencentSheetOrderNoMatches(order, thirdPartyOrderNo, verifyOrderNo)) { logOperation(null, fileId, sheetId, "WRITE_SINGLE", thirdPartyOrderNo, targetRow, logisticsLink, - "SKIPPED", String.format("验证失败:单号不匹配,期望 %s,实际 %s", thirdPartyOrderNo, verifyOrderNo)); + "SKIPPED", String.format("验证失败:单号不匹配,期望(单号/客户单号其一) %s,实际 %s", thirdPartyOrderNo, verifyOrderNo)); return AjaxResult.error("验证失败:单号不匹配,行数据已变化"); } @@ -899,6 +899,79 @@ public class TencentDocController extends BaseController { return null; } + /** + * 腾讯文档「单号」列单元格是否与本地订单对应:与请求键、订单号、客户/第三方单号任一完全相同(去首尾空白) + */ + private static boolean tencentSheetOrderNoMatches(JDOrder order, String requestKey, String cellText) { + if (cellText == null) { + return false; + } + String c = cellText.trim(); + if (c.isEmpty()) { + return false; + } + if (requestKey != null && c.equals(requestKey.trim())) { + return true; + } + if (order == null) { + return false; + } + if (order.getOrderId() != null && c.equals(order.getOrderId().trim())) { + return true; + } + return order.getThirdPartyOrderNo() != null && c.equals(order.getThirdPartyOrderNo().trim()); + } + + /** + * 批量同步中出现报错时,将摘要推送到企业微信(wxSend 闲鱼应用通道) + */ + private void pushTencentDocRowErrorsToWeCom(String batchId, String fileId, String sheetId, + int filledCount, int skippedCount, int errorCount, + List> errorLogs) { + if (errorCount <= 0 && (errorLogs == null || errorLogs.isEmpty())) { + return; + } + StringBuilder sb = new StringBuilder(); + sb.append("【腾讯文档推送】同步存在报错\n"); + if (batchId != null && !batchId.isEmpty()) { + sb.append("批次: ").append(batchId).append("\n"); + } + if (fileId != null && !fileId.isEmpty()) { + sb.append("fileId: ").append(fileId).append("\n"); + } + if (sheetId != null && !sheetId.isEmpty()) { + sb.append("sheetId: ").append(sheetId).append("\n"); + } + sb.append(String.format("成功队列: %d, 跳过: %d, 错误: %d\n", filledCount, skippedCount, errorCount)); + if (errorLogs != null && !errorLogs.isEmpty()) { + int max = Math.min(15, errorLogs.size()); + for (int i = 0; i < max; i++) { + Map el = errorLogs.get(i); + Object on = el != null ? el.get("orderNo") : null; + Object row = el != null ? el.get("row") : null; + Object em = el != null ? el.get("errorMessage") : null; + Object et = el != null ? el.get("errorType") : null; + sb.append(String.format("%d. 单号:%s 行:%s", i + 1, + on != null ? on : "-", row != null ? row : "-")); + if (et != null && String.valueOf(et).length() > 0) { + sb.append(" ").append(et); + } + sb.append("\n"); + if (em != null) { + String msg = String.valueOf(em); + if (msg.length() > 120) { + msg = msg.substring(0, 119) + "…"; + } + sb.append(" ").append(msg).append("\n"); + } + } + if (errorLogs.size() > max) { + sb.append("… 共 ").append(errorLogs.size()).append(" 条错误\n"); + } + } + wxSendGoofishNotifyClient.pushGoofishAgentText(null, sb.toString()); + } + /** * 合并同一行的腾讯文档填充任务(物流更新与仅补京东单号合并为一次 batchUpdate) */ @@ -1307,7 +1380,7 @@ public class TencentDocController extends BaseController { if (!trimmedExistingLink.isEmpty()) { // 文档中已有物流链接,需要比对数据库中的物流链接 try { - JDOrder existingOrder = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); + JDOrder existingOrder = jdOrderService.selectJDOrderByOrderIdOrThirdPartyOrderNo(orderNo); if (existingOrder != null) { String dbLogisticsLink = existingOrder.getLogisticsLink(); String trimmedDbLink = (dbLogisticsLink != null) ? dbLogisticsLink.trim() : ""; @@ -1404,8 +1477,8 @@ public class TencentDocController extends BaseController { } try { - // 根据第三方单号查询订单 - JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); + // 表格单号列与本地订单号或客户/第三方单号完全匹配 + JDOrder order = jdOrderService.selectJDOrderByOrderIdOrThirdPartyOrderNo(orderNo); if (order == null) { // 订单不存在,跳过但不统计为错误 @@ -1788,7 +1861,7 @@ public class TencentDocController extends BaseController { // 更新订单的推送状态(重新查询订单,避免使用旧对象) JDOrder orderToUpdate = null; try { - orderToUpdate = jdOrderService.selectJDOrderByThirdPartyOrderNo(expectedOrderNo); + orderToUpdate = jdOrderService.selectJDOrderByOrderIdOrThirdPartyOrderNo(expectedOrderNo); if (orderToUpdate != null) { orderToUpdate.setTencentDocPushed(1); orderToUpdate.setTencentDocPushTime(new java.util.Date()); @@ -2672,11 +2745,10 @@ public class TencentDocController extends BaseController { String cleanedLogisticsLink = cleanLogisticsLink(logisticsLinkFromDoc); try { - // 通过第三方单号查找本地订单 - JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNoFromDoc.trim()); + // 表格单号与订单号或客户/第三方单号完全匹配;否则再按内部单号(remark) + JDOrder order = jdOrderService.selectJDOrderByOrderIdOrThirdPartyOrderNo(orderNoFromDoc.trim()); if (order == null) { - // 如果通过第三方单号找不到,尝试通过内部单号(remark)查找 order = jdOrderService.selectJDOrderByRemark(orderNoFromDoc.trim()); } @@ -3102,6 +3174,14 @@ public class TencentDocController extends BaseController { } } + if (errorCount > 0 || (errorLogs != null && !errorLogs.isEmpty())) { + try { + pushTencentDocRowErrorsToWeCom(batchId, fileId, sheetId, filledCount, skippedCount, errorCount, errorLogs); + } catch (Exception ex) { + log.warn("腾讯文档报错企微推送失败: {}", ex.toString()); + } + } + // 构建请求体 JSONObject requestBody = new JSONObject(); requestBody.put("title", "腾讯文档同步成功"); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java index 90d3ab0..45534ad 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java @@ -46,6 +46,11 @@ public interface JDOrderMapper { */ JDOrder selectJDOrderByThirdPartyOrderNo(String thirdPartyOrderNo); + /** + * 腾讯文档「单号」列:与订单号(order_id)或客户/第三方单号(third_party_order_no)任一完全相等则命中 + */ + JDOrder selectJDOrderByOrderIdOrThirdPartyOrderNo(String orderKey); + /** * 后返备注 JSON 中含指定 uploadRecordId 的订单主键(撤销导入时用) */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java index 030edc1..1657d75 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java @@ -43,6 +43,11 @@ public interface IJDOrderService { /** 根据第三方单号查询订单 */ JDOrder selectJDOrderByThirdPartyOrderNo(String thirdPartyOrderNo); + /** + * 按订单号或客户/第三方单号(与表 jd_order.order_id、third_party_order_no 完全匹配) + */ + JDOrder selectJDOrderByOrderIdOrThirdPartyOrderNo(String orderKey); + /** 批量删除(根据主键ID) */ int deleteJDOrderByIds(Long[] ids); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java index 1f9756b..23b9cbd 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java @@ -69,6 +69,14 @@ public class JDOrderServiceImpl implements IJDOrderService { return jdOrderMapper.selectJDOrderByThirdPartyOrderNo(thirdPartyOrderNo); } + @Override + public JDOrder selectJDOrderByOrderIdOrThirdPartyOrderNo(String orderKey) { + if (orderKey == null || orderKey.trim().isEmpty()) { + return null; + } + return jdOrderMapper.selectJDOrderByOrderIdOrThirdPartyOrderNo(orderKey.trim()); + } + @Override public int deleteJDOrderByIds(Long[] ids) { if (ids == null || ids.length == 0) { diff --git a/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml b/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml index ded282a..2266088 100644 --- a/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml @@ -262,6 +262,13 @@ limit 1 + +