소스 검색

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

cgp 1 주 전
부모
커밋
596ff55840

+ 45 - 124
fs-admin/src/main/java/com/fs/his/controller/JstOrderSyncController.java

@@ -1,23 +1,20 @@
 package com.fs.his.controller;
 
 import com.baidu.dev2.thirdparty.commons.codec.digest.DigestUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fs.erp.dto.OrderItemDTO;
-import com.fs.erp.dto.PaymentDTO;
-import com.fs.erp.dto.ShopOrderDTO;
-import com.fs.erp.dto.tl.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.erp.dto.tl.dto.*;
 import com.fs.erp.service.TlErpOrderService;
 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.math.BigDecimal;
 import java.time.Instant;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 
 /**
- * 聚水潭订单同步接口
+ * 聚水潭[兔灵]订单同步接口
  */
 @Slf4j
 @RestController
@@ -28,157 +25,81 @@ public class JstOrderSyncController {
     @Autowired
     private TlErpOrderService jstErpHttpService;
 
+    @Autowired
+    private ObjectMapper objectMapper;
 
 
     private static final String partnerKey="erp";
 
 
+    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
+     * 其中取消订单回调传入了token,其他接口没有,暂时还不知道这个token的作用
      */
     @PostMapping("/open/callback")
-    public ResponseEntity<PushResponse> handleLogisticsPush(
+    public ResponseEntity<PushResponse> handleCallback(
             @RequestParam String partnerid,
             @RequestParam String method,
             @RequestParam Long ts,
             @RequestParam String sign,
-            @RequestBody JstLogisticsPushRequest request) {
+            // 注意:订单取消接口还有 token,但其他没有。聚水潭文档说 cancel.order 有 token
+            @RequestParam(required = false) String token,
+            @RequestBody String rawBody) {
 
         // 1. 校验 partnerid
         if (!"erp".equals(partnerid)) {
             return ResponseEntity.ok(new PushResponse("1", "invalid partnerid"));
         }
 
-        // 2. 校验时间戳(±10分钟)
+        // 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) {
             return ResponseEntity.ok(new PushResponse("1", "ts expired"));
         }
 
-        // 3. 验签
+        // 4. 验签(注意:sign 拼接规则不含 token!)
         String signSource = method + partnerid + "ts" + ts + partnerKey;
         String expectedSign = DigestUtils.md5Hex(signSource).toLowerCase();
         if (!expectedSign.equals(sign)) {
-            log.warn("聚水潭签名校验失败: method={}, ts={}, sign={}", method, ts, sign);
+            log.warn("签名校验失败: method={}, ts={}", method, ts);
             return ResponseEntity.ok(new PushResponse("1", "invalid sign"));
         }
 
-        // 4. 处理业务
+        // 5. 根据 method 反序列化并处理
         try {
-            jstErpHttpService.jSTanErpLogisticsCallback(request);
+            if ("logistics.upload".equals(method)) {
+                JstLogisticsPushDTO req = objectMapper.readValue(rawBody, JstLogisticsPushDTO.class);
+                jstErpHttpService.jSTanErpLogisticsCallback(req);
+            } else if ("inventory.upload".equals(method)) {
+                JstInventoryPushDTO req = objectMapper.readValue(rawBody, JstInventoryPushDTO.class);
+                jstErpHttpService.jSTanErpInventoryCallback(req);
+            } else if ("cancel.order".equals(method)) {
+                JstCancelOrderDTO req = objectMapper.readValue(rawBody, JstCancelOrderDTO.class);
+                jstErpHttpService.jSTanErpCancelOrderCallback(req);
+            } else if ("refund.goods".equals(method)) {
+                JstRefundGoodsDTO req = objectMapper.readValue(rawBody, JstRefundGoodsDTO.class);
+                jstErpHttpService.jSTanErpRefundGoodsCallback(req);
+            } else {
+                return ResponseEntity.ok(new PushResponse("1", "unknown method"));
+            }
             return ResponseEntity.ok(new PushResponse("0", "执行成功"));
         } catch (Exception e) {
-            log.error("处理聚水潭物流回调异常", e);
+            log.error("处理聚水潭回调异常, method={}", method, e);
             return ResponseEntity.ok(new PushResponse("1", "system error"));
         }
     }
-
-    // 模拟兔灵erp订单同步(推送)
-    @PostMapping("/create")
-    public Object syncOrderToJst(){
-        TlCreateOrderRequest request=fillRequest();
-        log.info("同步订单请求,corp_id={}, so_id={}",
-                request.getCorpId(),
-                request.getData() != null && !request.getData().isEmpty()
-                        ? request.getData().get(0).getSoId() : "N/A");
-        return jstErpHttpService.syncOrderToJst(request);
-    }
-
-    /**
-     * 辅助方法 填充入参对象JstCreateOrderRequest
-     * */
-
-    private TlCreateOrderRequest fillRequest() {
-        TlCreateOrderRequest request = new TlCreateOrderRequest();
-        request.setCorpId("LwMAMdlBIH7agxn2t9N4Zv40"); // 正式环境企业ID
-
-
-        //ShopOrderDTO order = buildOrderItem();
-        TlOrderItem order = buildOrderItem();
-        request.setData(Collections.singletonList(order));
-
-        TlOptions options = buildOptions();
-        request.setOptions(options);
-
-        return request;
-    }
-
-    // 构建订单主体
-    private TlOrderItem buildOrderItem() {
-        //ShopOrderDTO order = new ShopOrderDTO();
-        TlOrderItem order = new TlOrderItem();
-        //order.setShopId(18150182);//测试店铺
-        order.setShopId(19415819);
-        order.setSoId("SO_20251110_001");
-        order.setOrderDate("2025-11-10T10:30:00Z");
-        order.setShopStatus("paid");
-        order.setShopBuyerId("buyer_123");
-
-        order.setReceiverState("广东省");
-        order.setReceiverCity("深圳市");
-        order.setReceiverDistrict("南山区");
-        order.setReceiverAddress("科技园A座101");
-        order.setReceiverName("张三");
-        order.setReceiverMobile("13800138000");
-//        order.setPayAmount(10000.0);
-//        order.setFreight(0.0);
-        order.setPayAmount(10000);
-        order.setFreight(0);
-
-        order.setRemark("卖家备注");
-        order.setBuyerMessage("请发顺丰");
-        order.setLabels("测试,同步");
-        order.setShopModified("2025-11-10T10:30:00Z");
-        order.setLId("cs12345678912");
-        order.setIsCod(false);
-
-        // 设置商品明细和支付信息
-        order.setItems(Collections.singletonList(buildOrderItemDetail()));
-        order.setPay(buildPayDetail());
-
-        return order;
-    }
-
-    // 构建商品明细
-    private TlOrderItemDetail buildOrderItemDetail() {
-        TlOrderItemDetail item = new TlOrderItemDetail();
-        //OrderItemDTO item = new OrderItemDTO();
-        item.setSkuId("SKU123");
-        item.setShopSkuId("SHOP_SKU_001");
-//        item.setAmount(BigDecimal.valueOf(10000));      // 实付金额(分)
-//        item.setPrice(BigDecimal.valueOf(10000));       // 单价(分)
-//        item.setBasePrice(12000.0);   // 原价(分)
-
-        item.setAmount(10000);      // 实付金额(分)
-        item.setPrice(10000);       // 单价(分)
-        item.setBasePrice(12000);   // 原价(分)
-        item.setQty(1);
-        item.setName("测试商品");
-        item.setOuterOiId("OI_20251110_001");
-        item.setProducedDate("2025-11-10T00:00:00Z");
-        item.setBatchId(null);
-        return item;
-    }
-
-    // 构建支付明细
-    private TlPayDetail buildPayDetail() {
-        //PaymentDTO pay = new PaymentDTO();
-        TlPayDetail pay = new TlPayDetail();
-        pay.setOuterPayId("PAY_20251110_001"); // 必填
-        //pay.setPayDate("2025-11-10T10:30:00Z"); // 必填,RFC3339
-        pay.setPayDate("2025-11-11 10:39:03"); // 必填,RFC3339
-        pay.setPayment("online");
-        pay.setSellerAccount("alipay@company.com"); // 必填
-        pay.setBuyerAccount("buyer@example.com");   // 必填
-        pay.setAmount(10000);
-        return pay;
-    }
-
-    // 构建选项
-    private TlOptions buildOptions() {
-        TlOptions options = new TlOptions();
-        options.setJstServerId(1);
-        return options;
-    }
 }

