Explorar o código

对接微信官方发货返回的所有提示语

xw hai 1 semana
pai
achega
5df20c3cf0

+ 11 - 12
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -456,21 +456,20 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         ExcelUtil<FsStoreOrderDeliveryNoteExportVO> util=new ExcelUtil<>(FsStoreOrderDeliveryNoteExportVO.class);
         try {
             List<FsStoreOrderDeliveryNoteExportVO> dtoList = util.importExcel(file.getInputStream());
-            if(!dtoList.isEmpty()){
-                if(dtoList.size() > 200){
-                    R.error("操作失败,导入数据不能大于200条!");
-                }
-                if(shipmentType == null){
-                    shipmentType = 2;
-                }
-               return fsStoreOrderService.importDeliveryNoteExpress(dtoList,miniAppId,shipmentType);
-            }else {
-                R.error("操作失败,导入数据不能小于1条!");
+            if(dtoList.isEmpty()){
+                return R.error("操作失败,导入数据不能小于1条!");
+            }
+            if(dtoList.size() > 200){
+                return R.error("操作失败,导入数据不能大于200条!");
+            }
+            if(shipmentType == null){
+                shipmentType = 2;
             }
+            return fsStoreOrderService.importDeliveryNoteExpress(dtoList,miniAppId,shipmentType);
         }catch (Exception e){
-            e.getStackTrace();
+            logger.error("发货导入异常", e);
+            return R.error("导入失败:" + e.getMessage());
         }
-        return R.ok();
     }
 
     @GetMapping("/importDeliveryNoteExpressTemplate")

+ 102 - 0
fs-service/src/main/java/com/fs/hisStore/dto/DeliveryNoteImportResultDTO.java

@@ -0,0 +1,102 @@
+package com.fs.hisStore.dto;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 发货单导入结果DTO
+ */
+@Data
+public class DeliveryNoteImportResultDTO {
+
+    /**
+     * 成功数量
+     */
+    private int successNum = 0;
+
+    /**
+     * 失败数量
+     */
+    private int failureNum = 0;
+
+    /**
+     * 失败详情列表
+     */
+    private List<FailureDetail> failureDetails = new ArrayList<>();
+
+    /**
+     * 失败详情
+     */
+    @Data
+    public static class FailureDetail {
+        /**
+         * 行号(从第2行开始,第1行是表头)
+         */
+        private int rowNum;
+
+        /**
+         * 订单号
+         */
+        private String orderNumber;
+
+        /**
+         * 快递单号
+         */
+        private String deliveryId;
+
+        /**
+         * 失败原因
+         */
+        private String failureReason;
+
+        public FailureDetail(int rowNum, String orderNumber, String deliveryId, String failureReason) {
+            this.rowNum = rowNum;
+            this.orderNumber = orderNumber;
+            this.deliveryId = deliveryId;
+            this.failureReason = failureReason;
+        }
+    }
+
+    /**
+     * 增加成功计数
+     */
+    public void addSuccess() {
+        successNum++;
+    }
+
+    /**
+     * 增加失败记录
+     */
+    public void addFailure(int rowNum, String orderNumber, String deliveryId, String reason) {
+        failureNum++;
+        failureDetails.add(new FailureDetail(rowNum, orderNumber, deliveryId, reason));
+    }
+
+    /**
+     * 构建结果消息(纯文本格式,不含HTML标签)
+     */
+    public String buildResultMessage() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("导入完成!成功 ")
+                .append(successNum)
+                .append(" 条,失败 ")
+                .append(failureNum)
+                .append(" 条");
+
+        if (!failureDetails.isEmpty()) {
+            sb.append("\n");
+            for (FailureDetail detail : failureDetails) {
+                sb.append("第").append(detail.getRowNum()).append("行");
+                if (detail.getOrderNumber() != null && !detail.getOrderNumber().isEmpty()) {
+                    sb.append(" 订单号:").append(detail.getOrderNumber());
+                }
+                sb.append(" 失败原因:").append(detail.getFailureReason())
+                        .append("\n");
+            }
+        }
+
+        return sb.toString();
+    }
+}

+ 43 - 0
fs-service/src/main/java/com/fs/hisStore/dto/WxShippingUploadResult.java

