Explorar el Código

下单 物流费用路由回推

zxfqwert hace 1 semana
padre
commit
01ff4903c5
Se han modificado 16 ficheros con 503 adiciones y 73 borrados
  1. 25 0
      jd-logistics-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java
  2. 65 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/Kd100Controller.java
  3. 85 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/service/impl/Kuaidi100Service.java
  4. 2 36
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfFeePushCallback.java
  5. 11 2
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfPushOrderStatusCallback.java
  6. 128 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfRoutingPushCallback.java
  7. 31 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/config/KD100ExpressConfig.java
  8. 7 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/controller/BizWaybillOrderController.java
  9. 2 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/mapper/BizWaybillOrderMapper.java
  10. 5 1
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/IBizWaybillOrderService.java
  11. 2 1
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsOrderService.java
  12. 2 1
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsService.java
  13. 22 2
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/BizWaybillOrderServiceImpl.java
  14. 24 17
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/FeePushService.java
  15. 47 13
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/SFLogisticsService.java
  16. 45 0
      jd-logistics-modules/jd-logistics-system/src/main/resources/mapper/logistics/BizWaybillOrderMapper.xml

+ 25 - 0
jd-logistics-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java

@@ -1,5 +1,8 @@
 package com.ruoyi.common.redis.configure;
 
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
 import org.springframework.cache.annotation.CachingConfigurerSupport;
@@ -8,6 +11,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 /**
@@ -39,5 +43,26 @@ public class RedisConfig extends CachingConfigurerSupport
 
         template.afterPropertiesSet();
         return template;
+
+
+
+        /*// 配置 ObjectMapper 禁用类型信息
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
+        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
+        objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+        // 禁用类型信息输出
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
+
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(serializer);
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(serializer);
+        template.afterPropertiesSet();*/
     }
 }

+ 65 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/Kd100Controller.java

@@ -0,0 +1,65 @@
+package com.ruoyi.front.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.core.web.domain.AjaxResult;
+import com.ruoyi.front.service.impl.Kuaidi100Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * 快递100调用查询接口
+ *
+ * @author RuiJing
+ * @date 2026-01-29
+ */
+@RestController
+@RequestMapping("/kd100/wxmini")
+public class Kd100Controller {
+    private static final Logger logger = LoggerFactory.getLogger(Kd100Controller.class);
+
+   @Autowired
+   Kuaidi100Service kuaidi100Service;
+   @Autowired
+   RedisTemplate redisTemplate;
+
+    @PostMapping("/queryExpres")
+    public AjaxResult queryExpres(@RequestBody Map param)  {
+        try {
+            logger.info("调用快递100查询实时快递接口  运单号: {}", param.get("number"));
+            Object  redisResult= redisTemplate.opsForValue().get(param.get("number"));
+            if(redisResult==null){
+                String   result = kuaidi100Service.queryExpress(param);
+                ObjectMapper objectMapper = new ObjectMapper();
+                Map<String, Object> map = objectMapper.readValue(result, Map.class);
+                if("ok".equals(map.get("message"))){
+                    redisTemplate.opsForValue().set(param.get("number"), map, 30, TimeUnit.MINUTES);;
+                    return AjaxResult.success(map);
+                }
+                else{
+                   return  AjaxResult.error(map.get("message").toString());
+                }
+            }
+
+            return AjaxResult.success(redisResult);
+        } catch (Exception e) {
+            return AjaxResult.error("快递100查寻接口异常! 原因:{}" ,e.getMessage());
+        }
+
+
+    }
+
+
+}

+ 85 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/service/impl/Kuaidi100Service.java