+ 0 - 9
fs-service/src/main/java/com/fs/erp/dto/tl/TlCreateOrderResponse.java

@@ -1,9 +0,0 @@
-package com.fs.erp.dto.tl;
-
-import lombok.Data;
-
-@Data
-public class TlCreateOrderResponse {
-    private String status;
-    private String errmsg;
-}

+ 13 - 0
fs-service/src/main/java/com/fs/erp/dto/tl/dto/JstCancelOrderDTO.java

@@ -0,0 +1,13 @@
+package com.fs.erp.dto.tl.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class JstCancelOrderDTO {
+    @JsonProperty("so_id")
+    private String soId; // 线上单号
+
+    @JsonProperty("remark")
+    private String remark; // 备注
+}

+ 41 - 0
fs-service/src/main/java/com/fs/erp/dto/tl/dto/JstInventoryPushDTO.java

@@ -0,0 +1,41 @@
+package com.fs.erp.dto.tl.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class JstInventoryPushDTO {
+    @JsonProperty("datas")
+    private List<StockItem> datas;
+
+    @Data
+    public static class StockItem {
+        @JsonProperty("i_id")
+        private String iId; // 商品款号
+
+        @JsonProperty("id")
+        private Integer id; // 编号
+
+        @JsonProperty("qty")
+        private Integer qty; // 数量
+
+        @JsonProperty("shop_i_id")
+        private String shopIId; // 店铺商品款号
+
+        @JsonProperty("shop_id")
+        private Integer shopId; // 店铺编号
+
+        @JsonProperty("shop_sku_id")
+        private String shopSkuId; // 店铺商品编码
+
+        @JsonProperty("sku_id")
+        private String skuId; // 商品编码
+
+        @JsonProperty("sku_source")
+        private String skuSource; // 来源
+
+        @JsonProperty("modified")
+        private String modified; // 修改时间
+    }
+}