@@ -0,0 +1,43 @@
+package com.fs.hisStore.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 微信发货上传结果
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxShippingUploadResult {
+    
+    /**
+     * 是否成功
+     */
+    private boolean success;
+    
+    /**
+     * 错误码
+     */
+    private Integer errorCode;
+    
+    /**
+     * 错误描述
+     */
+    private String errorDesc;
+    
+    /**
+     * 创建成功结果
+     */
+    public static WxShippingUploadResult success() {
+        return new WxShippingUploadResult(true, null, null);
+    }
+    
+    /**
+     * 创建失败结果
+     */
+    public static WxShippingUploadResult fail(Integer errorCode, String errorDesc) {
+        return new WxShippingUploadResult(false, errorCode, errorDesc);
+    }
+}

+ 43 - 53
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -52,6 +52,7 @@ import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.course.dto.OrderOpenIdTransDTO;
+import com.fs.hisStore.dto.DeliveryNoteImportResultDTO;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryResponse;
@@ -4207,7 +4208,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Transactional(rollbackFor = Exception.class)
     public R importDeliveryNoteExpress(List<FsStoreOrderDeliveryNoteExportVO> voList, String appId,Integer shipmentType) {
         try {
-            StringBuilder builder = new StringBuilder();
+            DeliveryNoteImportResultDTO result = new DeliveryNoteImportResultDTO();
             //获取商城配置
             String json = configService.selectConfigByKey("store.config");
             StoreConfig config = JSONUtil.toBean(json, StoreConfig.class);
@@ -4221,23 +4222,29 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             for (int i = 0; i < voList.size(); i++) {
                 FsStoreOrderDeliveryNoteExportVO vo = voList.get(i);
                 FsOrderDeliveryNoteDTO dto = new FsOrderDeliveryNoteDTO();
+                int rowNum = i + 2;
+                
+                // 基础字段校验
                 if (StringUtils.isEmpty(vo.getOrderNumber())) {
-                    builder.append("数据第").append(i + 2).append("行系统订单为空!").append(System.lineSeparator());
+                    result.addFailure(rowNum, "", vo.getDeliveryId(), "系统订单号为空");
+                    continue;
                 }
                 if (StringUtils.isEmpty(vo.getLogisticsCompany())) {
-                    builder.append("数据第").append(i + 2).append("行物流公司为空!").append(System.lineSeparator());
+                    result.addFailure(rowNum, vo.getOrderNumber(), vo.getDeliveryId(), "物流公司为空");
+                    continue;
                 }
                 if (StringUtils.isEmpty(vo.getDeliveryId())) {
-                    builder.append("数据第").append(i + 2).append("行快递单号为空!").append(System.lineSeparator());
-                } else {
-                    //处理订单ID信息
-                    String originalOrderNumber = vo.getOrderNumber();
-                    String processedOrderNumber = extractNumbers(originalOrderNumber);
-                    dto.setOrderNumber(processedOrderNumber);
-                    orderCodeList.add(processedOrderNumber);
+                    result.addFailure(rowNum, vo.getOrderNumber(), "", "快递单号为空");
+                    continue;
                 }
+                
+                //处理订单ID信息
+                String originalOrderNumber = vo.getOrderNumber();
+                String processedOrderNumber = extractNumbers(originalOrderNumber);
+                dto.setOrderNumber(processedOrderNumber);
                 dto.setDeliveryName(vo.getLogisticsCompany());
                 dto.setDeliveryId(vo.getDeliveryId());
+                orderCodeList.add(processedOrderNumber);
                 successList.add(dto);
 
 
@@ -4268,7 +4275,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
             //批量查询订单信息
             if (orderCodeList.isEmpty()) {
-                return R.ok(builder.toString());
+                return R.ok(result.buildResultMessage());
             }
             List<FsStoreOrderCodeOpenIdVo> orderCodeOpenIdVoList = fsStoreOrderMapper.selectOrderCodeOpenIdInOrderCode(orderCodeList);
             Map<String, OrderOpenIdTransDTO> orderMap = new HashMap<>(orderCodeOpenIdVoList.size());
@@ -4296,34 +4303,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 if (StringUtils.isEmpty(dto.getOrderNumber())) {
                     continue;
                 }
-//                if (StringUtils.isEmpty(dto.getDeliveryId())) {
-//                    builder.append("数据第").append(rowNum).append("行快递单号为空!")
-//                            .append(System.lineSeparator());
-//                    continue;
-//                }
 
-                if (StringUtils.isEmpty(dto.getDeliveryName())) {
-                    builder.append("数据第").append(rowNum).append("行快递公司编号为空!")
-                            .append(System.lineSeparator());
-                    continue;
-                }
-//                if (dto.getDeliveryStatus() == null) {
-//                    dto.setDeliveryStatus(0);
-//                }
-//                if (ObjectUtil.isNotNull(dto.getDeliveryTime())) {
-//                    dto.setDeliveryTime(parseCstToDateOnlyString(dto.getDeliveryTime()));
-//                }
-//
-//                if (ObjectUtil.isNotNull(dto.getDeliveryPayTime()) &&
-//                        !dto.getDeliveryPayTime().isEmpty()) {
-//                    dto.setDeliveryPayTime(parseCstToDateOnlyString(dto.getDeliveryPayTime()));
-//                }
                 // 验证快递公司
                 String deliverySn = expressDeliveryMap.get(dto.getDeliveryName());
                 if (deliverySn == null) {
-                    builder.append("数据第").append(rowNum).append("行订单号为")
-                            .append(dto.getOrderNumber()).append("物流公司名称异常")
-                            .append(System.lineSeparator());
+                    result.addFailure(rowNum, dto.getOrderNumber(), dto.getDeliveryId(), "物流公司名称异常");
                     continue;
                 }
                 dto.setDeliverySn(deliverySn);
@@ -4332,22 +4316,25 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 String orderNumber = dto.getOrderNumber();
                 OrderOpenIdTransDTO orderInfo = orderMap.get(orderNumber);
                 if (orderInfo == null) {
-                    builder.append("数据第").append(rowNum).append("行订单号")
-                            .append(orderNumber).append("不存在").append(System.lineSeparator());
+                    result.addFailure(rowNum, orderNumber, dto.getDeliveryId(), "订单号不存在");
                     continue;
                 }
                 //验证是否开启微信发货
                 if (config.getIsWeChatShipping() != null && config.getIsWeChatShipping()) {
                     // 上传物流信息到微信
                     List<FsStoreOrderCodeOpenIdVo> orderDetails = orderDetailsMap.get(orderNumber);
-                    if (uploadShippingInfoToWechat(wxService, orderInfo, orderDetails, dto, uploadTime,shipmentType)) {
+                    WxShippingUploadResult uploadResult = uploadShippingInfoToWechat(wxService, orderInfo, orderDetails, dto, uploadTime,shipmentType);
+                    if (uploadResult.isSuccess()) {
                         updateList.add(dto);
+                        result.addSuccess();
                     } else {
-                        builder.append("数据第").append(rowNum).append("行订单号为")
-                                .append(orderNumber).append("上传微信失败").append(System.lineSeparator());
+                        // 直接使用错误描述,不展示错误码
+                        String failureReason = uploadResult.getErrorDesc();
+                        result.addFailure(rowNum, orderNumber, dto.getDeliveryId(), failureReason);
                     }
                 } else {
                     updateList.add(dto);
+                    result.addSuccess();
                 }
             }
 
@@ -4356,7 +4343,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 batchUpdateDeliveryNotes(updateList);
             }
 
-            return R.ok(builder.toString().equals("") ? "操作成功!" : builder.toString());
+            return R.ok(result.buildResultMessage());
         } catch (Exception e) {
             log.error("导入发货单快递信息失败", e);
             return R.error("导入失败:" + e.getMessage());
@@ -5383,11 +5370,14 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 if (config.getIsWeChatShipping() != null && config.getIsWeChatShipping()) {
                     // 上传物流信息到微信
                     List<FsStoreOrderCodeOpenIdVo> orderDetails = orderDetailsMap.get(orderNumber);
-                    if (uploadShippingInfoToWechat(wxService, orderInfo, orderDetails, dto, uploadTime)) {
+                    WxShippingUploadResult uploadResult = uploadShippingInfoToWechat(wxService, orderInfo, orderDetails, dto, uploadTime);
+                    if (uploadResult.isSuccess()) {
                         successList.add(dto);
                     } else {
+                        // 直接使用错误描述,不展示错误码
+                        String failureReason = uploadResult.getErrorDesc();
                         builder.append("数据第").append(rowNum).append("行订单号为")
-                                .append(orderNumber).append("上传微信失败").append(System.lineSeparator());
+                                .append(orderNumber).append(" ").append(failureReason).append(System.lineSeparator());
                     }
                 } else {
                     successList.add(dto);
@@ -5420,7 +5410,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         }
     }
 
-    private boolean uploadShippingInfoToWechat(WxMaService wxService,
+    private WxShippingUploadResult uploadShippingInfoToWechat(WxMaService wxService,
                                                OrderOpenIdTransDTO orderInfo,
                                                List<FsStoreOrderCodeOpenIdVo> orderDetails,
                                                FsOrderDeliveryNoteDTO dto,
@@ -5462,11 +5452,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
             // 上传物流信息
             WxMaOrderShippingInfoBaseResponse re = wxService.getWxMaOrderShippingService().upload(request);
-            // 使用统一的错误处理工具类
-            return WxShippingErrorHandler.handleError(re.getErrCode(), re.getErrMsg(), dto.getOrderNumber());
+            // 使用统一的错误处理工具类(增强版,返回详细错误信息)
+            return WxShippingErrorHandler.handleErrorWithDetail(re.getErrCode(), re.getErrMsg(), dto.getOrderNumber());
         } catch (Exception e) {
-            // 使用统一的异常错误处理工具类
-            return WxShippingErrorHandler.handleExceptionError(e.getMessage(), dto.getOrderNumber());
+            // 使用统一的异常错误处理工具类(增强版,返回详细错误信息)
+            return WxShippingErrorHandler.handleExceptionErrorWithDetail(e.getMessage(), dto.getOrderNumber());
         }
     }
 
@@ -5700,7 +5690,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         return value == null ? BigDecimal.ZERO : value;
     }
 
-    private boolean uploadShippingInfoToWechat(WxMaService wxService,
+    private WxShippingUploadResult uploadShippingInfoToWechat(WxMaService wxService,
                                                OrderOpenIdTransDTO orderInfo,
                                                List<FsStoreOrderCodeOpenIdVo> orderDetails,
                                                FsOrderDeliveryNoteDTO dto,
@@ -5747,11 +5737,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
             // 上传物流信息
             WxMaOrderShippingInfoBaseResponse re = wxService.getWxMaOrderShippingService().upload(request);
-            // 使用统一的错误处理工具类
-            return WxShippingErrorHandler.handleError(re.getErrCode(), re.getErrMsg(), dto.getOrderNumber());
+            // 使用统一的错误处理工具类(增强版,返回详细错误信息)
+            return WxShippingErrorHandler.handleErrorWithDetail(re.getErrCode(), re.getErrMsg(), dto.getOrderNumber());
         } catch (Exception e) {
-            // 使用统一的异常错误处理工具类
-            return WxShippingErrorHandler.handleExceptionError(e.getMessage(), dto.getOrderNumber());
+            // 使用统一的异常错误处理工具类(增强版,返回详细错误信息)
+            return WxShippingErrorHandler.handleExceptionErrorWithDetail(e.getMessage(), dto.getOrderNumber());
         }
     }
 }

