Переглянути джерело

完善聚水潭[兔灵]erp回调接口

cgp 1 тиждень тому
батько
коміт
c7ec9c19c8

+ 70 - 44
fs-admin/src/main/java/com/fs/his/controller/JstOrderSyncController.java

@@ -8,10 +8,9 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+
 import java.time.Instant;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
 /**
  * 聚水潭[兔灵]订单同步接口
@@ -21,24 +20,27 @@ import java.util.List;
 @RequestMapping("/sync/order/jst")
 public class JstOrderSyncController {
 
-
     @Autowired
     private TlErpOrderService jstErpHttpService;
 
     @Autowired
     private ObjectMapper objectMapper;
 
+    //聚水潭官方文档说对于回调请求 partnerKey 和 partnerid 的值相同
+    private static final String PARTNER_ID = "erp";
+    private static final String PARTNER_KEY = "erp";
 
-    private static final String partnerKey="erp";
+    private static final Set<String> SUPPORTED_METHODS;
 
+    static {
+        Set<String> supported = new HashSet<>();
+        supported.add("logistics.upload");
+        supported.add("cancel.order");
+        supported.add("inventory.upload");
+        supported.add("refund.goods");
+        SUPPORTED_METHODS = Collections.unmodifiableSet(supported);
+    }
 
-    private static final List<String> SUPPORTED_METHODS =
-            Collections.unmodifiableList(Arrays.asList(
-                    "logistics.upload",
-                    "cancel.order",
-                    "inventory.upload",
-                    "refund.goods"
-            ));
     /**
      * 聚水潭erp物流回调接口
      * URL: POST /open/callback?partnerid=erp&method=logistics.upload&ts=xxx&sign=xxx
@@ -50,55 +52,38 @@ public class JstOrderSyncController {
             @RequestParam String method,
             @RequestParam Long ts,
             @RequestParam String sign,
-            // 注意:订单取消接口还有 token,但其他没有。聚水潭文档说 cancel.order 有 token
-            @RequestParam(required = false) String token,
+            @RequestParam(required = false) String token, // token 未在当前逻辑中使用
             @RequestBody String rawBody) {
 
-        // 1. 校验 partnerid
-        if (!"erp".equals(partnerid)) {
-            return ResponseEntity.ok(new PushResponse("1", "invalid partnerid"));
-        }
+        log.info("收到聚水潭[兔灵]回调, method={}, ts={}, rawBody={}", method, ts, rawBody);
 
-        // 2. 校验 method
-        if (!SUPPORTED_METHODS.contains(method)) {
-            log.warn("不支持的 method: {}", method);
-            return ResponseEntity.ok(new PushResponse("1", "unsupported method"));
+        // 1. 调用封装的校验方法
+        ResponseEntity<PushResponse> validationResponse = validateRequest(partnerid, method, ts, sign);
+        if (validationResponse != null) {
+            // 如果校验失败,直接返回错误响应
+            return validationResponse;
         }
 
-        // 3. 校验时间戳
-        long now = Instant.now().getEpochSecond();
-        if (Math.abs(now - ts) > 600) {
-            return ResponseEntity.ok(new PushResponse("1", "ts expired"));
-        }
-
-        // 4. 验签(注意:sign 拼接规则不含 token!)
-        String signSource = method + partnerid + "ts" + ts + partnerKey;
-        String expectedSign = DigestUtils.md5Hex(signSource).toLowerCase();
-        if (!expectedSign.equals(sign)) {
-            log.warn("签名校验失败: method={}, ts={}", method, ts);
-            return ResponseEntity.ok(new PushResponse("1", "invalid sign"));
-        }
-
-        // 5. 根据 method 反序列化并处理
+        // 2. 根据 method 反序列化并处理
         try {
             if ("inventory.upload".equals(method)) {
-                log.info("处理聚水潭库存同步回调");
+                //处理聚水潭库存同步回调
                 JstInventoryPushDTO req = objectMapper.readValue(rawBody, JstInventoryPushDTO.class);
                 jstErpHttpService.jSTanErpInventoryCallback(req);
             } else if ("cancel.order".equals(method)) {
-                log.info("处理聚水潭取消订单回调");
+                //处理聚水潭取消订单回调
                 JstCancelOrderDTO req = objectMapper.readValue(rawBody, JstCancelOrderDTO.class);
                 jstErpHttpService.jSTanErpCancelOrderCallback(req);
-            }
-            else if ("logistics.upload".equals(method)) {
-                log.info("处理聚水潭物流同步回调");
+            } else if ("logistics.upload".equals(method)) {
+                //处理聚水潭物流同步回调
                 JstLogisticsPushDTO req = objectMapper.readValue(rawBody, JstLogisticsPushDTO.class);
                 jstErpHttpService.jSTanErpLogisticsCallback(req);
-            }else if ("refund.goods".equals(method)) {
-                log.info("处理聚水潭售后收货回调");
+            } else if ("refund.goods".equals(method)) {
+                //处理聚水潭售后收货回调
                 JstRefundGoodsDTO req = objectMapper.readValue(rawBody, JstRefundGoodsDTO.class);
                 jstErpHttpService.jSTanErpRefundGoodsCallback(req);
             } else {
+                // 理论上这步不会走到,因为 validateRequest 已经检查过了
                 return ResponseEntity.ok(new PushResponse("1", "unknown method"));
             }
             return ResponseEntity.ok(new PushResponse("0", "执行成功"));
@@ -107,4 +92,45 @@ public class JstOrderSyncController {
             return ResponseEntity.ok(new PushResponse("1", "system error"));
         }
     }
+
+    /**
+     * 封装的请求校验方法
+     *
+     * @param partnerid 请求中的 partnerid
+     * @param method    请求中的 method
+     * @param ts        请求中的时间戳
+     * @param sign      请求中的签名
+     * @return 如果校验失败,返回包含错误信息的 ResponseEntity;如果校验成功,返回 null。
+     */
+    private ResponseEntity<PushResponse> validateRequest(String partnerid, String method, Long ts, String sign) {
+        // 1. 校验 partnerid
+        if (!PARTNER_ID.equals(partnerid)) {
+            log.warn("校验失败: invalid partnerid={}", partnerid);
+            return ResponseEntity.ok(new PushResponse("1", "invalid partnerid"));
+        }
+
+        // 2. 校验 method
+        if (!SUPPORTED_METHODS.contains(method)) {
+            log.warn("校验失败: 不支持的 method={}", method);
+            return ResponseEntity.ok(new PushResponse("1", "unsupported method"));
+        }
+
+        // 3. 校验时间戳
+        long now = Instant.now().getEpochSecond();
+        if (Math.abs(now - ts) > 600) { // 允许 10 分钟的时间差
+            log.warn("校验失败: ts expired, now={}, ts={}", now, ts);
+            return ResponseEntity.ok(new PushResponse("1", "ts expired"));
+        }
+
+        // 4. 验签(注意:sign 拼接规则不含 token!)
+        String signSource = method + partnerid + "ts" + ts + PARTNER_KEY;
+        String expectedSign = DigestUtils.md5Hex(signSource).toLowerCase();
+        if (!expectedSign.equals(sign)) {
+            log.warn("校验失败: 签名校验失败, method={}, ts={}, expectedSign={}, receivedSign={}", method, ts, expectedSign, sign);
+            return ResponseEntity.ok(new PushResponse("1", "invalid sign"));
+        }
+
+        // 所有校验通过
+        return null;
+    }
 }

+ 0 - 9
fs-service/src/main/java/com/fs/erp/service/impl/TlErpOrderServiceImpl.java

@@ -117,15 +117,6 @@ public class TlErpOrderServiceImpl implements TlErpOrderService {
         String lcId = request.getLcId();       // 快递公司编码
         String sendDate = request.getSendDate();
         log.info("收到聚水潭[兔灵]物流单号推送: 外部单号:{}, 物流单号:{}, 快递公司编码:{}, 发送时间:{}", soId, lId, lcId, sendDate);
-
-        // TODO: 根据 id 查询系统中的订单,并更新物流信息
-        // Order order = orderRepository.findBySoId(soId);
-        // if (order != null) {
-        //     order.setLogisticsNo(lId);
-        //     order.setLogisticsCompany(lcId);
-        //     order.setShipTime(LocalDateTime.parse(sendDate, ...));
-        //     orderRepository.save(order);
-        // }
         FsStoreOrder fsStoreOrder = storeOrderService.selectFsStoreOrderByOrderCode(request.getSoId());
         if (fsStoreOrder != null && fsStoreOrder.getIsPay() == 1) {
             FsStoreOrder map = new FsStoreOrder();