+ 5 - 3
fs-service/src/main/java/com/fs/erp/dto/tl/JstLogisticsPushRequest.java → fs-service/src/main/java/com/fs/erp/dto/tl/dto/JstLogisticsPushDTO.java

@@ -1,11 +1,13 @@
-package com.fs.erp.dto.tl;
+package com.fs.erp.dto.tl.dto;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 import java.util.List;
-
+/**
+ * 物流同步回调Dto
+ * */
 @Data
-public class JstLogisticsPushRequest {
+public class JstLogisticsPushDTO {
     // 内部订单号
     @JsonProperty("o_id")
     private Long oId;

+ 44 - 0
fs-service/src/main/java/com/fs/erp/dto/tl/dto/JstRefundGoodsDTO.java

@@ -0,0 +1,44 @@
+package com.fs.erp.dto.tl.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class JstRefundGoodsDTO {
+    @JsonProperty("action_name")
+    private String actionName; // 操作类型: 确认收货/取消收货
+
+    @JsonProperty("as_id")
+    private Integer asId; // 内部售后单号
+
+    @JsonProperty("o_id")
+    private Integer oId; // 内部单号
+
+    @JsonProperty("outer_as_id")
+    private String outerAsId; // 外部售后单号
+
+    @JsonProperty("remark")
+    private String remark; // 备注
+
+    @JsonProperty("shop_id")
+    private Integer shopId; // 店铺编号
+
+    @JsonProperty("so_id")
+    private String soId; // 线上单号
+
+    @JsonProperty("unique_id")
+    private String uniqueId; // 请求唯一值
+
+    @JsonProperty("items")
+    private List<RefundItem> items;
+
+    @Data
+    public static class RefundItem {
+        @JsonProperty("qty")
+        private Integer qty;
+
+        @JsonProperty("sku_id")
+        private String skuId;
+    }
+}

+ 1 - 1
fs-service/src/main/java/com/fs/erp/dto/tl/PushResponse.java → fs-service/src/main/java/com/fs/erp/dto/tl/dto/PushResponse.java

@@ -1,4 +1,4 @@
-package com.fs.erp.dto.tl;
+package com.fs.erp.dto.tl.dto;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import lombok.AllArgsConstructor;

+ 0 - 3
fs-service/src/main/java/com/fs/erp/http/JstErpHttpService.java

@@ -2,9 +2,6 @@ package com.fs.erp.http;
 
 import com.alibaba.fastjson.JSONObject;
 import com.fs.erp.dto.*;
-import com.fs.erp.dto.tl.JstLogisticsPushRequest;
-import com.fs.erp.dto.tl.TlCreateOrderRequest;
-import com.fs.erp.dto.tl.TlCreateOrderResponse;
 import com.fs.ybPay.dto.RefundOrderDTO;
 
 /**

+ 0 - 10
fs-service/src/main/java/com/fs/erp/http/JstErpHttpServiceImpl.java

@@ -9,27 +9,17 @@ import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.PropertyNamingStrategy;
 import com.alibaba.fastjson.TypeReference;
 import com.alibaba.fastjson.serializer.SerializeConfig;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fs.erp.dto.*;
-import com.fs.erp.dto.tl.JstLogisticsPushRequest;
-import com.fs.erp.dto.tl.TlCreateOrderRequest;
-import com.fs.erp.dto.tl.TlCreateOrderResponse;
 import com.fs.erp.service.impl.JstTokenService;
 import com.fs.erp.utils.SignUtil;
 import com.fs.ybPay.dto.RefundOrderDTO;
 import com.hc.openapi.tool.util.ObjectUtils;
 import lombok.extern.slf4j.Slf4j;
 //import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.codec.digest.DigestUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.*;
 import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
 
-import java.time.Instant;
 import java.util.*;
 
 @Slf4j

+ 26 - 7
fs-service/src/main/java/com/fs/erp/service/TlErpOrderService.java

@@ -1,11 +1,11 @@
 package com.fs.erp.service;
 
-import cn.hutool.http.HttpResponse;
-import com.fs.erp.dto.CommonResponse;
-import com.fs.erp.dto.tl.JstLogisticsPushRequest;
+
+import com.fs.erp.dto.tl.dto.JstCancelOrderDTO;
+import com.fs.erp.dto.tl.dto.JstInventoryPushDTO;
+import com.fs.erp.dto.tl.dto.JstLogisticsPushDTO;
 import com.fs.erp.dto.tl.TlCreateOrderRequest;
-import com.fs.erp.dto.tl.TlCreateOrderResponse;
-import org.springframework.http.ResponseEntity;
+import com.fs.erp.dto.tl.dto.JstRefundGoodsDTO;
 
 public interface TlErpOrderService {
 
@@ -17,9 +17,28 @@ public interface TlErpOrderService {
      */
     Boolean syncOrderToJst(TlCreateOrderRequest request);
 
+
+    /**
+     * 聚水潭erp库存同步回调
+     * @param request 订单物流信息
+     */
+    void jSTanErpInventoryCallback(JstInventoryPushDTO request);
+
+    /**
+     * 聚水潭erp取消订单回调
+     * @param request 订单物流信息
+     */
+    void jSTanErpCancelOrderCallback(JstCancelOrderDTO request);
+
+    /**
+     * 聚水潭erp物流同步回调
+     * @param request 订单物流信息
+     */
+    void jSTanErpLogisticsCallback(JstLogisticsPushDTO request);
+
     /**
-     * 聚水潭erp物流回调接口
+     * 聚水潭erp售后收货回调
      * @param request 订单物流信息
      */
-    public void jSTanErpLogisticsCallback(JstLogisticsPushRequest request);
+    void jSTanErpRefundGoodsCallback(JstRefundGoodsDTO request);
 }

+ 0 - 1
fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java

@@ -13,7 +13,6 @@ import com.fs.erp.constant.TaskStatusEnum;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.tl.TlCreateOrderRequest;
-import com.fs.erp.dto.tl.TlCreateOrderResponse;
 import com.fs.erp.dto.tl.TlOptions;
 import com.fs.erp.http.JstErpHttpService;
 import com.fs.erp.mapper.FsJstAftersalePushMapper;

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

@@ -4,8 +4,11 @@ import cn.hutool.http.HttpResponse;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fs.erp.dto.tl.JstLogisticsPushRequest;
+import com.fs.erp.dto.tl.dto.JstCancelOrderDTO;
+import com.fs.erp.dto.tl.dto.JstInventoryPushDTO;
+import com.fs.erp.dto.tl.dto.JstLogisticsPushDTO;
 import com.fs.erp.dto.tl.TlCreateOrderRequest;
+import com.fs.erp.dto.tl.dto.JstRefundGoodsDTO;
 import com.fs.erp.service.TlErpOrderService;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.service.IFsStoreOrderService;
@@ -71,7 +74,7 @@ public class TlErpOrderServiceImpl implements TlErpOrderService {
 
             if (!response.isOk()) {
                 log.error("HTTP 请求失败,状态码: {}", response.getStatus());
-                throw new RuntimeException("调用【兔灵】接口失败,HTTP 状态码: " + response.getStatus());
+                throw new RuntimeException("调用[兔灵]接口失败,HTTP 状态码: " + response.getStatus());
             }
 
             // 解析响应体
@@ -80,17 +83,17 @@ public class TlErpOrderServiceImpl implements TlErpOrderService {
             try {
                 result = objectMapper.readValue(responseBody, Map.class);
             } catch (Exception e) {
-                log.error("无法解析【兔灵】响应体: {}", responseBody, e);
-                throw new RuntimeException("【兔灵】返回非 JSON 响应", e);
+                log.error("无法解析[兔灵]响应体: {}", responseBody, e);
+                throw new RuntimeException("[兔灵]返回非 JSON 响应", e);
             }
             // 判断业务状态是否为 "ok"
             String status = (String) result.get("status");
             if (!"ok".equals(status)) {
                 String errmsg = (String) result.get("errmsg");
-                log.error("【兔灵】业务处理失败,status: {}, errmsg: {}", status, errmsg);
-                throw new RuntimeException("【兔灵】同步订单失败: " + (errmsg != null ? errmsg : "未知错误"));
+                log.error("[兔灵]业务处理失败,status: {}, errmsg: {}", status, errmsg);
+                throw new RuntimeException("[兔灵]同步订单失败: " + (errmsg != null ? errmsg : "未知错误"));
             }
-            log.info("订单同步到【兔灵】成功!{}",result);
+            log.info("订单同步到[兔灵]成功!{}",result);
             return true;
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -98,13 +101,22 @@ public class TlErpOrderServiceImpl implements TlErpOrderService {
 
     }
 
-    public void jSTanErpLogisticsCallback(JstLogisticsPushRequest request) {
+    @Override
+    public void jSTanErpInventoryCallback(JstInventoryPushDTO request) {
+        log.info("收到聚水潭[兔灵]库存同步: {}", request);
+    }
+
+    @Override
+    public void jSTanErpCancelOrderCallback(JstCancelOrderDTO request) {
+        log.info("收到聚水潭[兔灵]取消订单: {}", request);
+    }
+    public void jSTanErpLogisticsCallback(JstLogisticsPushDTO request) {
         // 关键业务字段
         String soId = request.getSoId();       // 外部单号
         String lId = request.getLId();         // 物流单号
         String lcId = request.getLcId();       // 快递公司编码
         String sendDate = request.getSendDate();
-        log.info("收到聚水潭【兔灵】物流单号推送: 外部单号:{}, 物流单号:{}, 快递公司编码:{}, 发送时间:{}", soId, lId, lcId, sendDate);
+        log.info("收到聚水潭[兔灵]物流单号推送: 外部单号:{}, 物流单号:{}, 快递公司编码:{}, 发送时间:{}", soId, lId, lcId, sendDate);
 
         // TODO: 根据 id 查询系统中的订单,并更新物流信息
         // Order order = orderRepository.findBySoId(soId);
@@ -136,6 +148,11 @@ public class TlErpOrderServiceImpl implements TlErpOrderService {
 
     }
 
+    @Override
+    public void jSTanErpRefundGoodsCallback(JstRefundGoodsDTO request) {
+        log.info("收到聚水潭[兔灵]售后收货商品: {}", request);
+    }
+
 
     /**
      * 递归对 Map 进行按键升序排序(支持嵌套 Map 和 List)