@@ -0,0 +1,85 @@
+package com.ruoyi.front.service.impl;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.logistics.config.KD100ExpressConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.Map;
+
+
+@Service
+public class Kuaidi100Service {
+    @Autowired
+     KD100ExpressConfig kd100ExpressConfig;
+    /**
+     * 查询快递信息
+     * @return API原始返回的JSON字符串
+     */
+    public String  queryExpress(Map map) throws Exception {
+        // 1. 构建查询参数
+        String param = "{\"com\":\"" + map.get("company") + "\",\"num\":\"" + map.get("number") + "\"}";
+        // 2. 生成签名
+        String sign = md5(param + kd100ExpressConfig.getAppKey() + kd100ExpressConfig.getCustomer()).toUpperCase();
+        // 3. 构建请求体
+        String postData = "customer=" + URLEncoder.encode(kd100ExpressConfig.getCustomer(), "UTF-8")
+                + "&sign=" + URLEncoder.encode(sign, "UTF-8")
+                + "&param=" + URLEncoder.encode(param, "UTF-8");
+
+        // 4. 发送HTTP POST请求
+        URL url = new URL(kd100ExpressConfig.getQueryUrl());
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setRequestMethod("POST");
+        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.setConnectTimeout(5000);
+        conn.setReadTimeout(10000);
+
+        // 5. 写入请求数据
+        try (OutputStream os = conn.getOutputStream()) {
+            os.write(postData.getBytes(StandardCharsets.UTF_8));
+            os.flush();
+        }
+
+        // 6. 读取响应结果
+        int responseCode = conn.getResponseCode();
+        StringBuilder response = new StringBuilder();
+
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            BufferedReader in = new BufferedReader(
+                    new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
+            String inputLine;
+            while ((inputLine = in.readLine()) != null) {
+                response.append(inputLine);
+            }
+            in.close();
+        } else {
+            throw new RuntimeException("HTTP请求失败,状态码: " + responseCode);
+        }
+        conn.disconnect();
+        return response.toString();
+    }
+
+    /**
+     * MD5加密工具方法
+     */
+    private static String md5(String str) throws Exception {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        byte[] digest = md.digest(str.getBytes(StandardCharsets.UTF_8));
+        StringBuilder sb = new StringBuilder();
+        for (byte b : digest) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+}

+ 2 - 36
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfFeePushCallback.java

@@ -13,18 +13,13 @@ import org.springframework.web.bind.annotation.PostMapping;
 
 /**
  * 顺丰物流费用清单回调
- * 目前涉及的回调有:
- * 1.订单状态回调
- * 2.费用清单回调
- *
  * @author zxf
  * @date 2026-02-03
  */
 @RestController
-@RequestMapping("/feecallback")
+@RequestMapping("/callback")
 public class SfFeePushCallback {
     private static final Logger logger = LoggerFactory.getLogger(SfFeePushCallback.class);
-
     private final ObjectMapper objectMapper;
     private final FeePushService feePushService;
 
@@ -44,19 +39,10 @@ public class SfFeePushCallback {
     public ResponseEntity<SfFeeApiResponse> receiveFeePush(
             @RequestParam("sign") String sign,
             @RequestParam("content") String content) {
-
-        logger.info("收到顺丰运费清单推送,sign: {}", sign);
-
+        logger.info("收到顺丰运费清单推送,content: {}", content);
         try {
-          /*  // 1. 验证签名(根据顺丰文档实现)
-            if (!verifySignature(sign, content)) {
-                logger.error("签名验证失败");
-                return ResponseEntity.ok(SfFeeApiResponse.error("签名验证失败"));
-            }*/
-
             // 2. 解析JSON数据
             SfFeePushRequest feePushRequest = objectMapper.readValue(content, SfFeePushRequest.class);
-
             // 3. 参数验证
             if (feePushRequest.getWaybillNo() == null || feePushRequest.getWaybillNo().isEmpty()) {
                 return ResponseEntity.ok(SfFeeApiResponse.error("运单号不能为空"));
@@ -64,10 +50,8 @@ public class SfFeePushCallback {
             if (feePushRequest.getOrderNo() == null || feePushRequest.getOrderNo().isEmpty()) {
                 return ResponseEntity.ok(SfFeeApiResponse.error("订单号不能为空"));
             }
-
             // 4. 处理业务逻辑
             boolean success = feePushService.processFeePush(feePushRequest);
-
             if (success) {
                 logger.info("运费清单处理成功,运单号: {}, 订单号: {}",
                         feePushRequest.getWaybillNo(), feePushRequest.getOrderNo());
@@ -86,22 +70,4 @@ public class SfFeePushCallback {
         }
     }
 
-    /**
-     * 验证签名
-     * 根据顺丰文档实现签名验证逻辑
-     */
-    /*private boolean verifySignature(String sign, String content) {
-        // 实际实现应根据顺丰提供的签名算法
-        // 通常使用checkword对content进行加密,然后与sign比较
-        // 这里简化处理,实际应按照文档实现
-        try {
-            // 示例:使用MD5或SHA256等算法
-             String calculatedSign = calculateSign(content, yourCheckword);
-             return calculatedSign.equals(sign);
-
-        } catch (Exception e) {
-            logger.error("签名验证异常: {}", e.getMessage());
-            return false;
-        }
-    }*/
 }

+ 11 - 2
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfPushOrderStatusCallback.java

@@ -1,10 +1,13 @@
 package com.ruoyi.logistics.callback;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.ruoyi.logistics.domain.BizWaybillOrder;
 import com.ruoyi.logistics.domain.OrderStateDetail;
 import com.ruoyi.logistics.domain.SfApiResponse;
 import com.ruoyi.logistics.domain.SfPushOrderStateRequest;
+import com.ruoyi.logistics.service.IBizWaybillOrderService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -28,6 +31,9 @@ public class SfPushOrderStatusCallback {
     private static final Logger logger = LoggerFactory.getLogger(SfPushOrderStatusCallback.class);
 
 
+    @Autowired
+    private IBizWaybillOrderService bizWaybillOrderService;
+
     /**
      * 顺丰物流订单状态回调
      * 说明:仅限于推送上门订单调度状态  非预约订单不推送
@@ -35,7 +41,7 @@ public class SfPushOrderStatusCallback {
      * @author zxf
      * @date 2026-02-03
      */
-    @PostMapping("/orderStatus")
+    @PostMapping("/orderStatus11")
     public SfApiResponse orderStatus(@RequestBody SfPushOrderStateRequest pushRequest) throws UnsupportedEncodingException, JsonProcessingException {
         logger.info("收到顺丰订单状态推送,requestId: {}", pushRequest.getRequestId());
 
@@ -80,7 +86,10 @@ public class SfPushOrderStatusCallback {
         // 根据顺丰返回的状态吗进行系统状态变更  目前还没对
         switch (state.getOrderStateCode()) {
             case "04":
-
+                BizWaybillOrder bizWaybillOrder= new BizWaybillOrder();
+                bizWaybillOrder.setExternalWaybillNo(state.getOrderNo());
+                bizWaybillOrder.setOrderStatus(1);
+                bizWaybillOrderService.updateBizWaybillOrder(bizWaybillOrder);
                 break;
             case "04-40001":
 

+ 128 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/callback/SfRoutingPushCallback.java

@@ -0,0 +1,128 @@
+package com.ruoyi.logistics.callback;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.logistics.domain.BizWaybillOrder;
+import com.ruoyi.logistics.service.IBizWaybillOrderService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 顺丰物流订单路由状态回调相关
+ *
+ * @author zxf
+ * @date 2026-02-03
+ */
+@RestController
+@RequestMapping("/callback")
+public class SfRoutingPushCallback {
+    private static final Logger logger = LoggerFactory.getLogger(SfRoutingPushCallback.class);
+
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+    @Autowired
+    private IBizWaybillOrderService bizWaybillOrderService;
+    /**
+     * 接收JSON格式的路由推送数据
+     * 请求方法为"json"时使用此接口
+     */
+    @PostMapping("/orderStatus")
+    public Map<String, String> receiveRoutePushJson(@RequestBody Map<String, Object> requestBody) {
+        logger.info("收到顺丰物流路由推送,requestBody: {}", requestBody);
+        Map result = new HashMap<>();
+        try {
+            // 解析请求体
+            Map<String, Object> body = (Map<String, Object>) requestBody.get("Body");
+            if (body != null && body.containsKey("WaybillRoute")) {
+                List<Map<String, Object>> waybillRoutes = (List<Map<String, Object>>) body.get("WaybillRoute");
+                // 检查批次大小(顺丰限制最多10个WaybillRoute元素)
+                if (waybillRoutes.size() > 10) {
+                    result.put("return_code", "1000");
+                    result.put("return_msg", "路由信息批次大小不能超过10条");
+                    return result;
+                }
+
+                // 处理路由信息
+                for (Map<String, Object> route : waybillRoutes) {
+                    processRouteInfo(route);
+                }
+                // 返回成功响应(JSON格式)
+                result.put("return_code", "0000");
+                result.put("return_msg", "成功");
+                return result;
+            }
+            // 返回失败响应
+            result.put("return_code", "1000");
+            result.put("return_msg", "请求数据格式错误:缺少Body或WaybillRoute字段");
+            return result;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            result.put("return_code", "0000");
+            result.put("return_msg", "系统异常:" + e.getMessage());
+            return result;
+
+        }
+    }
+
+    /**
+     * 处理路由信息
+     */
+    private void processRouteInfo(Map<String, Object> route) {
+        logger.info("开始处理顺丰路由信息 - 客户运单号: {}, 客户订单号: {}, 状态码: {}, 备注: {}, 收货时间: {}",
+                route.get("mailno"),
+                route.get("orderid"),
+                route.get("opCode"),
+                route.get("remark"),
+                route.get("acceptTime"));
+        // 提取路由信息
+        String mailno = (String) route.get("mailno");          // 客户运单号
+        String orderid = (String) route.get("orderid");       // 客户订单号
+        String acceptTime = (String) route.get("acceptTime"); // 收货时间
+        String remark = (String) route.get("remark");         // 备注
+        String opCode = (String) route.get("opCode");         // 操作码
+        // TODO:
+        BizWaybillOrder bizWaybillOrder= new BizWaybillOrder();
+        switch (opCode) {
+            case "50": // 已收取快件
+                bizWaybillOrder.setOrderStatus(2);
+                bizWaybillOrder.setExternalWaybillNo(mailno);
+                //揽收时间
+                bizWaybillOrder.setPickupTime(new Date());
+                bizWaybillOrderService.updateBizWaybillOrderState( bizWaybillOrder);
+                break;
+            case "30": // 到达中转场
+                bizWaybillOrder.setOrderStatus(3);
+                bizWaybillOrder.setExternalWaybillNo(mailno);
+                bizWaybillOrderService.updateBizWaybillOrderState( bizWaybillOrder);
+                break;
+            case "44": // 派送中
+                bizWaybillOrder.setOrderStatus(5);
+                bizWaybillOrder.setExternalWaybillNo(mailno);
+                bizWaybillOrder.setDeliveryTime(new Date());
+                bizWaybillOrderService.updateBizWaybillOrderState( bizWaybillOrder);
+                break;
+            case "80": // 已签收
+                bizWaybillOrder.setOrderStatus(6);
+                bizWaybillOrder.setExternalWaybillNo(mailno);
+                bizWaybillOrder.setSignTime(new Date());
+                bizWaybillOrderService.updateBizWaybillOrderState( bizWaybillOrder);
+                break;
+            default:
+                logger.info("收到未定义的状态码: {}", opCode);
+        }
+
+
+    }
+
+
+}

+ 31 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/config/KD100ExpressConfig.java

@@ -0,0 +1,31 @@
+package com.ruoyi.logistics.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "kd100.express")
+public class KD100ExpressConfig {
+    /**
+     * 应用编码
+     */
+    private String appKey;
+
+    /**
+     * 应用密钥
+     */
+    private String appSecret;
+
+    /**
+     * 客户编码
+     */
+    private String customer;
+
+    /**
+     * 实时查询地址
+     */
+    private String queryUrl;
+
+}

+ 7 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/controller/BizWaybillOrderController.java

@@ -93,6 +93,13 @@ public class BizWaybillOrderController extends BaseController
 
     }
 
+
+
+
+
+
+
+
     /**
      * 修改运单管理
      */

+ 2 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/mapper/BizWaybillOrderMapper.java

@@ -65,4 +65,6 @@ public interface BizWaybillOrderMapper
      * @return
      */
     public BizWaybillOrder selectBizWaybillOrderByQuery(BizWaybillOrder query);
+
+    void updateBizWaybillOrderState(BizWaybillOrder bizWaybillOrder);
 }

+ 5 - 1
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/IBizWaybillOrderService.java

@@ -2,6 +2,8 @@ package com.ruoyi.logistics.service;
 
 import java.io.UnsupportedEncodingException;
 import java.util.List;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.ruoyi.logistics.domain.BizWaybillOrder;
 
 /**
@@ -34,7 +36,7 @@ public interface IBizWaybillOrderService
      * @param bizWaybillOrder 运单管理
      * @return 结果
      */
-    public int insertBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException;
+    public int insertBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException, JsonProcessingException;
 
     /**
      * 修改运单管理
@@ -66,4 +68,6 @@ public interface IBizWaybillOrderService
      * @return
      */
     public BizWaybillOrder selectBizWaybillOrderByQuery(BizWaybillOrder query);
+
+    void updateBizWaybillOrderState(BizWaybillOrder bizWaybillOrder);
 }

+ 2 - 1
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsOrderService.java

@@ -1,6 +1,7 @@
 package com.ruoyi.logistics.service;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.logistics.domain.BizWaybillOrder;
 import com.ruoyi.logistics.domain.LogisticsOrder;
@@ -24,7 +25,7 @@ public class LogisticsOrderService {
     }
 
 
-    public JSONObject createOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException {
+    public JSONObject createOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException, JsonProcessingException {
         // 根据订单中的物流公司类型获取对应服务
         LogisticsService logisticsService = logisticsFactory.getLogisticsService(bizWaybillOrder.getOrderType()==1?"JD":"SF");
         JSONObject  createOrder= logisticsService.createOrder(bizWaybillOrder);

+ 2 - 1
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsService.java

@@ -1,5 +1,6 @@
 package com.ruoyi.logistics.service;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.ruoyi.logistics.domain.BizWaybillOrder;
 /**
  * 物流相关接口定义
@@ -23,7 +24,7 @@ public interface LogisticsService {
      * @author RuiJing
      * @date 2026-02-02
      */
-    JSONObject createOrder(BizWaybillOrder bizWaybillOrder) ;
+    JSONObject createOrder(BizWaybillOrder bizWaybillOrder) throws JsonProcessingException;
 
     /**
      * 取消物流订单

+ 22 - 2
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/BizWaybillOrderServiceImpl.java

@@ -3,7 +3,9 @@ package com.ruoyi.logistics.service.impl;
 import java.io.UnsupportedEncodingException;
 import java.util.List;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.ruoyi.common.core.exception.ServiceException;
 import com.ruoyi.common.core.utils.DateUtils;
 import com.ruoyi.common.datascope.annotation.DataScope;
@@ -68,7 +70,7 @@ public class BizWaybillOrderServiceImpl implements IBizWaybillOrderService
      * @return 结果
      */
     @Override
-    public int insertBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException {
+    public int insertBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException, JsonProcessingException {
 
         LoginUser loginUser = SecurityUtils.getLoginUser();
         String orderId = redisIdGenerator.generateUniqueId("RJSD");
@@ -83,7 +85,19 @@ public class BizWaybillOrderServiceImpl implements IBizWaybillOrderService
         if(!orderObject.getBooleanValue("success")){
             throw new ServiceException("下单失败! 原因:"+orderObject.getString("msg"));
         }
-        bizWaybillOrder.setExternalWaybillNo(orderObject.getString("data"));
+        if("1".equals(bizWaybillOrder.getOrderType())){
+            bizWaybillOrder.setExternalWaybillNo(orderObject.getString("data"));
+        }
+        //顺丰物流返回的运单号
+        JSONArray waybillNoArray=orderObject.getJSONArray("data");
+        for (int i = 0; i < waybillNoArray.size(); i++) {
+            JSONObject waybillNoJSONObject = waybillNoArray.getJSONObject(i);
+            int waybillType = waybillNoJSONObject.getIntValue("waybillType");
+            String  waybillNo = waybillNoJSONObject.getString("waybillNo");
+            if(waybillType==1){
+                bizWaybillOrder.setExternalWaybillNo(waybillNo) ;
+            }
+        }
         bizWaybillOrder.setCreateTime(DateUtils.getNowDate());
         bizWaybillOrder.setUserId(loginUser.getUserid());
         bizWaybillOrder.setDeptId(loginUser.getSysUser().getDeptId());
@@ -133,4 +147,10 @@ public class BizWaybillOrderServiceImpl implements IBizWaybillOrderService
     public BizWaybillOrder selectBizWaybillOrderByQuery(BizWaybillOrder query) {
         return bizWaybillOrderMapper.selectBizWaybillOrderByQuery(query);
     }
+
+    @Override
+    public void updateBizWaybillOrderState(BizWaybillOrder bizWaybillOrder) {
+         bizWaybillOrderMapper.updateBizWaybillOrderState(bizWaybillOrder);
+
+    }
 }

+ 24 - 17
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/FeePushService.java

@@ -22,15 +22,14 @@ import java.util.List;
 
 @Service
 public class FeePushService {
+    private static final Logger logger = LoggerFactory.getLogger(FeePushService.class);
 
     @Autowired
     private IBizWaybillOrderService bizWaybillOrderService;
     @Autowired
     private IBizFinancialFeeItemsService BizFinancialFeeItemsService;
-
     @Autowired
     private IBizWaybillCostDetailsService bizWaybillCostDetailsService;
-    private static final Logger logger = LoggerFactory.getLogger(FeePushService.class);
 
     public boolean processFeePush(SfFeePushRequest request) {
         try {
@@ -40,9 +39,8 @@ public class FeePushService {
             Integer quantity = request.getQuantity();
             String productName = request.getProductName();
             List<SfFeeInfo> feeList = request.getFeeList();
-            logger.info("开始处理运费清单 - 运单号: {}, 订单号: {}, 产品: {}, 计费重量: {}kg",
+            logger.info("开始处理顺丰运费清单 - 运单号: {}, 订单号: {}, 产品: {}, 计费重量: {}kg",
                     waybillNo, orderNo, productName, totalWeight);
-
             // 1. 根据订单号查询本地订单 如果不存在该订单号  则不进行明细的入库
             BizWaybillOrder bizWaybillOrder= new BizWaybillOrder();
             bizWaybillOrder.setWaybillNo(orderNo);
@@ -52,32 +50,38 @@ public class FeePushService {
                 logger.error("订单不存在: {}", orderNo);
                 return false;
             }
-            //存在的话 就去拿到这个部门id 要知道这个供应商的费率
+            /**
+             * 存在的话 就去拿到这个部门id 要知道这个供应商的费率
+             * 还要拿到订单创建Id  数据权限可能到个人
+             */
             Long deptId=orderList.get(0).getDeptId();
-            //先写死
+            Long userId=orderList.get(0).getUserId();
+            Long waybillId=orderList.get(0).getWaybillId();
+            // TODO:先写死  这里差一个查询供应商费率的查询
             String  Rate="1.5";
-
-
-
-            // 2. 目前订单主表不涉及费用总计啥的  先不管
-
-
-            // 3. 处理费用明细
+            /*处理费用明细*/
             if (feeList != null && !feeList.isEmpty()) {
                 for (SfFeeInfo fee : feeList) {
                     BigDecimal feeAmt = fee.getFeeAmt();
-                    //回调回来的 费用类型  还需与系统 费用类型表-biz_inancial_fee_items
+                    /**
+                     * 回调回来的 费用类型  还需与系统 费用类型表-biz_inancial_fee_items
+                     *
+                     */
                     String feeTypeCode = fee.getFeeTypeCode();
                     BizFinancialFeeItems bizFinancialFeeItems = new BizFinancialFeeItems();
                     bizFinancialFeeItems.setFeeItemCategory("sf");
                     bizFinancialFeeItems.setExtFeeCode(feeTypeCode);
                     List<BizFinancialFeeItems> feeItemsList=BizFinancialFeeItemsService.selectBizFinancialFeeItemsList(bizFinancialFeeItems);
                     BizWaybillCostDetails bizWaybillCostDetails= new BizWaybillCostDetails();
-                    //顺丰的费用类型代码无法在费用类型表中匹配 这里默认给值 给到外部叫什么名字
+                    /**
+                     * 回顺丰的费用类型代码无法在费用类型表中匹配时
+                     * 匹配到---给到对应名称
+                     * 匹配不到 --- 还叫顺丰的自己的费用名称和编码
+                     */
                     bizWaybillCostDetails.setFeeName(feeItemsList.get(0).getExtFeeName());
                     if(StringUtils.isBlank(feeItemsList.get(0).getFeeItemCode())){
-                        bizWaybillCostDetails.setFeeItemCode("00");
-                        bizWaybillCostDetails.setFeeItemName("瑞鲸-其他");
+                        bizWaybillCostDetails.setFeeItemCode(feeItemsList.get(0).getExtFeeCode());
+                        bizWaybillCostDetails.setFeeItemName(feeItemsList.get(0).getExtFeeName());
                     }
                     else{
                         bizWaybillCostDetails.setFeeItemCode(feeItemsList.get(0).getFeeItemCode());
@@ -88,6 +92,9 @@ public class FeePushService {
                     BigDecimal result = feeAmt.multiply(deptRate);
                     bizWaybillCostDetails.setRateAmount(result);
                     bizWaybillCostDetails.setDeptId(deptId);
+                    bizWaybillCostDetails.setUserId(userId);
+                    bizWaybillCostDetails.setWaybillId(waybillId);
+                    bizWaybillCostDetails.setExternalWaybillNo(waybillNo);
                     // 记录费用明细
                     bizWaybillCostDetailsService.insertBizWaybillCostDetails(bizWaybillCostDetails);
                 }

+ 47 - 13
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/SFLogisticsService.java

@@ -2,6 +2,9 @@ package com.ruoyi.logistics.service.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.common.redis.service.RedisIdGenerator;
 import com.ruoyi.logistics.config.SFExpressConfig;
@@ -59,9 +62,9 @@ public class SFLogisticsService implements LogisticsService {
         1 顺丰特快
         2 顺丰标快
         6 顺丰即日*/
-        msgData.put("expressTypeId", 1);
+        msgData.put("expressTypeId", bizWaybillOrder.getProductCode());
         //包裹数  未定义  非必填
-        msgData.put("parcelQty", 1);
+        msgData.put("parcelQty", bizWaybillOrder.getGoodsQty());
         //收寄方地址参数
         List<Map<String, Object>> contactInfoList = new ArrayList<>();
         Map<String, Object> Consignor = new HashMap<>();
@@ -103,7 +106,7 @@ public class SFLogisticsService implements LogisticsService {
      * @date 2026-02-02
      */
     @Override
-    public JSONObject createOrder(BizWaybillOrder bizWaybillOrder) {
+    public JSONObject createOrder(BizWaybillOrder bizWaybillOrder) throws JsonProcessingException {
         IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER; //下订单
         CallExpressServiceTools tools=CallExpressServiceTools.getInstance();
         Map<String, String> params = new HashMap<String, String>();
@@ -113,8 +116,10 @@ public class SFLogisticsService implements LogisticsService {
         //预下单 已返回订单id
         orderData.put("orderId",bizWaybillOrder.getWaybillNo());
         orderData.put("monthlyCard",sfExpressConfig.getMonthlyCord());//月结账户
-        //包裹数目前字段没有
-        orderData.put("parcelQty",1);
+        //包裹数
+        orderData.put("parcelQty",bizWaybillOrder.getGoodsQty());
+        //产品类别
+        orderData.put("expressTypeId",bizWaybillOrder.getProductCode());
         //商品信息
         List<Map<String,Object>> cargoDetails = new ArrayList<>();
         Map cargo=new HashMap<>();
@@ -123,13 +128,8 @@ public class SFLogisticsService implements LogisticsService {
         cargo.put("weight",bizWaybillOrder.getGoodsWeight());
         cargoDetails.add(cargo);
         orderData.put("cargoDetails",cargoDetails);
-
-        //增值服务信息 serviceList":[{"name":"INSURE","value":"500"}]
-        List<Map<String,Object>> serviceList = new ArrayList<>();
-        Map service=new HashMap<>();
-        service.put("name","INSURE");
-        service.put("value","500");
-        serviceList.add(service);
+        //将增值服务字符串转换完增值服务参数
+        List<Map<String,Object>> serviceList=getAddedProducts(bizWaybillOrder.getAddedService());
         orderData.put("serviceList",serviceList);
         //收寄双方信息
         List<Map<String,Object>> contactInfoList = new ArrayList<>();
@@ -163,7 +163,8 @@ public class SFLogisticsService implements LogisticsService {
             JSONObject jsonObject = JSON.parseObject(result).getJSONObject("apiResultData");
             JSONObject resultInfo = new JSONObject();
             if (jsonObject != null && jsonObject.containsKey("success") && jsonObject.getBooleanValue("success")) {
-                resultInfo.put("success", true);
+                resultInfo.put("success", true);  //.getJSONObject("waybillNoInfoList")
+                resultInfo.put("data", jsonObject.getJSONObject("msgData").getJSONArray("waybillNoInfoList"));
                 resultInfo.put("msg", "下单成功!");
                 return resultInfo;
             } else {
@@ -179,6 +180,39 @@ public class SFLogisticsService implements LogisticsService {
 
     }
 
+    private List<Map<String, Object>> getAddedProducts(String addedService) throws JsonProcessingException {
+        List<Map<String, Object>> serviceList = new ArrayList<>();
+        ObjectMapper objectMapper = new ObjectMapper();
+        TypeFactory typeFactory = objectMapper.getTypeFactory();
+        Map<String, String> serviceMap = objectMapper.readValue(addedService, typeFactory.constructType(Map.class));
+
+        // 遍历Map的key
+        Set<String> keys = serviceMap.keySet();
+        for (String key : keys) {
+            switch (key) {
+                case "isPack":
+                    break;
+                case "guaranteeMoney": //顺丰基础包
+                    Map INSURE = new HashMap<>();
+                    INSURE.put("name", "INSURE");
+                    INSURE.put("value", serviceMap.get(key));
+                    serviceList.add(INSURE);
+                case "isOverLongWeight": //超长超重
+                    break;
+
+                case "isReceiptCollect": //签单返回
+                    break;
+                case "isWoodenCrate":   //打木架
+                    break;
+                default:
+                    log.info("收到未定义的增值服务代码: {}", key);
+
+            }
+
+        }
+       return serviceList;
+    }
+
 
     /**
      * 顺丰物流取消订单接口

+ 45 - 0
jd-logistics-modules/jd-logistics-system/src/main/resources/mapper/logistics/BizWaybillOrderMapper.xml

@@ -272,4 +272,49 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="userId != null "> and user_id = #{userId}</if>
         </where>
     </select>
+
+
+
+    <update id="updateBizWaybillOrderState" parameterType="com.ruoyi.logistics.domain.BizWaybillOrder">
+        update biz_waybill_order
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="waybillNo != null">waybill_no = #{waybillNo},</if>
+            <if test="orderType != null">order_type = #{orderType},</if>
+            <if test="senderName != null">sender_name = #{senderName},</if>
+            <if test="senderPhone != null">sender_phone = #{senderPhone},</if>
+            <if test="senderProvince != null">sender_province = #{senderProvince},</if>
+            <if test="senderCity != null">sender_city = #{senderCity},</if>
+            <if test="senderCounty != null">sender_county = #{senderCounty},</if>
+            <if test="senderAddress != null">sender_address = #{senderAddress},</if>
+            <if test="receiverName != null">receiver_name = #{receiverName},</if>
+            <if test="receiverPhone != null">receiver_phone = #{receiverPhone},</if>
+            <if test="receiverProvince != null">receiver_province = #{receiverProvince},</if>
+            <if test="receiverCity != null">receiver_city = #{receiverCity},</if>
+            <if test="receiverCounty != null">receiver_county = #{receiverCounty},</if>
+            <if test="receiverAddress != null">receiver_address = #{receiverAddress},</if>
+            <if test="goodsName != null">goods_name = #{goodsName},</if>
+            <if test="goodsWeight != null">goods_weight = #{goodsWeight},</if>
+            <if test="goodsVolume != null">goods_volume = #{goodsVolume},</if>
+            <if test="goodsQty != null">goods_qty = #{goodsQty},</if>
+            <if test="orderStatus != null">order_status = #{orderStatus},</if>
+            <if test="pickupType != null">pickup_type = #{pickupType},</if>
+            <if test="sendStartTime != null">send_start_time = #{sendStartTime},</if>
+            <if test="pickupTime != null">pickup_time = #{pickupTime},</if>
+            <if test="deliveryTime != null">delivery_time = #{deliveryTime},</if>
+            <if test="signTime != null">sign_time = #{signTime},</if>
+            <if test="cancelReason != null">cancel_reason = #{cancelReason},</if>
+            <if test="parentWaybillId != null">parent_waybill_id = #{parentWaybillId},</if>
+            <if test="invoiceFlag != null">invoice_flag = #{invoiceFlag},</if>
+            <if test="adjustFlag != null">adjust_flag = #{adjustFlag},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+        </trim>
+        where external_waybill_no = #{externalWaybillNo}
+    </update>
 </mapper>