xdd преди 2 месеца
родител
ревизия
87c5c22ed3

+ 0 - 4
fs-service-system/src/main/java/com/fs/erp/dto/sdk/wangdian/api/WdtClient.java

@@ -26,13 +26,9 @@ import java.util.Map;
 @Slf4j
 public class WdtClient {
 
-	@Value("${fsConfig.erpWdAppKey}")
 	private static String appkey;
-	@Value("${fsConfig.erpWdAppsecret}")
 	private static String appsecret;
-	@Value("${fsConfig.erpWdSid}")
 	private static String sid;
-	@Value("${fsConfig.erpWdBaseUrl}")
 	private static String baseUrl;
 
 	private static volatile WdtClient wdtClient;

+ 128 - 0
fs-service-system/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/AfterSaleStatusEnum.java

@@ -0,0 +1,128 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+import lombok.Getter;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * 平台售后状态枚举
+ * <p>
+ * 该枚举定义了平台售后流程中的各个主要状态及其对应的编码和中文描述。
+ * 用于标识和管理售后订单的处理进度。
+ * </p>
+ * <ul>
+ *     <li>{@link #WAIT_SELLER_AGREE} - 申请退款/售后,等待商家处理</li>
+ *     <li>{@link #SELLER_REFUSE} - 商家拒绝</li>
+ *     <li>{@link #CLOSED} - 售后关闭</li>
+ *     <li>{@link #GOODS_RETURNING} - 买家待退货</li>
+ *     <li>{@link #GOODS_RECEIVING} - 商家待收货</li>
+ *     <li>{@link #SUCCESS} - 售后成功</li>
+ * </ul>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Getter // Lombok注解,自动为所有final字段生成getter方法
+public enum AfterSaleStatusEnum {
+
+    /**
+     * code: wait_seller_agree
+     * <p>
+     * 状态描述: 申请退款。买家已发起售后申请,等待商家审核同意。
+     * </p>
+     */
+    WAIT_SELLER_AGREE("wait_seller_agree", "申请退款"),
+
+    /**
+     * code: seller_refuse
+     * <p>
+     * 状态描述: 拒绝退款。商家审核后,不同意买家的售后申请。
+     * </p>
+     */
+    SELLER_REFUSE("seller_refuse", "拒绝退款"),
+
+    /**
+     * code: closed
+     * <p>
+     * 状态描述: 退款关闭。售后流程结束,可能由买家撤销、超时未处理、双方协商一致等原因导致关闭。
+     * </p>
+     */
+    CLOSED("closed", "退款关闭"),
+
+    /**
+     * code: goods_returning
+     * <p>
+     * 状态描述: 待退货。商家同意退货后,等待买家填写物流单号并寄回商品。
+     * </p>
+     */
+    GOODS_RETURNING("goods_returning", "待退货"),
+
+    /**
+     * code: goods_receiving
+     * <p>
+     * 状态描述: 待收货。买家已发货,等待商家确认收到退回的商品。
+     * </p>
+     */
+    GOODS_RECEIVING("goods_receiving", "待收货"),
+
+    /**
+     * code: success
+     * <p>
+     * 状态描述: 退款成功。售后流程已成功完成,款项已退还给买家或换货/维修已处理完毕。
+     * </p>
+     */
+    SUCCESS("success", "退款成功");
+
+    /**
+     * 状态编码
+     * <p>
+     * 对应平台内部或接口传输时使用的状态标识符。
+     * </p>
+     */
+    private final String code;
+
+    /**
+     * 状态描述
+     * <p>
+     * 对售后状态的中文解释,用于界面展示或日志记录。
+     * </p>
+     */
+    private final String description;
+
+    /**
+     * 枚举构造函数
+     *
+     * @param code        状态编码 (String)
+     * @param description 状态描述 (String)
+     */
+    AfterSaleStatusEnum(String code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态编码获取对应的枚举实例
+     * <p>
+     * 提供一个便捷的方法,通过字符串编码查找对应的枚举常量。
+     * 比较时忽略大小写。
+     * </p>
+     *
+     * @param code 状态编码 (String)
+     * @return 对应的 {@code AfterSaleStatusEnum} 实例,如果 code 为 {@code null} 或未找到匹配项,则返回 {@code null}
+     */
+    public static AfterSaleStatusEnum getByCode(String code) {
+        if (code == null) {
+            return null; // 处理null输入
+        }
+        // 使用 Stream API 进行查找,忽略大小写进行匹配
+        return Arrays.stream(AfterSaleStatusEnum.values())
+                .filter(enumInstance -> enumInstance.getCode().equalsIgnoreCase(code)) // 忽略大小写比较
+                .findFirst() // 找到第一个匹配的
+                .orElse(null); // 如果找不到,返回null
+    }
+
+    // Lombok 的 @Getter 会自动生成以下公共方法:
+    // public String getCode() { return this.code; }
+    // public String getDescription() { return this.description; }
+}

+ 121 - 0
fs-service-system/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/RefundTypeEnum.java

@@ -0,0 +1,121 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+import lombok.Getter;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * 退款类型枚举
+ * <p>
+ * 该枚举定义了系统支持的几种主要退款类型及其对应的编码和描述。
+ * 主要用于区分订单在不同状态或场景下的退款处理方式。
+ * </p>
+ * <ul>
+ *     <li>{@link #REFUND_BEFORE_SHIPPING} - 未发货仅退款</li>
+ *     <li>{@link #REFUND_WITHOUT_RETURN} - 已发货仅退款(无需退货)</li>
+ *     <li>{@link #RETURN_AND_REFUND} - 退货退款</li>
+ * </ul>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Getter // Lombok注解,自动为所有final字段生成getter方法
+public enum RefundTypeEnum {
+
+    /**
+     * type=1:退款(未发货退款)
+     * <p>
+     * 适用于买家已付款,但商家尚未发货的场景下,买家申请退款。
+     * </p>
+     */
+    REFUND_BEFORE_SHIPPING(1, "未发货退款"),
+
+    /**
+     * type=2:退款不退货
+     * <p>
+     * 适用于商家已发货,但由于特定原因(如商品无需寄回、商家协商同意等),
+     * 买家仅申请退款而无需退回货物。
+     * </p>
+     */
+    REFUND_WITHOUT_RETURN(2, "退款不退货"),
+
+    /**
+     * type=3:退货退款
+     * <p>
+     * 适用于商家已发货,买家收到货后因商品问题或其他原因需要退回商品并申请退款。
+     * (用户原始描述为 "退货",在此明确为包含退款流程)
+     * </p>
+     */
+    RETURN_AND_REFUND(3, "退货退款");
+
+    /**
+     * 类型编码
+     * <p>
+     * 与数据库或接口中表示退款类型的字段值对应。
+     * </p>
+     */
+    private final int code;
+
+    /**
+     * 类型描述
+     * <p>
+     * 对退款类型的中文说明,方便理解和展示。
+     * </p>
+     */
+    private final String description;
+
+    /**
+     * 枚举构造函数
+     *
+     * @param code        类型编码
+     * @param description 类型描述
+     */
+    RefundTypeEnum(int code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据 code 获取对应的枚举实例
+     * <p>
+     * 提供一个便捷的方法,通过整数编码查找对应的枚举常量。
+     * </p>
+     *
+     * @param code 类型编码 (int)
+     * @return 对应的 {@code RefundTypeEnum} 实例,如果找不到则返回 {@code null}
+     */
+    public static RefundTypeEnum getByCode(int code) {
+        // 遍历枚举常量
+        for (RefundTypeEnum type : RefundTypeEnum.values()) {
+            if (type.getCode() == code) {
+                return type; // 找到匹配的code,返回对应的枚举实例
+            }
+        }
+        return null; // 没有找到匹配的code,返回null
+    }
+
+    /**
+     * 根据 code 获取对应的枚举实例 (Integer版本)
+     * <p>
+     * 提供一个处理 {@code Integer} 类型 code 的重载方法,增强兼容性。
+     * </p>
+     *
+     * @param code 类型编码 ({@code Integer})
+     * @return 对应的 {@code RefundTypeEnum} 实例,如果 code 为 {@code null} 或找不到则返回 {@code null}
+     */
+    public static RefundTypeEnum getByCode(Integer code) {
+        if (code == null) {
+            return null; // 处理null输入
+        }
+        // 使用 Java 8 Stream API 进行查找,更简洁
+        return Arrays.stream(RefundTypeEnum.values())
+                .filter(enumInstance -> Objects.equals(enumInstance.getCode(), code)) // 使用Objects.equals避免潜在的NullPointerException,虽然这里code已检查非null
+                .findFirst() // 找到第一个匹配的
+                .orElse(null); // 如果找不到,返回null
+    }
+
+    // Lombok 的 @Getter 会自动生成以下公共方法:
+    // public int getCode() { return this.code; }
+    // public String getDescription() { return this.description; }
+}

+ 101 - 15
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtApiRefund.java

@@ -1,93 +1,179 @@
 package com.fs.erp.dto.wdt;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.math.BigDecimal;
 import java.util.List;
 
 /**
- * 旺店通开放平台 API 退款单信息 DTO
+ * ERP旺店通单个退款单信息 DTO
+ * <p>
+ * 代表一个具体的平台售后退款/退货单据。
+ * </p>
+ *
  * @author xdd
- * @date 2025-02-27
+ * @since 2025-02-27
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class ErpWdtApiRefund {
 
     /**
      * 平台ID
-     * <p>输入固定值127</p>
+     * <p>
+     * 输入固定值127。
+     * 必须: 是
+     * 类型: smallint(6)
+     * </p>
      */
-    private short platformId;
+    @JsonProperty("platform_id")
+    private Integer platformId;
 
     /**
      * 店铺编号
-     * <p>代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置),用于推送指定店铺原始退款单据信息</p>
+     * <p>
+     * 代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置),用于推送指定店铺原始退款单据信息。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
      */
+    @JsonProperty("shop_no")
     private String shopNo;
 
     /**
      * 平台销售订单号
-     * <p>平台订单单号(与推送trade_push的tid保持一致,对应旺店通ERP内原始单号)</p>
+     * <p>
+     * 平台订单单号(与推送trade_push的tid保持一致,对应旺店通ERP内原始单号)。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
      */
+    @JsonProperty("tid")
     private String tid;
 
     /**
      * 平台退款/退货单号
-     * <p>平台退款/退货单单号,保证唯一</p>
+     * <p>
+     * 平台退款/退货单单号,保证唯一。
+     * 必须: 是
+     * 类型: varchar(40)
+     * </p>
      */
+    @JsonProperty("refund_no")
     private String refundNo;
 
     /**
      * 平台售后类型
-     * <p>type=1:退款(未发货退款);type=2:退款不退货;type=3:退货</p>
+     * <p>
+     * type=1:退款(未发货退款);type=2:退款不退货;type=3:退货。
+     * 必须: 是
+     * 类型: int
+     * </p>
      */
+    @JsonProperty("type")
     private Integer type;
 
     /**
      * 平台售后状态
-     * <p>可选值:wait_seller_agree(申请退款),  seller_refuse(拒绝退款) , closed(退款关闭) ,goods_returning(待退货) goods_receiving(待收货),success(退款成功)</p>
+     * <p>
+     * 可选值:wait_seller_agree(申请退款),seller_refuse(拒绝退款),closed(退款关闭),goods_returning(待退货),goods_receiving(待收货),success(退款成功)。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
      */
+    @JsonProperty("status")
     private String status;
 
     /**
      * 退款金额
+     * <p>
+     * 退款的总金额。
+     * 必须: 否
+     * 类型: decimal(19,4)
+     * </p>
      */
+    @JsonProperty("refund_fee")
     private BigDecimal refundFee;
 
     /**
      * 买家昵称
-     * <p>买家昵称(不传该字段,默认取原始订单上客户网名)</p>
+     * <p>
+     * 买家昵称(不传该字段,默认取原始订单上客户网名)。
+     * 必须: 是
+     * 类型: varchar(100)
+     * </p>
      */
+    @JsonProperty("buyer_nick")
     private String buyerNick;
 
     /**
      * 单据创建时间
-     * <p>单据创建时间,时间格式:yyyy-MM-dd HH:mm:ss</p>
+     * <p>
+     * 单据创建时间, 时间格式:yyyy-MM-dd HH:mm:ss。
+     * 必须: 是
+     * 类型: datetime
+     * </p>
      */
-    private String refundTime;
+    @JsonProperty("refund_time")
+    private String refundTime; // 使用String类型以匹配指定的格式
 
     /**
      * 退款原因
+     * <p>
+     * 客户申请退款的原因。
+     * 必须: 否
+     * 类型: varchar(255)
+     * </p>
      */
+    @JsonProperty("reason")
     private String reason;
 
     /**
      * 备注
+     * <p>
+     * 退款单相关的备注信息。
+     * 必须: 否
+     * 类型: varchar(255)
+     * </p>
      */
-    private String desc;
+    @JsonProperty("desc")
+    private String desc; // 注意:'desc' 在某些场景下可能是关键字,但这里保持与JSON一致
 
     /**
      * 物流单号
-     * <p>物流单号(如需维护退货物流单号,与logistics_name物流公司名称同时使用)</p>
+     * <p>
+     * 退货时的物流单号(如需维护退货物流单号,与logistics_name物流公司名称同时使用)。
+     * 必须: 否
+     * 类型: varchar(40)
+     * </p>
      */
+    @JsonProperty("logistics_no")
     private String logisticsNo;
 
     /**
      * 物流公司名称
+     * <p>
+     * 退货时的物流公司名称。
+     * 必须: 否
+     * 类型: varchar(40)
+     * </p>
      */
+    @JsonProperty("logistics_name")
     private String logisticsName;
 
     /**
-     * 售后子订单
+     * 售后子订单列表
+     * <p>
+     * 包含该退款单涉及的子订单信息。
+     * 必须: 是
+     * </p>
      */
+    @JsonProperty("order_list")
     private List<ErpWdtRefundOrder> orderList;
 }

+ 1 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtOrder.java

@@ -1,5 +1,6 @@
 package com.fs.erp.dto.wdt;
 
+import lombok.Builder;
 import lombok.Data;
 import java.math.BigDecimal;
 

+ 26 - 4
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundOrder.java

@@ -1,25 +1,47 @@
 package com.fs.erp.dto.wdt;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.math.BigDecimal;
 
 /**
- * 旺店通开放平台 API 售后子订单 DTO
+ * ERP旺店通售后子订单信息 DTO
+ * <p>
+ * 代表退款单中涉及的具体商品行项目。
+ * </p>
+ *
  * @author xdd
- * @date 2025-02-27
+ * @since 2025-02-27
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class ErpWdtRefundOrder {
 
     /**
      * 平台订单子订单编号
-     * <p>平台订单子订单编号(与推送trade_push的oid保持一致,对应旺店通ERP内原始子订单编号)可推送部分子订单</p>
+     * <p>
+     * 平台订单子订单编号(与推送trade_push的oid保持一致,对应旺店通ERP内原始子订单编号)。可推送部分子订单。
+     * 必须: 是
+     * 类型: varchar(40)
+     * </p>
      */
+    @JsonProperty("oid")
     private String oid;
 
     /**
      * 退货货品数量
-     * <p>退货货品数量(如果是type=1 退款   2 退款不退货类型,此处代表退款数量)</p>
+     * <p>
+     * 退货货品数量(如果是type=1 退款 或 2 退款不退货类型,此处代表退款数量)。
+     * 必须: 是
+     * 类型: decimal(19,4)
+     * </p>
      */
+    @JsonProperty("num")
     private BigDecimal num;
 }

+ 35 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundRequest.java

@@ -0,0 +1,35 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * ERP旺店通退款单推送请求 DTO
+ * <p>
+ * 包含推送给旺店通ERP的退款单据的顶层结构。
+ * </p>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtRefundRequest {
+
+    /**
+     * 请求参数的1级数据节点
+     * <p>
+     * 包含平台售后订单所有属性信息的数据节点列表。
+     * 必须: 是
+     * </p>
+     */
+    @JsonProperty("api_refund_list") // 对应JSON字段名
+    private List<ErpWdtApiRefund> apiRefundList;
+}

+ 47 - 1
fs-service-system/src/main/java/com/fs/erp/service/impl/WdtErpOrderServiceImpl.java

@@ -24,6 +24,7 @@ import com.fs.store.vo.FsStoreOrderItemVO;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.http.client.utils.DateUtils;
 import org.apache.http.util.Asserts;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -220,7 +221,52 @@ public class WdtErpOrderServiceImpl implements IErpOrderService {
 
     @Override
     public BaseResponse refundUpdate(ErpRefundUpdateRequest param) {
-        return null;
+        WdtClient client = WdtClient.getInstance();
+        Map<String,String> map = new HashMap<>();
+
+
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(param.getTid());
+
+        Asserts.check(ObjectUtils.isNotNull(fsStoreOrder), "该订单不存在! 订单id: {} ", param.getTid());
+
+        List<FsStoreOrderItemVO> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getId());
+        List<ErpWdtRefundOrder> refundOrders = new ArrayList<>();
+
+        for (FsStoreOrderItemVO item : fsStoreOrderItemVOS) {
+            refundOrders.add(ErpWdtRefundOrder.builder()
+                    .oid(String.format("%s%s",item.getOrderCode(),item.getItemId()))
+                    .num(BigDecimal.ONE)
+                    .build());
+        }
+        List<ErpWdtApiRefund> erpWdtApiRefunds = Collections.singletonList(ErpWdtApiRefund.builder()
+                .platformId(127)
+                .shopNo(shopCode)
+                .tid(param.getTid())
+                .refundNo(param.getTid())
+                .type(RefundTypeEnum.REFUND_BEFORE_SHIPPING.getCode())
+                .status(AfterSaleStatusEnum.SUCCESS.getCode())
+                .refundTime(DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"))
+                .orderList(refundOrders)
+                .build());
+
+        ErpWdtRefundRequest refundRequest = ErpWdtRefundRequest.builder()
+                .apiRefundList(erpWdtApiRefunds)
+                .build();
+
+        map.put("api_refund_list",JSON.toJSONString(refundRequest));
+        try {
+            String execute = client.execute("sales_refund_push.php", map);
+            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(execute, ErpWdtApiResponse.class);
+            if(ObjectUtil.equal(0, erpWdtApiResponse.getCode())){
+                log.info("退款单更新成功: {}", erpWdtApiResponse);
+                return new BaseResponse();
+            } else {
+                log.info("退款单更新失败: {}", erpWdtApiResponse);
+                throw new RuntimeException(String.format("退款单更新失败, 原因: %s", erpWdtApiResponse.getMessage()));
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
     public static String convertToSnakeCase(Object obj) {
         SerializeConfig config = new SerializeConfig();