+ 74 - 0
fs-service/src/main/java/com/fs/wx/order/utils/WxShippingErrorHandler.java

@@ -1,5 +1,6 @@
 package com.fs.wx.order.utils;
 
+import com.fs.hisStore.dto.WxShippingUploadResult;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.HashMap;
@@ -85,6 +86,79 @@ public class WxShippingErrorHandler {
         return "未知错误";
     }
 
+    /**
+     * 处理微信发货接口返回的错误码(增强版,返回详细错误信息)
+     * 统一的错误处理逻辑,根据错误码决定是否允许本地订单状态更新,并返回详细错误描述
+     *
+     * @param errCode 微信返回的错误码
+     * @param errMsg 微信返回的错误信息
+     * @param orderNumber 订单号(用于日志记录)
+     * @return WxShippingUploadResult 包含成功状态和错误详情
+     */
+    public static WxShippingUploadResult handleErrorWithDetail(Integer errCode, String errMsg, String orderNumber) {
+        if (errCode == null || errCode == 0) {
+            return WxShippingUploadResult.success(); // 成功
+        }
+
+        String errorDesc = getErrorDesc(errCode);
+
+        // 允许更新的错误码
+        if (shouldAllowUpdate(errCode)) {
+            log.warn("订单号: {} 微信发货接口返回错误码: {}, 错误描述: {}, 微信返回信息: {}。跳过微信发货上传,仍更新本地订单状态",
+                    orderNumber, errCode, errorDesc, errMsg);
+            return WxShippingUploadResult.success(); // 虽然微信接口报错,但允许更新本地数据
+        }
+
+        // 阻止更新的错误码
+        if (shouldBlockUpdate(errCode)) {
+            log.error("订单号: {} 微信发货接口返回错误码: {}, 错误描述: {}, 微信返回信息: {}。阻止本地订单状态更新",
+                    orderNumber, errCode, errorDesc, errMsg);
+            return WxShippingUploadResult.fail(errCode, errorDesc);
+        }
+
+        // 未知错误码,默认阻止更新
+        log.error("订单号: {} 微信发货接口返回未知错误码: {}, 微信返回信息: {}。阻止本地订单状态更新",
+                orderNumber, errCode, errMsg);
+        return WxShippingUploadResult.fail(errCode, "未知错误(" + errCode + ")");
+    }
+
+    /**
+     * 处理异常中的错误码(增强版,返回详细错误信息)
+     * 用于处理 WxErrorException 等异常情况
+     *
+     * @param errorMsg 异常消息
+     * @param orderNumber 订单号(用于日志记录)
+     * @return WxShippingUploadResult 包含成功状态和错误详情
+     */
+    public static WxShippingUploadResult handleExceptionErrorWithDetail(String errorMsg, String orderNumber) {
+        if (errorMsg == null || errorMsg.isEmpty()) {
+            log.error("订单号: {} 上传物流信息到微信失败,错误信息为空", orderNumber);
+            return WxShippingUploadResult.fail(null, "上传微信失败(未知错误)");
+        }
+
+        // 尝试从错误消息中提取错误码
+        for (Integer errCode : ALLOW_UPDATE_ERRORS.keySet()) {
+            if (errorMsg.contains(String.valueOf(errCode)) || errorMsg.contains(ALLOW_UPDATE_ERRORS.get(errCode))) {
+                log.warn("订单号: {} 微信发货异常,错误码: {}, 错误描述: {}。跳过微信发货上传,仍更新本地订单状态。异常详情: {}",
+                        orderNumber, errCode, ALLOW_UPDATE_ERRORS.get(errCode), errorMsg);
+                return WxShippingUploadResult.success(); // 允许更新
+            }
+        }
+
+        // 检查是否是阻止更新的错误
+        for (Integer errCode : BLOCK_UPDATE_ERRORS.keySet()) {
+            if (errorMsg.contains(String.valueOf(errCode)) || errorMsg.contains(BLOCK_UPDATE_ERRORS.get(errCode))) {
+                log.error("订单号: {} 微信发货异常,错误码: {}, 错误描述: {}。阻止本地订单状态更新。异常详情: {}",
+                        orderNumber, errCode, BLOCK_UPDATE_ERRORS.get(errCode), errorMsg);
+                return WxShippingUploadResult.fail(errCode, BLOCK_UPDATE_ERRORS.get(errCode));
+            }
+        }
+
+        // 未知错误,默认阻止更新
+        log.error("订单号: {} 上传物流信息到微信失败,未识别的错误。异常详情: {}", orderNumber, errorMsg);
+        return WxShippingUploadResult.fail(null, "上传微信失败(" + errorMsg + ")");
+    }
+
     /**
      * 处理微信发货接口返回的错误码
      * 统一的错误处理逻辑,根据错误码决定是否允许本地订单状态更新